Drop unconditional forfeits txs in offline payment (#344)

* remove unconditionnal forfeit tx

* fix sqlite vtxo repo

* remove pendingData struct

* delete uncond_forfeits_tx table
This commit is contained in:
Louis Singer
2024-10-04 18:06:00 +02:00
committed by GitHub
parent 1d40892196
commit 7606b4cd00
33 changed files with 1654 additions and 1041 deletions

View File

@@ -511,12 +511,6 @@
"properties": { "properties": {
"signedRedeemTx": { "signedRedeemTx": {
"type": "string" "type": "string"
},
"signedUnconditionalForfeitTxs": {
"type": "array",
"items": {
"type": "string"
}
} }
} }
}, },
@@ -548,12 +542,6 @@
"signedRedeemTx": { "signedRedeemTx": {
"type": "string", "type": "string",
"title": "signed only by the ASP" "title": "signed only by the ASP"
},
"usignedUnconditionalForfeitTxs": {
"type": "array",
"items": {
"type": "string"
}
} }
} }
}, },
@@ -735,20 +723,6 @@
} }
} }
}, },
"v1PendingPayment": {
"type": "object",
"properties": {
"redeemTx": {
"type": "string"
},
"unconditionalForfeitTxs": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"v1PingResponse": { "v1PingResponse": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -1094,8 +1068,8 @@
"pending": { "pending": {
"type": "boolean" "type": "boolean"
}, },
"pendingData": { "redeemTx": {
"$ref": "#/definitions/v1PendingPayment" "type": "string"
}, },
"amount": { "amount": {
"type": "string", "type": "string",

View File

@@ -193,12 +193,10 @@ message CreatePaymentRequest {
} }
message CreatePaymentResponse { message CreatePaymentResponse {
string signed_redeem_tx = 1; // signed only by the ASP string signed_redeem_tx = 1; // signed only by the ASP
repeated string usigned_unconditional_forfeit_txs = 2;
} }
message CompletePaymentRequest { message CompletePaymentRequest {
string signed_redeem_tx = 1; string signed_redeem_tx = 1;
repeated string signed_unconditional_forfeit_txs = 2;
} }
message CompletePaymentResponse {} message CompletePaymentResponse {}
@@ -318,14 +316,10 @@ message Vtxo {
int64 expire_at = 6; int64 expire_at = 6;
bool swept = 7; bool swept = 7;
bool pending = 8; bool pending = 8;
PendingPayment pending_data = 9; string redeem_tx = 9;
uint64 amount = 10; uint64 amount = 10;
} }
message PendingPayment {
string redeem_tx = 1;
repeated string unconditional_forfeit_txs =2;
}
message GetTransactionsStreamRequest {} message GetTransactionsStreamRequest {}
message GetTransactionsStreamResponse { message GetTransactionsStreamResponse {

File diff suppressed because it is too large Load Diff

View File

@@ -42,9 +42,9 @@ type ASPClient interface {
Ping(ctx context.Context, paymentID string) (RoundEvent, error) Ping(ctx context.Context, paymentID string) (RoundEvent, error)
CreatePayment( CreatePayment(
ctx context.Context, inputs []Input, outputs []Output, ctx context.Context, inputs []Input, outputs []Output,
) (string, []string, error) ) (string, error)
CompletePayment( CompletePayment(
ctx context.Context, signedRedeemTx string, signedUnconditionalForfeitTxs []string, ctx context.Context, signedRedeemTx string,
) error ) error
ListVtxos(ctx context.Context, addr string) ([]Vtxo, []Vtxo, error) ListVtxos(ctx context.Context, addr string) ([]Vtxo, []Vtxo, error)
GetRound(ctx context.Context, txID string) (*Round, error) GetRound(ctx context.Context, txID string) (*Round, error)
@@ -85,7 +85,6 @@ type Vtxo struct {
RoundTxid string RoundTxid string
ExpiresAt *time.Time ExpiresAt *time.Time
RedeemTx string RedeemTx string
UnconditionalForfeitTxs []string
Pending bool Pending bool
SpentBy string SpentBy string
} }

View File

@@ -238,24 +238,23 @@ func (a *grpcClient) Ping(
func (a *grpcClient) CreatePayment( func (a *grpcClient) CreatePayment(
ctx context.Context, inputs []client.Input, outputs []client.Output, ctx context.Context, inputs []client.Input, outputs []client.Output,
) (string, []string, error) { ) (string, error) {
req := &arkv1.CreatePaymentRequest{ req := &arkv1.CreatePaymentRequest{
Inputs: ins(inputs).toProto(), Inputs: ins(inputs).toProto(),
Outputs: outs(outputs).toProto(), Outputs: outs(outputs).toProto(),
} }
resp, err := a.svc.CreatePayment(ctx, req) resp, err := a.svc.CreatePayment(ctx, req)
if err != nil { if err != nil {
return "", nil, err return "", err
} }
return resp.SignedRedeemTx, resp.UsignedUnconditionalForfeitTxs, nil return resp.SignedRedeemTx, nil
} }
func (a *grpcClient) CompletePayment( func (a *grpcClient) CompletePayment(
ctx context.Context, redeemTx string, signedForfeitTxs []string, ctx context.Context, redeemTx string,
) error { ) error {
req := &arkv1.CompletePaymentRequest{ req := &arkv1.CompletePaymentRequest{
SignedRedeemTx: redeemTx, SignedRedeemTx: redeemTx,
SignedUnconditionalForfeitTxs: signedForfeitTxs,
} }
_, err := a.svc.CompletePayment(ctx, req) _, err := a.svc.CompletePayment(ctx, req)
return err return err

View File

@@ -118,12 +118,6 @@ func (v vtxo) toVtxo() client.Vtxo {
t := time.Unix(v.GetExpireAt(), 0) t := time.Unix(v.GetExpireAt(), 0)
expiresAt = &t expiresAt = &t
} }
var redeemTx string
var uncondForfeitTxs []string
if v.GetPendingData() != nil {
redeemTx = v.GetPendingData().GetRedeemTx()
uncondForfeitTxs = v.GetPendingData().GetUnconditionalForfeitTxs()
}
return client.Vtxo{ return client.Vtxo{
Outpoint: client.Outpoint{ Outpoint: client.Outpoint{
Txid: v.GetOutpoint().GetTxid(), Txid: v.GetOutpoint().GetTxid(),
@@ -133,8 +127,7 @@ func (v vtxo) toVtxo() client.Vtxo {
RoundTxid: v.GetRoundTxid(), RoundTxid: v.GetRoundTxid(),
ExpiresAt: expiresAt, ExpiresAt: expiresAt,
Pending: v.GetPending(), Pending: v.GetPending(),
RedeemTx: redeemTx, RedeemTx: v.GetRedeemTx(),
UnconditionalForfeitTxs: uncondForfeitTxs,
SpentBy: v.GetSpentBy(), SpentBy: v.GetSpentBy(),
Descriptor: v.GetDescriptor_(), Descriptor: v.GetDescriptor_(),
} }

View File

@@ -338,7 +338,7 @@ func (a *restClient) Ping(
func (a *restClient) CreatePayment( func (a *restClient) CreatePayment(
ctx context.Context, inputs []client.Input, outputs []client.Output, ctx context.Context, inputs []client.Input, outputs []client.Output,
) (string, []string, error) { ) (string, error) {
ins := make([]*models.V1Input, 0, len(inputs)) ins := make([]*models.V1Input, 0, len(inputs))
for _, i := range inputs { for _, i := range inputs {
ins = append(ins, &models.V1Input{ ins = append(ins, &models.V1Input{
@@ -365,21 +365,19 @@ func (a *restClient) CreatePayment(
ark_service.NewArkServiceCreatePaymentParams().WithBody(&body), ark_service.NewArkServiceCreatePaymentParams().WithBody(&body),
) )
if err != nil { if err != nil {
return "", nil, err return "", err
} }
return resp.GetPayload().SignedRedeemTx, resp.GetPayload().UsignedUnconditionalForfeitTxs, nil return resp.GetPayload().SignedRedeemTx, nil
} }
func (a *restClient) CompletePayment( func (a *restClient) CompletePayment(
ctx context.Context, signedRedeemTx string, signedUncondForfeitTxs []string, ctx context.Context, signedRedeemTx string,
) error { ) error {
req := &arkv1.CompletePaymentRequest{ req := &arkv1.CompletePaymentRequest{
SignedRedeemTx: signedRedeemTx, SignedRedeemTx: signedRedeemTx,
SignedUnconditionalForfeitTxs: signedUncondForfeitTxs,
} }
body := models.V1CompletePaymentRequest{ body := models.V1CompletePaymentRequest{
SignedRedeemTx: req.GetSignedRedeemTx(), SignedRedeemTx: req.GetSignedRedeemTx(),
SignedUnconditionalForfeitTxs: req.GetSignedUnconditionalForfeitTxs(),
} }
_, err := a.svc.ArkServiceCompletePayment( _, err := a.svc.ArkServiceCompletePayment(
ark_service.NewArkServiceCompletePaymentParams().WithBody(&body), ark_service.NewArkServiceCompletePaymentParams().WithBody(&body),
@@ -492,13 +490,6 @@ func (a *restClient) ListVtxos(
return nil, nil, err 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{ spendableVtxos = append(spendableVtxos, client.Vtxo{
Outpoint: client.Outpoint{ Outpoint: client.Outpoint{
Txid: v.Outpoint.Txid, Txid: v.Outpoint.Txid,
@@ -508,8 +499,7 @@ func (a *restClient) ListVtxos(
RoundTxid: v.RoundTxid, RoundTxid: v.RoundTxid,
ExpiresAt: expiresAt, ExpiresAt: expiresAt,
Pending: v.Pending, Pending: v.Pending,
RedeemTx: redeemTx, RedeemTx: v.RedeemTx,
UnconditionalForfeitTxs: uncondForfeitTxs,
SpentBy: v.SpentBy, SpentBy: v.SpentBy,
Descriptor: v.Descriptor, Descriptor: v.Descriptor,
}) })

View File

@@ -68,6 +68,8 @@ type ClientService interface {
ArkServiceGetRoundByID(params *ArkServiceGetRoundByIDParams, opts ...ClientOption) (*ArkServiceGetRoundByIDOK, error) ArkServiceGetRoundByID(params *ArkServiceGetRoundByIDParams, opts ...ClientOption) (*ArkServiceGetRoundByIDOK, error)
ArkServiceGetTransactionsStream(params *ArkServiceGetTransactionsStreamParams, opts ...ClientOption) (*ArkServiceGetTransactionsStreamOK, error)
ArkServiceListVtxos(params *ArkServiceListVtxosParams, opts ...ClientOption) (*ArkServiceListVtxosOK, error) ArkServiceListVtxos(params *ArkServiceListVtxosParams, opts ...ClientOption) (*ArkServiceListVtxosOK, error)
ArkServicePing(params *ArkServicePingParams, opts ...ClientOption) (*ArkServicePingOK, error) ArkServicePing(params *ArkServicePingParams, opts ...ClientOption) (*ArkServicePingOK, error)
@@ -344,6 +346,43 @@ func (a *Client) ArkServiceGetRoundByID(params *ArkServiceGetRoundByIDParams, op
return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code())
} }
/*
ArkServiceGetTransactionsStream ark service get transactions stream API
*/
func (a *Client) ArkServiceGetTransactionsStream(params *ArkServiceGetTransactionsStreamParams, opts ...ClientOption) (*ArkServiceGetTransactionsStreamOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewArkServiceGetTransactionsStreamParams()
}
op := &runtime.ClientOperation{
ID: "ArkService_GetTransactionsStream",
Method: "GET",
PathPattern: "/v1/transactions",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &ArkServiceGetTransactionsStreamReader{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.(*ArkServiceGetTransactionsStreamOK)
if ok {
return success, nil
}
// unexpected success response
unexpectedSuccess := result.(*ArkServiceGetTransactionsStreamDefault)
return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code())
}
/* /*
ArkServiceListVtxos ark service list vtxos API ArkServiceListVtxos ark service list vtxos API
*/ */

View File

@@ -0,0 +1,128 @@
// 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"
)
// NewArkServiceGetTransactionsStreamParams creates a new ArkServiceGetTransactionsStreamParams 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 NewArkServiceGetTransactionsStreamParams() *ArkServiceGetTransactionsStreamParams {
return &ArkServiceGetTransactionsStreamParams{
timeout: cr.DefaultTimeout,
}
}
// NewArkServiceGetTransactionsStreamParamsWithTimeout creates a new ArkServiceGetTransactionsStreamParams object
// with the ability to set a timeout on a request.
func NewArkServiceGetTransactionsStreamParamsWithTimeout(timeout time.Duration) *ArkServiceGetTransactionsStreamParams {
return &ArkServiceGetTransactionsStreamParams{
timeout: timeout,
}
}
// NewArkServiceGetTransactionsStreamParamsWithContext creates a new ArkServiceGetTransactionsStreamParams object
// with the ability to set a context for a request.
func NewArkServiceGetTransactionsStreamParamsWithContext(ctx context.Context) *ArkServiceGetTransactionsStreamParams {
return &ArkServiceGetTransactionsStreamParams{
Context: ctx,
}
}
// NewArkServiceGetTransactionsStreamParamsWithHTTPClient creates a new ArkServiceGetTransactionsStreamParams object
// with the ability to set a custom HTTPClient for a request.
func NewArkServiceGetTransactionsStreamParamsWithHTTPClient(client *http.Client) *ArkServiceGetTransactionsStreamParams {
return &ArkServiceGetTransactionsStreamParams{
HTTPClient: client,
}
}
/*
ArkServiceGetTransactionsStreamParams contains all the parameters to send to the API endpoint
for the ark service get transactions stream operation.
Typically these are written to a http.Request.
*/
type ArkServiceGetTransactionsStreamParams struct {
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the ark service get transactions stream params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *ArkServiceGetTransactionsStreamParams) WithDefaults() *ArkServiceGetTransactionsStreamParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the ark service get transactions stream params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *ArkServiceGetTransactionsStreamParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the ark service get transactions stream params
func (o *ArkServiceGetTransactionsStreamParams) WithTimeout(timeout time.Duration) *ArkServiceGetTransactionsStreamParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the ark service get transactions stream params
func (o *ArkServiceGetTransactionsStreamParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the ark service get transactions stream params
func (o *ArkServiceGetTransactionsStreamParams) WithContext(ctx context.Context) *ArkServiceGetTransactionsStreamParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the ark service get transactions stream params
func (o *ArkServiceGetTransactionsStreamParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the ark service get transactions stream params
func (o *ArkServiceGetTransactionsStreamParams) WithHTTPClient(client *http.Client) *ArkServiceGetTransactionsStreamParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the ark service get transactions stream params
func (o *ArkServiceGetTransactionsStreamParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WriteToRequest writes these params to a swagger request
func (o *ArkServiceGetTransactionsStreamParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -0,0 +1,337 @@
// 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"
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/ark-network/ark/pkg/client-sdk/client/rest/service/models"
)
// ArkServiceGetTransactionsStreamReader is a Reader for the ArkServiceGetTransactionsStream structure.
type ArkServiceGetTransactionsStreamReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *ArkServiceGetTransactionsStreamReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewArkServiceGetTransactionsStreamOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
default:
result := NewArkServiceGetTransactionsStreamDefault(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
}
}
// NewArkServiceGetTransactionsStreamOK creates a ArkServiceGetTransactionsStreamOK with default headers values
func NewArkServiceGetTransactionsStreamOK() *ArkServiceGetTransactionsStreamOK {
return &ArkServiceGetTransactionsStreamOK{}
}
/*
ArkServiceGetTransactionsStreamOK describes a response with status code 200, with default header values.
A successful response.(streaming responses)
*/
type ArkServiceGetTransactionsStreamOK struct {
Payload *ArkServiceGetTransactionsStreamOKBody
}
// IsSuccess returns true when this ark service get transactions stream o k response has a 2xx status code
func (o *ArkServiceGetTransactionsStreamOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this ark service get transactions stream o k response has a 3xx status code
func (o *ArkServiceGetTransactionsStreamOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this ark service get transactions stream o k response has a 4xx status code
func (o *ArkServiceGetTransactionsStreamOK) IsClientError() bool {
return false
}
// IsServerError returns true when this ark service get transactions stream o k response has a 5xx status code
func (o *ArkServiceGetTransactionsStreamOK) IsServerError() bool {
return false
}
// IsCode returns true when this ark service get transactions stream o k response a status code equal to that given
func (o *ArkServiceGetTransactionsStreamOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the ark service get transactions stream o k response
func (o *ArkServiceGetTransactionsStreamOK) Code() int {
return 200
}
func (o *ArkServiceGetTransactionsStreamOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /v1/transactions][%d] arkServiceGetTransactionsStreamOK %s", 200, payload)
}
func (o *ArkServiceGetTransactionsStreamOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /v1/transactions][%d] arkServiceGetTransactionsStreamOK %s", 200, payload)
}
func (o *ArkServiceGetTransactionsStreamOK) GetPayload() *ArkServiceGetTransactionsStreamOKBody {
return o.Payload
}
func (o *ArkServiceGetTransactionsStreamOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
o.Payload = new(ArkServiceGetTransactionsStreamOKBody)
// response payload
if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewArkServiceGetTransactionsStreamDefault creates a ArkServiceGetTransactionsStreamDefault with default headers values
func NewArkServiceGetTransactionsStreamDefault(code int) *ArkServiceGetTransactionsStreamDefault {
return &ArkServiceGetTransactionsStreamDefault{
_statusCode: code,
}
}
/*
ArkServiceGetTransactionsStreamDefault describes a response with status code -1, with default header values.
An unexpected error response.
*/
type ArkServiceGetTransactionsStreamDefault struct {
_statusCode int
Payload *models.RPCStatus
}
// IsSuccess returns true when this ark service get transactions stream default response has a 2xx status code
func (o *ArkServiceGetTransactionsStreamDefault) IsSuccess() bool {
return o._statusCode/100 == 2
}
// IsRedirect returns true when this ark service get transactions stream default response has a 3xx status code
func (o *ArkServiceGetTransactionsStreamDefault) IsRedirect() bool {
return o._statusCode/100 == 3
}
// IsClientError returns true when this ark service get transactions stream default response has a 4xx status code
func (o *ArkServiceGetTransactionsStreamDefault) IsClientError() bool {
return o._statusCode/100 == 4
}
// IsServerError returns true when this ark service get transactions stream default response has a 5xx status code
func (o *ArkServiceGetTransactionsStreamDefault) IsServerError() bool {
return o._statusCode/100 == 5
}
// IsCode returns true when this ark service get transactions stream default response a status code equal to that given
func (o *ArkServiceGetTransactionsStreamDefault) IsCode(code int) bool {
return o._statusCode == code
}
// Code gets the status code for the ark service get transactions stream default response
func (o *ArkServiceGetTransactionsStreamDefault) Code() int {
return o._statusCode
}
func (o *ArkServiceGetTransactionsStreamDefault) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /v1/transactions][%d] ArkService_GetTransactionsStream default %s", o._statusCode, payload)
}
func (o *ArkServiceGetTransactionsStreamDefault) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /v1/transactions][%d] ArkService_GetTransactionsStream default %s", o._statusCode, payload)
}
func (o *ArkServiceGetTransactionsStreamDefault) GetPayload() *models.RPCStatus {
return o.Payload
}
func (o *ArkServiceGetTransactionsStreamDefault) 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
}
/*
ArkServiceGetTransactionsStreamOKBody Stream result of v1GetTransactionsStreamResponse
swagger:model ArkServiceGetTransactionsStreamOKBody
*/
type ArkServiceGetTransactionsStreamOKBody struct {
// error
Error *models.RPCStatus `json:"error,omitempty"`
// result
Result *models.V1GetTransactionsStreamResponse `json:"result,omitempty"`
}
// Validate validates this ark service get transactions stream o k body
func (o *ArkServiceGetTransactionsStreamOKBody) Validate(formats strfmt.Registry) error {
var res []error
if err := o.validateError(formats); err != nil {
res = append(res, err)
}
if err := o.validateResult(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (o *ArkServiceGetTransactionsStreamOKBody) validateError(formats strfmt.Registry) error {
if swag.IsZero(o.Error) { // not required
return nil
}
if o.Error != nil {
if err := o.Error.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("arkServiceGetTransactionsStreamOK" + "." + "error")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("arkServiceGetTransactionsStreamOK" + "." + "error")
}
return err
}
}
return nil
}
func (o *ArkServiceGetTransactionsStreamOKBody) validateResult(formats strfmt.Registry) error {
if swag.IsZero(o.Result) { // not required
return nil
}
if o.Result != nil {
if err := o.Result.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("arkServiceGetTransactionsStreamOK" + "." + "result")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("arkServiceGetTransactionsStreamOK" + "." + "result")
}
return err
}
}
return nil
}
// ContextValidate validate this ark service get transactions stream o k body based on the context it is used
func (o *ArkServiceGetTransactionsStreamOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := o.contextValidateError(ctx, formats); err != nil {
res = append(res, err)
}
if err := o.contextValidateResult(ctx, formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (o *ArkServiceGetTransactionsStreamOKBody) contextValidateError(ctx context.Context, formats strfmt.Registry) error {
if o.Error != nil {
if swag.IsZero(o.Error) { // not required
return nil
}
if err := o.Error.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("arkServiceGetTransactionsStreamOK" + "." + "error")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("arkServiceGetTransactionsStreamOK" + "." + "error")
}
return err
}
}
return nil
}
func (o *ArkServiceGetTransactionsStreamOKBody) contextValidateResult(ctx context.Context, formats strfmt.Registry) error {
if o.Result != nil {
if swag.IsZero(o.Result) { // not required
return nil
}
if err := o.Result.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("arkServiceGetTransactionsStreamOK" + "." + "result")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("arkServiceGetTransactionsStreamOK" + "." + "result")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (o *ArkServiceGetTransactionsStreamOKBody) MarshalBinary() ([]byte, error) {
if o == nil {
return nil, nil
}
return swag.WriteJSON(o)
}
// UnmarshalBinary interface implementation
func (o *ArkServiceGetTransactionsStreamOKBody) UnmarshalBinary(b []byte) error {
var res ArkServiceGetTransactionsStreamOKBody
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*o = res
return nil
}

View File

@@ -19,9 +19,6 @@ type V1CompletePaymentRequest struct {
// signed redeem tx // signed redeem tx
SignedRedeemTx string `json:"signedRedeemTx,omitempty"` SignedRedeemTx string `json:"signedRedeemTx,omitempty"`
// signed unconditional forfeit txs
SignedUnconditionalForfeitTxs []string `json:"signedUnconditionalForfeitTxs"`
} }
// Validate validates this v1 complete payment request // Validate validates this v1 complete payment request

View File

@@ -19,9 +19,6 @@ type V1CreatePaymentResponse struct {
// signed only by the ASP // signed only by the ASP
SignedRedeemTx string `json:"signedRedeemTx,omitempty"` SignedRedeemTx string `json:"signedRedeemTx,omitempty"`
// usigned unconditional forfeit txs
UsignedUnconditionalForfeitTxs []string `json:"usignedUnconditionalForfeitTxs"`
} }
// Validate validates this v1 create payment response // Validate validates this v1 create payment response

View File

@@ -0,0 +1,160 @@
// 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/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// V1GetTransactionsStreamResponse v1 get transactions stream response
//
// swagger:model v1GetTransactionsStreamResponse
type V1GetTransactionsStreamResponse struct {
// redeem
Redeem *V1RedeemTransaction `json:"redeem,omitempty"`
// round
Round *V1RoundTransaction `json:"round,omitempty"`
}
// Validate validates this v1 get transactions stream response
func (m *V1GetTransactionsStreamResponse) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateRedeem(formats); err != nil {
res = append(res, err)
}
if err := m.validateRound(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *V1GetTransactionsStreamResponse) validateRedeem(formats strfmt.Registry) error {
if swag.IsZero(m.Redeem) { // not required
return nil
}
if m.Redeem != nil {
if err := m.Redeem.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("redeem")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("redeem")
}
return err
}
}
return nil
}
func (m *V1GetTransactionsStreamResponse) validateRound(formats strfmt.Registry) error {
if swag.IsZero(m.Round) { // not required
return nil
}
if m.Round != nil {
if err := m.Round.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("round")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("round")
}
return err
}
}
return nil
}
// ContextValidate validate this v1 get transactions stream response based on the context it is used
func (m *V1GetTransactionsStreamResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateRedeem(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidateRound(ctx, formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *V1GetTransactionsStreamResponse) contextValidateRedeem(ctx context.Context, formats strfmt.Registry) error {
if m.Redeem != nil {
if swag.IsZero(m.Redeem) { // not required
return nil
}
if err := m.Redeem.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("redeem")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("redeem")
}
return err
}
}
return nil
}
func (m *V1GetTransactionsStreamResponse) contextValidateRound(ctx context.Context, formats strfmt.Registry) error {
if m.Round != nil {
if swag.IsZero(m.Round) { // not required
return nil
}
if err := m.Round.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("round")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("round")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *V1GetTransactionsStreamResponse) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *V1GetTransactionsStreamResponse) UnmarshalBinary(b []byte) error {
var res V1GetTransactionsStreamResponse
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -19,9 +19,6 @@ type V1PendingPayment struct {
// redeem tx // redeem tx
RedeemTx string `json:"redeemTx,omitempty"` RedeemTx string `json:"redeemTx,omitempty"`
// unconditional forfeit txs
UnconditionalForfeitTxs []string `json:"unconditionalForfeitTxs"`
} }
// Validate validates this v1 pending payment // Validate validates this v1 pending payment

View File

@@ -0,0 +1,186 @@
// 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"
)
// V1RedeemTransaction v1 redeem transaction
//
// swagger:model v1RedeemTransaction
type V1RedeemTransaction struct {
// spendable vtxos
SpendableVtxos []*V1Vtxo `json:"spendableVtxos"`
// spent vtxos
SpentVtxos []*V1Outpoint `json:"spentVtxos"`
// txid
Txid string `json:"txid,omitempty"`
}
// Validate validates this v1 redeem transaction
func (m *V1RedeemTransaction) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateSpendableVtxos(formats); err != nil {
res = append(res, err)
}
if err := m.validateSpentVtxos(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *V1RedeemTransaction) validateSpendableVtxos(formats strfmt.Registry) error {
if swag.IsZero(m.SpendableVtxos) { // not required
return nil
}
for i := 0; i < len(m.SpendableVtxos); i++ {
if swag.IsZero(m.SpendableVtxos[i]) { // not required
continue
}
if m.SpendableVtxos[i] != nil {
if err := m.SpendableVtxos[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("spendableVtxos" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("spendableVtxos" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *V1RedeemTransaction) validateSpentVtxos(formats strfmt.Registry) error {
if swag.IsZero(m.SpentVtxos) { // not required
return nil
}
for i := 0; i < len(m.SpentVtxos); i++ {
if swag.IsZero(m.SpentVtxos[i]) { // not required
continue
}
if m.SpentVtxos[i] != nil {
if err := m.SpentVtxos[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("spentVtxos" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("spentVtxos" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// ContextValidate validate this v1 redeem transaction based on the context it is used
func (m *V1RedeemTransaction) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateSpendableVtxos(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidateSpentVtxos(ctx, formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *V1RedeemTransaction) contextValidateSpendableVtxos(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.SpendableVtxos); i++ {
if m.SpendableVtxos[i] != nil {
if swag.IsZero(m.SpendableVtxos[i]) { // not required
return nil
}
if err := m.SpendableVtxos[i].ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("spendableVtxos" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("spendableVtxos" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *V1RedeemTransaction) contextValidateSpentVtxos(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.SpentVtxos); i++ {
if m.SpentVtxos[i] != nil {
if swag.IsZero(m.SpentVtxos[i]) { // not required
return nil
}
if err := m.SpentVtxos[i].ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("spentVtxos" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("spentVtxos" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// MarshalBinary interface implementation
func (m *V1RedeemTransaction) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *V1RedeemTransaction) UnmarshalBinary(b []byte) error {
var res V1RedeemTransaction
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,248 @@
// 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"
)
// V1RoundTransaction v1 round transaction
//
// swagger:model v1RoundTransaction
type V1RoundTransaction struct {
// claimed boarding utxos
ClaimedBoardingUtxos []*V1Outpoint `json:"claimedBoardingUtxos"`
// spendable vtxos
SpendableVtxos []*V1Vtxo `json:"spendableVtxos"`
// spent vtxos
SpentVtxos []*V1Outpoint `json:"spentVtxos"`
// txid
Txid string `json:"txid,omitempty"`
}
// Validate validates this v1 round transaction
func (m *V1RoundTransaction) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateClaimedBoardingUtxos(formats); err != nil {
res = append(res, err)
}
if err := m.validateSpendableVtxos(formats); err != nil {
res = append(res, err)
}
if err := m.validateSpentVtxos(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *V1RoundTransaction) validateClaimedBoardingUtxos(formats strfmt.Registry) error {
if swag.IsZero(m.ClaimedBoardingUtxos) { // not required
return nil
}
for i := 0; i < len(m.ClaimedBoardingUtxos); i++ {
if swag.IsZero(m.ClaimedBoardingUtxos[i]) { // not required
continue
}
if m.ClaimedBoardingUtxos[i] != nil {
if err := m.ClaimedBoardingUtxos[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("claimedBoardingUtxos" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("claimedBoardingUtxos" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *V1RoundTransaction) validateSpendableVtxos(formats strfmt.Registry) error {
if swag.IsZero(m.SpendableVtxos) { // not required
return nil
}
for i := 0; i < len(m.SpendableVtxos); i++ {
if swag.IsZero(m.SpendableVtxos[i]) { // not required
continue
}
if m.SpendableVtxos[i] != nil {
if err := m.SpendableVtxos[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("spendableVtxos" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("spendableVtxos" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *V1RoundTransaction) validateSpentVtxos(formats strfmt.Registry) error {
if swag.IsZero(m.SpentVtxos) { // not required
return nil
}
for i := 0; i < len(m.SpentVtxos); i++ {
if swag.IsZero(m.SpentVtxos[i]) { // not required
continue
}
if m.SpentVtxos[i] != nil {
if err := m.SpentVtxos[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("spentVtxos" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("spentVtxos" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// ContextValidate validate this v1 round transaction based on the context it is used
func (m *V1RoundTransaction) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateClaimedBoardingUtxos(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidateSpendableVtxos(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidateSpentVtxos(ctx, formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *V1RoundTransaction) contextValidateClaimedBoardingUtxos(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.ClaimedBoardingUtxos); i++ {
if m.ClaimedBoardingUtxos[i] != nil {
if swag.IsZero(m.ClaimedBoardingUtxos[i]) { // not required
return nil
}
if err := m.ClaimedBoardingUtxos[i].ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("claimedBoardingUtxos" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("claimedBoardingUtxos" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *V1RoundTransaction) contextValidateSpendableVtxos(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.SpendableVtxos); i++ {
if m.SpendableVtxos[i] != nil {
if swag.IsZero(m.SpendableVtxos[i]) { // not required
return nil
}
if err := m.SpendableVtxos[i].ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("spendableVtxos" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("spendableVtxos" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *V1RoundTransaction) contextValidateSpentVtxos(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.SpentVtxos); i++ {
if m.SpentVtxos[i] != nil {
if swag.IsZero(m.SpentVtxos[i]) { // not required
return nil
}
if err := m.SpentVtxos[i].ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("spentVtxos" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("spentVtxos" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// MarshalBinary interface implementation
func (m *V1RoundTransaction) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *V1RoundTransaction) UnmarshalBinary(b []byte) error {
var res V1RoundTransaction
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -33,8 +33,8 @@ type V1Vtxo struct {
// pending // pending
Pending bool `json:"pending,omitempty"` Pending bool `json:"pending,omitempty"`
// pending data // redeem tx
PendingData *V1PendingPayment `json:"pendingData,omitempty"` RedeemTx string `json:"redeemTx,omitempty"`
// round txid // round txid
RoundTxid string `json:"roundTxid,omitempty"` RoundTxid string `json:"roundTxid,omitempty"`
@@ -57,10 +57,6 @@ func (m *V1Vtxo) Validate(formats strfmt.Registry) error {
res = append(res, err) res = append(res, err)
} }
if err := m.validatePendingData(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 { if len(res) > 0 {
return errors.CompositeValidationError(res...) return errors.CompositeValidationError(res...)
} }
@@ -86,25 +82,6 @@ func (m *V1Vtxo) validateOutpoint(formats strfmt.Registry) error {
return nil 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
}
// ContextValidate validate this v1 vtxo based on the context it is used // ContextValidate validate this v1 vtxo based on the context it is used
func (m *V1Vtxo) ContextValidate(ctx context.Context, formats strfmt.Registry) error { func (m *V1Vtxo) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error var res []error
@@ -113,10 +90,6 @@ func (m *V1Vtxo) ContextValidate(ctx context.Context, formats strfmt.Registry) e
res = append(res, err) res = append(res, err)
} }
if err := m.contextValidatePendingData(ctx, formats); err != nil {
res = append(res, err)
}
if len(res) > 0 { if len(res) > 0 {
return errors.CompositeValidationError(res...) return errors.CompositeValidationError(res...)
} }
@@ -144,27 +117,6 @@ func (m *V1Vtxo) contextValidateOutpoint(ctx context.Context, formats strfmt.Reg
return nil 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
}
// MarshalBinary interface implementation // MarshalBinary interface implementation
func (m *V1Vtxo) MarshalBinary() ([]byte, error) { func (m *V1Vtxo) MarshalBinary() ([]byte, error) {
if m == nil { if m == nil {

View File

@@ -200,7 +200,6 @@ func loadFixtures(jsonStr string) (vtxos, map[string]struct{}, error) {
RoundTxid: vtxo.PoolTxid, RoundTxid: vtxo.PoolTxid,
ExpiresAt: &expireAt, ExpiresAt: &expireAt,
RedeemTx: vtxo.PendingData.RedeemTx, RedeemTx: vtxo.PendingData.RedeemTx,
UnconditionalForfeitTxs: vtxo.PendingData.UnconditionalForfeitTxs,
Pending: vtxo.Pending, Pending: vtxo.Pending,
SpentBy: vtxo.SpentBy, SpentBy: vtxo.SpentBy,
} }
@@ -225,7 +224,6 @@ func loadFixtures(jsonStr string) (vtxos, map[string]struct{}, error) {
RoundTxid: vtxo.PoolTxid, RoundTxid: vtxo.PoolTxid,
ExpiresAt: &expireAt, ExpiresAt: &expireAt,
RedeemTx: vtxo.PendingData.RedeemTx, RedeemTx: vtxo.PendingData.RedeemTx,
UnconditionalForfeitTxs: vtxo.PendingData.UnconditionalForfeitTxs,
Pending: vtxo.Pending, Pending: vtxo.Pending,
SpentBy: vtxo.SpentBy, SpentBy: vtxo.SpentBy,
} }

View File

@@ -653,8 +653,7 @@ func (a *covenantlessArkClient) SendAsync(
}) })
} }
redeemTx, unconditionalForfeitTxs, err := a.client.CreatePayment( redeemTx, err := a.client.CreatePayment(ctx, inputs, receiversOutput)
ctx, inputs, receiversOutput)
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -667,7 +666,7 @@ func (a *covenantlessArkClient) SendAsync(
} }
if err = a.client.CompletePayment( if err = a.client.CompletePayment(
ctx, signedRedeemTx, unconditionalForfeitTxs, ctx, signedRedeemTx,
); err != nil { ); err != nil {
return "", err return "", err
} }

View File

@@ -320,12 +320,12 @@ func (s *covenantService) UpdatePaymentStatus(_ context.Context, id string) (dom
return s.lastEvent, nil return s.lastEvent, nil
} }
func (s *covenantService) CompleteAsyncPayment(ctx context.Context, redeemTx string, unconditionalForfeitTxs []string) error { func (s *covenantService) CompleteAsyncPayment(ctx context.Context, redeemTx string) error {
return fmt.Errorf("unimplemented") return fmt.Errorf("unimplemented")
} }
func (s *covenantService) CreateAsyncPayment(ctx context.Context, inputs []ports.Input, receivers []domain.Receiver) (string, []string, error) { func (s *covenantService) CreateAsyncPayment(ctx context.Context, inputs []ports.Input, receivers []domain.Receiver) (string, error) {
return "", nil, fmt.Errorf("unimplemented") return "", fmt.Errorf("unimplemented")
} }
func (s *covenantService) SignVtxos(ctx context.Context, forfeitTxs []string) error { func (s *covenantService) SignVtxos(ctx context.Context, forfeitTxs []string) error {

View File

@@ -139,7 +139,7 @@ func (s *covenantlessService) Stop() {
} }
func (s *covenantlessService) CompleteAsyncPayment( func (s *covenantlessService) CompleteAsyncPayment(
ctx context.Context, redeemTx string, unconditionalForfeitTxs []string, ctx context.Context, redeemTx string,
) error { ) error {
redeemPtx, err := psbt.NewFromRawBytes(strings.NewReader(redeemTx), true) redeemPtx, err := psbt.NewFromRawBytes(strings.NewReader(redeemTx), true)
if err != nil { if err != nil {
@@ -274,10 +274,7 @@ func (s *covenantlessService) CompleteAsyncPayment(
Amount: uint64(out.Value), Amount: uint64(out.Value),
}, },
ExpireAt: asyncPayData.expireAt, ExpireAt: asyncPayData.expireAt,
AsyncPayment: &domain.AsyncPaymentTxs{
RedeemTx: redeemTx, RedeemTx: redeemTx,
UnconditionalForfeitTxs: unconditionalForfeitTxs,
},
Pending: isPending, Pending: isPending,
}) })
} }
@@ -313,7 +310,7 @@ func (s *covenantlessService) CompleteAsyncPayment(
func (s *covenantlessService) CreateAsyncPayment( func (s *covenantlessService) CreateAsyncPayment(
ctx context.Context, inputs []ports.Input, receivers []domain.Receiver, ctx context.Context, inputs []ports.Input, receivers []domain.Receiver,
) (string, []string, error) { ) (string, error) {
vtxosKeys := make([]domain.VtxoKey, 0, len(inputs)) vtxosKeys := make([]domain.VtxoKey, 0, len(inputs))
for _, in := range inputs { for _, in := range inputs {
vtxosKeys = append(vtxosKeys, in.VtxoKey) vtxosKeys = append(vtxosKeys, in.VtxoKey)
@@ -321,10 +318,10 @@ func (s *covenantlessService) CreateAsyncPayment(
vtxos, err := s.repoManager.Vtxos().GetVtxos(ctx, vtxosKeys) vtxos, err := s.repoManager.Vtxos().GetVtxos(ctx, vtxosKeys)
if err != nil { if err != nil {
return "", nil, err return "", err
} }
if len(vtxos) <= 0 { if len(vtxos) <= 0 {
return "", nil, fmt.Errorf("vtxos not found") return "", fmt.Errorf("vtxos not found")
} }
vtxosInputs := make([]domain.Vtxo, 0, len(inputs)) vtxosInputs := make([]domain.Vtxo, 0, len(inputs))
@@ -332,18 +329,18 @@ func (s *covenantlessService) CreateAsyncPayment(
expiration := vtxos[0].ExpireAt expiration := vtxos[0].ExpireAt
for _, vtxo := range vtxos { for _, vtxo := range vtxos {
if vtxo.Spent { if vtxo.Spent {
return "", nil, fmt.Errorf("all vtxos must be unspent") return "", fmt.Errorf("all vtxos must be unspent")
} }
if vtxo.Redeemed { if vtxo.Redeemed {
return "", nil, fmt.Errorf("all vtxos must be redeemed") return "", fmt.Errorf("all vtxos must be redeemed")
} }
if vtxo.Swept { if vtxo.Swept {
return "", nil, fmt.Errorf("all vtxos must be swept") return "", fmt.Errorf("all vtxos must be swept")
} }
if vtxo.Pending { if vtxo.Pending {
return "", nil, fmt.Errorf("all vtxos must be claimed") return "", fmt.Errorf("all vtxos must be claimed")
} }
if vtxo.ExpireAt < expiration { if vtxo.ExpireAt < expiration {
@@ -353,19 +350,19 @@ func (s *covenantlessService) CreateAsyncPayment(
vtxosInputs = append(vtxosInputs, vtxo) vtxosInputs = append(vtxosInputs, vtxo)
} }
res, err := s.builder.BuildAsyncPaymentTransactions( redeemTx, err := s.builder.BuildAsyncPaymentTransactions(
vtxosInputs, s.pubkey, receivers, vtxosInputs, s.pubkey, receivers,
) )
if err != nil { if err != nil {
return "", nil, fmt.Errorf("failed to build async payment txs: %s", err) return "", fmt.Errorf("failed to build async payment txs: %s", err)
} }
redeemTx, err := psbt.NewFromRawBytes(strings.NewReader(res.RedeemTx), true) redeemPtx, err := psbt.NewFromRawBytes(strings.NewReader(redeemTx), true)
if err != nil { if err != nil {
return "", nil, fmt.Errorf("failed to parse redeem tx: %s", err) return "", fmt.Errorf("failed to parse redeem tx: %s", err)
} }
s.asyncPaymentsCache[redeemTx.UnsignedTx.TxID()] = struct { s.asyncPaymentsCache[redeemPtx.UnsignedTx.TxID()] = struct {
receivers []domain.Receiver receivers []domain.Receiver
expireAt int64 expireAt int64
}{ }{
@@ -373,7 +370,7 @@ func (s *covenantlessService) CreateAsyncPayment(
expireAt: expiration, expireAt: expiration,
} }
return res.RedeemTx, res.UnconditionalForfeitTxs, nil return redeemTx, nil
} }
func (s *covenantlessService) GetBoardingAddress( func (s *covenantlessService) GetBoardingAddress(
@@ -1536,7 +1533,7 @@ func (s *covenantlessService) reactToFraud(ctx context.Context, vtxo domain.Vtxo
log.Debugf("vtxo %s:%d has been spent by async payment", vtxo.Txid, vtxo.VOut) log.Debugf("vtxo %s:%d has been spent by async payment", vtxo.Txid, vtxo.VOut)
redeemTxHex, err := s.builder.FinalizeAndExtract(asyncPayVtxo.AsyncPayment.RedeemTx) redeemTxHex, err := s.builder.FinalizeAndExtract(asyncPayVtxo.RedeemTx)
if err != nil { if err != nil {
return fmt.Errorf("failed to finalize redeem tx: %s", err) return fmt.Errorf("failed to finalize redeem tx: %s", err)
} }

View File

@@ -33,9 +33,9 @@ type Service interface {
// Async payments // Async payments
CreateAsyncPayment( CreateAsyncPayment(
ctx context.Context, inputs []ports.Input, receivers []domain.Receiver, ctx context.Context, inputs []ports.Input, receivers []domain.Receiver,
) (string, []string, error) ) (string, error)
CompleteAsyncPayment( CompleteAsyncPayment(
ctx context.Context, redeemTx string, unconditionalForfeitTxs []string, ctx context.Context, redeemTx string,
) error ) error
GetBoardingAddress( GetBoardingAddress(
ctx context.Context, userPubkey *secp256k1.PublicKey, ctx context.Context, userPubkey *secp256k1.PublicKey,

View File

@@ -114,11 +114,6 @@ type Vtxo struct {
Redeemed bool Redeemed bool
Swept bool Swept bool
ExpireAt int64 ExpireAt int64
AsyncPayment *AsyncPaymentTxs // nil if not async vtxo RedeemTx string // empty if in-round vtxo
Pending bool Pending bool
} }
type AsyncPaymentTxs struct {
RedeemTx string // always signed by the ASP when created
UnconditionalForfeitTxs []string
}

View File

@@ -42,7 +42,7 @@ type TxBuilder interface {
BuildAsyncPaymentTransactions( BuildAsyncPaymentTransactions(
vtxosToSpend []domain.Vtxo, vtxosToSpend []domain.Vtxo,
aspPubKey *secp256k1.PublicKey, receivers []domain.Receiver, aspPubKey *secp256k1.PublicKey, receivers []domain.Receiver,
) (*domain.AsyncPaymentTxs, error) ) (string, error)
VerifyAndCombinePartialTx(dest string, src string) (string, error) VerifyAndCombinePartialTx(dest string, src string) (string, error)
GetTxID(tx string) (string, error) GetTxID(tx string) (string, error)
} }

View File

@@ -41,15 +41,6 @@ CREATE TABLE IF NOT EXISTS tx (
FOREIGN KEY (round_id) REFERENCES round(id) 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 ( CREATE TABLE IF NOT EXISTS vtxo (
txid TEXT NOT NULL, txid TEXT NOT NULL,
vout INTEGER NOT NULL, vout INTEGER NOT NULL,
@@ -86,8 +77,3 @@ CREATE VIEW payment_vtxo_vw AS SELECT vtxo.*
FROM payment FROM payment
LEFT OUTER JOIN vtxo LEFT OUTER JOIN vtxo
ON payment.id=vtxo.payment_id; 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;

View File

@@ -87,22 +87,6 @@ type Tx struct {
IsLeaf sql.NullBool 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 { type Vtxo struct {
Txid string Txid string
Vout int64 Vout int64

View File

@@ -54,16 +54,12 @@ func (q *Queries) MarkVtxoAsSwept(ctx context.Context, arg MarkVtxoAsSweptParams
} }
const selectNotRedeemedVtxos = `-- name: SelectNotRedeemedVtxos :many const selectNotRedeemedVtxos = `-- name: SelectNotRedeemedVtxos :many
SELECT vtxo.txid, vtxo.vout, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx, vtxo.descriptor, vtxo.pending, SELECT vtxo.txid, vtxo.vout, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx, vtxo.descriptor, vtxo.pending FROM vtxo
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 WHERE redeemed = false
` `
type SelectNotRedeemedVtxosRow struct { type SelectNotRedeemedVtxosRow struct {
Vtxo Vtxo Vtxo Vtxo
UncondForfeitTxVw UncondForfeitTxVw
} }
func (q *Queries) SelectNotRedeemedVtxos(ctx context.Context) ([]SelectNotRedeemedVtxosRow, error) { func (q *Queries) SelectNotRedeemedVtxos(ctx context.Context) ([]SelectNotRedeemedVtxosRow, error) {
@@ -89,11 +85,6 @@ func (q *Queries) SelectNotRedeemedVtxos(ctx context.Context) ([]SelectNotRedeem
&i.Vtxo.RedeemTx, &i.Vtxo.RedeemTx,
&i.Vtxo.Descriptor, &i.Vtxo.Descriptor,
&i.Vtxo.Pending, &i.Vtxo.Pending,
&i.UncondForfeitTxVw.ID,
&i.UncondForfeitTxVw.Tx,
&i.UncondForfeitTxVw.VtxoTxid,
&i.UncondForfeitTxVw.VtxoVout,
&i.UncondForfeitTxVw.Position,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
@@ -109,16 +100,12 @@ func (q *Queries) SelectNotRedeemedVtxos(ctx context.Context) ([]SelectNotRedeem
} }
const selectNotRedeemedVtxosWithPubkey = `-- name: SelectNotRedeemedVtxosWithPubkey :many const selectNotRedeemedVtxosWithPubkey = `-- name: SelectNotRedeemedVtxosWithPubkey :many
SELECT vtxo.txid, vtxo.vout, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx, vtxo.descriptor, vtxo.pending, SELECT vtxo.txid, vtxo.vout, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx, vtxo.descriptor, vtxo.pending FROM vtxo
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 INSTR(descriptor, ?) > 0 WHERE redeemed = false AND INSTR(descriptor, ?) > 0
` `
type SelectNotRedeemedVtxosWithPubkeyRow struct { type SelectNotRedeemedVtxosWithPubkeyRow struct {
Vtxo Vtxo Vtxo Vtxo
UncondForfeitTxVw UncondForfeitTxVw
} }
func (q *Queries) SelectNotRedeemedVtxosWithPubkey(ctx context.Context, instr string) ([]SelectNotRedeemedVtxosWithPubkeyRow, error) { func (q *Queries) SelectNotRedeemedVtxosWithPubkey(ctx context.Context, instr string) ([]SelectNotRedeemedVtxosWithPubkeyRow, error) {
@@ -144,11 +131,6 @@ func (q *Queries) SelectNotRedeemedVtxosWithPubkey(ctx context.Context, instr st
&i.Vtxo.RedeemTx, &i.Vtxo.RedeemTx,
&i.Vtxo.Descriptor, &i.Vtxo.Descriptor,
&i.Vtxo.Pending, &i.Vtxo.Pending,
&i.UncondForfeitTxVw.ID,
&i.UncondForfeitTxVw.Tx,
&i.UncondForfeitTxVw.VtxoTxid,
&i.UncondForfeitTxVw.VtxoVout,
&i.UncondForfeitTxVw.Position,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
@@ -481,16 +463,12 @@ func (q *Queries) SelectSweepableRounds(ctx context.Context) ([]SelectSweepableR
} }
const selectSweepableVtxos = `-- name: SelectSweepableVtxos :many const selectSweepableVtxos = `-- name: SelectSweepableVtxos :many
SELECT vtxo.txid, vtxo.vout, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx, vtxo.descriptor, vtxo.pending, SELECT vtxo.txid, vtxo.vout, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx, vtxo.descriptor, vtxo.pending FROM vtxo
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 WHERE redeemed = false AND swept = false
` `
type SelectSweepableVtxosRow struct { type SelectSweepableVtxosRow struct {
Vtxo Vtxo Vtxo Vtxo
UncondForfeitTxVw UncondForfeitTxVw
} }
func (q *Queries) SelectSweepableVtxos(ctx context.Context) ([]SelectSweepableVtxosRow, error) { func (q *Queries) SelectSweepableVtxos(ctx context.Context) ([]SelectSweepableVtxosRow, error) {
@@ -516,11 +494,6 @@ func (q *Queries) SelectSweepableVtxos(ctx context.Context) ([]SelectSweepableVt
&i.Vtxo.RedeemTx, &i.Vtxo.RedeemTx,
&i.Vtxo.Descriptor, &i.Vtxo.Descriptor,
&i.Vtxo.Pending, &i.Vtxo.Pending,
&i.UncondForfeitTxVw.ID,
&i.UncondForfeitTxVw.Tx,
&i.UncondForfeitTxVw.VtxoTxid,
&i.UncondForfeitTxVw.VtxoVout,
&i.UncondForfeitTxVw.Position,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
@@ -622,10 +595,7 @@ func (q *Queries) SelectSweptRounds(ctx context.Context) ([]SelectSweptRoundsRow
} }
const selectVtxoByOutpoint = `-- name: SelectVtxoByOutpoint :one const selectVtxoByOutpoint = `-- name: SelectVtxoByOutpoint :one
SELECT vtxo.txid, vtxo.vout, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx, vtxo.descriptor, vtxo.pending, SELECT vtxo.txid, vtxo.vout, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx, vtxo.descriptor, vtxo.pending FROM vtxo
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 = ? WHERE txid = ? AND vout = ?
` `
@@ -636,7 +606,6 @@ type SelectVtxoByOutpointParams struct {
type SelectVtxoByOutpointRow struct { type SelectVtxoByOutpointRow struct {
Vtxo Vtxo Vtxo Vtxo
UncondForfeitTxVw UncondForfeitTxVw
} }
func (q *Queries) SelectVtxoByOutpoint(ctx context.Context, arg SelectVtxoByOutpointParams) (SelectVtxoByOutpointRow, error) { func (q *Queries) SelectVtxoByOutpoint(ctx context.Context, arg SelectVtxoByOutpointParams) (SelectVtxoByOutpointRow, error) {
@@ -656,26 +625,17 @@ func (q *Queries) SelectVtxoByOutpoint(ctx context.Context, arg SelectVtxoByOutp
&i.Vtxo.RedeemTx, &i.Vtxo.RedeemTx,
&i.Vtxo.Descriptor, &i.Vtxo.Descriptor,
&i.Vtxo.Pending, &i.Vtxo.Pending,
&i.UncondForfeitTxVw.ID,
&i.UncondForfeitTxVw.Tx,
&i.UncondForfeitTxVw.VtxoTxid,
&i.UncondForfeitTxVw.VtxoVout,
&i.UncondForfeitTxVw.Position,
) )
return i, err return i, err
} }
const selectVtxosByPoolTxid = `-- name: SelectVtxosByPoolTxid :many const selectVtxosByPoolTxid = `-- name: SelectVtxosByPoolTxid :many
SELECT vtxo.txid, vtxo.vout, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx, vtxo.descriptor, vtxo.pending, SELECT vtxo.txid, vtxo.vout, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.payment_id, vtxo.redeem_tx, vtxo.descriptor, vtxo.pending FROM vtxo
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 = ? WHERE pool_tx = ?
` `
type SelectVtxosByPoolTxidRow struct { type SelectVtxosByPoolTxidRow struct {
Vtxo Vtxo Vtxo Vtxo
UncondForfeitTxVw UncondForfeitTxVw
} }
func (q *Queries) SelectVtxosByPoolTxid(ctx context.Context, poolTx string) ([]SelectVtxosByPoolTxidRow, error) { func (q *Queries) SelectVtxosByPoolTxid(ctx context.Context, poolTx string) ([]SelectVtxosByPoolTxidRow, error) {
@@ -701,11 +661,6 @@ func (q *Queries) SelectVtxosByPoolTxid(ctx context.Context, poolTx string) ([]S
&i.Vtxo.RedeemTx, &i.Vtxo.RedeemTx,
&i.Vtxo.Descriptor, &i.Vtxo.Descriptor,
&i.Vtxo.Pending, &i.Vtxo.Pending,
&i.UncondForfeitTxVw.ID,
&i.UncondForfeitTxVw.Tx,
&i.UncondForfeitTxVw.VtxoTxid,
&i.UncondForfeitTxVw.VtxoVout,
&i.UncondForfeitTxVw.Position,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
@@ -891,32 +846,6 @@ func (q *Queries) UpsertTransaction(ctx context.Context, arg UpsertTransactionPa
return err 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 const upsertVtxo = `-- name: UpsertVtxo :exec
INSERT INTO vtxo (txid, vout, descriptor, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at, redeem_tx, pending) INSERT INTO vtxo (txid, vout, descriptor, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at, redeem_tx, pending)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid, vout) DO UPDATE SET VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid, vout) DO UPDATE SET

View File

@@ -111,14 +111,6 @@ SELECT id FROM round WHERE starting_timestamp > ? AND starting_timestamp < ?;
-- name: SelectRoundIds :many -- name: SelectRoundIds :many
SELECT id FROM round; 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 -- name: UpsertVtxo :exec
INSERT INTO vtxo (txid, vout, descriptor, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at, redeem_tx, pending) INSERT INTO vtxo (txid, vout, descriptor, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at, redeem_tx, pending)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid, vout) DO UPDATE SET VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid, vout) DO UPDATE SET
@@ -134,38 +126,23 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid, vout) DO UPDATE SE
pending = EXCLUDED.pending; pending = EXCLUDED.pending;
-- name: SelectSweepableVtxos :many -- name: SelectSweepableVtxos :many
SELECT sqlc.embed(vtxo), SELECT sqlc.embed(vtxo) FROM 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; WHERE redeemed = false AND swept = false;
-- name: SelectNotRedeemedVtxos :many -- name: SelectNotRedeemedVtxos :many
SELECT sqlc.embed(vtxo), SELECT sqlc.embed(vtxo) FROM 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; WHERE redeemed = false;
-- name: SelectNotRedeemedVtxosWithPubkey :many -- name: SelectNotRedeemedVtxosWithPubkey :many
SELECT sqlc.embed(vtxo), SELECT sqlc.embed(vtxo) FROM 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 INSTR(descriptor, ?) > 0; WHERE redeemed = false AND INSTR(descriptor, ?) > 0;
-- name: SelectVtxoByOutpoint :one -- name: SelectVtxoByOutpoint :one
SELECT sqlc.embed(vtxo), SELECT sqlc.embed(vtxo) FROM 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 = ?; WHERE txid = ? AND vout = ?;
-- name: SelectVtxosByPoolTxid :many -- name: SelectVtxosByPoolTxid :many
SELECT sqlc.embed(vtxo), SELECT sqlc.embed(vtxo) FROM 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 = ?; WHERE pool_tx = ?;
-- name: MarkVtxoAsRedeemed :exec -- name: MarkVtxoAsRedeemed :exec

View File

@@ -37,10 +37,6 @@ func (v *vxtoRepository) AddVtxos(ctx context.Context, vtxos []domain.Vtxo) erro
txBody := func(querierWithTx *queries.Queries) error { txBody := func(querierWithTx *queries.Queries) error {
for i := range vtxos { for i := range vtxos {
vtxo := vtxos[i] vtxo := vtxos[i]
var redeemTx string
if vtxo.AsyncPayment != nil {
redeemTx = vtxo.AsyncPayment.RedeemTx
}
if err := querierWithTx.UpsertVtxo( if err := querierWithTx.UpsertVtxo(
ctx, queries.UpsertVtxoParams{ ctx, queries.UpsertVtxoParams{
Txid: vtxo.Txid, Txid: vtxo.Txid,
@@ -53,25 +49,12 @@ func (v *vxtoRepository) AddVtxos(ctx context.Context, vtxos []domain.Vtxo) erro
Redeemed: vtxo.Redeemed, Redeemed: vtxo.Redeemed,
Swept: vtxo.Swept, Swept: vtxo.Swept,
ExpireAt: vtxo.ExpireAt, ExpireAt: vtxo.ExpireAt,
RedeemTx: sql.NullString{String: redeemTx, Valid: true}, RedeemTx: sql.NullString{String: vtxo.RedeemTx, Valid: true},
Pending: vtxo.Pending, Pending: vtxo.Pending,
}, },
); err != nil { ); err != nil {
return err 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 return nil
@@ -86,12 +69,9 @@ func (v *vxtoRepository) GetAllSweepableVtxos(ctx context.Context) ([]domain.Vtx
return nil, err return nil, err
} }
rows := make([]vtxoWithUnconditionalForfeitTxs, 0, len(res)) rows := make([]queries.Vtxo, 0, len(res))
for _, row := range res { for _, row := range res {
rows = append(rows, vtxoWithUnconditionalForfeitTxs{ rows = append(rows, row.Vtxo)
vtxo: row.Vtxo,
tx: row.UncondForfeitTxVw,
})
} }
return readRows(rows) return readRows(rows)
} }
@@ -99,7 +79,7 @@ func (v *vxtoRepository) GetAllSweepableVtxos(ctx context.Context) ([]domain.Vtx
func (v *vxtoRepository) GetAllVtxos(ctx context.Context, pubkey string) ([]domain.Vtxo, []domain.Vtxo, error) { func (v *vxtoRepository) GetAllVtxos(ctx context.Context, pubkey string) ([]domain.Vtxo, []domain.Vtxo, error) {
withPubkey := len(pubkey) > 0 withPubkey := len(pubkey) > 0
var rows []vtxoWithUnconditionalForfeitTxs var rows []queries.Vtxo
if withPubkey { if withPubkey {
if len(pubkey) == 66 { if len(pubkey) == 66 {
pubkey = pubkey[2:] pubkey = pubkey[2:]
@@ -109,24 +89,18 @@ func (v *vxtoRepository) GetAllVtxos(ctx context.Context, pubkey string) ([]doma
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
rows = make([]vtxoWithUnconditionalForfeitTxs, 0, len(res)) rows = make([]queries.Vtxo, 0, len(res))
for _, row := range res { for _, row := range res {
rows = append(rows, vtxoWithUnconditionalForfeitTxs{ rows = append(rows, row.Vtxo)
vtxo: row.Vtxo,
tx: row.UncondForfeitTxVw,
})
} }
} else { } else {
res, err := v.querier.SelectNotRedeemedVtxos(ctx) res, err := v.querier.SelectNotRedeemedVtxos(ctx)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
rows = make([]vtxoWithUnconditionalForfeitTxs, 0, len(res)) rows = make([]queries.Vtxo, 0, len(res))
for _, row := range res { for _, row := range res {
rows = append(rows, vtxoWithUnconditionalForfeitTxs{ rows = append(rows, row.Vtxo)
vtxo: row.Vtxo,
tx: row.UncondForfeitTxVw,
})
} }
} }
@@ -163,12 +137,7 @@ func (v *vxtoRepository) GetVtxos(ctx context.Context, outpoints []domain.VtxoKe
return nil, err return nil, err
} }
result, err := readRows([]vtxoWithUnconditionalForfeitTxs{ result, err := readRows([]queries.Vtxo{res.Vtxo})
{
vtxo: res.Vtxo,
tx: res.UncondForfeitTxVw,
},
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -188,12 +157,9 @@ func (v *vxtoRepository) GetVtxosForRound(ctx context.Context, txid string) ([]d
if err != nil { if err != nil {
return nil, err return nil, err
} }
rows := make([]vtxoWithUnconditionalForfeitTxs, 0, len(res)) rows := make([]queries.Vtxo, 0, len(res))
for _, row := range res { for _, row := range res {
rows = append(rows, vtxoWithUnconditionalForfeitTxs{ rows = append(rows, row.Vtxo)
vtxo: row.Vtxo,
tx: row.UncondForfeitTxVw,
})
} }
return readRows(rows) return readRows(rows)
@@ -281,18 +247,7 @@ func (v *vxtoRepository) UpdateExpireAt(ctx context.Context, vtxos []domain.Vtxo
return execTx(ctx, v.db, txBody) return execTx(ctx, v.db, txBody)
} }
func rowToVtxo(row queries.Vtxo, uncondForfeitTxs []queries.UncondForfeitTxVw) domain.Vtxo { func rowToVtxo(row queries.Vtxo) 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{ return domain.Vtxo{
VtxoKey: domain.VtxoKey{ VtxoKey: domain.VtxoKey{
Txid: row.Txid, Txid: row.Txid,
@@ -308,43 +263,15 @@ func rowToVtxo(row queries.Vtxo, uncondForfeitTxs []queries.UncondForfeitTxVw) d
Redeemed: row.Redeemed, Redeemed: row.Redeemed,
Swept: row.Swept, Swept: row.Swept,
ExpireAt: row.ExpireAt, ExpireAt: row.ExpireAt,
AsyncPayment: asyncPayment, RedeemTx: row.RedeemTx.String,
Pending: row.Pending, Pending: row.Pending,
} }
} }
type vtxoWithUnconditionalForfeitTxs struct { func readRows(rows []queries.Vtxo) ([]domain.Vtxo, error) {
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)) vtxos := make([]domain.Vtxo, 0, len(rows))
for _, row := range rows { for _, vtxo := range rows {
vtxoKey := domain.VtxoKey{ vtxos = append(vtxos, rowToVtxo(vtxo))
Txid: row.vtxo.Txid,
VOut: uint32(row.vtxo.Vout),
}
uncondForfeitTxs := uncondForfeitTxsMap[vtxoKey]
vtxos = append(vtxos, rowToVtxo(row.vtxo, uncondForfeitTxs))
} }
return vtxos, nil return vtxos, nil

View File

@@ -365,8 +365,8 @@ func (b *txBuilder) FindLeaves(
func (b *txBuilder) BuildAsyncPaymentTransactions( func (b *txBuilder) BuildAsyncPaymentTransactions(
_ []domain.Vtxo, _ *secp256k1.PublicKey, _ []domain.Receiver, _ []domain.Vtxo, _ *secp256k1.PublicKey, _ []domain.Receiver,
) (*domain.AsyncPaymentTxs, error) { ) (string, error) {
return nil, fmt.Errorf("not implemented") return "", fmt.Errorf("not implemented")
} }
func (b *txBuilder) createPoolTx( func (b *txBuilder) createPoolTx(

View File

@@ -402,28 +402,25 @@ func (b *txBuilder) FindLeaves(congestionTree tree.CongestionTree, fromtxid stri
func (b *txBuilder) BuildAsyncPaymentTransactions( func (b *txBuilder) BuildAsyncPaymentTransactions(
vtxos []domain.Vtxo, aspPubKey *secp256k1.PublicKey, receivers []domain.Receiver, vtxos []domain.Vtxo, aspPubKey *secp256k1.PublicKey, receivers []domain.Receiver,
) (*domain.AsyncPaymentTxs, error) { ) (string, error) {
if len(vtxos) <= 0 { if len(vtxos) <= 0 {
return nil, fmt.Errorf("missing vtxos") return "", fmt.Errorf("missing vtxos")
} }
ins := make([]*wire.OutPoint, 0, len(vtxos)) ins := make([]*wire.OutPoint, 0, len(vtxos))
outs := make([]*wire.TxOut, 0, len(receivers)) outs := make([]*wire.TxOut, 0, len(receivers))
unconditionalForfeitTxs := make([]string, 0, len(vtxos)) witnessUtxos := make(map[int]*wire.TxOut)
redeemTxWeightEstimator := &input.TxWeightEstimator{} tapscripts := make(map[int]*psbt.TaprootTapLeafScript)
for _, vtxo := range vtxos {
if vtxo.Spent || vtxo.Redeemed || vtxo.Swept {
return nil, fmt.Errorf("all vtxos must be unspent")
}
aspScript, err := common.P2TRScript(aspPubKey) redeemTxWeightEstimator := &input.TxWeightEstimator{}
if err != nil { for index, vtxo := range vtxos {
return nil, err if vtxo.Spent || vtxo.Redeemed || vtxo.Swept {
return "", fmt.Errorf("all vtxos must be unspent")
} }
vtxoTxID, err := chainhash.NewHashFromStr(vtxo.Txid) vtxoTxID, err := chainhash.NewHashFromStr(vtxo.Txid)
if err != nil { if err != nil {
return nil, err return "", err
} }
vtxoOutpoint := &wire.OutPoint{ vtxoOutpoint := &wire.OutPoint{
@@ -433,104 +430,60 @@ func (b *txBuilder) BuildAsyncPaymentTransactions(
vtxoScript, err := bitcointree.ParseVtxoScript(vtxo.Descriptor) vtxoScript, err := bitcointree.ParseVtxoScript(vtxo.Descriptor)
if err != nil { if err != nil {
return nil, err return "", err
} }
vtxoTapKey, vtxoTree, err := vtxoScript.TapTree() vtxoTapKey, vtxoTree, err := vtxoScript.TapTree()
if err != nil { if err != nil {
return nil, err return "", err
} }
vtxoOutputScript, err := common.P2TRScript(vtxoTapKey) vtxoOutputScript, err := common.P2TRScript(vtxoTapKey)
if err != nil { if err != nil {
return nil, err return "", err
} }
var tapscript *waddrmgr.Tapscript witnessUtxos[index] = &wire.TxOut{
forfeitTxWeightEstimator := &input.TxWeightEstimator{}
if defaultVtxoScript, ok := vtxoScript.(*bitcointree.DefaultVtxoScript); ok {
forfeitClosure := &bitcointree.MultisigClosure{
Pubkey: defaultVtxoScript.Owner,
AspPubkey: defaultVtxoScript.Asp,
}
forfeitLeaf, err := forfeitClosure.Leaf()
if err != nil {
return nil, err
}
forfeitProof, err := vtxoTree.GetTaprootMerkleProof(forfeitLeaf.TapHash())
if err != nil {
return nil, err
}
ctrlBlock, err := txscript.ParseControlBlock(forfeitProof.ControlBlock)
if err != nil {
return nil, err
}
tapscript = &waddrmgr.Tapscript{
RevealedScript: forfeitProof.Script,
ControlBlock: ctrlBlock,
}
forfeitTxWeightEstimator.AddTapscriptInput(64*2, tapscript)
forfeitTxWeightEstimator.AddP2TROutput() // ASP output
} else {
return nil, fmt.Errorf("vtxo script is not a default vtxo script, cannot be async spent")
}
forfeitTxFee, err := b.wallet.MinRelayFee(context.Background(), uint64(forfeitTxWeightEstimator.VSize()))
if err != nil {
return nil, err
}
if forfeitTxFee >= vtxo.Amount {
return nil, fmt.Errorf("forfeit tx fee is higher than the amount of the vtxo")
}
output := &wire.TxOut{
PkScript: aspScript,
Value: int64(vtxo.Amount - forfeitTxFee),
}
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), Value: int64(vtxo.Amount),
PkScript: vtxoOutputScript, PkScript: vtxoOutputScript,
} }
ctrlBlock, err := tapscript.ControlBlock.ToBytes() if defaultVtxoScript, ok := vtxoScript.(*bitcointree.DefaultVtxoScript); ok {
if err != nil { forfeitLeaf := bitcointree.MultisigClosure{
return nil, err Pubkey: defaultVtxoScript.Owner,
AspPubkey: defaultVtxoScript.Asp,
} }
unconditionnalForfeitPtx.Inputs[0].TaprootLeafScript = []*psbt.TaprootTapLeafScript{ tapLeaf, err := forfeitLeaf.Leaf()
{ if err != nil {
Script: tapscript.RevealedScript, return "", err
ControlBlock: ctrlBlock, }
leafProof, err := vtxoTree.GetTaprootMerkleProof(tapLeaf.TapHash())
if err != nil {
return "", err
}
tapscripts[index] = &psbt.TaprootTapLeafScript{
ControlBlock: leafProof.ControlBlock,
Script: leafProof.Script,
LeafVersion: txscript.BaseLeafVersion, LeafVersion: txscript.BaseLeafVersion,
},
} }
forfeitTx, err := unconditionnalForfeitPtx.B64Encode() ctrlBlock, err := txscript.ParseControlBlock(leafProof.ControlBlock)
if err != nil { if err != nil {
return nil, err return "", err
}
redeemTxWeightEstimator.AddTapscriptInput(64*2, &waddrmgr.Tapscript{
RevealedScript: leafProof.Script,
ControlBlock: ctrlBlock,
})
} else {
return "", fmt.Errorf("vtxo %s:%d script is not default script, can't be async spent", vtxo.Txid, vtxo.VOut)
} }
unconditionalForfeitTxs = append(unconditionalForfeitTxs, forfeitTx)
ins = append(ins, vtxoOutpoint) ins = append(ins, vtxoOutpoint)
redeemTxWeightEstimator.AddTapscriptInput(64*2, tapscript)
} }
for range receivers { for range receivers {
@@ -539,27 +492,27 @@ func (b *txBuilder) BuildAsyncPaymentTransactions(
redeemTxMinRelayFee, err := b.wallet.MinRelayFee(context.Background(), uint64(redeemTxWeightEstimator.VSize())) redeemTxMinRelayFee, err := b.wallet.MinRelayFee(context.Background(), uint64(redeemTxWeightEstimator.VSize()))
if err != nil { if err != nil {
return nil, err return "", err
} }
if redeemTxMinRelayFee >= receivers[len(receivers)-1].Amount { if redeemTxMinRelayFee >= receivers[len(receivers)-1].Amount {
return nil, fmt.Errorf("redeem tx fee is higher than the amount of the change receiver") return "", fmt.Errorf("redeem tx fee is higher than the amount of the change receiver")
} }
for i, receiver := range receivers { for i, receiver := range receivers {
offchainScript, err := bitcointree.ParseVtxoScript(receiver.Descriptor) offchainScript, err := bitcointree.ParseVtxoScript(receiver.Descriptor)
if err != nil { if err != nil {
return nil, err return "", err
} }
receiverVtxoTaprootKey, _, err := offchainScript.TapTree() receiverVtxoTaprootKey, _, err := offchainScript.TapTree()
if err != nil { if err != nil {
return nil, err return "", err
} }
newVtxoScript, err := common.P2TRScript(receiverVtxoTaprootKey) newVtxoScript, err := common.P2TRScript(receiverVtxoTaprootKey)
if err != nil { if err != nil {
return nil, err return "", err
} }
// Deduct the min relay fee from the very last receiver which is supposed // Deduct the min relay fee from the very last receiver which is supposed
@@ -583,34 +536,27 @@ func (b *txBuilder) BuildAsyncPaymentTransactions(
ins, outs, 2, 0, sequences, ins, outs, 2, 0, sequences,
) )
if err != nil { if err != nil {
return nil, err return "", err
} }
for i := range redeemPtx.Inputs { for i := range redeemPtx.Inputs {
unconditionnalForfeitPsbt, _ := psbt.NewFromRawBytes( redeemPtx.Inputs[i].WitnessUtxo = witnessUtxos[i]
strings.NewReader(unconditionalForfeitTxs[i]), true, redeemPtx.Inputs[i].TaprootLeafScript = []*psbt.TaprootTapLeafScript{tapscripts[i]}
)
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() redeemTx, err := redeemPtx.B64Encode()
if err != nil { if err != nil {
return nil, err return "", err
} }
signedRedeemTx, err := b.wallet.SignTransactionTapscript( signedRedeemTx, err := b.wallet.SignTransactionTapscript(
context.Background(), redeemTx, nil, context.Background(), redeemTx, nil,
) )
if err != nil { if err != nil {
return nil, err return "", err
} }
return &domain.AsyncPaymentTxs{ return signedRedeemTx, nil
RedeemTx: signedRedeemTx,
UnconditionalForfeitTxs: unconditionalForfeitTxs,
}, nil
} }
// TODO use lnd CoinSelect to craft the pool tx // TODO use lnd CoinSelect to craft the pool tx

View File

@@ -362,7 +362,7 @@ func (h *handler) CreatePayment(
} }
} }
redeemTx, unconditionalForfeitTxs, err := h.svc.CreateAsyncPayment( redeemTx, err := h.svc.CreateAsyncPayment(
ctx, inputs, receivers, ctx, inputs, receivers,
) )
if err != nil { if err != nil {
@@ -371,7 +371,6 @@ func (h *handler) CreatePayment(
return &arkv1.CreatePaymentResponse{ return &arkv1.CreatePaymentResponse{
SignedRedeemTx: redeemTx, SignedRedeemTx: redeemTx,
UsignedUnconditionalForfeitTxs: unconditionalForfeitTxs,
}, nil }, nil
} }
@@ -382,12 +381,8 @@ func (h *handler) CompletePayment(
return nil, status.Error(codes.InvalidArgument, "missing signed redeem tx") 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( if err := h.svc.CompleteAsyncPayment(
ctx, req.GetSignedRedeemTx(), req.GetSignedUnconditionalForfeitTxs(), ctx, req.GetSignedRedeemTx(),
); err != nil { ); err != nil {
return nil, err return nil, err
} }

View File

@@ -65,13 +65,6 @@ type vtxoList []domain.Vtxo
func (v vtxoList) toProto() []*arkv1.Vtxo { func (v vtxoList) toProto() []*arkv1.Vtxo {
list := make([]*arkv1.Vtxo, 0, len(v)) list := make([]*arkv1.Vtxo, 0, len(v))
for _, vv := range v { for _, vv := range v {
var pendingData *arkv1.PendingPayment
if vv.AsyncPayment != nil {
pendingData = &arkv1.PendingPayment{
RedeemTx: vv.AsyncPayment.RedeemTx,
UnconditionalForfeitTxs: vv.AsyncPayment.UnconditionalForfeitTxs,
}
}
list = append(list, &arkv1.Vtxo{ list = append(list, &arkv1.Vtxo{
Outpoint: &arkv1.Outpoint{ Outpoint: &arkv1.Outpoint{
Txid: vv.Txid, Txid: vv.Txid,
@@ -84,7 +77,7 @@ func (v vtxoList) toProto() []*arkv1.Vtxo {
ExpireAt: vv.ExpireAt, ExpireAt: vv.ExpireAt,
SpentBy: vv.SpentBy, SpentBy: vv.SpentBy,
Swept: vv.Swept, Swept: vv.Swept,
PendingData: pendingData, RedeemTx: vv.RedeemTx,
Pending: vv.Pending, Pending: vv.Pending,
}) })
} }