diff --git a/client/covenant/cli.go b/client/covenant/cli.go index d6970ed..b466195 100644 --- a/client/covenant/cli.go +++ b/client/covenant/cli.go @@ -25,6 +25,14 @@ const dust = 450 type covenantLiquidCLI struct{} +func (c *covenantLiquidCLI) SendAsync(ctx *cli.Context) error { + return fmt.Errorf("not implemented") +} + +func (c *covenantLiquidCLI) ClaimAsync(ctx *cli.Context) error { + return fmt.Errorf("not implemented") +} + func (c *covenantLiquidCLI) Receive(ctx *cli.Context) error { offchainAddr, onchainAddr, _, err := getAddress(ctx) if err != nil { diff --git a/client/covenant/client.go b/client/covenant/client.go index 0455faa..33f7a58 100644 --- a/client/covenant/client.go +++ b/client/covenant/client.go @@ -109,7 +109,7 @@ func getClient(addr string) (arkv1.ArkServiceClient, func(), error) { if !strings.Contains(addr, ":") { addr = fmt.Sprintf("%s:%d", addr, port) } - conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(creds)) + conn, err := grpc.NewClient(addr, grpc.WithTransportCredentials(creds)) if err != nil { return nil, nil, err } diff --git a/client/covenantless/claim.go b/client/covenantless/claim.go new file mode 100644 index 0000000..a607302 --- /dev/null +++ b/client/covenantless/claim.go @@ -0,0 +1,98 @@ +package covenantless + +import ( + "github.com/ark-network/ark-cli/utils" + arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1" + "github.com/urfave/cli/v2" +) + +func (c *clArkBitcoinCLI) ClaimAsync(ctx *cli.Context) error { + client, cancel, err := getClientFromState(ctx) + if err != nil { + return err + } + defer cancel() + + myselfOffchain, _, _, err := getAddress(ctx) + if err != nil { + return err + } + + vtxos, err := getVtxos(ctx, nil, client, myselfOffchain, false) + if err != nil { + return err + } + + var pendingBalance uint64 + var pendingVtxos []vtxo + for _, vtxo := range vtxos { + if vtxo.pending { + pendingBalance += vtxo.amount + pendingVtxos = append(pendingVtxos, vtxo) + } + } + if pendingBalance == 0 { + return nil + } + + receiver := receiver{ + To: myselfOffchain, + Amount: pendingBalance, + } + return selfTransferAllPendingPayments( + ctx, client, pendingVtxos, receiver, + ) +} + +func selfTransferAllPendingPayments( + ctx *cli.Context, client arkv1.ArkServiceClient, + pendingVtxos []vtxo, myself receiver, +) error { + inputs := make([]*arkv1.Input, 0, len(pendingVtxos)) + + for _, coin := range pendingVtxos { + inputs = append(inputs, &arkv1.Input{ + Txid: coin.txid, + Vout: coin.vout, + }) + } + + receiversOutput := []*arkv1.Output{ + { + Address: myself.To, + Amount: myself.Amount, + }, + } + + secKey, err := utils.PrivateKeyFromPassword(ctx) + if err != nil { + return err + } + + registerResponse, err := client.RegisterPayment( + ctx.Context, &arkv1.RegisterPaymentRequest{Inputs: inputs}, + ) + if err != nil { + return err + } + + _, err = client.ClaimPayment(ctx.Context, &arkv1.ClaimPaymentRequest{ + Id: registerResponse.GetId(), + Outputs: []*arkv1.Output{{Address: myself.To, Amount: myself.Amount}}, + }) + if err != nil { + return err + } + + poolTxID, err := handleRoundStream( + ctx, client, registerResponse.GetId(), + pendingVtxos, secKey, receiversOutput, + ) + if err != nil { + return err + } + + return utils.PrintJSON(map[string]interface{}{ + "pool_txid": poolTxID, + }) +} diff --git a/client/covenantless/cli.go b/client/covenantless/cli.go index 53b679d..8f3d977 100644 --- a/client/covenantless/cli.go +++ b/client/covenantless/cli.go @@ -70,15 +70,19 @@ func New() interfaces.CLI { return &clArkBitcoinCLI{} } +func (c *clArkBitcoinCLI) Send(ctx *cli.Context) error { + return fmt.Errorf("not implemented") +} + type receiver struct { To string `json:"to"` Amount uint64 `json:"amount"` } -func (r *receiver) isOnchain() bool { - _, err := btcutil.DecodeAddress(r.To, nil) - return err == nil -} +// func (r *receiver) isOnchain() bool { +// _, err := btcutil.DecodeAddress(r.To, nil) +// return err == nil +// } func sendOnchain(ctx *cli.Context, receivers []receiver) (string, error) { ptx, err := psbt.New(nil, nil, 2, 0, nil) diff --git a/client/covenantless/client.go b/client/covenantless/client.go index f8a2c8d..3b4909e 100644 --- a/client/covenantless/client.go +++ b/client/covenantless/client.go @@ -27,6 +27,7 @@ type vtxo struct { vout uint32 poolTxid string expireAt *time.Time + pending bool } func getVtxos( @@ -43,19 +44,20 @@ func getVtxos( vtxos := make([]vtxo, 0, len(response.GetSpendableVtxos())) for _, v := range response.GetSpendableVtxos() { var expireAt *time.Time - if v.ExpireAt > 0 { + if v.GetExpireAt() > 0 { t := time.Unix(v.ExpireAt, 0) expireAt = &t } - if v.Swept { + if v.GetSwept() { continue } vtxos = append(vtxos, vtxo{ - amount: v.Receiver.Amount, - txid: v.Outpoint.Txid, - vout: v.Outpoint.Vout, - poolTxid: v.PoolTxid, + amount: v.GetReceiver().GetAmount(), + txid: v.GetOutpoint().GetTxid(), + vout: v.GetOutpoint().GetVout(), + poolTxid: v.GetPoolTxid(), expireAt: expireAt, + pending: v.GetPending(), }) } @@ -108,7 +110,7 @@ func getClient(addr string) (arkv1.ArkServiceClient, func(), error) { if !strings.Contains(addr, ":") { addr = fmt.Sprintf("%s:%d", addr, port) } - conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(creds)) + conn, err := grpc.NewClient(addr, grpc.WithTransportCredentials(creds)) if err != nil { return nil, nil, err } diff --git a/client/covenantless/send.go b/client/covenantless/send.go index babc5fd..cfdcb6d 100644 --- a/client/covenantless/send.go +++ b/client/covenantless/send.go @@ -2,118 +2,63 @@ package covenantless import ( "bytes" - "encoding/json" "fmt" "sort" + "strings" "github.com/ark-network/ark-cli/utils" arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1" "github.com/ark-network/ark/common" + "github.com/btcsuite/btcd/btcutil/psbt" "github.com/urfave/cli/v2" ) -func (c *clArkBitcoinCLI) Send(ctx *cli.Context) error { - if !ctx.IsSet("receivers") && !ctx.IsSet("to") && !ctx.IsSet("amount") { - return fmt.Errorf("missing destination, either use --to and --amount to send or --receivers to send to many") - } - receivers := ctx.String("receivers") - to := ctx.String("to") +func (c *clArkBitcoinCLI) SendAsync(ctx *cli.Context) error { + receiver := ctx.String("to") amount := ctx.Uint64("amount") - - var receiversJSON []receiver - if len(receivers) > 0 { - if err := json.Unmarshal([]byte(receivers), &receiversJSON); err != nil { - return fmt.Errorf("invalid receivers: %s", err) - } - } else { - receiversJSON = []receiver{ - { - To: to, - Amount: amount, - }, - } - } - - if len(receiversJSON) <= 0 { - return fmt.Errorf("no receivers specified") - } - - onchainReceivers := make([]receiver, 0) - offchainReceivers := make([]receiver, 0) - - for _, receiver := range receiversJSON { - if receiver.isOnchain() { - onchainReceivers = append(onchainReceivers, receiver) - } else { - offchainReceivers = append(offchainReceivers, receiver) - } - } - - explorer := utils.NewExplorer(ctx) - - if len(onchainReceivers) > 0 { - pset, err := sendOnchain(ctx, onchainReceivers) - if err != nil { - return err - } - - txid, err := explorer.Broadcast(pset) - if err != nil { - return err - } - - return utils.PrintJSON(map[string]interface{}{ - "txid": txid, - }) - } - - if len(offchainReceivers) > 0 { - if err := sendOffchain(ctx, offchainReceivers); err != nil { - return err - } - } - - return nil -} - -func sendOffchain(ctx *cli.Context, receivers []receiver) error { withExpiryCoinselect := ctx.Bool("enable-expiry-coinselect") + if amount < dust { + return fmt.Errorf("invalid amount (%d), must be greater than dust %d", amount, dust) + } + + if receiver == "" { + return fmt.Errorf("receiver address is required") + } + isOnchain, _, _, err := decodeReceiverAddress(receiver) + if err != nil { + return err + } + if isOnchain { + return fmt.Errorf("receiver address is onchain") + } + offchainAddr, _, _, err := getAddress(ctx) if err != nil { return err } - _, _, aspPubKey, err := common.DecodeAddress(offchainAddr) if err != nil { return err } + _, _, aspKey, err := common.DecodeAddress(receiver) + if err != nil { + return fmt.Errorf("invalid receiver address: %s", err) + } + if !bytes.Equal( + aspPubKey.SerializeCompressed(), aspKey.SerializeCompressed(), + ) { + return fmt.Errorf("invalid receiver address '%s': must be associated with the connected service provider", receiver) + } receiversOutput := make([]*arkv1.Output, 0) sumOfReceivers := uint64(0) + receiversOutput = append(receiversOutput, &arkv1.Output{ + Address: receiver, + Amount: amount, + }) + sumOfReceivers += amount - for _, receiver := range receivers { - _, _, aspKey, err := common.DecodeAddress(receiver.To) - if err != nil { - return fmt.Errorf("invalid receiver address: %s", err) - } - - if !bytes.Equal( - aspPubKey.SerializeCompressed(), aspKey.SerializeCompressed(), - ) { - return fmt.Errorf("invalid receiver address '%s': must be associated with the connected service provider", receiver.To) - } - - if receiver.Amount < dust { - return fmt.Errorf("invalid amount (%d), must be greater than dust %d", receiver.Amount, dust) - } - - receiversOutput = append(receiversOutput, &arkv1.Output{ - Address: receiver.To, - Amount: uint64(receiver.Amount), - }) - sumOfReceivers += receiver.Amount - } client, close, err := getClientFromState(ctx) if err != nil { return err @@ -148,37 +93,66 @@ func sendOffchain(ctx *cli.Context, receivers []receiver) error { }) } - secKey, err := utils.PrivateKeyFromPassword(ctx) + resp, err := client.CreatePayment( + ctx.Context, &arkv1.CreatePaymentRequest{ + Inputs: inputs, + Outputs: receiversOutput, + }) if err != nil { return err } - registerResponse, err := client.RegisterPayment( - ctx.Context, &arkv1.RegisterPaymentRequest{Inputs: inputs}, - ) + // TODO verify the redeem tx signature + fmt.Println("payment created") + fmt.Println("signing redeem and forfeit txs...") + + seckey, err := utils.PrivateKeyFromPassword(ctx) if err != nil { return err } - _, err = client.ClaimPayment(ctx.Context, &arkv1.ClaimPaymentRequest{ - Id: registerResponse.GetId(), - Outputs: receiversOutput, - }) + signedUnconditionalForfeitTxs := make([]string, 0, len(resp.UsignedUnconditionalForfeitTxs)) + for _, tx := range resp.UsignedUnconditionalForfeitTxs { + forfeitPtx, err := psbt.NewFromRawBytes(strings.NewReader(tx), true) + if err != nil { + return err + } + + if err := signPsbt(ctx, forfeitPtx, explorer, seckey); err != nil { + return err + } + + signedForfeitTx, err := forfeitPtx.B64Encode() + if err != nil { + return err + } + + signedUnconditionalForfeitTxs = append(signedUnconditionalForfeitTxs, signedForfeitTx) + } + + redeemPtx, err := psbt.NewFromRawBytes(strings.NewReader(resp.SignedRedeemTx), true) if err != nil { return err } - poolTxID, err := handleRoundStream( - ctx, client, registerResponse.GetId(), - selectedCoins, secKey, receiversOutput, - ) + if err := signPsbt(ctx, redeemPtx, explorer, seckey); err != nil { + return err + } + + signedRedeem, err := redeemPtx.B64Encode() if err != nil { return err } - return utils.PrintJSON(map[string]interface{}{ - "pool_txid": poolTxID, - }) + if _, err = client.CompletePayment(ctx.Context, &arkv1.CompletePaymentRequest{ + SignedRedeemTx: signedRedeem, + SignedUnconditionalForfeitTxs: signedUnconditionalForfeitTxs, + }); err != nil { + return err + } + + fmt.Println("payment completed") + return nil } func coinSelect(vtxos []vtxo, amount uint64, sortByExpirationTime bool) ([]vtxo, uint64, error) { @@ -213,7 +187,7 @@ func coinSelect(vtxos []vtxo, amount uint64, sortByExpirationTime bool) ([]vtxo, change := selectedAmount - amount - if change < dust { + if change > 0 && change < dust { if len(notSelected) > 0 { selected = append(selected, notSelected[0]) change += notSelected[0].amount diff --git a/client/covenantless/signer.go b/client/covenantless/signer.go index c09130b..44984e9 100644 --- a/client/covenantless/signer.go +++ b/client/covenantless/signer.go @@ -132,7 +132,7 @@ func signPsbt( switch c := closure.(type) { case *bitcointree.CSVSigClosure: sign = bytes.Equal(c.Pubkey.SerializeCompressed()[1:], pubkey.SerializeCompressed()[1:]) - case *bitcointree.ForfeitClosure: + case *bitcointree.MultisigClosure: sign = bytes.Equal(c.Pubkey.SerializeCompressed()[1:], pubkey.SerializeCompressed()[1:]) } diff --git a/client/covenantless/vtxo.go b/client/covenantless/vtxo.go index b9b1c77..18f4ba1 100644 --- a/client/covenantless/vtxo.go +++ b/client/covenantless/vtxo.go @@ -14,7 +14,7 @@ func computeVtxoTaprootScript( Seconds: exitDelay, } - forfeitClosure := &bitcointree.ForfeitClosure{ + forfeitClosure := &bitcointree.MultisigClosure{ Pubkey: userPubkey, AspPubkey: aspPubkey, } diff --git a/client/flags/flags.go b/client/flags/flags.go index 811d83f..8cdf50f 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -72,18 +72,22 @@ var ( Value: "", Required: false, } - AmountToRedeemFlag = cli.Uint64Flag{ Name: "amount", Usage: "amount to redeem", Value: 0, Required: false, } - ForceFlag = cli.BoolFlag{ Name: "force", Usage: "force redemption without collaborate with the Ark service provider", Value: false, Required: false, } + AsyncPaymentFlag = cli.BoolFlag{ + Name: "async", + Usage: "use async payment protocol", + Value: false, + Required: false, + } ) diff --git a/client/interfaces/cli.go b/client/interfaces/cli.go index da67b5f..b1283cb 100644 --- a/client/interfaces/cli.go +++ b/client/interfaces/cli.go @@ -8,5 +8,7 @@ type CLI interface { Receive(ctx *cli.Context) error Redeem(ctx *cli.Context) error Send(ctx *cli.Context) error + ClaimAsync(ctx *cli.Context) error + SendAsync(ctx *cli.Context) error Onboard(ctx *cli.Context) error } diff --git a/client/main.go b/client/main.go index 1b82d76..cc82d85 100644 --- a/client/main.go +++ b/client/main.go @@ -92,14 +92,36 @@ var ( sendCommand = cli.Command{ Name: "send", Usage: "Send your onchain or offchain funds to one or many receivers", + Action: func(ctx *cli.Context) error { + state, err := utils.GetState(ctx) + if err != nil { + return err + } + + networkName := state[utils.NETWORK] + cli, err := getCLI(networkName) + if err != nil { + return err + } + if strings.Contains(networkName, "liquid") { + return cli.Send(ctx) + } + return cli.SendAsync(ctx) + }, + Flags: []cli.Flag{&flags.ReceiversFlag, &flags.ToFlag, &flags.AmountFlag, &flags.PasswordFlag, &flags.EnableExpiryCoinselectFlag, &flags.AsyncPaymentFlag}, + } + + claimCommand = cli.Command{ + Name: "claim", + Usage: "Join round to claim pending payments", Action: func(ctx *cli.Context) error { cli, err := getCLIFromState(ctx) if err != nil { return err } - return cli.Send(ctx) + return cli.ClaimAsync(ctx) }, - Flags: []cli.Flag{&flags.ReceiversFlag, &flags.ToFlag, &flags.AmountFlag, &flags.PasswordFlag, &flags.EnableExpiryCoinselectFlag}, + Flags: []cli.Flag{&flags.PasswordFlag}, } receiveCommand = cli.Command{ @@ -144,6 +166,7 @@ func main() { &receiveCommand, &redeemCommand, &sendCommand, + &claimCommand, &onboardCommand, ) app.Flags = []cli.Flag{ diff --git a/client/utils/explorer.go b/client/utils/explorer.go index d9687bb..55967f2 100644 --- a/client/utils/explorer.go +++ b/client/utils/explorer.go @@ -84,7 +84,6 @@ func (e *explorer) GetFeeRate() (float64, error) { fmt.Println("empty fee-estimates response, default to 2 sat/vbyte") return 2, nil } - fmt.Println("fee rate", response["1"]) return response["1"], nil } diff --git a/common/bitcointree/builder.go b/common/bitcointree/builder.go index 45b2d0c..bad85fd 100644 --- a/common/bitcointree/builder.go +++ b/common/bitcointree/builder.go @@ -155,7 +155,7 @@ func (l *leaf) getOutputs() ([]*wire.TxOut, error) { return nil, err } - forfeitClosure := &ForfeitClosure{ + forfeitClosure := &MultisigClosure{ Pubkey: l.vtxoKey, AspPubkey: l.aspKey, } diff --git a/common/bitcointree/script.go b/common/bitcointree/script.go index 51dc5fc..ab56303 100644 --- a/common/bitcointree/script.go +++ b/common/bitcointree/script.go @@ -20,7 +20,7 @@ type CSVSigClosure struct { Seconds uint } -type ForfeitClosure struct { +type MultisigClosure struct { Pubkey *secp256k1.PublicKey AspPubkey *secp256k1.PublicKey } @@ -33,7 +33,7 @@ func DecodeClosure(script []byte) (Closure, error) { return closure, nil } - closure = &ForfeitClosure{} + closure = &MultisigClosure{} if valid, err := closure.Decode(script); err == nil && valid { return closure, nil } @@ -42,7 +42,7 @@ func DecodeClosure(script []byte) (Closure, error) { } -func (f *ForfeitClosure) Leaf() (*txscript.TapLeaf, error) { +func (f *MultisigClosure) Leaf() (*txscript.TapLeaf, error) { aspKeyBytes := schnorr.SerializePubKey(f.AspPubkey) userKeyBytes := schnorr.SerializePubKey(f.Pubkey) @@ -57,7 +57,7 @@ func (f *ForfeitClosure) Leaf() (*txscript.TapLeaf, error) { return &tapLeaf, nil } -func (f *ForfeitClosure) Decode(script []byte) (bool, error) { +func (f *MultisigClosure) Decode(script []byte) (bool, error) { valid, aspPubKey, err := decodeChecksigScript(script) if err != nil { return false, err @@ -149,7 +149,7 @@ func ComputeVtxoTaprootScript( Seconds: exitDelay, } - forfeitClosure := &ForfeitClosure{ + forfeitClosure := &MultisigClosure{ Pubkey: userPubkey, AspPubkey: aspPubkey, } diff --git a/docker-compose.clark.regtest.yml b/docker-compose.clark.regtest.yml index ea7577a..7e90d92 100644 --- a/docker-compose.clark.regtest.yml +++ b/docker-compose.clark.regtest.yml @@ -18,6 +18,9 @@ services: - ARK_NO_MACAROONS=true ports: - "6000:6000" + volumes: + - clarkd:/app/data + - clark:/app/wallet-data volumes: clarkd: diff --git a/docker-compose.regtest.yml b/docker-compose.regtest.yml index 5c0c615..9bbe644 100644 --- a/docker-compose.regtest.yml +++ b/docker-compose.regtest.yml @@ -14,6 +14,9 @@ services: - OCEAN_DB_TYPE=badger ports: - "18000:18000" + volumes: + - oceand:/app/data/oceand + - ocean:/app/data/ocean arkd: container_name: arkd build: @@ -35,6 +38,9 @@ services: - ARK_NO_MACAROONS=true ports: - "8080:8080" + volumes: + - arkd:/app/data + - ark:/app/wallet-data volumes: oceand: diff --git a/pkg/client-sdk/ark_sdk.go b/pkg/client-sdk/ark_sdk.go index 4c7fdd2..82bd77a 100644 --- a/pkg/client-sdk/ark_sdk.go +++ b/pkg/client-sdk/ark_sdk.go @@ -23,6 +23,8 @@ type ArkClient interface { CollaborativeRedeem( ctx context.Context, addr string, amount uint64, withExpiryCoinselect bool, ) (string, error) + SendAsync(ctx context.Context, withExpiryCoinselect bool, receivers []Receiver) (string, error) + ClaimAsync(ctx context.Context) (string, error) } type Receiver interface { diff --git a/pkg/client-sdk/client/client.go b/pkg/client-sdk/client/client.go index 7cad7d0..7466735 100644 --- a/pkg/client-sdk/client/client.go +++ b/pkg/client-sdk/client/client.go @@ -37,6 +37,12 @@ type ASPClient interface { FinalizePayment( ctx context.Context, signedForfeitTxs []string, ) error + CreatePayment( + ctx context.Context, inputs []VtxoKey, outputs []Output, + ) (string, []string, error) + CompletePayment( + ctx context.Context, signedRedeemTx string, signedUnconditionalForfeitTxs []string, + ) error Close() } @@ -61,9 +67,12 @@ type VtxoKey struct { type Vtxo struct { VtxoKey - Amount uint64 - RoundTxid string - ExpiresAt *time.Time + Amount uint64 + RoundTxid string + ExpiresAt *time.Time + RedeemTx string + UnconditionalForfeitTxs []string + Pending bool } type Output struct { diff --git a/pkg/client-sdk/client/grpc/client.go b/pkg/client-sdk/client/grpc/client.go index 157b4dd..73ae6c4 100644 --- a/pkg/client-sdk/client/grpc/client.go +++ b/pkg/client-sdk/client/grpc/client.go @@ -199,6 +199,31 @@ func (a *grpcClient) FinalizePayment( return err } +func (a *grpcClient) CreatePayment( + ctx context.Context, inputs []client.VtxoKey, outputs []client.Output, +) (string, []string, error) { + req := &arkv1.CreatePaymentRequest{ + Inputs: ins(inputs).toProto(), + Outputs: outs(outputs).toProto(), + } + resp, err := a.svc.CreatePayment(ctx, req) + if err != nil { + return "", nil, err + } + return resp.SignedRedeemTx, resp.UsignedUnconditionalForfeitTxs, nil +} + +func (a *grpcClient) CompletePayment( + ctx context.Context, redeemTx string, signedForfeitTxs []string, +) error { + req := &arkv1.CompletePaymentRequest{ + SignedRedeemTx: redeemTx, + SignedUnconditionalForfeitTxs: signedForfeitTxs, + } + _, err := a.svc.CompletePayment(ctx, req) + return err +} + func (a *grpcClient) GetRoundByID( ctx context.Context, roundID string, ) (*client.Round, error) { @@ -284,14 +309,23 @@ func (v vtxo) toVtxo() client.Vtxo { t := time.Unix(v.GetExpireAt(), 0) expiresAt = &t } + var redeemTx string + var uncondForfeitTxs []string + if v.GetPendingData() != nil { + redeemTx = v.GetPendingData().GetRedeemTx() + uncondForfeitTxs = v.GetPendingData().GetUnconditionalForfeitTxs() + } return client.Vtxo{ VtxoKey: client.VtxoKey{ Txid: v.GetOutpoint().GetTxid(), VOut: v.GetOutpoint().GetVout(), }, - Amount: v.GetReceiver().GetAmount(), - RoundTxid: v.GetPoolTxid(), - ExpiresAt: expiresAt, + Amount: v.GetReceiver().GetAmount(), + RoundTxid: v.GetPoolTxid(), + ExpiresAt: expiresAt, + Pending: v.GetPending(), + RedeemTx: redeemTx, + UnconditionalForfeitTxs: uncondForfeitTxs, } } diff --git a/pkg/client-sdk/client/rest/client.go b/pkg/client-sdk/client/rest/client.go index ce8a6fb..d7dc7c0 100644 --- a/pkg/client-sdk/client/rest/client.go +++ b/pkg/client-sdk/client/rest/client.go @@ -180,14 +180,24 @@ func (a *restClient) ListVtxos( return nil, nil, err } + var redeemTx string + var uncondForfeitTxs []string + if v.PendingData != nil { + redeemTx = v.PendingData.RedeemTx + uncondForfeitTxs = v.PendingData.UnconditionalForfeitTxs + } + spendableVtxos = append(spendableVtxos, client.Vtxo{ VtxoKey: client.VtxoKey{ Txid: v.Outpoint.Txid, VOut: uint32(v.Outpoint.Vout), }, - Amount: uint64(amount), - RoundTxid: v.PoolTxid, - ExpiresAt: expiresAt, + Amount: uint64(amount), + RoundTxid: v.PoolTxid, + ExpiresAt: expiresAt, + Pending: v.Pending, + RedeemTx: redeemTx, + UnconditionalForfeitTxs: uncondForfeitTxs, }) } @@ -358,6 +368,53 @@ func (a *restClient) FinalizePayment( return err } +func (a *restClient) CreatePayment( + ctx context.Context, inputs []client.VtxoKey, outputs []client.Output, +) (string, []string, error) { + ins := make([]*models.V1Input, 0, len(inputs)) + for _, i := range inputs { + ins = append(ins, &models.V1Input{ + Txid: i.Txid, + Vout: int64(i.VOut), + }) + } + outs := make([]*models.V1Output, 0, len(outputs)) + for _, o := range outputs { + outs = append(outs, &models.V1Output{ + Address: o.Address, + Amount: strconv.Itoa(int(o.Amount)), + }) + } + body := models.V1CreatePaymentRequest{ + Inputs: ins, + Outputs: outs, + } + resp, err := a.svc.ArkServiceCreatePayment( + ark_service.NewArkServiceCreatePaymentParams().WithBody(&body), + ) + if err != nil { + return "", nil, err + } + return resp.GetPayload().SignedRedeemTx, resp.GetPayload().UsignedUnconditionalForfeitTxs, nil +} + +func (a *restClient) CompletePayment( + ctx context.Context, signedRedeemTx string, signedUnconditionalForfeitTxs []string, +) error { + req := &arkv1.CompletePaymentRequest{ + SignedRedeemTx: signedRedeemTx, + SignedUnconditionalForfeitTxs: signedUnconditionalForfeitTxs, + } + body := models.V1CompletePaymentRequest{ + SignedRedeemTx: req.GetSignedRedeemTx(), + SignedUnconditionalForfeitTxs: req.GetSignedUnconditionalForfeitTxs(), + } + _, err := a.svc.ArkServiceCompletePayment( + ark_service.NewArkServiceCompletePaymentParams().WithBody(&body), + ) + return err +} + func (a *restClient) GetRoundByID( ctx context.Context, roundID string, ) (*client.Round, error) { diff --git a/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_client.go b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_client.go index b153acd..a36fbfa 100644 --- a/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_client.go +++ b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_client.go @@ -56,6 +56,10 @@ type ClientOption func(*runtime.ClientOperation) type ClientService interface { ArkServiceClaimPayment(params *ArkServiceClaimPaymentParams, opts ...ClientOption) (*ArkServiceClaimPaymentOK, error) + ArkServiceCompletePayment(params *ArkServiceCompletePaymentParams, opts ...ClientOption) (*ArkServiceCompletePaymentOK, error) + + ArkServiceCreatePayment(params *ArkServiceCreatePaymentParams, opts ...ClientOption) (*ArkServiceCreatePaymentOK, error) + ArkServiceFinalizePayment(params *ArkServiceFinalizePaymentParams, opts ...ClientOption) (*ArkServiceFinalizePaymentOK, error) ArkServiceGetEventStream(params *ArkServiceGetEventStreamParams, opts ...ClientOption) (*ArkServiceGetEventStreamOK, error) @@ -114,6 +118,80 @@ func (a *Client) ArkServiceClaimPayment(params *ArkServiceClaimPaymentParams, op return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) } +/* +ArkServiceCompletePayment ark service complete payment API +*/ +func (a *Client) ArkServiceCompletePayment(params *ArkServiceCompletePaymentParams, opts ...ClientOption) (*ArkServiceCompletePaymentOK, error) { + // TODO: Validate the params before sending + if params == nil { + params = NewArkServiceCompletePaymentParams() + } + op := &runtime.ClientOperation{ + ID: "ArkService_CompletePayment", + Method: "POST", + PathPattern: "/v1/payment/complete", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &ArkServiceCompletePaymentReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + success, ok := result.(*ArkServiceCompletePaymentOK) + if ok { + return success, nil + } + // unexpected success response + unexpectedSuccess := result.(*ArkServiceCompletePaymentDefault) + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +ArkServiceCreatePayment ark service create payment API +*/ +func (a *Client) ArkServiceCreatePayment(params *ArkServiceCreatePaymentParams, opts ...ClientOption) (*ArkServiceCreatePaymentOK, error) { + // TODO: Validate the params before sending + if params == nil { + params = NewArkServiceCreatePaymentParams() + } + op := &runtime.ClientOperation{ + ID: "ArkService_CreatePayment", + Method: "POST", + PathPattern: "/v1/payment", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &ArkServiceCreatePaymentReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + success, ok := result.(*ArkServiceCreatePaymentOK) + if ok { + return success, nil + } + // unexpected success response + unexpectedSuccess := result.(*ArkServiceCreatePaymentDefault) + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + /* ArkServiceFinalizePayment ark service finalize payment API */ diff --git a/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_complete_payment_parameters.go b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_complete_payment_parameters.go new file mode 100644 index 0000000..6e723d4 --- /dev/null +++ b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_complete_payment_parameters.go @@ -0,0 +1,150 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ark_service + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" + + "github.com/ark-network/ark/pkg/client-sdk/client/rest/service/models" +) + +// NewArkServiceCompletePaymentParams creates a new ArkServiceCompletePaymentParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewArkServiceCompletePaymentParams() *ArkServiceCompletePaymentParams { + return &ArkServiceCompletePaymentParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewArkServiceCompletePaymentParamsWithTimeout creates a new ArkServiceCompletePaymentParams object +// with the ability to set a timeout on a request. +func NewArkServiceCompletePaymentParamsWithTimeout(timeout time.Duration) *ArkServiceCompletePaymentParams { + return &ArkServiceCompletePaymentParams{ + timeout: timeout, + } +} + +// NewArkServiceCompletePaymentParamsWithContext creates a new ArkServiceCompletePaymentParams object +// with the ability to set a context for a request. +func NewArkServiceCompletePaymentParamsWithContext(ctx context.Context) *ArkServiceCompletePaymentParams { + return &ArkServiceCompletePaymentParams{ + Context: ctx, + } +} + +// NewArkServiceCompletePaymentParamsWithHTTPClient creates a new ArkServiceCompletePaymentParams object +// with the ability to set a custom HTTPClient for a request. +func NewArkServiceCompletePaymentParamsWithHTTPClient(client *http.Client) *ArkServiceCompletePaymentParams { + return &ArkServiceCompletePaymentParams{ + HTTPClient: client, + } +} + +/* +ArkServiceCompletePaymentParams contains all the parameters to send to the API endpoint + + for the ark service complete payment operation. + + Typically these are written to a http.Request. +*/ +type ArkServiceCompletePaymentParams struct { + + // Body. + Body *models.V1CompletePaymentRequest + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the ark service complete payment params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ArkServiceCompletePaymentParams) WithDefaults() *ArkServiceCompletePaymentParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the ark service complete payment params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ArkServiceCompletePaymentParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the ark service complete payment params +func (o *ArkServiceCompletePaymentParams) WithTimeout(timeout time.Duration) *ArkServiceCompletePaymentParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the ark service complete payment params +func (o *ArkServiceCompletePaymentParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the ark service complete payment params +func (o *ArkServiceCompletePaymentParams) WithContext(ctx context.Context) *ArkServiceCompletePaymentParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the ark service complete payment params +func (o *ArkServiceCompletePaymentParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the ark service complete payment params +func (o *ArkServiceCompletePaymentParams) WithHTTPClient(client *http.Client) *ArkServiceCompletePaymentParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the ark service complete payment params +func (o *ArkServiceCompletePaymentParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the ark service complete payment params +func (o *ArkServiceCompletePaymentParams) WithBody(body *models.V1CompletePaymentRequest) *ArkServiceCompletePaymentParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the ark service complete payment params +func (o *ArkServiceCompletePaymentParams) SetBody(body *models.V1CompletePaymentRequest) { + o.Body = body +} + +// WriteToRequest writes these params to a swagger request +func (o *ArkServiceCompletePaymentParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if o.Body != nil { + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_complete_payment_responses.go b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_complete_payment_responses.go new file mode 100644 index 0000000..87a4fc4 --- /dev/null +++ b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_complete_payment_responses.go @@ -0,0 +1,185 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ark_service + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + "github.com/ark-network/ark/pkg/client-sdk/client/rest/service/models" +) + +// ArkServiceCompletePaymentReader is a Reader for the ArkServiceCompletePayment structure. +type ArkServiceCompletePaymentReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *ArkServiceCompletePaymentReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { + switch response.Code() { + case 200: + result := NewArkServiceCompletePaymentOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewArkServiceCompletePaymentDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewArkServiceCompletePaymentOK creates a ArkServiceCompletePaymentOK with default headers values +func NewArkServiceCompletePaymentOK() *ArkServiceCompletePaymentOK { + return &ArkServiceCompletePaymentOK{} +} + +/* +ArkServiceCompletePaymentOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type ArkServiceCompletePaymentOK struct { + Payload models.V1CompletePaymentResponse +} + +// IsSuccess returns true when this ark service complete payment o k response has a 2xx status code +func (o *ArkServiceCompletePaymentOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this ark service complete payment o k response has a 3xx status code +func (o *ArkServiceCompletePaymentOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this ark service complete payment o k response has a 4xx status code +func (o *ArkServiceCompletePaymentOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this ark service complete payment o k response has a 5xx status code +func (o *ArkServiceCompletePaymentOK) IsServerError() bool { + return false +} + +// IsCode returns true when this ark service complete payment o k response a status code equal to that given +func (o *ArkServiceCompletePaymentOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the ark service complete payment o k response +func (o *ArkServiceCompletePaymentOK) Code() int { + return 200 +} + +func (o *ArkServiceCompletePaymentOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/payment/complete][%d] arkServiceCompletePaymentOK %s", 200, payload) +} + +func (o *ArkServiceCompletePaymentOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/payment/complete][%d] arkServiceCompletePaymentOK %s", 200, payload) +} + +func (o *ArkServiceCompletePaymentOK) GetPayload() models.V1CompletePaymentResponse { + return o.Payload +} + +func (o *ArkServiceCompletePaymentOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewArkServiceCompletePaymentDefault creates a ArkServiceCompletePaymentDefault with default headers values +func NewArkServiceCompletePaymentDefault(code int) *ArkServiceCompletePaymentDefault { + return &ArkServiceCompletePaymentDefault{ + _statusCode: code, + } +} + +/* +ArkServiceCompletePaymentDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type ArkServiceCompletePaymentDefault struct { + _statusCode int + + Payload *models.RPCStatus +} + +// IsSuccess returns true when this ark service complete payment default response has a 2xx status code +func (o *ArkServiceCompletePaymentDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this ark service complete payment default response has a 3xx status code +func (o *ArkServiceCompletePaymentDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this ark service complete payment default response has a 4xx status code +func (o *ArkServiceCompletePaymentDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this ark service complete payment default response has a 5xx status code +func (o *ArkServiceCompletePaymentDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this ark service complete payment default response a status code equal to that given +func (o *ArkServiceCompletePaymentDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the ark service complete payment default response +func (o *ArkServiceCompletePaymentDefault) Code() int { + return o._statusCode +} + +func (o *ArkServiceCompletePaymentDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/payment/complete][%d] ArkService_CompletePayment default %s", o._statusCode, payload) +} + +func (o *ArkServiceCompletePaymentDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/payment/complete][%d] ArkService_CompletePayment default %s", o._statusCode, payload) +} + +func (o *ArkServiceCompletePaymentDefault) GetPayload() *models.RPCStatus { + return o.Payload +} + +func (o *ArkServiceCompletePaymentDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.RPCStatus) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_create_payment_parameters.go b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_create_payment_parameters.go new file mode 100644 index 0000000..fba9d2e --- /dev/null +++ b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_create_payment_parameters.go @@ -0,0 +1,150 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ark_service + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" + + "github.com/ark-network/ark/pkg/client-sdk/client/rest/service/models" +) + +// NewArkServiceCreatePaymentParams creates a new ArkServiceCreatePaymentParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewArkServiceCreatePaymentParams() *ArkServiceCreatePaymentParams { + return &ArkServiceCreatePaymentParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewArkServiceCreatePaymentParamsWithTimeout creates a new ArkServiceCreatePaymentParams object +// with the ability to set a timeout on a request. +func NewArkServiceCreatePaymentParamsWithTimeout(timeout time.Duration) *ArkServiceCreatePaymentParams { + return &ArkServiceCreatePaymentParams{ + timeout: timeout, + } +} + +// NewArkServiceCreatePaymentParamsWithContext creates a new ArkServiceCreatePaymentParams object +// with the ability to set a context for a request. +func NewArkServiceCreatePaymentParamsWithContext(ctx context.Context) *ArkServiceCreatePaymentParams { + return &ArkServiceCreatePaymentParams{ + Context: ctx, + } +} + +// NewArkServiceCreatePaymentParamsWithHTTPClient creates a new ArkServiceCreatePaymentParams object +// with the ability to set a custom HTTPClient for a request. +func NewArkServiceCreatePaymentParamsWithHTTPClient(client *http.Client) *ArkServiceCreatePaymentParams { + return &ArkServiceCreatePaymentParams{ + HTTPClient: client, + } +} + +/* +ArkServiceCreatePaymentParams contains all the parameters to send to the API endpoint + + for the ark service create payment operation. + + Typically these are written to a http.Request. +*/ +type ArkServiceCreatePaymentParams struct { + + // Body. + Body *models.V1CreatePaymentRequest + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the ark service create payment params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ArkServiceCreatePaymentParams) WithDefaults() *ArkServiceCreatePaymentParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the ark service create payment params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ArkServiceCreatePaymentParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the ark service create payment params +func (o *ArkServiceCreatePaymentParams) WithTimeout(timeout time.Duration) *ArkServiceCreatePaymentParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the ark service create payment params +func (o *ArkServiceCreatePaymentParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the ark service create payment params +func (o *ArkServiceCreatePaymentParams) WithContext(ctx context.Context) *ArkServiceCreatePaymentParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the ark service create payment params +func (o *ArkServiceCreatePaymentParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the ark service create payment params +func (o *ArkServiceCreatePaymentParams) WithHTTPClient(client *http.Client) *ArkServiceCreatePaymentParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the ark service create payment params +func (o *ArkServiceCreatePaymentParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the ark service create payment params +func (o *ArkServiceCreatePaymentParams) WithBody(body *models.V1CreatePaymentRequest) *ArkServiceCreatePaymentParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the ark service create payment params +func (o *ArkServiceCreatePaymentParams) SetBody(body *models.V1CreatePaymentRequest) { + o.Body = body +} + +// WriteToRequest writes these params to a swagger request +func (o *ArkServiceCreatePaymentParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if o.Body != nil { + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_create_payment_responses.go b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_create_payment_responses.go new file mode 100644 index 0000000..d7fb17b --- /dev/null +++ b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_create_payment_responses.go @@ -0,0 +1,187 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ark_service + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + "github.com/ark-network/ark/pkg/client-sdk/client/rest/service/models" +) + +// ArkServiceCreatePaymentReader is a Reader for the ArkServiceCreatePayment structure. +type ArkServiceCreatePaymentReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *ArkServiceCreatePaymentReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { + switch response.Code() { + case 200: + result := NewArkServiceCreatePaymentOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewArkServiceCreatePaymentDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewArkServiceCreatePaymentOK creates a ArkServiceCreatePaymentOK with default headers values +func NewArkServiceCreatePaymentOK() *ArkServiceCreatePaymentOK { + return &ArkServiceCreatePaymentOK{} +} + +/* +ArkServiceCreatePaymentOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type ArkServiceCreatePaymentOK struct { + Payload *models.V1CreatePaymentResponse +} + +// IsSuccess returns true when this ark service create payment o k response has a 2xx status code +func (o *ArkServiceCreatePaymentOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this ark service create payment o k response has a 3xx status code +func (o *ArkServiceCreatePaymentOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this ark service create payment o k response has a 4xx status code +func (o *ArkServiceCreatePaymentOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this ark service create payment o k response has a 5xx status code +func (o *ArkServiceCreatePaymentOK) IsServerError() bool { + return false +} + +// IsCode returns true when this ark service create payment o k response a status code equal to that given +func (o *ArkServiceCreatePaymentOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the ark service create payment o k response +func (o *ArkServiceCreatePaymentOK) Code() int { + return 200 +} + +func (o *ArkServiceCreatePaymentOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/payment][%d] arkServiceCreatePaymentOK %s", 200, payload) +} + +func (o *ArkServiceCreatePaymentOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/payment][%d] arkServiceCreatePaymentOK %s", 200, payload) +} + +func (o *ArkServiceCreatePaymentOK) GetPayload() *models.V1CreatePaymentResponse { + return o.Payload +} + +func (o *ArkServiceCreatePaymentOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.V1CreatePaymentResponse) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewArkServiceCreatePaymentDefault creates a ArkServiceCreatePaymentDefault with default headers values +func NewArkServiceCreatePaymentDefault(code int) *ArkServiceCreatePaymentDefault { + return &ArkServiceCreatePaymentDefault{ + _statusCode: code, + } +} + +/* +ArkServiceCreatePaymentDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type ArkServiceCreatePaymentDefault struct { + _statusCode int + + Payload *models.RPCStatus +} + +// IsSuccess returns true when this ark service create payment default response has a 2xx status code +func (o *ArkServiceCreatePaymentDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this ark service create payment default response has a 3xx status code +func (o *ArkServiceCreatePaymentDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this ark service create payment default response has a 4xx status code +func (o *ArkServiceCreatePaymentDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this ark service create payment default response has a 5xx status code +func (o *ArkServiceCreatePaymentDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this ark service create payment default response a status code equal to that given +func (o *ArkServiceCreatePaymentDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the ark service create payment default response +func (o *ArkServiceCreatePaymentDefault) Code() int { + return o._statusCode +} + +func (o *ArkServiceCreatePaymentDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/payment][%d] ArkService_CreatePayment default %s", o._statusCode, payload) +} + +func (o *ArkServiceCreatePaymentDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/payment][%d] ArkService_CreatePayment default %s", o._statusCode, payload) +} + +func (o *ArkServiceCreatePaymentDefault) GetPayload() *models.RPCStatus { + return o.Payload +} + +func (o *ArkServiceCreatePaymentDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.RPCStatus) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/pkg/client-sdk/client/rest/service/models/v1_complete_payment_request.go b/pkg/client-sdk/client/rest/service/models/v1_complete_payment_request.go new file mode 100644 index 0000000..c267a4e --- /dev/null +++ b/pkg/client-sdk/client/rest/service/models/v1_complete_payment_request.go @@ -0,0 +1,53 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1CompletePaymentRequest v1 complete payment request +// +// swagger:model v1CompletePaymentRequest +type V1CompletePaymentRequest struct { + + // signed redeem tx + SignedRedeemTx string `json:"signedRedeemTx,omitempty"` + + // signed unconditional forfeit txs + SignedUnconditionalForfeitTxs []string `json:"signedUnconditionalForfeitTxs"` +} + +// Validate validates this v1 complete payment request +func (m *V1CompletePaymentRequest) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 complete payment request based on context it is used +func (m *V1CompletePaymentRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1CompletePaymentRequest) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1CompletePaymentRequest) UnmarshalBinary(b []byte) error { + var res V1CompletePaymentRequest + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client-sdk/client/rest/service/models/v1_complete_payment_response.go b/pkg/client-sdk/client/rest/service/models/v1_complete_payment_response.go new file mode 100644 index 0000000..c2ebdf2 --- /dev/null +++ b/pkg/client-sdk/client/rest/service/models/v1_complete_payment_response.go @@ -0,0 +1,11 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// V1CompletePaymentResponse v1 complete payment response +// +// swagger:model v1CompletePaymentResponse +type V1CompletePaymentResponse interface{} diff --git a/pkg/client-sdk/client/rest/service/models/v1_create_payment_request.go b/pkg/client-sdk/client/rest/service/models/v1_create_payment_request.go new file mode 100644 index 0000000..72140d3 --- /dev/null +++ b/pkg/client-sdk/client/rest/service/models/v1_create_payment_request.go @@ -0,0 +1,183 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1CreatePaymentRequest v1 create payment request +// +// swagger:model v1CreatePaymentRequest +type V1CreatePaymentRequest struct { + + // inputs + Inputs []*V1Input `json:"inputs"` + + // outputs + Outputs []*V1Output `json:"outputs"` +} + +// Validate validates this v1 create payment request +func (m *V1CreatePaymentRequest) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateInputs(formats); err != nil { + res = append(res, err) + } + + if err := m.validateOutputs(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1CreatePaymentRequest) validateInputs(formats strfmt.Registry) error { + if swag.IsZero(m.Inputs) { // not required + return nil + } + + for i := 0; i < len(m.Inputs); i++ { + if swag.IsZero(m.Inputs[i]) { // not required + continue + } + + if m.Inputs[i] != nil { + if err := m.Inputs[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("inputs" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("inputs" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +func (m *V1CreatePaymentRequest) validateOutputs(formats strfmt.Registry) error { + if swag.IsZero(m.Outputs) { // not required + return nil + } + + for i := 0; i < len(m.Outputs); i++ { + if swag.IsZero(m.Outputs[i]) { // not required + continue + } + + if m.Outputs[i] != nil { + if err := m.Outputs[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("outputs" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("outputs" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 create payment request based on the context it is used +func (m *V1CreatePaymentRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateInputs(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateOutputs(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1CreatePaymentRequest) contextValidateInputs(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Inputs); i++ { + + if m.Inputs[i] != nil { + + if swag.IsZero(m.Inputs[i]) { // not required + return nil + } + + if err := m.Inputs[i].ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("inputs" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("inputs" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +func (m *V1CreatePaymentRequest) contextValidateOutputs(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Outputs); i++ { + + if m.Outputs[i] != nil { + + if swag.IsZero(m.Outputs[i]) { // not required + return nil + } + + if err := m.Outputs[i].ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("outputs" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("outputs" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1CreatePaymentRequest) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1CreatePaymentRequest) UnmarshalBinary(b []byte) error { + var res V1CreatePaymentRequest + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client-sdk/client/rest/service/models/v1_create_payment_response.go b/pkg/client-sdk/client/rest/service/models/v1_create_payment_response.go new file mode 100644 index 0000000..7e6bf95 --- /dev/null +++ b/pkg/client-sdk/client/rest/service/models/v1_create_payment_response.go @@ -0,0 +1,53 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1CreatePaymentResponse v1 create payment response +// +// swagger:model v1CreatePaymentResponse +type V1CreatePaymentResponse struct { + + // signed only by the ASP + SignedRedeemTx string `json:"signedRedeemTx,omitempty"` + + // usigned unconditional forfeit txs + UsignedUnconditionalForfeitTxs []string `json:"usignedUnconditionalForfeitTxs"` +} + +// Validate validates this v1 create payment response +func (m *V1CreatePaymentResponse) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 create payment response based on context it is used +func (m *V1CreatePaymentResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1CreatePaymentResponse) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1CreatePaymentResponse) UnmarshalBinary(b []byte) error { + var res V1CreatePaymentResponse + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client-sdk/client/rest/service/models/v1_pending_payment.go b/pkg/client-sdk/client/rest/service/models/v1_pending_payment.go new file mode 100644 index 0000000..76086b4 --- /dev/null +++ b/pkg/client-sdk/client/rest/service/models/v1_pending_payment.go @@ -0,0 +1,53 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PendingPayment v1 pending payment +// +// swagger:model v1PendingPayment +type V1PendingPayment struct { + + // redeem tx + RedeemTx string `json:"redeemTx,omitempty"` + + // unconditional forfeit txs + UnconditionalForfeitTxs []string `json:"unconditionalForfeitTxs"` +} + +// Validate validates this v1 pending payment +func (m *V1PendingPayment) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 pending payment based on context it is used +func (m *V1PendingPayment) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1PendingPayment) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PendingPayment) UnmarshalBinary(b []byte) error { + var res V1PendingPayment + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client-sdk/client/rest/service/models/v1_vtxo.go b/pkg/client-sdk/client/rest/service/models/v1_vtxo.go index 61c3996..ff9ef86 100644 --- a/pkg/client-sdk/client/rest/service/models/v1_vtxo.go +++ b/pkg/client-sdk/client/rest/service/models/v1_vtxo.go @@ -24,6 +24,12 @@ type V1Vtxo struct { // outpoint Outpoint *V1Input `json:"outpoint,omitempty"` + // pending + Pending bool `json:"pending,omitempty"` + + // pending data + PendingData *V1PendingPayment `json:"pendingData,omitempty"` + // pool txid PoolTxid string `json:"poolTxid,omitempty"` @@ -48,6 +54,10 @@ func (m *V1Vtxo) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validatePendingData(formats); err != nil { + res = append(res, err) + } + if err := m.validateReceiver(formats); err != nil { res = append(res, err) } @@ -77,6 +87,25 @@ func (m *V1Vtxo) validateOutpoint(formats strfmt.Registry) error { return nil } +func (m *V1Vtxo) validatePendingData(formats strfmt.Registry) error { + if swag.IsZero(m.PendingData) { // not required + return nil + } + + if m.PendingData != nil { + if err := m.PendingData.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("pendingData") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("pendingData") + } + return err + } + } + + return nil +} + func (m *V1Vtxo) validateReceiver(formats strfmt.Registry) error { if swag.IsZero(m.Receiver) { // not required return nil @@ -104,6 +133,10 @@ func (m *V1Vtxo) ContextValidate(ctx context.Context, formats strfmt.Registry) e res = append(res, err) } + if err := m.contextValidatePendingData(ctx, formats); err != nil { + res = append(res, err) + } + if err := m.contextValidateReceiver(ctx, formats); err != nil { res = append(res, err) } @@ -135,6 +168,27 @@ func (m *V1Vtxo) contextValidateOutpoint(ctx context.Context, formats strfmt.Reg return nil } +func (m *V1Vtxo) contextValidatePendingData(ctx context.Context, formats strfmt.Registry) error { + + if m.PendingData != nil { + + if swag.IsZero(m.PendingData) { // not required + return nil + } + + if err := m.PendingData.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("pendingData") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("pendingData") + } + return err + } + } + + return nil +} + func (m *V1Vtxo) contextValidateReceiver(ctx context.Context, formats strfmt.Registry) error { if m.Receiver != nil { diff --git a/pkg/client-sdk/covenant_client.go b/pkg/client-sdk/covenant_client.go index ae31ed9..ed3655a 100644 --- a/pkg/client-sdk/covenant_client.go +++ b/pkg/client-sdk/covenant_client.go @@ -547,6 +547,17 @@ func (a *covenantArkClient) CollaborativeRedeem( return poolTxID, nil } +func (a *covenantArkClient) SendAsync( + ctx context.Context, + withExpiryCoinselect bool, receivers []Receiver, +) (string, error) { + return "", fmt.Errorf("not implemented") +} + +func (a *covenantArkClient) ClaimAsync(ctx context.Context) (string, error) { + return "", fmt.Errorf("not implemented") +} + func (a *covenantArkClient) sendOnchain( ctx context.Context, receivers []Receiver, ) (string, error) { diff --git a/pkg/client-sdk/covenantless_client.go b/pkg/client-sdk/covenantless_client.go index 4b691ab..616ad18 100644 --- a/pkg/client-sdk/covenantless_client.go +++ b/pkg/client-sdk/covenantless_client.go @@ -478,7 +478,7 @@ func (a *covenantlessArkClient) UnilateralRedeem(ctx context.Context) error { vtxos := make([]client.Vtxo, 0) for _, offchainAddr := range offchainAddrs { - spendableVtxos, err := a.getVtxos(ctx, offchainAddr, false) + spendableVtxos, _, err := a.getVtxos(ctx, offchainAddr, false) if err != nil { return err } @@ -574,7 +574,7 @@ func (a *covenantlessArkClient) CollaborativeRedeem( vtxos := make([]client.Vtxo, 0) for _, offchainAddr := range offchainAddrs { - spendableVtxos, err := a.getVtxos(ctx, offchainAddr, withExpiryCoinselect) + spendableVtxos, _, err := a.getVtxos(ctx, offchainAddr, withExpiryCoinselect) if err != nil { return "", err } @@ -627,6 +627,145 @@ func (a *covenantlessArkClient) CollaborativeRedeem( return poolTxID, nil } +func (a *covenantlessArkClient) SendAsync( + ctx context.Context, + withExpiryCoinselect bool, receivers []Receiver, +) (string, error) { + if len(receivers) <= 0 { + return "", fmt.Errorf("missing receivers") + } + + for _, receiver := range receivers { + isOnchain, _, _, err := utils.DecodeReceiverAddress(receiver.To()) + if err != nil { + return "", err + } + if isOnchain { + return "", fmt.Errorf("all receiver addresses must be offchain addresses") + } + } + + offchainAddrs, _, _, err := a.wallet.GetAddresses(ctx) + if err != nil { + return "", err + } + + _, _, aspPubKey, err := common.DecodeAddress(offchainAddrs[0]) + if err != nil { + return "", err + } + + receiversOutput := make([]client.Output, 0) + sumOfReceivers := uint64(0) + + for _, receiver := range receivers { + _, _, aspKey, err := common.DecodeAddress(receiver.To()) + if err != nil { + return "", fmt.Errorf("invalid receiver address: %s", err) + } + + if !bytes.Equal( + aspPubKey.SerializeCompressed(), aspKey.SerializeCompressed(), + ) { + return "", fmt.Errorf("invalid receiver address '%s': must be associated with the connected service provider", receiver) + } + + if receiver.Amount() < DUST { + return "", fmt.Errorf("invalid amount (%d), must be greater than dust %d", receiver.Amount(), DUST) + } + + receiversOutput = append(receiversOutput, client.Output{ + Address: receiver.To(), + Amount: receiver.Amount(), + }) + sumOfReceivers += receiver.Amount() + } + + vtxos, _, err := a.getVtxos(ctx, offchainAddrs[0], withExpiryCoinselect) + if err != nil { + return "", err + } + selectedCoins, changeAmount, err := utils.CoinSelect( + vtxos, sumOfReceivers, DUST, withExpiryCoinselect, + ) + if err != nil { + return "", err + } + + if changeAmount > 0 { + changeReceiver := client.Output{ + Address: offchainAddrs[0], + Amount: changeAmount, + } + receiversOutput = append(receiversOutput, changeReceiver) + } + + inputs := make([]client.VtxoKey, 0, len(selectedCoins)) + + for _, coin := range selectedCoins { + inputs = append(inputs, coin.VtxoKey) + } + + redeemTx, unconditionalForfeitTxs, err := a.client.CreatePayment( + ctx, inputs, receiversOutput) + if err != nil { + return "", err + } + + // TODO verify the redeem tx signature + + signedUnconditionalForfeitTxs := make([]string, 0, len(unconditionalForfeitTxs)) + for _, tx := range unconditionalForfeitTxs { + signedForfeitTx, err := a.wallet.SignTransaction(ctx, a.explorer, tx) + if err != nil { + return "", err + } + + signedUnconditionalForfeitTxs = append(signedUnconditionalForfeitTxs, signedForfeitTx) + } + + signedRedeemTx, err := a.wallet.SignTransaction(ctx, a.explorer, redeemTx) + if err != nil { + return "", err + } + + if err = a.client.CompletePayment( + ctx, signedRedeemTx, signedUnconditionalForfeitTxs, + ); err != nil { + return "", err + } + + return signedRedeemTx, nil +} + +func (a *covenantlessArkClient) ClaimAsync( + ctx context.Context, +) (string, error) { + myselfOffchain, _, err := a.wallet.NewAddress(ctx, false) + if err != nil { + return "", err + } + + _, pendingVtxos, err := a.getVtxos(ctx, myselfOffchain, false) + if err != nil { + return "", err + } + + var pendingBalance uint64 + for _, vtxo := range pendingVtxos { + pendingBalance += vtxo.Amount + } + if pendingBalance == 0 { + return "", nil + } + + receiver := client.Output{ + Address: myselfOffchain, + Amount: pendingBalance, + } + return a.selfTransferAllPendingPayments(ctx, pendingVtxos, receiver) +} + func (a *covenantlessArkClient) sendOnchain( ctx context.Context, receivers []Receiver, ) (string, error) { @@ -817,7 +956,7 @@ func (a *covenantlessArkClient) sendOffchain( vtxos := make([]client.Vtxo, 0) for _, offchainAddr := range offchainAddrs { - spendableVtxos, err := a.getVtxos(ctx, offchainAddr, withExpiryCoinselect) + spendableVtxos, _, err := a.getVtxos(ctx, offchainAddr, withExpiryCoinselect) if err != nil { return "", err } @@ -1394,16 +1533,20 @@ func (a *covenantlessArkClient) getRedeemBranches( return redeemBranches, nil } +// TODO (@louisinger): return pending balance in dedicated map. +// Currently, the returned balance is calculated from both spendable and +// pending vtxos. func (a *covenantlessArkClient) getOffchainBalance( ctx context.Context, addr string, computeVtxoExpiration bool, ) (uint64, map[int64]uint64, error) { amountByExpiration := make(map[int64]uint64, 0) - vtxos, err := a.getVtxos(ctx, addr, computeVtxoExpiration) + spendableVtxos, pendingVtxos, err := a.getVtxos(ctx, addr, computeVtxoExpiration) if err != nil { return 0, nil, err } var balance uint64 + vtxos := append(spendableVtxos, pendingVtxos...) for _, vtxo := range vtxos { balance += vtxo.Amount @@ -1423,28 +1566,38 @@ func (a *covenantlessArkClient) getOffchainBalance( func (a *covenantlessArkClient) getVtxos( ctx context.Context, addr string, computeVtxoExpiration bool, -) ([]client.Vtxo, error) { +) ([]client.Vtxo, []client.Vtxo, error) { vtxos, _, err := a.client.ListVtxos(ctx, addr) if err != nil { - return nil, err + return nil, nil, err + } + + pendingVtxos := make([]client.Vtxo, 0) + spendableVtxos := make([]client.Vtxo, 0) + for _, vtxo := range vtxos { + if vtxo.Pending { + pendingVtxos = append(pendingVtxos, vtxo) + continue + } + spendableVtxos = append(spendableVtxos, vtxo) } if !computeVtxoExpiration { - return vtxos, nil + return spendableVtxos, pendingVtxos, nil } - redeemBranches, err := a.getRedeemBranches(ctx, vtxos) + redeemBranches, err := a.getRedeemBranches(ctx, spendableVtxos) if err != nil { - return nil, err + return nil, nil, err } for vtxoTxid, branch := range redeemBranches { expiration, err := branch.ExpiresAt() if err != nil { - return nil, err + return nil, nil, err } - for i, vtxo := range vtxos { + for i, vtxo := range spendableVtxos { if vtxo.Txid == vtxoTxid { vtxos[i].ExpiresAt = expiration break @@ -1452,5 +1605,35 @@ func (a *covenantlessArkClient) getVtxos( } } - return vtxos, nil + return spendableVtxos, pendingVtxos, nil +} + +func (a *covenantlessArkClient) selfTransferAllPendingPayments( + ctx context.Context, pendingVtxos []client.Vtxo, myself client.Output, +) (string, error) { + inputs := make([]client.VtxoKey, 0, len(pendingVtxos)) + + for _, coin := range pendingVtxos { + inputs = append(inputs, coin.VtxoKey) + } + + outputs := []client.Output{myself} + + paymentID, err := a.client.RegisterPayment(ctx, inputs) + if err != nil { + return "", err + } + + if err := a.client.ClaimPayment(ctx, paymentID, outputs); err != nil { + return "", err + } + + roundTxid, err := a.handleRoundStream( + ctx, paymentID, pendingVtxos, outputs, + ) + if err != nil { + return "", err + } + + return roundTxid, nil } diff --git a/pkg/client-sdk/example/covenantless/alice_to_bob.go b/pkg/client-sdk/example/covenantless/alice_to_bob.go index 312cba4..a8c0e80 100644 --- a/pkg/client-sdk/example/covenantless/alice_to_bob.go +++ b/pkg/client-sdk/example/covenantless/alice_to_bob.go @@ -106,12 +106,11 @@ func main() { fmt.Println("") log.Infof("alice is sending %d sats to bob offchain...", amount) - txid, err = aliceArkClient.SendOffChain(ctx, false, receivers) - if err != nil { + if _, err = aliceArkClient.SendAsync(ctx, false, receivers); err != nil { log.Fatal(err) } - log.Infof("payment completed in round tx: %s", txid) + log.Info("payment completed out of round") if err := generateBlock(); err != nil { log.Fatal(err) @@ -135,6 +134,15 @@ func main() { log.Infof("bob onchain balance: %d", bobBalance.OnchainBalance.SpendableAmount) log.Infof("bob offchain balance: %d", bobBalance.OffchainBalance.Total) + + fmt.Println("") + log.Info("bob is claiming the incoming payment...") + roundTxid, err := bobArkClient.ClaimAsync(ctx) + if err != nil { + log.Fatal(err) + } + + log.Infof("bob claimed the incoming payment in round %s", roundTxid) } func setupArkClient() (arksdk.ArkClient, error) { diff --git a/pkg/client-sdk/explorer/explorer.go b/pkg/client-sdk/explorer/explorer.go index 3e94da2..fba9b71 100644 --- a/pkg/client-sdk/explorer/explorer.go +++ b/pkg/client-sdk/explorer/explorer.go @@ -15,7 +15,6 @@ import ( "github.com/ark-network/ark/pkg/client-sdk/internal/utils" "github.com/btcsuite/btcd/btcutil/psbt" "github.com/btcsuite/btcd/wire" - log "github.com/sirupsen/logrus" "github.com/vulpemventures/go-elements/psetv2" "github.com/vulpemventures/go-elements/transaction" ) @@ -97,8 +96,7 @@ func (e *explorerSvc) GetFeeRate() (float64, error) { } if len(response) == 0 { - log.Debug("empty fee-estimates response, default to 2 sat/vbyte") - return 2, nil + return 1, nil } return response["1"], nil diff --git a/pkg/client-sdk/wallet/singlekey/bitcoin_wallet.go b/pkg/client-sdk/wallet/singlekey/bitcoin_wallet.go index f969b5d..698fb7f 100644 --- a/pkg/client-sdk/wallet/singlekey/bitcoin_wallet.go +++ b/pkg/client-sdk/wallet/singlekey/bitcoin_wallet.go @@ -201,7 +201,7 @@ func (s *bitcoinWallet) SignTransaction( switch c := closure.(type) { case *bitcointree.CSVSigClosure: sign = bytes.Equal(c.Pubkey.SerializeCompressed()[1:], pubkey.SerializeCompressed()[1:]) - case *bitcointree.ForfeitClosure: + case *bitcointree.MultisigClosure: sign = bytes.Equal(c.Pubkey.SerializeCompressed()[1:], pubkey.SerializeCompressed()[1:]) } diff --git a/server/Makefile b/server/Makefile index be23e60..810967e 100755 --- a/server/Makefile +++ b/server/Makefile @@ -33,13 +33,16 @@ lint: ## run: run in dev mode run: clean @echo "Running arkd in dev mode..." - @export ARK_WALLET_ADDR=localhost:18000; \ + @export ARK_NEUTRINO_PEER=localhost:18444; \ export ARK_ROUND_INTERVAL=10; \ export ARK_LOG_LEVEL=5; \ - export ARK_NETWORK=liquidregtest; \ + export ARK_NETWORK=regtest; \ export ARK_PORT=8080; \ export ARK_NO_TLS=true; \ export ARK_NO_MACAROONS=true; \ + export ARK_TX_BUILDER_TYPE=covenantless; \ + export ARK_ESPLORA_URL=http://localhost:3000; \ + export ARK_MIN_RELAY_FEE=200; \ go run ./cmd/arkd ## test: runs unit and component tests diff --git a/server/api-spec/openapi/swagger/ark/v1/service.swagger.json b/server/api-spec/openapi/swagger/ark/v1/service.swagger.json index df2f846..5c94faa 100644 --- a/server/api-spec/openapi/swagger/ark/v1/service.swagger.json +++ b/server/api-spec/openapi/swagger/ark/v1/service.swagger.json @@ -101,6 +101,38 @@ ] } }, + "/v1/payment": { + "post": { + "operationId": "ArkService_CreatePayment", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1CreatePaymentResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1CreatePaymentRequest" + } + } + ], + "tags": [ + "ArkService" + ] + } + }, "/v1/payment/claim": { "post": { "operationId": "ArkService_ClaimPayment", @@ -133,6 +165,38 @@ ] } }, + "/v1/payment/complete": { + "post": { + "operationId": "ArkService_CompletePayment", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1CompletePaymentResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1CompletePaymentRequest" + } + } + ], + "tags": [ + "ArkService" + ] + } + }, "/v1/payment/finalize": { "post": { "operationId": "ArkService_FinalizePayment", @@ -368,6 +432,57 @@ "v1ClaimPaymentResponse": { "type": "object" }, + "v1CompletePaymentRequest": { + "type": "object", + "properties": { + "signedRedeemTx": { + "type": "string" + }, + "signedUnconditionalForfeitTxs": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "v1CompletePaymentResponse": { + "type": "object" + }, + "v1CreatePaymentRequest": { + "type": "object", + "properties": { + "inputs": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Input" + } + }, + "outputs": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Output" + } + } + } + }, + "v1CreatePaymentResponse": { + "type": "object", + "properties": { + "signedRedeemTx": { + "type": "string", + "title": "signed only by the ASP" + }, + "usignedUnconditionalForfeitTxs": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "v1FinalizePaymentRequest": { "type": "object", "properties": { @@ -517,6 +632,20 @@ } } }, + "v1PendingPayment": { + "type": "object", + "properties": { + "redeemTx": { + "type": "string" + }, + "unconditionalForfeitTxs": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "v1PingResponse": { "type": "object", "properties": { @@ -696,6 +825,12 @@ }, "swept": { "type": "boolean" + }, + "pending": { + "type": "boolean" + }, + "pendingData": { + "$ref": "#/definitions/v1PendingPayment" } } } diff --git a/server/api-spec/openapi/swagger/clark/v1/service.swagger.json b/server/api-spec/openapi/swagger/clark/v1/service.swagger.json new file mode 100644 index 0000000..bac48a8 --- /dev/null +++ b/server/api-spec/openapi/swagger/clark/v1/service.swagger.json @@ -0,0 +1,820 @@ +{ + "swagger": "2.0", + "info": { + "title": "clark/v1/service.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "ArkService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/events": { + "get": { + "operationId": "ArkService_GetEventStream", + "responses": { + "200": { + "description": "A successful response.(streaming responses)", + "schema": { + "type": "object", + "properties": { + "result": { + "$ref": "#/definitions/v1GetEventStreamResponse" + }, + "error": { + "$ref": "#/definitions/rpcStatus" + } + }, + "title": "Stream result of v1GetEventStreamResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "ArkService" + ] + } + }, + "/v1/info": { + "get": { + "operationId": "ArkService_GetInfo", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetInfoResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "ArkService" + ] + } + }, + "/v1/onboard": { + "post": { + "operationId": "ArkService_Onboard", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1OnboardResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1OnboardRequest" + } + } + ], + "tags": [ + "ArkService" + ] + } + }, + "/v1/payment/async": { + "post": { + "operationId": "ArkService_CreateAsyncPayment", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1CreateAsyncPaymentResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1CreateAsyncPaymentRequest" + } + } + ], + "tags": [ + "ArkService" + ] + } + }, + "/v1/payment/async/complete": { + "post": { + "operationId": "ArkService_CompleteAsyncPayment", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1CompleteAsyncPaymentResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1CompleteAsyncPaymentRequest" + } + } + ], + "tags": [ + "ArkService" + ] + } + }, + "/v1/payment/claim": { + "post": { + "operationId": "ArkService_ClaimPayment", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ClaimPaymentResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1ClaimPaymentRequest" + } + } + ], + "tags": [ + "ArkService" + ] + } + }, + "/v1/payment/finalize": { + "post": { + "operationId": "ArkService_FinalizePayment", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1FinalizePaymentResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1FinalizePaymentRequest" + } + } + ], + "tags": [ + "ArkService" + ] + } + }, + "/v1/payment/register": { + "post": { + "operationId": "ArkService_RegisterPayment", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1RegisterPaymentResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1RegisterPaymentRequest" + } + } + ], + "tags": [ + "ArkService" + ] + } + }, + "/v1/ping/{paymentId}": { + "get": { + "operationId": "ArkService_Ping", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1PingResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "paymentId", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "ArkService" + ] + } + }, + "/v1/round/id/{id}": { + "get": { + "operationId": "ArkService_GetRoundById", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetRoundByIdResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "ArkService" + ] + } + }, + "/v1/round/{txid}": { + "get": { + "summary": "TODO BTC: signTree rpc", + "operationId": "ArkService_GetRound", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetRoundResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "txid", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "ArkService" + ] + } + }, + "/v1/vtxos/{address}": { + "get": { + "operationId": "ArkService_ListVtxos", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListVtxosResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "address", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "ArkService" + ] + } + } + }, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "v1ClaimPaymentRequest": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Mocks wabisabi's credentials." + }, + "outputs": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Output" + }, + "description": "List of receivers for a registered payment." + } + } + }, + "v1ClaimPaymentResponse": { + "type": "object" + }, + "v1CompleteAsyncPaymentRequest": { + "type": "object", + "properties": { + "signedSenderTx": { + "type": "string" + }, + "signedReceiverTx": { + "type": "string" + }, + "signedUnconditionalForfeitTx": { + "type": "string" + } + } + }, + "v1CompleteAsyncPaymentResponse": { + "type": "object", + "properties": { + "senderTx": { + "type": "string" + }, + "receiverTx": { + "type": "string" + }, + "unconditionalForfeitTx": { + "type": "string" + } + } + }, + "v1CreateAsyncPaymentRequest": { + "type": "object", + "properties": { + "input": { + "$ref": "#/definitions/v1Input" + }, + "receiverPubkey": { + "type": "string" + } + } + }, + "v1CreateAsyncPaymentResponse": { + "type": "object", + "properties": { + "unsignedSenderTx": { + "type": "string" + }, + "unsignedReceiverTx": { + "type": "string" + }, + "usignedUnconditionalForfeitTx": { + "type": "string" + } + } + }, + "v1FinalizePaymentRequest": { + "type": "object", + "properties": { + "signedForfeitTxs": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Forfeit txs signed by the user." + } + } + }, + "v1FinalizePaymentResponse": { + "type": "object" + }, + "v1GetEventStreamResponse": { + "type": "object", + "properties": { + "roundFinalization": { + "$ref": "#/definitions/v1RoundFinalizationEvent", + "title": "TODO: BTC add \"signTree\" event" + }, + "roundFinalized": { + "$ref": "#/definitions/v1RoundFinalizedEvent" + }, + "roundFailed": { + "$ref": "#/definitions/v1RoundFailed" + } + } + }, + "v1GetInfoResponse": { + "type": "object", + "properties": { + "pubkey": { + "type": "string" + }, + "roundLifetime": { + "type": "string", + "format": "int64" + }, + "unilateralExitDelay": { + "type": "string", + "format": "int64" + }, + "roundInterval": { + "type": "string", + "format": "int64" + }, + "network": { + "type": "string" + }, + "minRelayFee": { + "type": "string", + "format": "int64" + } + } + }, + "v1GetRoundByIdResponse": { + "type": "object", + "properties": { + "round": { + "$ref": "#/definitions/v1Round" + } + } + }, + "v1GetRoundResponse": { + "type": "object", + "properties": { + "round": { + "$ref": "#/definitions/v1Round" + } + } + }, + "v1Input": { + "type": "object", + "properties": { + "txid": { + "type": "string" + }, + "vout": { + "type": "integer", + "format": "int64" + } + } + }, + "v1ListVtxosResponse": { + "type": "object", + "properties": { + "spendableVtxos": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Vtxo" + } + }, + "spentVtxos": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Vtxo" + } + } + } + }, + "v1Node": { + "type": "object", + "properties": { + "txid": { + "type": "string" + }, + "tx": { + "type": "string" + }, + "parentTxid": { + "type": "string" + } + } + }, + "v1OnboardRequest": { + "type": "object", + "properties": { + "boardingTx": { + "type": "string" + }, + "congestionTree": { + "$ref": "#/definitions/v1Tree" + }, + "userPubkey": { + "type": "string" + } + } + }, + "v1OnboardResponse": { + "type": "object" + }, + "v1Output": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "Either the offchain or onchain address." + }, + "amount": { + "type": "string", + "format": "uint64", + "description": "Amount to send in satoshis." + } + } + }, + "v1PingResponse": { + "type": "object", + "properties": { + "forfeitTxs": { + "type": "array", + "items": { + "type": "string" + } + }, + "event": { + "$ref": "#/definitions/v1RoundFinalizationEvent" + } + } + }, + "v1RegisterPaymentRequest": { + "type": "object", + "properties": { + "inputs": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Input" + } + } + } + }, + "v1RegisterPaymentResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Mocks wabisabi's credentials." + } + } + }, + "v1Round": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "start": { + "type": "string", + "format": "int64" + }, + "end": { + "type": "string", + "format": "int64" + }, + "poolTx": { + "type": "string" + }, + "congestionTree": { + "$ref": "#/definitions/v1Tree" + }, + "forfeitTxs": { + "type": "array", + "items": { + "type": "string" + } + }, + "connectors": { + "type": "array", + "items": { + "type": "string" + } + }, + "stage": { + "$ref": "#/definitions/v1RoundStage" + } + } + }, + "v1RoundFailed": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "reason": { + "type": "string" + } + } + }, + "v1RoundFinalizationEvent": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "poolTx": { + "type": "string" + }, + "forfeitTxs": { + "type": "array", + "items": { + "type": "string" + } + }, + "congestionTree": { + "$ref": "#/definitions/v1Tree" + }, + "connectors": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "v1RoundFinalizedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "poolTxid": { + "type": "string" + } + } + }, + "v1RoundStage": { + "type": "string", + "enum": [ + "ROUND_STAGE_UNSPECIFIED", + "ROUND_STAGE_REGISTRATION", + "ROUND_STAGE_FINALIZATION", + "ROUND_STAGE_FINALIZED", + "ROUND_STAGE_FAILED" + ], + "default": "ROUND_STAGE_UNSPECIFIED" + }, + "v1Tree": { + "type": "object", + "properties": { + "levels": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1TreeLevel" + } + } + } + }, + "v1TreeLevel": { + "type": "object", + "properties": { + "nodes": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Node" + } + } + } + }, + "v1Vtxo": { + "type": "object", + "properties": { + "outpoint": { + "$ref": "#/definitions/v1Input" + }, + "receiver": { + "$ref": "#/definitions/v1Output" + }, + "spent": { + "type": "boolean" + }, + "poolTxid": { + "type": "string" + }, + "spentBy": { + "type": "string" + }, + "expireAt": { + "type": "string", + "format": "int64" + }, + "swept": { + "type": "boolean" + } + } + } + } +} diff --git a/server/api-spec/protobuf/ark/v1/service.proto b/server/api-spec/protobuf/ark/v1/service.proto index a1406d2..548ea55 100755 --- a/server/api-spec/protobuf/ark/v1/service.proto +++ b/server/api-spec/protobuf/ark/v1/service.proto @@ -60,8 +60,35 @@ service ArkService { body: "*" }; } + rpc CreatePayment(CreatePaymentRequest) returns (CreatePaymentResponse) { + option (google.api.http) = { + post: "/v1/payment" + body: "*" + }; + } + rpc CompletePayment(CompletePaymentRequest) returns (CompletePaymentResponse) { + option (google.api.http) = { + post: "/v1/payment/complete" + body: "*" + }; + } } +message CreatePaymentRequest { + repeated Input inputs = 1; + repeated Output outputs = 2; +} +message CreatePaymentResponse { + string signed_redeem_tx = 1; // signed only by the ASP + repeated string usigned_unconditional_forfeit_txs = 2; +} + +message CompletePaymentRequest { + string signed_redeem_tx = 1; + repeated string signed_unconditional_forfeit_txs = 2; +} +message CompletePaymentResponse {} + message RegisterPaymentRequest { repeated Input inputs = 1; } @@ -217,4 +244,11 @@ message Vtxo { string spent_by = 5; int64 expire_at = 6; bool swept = 7; + bool pending = 8; + PendingPayment pending_data = 9; +} + +message PendingPayment { + string redeem_tx = 1; + repeated string unconditional_forfeit_txs =2; } \ No newline at end of file diff --git a/server/api-spec/protobuf/gen/ark/v1/service.pb.go b/server/api-spec/protobuf/gen/ark/v1/service.pb.go index 6fdebd3..af9e91f 100644 --- a/server/api-spec/protobuf/gen/ark/v1/service.pb.go +++ b/server/api-spec/protobuf/gen/ark/v1/service.pb.go @@ -76,6 +76,209 @@ func (RoundStage) EnumDescriptor() ([]byte, []int) { return file_ark_v1_service_proto_rawDescGZIP(), []int{0} } +type CreatePaymentRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Inputs []*Input `protobuf:"bytes,1,rep,name=inputs,proto3" json:"inputs,omitempty"` + Outputs []*Output `protobuf:"bytes,2,rep,name=outputs,proto3" json:"outputs,omitempty"` +} + +func (x *CreatePaymentRequest) Reset() { + *x = CreatePaymentRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_ark_v1_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreatePaymentRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreatePaymentRequest) ProtoMessage() {} + +func (x *CreatePaymentRequest) ProtoReflect() protoreflect.Message { + mi := &file_ark_v1_service_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreatePaymentRequest.ProtoReflect.Descriptor instead. +func (*CreatePaymentRequest) Descriptor() ([]byte, []int) { + return file_ark_v1_service_proto_rawDescGZIP(), []int{0} +} + +func (x *CreatePaymentRequest) GetInputs() []*Input { + if x != nil { + return x.Inputs + } + return nil +} + +func (x *CreatePaymentRequest) GetOutputs() []*Output { + if x != nil { + return x.Outputs + } + return nil +} + +type CreatePaymentResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SignedRedeemTx string `protobuf:"bytes,1,opt,name=signed_redeem_tx,json=signedRedeemTx,proto3" json:"signed_redeem_tx,omitempty"` // signed only by the ASP + UsignedUnconditionalForfeitTxs []string `protobuf:"bytes,2,rep,name=usigned_unconditional_forfeit_txs,json=usignedUnconditionalForfeitTxs,proto3" json:"usigned_unconditional_forfeit_txs,omitempty"` +} + +func (x *CreatePaymentResponse) Reset() { + *x = CreatePaymentResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_ark_v1_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreatePaymentResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreatePaymentResponse) ProtoMessage() {} + +func (x *CreatePaymentResponse) ProtoReflect() protoreflect.Message { + mi := &file_ark_v1_service_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreatePaymentResponse.ProtoReflect.Descriptor instead. +func (*CreatePaymentResponse) Descriptor() ([]byte, []int) { + return file_ark_v1_service_proto_rawDescGZIP(), []int{1} +} + +func (x *CreatePaymentResponse) GetSignedRedeemTx() string { + if x != nil { + return x.SignedRedeemTx + } + return "" +} + +func (x *CreatePaymentResponse) GetUsignedUnconditionalForfeitTxs() []string { + if x != nil { + return x.UsignedUnconditionalForfeitTxs + } + return nil +} + +type CompletePaymentRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SignedRedeemTx string `protobuf:"bytes,1,opt,name=signed_redeem_tx,json=signedRedeemTx,proto3" json:"signed_redeem_tx,omitempty"` + SignedUnconditionalForfeitTxs []string `protobuf:"bytes,2,rep,name=signed_unconditional_forfeit_txs,json=signedUnconditionalForfeitTxs,proto3" json:"signed_unconditional_forfeit_txs,omitempty"` +} + +func (x *CompletePaymentRequest) Reset() { + *x = CompletePaymentRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_ark_v1_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CompletePaymentRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompletePaymentRequest) ProtoMessage() {} + +func (x *CompletePaymentRequest) ProtoReflect() protoreflect.Message { + mi := &file_ark_v1_service_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompletePaymentRequest.ProtoReflect.Descriptor instead. +func (*CompletePaymentRequest) Descriptor() ([]byte, []int) { + return file_ark_v1_service_proto_rawDescGZIP(), []int{2} +} + +func (x *CompletePaymentRequest) GetSignedRedeemTx() string { + if x != nil { + return x.SignedRedeemTx + } + return "" +} + +func (x *CompletePaymentRequest) GetSignedUnconditionalForfeitTxs() []string { + if x != nil { + return x.SignedUnconditionalForfeitTxs + } + return nil +} + +type CompletePaymentResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *CompletePaymentResponse) Reset() { + *x = CompletePaymentResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_ark_v1_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CompletePaymentResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompletePaymentResponse) ProtoMessage() {} + +func (x *CompletePaymentResponse) ProtoReflect() protoreflect.Message { + mi := &file_ark_v1_service_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompletePaymentResponse.ProtoReflect.Descriptor instead. +func (*CompletePaymentResponse) Descriptor() ([]byte, []int) { + return file_ark_v1_service_proto_rawDescGZIP(), []int{3} +} + type RegisterPaymentRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -87,7 +290,7 @@ type RegisterPaymentRequest struct { func (x *RegisterPaymentRequest) Reset() { *x = RegisterPaymentRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[0] + mi := &file_ark_v1_service_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -100,7 +303,7 @@ func (x *RegisterPaymentRequest) String() string { func (*RegisterPaymentRequest) ProtoMessage() {} func (x *RegisterPaymentRequest) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[0] + mi := &file_ark_v1_service_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -113,7 +316,7 @@ func (x *RegisterPaymentRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterPaymentRequest.ProtoReflect.Descriptor instead. func (*RegisterPaymentRequest) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{0} + return file_ark_v1_service_proto_rawDescGZIP(), []int{4} } func (x *RegisterPaymentRequest) GetInputs() []*Input { @@ -135,7 +338,7 @@ type RegisterPaymentResponse struct { func (x *RegisterPaymentResponse) Reset() { *x = RegisterPaymentResponse{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[1] + mi := &file_ark_v1_service_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -148,7 +351,7 @@ func (x *RegisterPaymentResponse) String() string { func (*RegisterPaymentResponse) ProtoMessage() {} func (x *RegisterPaymentResponse) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[1] + mi := &file_ark_v1_service_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -161,7 +364,7 @@ func (x *RegisterPaymentResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterPaymentResponse.ProtoReflect.Descriptor instead. func (*RegisterPaymentResponse) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{1} + return file_ark_v1_service_proto_rawDescGZIP(), []int{5} } func (x *RegisterPaymentResponse) GetId() string { @@ -185,7 +388,7 @@ type ClaimPaymentRequest struct { func (x *ClaimPaymentRequest) Reset() { *x = ClaimPaymentRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[2] + mi := &file_ark_v1_service_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -198,7 +401,7 @@ func (x *ClaimPaymentRequest) String() string { func (*ClaimPaymentRequest) ProtoMessage() {} func (x *ClaimPaymentRequest) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[2] + mi := &file_ark_v1_service_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -211,7 +414,7 @@ func (x *ClaimPaymentRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ClaimPaymentRequest.ProtoReflect.Descriptor instead. func (*ClaimPaymentRequest) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{2} + return file_ark_v1_service_proto_rawDescGZIP(), []int{6} } func (x *ClaimPaymentRequest) GetId() string { @@ -237,7 +440,7 @@ type ClaimPaymentResponse struct { func (x *ClaimPaymentResponse) Reset() { *x = ClaimPaymentResponse{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[3] + mi := &file_ark_v1_service_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -250,7 +453,7 @@ func (x *ClaimPaymentResponse) String() string { func (*ClaimPaymentResponse) ProtoMessage() {} func (x *ClaimPaymentResponse) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[3] + mi := &file_ark_v1_service_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -263,7 +466,7 @@ func (x *ClaimPaymentResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ClaimPaymentResponse.ProtoReflect.Descriptor instead. func (*ClaimPaymentResponse) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{3} + return file_ark_v1_service_proto_rawDescGZIP(), []int{7} } type FinalizePaymentRequest struct { @@ -278,7 +481,7 @@ type FinalizePaymentRequest struct { func (x *FinalizePaymentRequest) Reset() { *x = FinalizePaymentRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[4] + mi := &file_ark_v1_service_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -291,7 +494,7 @@ func (x *FinalizePaymentRequest) String() string { func (*FinalizePaymentRequest) ProtoMessage() {} func (x *FinalizePaymentRequest) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[4] + mi := &file_ark_v1_service_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -304,7 +507,7 @@ func (x *FinalizePaymentRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use FinalizePaymentRequest.ProtoReflect.Descriptor instead. func (*FinalizePaymentRequest) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{4} + return file_ark_v1_service_proto_rawDescGZIP(), []int{8} } func (x *FinalizePaymentRequest) GetSignedForfeitTxs() []string { @@ -323,7 +526,7 @@ type FinalizePaymentResponse struct { func (x *FinalizePaymentResponse) Reset() { *x = FinalizePaymentResponse{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[5] + mi := &file_ark_v1_service_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -336,7 +539,7 @@ func (x *FinalizePaymentResponse) String() string { func (*FinalizePaymentResponse) ProtoMessage() {} func (x *FinalizePaymentResponse) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[5] + mi := &file_ark_v1_service_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -349,7 +552,7 @@ func (x *FinalizePaymentResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use FinalizePaymentResponse.ProtoReflect.Descriptor instead. func (*FinalizePaymentResponse) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{5} + return file_ark_v1_service_proto_rawDescGZIP(), []int{9} } type GetRoundRequest struct { @@ -363,7 +566,7 @@ type GetRoundRequest struct { func (x *GetRoundRequest) Reset() { *x = GetRoundRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[6] + mi := &file_ark_v1_service_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -376,7 +579,7 @@ func (x *GetRoundRequest) String() string { func (*GetRoundRequest) ProtoMessage() {} func (x *GetRoundRequest) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[6] + mi := &file_ark_v1_service_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -389,7 +592,7 @@ func (x *GetRoundRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetRoundRequest.ProtoReflect.Descriptor instead. func (*GetRoundRequest) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{6} + return file_ark_v1_service_proto_rawDescGZIP(), []int{10} } func (x *GetRoundRequest) GetTxid() string { @@ -410,7 +613,7 @@ type GetRoundResponse struct { func (x *GetRoundResponse) Reset() { *x = GetRoundResponse{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[7] + mi := &file_ark_v1_service_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -423,7 +626,7 @@ func (x *GetRoundResponse) String() string { func (*GetRoundResponse) ProtoMessage() {} func (x *GetRoundResponse) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[7] + mi := &file_ark_v1_service_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -436,7 +639,7 @@ func (x *GetRoundResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetRoundResponse.ProtoReflect.Descriptor instead. func (*GetRoundResponse) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{7} + return file_ark_v1_service_proto_rawDescGZIP(), []int{11} } func (x *GetRoundResponse) GetRound() *Round { @@ -457,7 +660,7 @@ type GetRoundByIdRequest struct { func (x *GetRoundByIdRequest) Reset() { *x = GetRoundByIdRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[8] + mi := &file_ark_v1_service_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -470,7 +673,7 @@ func (x *GetRoundByIdRequest) String() string { func (*GetRoundByIdRequest) ProtoMessage() {} func (x *GetRoundByIdRequest) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[8] + mi := &file_ark_v1_service_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -483,7 +686,7 @@ func (x *GetRoundByIdRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetRoundByIdRequest.ProtoReflect.Descriptor instead. func (*GetRoundByIdRequest) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{8} + return file_ark_v1_service_proto_rawDescGZIP(), []int{12} } func (x *GetRoundByIdRequest) GetId() string { @@ -504,7 +707,7 @@ type GetRoundByIdResponse struct { func (x *GetRoundByIdResponse) Reset() { *x = GetRoundByIdResponse{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[9] + mi := &file_ark_v1_service_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -517,7 +720,7 @@ func (x *GetRoundByIdResponse) String() string { func (*GetRoundByIdResponse) ProtoMessage() {} func (x *GetRoundByIdResponse) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[9] + mi := &file_ark_v1_service_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -530,7 +733,7 @@ func (x *GetRoundByIdResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetRoundByIdResponse.ProtoReflect.Descriptor instead. func (*GetRoundByIdResponse) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{9} + return file_ark_v1_service_proto_rawDescGZIP(), []int{13} } func (x *GetRoundByIdResponse) GetRound() *Round { @@ -549,7 +752,7 @@ type GetEventStreamRequest struct { func (x *GetEventStreamRequest) Reset() { *x = GetEventStreamRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[10] + mi := &file_ark_v1_service_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -562,7 +765,7 @@ func (x *GetEventStreamRequest) String() string { func (*GetEventStreamRequest) ProtoMessage() {} func (x *GetEventStreamRequest) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[10] + mi := &file_ark_v1_service_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -575,7 +778,7 @@ func (x *GetEventStreamRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetEventStreamRequest.ProtoReflect.Descriptor instead. func (*GetEventStreamRequest) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{10} + return file_ark_v1_service_proto_rawDescGZIP(), []int{14} } type GetEventStreamResponse struct { @@ -594,7 +797,7 @@ type GetEventStreamResponse struct { func (x *GetEventStreamResponse) Reset() { *x = GetEventStreamResponse{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[11] + mi := &file_ark_v1_service_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -607,7 +810,7 @@ func (x *GetEventStreamResponse) String() string { func (*GetEventStreamResponse) ProtoMessage() {} func (x *GetEventStreamResponse) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[11] + mi := &file_ark_v1_service_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -620,7 +823,7 @@ func (x *GetEventStreamResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetEventStreamResponse.ProtoReflect.Descriptor instead. func (*GetEventStreamResponse) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{11} + return file_ark_v1_service_proto_rawDescGZIP(), []int{15} } func (m *GetEventStreamResponse) GetEvent() isGetEventStreamResponse_Event { @@ -685,7 +888,7 @@ type PingRequest struct { func (x *PingRequest) Reset() { *x = PingRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[12] + mi := &file_ark_v1_service_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -698,7 +901,7 @@ func (x *PingRequest) String() string { func (*PingRequest) ProtoMessage() {} func (x *PingRequest) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[12] + mi := &file_ark_v1_service_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -711,7 +914,7 @@ func (x *PingRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PingRequest.ProtoReflect.Descriptor instead. func (*PingRequest) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{12} + return file_ark_v1_service_proto_rawDescGZIP(), []int{16} } func (x *PingRequest) GetPaymentId() string { @@ -733,7 +936,7 @@ type PingResponse struct { func (x *PingResponse) Reset() { *x = PingResponse{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[13] + mi := &file_ark_v1_service_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -746,7 +949,7 @@ func (x *PingResponse) String() string { func (*PingResponse) ProtoMessage() {} func (x *PingResponse) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[13] + mi := &file_ark_v1_service_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -759,7 +962,7 @@ func (x *PingResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PingResponse.ProtoReflect.Descriptor instead. func (*PingResponse) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{13} + return file_ark_v1_service_proto_rawDescGZIP(), []int{17} } func (x *PingResponse) GetForfeitTxs() []string { @@ -787,7 +990,7 @@ type ListVtxosRequest struct { func (x *ListVtxosRequest) Reset() { *x = ListVtxosRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[14] + mi := &file_ark_v1_service_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -800,7 +1003,7 @@ func (x *ListVtxosRequest) String() string { func (*ListVtxosRequest) ProtoMessage() {} func (x *ListVtxosRequest) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[14] + mi := &file_ark_v1_service_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -813,7 +1016,7 @@ func (x *ListVtxosRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListVtxosRequest.ProtoReflect.Descriptor instead. func (*ListVtxosRequest) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{14} + return file_ark_v1_service_proto_rawDescGZIP(), []int{18} } func (x *ListVtxosRequest) GetAddress() string { @@ -835,7 +1038,7 @@ type ListVtxosResponse struct { func (x *ListVtxosResponse) Reset() { *x = ListVtxosResponse{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[15] + mi := &file_ark_v1_service_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -848,7 +1051,7 @@ func (x *ListVtxosResponse) String() string { func (*ListVtxosResponse) ProtoMessage() {} func (x *ListVtxosResponse) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[15] + mi := &file_ark_v1_service_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -861,7 +1064,7 @@ func (x *ListVtxosResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListVtxosResponse.ProtoReflect.Descriptor instead. func (*ListVtxosResponse) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{15} + return file_ark_v1_service_proto_rawDescGZIP(), []int{19} } func (x *ListVtxosResponse) GetSpendableVtxos() []*Vtxo { @@ -887,7 +1090,7 @@ type GetInfoRequest struct { func (x *GetInfoRequest) Reset() { *x = GetInfoRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[16] + mi := &file_ark_v1_service_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -900,7 +1103,7 @@ func (x *GetInfoRequest) String() string { func (*GetInfoRequest) ProtoMessage() {} func (x *GetInfoRequest) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[16] + mi := &file_ark_v1_service_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -913,7 +1116,7 @@ func (x *GetInfoRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetInfoRequest.ProtoReflect.Descriptor instead. func (*GetInfoRequest) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{16} + return file_ark_v1_service_proto_rawDescGZIP(), []int{20} } type GetInfoResponse struct { @@ -932,7 +1135,7 @@ type GetInfoResponse struct { func (x *GetInfoResponse) Reset() { *x = GetInfoResponse{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[17] + mi := &file_ark_v1_service_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -945,7 +1148,7 @@ func (x *GetInfoResponse) String() string { func (*GetInfoResponse) ProtoMessage() {} func (x *GetInfoResponse) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[17] + mi := &file_ark_v1_service_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -958,7 +1161,7 @@ func (x *GetInfoResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetInfoResponse.ProtoReflect.Descriptor instead. func (*GetInfoResponse) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{17} + return file_ark_v1_service_proto_rawDescGZIP(), []int{21} } func (x *GetInfoResponse) GetPubkey() string { @@ -1016,7 +1219,7 @@ type OnboardRequest struct { func (x *OnboardRequest) Reset() { *x = OnboardRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[18] + mi := &file_ark_v1_service_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1029,7 +1232,7 @@ func (x *OnboardRequest) String() string { func (*OnboardRequest) ProtoMessage() {} func (x *OnboardRequest) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[18] + mi := &file_ark_v1_service_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1042,7 +1245,7 @@ func (x *OnboardRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use OnboardRequest.ProtoReflect.Descriptor instead. func (*OnboardRequest) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{18} + return file_ark_v1_service_proto_rawDescGZIP(), []int{22} } func (x *OnboardRequest) GetBoardingTx() string { @@ -1075,7 +1278,7 @@ type OnboardResponse struct { func (x *OnboardResponse) Reset() { *x = OnboardResponse{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[19] + mi := &file_ark_v1_service_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1088,7 +1291,7 @@ func (x *OnboardResponse) String() string { func (*OnboardResponse) ProtoMessage() {} func (x *OnboardResponse) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[19] + mi := &file_ark_v1_service_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1101,7 +1304,7 @@ func (x *OnboardResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use OnboardResponse.ProtoReflect.Descriptor instead. func (*OnboardResponse) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{19} + return file_ark_v1_service_proto_rawDescGZIP(), []int{23} } type RoundFinalizationEvent struct { @@ -1119,7 +1322,7 @@ type RoundFinalizationEvent struct { func (x *RoundFinalizationEvent) Reset() { *x = RoundFinalizationEvent{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[20] + mi := &file_ark_v1_service_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1132,7 +1335,7 @@ func (x *RoundFinalizationEvent) String() string { func (*RoundFinalizationEvent) ProtoMessage() {} func (x *RoundFinalizationEvent) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[20] + mi := &file_ark_v1_service_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1145,7 +1348,7 @@ func (x *RoundFinalizationEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use RoundFinalizationEvent.ProtoReflect.Descriptor instead. func (*RoundFinalizationEvent) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{20} + return file_ark_v1_service_proto_rawDescGZIP(), []int{24} } func (x *RoundFinalizationEvent) GetId() string { @@ -1195,7 +1398,7 @@ type RoundFinalizedEvent struct { func (x *RoundFinalizedEvent) Reset() { *x = RoundFinalizedEvent{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[21] + mi := &file_ark_v1_service_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1208,7 +1411,7 @@ func (x *RoundFinalizedEvent) String() string { func (*RoundFinalizedEvent) ProtoMessage() {} func (x *RoundFinalizedEvent) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[21] + mi := &file_ark_v1_service_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1221,7 +1424,7 @@ func (x *RoundFinalizedEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use RoundFinalizedEvent.ProtoReflect.Descriptor instead. func (*RoundFinalizedEvent) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{21} + return file_ark_v1_service_proto_rawDescGZIP(), []int{25} } func (x *RoundFinalizedEvent) GetId() string { @@ -1250,7 +1453,7 @@ type RoundFailed struct { func (x *RoundFailed) Reset() { *x = RoundFailed{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[22] + mi := &file_ark_v1_service_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1263,7 +1466,7 @@ func (x *RoundFailed) String() string { func (*RoundFailed) ProtoMessage() {} func (x *RoundFailed) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[22] + mi := &file_ark_v1_service_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1276,7 +1479,7 @@ func (x *RoundFailed) ProtoReflect() protoreflect.Message { // Deprecated: Use RoundFailed.ProtoReflect.Descriptor instead. func (*RoundFailed) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{22} + return file_ark_v1_service_proto_rawDescGZIP(), []int{26} } func (x *RoundFailed) GetId() string { @@ -1311,7 +1514,7 @@ type Round struct { func (x *Round) Reset() { *x = Round{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[23] + mi := &file_ark_v1_service_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1324,7 +1527,7 @@ func (x *Round) String() string { func (*Round) ProtoMessage() {} func (x *Round) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[23] + mi := &file_ark_v1_service_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1337,7 +1540,7 @@ func (x *Round) ProtoReflect() protoreflect.Message { // Deprecated: Use Round.ProtoReflect.Descriptor instead. func (*Round) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{23} + return file_ark_v1_service_proto_rawDescGZIP(), []int{27} } func (x *Round) GetId() string { @@ -1408,7 +1611,7 @@ type Input struct { func (x *Input) Reset() { *x = Input{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[24] + mi := &file_ark_v1_service_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1421,7 +1624,7 @@ func (x *Input) String() string { func (*Input) ProtoMessage() {} func (x *Input) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[24] + mi := &file_ark_v1_service_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1434,7 +1637,7 @@ func (x *Input) ProtoReflect() protoreflect.Message { // Deprecated: Use Input.ProtoReflect.Descriptor instead. func (*Input) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{24} + return file_ark_v1_service_proto_rawDescGZIP(), []int{28} } func (x *Input) GetTxid() string { @@ -1465,7 +1668,7 @@ type Output struct { func (x *Output) Reset() { *x = Output{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[25] + mi := &file_ark_v1_service_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1478,7 +1681,7 @@ func (x *Output) String() string { func (*Output) ProtoMessage() {} func (x *Output) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[25] + mi := &file_ark_v1_service_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1491,7 +1694,7 @@ func (x *Output) ProtoReflect() protoreflect.Message { // Deprecated: Use Output.ProtoReflect.Descriptor instead. func (*Output) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{25} + return file_ark_v1_service_proto_rawDescGZIP(), []int{29} } func (x *Output) GetAddress() string { @@ -1519,7 +1722,7 @@ type Tree struct { func (x *Tree) Reset() { *x = Tree{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[26] + mi := &file_ark_v1_service_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1532,7 +1735,7 @@ func (x *Tree) String() string { func (*Tree) ProtoMessage() {} func (x *Tree) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[26] + mi := &file_ark_v1_service_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1545,7 +1748,7 @@ func (x *Tree) ProtoReflect() protoreflect.Message { // Deprecated: Use Tree.ProtoReflect.Descriptor instead. func (*Tree) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{26} + return file_ark_v1_service_proto_rawDescGZIP(), []int{30} } func (x *Tree) GetLevels() []*TreeLevel { @@ -1566,7 +1769,7 @@ type TreeLevel struct { func (x *TreeLevel) Reset() { *x = TreeLevel{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[27] + mi := &file_ark_v1_service_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1579,7 +1782,7 @@ func (x *TreeLevel) String() string { func (*TreeLevel) ProtoMessage() {} func (x *TreeLevel) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[27] + mi := &file_ark_v1_service_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1592,7 +1795,7 @@ func (x *TreeLevel) ProtoReflect() protoreflect.Message { // Deprecated: Use TreeLevel.ProtoReflect.Descriptor instead. func (*TreeLevel) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{27} + return file_ark_v1_service_proto_rawDescGZIP(), []int{31} } func (x *TreeLevel) GetNodes() []*Node { @@ -1615,7 +1818,7 @@ type Node struct { func (x *Node) Reset() { *x = Node{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[28] + mi := &file_ark_v1_service_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1628,7 +1831,7 @@ func (x *Node) String() string { func (*Node) ProtoMessage() {} func (x *Node) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[28] + mi := &file_ark_v1_service_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1641,7 +1844,7 @@ func (x *Node) ProtoReflect() protoreflect.Message { // Deprecated: Use Node.ProtoReflect.Descriptor instead. func (*Node) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{28} + return file_ark_v1_service_proto_rawDescGZIP(), []int{32} } func (x *Node) GetTxid() string { @@ -1670,19 +1873,21 @@ type Vtxo struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Outpoint *Input `protobuf:"bytes,1,opt,name=outpoint,proto3" json:"outpoint,omitempty"` - Receiver *Output `protobuf:"bytes,2,opt,name=receiver,proto3" json:"receiver,omitempty"` - Spent bool `protobuf:"varint,3,opt,name=spent,proto3" json:"spent,omitempty"` - PoolTxid string `protobuf:"bytes,4,opt,name=pool_txid,json=poolTxid,proto3" json:"pool_txid,omitempty"` - SpentBy string `protobuf:"bytes,5,opt,name=spent_by,json=spentBy,proto3" json:"spent_by,omitempty"` - ExpireAt int64 `protobuf:"varint,6,opt,name=expire_at,json=expireAt,proto3" json:"expire_at,omitempty"` - Swept bool `protobuf:"varint,7,opt,name=swept,proto3" json:"swept,omitempty"` + Outpoint *Input `protobuf:"bytes,1,opt,name=outpoint,proto3" json:"outpoint,omitempty"` + Receiver *Output `protobuf:"bytes,2,opt,name=receiver,proto3" json:"receiver,omitempty"` + Spent bool `protobuf:"varint,3,opt,name=spent,proto3" json:"spent,omitempty"` + PoolTxid string `protobuf:"bytes,4,opt,name=pool_txid,json=poolTxid,proto3" json:"pool_txid,omitempty"` + SpentBy string `protobuf:"bytes,5,opt,name=spent_by,json=spentBy,proto3" json:"spent_by,omitempty"` + ExpireAt int64 `protobuf:"varint,6,opt,name=expire_at,json=expireAt,proto3" json:"expire_at,omitempty"` + Swept bool `protobuf:"varint,7,opt,name=swept,proto3" json:"swept,omitempty"` + Pending bool `protobuf:"varint,8,opt,name=pending,proto3" json:"pending,omitempty"` + PendingData *PendingPayment `protobuf:"bytes,9,opt,name=pending_data,json=pendingData,proto3" json:"pending_data,omitempty"` } func (x *Vtxo) Reset() { *x = Vtxo{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[29] + mi := &file_ark_v1_service_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1695,7 +1900,7 @@ func (x *Vtxo) String() string { func (*Vtxo) ProtoMessage() {} func (x *Vtxo) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[29] + mi := &file_ark_v1_service_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1708,7 +1913,7 @@ func (x *Vtxo) ProtoReflect() protoreflect.Message { // Deprecated: Use Vtxo.ProtoReflect.Descriptor instead. func (*Vtxo) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{29} + return file_ark_v1_service_proto_rawDescGZIP(), []int{33} } func (x *Vtxo) GetOutpoint() *Input { @@ -1760,256 +1965,377 @@ func (x *Vtxo) GetSwept() bool { return false } +func (x *Vtxo) GetPending() bool { + if x != nil { + return x.Pending + } + return false +} + +func (x *Vtxo) GetPendingData() *PendingPayment { + if x != nil { + return x.PendingData + } + return nil +} + +type PendingPayment struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RedeemTx string `protobuf:"bytes,1,opt,name=redeem_tx,json=redeemTx,proto3" json:"redeem_tx,omitempty"` + UnconditionalForfeitTxs []string `protobuf:"bytes,2,rep,name=unconditional_forfeit_txs,json=unconditionalForfeitTxs,proto3" json:"unconditional_forfeit_txs,omitempty"` +} + +func (x *PendingPayment) Reset() { + *x = PendingPayment{} + if protoimpl.UnsafeEnabled { + mi := &file_ark_v1_service_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PendingPayment) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PendingPayment) ProtoMessage() {} + +func (x *PendingPayment) ProtoReflect() protoreflect.Message { + mi := &file_ark_v1_service_proto_msgTypes[34] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PendingPayment.ProtoReflect.Descriptor instead. +func (*PendingPayment) Descriptor() ([]byte, []int) { + return file_ark_v1_service_proto_rawDescGZIP(), []int{34} +} + +func (x *PendingPayment) GetRedeemTx() string { + if x != nil { + return x.RedeemTx + } + return "" +} + +func (x *PendingPayment) GetUnconditionalForfeitTxs() []string { + if x != nil { + return x.UnconditionalForfeitTxs + } + return nil +} + var File_ark_v1_service_proto protoreflect.FileDescriptor var file_ark_v1_service_proto_rawDesc = []byte{ 0x0a, 0x14, 0x61, 0x72, 0x6b, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x3f, 0x0a, 0x16, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, - 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x22, 0x29, 0x0a, - 0x17, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x4f, 0x0a, 0x13, 0x43, 0x6c, 0x61, 0x69, - 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x67, 0x0a, 0x14, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, + 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x28, 0x0a, 0x07, 0x6f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, + 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, + 0x74, 0x70, 0x75, 0x74, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x28, 0x0a, 0x10, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, + 0x5f, 0x74, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x69, 0x67, 0x6e, 0x65, + 0x64, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78, 0x12, 0x49, 0x0a, 0x21, 0x75, 0x73, 0x69, + 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x5f, 0x66, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x5f, 0x74, 0x78, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x1e, 0x75, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x55, 0x6e, 0x63, + 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, + 0x74, 0x54, 0x78, 0x73, 0x22, 0x8b, 0x01, 0x0a, 0x16, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, + 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x28, 0x0a, 0x10, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, + 0x5f, 0x74, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x69, 0x67, 0x6e, 0x65, + 0x64, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78, 0x12, 0x47, 0x0a, 0x20, 0x73, 0x69, 0x67, + 0x6e, 0x65, 0x64, 0x5f, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, + 0x6c, 0x5f, 0x66, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x5f, 0x74, 0x78, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x1d, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, + 0x78, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3f, 0x0a, + 0x16, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, + 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x22, 0x29, + 0x0a, 0x17, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x4f, 0x0a, 0x13, 0x43, 0x6c, 0x61, + 0x69, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x28, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x22, 0x16, 0x0a, 0x14, 0x43, 0x6c, + 0x61, 0x69, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x46, 0x0a, 0x16, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x12, + 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x66, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x5f, 0x74, + 0x78, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x46, 0x69, + 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x22, 0x37, 0x0a, 0x10, + 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x23, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x05, + 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x25, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, + 0x64, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x14, + 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, + 0x6e, 0x64, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x74, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x22, 0xf4, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, + 0x12, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x11, 0x72, 0x6f, 0x75, + 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x46, + 0x0a, 0x0f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, + 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, + 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x0c, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, + 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x61, + 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x61, 0x69, 0x6c, 0x65, + 0x64, 0x48, 0x00, 0x52, 0x0b, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, + 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x2c, 0x0a, 0x0b, 0x50, 0x69, 0x6e, + 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x65, 0x0a, 0x0c, 0x50, 0x69, 0x6e, 0x67, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x6f, 0x72, 0x66, 0x65, + 0x69, 0x74, 0x5f, 0x74, 0x78, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x6f, + 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x12, 0x34, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, + 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x2c, + 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x79, 0x0a, 0x11, + 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x35, 0x0a, 0x0f, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, + 0x74, 0x78, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, + 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x74, 0x78, 0x6f, 0x52, 0x0e, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x61, + 0x62, 0x6c, 0x65, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x2d, 0x0a, 0x0b, 0x73, 0x70, 0x65, 0x6e, + 0x74, 0x5f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, + 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x74, 0x78, 0x6f, 0x52, 0x0a, 0x73, 0x70, 0x65, + 0x6e, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xe9, 0x01, 0x0a, 0x0f, 0x47, 0x65, + 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, + 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x6c, + 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x72, + 0x6f, 0x75, 0x6e, 0x64, 0x4c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x15, + 0x75, 0x6e, 0x69, 0x6c, 0x61, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x5f, + 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x75, 0x6e, 0x69, + 0x6c, 0x61, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x45, 0x78, 0x69, 0x74, 0x44, 0x65, 0x6c, 0x61, 0x79, + 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, + 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x66, + 0x65, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x6c, + 0x61, 0x79, 0x46, 0x65, 0x65, 0x22, 0x89, 0x01, 0x0a, 0x0e, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6f, 0x61, 0x72, + 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x62, + 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x12, 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, + 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, + 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x65, 0x65, + 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, + 0x79, 0x22, 0x11, 0x0a, 0x0f, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xb9, 0x01, 0x0a, 0x16, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, + 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x28, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x0e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x22, 0x16, 0x0a, 0x14, 0x43, 0x6c, 0x61, + 0x17, 0x0a, 0x07, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x70, 0x6f, 0x6f, 0x6c, 0x54, 0x78, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x6f, 0x72, 0x66, + 0x65, 0x69, 0x74, 0x5f, 0x74, 0x78, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x66, + 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x12, 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, + 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, + 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x65, 0x65, + 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x05, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, + 0x22, 0x42, 0x0a, 0x13, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, + 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, + 0x74, 0x78, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x6f, 0x6c, + 0x54, 0x78, 0x69, 0x64, 0x22, 0x35, 0x0a, 0x0b, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x61, 0x69, + 0x6c, 0x65, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0xfa, 0x01, 0x0a, 0x05, + 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, + 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x17, 0x0a, + 0x07, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x74, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x70, 0x6f, 0x6f, 0x6c, 0x54, 0x78, 0x12, 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x67, 0x65, 0x73, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x52, 0x0e, 0x63, + 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x65, 0x65, 0x12, 0x1f, 0x0a, + 0x0b, 0x66, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x5f, 0x74, 0x78, 0x73, 0x18, 0x06, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0a, 0x66, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x12, 0x1e, + 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x07, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x28, + 0x0a, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, + 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x67, + 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x22, 0x2f, 0x0a, 0x05, 0x49, 0x6e, 0x70, 0x75, + 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x76, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x04, 0x76, 0x6f, 0x75, 0x74, 0x22, 0x3a, 0x0a, 0x06, 0x4f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x31, 0x0a, 0x04, 0x54, 0x72, 0x65, 0x65, 0x12, 0x29, 0x0a, + 0x06, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, + 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, + 0x52, 0x06, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x73, 0x22, 0x2f, 0x0a, 0x09, 0x54, 0x72, 0x65, 0x65, + 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x22, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, + 0x64, 0x65, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x4b, 0x0a, 0x04, 0x4e, 0x6f, 0x64, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x74, 0x78, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, + 0x74, 0x78, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x54, 0x78, 0x69, 0x64, 0x22, 0xb3, 0x02, 0x0a, 0x04, 0x56, 0x74, 0x78, 0x6f, 0x12, + 0x29, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x08, 0x72, 0x65, + 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, + 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x08, 0x72, 0x65, + 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, + 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x70, 0x6f, 0x6f, 0x6c, 0x54, 0x78, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x65, + 0x6e, 0x74, 0x5f, 0x62, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x65, + 0x6e, 0x74, 0x42, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x5f, 0x61, + 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x41, + 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x77, 0x65, 0x70, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x05, 0x73, 0x77, 0x65, 0x70, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x12, 0x39, 0x0a, 0x0c, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x61, 0x74, + 0x61, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, + 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, + 0x0b, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x44, 0x61, 0x74, 0x61, 0x22, 0x69, 0x0a, 0x0e, + 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1b, + 0x0a, 0x09, 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x5f, 0x74, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78, 0x12, 0x3a, 0x0a, 0x19, 0x75, + 0x6e, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x6f, 0x72, + 0x66, 0x65, 0x69, 0x74, 0x5f, 0x74, 0x78, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x17, + 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x46, 0x6f, 0x72, + 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x2a, 0x98, 0x01, 0x0a, 0x0a, 0x52, 0x6f, 0x75, 0x6e, + 0x64, 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, + 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, + 0x47, 0x45, 0x5f, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, + 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, + 0x5f, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x49, 0x5a, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x12, + 0x19, 0x0a, 0x15, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x46, + 0x49, 0x4e, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x4f, + 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, + 0x10, 0x04, 0x32, 0xb3, 0x09, 0x0a, 0x0a, 0x41, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x73, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, + 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x72, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x67, 0x0a, 0x0c, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x46, 0x0a, 0x16, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x73, - 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x66, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x5f, 0x74, 0x78, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, - 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x46, 0x69, 0x6e, - 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x22, 0x37, 0x0a, 0x10, 0x47, - 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x23, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, - 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x05, 0x72, - 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x25, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, - 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x14, 0x47, - 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, - 0x64, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x22, 0xf4, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x12, - 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, - 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x11, 0x72, 0x6f, 0x75, 0x6e, - 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x46, 0x0a, - 0x0f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, - 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, - 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x0c, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x66, - 0x61, 0x69, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x61, 0x72, - 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, - 0x48, 0x00, 0x52, 0x0b, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x42, - 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x2c, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x79, 0x6d, 0x65, - 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x65, 0x0a, 0x0c, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x6f, 0x72, 0x66, 0x65, 0x69, - 0x74, 0x5f, 0x74, 0x78, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x6f, 0x72, - 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x12, 0x34, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, - 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x2c, 0x0a, - 0x10, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x79, 0x0a, 0x11, 0x4c, - 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x35, 0x0a, 0x0f, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x74, - 0x78, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, - 0x76, 0x31, 0x2e, 0x56, 0x74, 0x78, 0x6f, 0x52, 0x0e, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, - 0x6c, 0x65, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x2d, 0x0a, 0x0b, 0x73, 0x70, 0x65, 0x6e, 0x74, - 0x5f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, - 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x74, 0x78, 0x6f, 0x52, 0x0a, 0x73, 0x70, 0x65, 0x6e, - 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xe9, 0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, - 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, - 0x62, 0x6b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x6c, 0x69, - 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x72, 0x6f, - 0x75, 0x6e, 0x64, 0x4c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x75, - 0x6e, 0x69, 0x6c, 0x61, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x64, - 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x75, 0x6e, 0x69, 0x6c, - 0x61, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x45, 0x78, 0x69, 0x74, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, - 0x25, 0x0a, 0x0e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, - 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x6e, - 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x66, 0x65, - 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x6c, 0x61, - 0x79, 0x46, 0x65, 0x65, 0x22, 0x89, 0x01, 0x0a, 0x0e, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6f, 0x61, 0x72, 0x64, - 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x62, 0x6f, - 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x12, 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x67, - 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x52, - 0x0e, 0x63, 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x65, 0x65, 0x12, - 0x1f, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, - 0x22, 0x11, 0x0a, 0x0f, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0xb9, 0x01, 0x0a, 0x16, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, - 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x17, - 0x0a, 0x07, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x70, 0x6f, 0x6f, 0x6c, 0x54, 0x78, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x6f, 0x72, 0x66, 0x65, - 0x69, 0x74, 0x5f, 0x74, 0x78, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x6f, - 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x12, 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x67, - 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x52, - 0x0e, 0x63, 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x65, 0x65, 0x12, - 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x05, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x22, - 0x42, 0x0a, 0x13, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, - 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x74, - 0x78, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x6f, 0x6c, 0x54, - 0x78, 0x69, 0x64, 0x22, 0x35, 0x0a, 0x0b, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x61, 0x69, 0x6c, - 0x65, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, - 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0xfa, 0x01, 0x0a, 0x05, 0x52, - 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x17, 0x0a, 0x07, - 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x74, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, - 0x6f, 0x6f, 0x6c, 0x54, 0x78, 0x12, 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, - 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x52, 0x0e, 0x63, 0x6f, - 0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x65, 0x65, 0x12, 0x1f, 0x0a, 0x0b, - 0x66, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x5f, 0x74, 0x78, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x0a, 0x66, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x12, 0x1e, 0x0a, - 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x28, 0x0a, - 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x61, - 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x67, 0x65, - 0x52, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x22, 0x2f, 0x0a, 0x05, 0x49, 0x6e, 0x70, 0x75, 0x74, - 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x74, 0x78, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x76, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x04, 0x76, 0x6f, 0x75, 0x74, 0x22, 0x3a, 0x0a, 0x06, 0x4f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, - 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x31, 0x0a, 0x04, 0x54, 0x72, 0x65, 0x65, 0x12, 0x29, 0x0a, 0x06, - 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x61, - 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, - 0x06, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x73, 0x22, 0x2f, 0x0a, 0x09, 0x54, 0x72, 0x65, 0x65, 0x4c, - 0x65, 0x76, 0x65, 0x6c, 0x12, 0x22, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, - 0x65, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x4b, 0x0a, 0x04, 0x4e, 0x6f, 0x64, 0x65, - 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x74, 0x78, 0x69, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x02, 0x74, 0x78, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, - 0x78, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x54, 0x78, 0x69, 0x64, 0x22, 0xde, 0x01, 0x0a, 0x04, 0x56, 0x74, 0x78, 0x6f, 0x12, 0x29, - 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, - 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x08, 0x72, 0x65, 0x63, - 0x65, 0x69, 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x72, - 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x08, 0x72, 0x65, 0x63, - 0x65, 0x69, 0x76, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, - 0x6f, 0x6f, 0x6c, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x70, 0x6f, 0x6f, 0x6c, 0x54, 0x78, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x65, 0x6e, - 0x74, 0x5f, 0x62, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x65, 0x6e, - 0x74, 0x42, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x5f, 0x61, 0x74, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x41, 0x74, - 0x12, 0x14, 0x0a, 0x05, 0x73, 0x77, 0x65, 0x70, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x05, 0x73, 0x77, 0x65, 0x70, 0x74, 0x2a, 0x98, 0x01, 0x0a, 0x0a, 0x52, 0x6f, 0x75, 0x6e, 0x64, - 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, - 0x54, 0x41, 0x47, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, - 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, - 0x45, 0x5f, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x01, - 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, - 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x49, 0x5a, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x12, 0x19, - 0x0a, 0x15, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x46, 0x49, - 0x4e, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x4f, 0x55, - 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, - 0x04, 0x32, 0xd8, 0x07, 0x0a, 0x0a, 0x41, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x12, 0x73, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, - 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, - 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, - 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, - 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x72, 0x65, 0x67, - 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x67, 0x0a, 0x0c, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, 0x69, - 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x3a, 0x01, 0x2a, 0x22, 0x11, 0x2f, 0x76, 0x31, - 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x12, 0x73, - 0x0a, 0x0f, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, - 0x74, 0x12, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6e, 0x61, 0x6c, - 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6e, 0x61, 0x6c, - 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, 0x2f, - 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x66, 0x69, 0x6e, 0x61, 0x6c, - 0x69, 0x7a, 0x65, 0x12, 0x57, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x12, - 0x17, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, - 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, - 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x7b, 0x74, 0x78, 0x69, 0x64, 0x7d, 0x12, 0x64, 0x0a, 0x0c, - 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x79, 0x49, 0x64, 0x12, 0x1b, 0x2e, 0x61, - 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x79, - 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, - 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x79, 0x49, 0x64, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, - 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x69, 0x64, 0x2f, 0x7b, 0x69, - 0x64, 0x7d, 0x12, 0x65, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, - 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, 0x2f, 0x76, 0x31, - 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x30, 0x01, 0x12, 0x50, 0x0a, 0x04, 0x50, 0x69, 0x6e, - 0x67, 0x12, 0x13, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, - 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x69, 0x6e, 0x67, 0x2f, 0x7b, - 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x5d, 0x0a, 0x09, 0x4c, - 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, - 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x74, 0x78, 0x6f, 0x73, - 0x2f, 0x7b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x12, 0x4c, 0x0a, 0x07, 0x47, 0x65, - 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, - 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, - 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x10, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08, - 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x52, 0x0a, 0x07, 0x4f, 0x6e, 0x62, 0x6f, - 0x61, 0x72, 0x64, 0x12, 0x16, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x6e, 0x62, - 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x61, 0x72, - 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x3a, 0x01, 0x2a, 0x22, - 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x42, 0x92, 0x01, 0x0a, - 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3d, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x6b, 0x2d, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x2f, 0x61, 0x72, 0x6b, 0x2f, 0x61, 0x70, 0x69, 0x2d, 0x73, 0x70, 0x65, 0x63, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x72, - 0x6b, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x72, 0x6b, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x41, 0x58, 0x58, - 0xaa, 0x02, 0x06, 0x41, 0x72, 0x6b, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x06, 0x41, 0x72, 0x6b, 0x5c, - 0x56, 0x31, 0xe2, 0x02, 0x12, 0x41, 0x72, 0x6b, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x07, 0x41, 0x72, 0x6b, 0x3a, 0x3a, 0x56, - 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x3a, 0x01, 0x2a, 0x22, 0x11, 0x2f, 0x76, + 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x12, + 0x73, 0x0a, 0x0f, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6e, 0x61, + 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6e, 0x61, + 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, + 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x66, 0x69, 0x6e, 0x61, + 0x6c, 0x69, 0x7a, 0x65, 0x12, 0x57, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, + 0x12, 0x17, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, + 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, + 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x7b, 0x74, 0x78, 0x69, 0x64, 0x7d, 0x12, 0x64, 0x0a, + 0x0c, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x79, 0x49, 0x64, 0x12, 0x1b, 0x2e, + 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, + 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x72, 0x6b, + 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x79, 0x49, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, + 0x12, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x69, 0x64, 0x2f, 0x7b, + 0x69, 0x64, 0x7d, 0x12, 0x65, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, + 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, + 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, 0x2f, 0x76, + 0x31, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x30, 0x01, 0x12, 0x50, 0x0a, 0x04, 0x50, 0x69, + 0x6e, 0x67, 0x12, 0x13, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, + 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x69, 0x6e, 0x67, 0x2f, + 0x7b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x5d, 0x0a, 0x09, + 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x74, 0x78, 0x6f, + 0x73, 0x2f, 0x7b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x12, 0x4c, 0x0a, 0x07, 0x47, + 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, + 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, + 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x10, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0a, 0x12, + 0x08, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x52, 0x0a, 0x07, 0x4f, 0x6e, 0x62, + 0x6f, 0x61, 0x72, 0x64, 0x12, 0x16, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x6e, + 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x61, + 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x3a, 0x01, 0x2a, + 0x22, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x12, 0x64, 0x0a, + 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1c, + 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, + 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x10, 0x3a, 0x01, 0x2a, 0x22, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x12, 0x73, 0x0a, 0x0f, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x50, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, + 0x01, 0x2a, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2f, + 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x92, 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, + 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x6b, 0x2d, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, + 0x61, 0x72, 0x6b, 0x2f, 0x61, 0x70, 0x69, 0x2d, 0x73, 0x70, 0x65, 0x63, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x72, 0x6b, 0x2f, 0x76, 0x31, + 0x3b, 0x61, 0x72, 0x6b, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x41, 0x58, 0x58, 0xaa, 0x02, 0x06, 0x41, + 0x72, 0x6b, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x06, 0x41, 0x72, 0x6b, 0x5c, 0x56, 0x31, 0xe2, 0x02, + 0x12, 0x41, 0x72, 0x6b, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0xea, 0x02, 0x07, 0x41, 0x72, 0x6b, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2025,84 +2351,96 @@ func file_ark_v1_service_proto_rawDescGZIP() []byte { } var file_ark_v1_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_ark_v1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 30) +var file_ark_v1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 35) var file_ark_v1_service_proto_goTypes = []interface{}{ (RoundStage)(0), // 0: ark.v1.RoundStage - (*RegisterPaymentRequest)(nil), // 1: ark.v1.RegisterPaymentRequest - (*RegisterPaymentResponse)(nil), // 2: ark.v1.RegisterPaymentResponse - (*ClaimPaymentRequest)(nil), // 3: ark.v1.ClaimPaymentRequest - (*ClaimPaymentResponse)(nil), // 4: ark.v1.ClaimPaymentResponse - (*FinalizePaymentRequest)(nil), // 5: ark.v1.FinalizePaymentRequest - (*FinalizePaymentResponse)(nil), // 6: ark.v1.FinalizePaymentResponse - (*GetRoundRequest)(nil), // 7: ark.v1.GetRoundRequest - (*GetRoundResponse)(nil), // 8: ark.v1.GetRoundResponse - (*GetRoundByIdRequest)(nil), // 9: ark.v1.GetRoundByIdRequest - (*GetRoundByIdResponse)(nil), // 10: ark.v1.GetRoundByIdResponse - (*GetEventStreamRequest)(nil), // 11: ark.v1.GetEventStreamRequest - (*GetEventStreamResponse)(nil), // 12: ark.v1.GetEventStreamResponse - (*PingRequest)(nil), // 13: ark.v1.PingRequest - (*PingResponse)(nil), // 14: ark.v1.PingResponse - (*ListVtxosRequest)(nil), // 15: ark.v1.ListVtxosRequest - (*ListVtxosResponse)(nil), // 16: ark.v1.ListVtxosResponse - (*GetInfoRequest)(nil), // 17: ark.v1.GetInfoRequest - (*GetInfoResponse)(nil), // 18: ark.v1.GetInfoResponse - (*OnboardRequest)(nil), // 19: ark.v1.OnboardRequest - (*OnboardResponse)(nil), // 20: ark.v1.OnboardResponse - (*RoundFinalizationEvent)(nil), // 21: ark.v1.RoundFinalizationEvent - (*RoundFinalizedEvent)(nil), // 22: ark.v1.RoundFinalizedEvent - (*RoundFailed)(nil), // 23: ark.v1.RoundFailed - (*Round)(nil), // 24: ark.v1.Round - (*Input)(nil), // 25: ark.v1.Input - (*Output)(nil), // 26: ark.v1.Output - (*Tree)(nil), // 27: ark.v1.Tree - (*TreeLevel)(nil), // 28: ark.v1.TreeLevel - (*Node)(nil), // 29: ark.v1.Node - (*Vtxo)(nil), // 30: ark.v1.Vtxo + (*CreatePaymentRequest)(nil), // 1: ark.v1.CreatePaymentRequest + (*CreatePaymentResponse)(nil), // 2: ark.v1.CreatePaymentResponse + (*CompletePaymentRequest)(nil), // 3: ark.v1.CompletePaymentRequest + (*CompletePaymentResponse)(nil), // 4: ark.v1.CompletePaymentResponse + (*RegisterPaymentRequest)(nil), // 5: ark.v1.RegisterPaymentRequest + (*RegisterPaymentResponse)(nil), // 6: ark.v1.RegisterPaymentResponse + (*ClaimPaymentRequest)(nil), // 7: ark.v1.ClaimPaymentRequest + (*ClaimPaymentResponse)(nil), // 8: ark.v1.ClaimPaymentResponse + (*FinalizePaymentRequest)(nil), // 9: ark.v1.FinalizePaymentRequest + (*FinalizePaymentResponse)(nil), // 10: ark.v1.FinalizePaymentResponse + (*GetRoundRequest)(nil), // 11: ark.v1.GetRoundRequest + (*GetRoundResponse)(nil), // 12: ark.v1.GetRoundResponse + (*GetRoundByIdRequest)(nil), // 13: ark.v1.GetRoundByIdRequest + (*GetRoundByIdResponse)(nil), // 14: ark.v1.GetRoundByIdResponse + (*GetEventStreamRequest)(nil), // 15: ark.v1.GetEventStreamRequest + (*GetEventStreamResponse)(nil), // 16: ark.v1.GetEventStreamResponse + (*PingRequest)(nil), // 17: ark.v1.PingRequest + (*PingResponse)(nil), // 18: ark.v1.PingResponse + (*ListVtxosRequest)(nil), // 19: ark.v1.ListVtxosRequest + (*ListVtxosResponse)(nil), // 20: ark.v1.ListVtxosResponse + (*GetInfoRequest)(nil), // 21: ark.v1.GetInfoRequest + (*GetInfoResponse)(nil), // 22: ark.v1.GetInfoResponse + (*OnboardRequest)(nil), // 23: ark.v1.OnboardRequest + (*OnboardResponse)(nil), // 24: ark.v1.OnboardResponse + (*RoundFinalizationEvent)(nil), // 25: ark.v1.RoundFinalizationEvent + (*RoundFinalizedEvent)(nil), // 26: ark.v1.RoundFinalizedEvent + (*RoundFailed)(nil), // 27: ark.v1.RoundFailed + (*Round)(nil), // 28: ark.v1.Round + (*Input)(nil), // 29: ark.v1.Input + (*Output)(nil), // 30: ark.v1.Output + (*Tree)(nil), // 31: ark.v1.Tree + (*TreeLevel)(nil), // 32: ark.v1.TreeLevel + (*Node)(nil), // 33: ark.v1.Node + (*Vtxo)(nil), // 34: ark.v1.Vtxo + (*PendingPayment)(nil), // 35: ark.v1.PendingPayment } var file_ark_v1_service_proto_depIdxs = []int32{ - 25, // 0: ark.v1.RegisterPaymentRequest.inputs:type_name -> ark.v1.Input - 26, // 1: ark.v1.ClaimPaymentRequest.outputs:type_name -> ark.v1.Output - 24, // 2: ark.v1.GetRoundResponse.round:type_name -> ark.v1.Round - 24, // 3: ark.v1.GetRoundByIdResponse.round:type_name -> ark.v1.Round - 21, // 4: ark.v1.GetEventStreamResponse.round_finalization:type_name -> ark.v1.RoundFinalizationEvent - 22, // 5: ark.v1.GetEventStreamResponse.round_finalized:type_name -> ark.v1.RoundFinalizedEvent - 23, // 6: ark.v1.GetEventStreamResponse.round_failed:type_name -> ark.v1.RoundFailed - 21, // 7: ark.v1.PingResponse.event:type_name -> ark.v1.RoundFinalizationEvent - 30, // 8: ark.v1.ListVtxosResponse.spendable_vtxos:type_name -> ark.v1.Vtxo - 30, // 9: ark.v1.ListVtxosResponse.spent_vtxos:type_name -> ark.v1.Vtxo - 27, // 10: ark.v1.OnboardRequest.congestion_tree:type_name -> ark.v1.Tree - 27, // 11: ark.v1.RoundFinalizationEvent.congestion_tree:type_name -> ark.v1.Tree - 27, // 12: ark.v1.Round.congestion_tree:type_name -> ark.v1.Tree - 0, // 13: ark.v1.Round.stage:type_name -> ark.v1.RoundStage - 28, // 14: ark.v1.Tree.levels:type_name -> ark.v1.TreeLevel - 29, // 15: ark.v1.TreeLevel.nodes:type_name -> ark.v1.Node - 25, // 16: ark.v1.Vtxo.outpoint:type_name -> ark.v1.Input - 26, // 17: ark.v1.Vtxo.receiver:type_name -> ark.v1.Output - 1, // 18: ark.v1.ArkService.RegisterPayment:input_type -> ark.v1.RegisterPaymentRequest - 3, // 19: ark.v1.ArkService.ClaimPayment:input_type -> ark.v1.ClaimPaymentRequest - 5, // 20: ark.v1.ArkService.FinalizePayment:input_type -> ark.v1.FinalizePaymentRequest - 7, // 21: ark.v1.ArkService.GetRound:input_type -> ark.v1.GetRoundRequest - 9, // 22: ark.v1.ArkService.GetRoundById:input_type -> ark.v1.GetRoundByIdRequest - 11, // 23: ark.v1.ArkService.GetEventStream:input_type -> ark.v1.GetEventStreamRequest - 13, // 24: ark.v1.ArkService.Ping:input_type -> ark.v1.PingRequest - 15, // 25: ark.v1.ArkService.ListVtxos:input_type -> ark.v1.ListVtxosRequest - 17, // 26: ark.v1.ArkService.GetInfo:input_type -> ark.v1.GetInfoRequest - 19, // 27: ark.v1.ArkService.Onboard:input_type -> ark.v1.OnboardRequest - 2, // 28: ark.v1.ArkService.RegisterPayment:output_type -> ark.v1.RegisterPaymentResponse - 4, // 29: ark.v1.ArkService.ClaimPayment:output_type -> ark.v1.ClaimPaymentResponse - 6, // 30: ark.v1.ArkService.FinalizePayment:output_type -> ark.v1.FinalizePaymentResponse - 8, // 31: ark.v1.ArkService.GetRound:output_type -> ark.v1.GetRoundResponse - 10, // 32: ark.v1.ArkService.GetRoundById:output_type -> ark.v1.GetRoundByIdResponse - 12, // 33: ark.v1.ArkService.GetEventStream:output_type -> ark.v1.GetEventStreamResponse - 14, // 34: ark.v1.ArkService.Ping:output_type -> ark.v1.PingResponse - 16, // 35: ark.v1.ArkService.ListVtxos:output_type -> ark.v1.ListVtxosResponse - 18, // 36: ark.v1.ArkService.GetInfo:output_type -> ark.v1.GetInfoResponse - 20, // 37: ark.v1.ArkService.Onboard:output_type -> ark.v1.OnboardResponse - 28, // [28:38] is the sub-list for method output_type - 18, // [18:28] is the sub-list for method input_type - 18, // [18:18] is the sub-list for extension type_name - 18, // [18:18] is the sub-list for extension extendee - 0, // [0:18] is the sub-list for field type_name + 29, // 0: ark.v1.CreatePaymentRequest.inputs:type_name -> ark.v1.Input + 30, // 1: ark.v1.CreatePaymentRequest.outputs:type_name -> ark.v1.Output + 29, // 2: ark.v1.RegisterPaymentRequest.inputs:type_name -> ark.v1.Input + 30, // 3: ark.v1.ClaimPaymentRequest.outputs:type_name -> ark.v1.Output + 28, // 4: ark.v1.GetRoundResponse.round:type_name -> ark.v1.Round + 28, // 5: ark.v1.GetRoundByIdResponse.round:type_name -> ark.v1.Round + 25, // 6: ark.v1.GetEventStreamResponse.round_finalization:type_name -> ark.v1.RoundFinalizationEvent + 26, // 7: ark.v1.GetEventStreamResponse.round_finalized:type_name -> ark.v1.RoundFinalizedEvent + 27, // 8: ark.v1.GetEventStreamResponse.round_failed:type_name -> ark.v1.RoundFailed + 25, // 9: ark.v1.PingResponse.event:type_name -> ark.v1.RoundFinalizationEvent + 34, // 10: ark.v1.ListVtxosResponse.spendable_vtxos:type_name -> ark.v1.Vtxo + 34, // 11: ark.v1.ListVtxosResponse.spent_vtxos:type_name -> ark.v1.Vtxo + 31, // 12: ark.v1.OnboardRequest.congestion_tree:type_name -> ark.v1.Tree + 31, // 13: ark.v1.RoundFinalizationEvent.congestion_tree:type_name -> ark.v1.Tree + 31, // 14: ark.v1.Round.congestion_tree:type_name -> ark.v1.Tree + 0, // 15: ark.v1.Round.stage:type_name -> ark.v1.RoundStage + 32, // 16: ark.v1.Tree.levels:type_name -> ark.v1.TreeLevel + 33, // 17: ark.v1.TreeLevel.nodes:type_name -> ark.v1.Node + 29, // 18: ark.v1.Vtxo.outpoint:type_name -> ark.v1.Input + 30, // 19: ark.v1.Vtxo.receiver:type_name -> ark.v1.Output + 35, // 20: ark.v1.Vtxo.pending_data:type_name -> ark.v1.PendingPayment + 5, // 21: ark.v1.ArkService.RegisterPayment:input_type -> ark.v1.RegisterPaymentRequest + 7, // 22: ark.v1.ArkService.ClaimPayment:input_type -> ark.v1.ClaimPaymentRequest + 9, // 23: ark.v1.ArkService.FinalizePayment:input_type -> ark.v1.FinalizePaymentRequest + 11, // 24: ark.v1.ArkService.GetRound:input_type -> ark.v1.GetRoundRequest + 13, // 25: ark.v1.ArkService.GetRoundById:input_type -> ark.v1.GetRoundByIdRequest + 15, // 26: ark.v1.ArkService.GetEventStream:input_type -> ark.v1.GetEventStreamRequest + 17, // 27: ark.v1.ArkService.Ping:input_type -> ark.v1.PingRequest + 19, // 28: ark.v1.ArkService.ListVtxos:input_type -> ark.v1.ListVtxosRequest + 21, // 29: ark.v1.ArkService.GetInfo:input_type -> ark.v1.GetInfoRequest + 23, // 30: ark.v1.ArkService.Onboard:input_type -> ark.v1.OnboardRequest + 1, // 31: ark.v1.ArkService.CreatePayment:input_type -> ark.v1.CreatePaymentRequest + 3, // 32: ark.v1.ArkService.CompletePayment:input_type -> ark.v1.CompletePaymentRequest + 6, // 33: ark.v1.ArkService.RegisterPayment:output_type -> ark.v1.RegisterPaymentResponse + 8, // 34: ark.v1.ArkService.ClaimPayment:output_type -> ark.v1.ClaimPaymentResponse + 10, // 35: ark.v1.ArkService.FinalizePayment:output_type -> ark.v1.FinalizePaymentResponse + 12, // 36: ark.v1.ArkService.GetRound:output_type -> ark.v1.GetRoundResponse + 14, // 37: ark.v1.ArkService.GetRoundById:output_type -> ark.v1.GetRoundByIdResponse + 16, // 38: ark.v1.ArkService.GetEventStream:output_type -> ark.v1.GetEventStreamResponse + 18, // 39: ark.v1.ArkService.Ping:output_type -> ark.v1.PingResponse + 20, // 40: ark.v1.ArkService.ListVtxos:output_type -> ark.v1.ListVtxosResponse + 22, // 41: ark.v1.ArkService.GetInfo:output_type -> ark.v1.GetInfoResponse + 24, // 42: ark.v1.ArkService.Onboard:output_type -> ark.v1.OnboardResponse + 2, // 43: ark.v1.ArkService.CreatePayment:output_type -> ark.v1.CreatePaymentResponse + 4, // 44: ark.v1.ArkService.CompletePayment:output_type -> ark.v1.CompletePaymentResponse + 33, // [33:45] is the sub-list for method output_type + 21, // [21:33] is the sub-list for method input_type + 21, // [21:21] is the sub-list for extension type_name + 21, // [21:21] is the sub-list for extension extendee + 0, // [0:21] is the sub-list for field type_name } func init() { file_ark_v1_service_proto_init() } @@ -2112,7 +2450,7 @@ func file_ark_v1_service_proto_init() { } if !protoimpl.UnsafeEnabled { file_ark_v1_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegisterPaymentRequest); i { + switch v := v.(*CreatePaymentRequest); i { case 0: return &v.state case 1: @@ -2124,7 +2462,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegisterPaymentResponse); i { + switch v := v.(*CreatePaymentResponse); i { case 0: return &v.state case 1: @@ -2136,7 +2474,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ClaimPaymentRequest); i { + switch v := v.(*CompletePaymentRequest); i { case 0: return &v.state case 1: @@ -2148,7 +2486,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ClaimPaymentResponse); i { + switch v := v.(*CompletePaymentResponse); i { case 0: return &v.state case 1: @@ -2160,7 +2498,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FinalizePaymentRequest); i { + switch v := v.(*RegisterPaymentRequest); i { case 0: return &v.state case 1: @@ -2172,7 +2510,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FinalizePaymentResponse); i { + switch v := v.(*RegisterPaymentResponse); i { case 0: return &v.state case 1: @@ -2184,7 +2522,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetRoundRequest); i { + switch v := v.(*ClaimPaymentRequest); i { case 0: return &v.state case 1: @@ -2196,7 +2534,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetRoundResponse); i { + switch v := v.(*ClaimPaymentResponse); i { case 0: return &v.state case 1: @@ -2208,7 +2546,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetRoundByIdRequest); i { + switch v := v.(*FinalizePaymentRequest); i { case 0: return &v.state case 1: @@ -2220,7 +2558,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetRoundByIdResponse); i { + switch v := v.(*FinalizePaymentResponse); i { case 0: return &v.state case 1: @@ -2232,7 +2570,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetEventStreamRequest); i { + switch v := v.(*GetRoundRequest); i { case 0: return &v.state case 1: @@ -2244,7 +2582,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetEventStreamResponse); i { + switch v := v.(*GetRoundResponse); i { case 0: return &v.state case 1: @@ -2256,7 +2594,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PingRequest); i { + switch v := v.(*GetRoundByIdRequest); i { case 0: return &v.state case 1: @@ -2268,7 +2606,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PingResponse); i { + switch v := v.(*GetRoundByIdResponse); i { case 0: return &v.state case 1: @@ -2280,7 +2618,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListVtxosRequest); i { + switch v := v.(*GetEventStreamRequest); i { case 0: return &v.state case 1: @@ -2292,7 +2630,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListVtxosResponse); i { + switch v := v.(*GetEventStreamResponse); i { case 0: return &v.state case 1: @@ -2304,7 +2642,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetInfoRequest); i { + switch v := v.(*PingRequest); i { case 0: return &v.state case 1: @@ -2316,7 +2654,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetInfoResponse); i { + switch v := v.(*PingResponse); i { case 0: return &v.state case 1: @@ -2328,7 +2666,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*OnboardRequest); i { + switch v := v.(*ListVtxosRequest); i { case 0: return &v.state case 1: @@ -2340,7 +2678,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*OnboardResponse); i { + switch v := v.(*ListVtxosResponse); i { case 0: return &v.state case 1: @@ -2352,7 +2690,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RoundFinalizationEvent); i { + switch v := v.(*GetInfoRequest); i { case 0: return &v.state case 1: @@ -2364,7 +2702,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RoundFinalizedEvent); i { + switch v := v.(*GetInfoResponse); i { case 0: return &v.state case 1: @@ -2376,7 +2714,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RoundFailed); i { + switch v := v.(*OnboardRequest); i { case 0: return &v.state case 1: @@ -2388,7 +2726,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Round); i { + switch v := v.(*OnboardResponse); i { case 0: return &v.state case 1: @@ -2400,7 +2738,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Input); i { + switch v := v.(*RoundFinalizationEvent); i { case 0: return &v.state case 1: @@ -2412,7 +2750,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Output); i { + switch v := v.(*RoundFinalizedEvent); i { case 0: return &v.state case 1: @@ -2424,7 +2762,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Tree); i { + switch v := v.(*RoundFailed); i { case 0: return &v.state case 1: @@ -2436,7 +2774,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TreeLevel); i { + switch v := v.(*Round); i { case 0: return &v.state case 1: @@ -2448,7 +2786,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Node); i { + switch v := v.(*Input); i { case 0: return &v.state case 1: @@ -2460,6 +2798,54 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Output); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ark_v1_service_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Tree); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ark_v1_service_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TreeLevel); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ark_v1_service_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Node); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ark_v1_service_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Vtxo); i { case 0: return &v.state @@ -2471,8 +2857,20 @@ func file_ark_v1_service_proto_init() { return nil } } + file_ark_v1_service_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PendingPayment); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } - file_ark_v1_service_proto_msgTypes[11].OneofWrappers = []interface{}{ + file_ark_v1_service_proto_msgTypes[15].OneofWrappers = []interface{}{ (*GetEventStreamResponse_RoundFinalization)(nil), (*GetEventStreamResponse_RoundFinalized)(nil), (*GetEventStreamResponse_RoundFailed)(nil), @@ -2483,7 +2881,7 @@ func file_ark_v1_service_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_ark_v1_service_proto_rawDesc, NumEnums: 1, - NumMessages: 30, + NumMessages: 35, NumExtensions: 0, NumServices: 1, }, diff --git a/server/api-spec/protobuf/gen/ark/v1/service.pb.gw.go b/server/api-spec/protobuf/gen/ark/v1/service.pb.gw.go index a36bd07..166012e 100644 --- a/server/api-spec/protobuf/gen/ark/v1/service.pb.gw.go +++ b/server/api-spec/protobuf/gen/ark/v1/service.pb.gw.go @@ -378,6 +378,58 @@ func local_request_ArkService_Onboard_0(ctx context.Context, marshaler runtime.M } +func request_ArkService_CreatePayment_0(ctx context.Context, marshaler runtime.Marshaler, client ArkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq CreatePaymentRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.CreatePayment(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_ArkService_CreatePayment_0(ctx context.Context, marshaler runtime.Marshaler, server ArkServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq CreatePaymentRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.CreatePayment(ctx, &protoReq) + return msg, metadata, err + +} + +func request_ArkService_CompletePayment_0(ctx context.Context, marshaler runtime.Marshaler, client ArkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq CompletePaymentRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.CompletePayment(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_ArkService_CompletePayment_0(ctx context.Context, marshaler runtime.Marshaler, server ArkServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq CompletePaymentRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.CompletePayment(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterArkServiceHandlerServer registers the http handlers for service ArkService to "mux". // UnaryRPC :call ArkServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -617,6 +669,56 @@ func RegisterArkServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, }) + mux.Handle("POST", pattern_ArkService_CreatePayment_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) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/ark.v1.ArkService/CreatePayment", runtime.WithHTTPPathPattern("/v1/payment")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_ArkService_CreatePayment_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_ArkService_CreatePayment_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_ArkService_CompletePayment_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) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/ark.v1.ArkService/CompletePayment", runtime.WithHTTPPathPattern("/v1/payment/complete")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_ArkService_CompletePayment_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_ArkService_CompletePayment_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -878,6 +980,50 @@ func RegisterArkServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) + mux.Handle("POST", pattern_ArkService_CreatePayment_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) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/ark.v1.ArkService/CreatePayment", runtime.WithHTTPPathPattern("/v1/payment")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ArkService_CreatePayment_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_ArkService_CreatePayment_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_ArkService_CompletePayment_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) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/ark.v1.ArkService/CompletePayment", runtime.WithHTTPPathPattern("/v1/payment/complete")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ArkService_CompletePayment_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_ArkService_CompletePayment_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -901,6 +1047,10 @@ var ( pattern_ArkService_GetInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "info"}, "")) pattern_ArkService_Onboard_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "onboard"}, "")) + + pattern_ArkService_CreatePayment_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "payment"}, "")) + + pattern_ArkService_CompletePayment_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "payment", "complete"}, "")) ) var ( @@ -923,4 +1073,8 @@ var ( forward_ArkService_GetInfo_0 = runtime.ForwardResponseMessage forward_ArkService_Onboard_0 = runtime.ForwardResponseMessage + + forward_ArkService_CreatePayment_0 = runtime.ForwardResponseMessage + + forward_ArkService_CompletePayment_0 = runtime.ForwardResponseMessage ) diff --git a/server/api-spec/protobuf/gen/ark/v1/service_grpc.pb.go b/server/api-spec/protobuf/gen/ark/v1/service_grpc.pb.go index 5770baa..8068e32 100644 --- a/server/api-spec/protobuf/gen/ark/v1/service_grpc.pb.go +++ b/server/api-spec/protobuf/gen/ark/v1/service_grpc.pb.go @@ -29,6 +29,8 @@ type ArkServiceClient interface { ListVtxos(ctx context.Context, in *ListVtxosRequest, opts ...grpc.CallOption) (*ListVtxosResponse, error) GetInfo(ctx context.Context, in *GetInfoRequest, opts ...grpc.CallOption) (*GetInfoResponse, error) Onboard(ctx context.Context, in *OnboardRequest, opts ...grpc.CallOption) (*OnboardResponse, error) + CreatePayment(ctx context.Context, in *CreatePaymentRequest, opts ...grpc.CallOption) (*CreatePaymentResponse, error) + CompletePayment(ctx context.Context, in *CompletePaymentRequest, opts ...grpc.CallOption) (*CompletePaymentResponse, error) } type arkServiceClient struct { @@ -152,6 +154,24 @@ func (c *arkServiceClient) Onboard(ctx context.Context, in *OnboardRequest, opts return out, nil } +func (c *arkServiceClient) CreatePayment(ctx context.Context, in *CreatePaymentRequest, opts ...grpc.CallOption) (*CreatePaymentResponse, error) { + out := new(CreatePaymentResponse) + err := c.cc.Invoke(ctx, "/ark.v1.ArkService/CreatePayment", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *arkServiceClient) CompletePayment(ctx context.Context, in *CompletePaymentRequest, opts ...grpc.CallOption) (*CompletePaymentResponse, error) { + out := new(CompletePaymentResponse) + err := c.cc.Invoke(ctx, "/ark.v1.ArkService/CompletePayment", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // ArkServiceServer is the server API for ArkService service. // All implementations should embed UnimplementedArkServiceServer // for forward compatibility @@ -167,6 +187,8 @@ type ArkServiceServer interface { ListVtxos(context.Context, *ListVtxosRequest) (*ListVtxosResponse, error) GetInfo(context.Context, *GetInfoRequest) (*GetInfoResponse, error) Onboard(context.Context, *OnboardRequest) (*OnboardResponse, error) + CreatePayment(context.Context, *CreatePaymentRequest) (*CreatePaymentResponse, error) + CompletePayment(context.Context, *CompletePaymentRequest) (*CompletePaymentResponse, error) } // UnimplementedArkServiceServer should be embedded to have forward compatible implementations. @@ -203,6 +225,12 @@ func (UnimplementedArkServiceServer) GetInfo(context.Context, *GetInfoRequest) ( func (UnimplementedArkServiceServer) Onboard(context.Context, *OnboardRequest) (*OnboardResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Onboard not implemented") } +func (UnimplementedArkServiceServer) CreatePayment(context.Context, *CreatePaymentRequest) (*CreatePaymentResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreatePayment not implemented") +} +func (UnimplementedArkServiceServer) CompletePayment(context.Context, *CompletePaymentRequest) (*CompletePaymentResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CompletePayment not implemented") +} // UnsafeArkServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ArkServiceServer will @@ -398,6 +426,42 @@ func _ArkService_Onboard_Handler(srv interface{}, ctx context.Context, dec func( return interceptor(ctx, in, info, handler) } +func _ArkService_CreatePayment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreatePaymentRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ArkServiceServer).CreatePayment(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ark.v1.ArkService/CreatePayment", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ArkServiceServer).CreatePayment(ctx, req.(*CreatePaymentRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ArkService_CompletePayment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CompletePaymentRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ArkServiceServer).CompletePayment(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ark.v1.ArkService/CompletePayment", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ArkServiceServer).CompletePayment(ctx, req.(*CompletePaymentRequest)) + } + return interceptor(ctx, in, info, handler) +} + // ArkService_ServiceDesc is the grpc.ServiceDesc for ArkService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -441,6 +505,14 @@ var ArkService_ServiceDesc = grpc.ServiceDesc{ MethodName: "Onboard", Handler: _ArkService_Onboard_Handler, }, + { + MethodName: "CreatePayment", + Handler: _ArkService_CreatePayment_Handler, + }, + { + MethodName: "CompletePayment", + Handler: _ArkService_CompletePayment_Handler, + }, }, Streams: []grpc.StreamDesc{ { diff --git a/server/cmd/arkd/commands.go b/server/cmd/arkd/commands.go index 9c5c1e3..3e91fef 100644 --- a/server/cmd/arkd/commands.go +++ b/server/cmd/arkd/commands.go @@ -220,7 +220,7 @@ func post[T any](url, body, key, macaroon, tlsCert string) (result T, err error) req.Header.Add("X-Macaroon", macaroon) } client := &http.Client{ - Timeout: 15 * time.Second, + Timeout: 30 * time.Second, Transport: &http.Transport{ TLSClientConfig: tlsConfig, }, @@ -267,7 +267,7 @@ func get[T any](url, key, macaroon, tlsCert string) (result T, err error) { } client := &http.Client{ - Timeout: 15 * time.Second, + Timeout: 30 * time.Second, Transport: &http.Transport{ TLSClientConfig: tlsConfig, }, @@ -331,7 +331,7 @@ func getBalance(url, macaroon, tlsCert string) (*balance, error) { req.Header.Add("X-Macaroon", macaroon) } client := &http.Client{ - Timeout: 15 * time.Second, + Timeout: 30 * time.Second, Transport: &http.Transport{ TLSClientConfig: tlsConfig, }, @@ -384,7 +384,7 @@ func getStatus(url, tlsCert string) (*status, error) { req.Header.Add("Content-Type", "application/json") client := &http.Client{ - Timeout: 15 * time.Second, + Timeout: 30 * time.Second, Transport: &http.Transport{ TLSClientConfig: tlsConfig, }, diff --git a/server/internal/core/application/admin.go b/server/internal/core/application/admin.go index 435f6d7..2cbb641 100644 --- a/server/internal/core/application/admin.go +++ b/server/internal/core/application/admin.go @@ -45,6 +45,8 @@ type AdminService interface { GetScheduledSweeps(ctx context.Context) ([]ScheduledSweep, error) GetRoundDetails(ctx context.Context, roundId string) (*RoundDetails, error) GetRounds(ctx context.Context, after int64, before int64) ([]string, error) + GetWalletAddress(ctx context.Context) (string, error) + GetWalletStatus(ctx context.Context) (*WalletStatus, error) } type adminService struct { @@ -154,3 +156,24 @@ func (a *adminService) GetScheduledSweeps(ctx context.Context) ([]ScheduledSweep return scheduledSweeps, nil } + +func (a *adminService) GetWalletAddress(ctx context.Context) (string, error) { + addresses, err := a.walletSvc.DeriveAddresses(ctx, 1) + if err != nil { + return "", err + } + + return addresses[0], nil +} + +func (a *adminService) GetWalletStatus(ctx context.Context) (*WalletStatus, error) { + status, err := a.walletSvc.Status(ctx) + if err != nil { + return nil, err + } + return &WalletStatus{ + IsInitialized: status.IsInitialized(), + IsUnlocked: status.IsUnlocked(), + IsSynced: status.IsSynced(), + }, nil +} diff --git a/server/internal/core/application/covenant.go b/server/internal/core/application/covenant.go index 6828615..9ff9d15 100644 --- a/server/internal/core/application/covenant.go +++ b/server/internal/core/application/covenant.go @@ -161,6 +161,14 @@ func (s *covenantService) UpdatePaymentStatus(_ context.Context, id string) ([]s return nil, nil, nil } +func (s *covenantService) CompleteAsyncPayment(ctx context.Context, redeemTx string, unconditionalForfeitTxs []string) error { + return fmt.Errorf("unimplemented") +} + +func (s *covenantService) CreateAsyncPayment(ctx context.Context, inputs []domain.VtxoKey, receivers []domain.Receiver) (string, []string, error) { + return "", nil, fmt.Errorf("unimplemented") +} + func (s *covenantService) SignVtxos(ctx context.Context, forfeitTxs []string) error { return s.forfeitTxs.sign(forfeitTxs) } diff --git a/server/internal/core/application/covenantless.go b/server/internal/core/application/covenantless.go index 06b87af..637347e 100644 --- a/server/internal/core/application/covenantless.go +++ b/server/internal/core/application/covenantless.go @@ -42,6 +42,11 @@ type covenantlessService struct { onboardingCh chan onboarding currentRound *domain.Round + + asyncPaymentsCache map[domain.VtxoKey]struct { + receivers []domain.Receiver + expireAt int64 + } } func NewCovenantlessService( @@ -62,13 +67,30 @@ func NewCovenantlessService( } sweeper := newSweeper(walletSvc, repoManager, builder, scheduler) + asyncPaymentsCache := make(map[domain.VtxoKey]struct { + receivers []domain.Receiver + expireAt int64 + }) svc := &covenantlessService{ - network, pubkey, - roundLifetime, roundInterval, unilateralExitDelay, minRelayFee, - walletSvc, repoManager, builder, scanner, sweeper, - paymentRequests, forfeitTxs, eventsCh, onboardingCh, nil, + network: network, + pubkey: pubkey, + roundLifetime: roundLifetime, + roundInterval: roundInterval, + unilateralExitDelay: unilateralExitDelay, + minRelayFee: minRelayFee, + wallet: walletSvc, + repoManager: repoManager, + builder: builder, + scanner: scanner, + sweeper: sweeper, + paymentRequests: paymentRequests, + forfeitTxs: forfeitTxs, + eventsCh: eventsCh, + onboardingCh: onboardingCh, + asyncPaymentsCache: asyncPaymentsCache, } + repoManager.RegisterEventsHandler( func(round *domain.Round) { go svc.propagateEvents(round) @@ -115,6 +137,108 @@ func (s *covenantlessService) Stop() { close(s.onboardingCh) } +func (s *covenantlessService) CompleteAsyncPayment( + ctx context.Context, redeemTx string, unconditionalForfeitTxs []string, +) error { + // TODO check that the user signed both transactions + + redeemPtx, err := psbt.NewFromRawBytes(strings.NewReader(redeemTx), true) + if err != nil { + return fmt.Errorf("failed to parse redeem tx: %s", err) + } + redeemTxid := redeemPtx.UnsignedTx.TxID() + + spentVtxos := make([]domain.VtxoKey, 0, len(unconditionalForfeitTxs)) + for _, in := range redeemPtx.UnsignedTx.TxIn { + spentVtxos = append(spentVtxos, domain.VtxoKey{ + Txid: in.PreviousOutPoint.Hash.String(), + VOut: in.PreviousOutPoint.Index, + }) + } + + asyncPayData, ok := s.asyncPaymentsCache[spentVtxos[0]] + if !ok { + return fmt.Errorf("async payment not found") + } + + vtxos := make([]domain.Vtxo, 0, len(asyncPayData.receivers)) + for i, receiver := range asyncPayData.receivers { + vtxos = append(vtxos, domain.Vtxo{ + VtxoKey: domain.VtxoKey{ + Txid: redeemTxid, + VOut: uint32(i), + }, + Receiver: receiver, + ExpireAt: asyncPayData.expireAt, + AsyncPayment: &domain.AsyncPaymentTxs{ + RedeemTx: redeemTx, + UnconditionalForfeitTxs: unconditionalForfeitTxs, + }, + }) + } + + if err := s.repoManager.Vtxos().AddVtxos(ctx, vtxos); err != nil { + return fmt.Errorf("failed to add vtxos: %s", err) + } + log.Infof("added %d vtxos", len(vtxos)) + + if err := s.repoManager.Vtxos().SpendVtxos(ctx, spentVtxos, redeemTxid); err != nil { + return fmt.Errorf("failed to spend vtxo: %s", err) + } + log.Infof("spent %d vtxos", len(spentVtxos)) + + delete(s.asyncPaymentsCache, spentVtxos[0]) + + return nil +} + +func (s *covenantlessService) CreateAsyncPayment( + ctx context.Context, inputs []domain.VtxoKey, receivers []domain.Receiver, +) (string, []string, error) { + vtxos, err := s.repoManager.Vtxos().GetVtxos(ctx, inputs) + if err != nil { + return "", nil, err + } + if len(vtxos) <= 0 { + return "", nil, fmt.Errorf("vtxos not found") + } + + expiration := vtxos[0].ExpireAt + for _, vtxo := range vtxos { + if vtxo.Spent { + return "", nil, fmt.Errorf("all vtxos must be unspent") + } + + if vtxo.Redeemed { + return "", nil, fmt.Errorf("all vtxos must be redeemed") + } + + if vtxo.Swept { + return "", nil, fmt.Errorf("all vtxos must be swept") + } + if vtxo.ExpireAt < expiration { + expiration = vtxo.ExpireAt + } + } + + res, err := s.builder.BuildAsyncPaymentTransactions( + vtxos, s.pubkey, receivers, s.minRelayFee, + ) + if err != nil { + return "", nil, fmt.Errorf("failed to build async payment txs: %s", err) + } + + s.asyncPaymentsCache[inputs[0]] = struct { + receivers []domain.Receiver + expireAt int64 + }{ + receivers: receivers, + expireAt: expiration, + } + + return res.RedeemTx, res.UnconditionalForfeitTxs, nil +} + func (s *covenantlessService) SpendVtxos(ctx context.Context, inputs []domain.VtxoKey) (string, error) { vtxos, err := s.repoManager.Vtxos().GetVtxos(ctx, inputs) if err != nil { diff --git a/server/internal/core/application/sweeper.go b/server/internal/core/application/sweeper.go index 60495cb..6655b57 100644 --- a/server/internal/core/application/sweeper.go +++ b/server/internal/core/application/sweeper.go @@ -149,6 +149,7 @@ func (s *sweeper) createTask( for _, input := range inputs { // sweepableVtxos related to the sweep input sweepableVtxos := make([]domain.VtxoKey, 0) + fmt.Println("input", input.GetHash().String(), input.GetIndex()) // check if input is the vtxo itself vtxos, _ := s.repoManager.Vtxos().GetVtxos( diff --git a/server/internal/core/application/types.go b/server/internal/core/application/types.go index 77407f8..79ff9a3 100644 --- a/server/internal/core/application/types.go +++ b/server/internal/core/application/types.go @@ -34,6 +34,13 @@ type Service interface { ctx context.Context, boardingTx string, congestionTree tree.CongestionTree, userPubkey *secp256k1.PublicKey, ) error + // Async payments + CreateAsyncPayment( + ctx context.Context, inputs []domain.VtxoKey, receivers []domain.Receiver, + ) (string, []string, error) + CompleteAsyncPayment( + ctx context.Context, redeemTx string, unconditionalForfeitTxs []string, + ) error } type ServiceInfo struct { diff --git a/server/internal/core/domain/payment.go b/server/internal/core/domain/payment.go index 042aaa4..230da99 100644 --- a/server/internal/core/domain/payment.go +++ b/server/internal/core/domain/payment.go @@ -130,10 +130,16 @@ func (r Receiver) IsOnchain() bool { type Vtxo struct { VtxoKey Receiver - PoolTx string - SpentBy string - Spent bool - Redeemed bool - Swept bool - ExpireAt int64 + PoolTx string + SpentBy string // round txid or async redeem txid + Spent bool + Redeemed bool + Swept bool + ExpireAt int64 + AsyncPayment *AsyncPaymentTxs // nil if not async vtxo +} + +type AsyncPaymentTxs struct { + RedeemTx string // always signed by the ASP when created + UnconditionalForfeitTxs []string } diff --git a/server/internal/core/ports/tx_builder.go b/server/internal/core/ports/tx_builder.go index bbe6e1f..a8feaec 100644 --- a/server/internal/core/ports/tx_builder.go +++ b/server/internal/core/ports/tx_builder.go @@ -29,4 +29,8 @@ type TxBuilder interface { FinalizeAndExtractForfeit(tx string) (txhex string, err error) // FindLeaves returns all the leaves txs that are reachable from the given outpoint FindLeaves(congestionTree tree.CongestionTree, fromtxid string, vout uint32) (leaves []tree.Node, err error) + BuildAsyncPaymentTransactions( + vtxosToSpend []domain.Vtxo, + aspPubKey *secp256k1.PublicKey, receivers []domain.Receiver, minRelayFee uint64, + ) (*domain.AsyncPaymentTxs, error) } diff --git a/server/internal/core/ports/wallet.go b/server/internal/core/ports/wallet.go index 02e7ac0..48ef036 100644 --- a/server/internal/core/ports/wallet.go +++ b/server/internal/core/ports/wallet.go @@ -28,7 +28,7 @@ type WalletService interface { SelectUtxos(ctx context.Context, asset string, amount uint64) ([]TxInput, uint64, error) BroadcastTransaction(ctx context.Context, txHex string) (string, error) WaitForSync(ctx context.Context, txid string) error - EstimateFees(ctx context.Context, pset string) (uint64, error) + EstimateFees(ctx context.Context, psbt string) (uint64, error) ListConnectorUtxos(ctx context.Context, connectorAddress string) ([]TxInput, error) MainAccountBalance(ctx context.Context) (uint64, uint64, error) ConnectorsAccountBalance(ctx context.Context) (uint64, uint64, error) diff --git a/server/internal/infrastructure/db/sqlite/migration/20240703120550_init.up.sql b/server/internal/infrastructure/db/sqlite/migration/20240703120550_init.up.sql index 98b6cd1..784b8d3 100644 --- a/server/internal/infrastructure/db/sqlite/migration/20240703120550_init.up.sql +++ b/server/internal/infrastructure/db/sqlite/migration/20240703120550_init.up.sql @@ -41,8 +41,17 @@ CREATE TABLE IF NOT EXISTS tx ( FOREIGN KEY (round_id) REFERENCES round(id) ); +CREATE TABLE IF NOT EXISTS uncond_forfeit_tx ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + tx TEXT NOT NULL, + vtxo_txid TEXT NOT NULL, + vtxo_vout INTEGER NOT NULL, + position INTEGER NOT NULL, + FOREIGN KEY (vtxo_txid, vtxo_vout) REFERENCES vtxo(txid, vout) +); + CREATE TABLE IF NOT EXISTS vtxo ( - txid TEXT NOT NULL PRIMARY KEY, + txid TEXT NOT NULL, vout INTEGER NOT NULL, pubkey TEXT NOT NULL, amount INTEGER NOT NULL, @@ -53,6 +62,8 @@ CREATE TABLE IF NOT EXISTS vtxo ( swept BOOLEAN NOT NULL, expire_at INTEGER NOT NULL, payment_id TEXT, + redeem_tx TEXT, + PRIMARY KEY (txid, vout), FOREIGN KEY (payment_id) REFERENCES payment(id) ); @@ -74,4 +85,9 @@ ON payment.id=receiver.payment_id; CREATE VIEW payment_vtxo_vw AS SELECT vtxo.* FROM payment LEFT OUTER JOIN vtxo -ON payment.id=vtxo.payment_id; \ No newline at end of file +ON payment.id=vtxo.payment_id; + +CREATE VIEW uncond_forfeit_tx_vw AS SELECT uncond_forfeit_tx.* +FROM vtxo +LEFT OUTER JOIN uncond_forfeit_tx +ON vtxo.txid=uncond_forfeit_tx.vtxo_txid AND vtxo.vout=uncond_forfeit_tx.vtxo_vout; \ No newline at end of file diff --git a/server/internal/infrastructure/db/sqlite/sqlc/queries/db.go b/server/internal/infrastructure/db/sqlite/sqlc/queries/db.go index fa78573..1cbab90 100644 --- a/server/internal/infrastructure/db/sqlite/sqlc/queries/db.go +++ b/server/internal/infrastructure/db/sqlite/sqlc/queries/db.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.26.0 +// sqlc v1.27.0 package queries diff --git a/server/internal/infrastructure/db/sqlite/sqlc/queries/models.go b/server/internal/infrastructure/db/sqlite/sqlc/queries/models.go index e033ab8..f81a5af 100644 --- a/server/internal/infrastructure/db/sqlite/sqlc/queries/models.go +++ b/server/internal/infrastructure/db/sqlite/sqlc/queries/models.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.26.0 +// sqlc v1.27.0 package queries @@ -32,6 +32,7 @@ type PaymentVtxoVw struct { Swept sql.NullBool ExpireAt sql.NullInt64 PaymentID sql.NullString + RedeemTx sql.NullString } type Receiver struct { @@ -85,6 +86,22 @@ type Tx struct { IsLeaf sql.NullBool } +type UncondForfeitTx struct { + ID int64 + Tx string + VtxoTxid string + VtxoVout int64 + Position int64 +} + +type UncondForfeitTxVw struct { + ID sql.NullInt64 + Tx sql.NullString + VtxoTxid sql.NullString + VtxoVout sql.NullInt64 + Position sql.NullInt64 +} + type Vtxo struct { Txid string Vout int64 @@ -97,4 +114,5 @@ type Vtxo struct { Swept bool ExpireAt int64 PaymentID sql.NullString + RedeemTx sql.NullString } diff --git a/server/internal/infrastructure/db/sqlite/sqlc/queries/query.sql.go b/server/internal/infrastructure/db/sqlite/sqlc/queries/query.sql.go index 2dfbc5c..bf7d53e 100644 --- a/server/internal/infrastructure/db/sqlite/sqlc/queries/query.sql.go +++ b/server/internal/infrastructure/db/sqlite/sqlc/queries/query.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.26.0 +// sqlc v1.27.0 // source: query.sql package queries @@ -54,30 +54,45 @@ func (q *Queries) MarkVtxoAsSwept(ctx context.Context, arg MarkVtxoAsSweptParams } const selectNotRedeemedVtxos = `-- name: SelectNotRedeemedVtxos :many -SELECT txid, vout, pubkey, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at, payment_id FROM vtxo WHERE redeemed = false +SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx, + uncond_forfeit_tx_vw.id, uncond_forfeit_tx_vw.tx, uncond_forfeit_tx_vw.vtxo_txid, uncond_forfeit_tx_vw.vtxo_vout, uncond_forfeit_tx_vw.position +FROM vtxo + LEFT OUTER JOIN uncond_forfeit_tx_vw ON vtxo.txid=uncond_forfeit_tx_vw.vtxo_txid AND vtxo.vout=uncond_forfeit_tx_vw.vtxo_vout +WHERE redeemed = false ` -func (q *Queries) SelectNotRedeemedVtxos(ctx context.Context) ([]Vtxo, error) { +type SelectNotRedeemedVtxosRow struct { + Vtxo Vtxo + UncondForfeitTxVw UncondForfeitTxVw +} + +func (q *Queries) SelectNotRedeemedVtxos(ctx context.Context) ([]SelectNotRedeemedVtxosRow, error) { rows, err := q.db.QueryContext(ctx, selectNotRedeemedVtxos) if err != nil { return nil, err } defer rows.Close() - var items []Vtxo + var items []SelectNotRedeemedVtxosRow for rows.Next() { - var i Vtxo + var i SelectNotRedeemedVtxosRow if err := rows.Scan( - &i.Txid, - &i.Vout, - &i.Pubkey, - &i.Amount, - &i.PoolTx, - &i.SpentBy, - &i.Spent, - &i.Redeemed, - &i.Swept, - &i.ExpireAt, - &i.PaymentID, + &i.Vtxo.Txid, + &i.Vtxo.Vout, + &i.Vtxo.Pubkey, + &i.Vtxo.Amount, + &i.Vtxo.PoolTx, + &i.Vtxo.SpentBy, + &i.Vtxo.Spent, + &i.Vtxo.Redeemed, + &i.Vtxo.Swept, + &i.Vtxo.ExpireAt, + &i.Vtxo.PaymentID, + &i.Vtxo.RedeemTx, + &i.UncondForfeitTxVw.ID, + &i.UncondForfeitTxVw.Tx, + &i.UncondForfeitTxVw.VtxoTxid, + &i.UncondForfeitTxVw.VtxoVout, + &i.UncondForfeitTxVw.Position, ); err != nil { return nil, err } @@ -93,30 +108,45 @@ func (q *Queries) SelectNotRedeemedVtxos(ctx context.Context) ([]Vtxo, error) { } const selectNotRedeemedVtxosWithPubkey = `-- name: SelectNotRedeemedVtxosWithPubkey :many -SELECT txid, vout, pubkey, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at, payment_id FROM vtxo WHERE redeemed = false AND pubkey = ? +SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx, + uncond_forfeit_tx_vw.id, uncond_forfeit_tx_vw.tx, uncond_forfeit_tx_vw.vtxo_txid, uncond_forfeit_tx_vw.vtxo_vout, uncond_forfeit_tx_vw.position +FROM vtxo + LEFT OUTER JOIN uncond_forfeit_tx_vw ON vtxo.txid=uncond_forfeit_tx_vw.vtxo_txid AND vtxo.vout=uncond_forfeit_tx_vw.vtxo_vout +WHERE redeemed = false AND pubkey = ? ` -func (q *Queries) SelectNotRedeemedVtxosWithPubkey(ctx context.Context, pubkey string) ([]Vtxo, error) { +type SelectNotRedeemedVtxosWithPubkeyRow struct { + Vtxo Vtxo + UncondForfeitTxVw UncondForfeitTxVw +} + +func (q *Queries) SelectNotRedeemedVtxosWithPubkey(ctx context.Context, pubkey string) ([]SelectNotRedeemedVtxosWithPubkeyRow, error) { rows, err := q.db.QueryContext(ctx, selectNotRedeemedVtxosWithPubkey, pubkey) if err != nil { return nil, err } defer rows.Close() - var items []Vtxo + var items []SelectNotRedeemedVtxosWithPubkeyRow for rows.Next() { - var i Vtxo + var i SelectNotRedeemedVtxosWithPubkeyRow if err := rows.Scan( - &i.Txid, - &i.Vout, - &i.Pubkey, - &i.Amount, - &i.PoolTx, - &i.SpentBy, - &i.Spent, - &i.Redeemed, - &i.Swept, - &i.ExpireAt, - &i.PaymentID, + &i.Vtxo.Txid, + &i.Vtxo.Vout, + &i.Vtxo.Pubkey, + &i.Vtxo.Amount, + &i.Vtxo.PoolTx, + &i.Vtxo.SpentBy, + &i.Vtxo.Spent, + &i.Vtxo.Redeemed, + &i.Vtxo.Swept, + &i.Vtxo.ExpireAt, + &i.Vtxo.PaymentID, + &i.Vtxo.RedeemTx, + &i.UncondForfeitTxVw.ID, + &i.UncondForfeitTxVw.Tx, + &i.UncondForfeitTxVw.VtxoTxid, + &i.UncondForfeitTxVw.VtxoVout, + &i.UncondForfeitTxVw.Position, ); err != nil { return nil, err } @@ -195,7 +225,7 @@ SELECT round.id, round.starting_timestamp, round.ending_timestamp, round.ended, round_payment_vw.id, round_payment_vw.round_id, round_tx_vw.id, round_tx_vw.tx, round_tx_vw.round_id, round_tx_vw.type, round_tx_vw.position, round_tx_vw.txid, round_tx_vw.tree_level, round_tx_vw.parent_txid, round_tx_vw.is_leaf, payment_receiver_vw.payment_id, payment_receiver_vw.pubkey, payment_receiver_vw.amount, payment_receiver_vw.onchain_address, - payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.payment_id + payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.payment_id, payment_vtxo_vw.redeem_tx FROM round LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id @@ -260,6 +290,7 @@ func (q *Queries) SelectRoundWithRoundId(ctx context.Context, id string) ([]Sele &i.PaymentVtxoVw.Swept, &i.PaymentVtxoVw.ExpireAt, &i.PaymentVtxoVw.PaymentID, + &i.PaymentVtxoVw.RedeemTx, ); err != nil { return nil, err } @@ -279,7 +310,7 @@ SELECT round.id, round.starting_timestamp, round.ending_timestamp, round.ended, round_payment_vw.id, round_payment_vw.round_id, round_tx_vw.id, round_tx_vw.tx, round_tx_vw.round_id, round_tx_vw.type, round_tx_vw.position, round_tx_vw.txid, round_tx_vw.tree_level, round_tx_vw.parent_txid, round_tx_vw.is_leaf, payment_receiver_vw.payment_id, payment_receiver_vw.pubkey, payment_receiver_vw.amount, payment_receiver_vw.onchain_address, - payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.payment_id + payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.payment_id, payment_vtxo_vw.redeem_tx FROM round LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id @@ -344,6 +375,7 @@ func (q *Queries) SelectRoundWithRoundTxId(ctx context.Context, txid string) ([] &i.PaymentVtxoVw.Swept, &i.PaymentVtxoVw.ExpireAt, &i.PaymentVtxoVw.PaymentID, + &i.PaymentVtxoVw.RedeemTx, ); err != nil { return nil, err } @@ -363,7 +395,7 @@ SELECT round.id, round.starting_timestamp, round.ending_timestamp, round.ended, round_payment_vw.id, round_payment_vw.round_id, round_tx_vw.id, round_tx_vw.tx, round_tx_vw.round_id, round_tx_vw.type, round_tx_vw.position, round_tx_vw.txid, round_tx_vw.tree_level, round_tx_vw.parent_txid, round_tx_vw.is_leaf, payment_receiver_vw.payment_id, payment_receiver_vw.pubkey, payment_receiver_vw.amount, payment_receiver_vw.onchain_address, - payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.payment_id + payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.payment_id, payment_vtxo_vw.redeem_tx FROM round LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id @@ -428,6 +460,7 @@ func (q *Queries) SelectSweepableRounds(ctx context.Context) ([]SelectSweepableR &i.PaymentVtxoVw.Swept, &i.PaymentVtxoVw.ExpireAt, &i.PaymentVtxoVw.PaymentID, + &i.PaymentVtxoVw.RedeemTx, ); err != nil { return nil, err } @@ -443,30 +476,45 @@ func (q *Queries) SelectSweepableRounds(ctx context.Context) ([]SelectSweepableR } const selectSweepableVtxos = `-- name: SelectSweepableVtxos :many -SELECT txid, vout, pubkey, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at, payment_id FROM vtxo WHERE redeemed = false AND swept = false +SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx, + uncond_forfeit_tx_vw.id, uncond_forfeit_tx_vw.tx, uncond_forfeit_tx_vw.vtxo_txid, uncond_forfeit_tx_vw.vtxo_vout, uncond_forfeit_tx_vw.position +FROM vtxo + LEFT OUTER JOIN uncond_forfeit_tx_vw ON vtxo.txid=uncond_forfeit_tx_vw.vtxo_txid AND vtxo.vout=uncond_forfeit_tx_vw.vtxo_vout +WHERE redeemed = false AND swept = false ` -func (q *Queries) SelectSweepableVtxos(ctx context.Context) ([]Vtxo, error) { +type SelectSweepableVtxosRow struct { + Vtxo Vtxo + UncondForfeitTxVw UncondForfeitTxVw +} + +func (q *Queries) SelectSweepableVtxos(ctx context.Context) ([]SelectSweepableVtxosRow, error) { rows, err := q.db.QueryContext(ctx, selectSweepableVtxos) if err != nil { return nil, err } defer rows.Close() - var items []Vtxo + var items []SelectSweepableVtxosRow for rows.Next() { - var i Vtxo + var i SelectSweepableVtxosRow if err := rows.Scan( - &i.Txid, - &i.Vout, - &i.Pubkey, - &i.Amount, - &i.PoolTx, - &i.SpentBy, - &i.Spent, - &i.Redeemed, - &i.Swept, - &i.ExpireAt, - &i.PaymentID, + &i.Vtxo.Txid, + &i.Vtxo.Vout, + &i.Vtxo.Pubkey, + &i.Vtxo.Amount, + &i.Vtxo.PoolTx, + &i.Vtxo.SpentBy, + &i.Vtxo.Spent, + &i.Vtxo.Redeemed, + &i.Vtxo.Swept, + &i.Vtxo.ExpireAt, + &i.Vtxo.PaymentID, + &i.Vtxo.RedeemTx, + &i.UncondForfeitTxVw.ID, + &i.UncondForfeitTxVw.Tx, + &i.UncondForfeitTxVw.VtxoTxid, + &i.UncondForfeitTxVw.VtxoVout, + &i.UncondForfeitTxVw.Position, ); err != nil { return nil, err } @@ -486,7 +534,7 @@ SELECT round.id, round.starting_timestamp, round.ending_timestamp, round.ended, round_payment_vw.id, round_payment_vw.round_id, round_tx_vw.id, round_tx_vw.tx, round_tx_vw.round_id, round_tx_vw.type, round_tx_vw.position, round_tx_vw.txid, round_tx_vw.tree_level, round_tx_vw.parent_txid, round_tx_vw.is_leaf, payment_receiver_vw.payment_id, payment_receiver_vw.pubkey, payment_receiver_vw.amount, payment_receiver_vw.onchain_address, - payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.payment_id + payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.payment_id, payment_vtxo_vw.redeem_tx FROM round LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id @@ -551,6 +599,7 @@ func (q *Queries) SelectSweptRounds(ctx context.Context) ([]SelectSweptRoundsRow &i.PaymentVtxoVw.Swept, &i.PaymentVtxoVw.ExpireAt, &i.PaymentVtxoVw.PaymentID, + &i.PaymentVtxoVw.RedeemTx, ); err != nil { return nil, err } @@ -566,7 +615,11 @@ func (q *Queries) SelectSweptRounds(ctx context.Context) ([]SelectSweptRoundsRow } const selectVtxoByOutpoint = `-- name: SelectVtxoByOutpoint :one -SELECT txid, vout, pubkey, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at, payment_id FROM vtxo WHERE txid = ? AND vout = ? +SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx, + uncond_forfeit_tx_vw.id, uncond_forfeit_tx_vw.tx, uncond_forfeit_tx_vw.vtxo_txid, uncond_forfeit_tx_vw.vtxo_vout, uncond_forfeit_tx_vw.position +FROM vtxo + LEFT OUTER JOIN uncond_forfeit_tx_vw ON vtxo.txid=uncond_forfeit_tx_vw.vtxo_txid AND vtxo.vout=uncond_forfeit_tx_vw.vtxo_vout +WHERE txid = ? AND vout = ? ` type SelectVtxoByOutpointParams struct { @@ -574,50 +627,76 @@ type SelectVtxoByOutpointParams struct { Vout int64 } -func (q *Queries) SelectVtxoByOutpoint(ctx context.Context, arg SelectVtxoByOutpointParams) (Vtxo, error) { +type SelectVtxoByOutpointRow struct { + Vtxo Vtxo + UncondForfeitTxVw UncondForfeitTxVw +} + +func (q *Queries) SelectVtxoByOutpoint(ctx context.Context, arg SelectVtxoByOutpointParams) (SelectVtxoByOutpointRow, error) { row := q.db.QueryRowContext(ctx, selectVtxoByOutpoint, arg.Txid, arg.Vout) - var i Vtxo + var i SelectVtxoByOutpointRow err := row.Scan( - &i.Txid, - &i.Vout, - &i.Pubkey, - &i.Amount, - &i.PoolTx, - &i.SpentBy, - &i.Spent, - &i.Redeemed, - &i.Swept, - &i.ExpireAt, - &i.PaymentID, + &i.Vtxo.Txid, + &i.Vtxo.Vout, + &i.Vtxo.Pubkey, + &i.Vtxo.Amount, + &i.Vtxo.PoolTx, + &i.Vtxo.SpentBy, + &i.Vtxo.Spent, + &i.Vtxo.Redeemed, + &i.Vtxo.Swept, + &i.Vtxo.ExpireAt, + &i.Vtxo.PaymentID, + &i.Vtxo.RedeemTx, + &i.UncondForfeitTxVw.ID, + &i.UncondForfeitTxVw.Tx, + &i.UncondForfeitTxVw.VtxoTxid, + &i.UncondForfeitTxVw.VtxoVout, + &i.UncondForfeitTxVw.Position, ) return i, err } const selectVtxosByPoolTxid = `-- name: SelectVtxosByPoolTxid :many -SELECT txid, vout, pubkey, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at, payment_id FROM vtxo WHERE pool_tx = ? +SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx, + uncond_forfeit_tx_vw.id, uncond_forfeit_tx_vw.tx, uncond_forfeit_tx_vw.vtxo_txid, uncond_forfeit_tx_vw.vtxo_vout, uncond_forfeit_tx_vw.position +FROM vtxo + LEFT OUTER JOIN uncond_forfeit_tx_vw ON vtxo.txid=uncond_forfeit_tx_vw.vtxo_txid AND vtxo.vout=uncond_forfeit_tx_vw.vtxo_vout +WHERE pool_tx = ? ` -func (q *Queries) SelectVtxosByPoolTxid(ctx context.Context, poolTx string) ([]Vtxo, error) { +type SelectVtxosByPoolTxidRow struct { + Vtxo Vtxo + UncondForfeitTxVw UncondForfeitTxVw +} + +func (q *Queries) SelectVtxosByPoolTxid(ctx context.Context, poolTx string) ([]SelectVtxosByPoolTxidRow, error) { rows, err := q.db.QueryContext(ctx, selectVtxosByPoolTxid, poolTx) if err != nil { return nil, err } defer rows.Close() - var items []Vtxo + var items []SelectVtxosByPoolTxidRow for rows.Next() { - var i Vtxo + var i SelectVtxosByPoolTxidRow if err := rows.Scan( - &i.Txid, - &i.Vout, - &i.Pubkey, - &i.Amount, - &i.PoolTx, - &i.SpentBy, - &i.Spent, - &i.Redeemed, - &i.Swept, - &i.ExpireAt, - &i.PaymentID, + &i.Vtxo.Txid, + &i.Vtxo.Vout, + &i.Vtxo.Pubkey, + &i.Vtxo.Amount, + &i.Vtxo.PoolTx, + &i.Vtxo.SpentBy, + &i.Vtxo.Spent, + &i.Vtxo.Redeemed, + &i.Vtxo.Swept, + &i.Vtxo.ExpireAt, + &i.Vtxo.PaymentID, + &i.Vtxo.RedeemTx, + &i.UncondForfeitTxVw.ID, + &i.UncondForfeitTxVw.Tx, + &i.UncondForfeitTxVw.VtxoTxid, + &i.UncondForfeitTxVw.VtxoVout, + &i.UncondForfeitTxVw.Position, ); err != nil { return nil, err } @@ -803,18 +882,44 @@ func (q *Queries) UpsertTransaction(ctx context.Context, arg UpsertTransactionPa return err } +const upsertUnconditionalForfeitTx = `-- name: UpsertUnconditionalForfeitTx :exec +INSERT INTO uncond_forfeit_tx (tx, vtxo_txid, vtxo_vout, position) +VALUES (?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET + tx = EXCLUDED.tx, + vtxo_txid = EXCLUDED.vtxo_txid, + vtxo_vout = EXCLUDED.vtxo_vout, + position = EXCLUDED.position +` + +type UpsertUnconditionalForfeitTxParams struct { + Tx string + VtxoTxid string + VtxoVout int64 + Position int64 +} + +func (q *Queries) UpsertUnconditionalForfeitTx(ctx context.Context, arg UpsertUnconditionalForfeitTxParams) error { + _, err := q.db.ExecContext(ctx, upsertUnconditionalForfeitTx, + arg.Tx, + arg.VtxoTxid, + arg.VtxoVout, + arg.Position, + ) + return err +} + const upsertVtxo = `-- name: UpsertVtxo :exec -INSERT INTO vtxo (txid, vout, pubkey, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at) -VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid) DO UPDATE SET - vout = excluded.vout, - pubkey = excluded.pubkey, - amount = excluded.amount, - pool_tx = excluded.pool_tx, - spent_by = excluded.spent_by, - spent = excluded.spent, - redeemed = excluded.redeemed, - swept = excluded.swept, - expire_at = excluded.expire_at +INSERT INTO vtxo (txid, vout, pubkey, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at, redeem_tx) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid, vout) DO UPDATE SET + pubkey = EXCLUDED.pubkey, + amount = EXCLUDED.amount, + pool_tx = EXCLUDED.pool_tx, + spent_by = EXCLUDED.spent_by, + spent = EXCLUDED.spent, + redeemed = EXCLUDED.redeemed, + swept = EXCLUDED.swept, + expire_at = EXCLUDED.expire_at, + redeem_tx = EXCLUDED.redeem_tx ` type UpsertVtxoParams struct { @@ -828,6 +933,7 @@ type UpsertVtxoParams struct { Redeemed bool Swept bool ExpireAt int64 + RedeemTx sql.NullString } func (q *Queries) UpsertVtxo(ctx context.Context, arg UpsertVtxoParams) error { @@ -842,6 +948,7 @@ func (q *Queries) UpsertVtxo(ctx context.Context, arg UpsertVtxoParams) error { arg.Redeemed, arg.Swept, arg.ExpireAt, + arg.RedeemTx, ) return err } diff --git a/server/internal/infrastructure/db/sqlite/sqlc/query.sql b/server/internal/infrastructure/db/sqlite/sqlc/query.sql index 713feef..620c1a7 100644 --- a/server/internal/infrastructure/db/sqlite/sqlc/query.sql +++ b/server/internal/infrastructure/db/sqlite/sqlc/query.sql @@ -111,33 +111,61 @@ SELECT id FROM round WHERE starting_timestamp > ? AND starting_timestamp < ?; -- name: SelectRoundIds :many SELECT id FROM round; +-- name: UpsertUnconditionalForfeitTx :exec +INSERT INTO uncond_forfeit_tx (tx, vtxo_txid, vtxo_vout, position) +VALUES (?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET + tx = EXCLUDED.tx, + vtxo_txid = EXCLUDED.vtxo_txid, + vtxo_vout = EXCLUDED.vtxo_vout, + position = EXCLUDED.position; + -- name: UpsertVtxo :exec -INSERT INTO vtxo (txid, vout, pubkey, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at) -VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid) DO UPDATE SET - vout = excluded.vout, - pubkey = excluded.pubkey, - amount = excluded.amount, - pool_tx = excluded.pool_tx, - spent_by = excluded.spent_by, - spent = excluded.spent, - redeemed = excluded.redeemed, - swept = excluded.swept, - expire_at = excluded.expire_at; +INSERT INTO vtxo (txid, vout, pubkey, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at, redeem_tx) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid, vout) DO UPDATE SET + pubkey = EXCLUDED.pubkey, + amount = EXCLUDED.amount, + pool_tx = EXCLUDED.pool_tx, + spent_by = EXCLUDED.spent_by, + spent = EXCLUDED.spent, + redeemed = EXCLUDED.redeemed, + swept = EXCLUDED.swept, + expire_at = EXCLUDED.expire_at, + redeem_tx = EXCLUDED.redeem_tx; -- name: SelectSweepableVtxos :many -SELECT * FROM vtxo WHERE redeemed = false AND swept = false; +SELECT sqlc.embed(vtxo), + sqlc.embed(uncond_forfeit_tx_vw) +FROM vtxo + LEFT OUTER JOIN uncond_forfeit_tx_vw ON vtxo.txid=uncond_forfeit_tx_vw.vtxo_txid AND vtxo.vout=uncond_forfeit_tx_vw.vtxo_vout +WHERE redeemed = false AND swept = false; -- name: SelectNotRedeemedVtxos :many -SELECT * FROM vtxo WHERE redeemed = false; +SELECT sqlc.embed(vtxo), + sqlc.embed(uncond_forfeit_tx_vw) +FROM vtxo + LEFT OUTER JOIN uncond_forfeit_tx_vw ON vtxo.txid=uncond_forfeit_tx_vw.vtxo_txid AND vtxo.vout=uncond_forfeit_tx_vw.vtxo_vout +WHERE redeemed = false; -- name: SelectNotRedeemedVtxosWithPubkey :many -SELECT * FROM vtxo WHERE redeemed = false AND pubkey = ?; +SELECT sqlc.embed(vtxo), + sqlc.embed(uncond_forfeit_tx_vw) +FROM vtxo + LEFT OUTER JOIN uncond_forfeit_tx_vw ON vtxo.txid=uncond_forfeit_tx_vw.vtxo_txid AND vtxo.vout=uncond_forfeit_tx_vw.vtxo_vout +WHERE redeemed = false AND pubkey = ?; -- name: SelectVtxoByOutpoint :one -SELECT * FROM vtxo WHERE txid = ? AND vout = ?; +SELECT sqlc.embed(vtxo), + sqlc.embed(uncond_forfeit_tx_vw) +FROM vtxo + LEFT OUTER JOIN uncond_forfeit_tx_vw ON vtxo.txid=uncond_forfeit_tx_vw.vtxo_txid AND vtxo.vout=uncond_forfeit_tx_vw.vtxo_vout +WHERE txid = ? AND vout = ?; -- name: SelectVtxosByPoolTxid :many -SELECT * FROM vtxo WHERE pool_tx = ?; +SELECT sqlc.embed(vtxo), + sqlc.embed(uncond_forfeit_tx_vw) +FROM vtxo + LEFT OUTER JOIN uncond_forfeit_tx_vw ON vtxo.txid=uncond_forfeit_tx_vw.vtxo_txid AND vtxo.vout=uncond_forfeit_tx_vw.vtxo_vout +WHERE pool_tx = ?; -- name: MarkVtxoAsRedeemed :exec UPDATE vtxo SET redeemed = true WHERE txid = ? AND vout = ?; diff --git a/server/internal/infrastructure/db/sqlite/vtxo_repo.go b/server/internal/infrastructure/db/sqlite/vtxo_repo.go index 0cea81b..204a66a 100644 --- a/server/internal/infrastructure/db/sqlite/vtxo_repo.go +++ b/server/internal/infrastructure/db/sqlite/vtxo_repo.go @@ -35,10 +35,14 @@ func (v *vxtoRepository) Close() { func (v *vxtoRepository) AddVtxos(ctx context.Context, vtxos []domain.Vtxo) error { txBody := func(querierWithTx *queries.Queries) error { - for _, vtxo := range vtxos { + for i := range vtxos { + vtxo := vtxos[i] + var redeemTx string + if vtxo.AsyncPayment != nil { + redeemTx = vtxo.AsyncPayment.RedeemTx + } if err := querierWithTx.UpsertVtxo( - ctx, - queries.UpsertVtxoParams{ + ctx, queries.UpsertVtxoParams{ Txid: vtxo.Txid, Vout: int64(vtxo.VOut), Pubkey: vtxo.Pubkey, @@ -49,10 +53,24 @@ func (v *vxtoRepository) AddVtxos(ctx context.Context, vtxos []domain.Vtxo) erro Redeemed: vtxo.Redeemed, Swept: vtxo.Swept, ExpireAt: vtxo.ExpireAt, + RedeemTx: sql.NullString{String: redeemTx, Valid: true}, }, ); err != nil { return err } + + if vtxo.AsyncPayment != nil { + for i, tx := range vtxo.AsyncPayment.UnconditionalForfeitTxs { + if err := querierWithTx.UpsertUnconditionalForfeitTx(ctx, queries.UpsertUnconditionalForfeitTxParams{ + Tx: tx, + VtxoTxid: vtxo.Txid, + VtxoVout: int64(vtxo.VOut), + Position: int64(i), + }); err != nil { + return err + } + } + } } return nil @@ -62,27 +80,49 @@ func (v *vxtoRepository) AddVtxos(ctx context.Context, vtxos []domain.Vtxo) erro } func (v *vxtoRepository) GetAllSweepableVtxos(ctx context.Context) ([]domain.Vtxo, error) { - rows, err := v.querier.SelectSweepableVtxos(ctx) + res, err := v.querier.SelectSweepableVtxos(ctx) if err != nil { return nil, err } + rows := make([]vtxoWithUnconditionalForfeitTxs, 0, len(res)) + for _, row := range res { + rows = append(rows, vtxoWithUnconditionalForfeitTxs{ + vtxo: row.Vtxo, + tx: row.UncondForfeitTxVw, + }) + } return readRows(rows) } func (v *vxtoRepository) GetAllVtxos(ctx context.Context, pubkey string) ([]domain.Vtxo, []domain.Vtxo, error) { withPubkey := len(pubkey) > 0 - var rows []queries.Vtxo - var err error - + var rows []vtxoWithUnconditionalForfeitTxs if withPubkey { - rows, err = v.querier.SelectNotRedeemedVtxosWithPubkey(ctx, pubkey) + res, err := v.querier.SelectNotRedeemedVtxosWithPubkey(ctx, pubkey) + if err != nil { + return nil, nil, err + } + rows = make([]vtxoWithUnconditionalForfeitTxs, 0, len(res)) + for _, row := range res { + rows = append(rows, vtxoWithUnconditionalForfeitTxs{ + vtxo: row.Vtxo, + tx: row.UncondForfeitTxVw, + }) + } } else { - rows, err = v.querier.SelectNotRedeemedVtxos(ctx) - } - if err != nil { - return nil, nil, err + res, err := v.querier.SelectNotRedeemedVtxos(ctx) + if err != nil { + return nil, nil, err + } + rows = make([]vtxoWithUnconditionalForfeitTxs, 0, len(res)) + for _, row := range res { + rows = append(rows, vtxoWithUnconditionalForfeitTxs{ + vtxo: row.Vtxo, + tx: row.UncondForfeitTxVw, + }) + } } vtxos, err := readRows(rows) @@ -107,7 +147,7 @@ func (v *vxtoRepository) GetAllVtxos(ctx context.Context, pubkey string) ([]doma func (v *vxtoRepository) GetVtxos(ctx context.Context, outpoints []domain.VtxoKey) ([]domain.Vtxo, error) { vtxos := make([]domain.Vtxo, 0, len(outpoints)) for _, o := range outpoints { - vtxo, err := v.querier.SelectVtxoByOutpoint( + res, err := v.querier.SelectVtxoByOutpoint( ctx, queries.SelectVtxoByOutpointParams{ Txid: o.Txid, @@ -118,7 +158,12 @@ func (v *vxtoRepository) GetVtxos(ctx context.Context, outpoints []domain.VtxoKe return nil, err } - result, err := readRows([]queries.Vtxo{vtxo}) + result, err := readRows([]vtxoWithUnconditionalForfeitTxs{ + { + vtxo: res.Vtxo, + tx: res.UncondForfeitTxVw, + }, + }) if err != nil { return nil, err } @@ -134,10 +179,17 @@ func (v *vxtoRepository) GetVtxos(ctx context.Context, outpoints []domain.VtxoKe } func (v *vxtoRepository) GetVtxosForRound(ctx context.Context, txid string) ([]domain.Vtxo, error) { - rows, err := v.querier.SelectVtxosByPoolTxid(ctx, txid) + res, err := v.querier.SelectVtxosByPoolTxid(ctx, txid) if err != nil { return nil, err } + rows := make([]vtxoWithUnconditionalForfeitTxs, 0, len(res)) + for _, row := range res { + rows = append(rows, vtxoWithUnconditionalForfeitTxs{ + vtxo: row.Vtxo, + tx: row.UncondForfeitTxVw, + }) + } return readRows(rows) } @@ -224,7 +276,18 @@ func (v *vxtoRepository) UpdateExpireAt(ctx context.Context, vtxos []domain.Vtxo return execTx(ctx, v.db, txBody) } -func rowToVtxo(row queries.Vtxo) domain.Vtxo { +func rowToVtxo(row queries.Vtxo, uncondForfeitTxs []queries.UncondForfeitTxVw) domain.Vtxo { + var asyncPayment *domain.AsyncPaymentTxs + if row.RedeemTx.Valid && len(uncondForfeitTxs) > 0 { + txs := make([]string, len(uncondForfeitTxs)) + for _, tx := range uncondForfeitTxs { + txs[tx.Position.Int64] = tx.Tx.String + } + asyncPayment = &domain.AsyncPaymentTxs{ + RedeemTx: row.RedeemTx.String, + UnconditionalForfeitTxs: txs, + } + } return domain.Vtxo{ VtxoKey: domain.VtxoKey{ Txid: row.Txid, @@ -234,19 +297,48 @@ func rowToVtxo(row queries.Vtxo) domain.Vtxo { Pubkey: row.Pubkey, Amount: uint64(row.Amount), }, - PoolTx: row.PoolTx, - SpentBy: row.SpentBy, - Spent: row.Spent, - Redeemed: row.Redeemed, - Swept: row.Swept, - ExpireAt: row.ExpireAt, + PoolTx: row.PoolTx, + SpentBy: row.SpentBy, + Spent: row.Spent, + Redeemed: row.Redeemed, + Swept: row.Swept, + ExpireAt: row.ExpireAt, + AsyncPayment: asyncPayment, } } -func readRows(rows []queries.Vtxo) ([]domain.Vtxo, error) { +type vtxoWithUnconditionalForfeitTxs struct { + vtxo queries.Vtxo + tx queries.UncondForfeitTxVw +} + +func readRows(rows []vtxoWithUnconditionalForfeitTxs) ([]domain.Vtxo, error) { + uncondForfeitTxsMap := make(map[domain.VtxoKey][]queries.UncondForfeitTxVw) + for _, row := range rows { + if !row.vtxo.RedeemTx.Valid { + continue + } + vtxoKey := domain.VtxoKey{ + Txid: row.vtxo.Txid, + VOut: uint32(row.vtxo.Vout), + } + if _, ok := uncondForfeitTxsMap[vtxoKey]; !ok { + uncondForfeitTxsMap[vtxoKey] = make([]queries.UncondForfeitTxVw, 0) + } + if row.tx.Tx.Valid { + uncondForfeitTxsMap[vtxoKey] = append( + uncondForfeitTxsMap[vtxoKey], row.tx, + ) + } + } vtxos := make([]domain.Vtxo, 0, len(rows)) - for _, v := range rows { - vtxos = append(vtxos, rowToVtxo(v)) + for _, row := range rows { + vtxoKey := domain.VtxoKey{ + Txid: row.vtxo.Txid, + VOut: uint32(row.vtxo.Vout), + } + uncondForfeitTxs := uncondForfeitTxsMap[vtxoKey] + vtxos = append(vtxos, rowToVtxo(row.vtxo, uncondForfeitTxs)) } return vtxos, nil diff --git a/server/internal/infrastructure/tx-builder/covenant/builder.go b/server/internal/infrastructure/tx-builder/covenant/builder.go index 8698bf8..84dc605 100644 --- a/server/internal/infrastructure/tx-builder/covenant/builder.go +++ b/server/internal/infrastructure/tx-builder/covenant/builder.go @@ -316,6 +316,12 @@ func (b *txBuilder) FindLeaves( return foundLeaves, nil } +func (b *txBuilder) BuildAsyncPaymentTransactions( + _ []domain.Vtxo, _ *secp256k1.PublicKey, _ []domain.Receiver, _ uint64, +) (*domain.AsyncPaymentTxs, error) { + return nil, fmt.Errorf("not implemented") +} + func (b *txBuilder) getLeafScriptAndTree( userPubkey, aspPubkey *secp256k1.PublicKey, ) ([]byte, *taproot.IndexedElementsTapScriptTree, error) { diff --git a/server/internal/infrastructure/tx-builder/covenantless/builder.go b/server/internal/infrastructure/tx-builder/covenantless/builder.go index 049e44e..f5911aa 100644 --- a/server/internal/infrastructure/tx-builder/covenantless/builder.go +++ b/server/internal/infrastructure/tx-builder/covenantless/builder.go @@ -303,6 +303,171 @@ func (b *txBuilder) FindLeaves(congestionTree tree.CongestionTree, fromtxid stri return foundLeaves, nil } +// TODO add locktimes to txs +func (b *txBuilder) BuildAsyncPaymentTransactions( + vtxos []domain.Vtxo, aspPubKey *secp256k1.PublicKey, + receivers []domain.Receiver, minRelayFee uint64, +) (*domain.AsyncPaymentTxs, error) { + if len(vtxos) <= 0 { + return nil, fmt.Errorf("missing vtxos") + } + + ins := make([]*wire.OutPoint, 0, len(vtxos)) + outs := make([]*wire.TxOut, 0, len(receivers)) + unconditionalForfeitTxs := make([]string, 0, len(vtxos)) + for _, vtxo := range vtxos { + if vtxo.Spent { + return nil, fmt.Errorf("all vtxos must be unspent") + } + + senderBytes, err := hex.DecodeString(vtxo.Pubkey) + if err != nil { + return nil, err + } + + sender, err := secp256k1.ParsePubKey(senderBytes) + if err != nil { + return nil, err + } + + aspScript, err := p2trScript(aspPubKey, b.onchainNetwork()) + if err != nil { + return nil, err + } + + vtxoTxID, err := chainhash.NewHashFromStr(vtxo.Txid) + if err != nil { + return nil, err + } + + vtxoOutpoint := &wire.OutPoint{ + Hash: *vtxoTxID, + Index: vtxo.VOut, + } + + vtxoScript, vtxoTree, err := b.getLeafScriptAndTree(sender, aspPubKey) + if err != nil { + return nil, err + } + + output := &wire.TxOut{ + PkScript: aspScript, + Value: int64(vtxo.Amount - minRelayFee), + } + + forfeitClosure := &bitcointree.MultisigClosure{ + Pubkey: sender, + AspPubkey: aspPubKey, + } + + forfeitLeaf, err := forfeitClosure.Leaf() + if err != nil { + return nil, err + } + + leafProof := vtxoTree.LeafMerkleProofs[vtxoTree.LeafProofIndex[forfeitLeaf.TapHash()]] + ctrlBlock := leafProof.ToControlBlock(bitcointree.UnspendableKey()) + ctrlBlockBytes, err := ctrlBlock.ToBytes() + if err != nil { + return nil, err + } + + unconditionnalForfeitPtx, err := psbt.New( + []*wire.OutPoint{vtxoOutpoint}, + []*wire.TxOut{output}, + 2, + 0, + []uint32{wire.MaxTxInSequenceNum}, + ) + if err != nil { + return nil, err + } + + unconditionnalForfeitPtx.Inputs[0].WitnessUtxo = &wire.TxOut{ + Value: int64(vtxo.Amount), + PkScript: vtxoScript, + } + + unconditionnalForfeitPtx.Inputs[0].TaprootInternalKey = schnorr.SerializePubKey(bitcointree.UnspendableKey()) + unconditionnalForfeitPtx.Inputs[0].TaprootLeafScript = []*psbt.TaprootTapLeafScript{ + { + ControlBlock: ctrlBlockBytes, + Script: forfeitLeaf.Script, + LeafVersion: txscript.BaseLeafVersion, + }, + } + + forfeitTx, err := unconditionnalForfeitPtx.B64Encode() + if err != nil { + return nil, err + } + + unconditionalForfeitTxs = append(unconditionalForfeitTxs, forfeitTx) + ins = append(ins, vtxoOutpoint) + } + + for i, receiver := range receivers { + // TODO (@louisinger): Add revert policy (sender+ASP) + buf, err := hex.DecodeString(receiver.Pubkey) + if err != nil { + return nil, err + } + receiverPk, err := secp256k1.ParsePubKey(buf) + if err != nil { + return nil, err + } + newVtxoScript, _, err := b.getLeafScriptAndTree(receiverPk, aspPubKey) + if err != nil { + return nil, err + } + + // Deduct the min relay fee from the very last receiver which is supposed + // to be the change in case it's not a send-all. + value := receiver.Amount + if i == len(receivers)-1 { + value -= minRelayFee + } + outs = append(outs, &wire.TxOut{ + Value: int64(value), + PkScript: newVtxoScript, + }) + } + + redeemPtx, err := psbt.New( + ins, outs, 2, 0, []uint32{wire.MaxTxInSequenceNum}, + ) + if err != nil { + return nil, err + } + + for i := range redeemPtx.Inputs { + unconditionnalForfeitPsbt, _ := psbt.NewFromRawBytes( + strings.NewReader(unconditionalForfeitTxs[i]), true, + ) + redeemPtx.Inputs[i].WitnessUtxo = unconditionnalForfeitPsbt.Inputs[0].WitnessUtxo + redeemPtx.Inputs[i].TaprootInternalKey = unconditionnalForfeitPsbt.Inputs[0].TaprootInternalKey + redeemPtx.Inputs[i].TaprootLeafScript = unconditionnalForfeitPsbt.Inputs[0].TaprootLeafScript + + } + + redeemTx, err := redeemPtx.B64Encode() + if err != nil { + return nil, err + } + + signedRedeemTx, err := b.wallet.SignTransactionTapscript( + context.Background(), redeemTx, nil, + ) + if err != nil { + return nil, err + } + + return &domain.AsyncPaymentTxs{ + RedeemTx: signedRedeemTx, + UnconditionalForfeitTxs: unconditionalForfeitTxs, + }, nil +} + func (b *txBuilder) getLeafScriptAndTree( userPubkey, aspPubkey *secp256k1.PublicKey, ) ([]byte, *txscript.IndexedTapScriptTree, error) { @@ -316,7 +481,7 @@ func (b *txBuilder) getLeafScriptAndTree( return nil, nil, err } - forfeitClosure := &bitcointree.ForfeitClosure{ + forfeitClosure := &bitcointree.MultisigClosure{ Pubkey: userPubkey, AspPubkey: aspPubkey, } @@ -693,7 +858,9 @@ func (b *txBuilder) createConnectors( func (b *txBuilder) createForfeitTxs( aspPubkey *secp256k1.PublicKey, payments []domain.Payment, connectors []*psbt.Packet, minRelayFee uint64, ) ([]string, error) { - aspScript, err := p2wpkhScript(aspPubkey, b.onchainNetwork()) + // TODO (@louisinger): are we sure about this change? + aspScript, err := p2trScript(aspPubkey, b.onchainNetwork()) + // aspScript, err := p2wpkhScript(aspPubkey, b.onchainNetwork()) if err != nil { return nil, err } @@ -719,7 +886,7 @@ func (b *txBuilder) createForfeitTxs( var forfeitProof *txscript.TapscriptProof for _, proof := range vtxoTaprootTree.LeafMerkleProofs { - isForfeit, err := (&bitcointree.ForfeitClosure{}).Decode(proof.Script) + isForfeit, err := (&bitcointree.MultisigClosure{}).Decode(proof.Script) if !isForfeit || err != nil { continue } diff --git a/server/internal/infrastructure/tx-builder/covenantless/utils.go b/server/internal/infrastructure/tx-builder/covenantless/utils.go index e70b5cb..7fa31fe 100644 --- a/server/internal/infrastructure/tx-builder/covenantless/utils.go +++ b/server/internal/infrastructure/tx-builder/covenantless/utils.go @@ -10,7 +10,7 @@ import ( "github.com/decred/dcrd/dcrec/secp256k1/v4" ) -func p2wpkhScript(publicKey *secp256k1.PublicKey, net *chaincfg.Params) ([]byte, error) { +func p2trScript(publicKey *secp256k1.PublicKey, net *chaincfg.Params) ([]byte, error) { tapKey := txscript.ComputeTaprootKeyNoScript(publicKey) payment, err := btcutil.NewAddressWitnessPubKeyHash( diff --git a/server/internal/infrastructure/wallet/btc-embedded/psbt.go b/server/internal/infrastructure/wallet/btc-embedded/psbt.go index 940418e..d99e065 100644 --- a/server/internal/infrastructure/wallet/btc-embedded/psbt.go +++ b/server/internal/infrastructure/wallet/btc-embedded/psbt.go @@ -93,7 +93,7 @@ func (s *service) signPsbt(packet *psbt.Packet) ([]uint32, error) { } } - // TODO: @louisinger shall we delete this code? + // TODO (@louisinger): shall we delete this code? // prevOutputFetcher := wallet.PsbtPrevOutputFetcher(packet) // sigHashes := txscript.NewTxSigHashes(tx, prevOutputFetcher) diff --git a/server/internal/infrastructure/wallet/btc-embedded/wallet.go b/server/internal/infrastructure/wallet/btc-embedded/wallet.go index edd5eda..40e22e7 100644 --- a/server/internal/infrastructure/wallet/btc-embedded/wallet.go +++ b/server/internal/infrastructure/wallet/btc-embedded/wallet.go @@ -177,6 +177,82 @@ func (s *service) Restore(_ context.Context, seed, password string) error { } func (s *service) Unlock(_ context.Context, password string) error { + if s.wallet == nil { + pwd := []byte(password) + opt := btcwallet.LoaderWithLocalWalletDB(s.cfg.Datadir, false, time.Minute) + config := btcwallet.Config{ + LogDir: s.cfg.Datadir, + PrivatePass: pwd, + PublicPass: pwd, + Birthday: time.Now(), + RecoveryWindow: 0, + NetParams: s.cfg.chainParams(), + LoaderOptions: []btcwallet.LoaderOption{opt}, + CoinSelectionStrategy: wallet.CoinSelectionLargest, + ChainSource: s.chainSource, + } + blockCache := blockcache.NewBlockCache(20 * 1024 * 1024) + + wallet, err := btcwallet.New(config, blockCache) + if err != nil { + return fmt.Errorf("failed to setup wallet loader: %s", err) + } + + if err := wallet.Start(); err != nil { + return fmt.Errorf("failed to start wallet: %s", err) + } + + for { + if !wallet.InternalWallet().ChainSynced() { + log.Debug("waiting sync....") + time.Sleep(3 * time.Second) + continue + } + break + } + log.Debugf("chain synced") + + addrs, err := wallet.ListAddresses(string(aspKeyAccount), false) + if err != nil { + return err + } + for info, addrs := range addrs { + if info.AccountName != string(aspKeyAccount) { + continue + } + + for _, addr := range addrs { + if addr.Internal { + continue + } + + splittedPath := strings.Split(addr.DerivationPath, "/") + last := splittedPath[len(splittedPath)-1] + if last == "0" { + decoded, err := btcutil.DecodeAddress(addr.Address, s.cfg.chainParams()) + if err != nil { + return err + } + + infos, err := wallet.AddressInfo(decoded) + if err != nil { + return err + } + + managedPubkeyAddr, ok := infos.(waddrmgr.ManagedPubKeyAddress) + if !ok { + return fmt.Errorf("failed to cast address to managed pubkey address") + } + + s.aspTaprootAddr = managedPubkeyAddr + break + } + } + } + + s.wallet = wallet + return nil + } return s.wallet.InternalWallet().Unlock([]byte(password), nil) } diff --git a/server/internal/interface/grpc/handlers/arkservice.go b/server/internal/interface/grpc/handlers/arkservice.go index 670b836..6b9b3ad 100644 --- a/server/internal/interface/grpc/handlers/arkservice.go +++ b/server/internal/interface/grpc/handlers/arkservice.go @@ -40,6 +40,48 @@ func NewHandler(service application.Service) arkv1.ArkServiceServer { return h } +func (h *handler) CompletePayment(ctx context.Context, req *arkv1.CompletePaymentRequest) (*arkv1.CompletePaymentResponse, error) { + if req.GetSignedRedeemTx() == "" { + return nil, status.Error(codes.InvalidArgument, "missing signed redeem tx") + } + + if len(req.GetSignedUnconditionalForfeitTxs()) <= 0 { + return nil, status.Error(codes.InvalidArgument, "missing signed unconditional forfeit txs") + } + + if err := h.svc.CompleteAsyncPayment( + ctx, req.GetSignedRedeemTx(), req.GetSignedUnconditionalForfeitTxs(), + ); err != nil { + return nil, err + } + + return &arkv1.CompletePaymentResponse{}, nil +} + +func (h *handler) CreatePayment(ctx context.Context, req *arkv1.CreatePaymentRequest) (*arkv1.CreatePaymentResponse, error) { + vtxosKeys, err := parseInputs(req.GetInputs()) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + receivers, err := parseReceivers(req.GetOutputs()) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + redeemTx, unconditionalForfeitTxs, err := h.svc.CreateAsyncPayment( + ctx, vtxosKeys, receivers, + ) + if err != nil { + return nil, err + } + + return &arkv1.CreatePaymentResponse{ + SignedRedeemTx: redeemTx, + UsignedUnconditionalForfeitTxs: unconditionalForfeitTxs, + }, nil +} + func (h *handler) Onboard(ctx context.Context, req *arkv1.OnboardRequest) (*arkv1.OnboardResponse, error) { if req.GetUserPubkey() == "" { return nil, status.Error(codes.InvalidArgument, "missing user pubkey") @@ -98,12 +140,9 @@ func (h *handler) Ping(ctx context.Context, req *arkv1.PingRequest) (*arkv1.Ping } func (h *handler) RegisterPayment(ctx context.Context, req *arkv1.RegisterPaymentRequest) (*arkv1.RegisterPaymentResponse, error) { - vtxosKeys := make([]domain.VtxoKey, 0, len(req.GetInputs())) - for _, input := range req.GetInputs() { - vtxosKeys = append(vtxosKeys, domain.VtxoKey{ - Txid: input.GetTxid(), - VOut: input.GetVout(), - }) + vtxosKeys, err := parseInputs(req.GetInputs()) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) } id, err := h.svc.SpendVtxos(ctx, vtxosKeys) @@ -350,6 +389,13 @@ func (v vtxoList) toProto(hrp string, aspKey *secp256k1.PublicKey) []*arkv1.Vtxo key, _ := secp256k1.ParsePubKey(buf) addr, _ = common.EncodeAddress(hrp, key, aspKey) } + var pendingData *arkv1.PendingPayment + if vv.AsyncPayment != nil { + pendingData = &arkv1.PendingPayment{ + RedeemTx: vv.AsyncPayment.RedeemTx, + UnconditionalForfeitTxs: vv.AsyncPayment.UnconditionalForfeitTxs, + } + } list = append(list, &arkv1.Vtxo{ Outpoint: &arkv1.Input{ Txid: vv.Txid, @@ -359,13 +405,16 @@ func (v vtxoList) toProto(hrp string, aspKey *secp256k1.PublicKey) []*arkv1.Vtxo Address: addr, Amount: vv.Amount, }, - PoolTxid: vv.PoolTx, - Spent: vv.Spent, - ExpireAt: vv.ExpireAt, - SpentBy: vv.SpentBy, - Swept: vv.Swept, + PoolTxid: vv.PoolTx, + Spent: vv.Spent, + ExpireAt: vv.ExpireAt, + SpentBy: vv.SpentBy, + Swept: vv.Swept, + PendingData: pendingData, + Pending: pendingData != nil, }) } + return list } diff --git a/server/internal/interface/grpc/handlers/utils.go b/server/internal/interface/grpc/handlers/utils.go index f69f93e..5e045aa 100644 --- a/server/internal/interface/grpc/handlers/utils.go +++ b/server/internal/interface/grpc/handlers/utils.go @@ -30,6 +30,21 @@ func parseAddress(addr string) (string, *secp256k1.PublicKey, *secp256k1.PublicK return common.DecodeAddress(addr) } +func parseInputs(ins []*arkv1.Input) ([]domain.VtxoKey, error) { + if len(ins) <= 0 { + return nil, fmt.Errorf("missing inputs") + } + + vtxos := make([]domain.VtxoKey, 0, len(ins)) + for _, input := range ins { + vtxos = append(vtxos, domain.VtxoKey{ + Txid: input.GetTxid(), + VOut: input.GetVout(), + }) + } + return vtxos, nil +} + func parseReceivers(outs []*arkv1.Output) ([]domain.Receiver, error) { receivers := make([]domain.Receiver, 0, len(outs)) for _, out := range outs { diff --git a/server/internal/interface/grpc/permissions/permissions.go b/server/internal/interface/grpc/permissions/permissions.go index 440ddae..8aded4a 100644 --- a/server/internal/interface/grpc/permissions/permissions.go +++ b/server/internal/interface/grpc/permissions/permissions.go @@ -149,6 +149,14 @@ func Whitelist() map[string][]bakery.Op { Entity: EntityArk, Action: "write", }}, + fmt.Sprintf("/%s/CreatePayment", arkv1.ArkService_ServiceDesc.ServiceName): {{ + Entity: EntityArk, + Action: "write", + }}, + fmt.Sprintf("/%s/CompletePayment", arkv1.ArkService_ServiceDesc.ServiceName): {{ + Entity: EntityArk, + Action: "write", + }}, fmt.Sprintf("/%s/Check", grpchealth.Health_ServiceDesc.ServiceName): {{ Entity: EntityHealth, Action: "read", diff --git a/server/test/e2e/covenantless/e2e_test.go b/server/test/e2e/covenantless/e2e_test.go index 372a2ee..9a800a6 100644 --- a/server/test/e2e/covenantless/e2e_test.go +++ b/server/test/e2e/covenantless/e2e_test.go @@ -109,6 +109,14 @@ func TestSendOffchain(t *testing.T) { require.NoError(t, err) require.NoError(t, json.Unmarshal([]byte(balanceStr), &balance)) require.NotZero(t, balance.Offchain.Total) + + _, err = runClarkCommand("claim", "--password", utils.Password) + require.NoError(t, err) + + balanceStr, err = runClarkCommand("balance") + require.NoError(t, err) + require.NoError(t, json.Unmarshal([]byte(balanceStr), &balance)) + require.NotZero(t, balance.Offchain.Total) } func TestUnilateralExit(t *testing.T) {