admin swaps

This commit is contained in:
boufni95 2026-01-27 16:08:52 +00:00
parent a596e186fe
commit d120ad7f99
22 changed files with 1258 additions and 226 deletions

View file

@ -22,6 +22,7 @@ import { AppUserDevice } from "./build/src/services/storage/entity/AppUserDevice
import { UserAccess } from "./build/src/services/storage/entity/UserAccess.js" import { UserAccess } from "./build/src/services/storage/entity/UserAccess.js"
import { AdminSettings } from "./build/src/services/storage/entity/AdminSettings.js" import { AdminSettings } from "./build/src/services/storage/entity/AdminSettings.js"
import { TransactionSwap } from "./build/src/services/storage/entity/TransactionSwap.js" import { TransactionSwap } from "./build/src/services/storage/entity/TransactionSwap.js"
import { InvoiceSwap } from "./build/src/services/storage/entity/InvoiceSwap.js"
import { Initial1703170309875 } from './build/src/services/storage/migrations/1703170309875-initial.js' import { Initial1703170309875 } from './build/src/services/storage/migrations/1703170309875-initial.js'
import { LspOrder1718387847693 } from './build/src/services/storage/migrations/1718387847693-lsp_order.js' import { LspOrder1718387847693 } from './build/src/services/storage/migrations/1718387847693-lsp_order.js'
@ -47,6 +48,7 @@ import { TxSwap1762890527098 } from './build/src/services/storage/migrations/176
import { TxSwapAddress1764779178945 } from './build/src/services/storage/migrations/1764779178945-tx_swap_address.js' import { TxSwapAddress1764779178945 } from './build/src/services/storage/migrations/1764779178945-tx_swap_address.js'
import { ClinkRequester1765497600000 } from './build/src/services/storage/migrations/1765497600000-clink_requester.js' import { ClinkRequester1765497600000 } from './build/src/services/storage/migrations/1765497600000-clink_requester.js'
import { TrackedProviderHeight1766504040000 } from './build/src/services/storage/migrations/1766504040000-tracked_provider_height.js' import { TrackedProviderHeight1766504040000 } from './build/src/services/storage/migrations/1766504040000-tracked_provider_height.js'
import { SwapsServiceUrl1768413055036 } from './build/src/services/storage/migrations/1768413055036-swaps_service_url.js'
export default new DataSource({ export default new DataSource({
type: "better-sqlite3", type: "better-sqlite3",
@ -56,11 +58,11 @@ export default new DataSource({
PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264, DebitToPub1727105758354, UserCbUrl1727112281043, PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264, DebitToPub1727105758354, UserCbUrl1727112281043,
UserOffer1733502626042, ManagementGrant1751307732346, InvoiceCallbackUrls1752425992291, OldSomethingLeftover1753106599604, UserReceivingInvoiceIdx1753109184611, UserOffer1733502626042, ManagementGrant1751307732346, InvoiceCallbackUrls1752425992291, OldSomethingLeftover1753106599604, UserReceivingInvoiceIdx1753109184611,
AppUserDevice1753285173175, UserAccess1759426050669, AddBlindToUserOffer1760000000000, ApplicationAvatarUrl1761000001000, AdminSettings1761683639419, TxSwap1762890527098, AppUserDevice1753285173175, UserAccess1759426050669, AddBlindToUserOffer1760000000000, ApplicationAvatarUrl1761000001000, AdminSettings1761683639419, TxSwap1762890527098,
TxSwapAddress1764779178945, ClinkRequester1765497600000, TrackedProviderHeight1766504040000], TxSwapAddress1764779178945, ClinkRequester1765497600000, TrackedProviderHeight1766504040000, SwapsServiceUrl1768413055036],
entities: [User, UserReceivingInvoice, UserReceivingAddress, AddressReceivingTransaction, UserInvoicePayment, UserTransactionPayment, entities: [User, UserReceivingInvoice, UserReceivingAddress, AddressReceivingTransaction, UserInvoicePayment, UserTransactionPayment,
UserBasicAuth, UserEphemeralKey, Product, UserToUserPayment, Application, ApplicationUser, UserToUserPayment, LspOrder, LndNodeInfo, UserBasicAuth, UserEphemeralKey, Product, UserToUserPayment, Application, ApplicationUser, UserToUserPayment, LspOrder, LndNodeInfo,
TrackedProvider, InviteToken, DebitAccess, UserOffer, ManagementGrant, AppUserDevice, UserAccess, AdminSettings, TransactionSwap], TrackedProvider, InviteToken, DebitAccess, UserOffer, ManagementGrant, AppUserDevice, UserAccess, AdminSettings, TransactionSwap, InvoiceSwap],
// synchronize: true, // synchronize: true,
}) })
//npx typeorm migration:generate ./src/services/storage/migrations/swaps_service_url -d ./datasource.js //npx typeorm migration:generate ./src/services/storage/migrations/invoice_swaps -d ./datasource.js

View file

@ -93,6 +93,11 @@ The nostr server will send back a message response, and inside the body there wi
- input: [MessagingToken](#MessagingToken) - input: [MessagingToken](#MessagingToken)
- This methods has an __empty__ __response__ body - This methods has an __empty__ __response__ body
- GetAdminInvoiceSwapQuotes
- auth type: __Admin__
- input: [InvoiceSwapRequest](#InvoiceSwapRequest)
- output: [InvoiceSwapQuoteList](#InvoiceSwapQuoteList)
- GetAdminTransactionSwapQuotes - GetAdminTransactionSwapQuotes
- auth type: __Admin__ - auth type: __Admin__
- input: [TransactionSwapRequest](#TransactionSwapRequest) - input: [TransactionSwapRequest](#TransactionSwapRequest)
@ -243,20 +248,25 @@ The nostr server will send back a message response, and inside the body there wi
- input: [LinkNPubThroughTokenRequest](#LinkNPubThroughTokenRequest) - input: [LinkNPubThroughTokenRequest](#LinkNPubThroughTokenRequest)
- This methods has an __empty__ __response__ body - This methods has an __empty__ __response__ body
- ListAdminSwaps - ListAdminInvoiceSwaps
- auth type: __Admin__ - auth type: __Admin__
- This methods has an __empty__ __request__ body - This methods has an __empty__ __request__ body
- output: [SwapsList](#SwapsList) - output: [InvoiceSwapsList](#InvoiceSwapsList)
- ListAdminTxSwaps
- auth type: __Admin__
- This methods has an __empty__ __request__ body
- output: [TxSwapsList](#TxSwapsList)
- ListChannels - ListChannels
- auth type: __Admin__ - auth type: __Admin__
- This methods has an __empty__ __request__ body - This methods has an __empty__ __request__ body
- output: [LndChannels](#LndChannels) - output: [LndChannels](#LndChannels)
- ListSwaps - ListTxSwaps
- auth type: __User__ - auth type: __User__
- This methods has an __empty__ __request__ body - This methods has an __empty__ __request__ body
- output: [SwapsList](#SwapsList) - output: [TxSwapsList](#TxSwapsList)
- LndGetInfo - LndGetInfo
- auth type: __Admin__ - auth type: __Admin__
@ -290,10 +300,15 @@ The nostr server will send back a message response, and inside the body there wi
- input: [PayAddressRequest](#PayAddressRequest) - input: [PayAddressRequest](#PayAddressRequest)
- output: [PayAddressResponse](#PayAddressResponse) - output: [PayAddressResponse](#PayAddressResponse)
- PayAdminInvoiceSwap
- auth type: __Admin__
- input: [PayAdminInvoiceSwapRequest](#PayAdminInvoiceSwapRequest)
- output: [AdminInvoiceSwapResponse](#AdminInvoiceSwapResponse)
- PayAdminTransactionSwap - PayAdminTransactionSwap
- auth type: __Admin__ - auth type: __Admin__
- input: [PayAdminTransactionSwapRequest](#PayAdminTransactionSwapRequest) - input: [PayAdminTransactionSwapRequest](#PayAdminTransactionSwapRequest)
- output: [AdminSwapResponse](#AdminSwapResponse) - output: [AdminTxSwapResponse](#AdminTxSwapResponse)
- PayInvoice - PayInvoice
- auth type: __User__ - auth type: __User__
@ -540,6 +555,13 @@ The nostr server will send back a message response, and inside the body there wi
- input: [MessagingToken](#MessagingToken) - input: [MessagingToken](#MessagingToken)
- This methods has an __empty__ __response__ body - This methods has an __empty__ __response__ body
- GetAdminInvoiceSwapQuotes
- auth type: __Admin__
- http method: __post__
- http route: __/api/admin/swap/invoice/quote__
- input: [InvoiceSwapRequest](#InvoiceSwapRequest)
- output: [InvoiceSwapQuoteList](#InvoiceSwapQuoteList)
- GetAdminTransactionSwapQuotes - GetAdminTransactionSwapQuotes
- auth type: __Admin__ - auth type: __Admin__
- http method: __post__ - http method: __post__
@ -743,7 +765,7 @@ The nostr server will send back a message response, and inside the body there wi
- GetTransactionSwapQuotes - GetTransactionSwapQuotes
- auth type: __User__ - auth type: __User__
- http method: __post__ - http method: __post__
- http route: __/api/user/swap/quote__ - http route: __/api/user/swap/transaction/quote__
- input: [TransactionSwapRequest](#TransactionSwapRequest) - input: [TransactionSwapRequest](#TransactionSwapRequest)
- output: [TransactionSwapQuoteList](#TransactionSwapQuoteList) - output: [TransactionSwapQuoteList](#TransactionSwapQuoteList)
@ -834,12 +856,19 @@ The nostr server will send back a message response, and inside the body there wi
- input: [LinkNPubThroughTokenRequest](#LinkNPubThroughTokenRequest) - input: [LinkNPubThroughTokenRequest](#LinkNPubThroughTokenRequest)
- This methods has an __empty__ __response__ body - This methods has an __empty__ __response__ body
- ListAdminSwaps - ListAdminInvoiceSwaps
- auth type: __Admin__ - auth type: __Admin__
- http method: __post__ - http method: __post__
- http route: __/api/admin/swap/list__ - http route: __/api/admin/swap/invoice/list__
- This methods has an __empty__ __request__ body - This methods has an __empty__ __request__ body
- output: [SwapsList](#SwapsList) - output: [InvoiceSwapsList](#InvoiceSwapsList)
- ListAdminTxSwaps
- auth type: __Admin__
- http method: __post__
- http route: __/api/admin/swap/transaction/list__
- This methods has an __empty__ __request__ body
- output: [TxSwapsList](#TxSwapsList)
- ListChannels - ListChannels
- auth type: __Admin__ - auth type: __Admin__
@ -848,12 +877,12 @@ The nostr server will send back a message response, and inside the body there wi
- This methods has an __empty__ __request__ body - This methods has an __empty__ __request__ body
- output: [LndChannels](#LndChannels) - output: [LndChannels](#LndChannels)
- ListSwaps - ListTxSwaps
- auth type: __User__ - auth type: __User__
- http method: __post__ - http method: __post__
- http route: __/api/user/swap/list__ - http route: __/api/user/swap/transaction/list__
- This methods has an __empty__ __request__ body - This methods has an __empty__ __request__ body
- output: [SwapsList](#SwapsList) - output: [TxSwapsList](#TxSwapsList)
- LndGetInfo - LndGetInfo
- auth type: __Admin__ - auth type: __Admin__
@ -899,12 +928,19 @@ The nostr server will send back a message response, and inside the body there wi
- input: [PayAddressRequest](#PayAddressRequest) - input: [PayAddressRequest](#PayAddressRequest)
- output: [PayAddressResponse](#PayAddressResponse) - output: [PayAddressResponse](#PayAddressResponse)
- PayAdminInvoiceSwap
- auth type: __Admin__
- http method: __post__
- http route: __/api/admin/swap/invoice/pay__
- input: [PayAdminInvoiceSwapRequest](#PayAdminInvoiceSwapRequest)
- output: [AdminInvoiceSwapResponse](#AdminInvoiceSwapResponse)
- PayAdminTransactionSwap - PayAdminTransactionSwap
- auth type: __Admin__ - auth type: __Admin__
- http method: __post__ - http method: __post__
- http route: __/api/admin/swap/transaction/pay__ - http route: __/api/admin/swap/transaction/pay__
- input: [PayAdminTransactionSwapRequest](#PayAdminTransactionSwapRequest) - input: [PayAdminTransactionSwapRequest](#PayAdminTransactionSwapRequest)
- output: [AdminSwapResponse](#AdminSwapResponse) - output: [AdminTxSwapResponse](#AdminTxSwapResponse)
- PayAppUserInvoice - PayAppUserInvoice
- auth type: __App__ - auth type: __App__
@ -1098,7 +1134,10 @@ The nostr server will send back a message response, and inside the body there wi
- __name__: _string_ - __name__: _string_
- __price_sats__: _number_ - __price_sats__: _number_
### AdminSwapResponse ### AdminInvoiceSwapResponse
- __tx_id__: _string_
### AdminTxSwapResponse
- __network_fee__: _number_ - __network_fee__: _number_
- __tx_id__: _string_ - __tx_id__: _string_
@ -1331,6 +1370,35 @@ The nostr server will send back a message response, and inside the body there wi
- __token__: _string_ - __token__: _string_
- __url__: _string_ - __url__: _string_
### InvoiceSwapOperation
- __failure_reason__: _string_ *this field is optional
- __invoice_paid__: _string_
- __operation_payment__: _[UserOperation](#UserOperation)_ *this field is optional
- __swap_operation_id__: _string_
- __tx_id__: _string_
### InvoiceSwapQuote
- __address__: _string_
- __chain_fee_sats__: _number_
- __invoice__: _string_
- __invoice_amount_sats__: _number_
- __service_fee_sats__: _number_
- __service_url__: _string_
- __swap_fee_sats__: _number_
- __swap_operation_id__: _string_
- __transaction_amount_sats__: _number_
- __tx_id__: _string_
### InvoiceSwapQuoteList
- __quotes__: ARRAY of: _[InvoiceSwapQuote](#InvoiceSwapQuote)_
### InvoiceSwapRequest
- __invoice__: _string_
### InvoiceSwapsList
- __quotes__: ARRAY of: _[InvoiceSwapQuote](#InvoiceSwapQuote)_
- __swaps__: ARRAY of: _[InvoiceSwapOperation](#InvoiceSwapOperation)_
### LatestBundleMetricReq ### LatestBundleMetricReq
- __limit__: _number_ *this field is optional - __limit__: _number_ *this field is optional
@ -1534,6 +1602,10 @@ The nostr server will send back a message response, and inside the body there wi
- __service_fee__: _number_ - __service_fee__: _number_
- __txId__: _string_ - __txId__: _string_
### PayAdminInvoiceSwapRequest
- __sat_per_v_byte__: _number_
- __swap_operation_id__: _string_
### PayAdminTransactionSwapRequest ### PayAdminTransactionSwapRequest
- __address__: _string_ - __address__: _string_
- __swap_operation_id__: _string_ - __swap_operation_id__: _string_
@ -1640,16 +1712,6 @@ The nostr server will send back a message response, and inside the body there wi
- __page__: _number_ - __page__: _number_
- __request_id__: _number_ *this field is optional - __request_id__: _number_ *this field is optional
### SwapOperation
- __address_paid__: _string_
- __failure_reason__: _string_ *this field is optional
- __operation_payment__: _[UserOperation](#UserOperation)_ *this field is optional
- __swap_operation_id__: _string_
### SwapsList
- __quotes__: ARRAY of: _[TransactionSwapQuote](#TransactionSwapQuote)_
- __swaps__: ARRAY of: _[SwapOperation](#SwapOperation)_
### TransactionSwapQuote ### TransactionSwapQuote
- __chain_fee_sats__: _number_ - __chain_fee_sats__: _number_
- __invoice_amount_sats__: _number_ - __invoice_amount_sats__: _number_
@ -1665,6 +1727,16 @@ The nostr server will send back a message response, and inside the body there wi
### TransactionSwapRequest ### TransactionSwapRequest
- __transaction_amount_sats__: _number_ - __transaction_amount_sats__: _number_
### TxSwapOperation
- __address_paid__: _string_
- __failure_reason__: _string_ *this field is optional
- __operation_payment__: _[UserOperation](#UserOperation)_ *this field is optional
- __swap_operation_id__: _string_
### TxSwapsList
- __quotes__: ARRAY of: _[TransactionSwapQuote](#TransactionSwapQuote)_
- __swaps__: ARRAY of: _[TxSwapOperation](#TxSwapOperation)_
### UpdateChannelPolicyRequest ### UpdateChannelPolicyRequest
- __policy__: _[ChannelPolicy](#ChannelPolicy)_ - __policy__: _[ChannelPolicy](#ChannelPolicy)_
- __update__: _[UpdateChannelPolicyRequest_update](#UpdateChannelPolicyRequest_update)_ - __update__: _[UpdateChannelPolicyRequest_update](#UpdateChannelPolicyRequest_update)_

View file

@ -74,6 +74,7 @@ type Client struct {
EncryptionExchange func(req EncryptionExchangeRequest) error EncryptionExchange func(req EncryptionExchangeRequest) error
EnrollAdminToken func(req EnrollAdminTokenRequest) error EnrollAdminToken func(req EnrollAdminTokenRequest) error
EnrollMessagingToken func(req MessagingToken) error EnrollMessagingToken func(req MessagingToken) error
GetAdminInvoiceSwapQuotes func(req InvoiceSwapRequest) (*InvoiceSwapQuoteList, error)
GetAdminTransactionSwapQuotes func(req TransactionSwapRequest) (*TransactionSwapQuoteList, error) GetAdminTransactionSwapQuotes func(req TransactionSwapRequest) (*TransactionSwapQuoteList, error)
GetApp func() (*Application, error) GetApp func() (*Application, error)
GetAppUser func(req GetAppUserRequest) (*AppUser, error) GetAppUser func(req GetAppUserRequest) (*AppUser, error)
@ -114,16 +115,18 @@ type Client struct {
HandleLnurlWithdraw func(query HandleLnurlWithdraw_Query) error HandleLnurlWithdraw func(query HandleLnurlWithdraw_Query) error
Health func() error Health func() error
LinkNPubThroughToken func(req LinkNPubThroughTokenRequest) error LinkNPubThroughToken func(req LinkNPubThroughTokenRequest) error
ListAdminSwaps func() (*SwapsList, error) ListAdminInvoiceSwaps func() (*InvoiceSwapsList, error)
ListAdminTxSwaps func() (*TxSwapsList, error)
ListChannels func() (*LndChannels, error) ListChannels func() (*LndChannels, error)
ListSwaps func() (*SwapsList, error) ListTxSwaps func() (*TxSwapsList, error)
LndGetInfo func(req LndGetInfoRequest) (*LndGetInfoResponse, error) LndGetInfo func(req LndGetInfoRequest) (*LndGetInfoResponse, error)
NewAddress func(req NewAddressRequest) (*NewAddressResponse, error) NewAddress func(req NewAddressRequest) (*NewAddressResponse, error)
NewInvoice func(req NewInvoiceRequest) (*NewInvoiceResponse, error) NewInvoice func(req NewInvoiceRequest) (*NewInvoiceResponse, error)
NewProductInvoice func(query NewProductInvoice_Query) (*NewInvoiceResponse, error) NewProductInvoice func(query NewProductInvoice_Query) (*NewInvoiceResponse, error)
OpenChannel func(req OpenChannelRequest) (*OpenChannelResponse, error) OpenChannel func(req OpenChannelRequest) (*OpenChannelResponse, error)
PayAddress func(req PayAddressRequest) (*PayAddressResponse, error) PayAddress func(req PayAddressRequest) (*PayAddressResponse, error)
PayAdminTransactionSwap func(req PayAdminTransactionSwapRequest) (*AdminSwapResponse, error) PayAdminInvoiceSwap func(req PayAdminInvoiceSwapRequest) (*AdminInvoiceSwapResponse, error)
PayAdminTransactionSwap func(req PayAdminTransactionSwapRequest) (*AdminTxSwapResponse, error)
PayAppUserInvoice func(req PayAppUserInvoiceRequest) (*PayInvoiceResponse, error) PayAppUserInvoice func(req PayAppUserInvoiceRequest) (*PayInvoiceResponse, error)
PayInvoice func(req PayInvoiceRequest) (*PayInvoiceResponse, error) PayInvoice func(req PayInvoiceRequest) (*PayInvoiceResponse, error)
PingSubProcesses func() error PingSubProcesses func() error
@ -667,6 +670,35 @@ func NewClient(params ClientParams) *Client {
} }
return nil return nil
}, },
GetAdminInvoiceSwapQuotes: func(req InvoiceSwapRequest) (*InvoiceSwapQuoteList, error) {
auth, err := params.RetrieveAdminAuth()
if err != nil {
return nil, err
}
finalRoute := "/api/admin/swap/invoice/quote"
body, err := json.Marshal(req)
if err != nil {
return nil, err
}
resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth)
if err != nil {
return nil, err
}
result := ResultError{}
err = json.Unmarshal(resBody, &result)
if err != nil {
return nil, err
}
if result.Status == "ERROR" {
return nil, fmt.Errorf(result.Reason)
}
res := InvoiceSwapQuoteList{}
err = json.Unmarshal(resBody, &res)
if err != nil {
return nil, err
}
return &res, nil
},
GetAdminTransactionSwapQuotes: func(req TransactionSwapRequest) (*TransactionSwapQuoteList, error) { GetAdminTransactionSwapQuotes: func(req TransactionSwapRequest) (*TransactionSwapQuoteList, error) {
auth, err := params.RetrieveAdminAuth() auth, err := params.RetrieveAdminAuth()
if err != nil { if err != nil {
@ -1324,7 +1356,7 @@ func NewClient(params ClientParams) *Client {
if err != nil { if err != nil {
return nil, err return nil, err
} }
finalRoute := "/api/user/swap/quote" finalRoute := "/api/user/swap/transaction/quote"
body, err := json.Marshal(req) body, err := json.Marshal(req)
if err != nil { if err != nil {
return nil, err return nil, err
@ -1643,12 +1675,12 @@ func NewClient(params ClientParams) *Client {
} }
return nil return nil
}, },
ListAdminSwaps: func() (*SwapsList, error) { ListAdminInvoiceSwaps: func() (*InvoiceSwapsList, error) {
auth, err := params.RetrieveAdminAuth() auth, err := params.RetrieveAdminAuth()
if err != nil { if err != nil {
return nil, err return nil, err
} }
finalRoute := "/api/admin/swap/list" finalRoute := "/api/admin/swap/invoice/list"
body := []byte{} body := []byte{}
resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth)
if err != nil { if err != nil {
@ -1662,7 +1694,33 @@ func NewClient(params ClientParams) *Client {
if result.Status == "ERROR" { if result.Status == "ERROR" {
return nil, fmt.Errorf(result.Reason) return nil, fmt.Errorf(result.Reason)
} }
res := SwapsList{} res := InvoiceSwapsList{}
err = json.Unmarshal(resBody, &res)
if err != nil {
return nil, err
}
return &res, nil
},
ListAdminTxSwaps: func() (*TxSwapsList, error) {
auth, err := params.RetrieveAdminAuth()
if err != nil {
return nil, err
}
finalRoute := "/api/admin/swap/transaction/list"
body := []byte{}
resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth)
if err != nil {
return nil, err
}
result := ResultError{}
err = json.Unmarshal(resBody, &result)
if err != nil {
return nil, err
}
if result.Status == "ERROR" {
return nil, fmt.Errorf(result.Reason)
}
res := TxSwapsList{}
err = json.Unmarshal(resBody, &res) err = json.Unmarshal(resBody, &res)
if err != nil { if err != nil {
return nil, err return nil, err
@ -1691,12 +1749,12 @@ func NewClient(params ClientParams) *Client {
} }
return &res, nil return &res, nil
}, },
ListSwaps: func() (*SwapsList, error) { ListTxSwaps: func() (*TxSwapsList, error) {
auth, err := params.RetrieveUserAuth() auth, err := params.RetrieveUserAuth()
if err != nil { if err != nil {
return nil, err return nil, err
} }
finalRoute := "/api/user/swap/list" finalRoute := "/api/user/swap/transaction/list"
body := []byte{} body := []byte{}
resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth)
if err != nil { if err != nil {
@ -1710,7 +1768,7 @@ func NewClient(params ClientParams) *Client {
if result.Status == "ERROR" { if result.Status == "ERROR" {
return nil, fmt.Errorf(result.Reason) return nil, fmt.Errorf(result.Reason)
} }
res := SwapsList{} res := TxSwapsList{}
err = json.Unmarshal(resBody, &res) err = json.Unmarshal(resBody, &res)
if err != nil { if err != nil {
return nil, err return nil, err
@ -1892,7 +1950,36 @@ func NewClient(params ClientParams) *Client {
} }
return &res, nil return &res, nil
}, },
PayAdminTransactionSwap: func(req PayAdminTransactionSwapRequest) (*AdminSwapResponse, error) { PayAdminInvoiceSwap: func(req PayAdminInvoiceSwapRequest) (*AdminInvoiceSwapResponse, error) {
auth, err := params.RetrieveAdminAuth()
if err != nil {
return nil, err
}
finalRoute := "/api/admin/swap/invoice/pay"
body, err := json.Marshal(req)
if err != nil {
return nil, err
}
resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth)
if err != nil {
return nil, err
}
result := ResultError{}
err = json.Unmarshal(resBody, &result)
if err != nil {
return nil, err
}
if result.Status == "ERROR" {
return nil, fmt.Errorf(result.Reason)
}
res := AdminInvoiceSwapResponse{}
err = json.Unmarshal(resBody, &res)
if err != nil {
return nil, err
}
return &res, nil
},
PayAdminTransactionSwap: func(req PayAdminTransactionSwapRequest) (*AdminTxSwapResponse, error) {
auth, err := params.RetrieveAdminAuth() auth, err := params.RetrieveAdminAuth()
if err != nil { if err != nil {
return nil, err return nil, err
@ -1914,7 +2001,7 @@ func NewClient(params ClientParams) *Client {
if result.Status == "ERROR" { if result.Status == "ERROR" {
return nil, fmt.Errorf(result.Reason) return nil, fmt.Errorf(result.Reason)
} }
res := AdminSwapResponse{} res := AdminTxSwapResponse{}
err = json.Unmarshal(resBody, &res) err = json.Unmarshal(resBody, &res)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -123,7 +123,10 @@ type AddProductRequest struct {
Name string `json:"name"` Name string `json:"name"`
Price_sats int64 `json:"price_sats"` Price_sats int64 `json:"price_sats"`
} }
type AdminSwapResponse struct { type AdminInvoiceSwapResponse struct {
Tx_id string `json:"tx_id"`
}
type AdminTxSwapResponse struct {
Network_fee int64 `json:"network_fee"` Network_fee int64 `json:"network_fee"`
Tx_id string `json:"tx_id"` Tx_id string `json:"tx_id"`
} }
@ -356,6 +359,35 @@ type HttpCreds struct {
Token string `json:"token"` Token string `json:"token"`
Url string `json:"url"` Url string `json:"url"`
} }
type InvoiceSwapOperation struct {
Failure_reason string `json:"failure_reason"`
Invoice_paid string `json:"invoice_paid"`
Operation_payment *UserOperation `json:"operation_payment"`
Swap_operation_id string `json:"swap_operation_id"`
Tx_id string `json:"tx_id"`
}
type InvoiceSwapQuote struct {
Address string `json:"address"`
Chain_fee_sats int64 `json:"chain_fee_sats"`
Invoice string `json:"invoice"`
Invoice_amount_sats int64 `json:"invoice_amount_sats"`
Service_fee_sats int64 `json:"service_fee_sats"`
Service_url string `json:"service_url"`
Swap_fee_sats int64 `json:"swap_fee_sats"`
Swap_operation_id string `json:"swap_operation_id"`
Transaction_amount_sats int64 `json:"transaction_amount_sats"`
Tx_id string `json:"tx_id"`
}
type InvoiceSwapQuoteList struct {
Quotes []InvoiceSwapQuote `json:"quotes"`
}
type InvoiceSwapRequest struct {
Invoice string `json:"invoice"`
}
type InvoiceSwapsList struct {
Quotes []InvoiceSwapQuote `json:"quotes"`
Swaps []InvoiceSwapOperation `json:"swaps"`
}
type LatestBundleMetricReq struct { type LatestBundleMetricReq struct {
Limit int64 `json:"limit"` Limit int64 `json:"limit"`
} }
@ -559,6 +591,10 @@ type PayAddressResponse struct {
Service_fee int64 `json:"service_fee"` Service_fee int64 `json:"service_fee"`
Txid string `json:"txId"` Txid string `json:"txId"`
} }
type PayAdminInvoiceSwapRequest struct {
Sat_per_v_byte int64 `json:"sat_per_v_byte"`
Swap_operation_id string `json:"swap_operation_id"`
}
type PayAdminTransactionSwapRequest struct { type PayAdminTransactionSwapRequest struct {
Address string `json:"address"` Address string `json:"address"`
Swap_operation_id string `json:"swap_operation_id"` Swap_operation_id string `json:"swap_operation_id"`
@ -665,16 +701,6 @@ type SingleMetricReq struct {
Page int64 `json:"page"` Page int64 `json:"page"`
Request_id int64 `json:"request_id"` Request_id int64 `json:"request_id"`
} }
type SwapOperation struct {
Address_paid string `json:"address_paid"`
Failure_reason string `json:"failure_reason"`
Operation_payment *UserOperation `json:"operation_payment"`
Swap_operation_id string `json:"swap_operation_id"`
}
type SwapsList struct {
Quotes []TransactionSwapQuote `json:"quotes"`
Swaps []SwapOperation `json:"swaps"`
}
type TransactionSwapQuote struct { type TransactionSwapQuote struct {
Chain_fee_sats int64 `json:"chain_fee_sats"` Chain_fee_sats int64 `json:"chain_fee_sats"`
Invoice_amount_sats int64 `json:"invoice_amount_sats"` Invoice_amount_sats int64 `json:"invoice_amount_sats"`
@ -690,6 +716,16 @@ type TransactionSwapQuoteList struct {
type TransactionSwapRequest struct { type TransactionSwapRequest struct {
Transaction_amount_sats int64 `json:"transaction_amount_sats"` Transaction_amount_sats int64 `json:"transaction_amount_sats"`
} }
type TxSwapOperation struct {
Address_paid string `json:"address_paid"`
Failure_reason string `json:"failure_reason"`
Operation_payment *UserOperation `json:"operation_payment"`
Swap_operation_id string `json:"swap_operation_id"`
}
type TxSwapsList struct {
Quotes []TransactionSwapQuote `json:"quotes"`
Swaps []TxSwapOperation `json:"swaps"`
}
type UpdateChannelPolicyRequest struct { type UpdateChannelPolicyRequest struct {
Policy *ChannelPolicy `json:"policy"` Policy *ChannelPolicy `json:"policy"`
Update *UpdateChannelPolicyRequest_update `json:"update"` Update *UpdateChannelPolicyRequest_update `json:"update"`

View file

@ -545,12 +545,12 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
} }
break break
case 'ListSwaps': case 'ListTxSwaps':
if (!methods.ListSwaps) { if (!methods.ListTxSwaps) {
throw new Error('method ListSwaps not found' ) throw new Error('method ListTxSwaps not found' )
} else { } else {
opStats.validate = opStats.guard opStats.validate = opStats.guard
const res = await methods.ListSwaps({...operation, ctx}); responses.push({ status: 'OK', ...res }) const res = await methods.ListTxSwaps({...operation, ctx}); responses.push({ status: 'OK', ...res })
opStats.handle = process.hrtime.bigint() opStats.handle = process.hrtime.bigint()
callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
} }
@ -869,6 +869,28 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
opts.metricsCallback([{ ...info, ...stats, ...authContext }]) opts.metricsCallback([{ ...info, ...stats, ...authContext }])
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
}) })
if (!opts.allowNotImplementedMethods && !methods.GetAdminInvoiceSwapQuotes) throw new Error('method: GetAdminInvoiceSwapQuotes is not implemented')
app.post('/api/admin/swap/invoice/quote', async (req, res) => {
const info: Types.RequestInfo = { rpcName: 'GetAdminInvoiceSwapQuotes', batch: false, nostr: false, batchSize: 0}
const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
let authCtx: Types.AuthContext = {}
try {
if (!methods.GetAdminInvoiceSwapQuotes) throw new Error('method: GetAdminInvoiceSwapQuotes is not implemented')
const authContext = await opts.AdminAuthGuard(req.headers['authorization'])
authCtx = authContext
stats.guard = process.hrtime.bigint()
const request = req.body
const error = Types.InvoiceSwapRequestValidate(request)
stats.validate = process.hrtime.bigint()
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)
const query = req.query
const params = req.params
const response = await methods.GetAdminInvoiceSwapQuotes({rpcName:'GetAdminInvoiceSwapQuotes', ctx:authContext , req: request})
stats.handle = process.hrtime.bigint()
res.json({status: 'OK', ...response})
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
})
if (!opts.allowNotImplementedMethods && !methods.GetAdminTransactionSwapQuotes) throw new Error('method: GetAdminTransactionSwapQuotes is not implemented') if (!opts.allowNotImplementedMethods && !methods.GetAdminTransactionSwapQuotes) throw new Error('method: GetAdminTransactionSwapQuotes is not implemented')
app.post('/api/admin/swap/transaction/quote', async (req, res) => { app.post('/api/admin/swap/transaction/quote', async (req, res) => {
const info: Types.RequestInfo = { rpcName: 'GetAdminTransactionSwapQuotes', batch: false, nostr: false, batchSize: 0} const info: Types.RequestInfo = { rpcName: 'GetAdminTransactionSwapQuotes', batch: false, nostr: false, batchSize: 0}
@ -1362,7 +1384,7 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
}) })
if (!opts.allowNotImplementedMethods && !methods.GetTransactionSwapQuotes) throw new Error('method: GetTransactionSwapQuotes is not implemented') if (!opts.allowNotImplementedMethods && !methods.GetTransactionSwapQuotes) throw new Error('method: GetTransactionSwapQuotes is not implemented')
app.post('/api/user/swap/quote', async (req, res) => { app.post('/api/user/swap/transaction/quote', async (req, res) => {
const info: Types.RequestInfo = { rpcName: 'GetTransactionSwapQuotes', batch: false, nostr: false, batchSize: 0} const info: Types.RequestInfo = { rpcName: 'GetTransactionSwapQuotes', batch: false, nostr: false, batchSize: 0}
const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
let authCtx: Types.AuthContext = {} let authCtx: Types.AuthContext = {}
@ -1607,20 +1629,39 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
opts.metricsCallback([{ ...info, ...stats, ...authContext }]) opts.metricsCallback([{ ...info, ...stats, ...authContext }])
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
}) })
if (!opts.allowNotImplementedMethods && !methods.ListAdminSwaps) throw new Error('method: ListAdminSwaps is not implemented') if (!opts.allowNotImplementedMethods && !methods.ListAdminInvoiceSwaps) throw new Error('method: ListAdminInvoiceSwaps is not implemented')
app.post('/api/admin/swap/list', async (req, res) => { app.post('/api/admin/swap/invoice/list', async (req, res) => {
const info: Types.RequestInfo = { rpcName: 'ListAdminSwaps', batch: false, nostr: false, batchSize: 0} const info: Types.RequestInfo = { rpcName: 'ListAdminInvoiceSwaps', batch: false, nostr: false, batchSize: 0}
const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
let authCtx: Types.AuthContext = {} let authCtx: Types.AuthContext = {}
try { try {
if (!methods.ListAdminSwaps) throw new Error('method: ListAdminSwaps is not implemented') if (!methods.ListAdminInvoiceSwaps) throw new Error('method: ListAdminInvoiceSwaps is not implemented')
const authContext = await opts.AdminAuthGuard(req.headers['authorization']) const authContext = await opts.AdminAuthGuard(req.headers['authorization'])
authCtx = authContext authCtx = authContext
stats.guard = process.hrtime.bigint() stats.guard = process.hrtime.bigint()
stats.validate = stats.guard stats.validate = stats.guard
const query = req.query const query = req.query
const params = req.params const params = req.params
const response = await methods.ListAdminSwaps({rpcName:'ListAdminSwaps', ctx:authContext }) const response = await methods.ListAdminInvoiceSwaps({rpcName:'ListAdminInvoiceSwaps', ctx:authContext })
stats.handle = process.hrtime.bigint()
res.json({status: 'OK', ...response})
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
})
if (!opts.allowNotImplementedMethods && !methods.ListAdminTxSwaps) throw new Error('method: ListAdminTxSwaps is not implemented')
app.post('/api/admin/swap/transaction/list', async (req, res) => {
const info: Types.RequestInfo = { rpcName: 'ListAdminTxSwaps', batch: false, nostr: false, batchSize: 0}
const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
let authCtx: Types.AuthContext = {}
try {
if (!methods.ListAdminTxSwaps) throw new Error('method: ListAdminTxSwaps is not implemented')
const authContext = await opts.AdminAuthGuard(req.headers['authorization'])
authCtx = authContext
stats.guard = process.hrtime.bigint()
stats.validate = stats.guard
const query = req.query
const params = req.params
const response = await methods.ListAdminTxSwaps({rpcName:'ListAdminTxSwaps', ctx:authContext })
stats.handle = process.hrtime.bigint() stats.handle = process.hrtime.bigint()
res.json({status: 'OK', ...response}) res.json({status: 'OK', ...response})
opts.metricsCallback([{ ...info, ...stats, ...authContext }]) opts.metricsCallback([{ ...info, ...stats, ...authContext }])
@ -1645,20 +1686,20 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
opts.metricsCallback([{ ...info, ...stats, ...authContext }]) opts.metricsCallback([{ ...info, ...stats, ...authContext }])
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
}) })
if (!opts.allowNotImplementedMethods && !methods.ListSwaps) throw new Error('method: ListSwaps is not implemented') if (!opts.allowNotImplementedMethods && !methods.ListTxSwaps) throw new Error('method: ListTxSwaps is not implemented')
app.post('/api/user/swap/list', async (req, res) => { app.post('/api/user/swap/transaction/list', async (req, res) => {
const info: Types.RequestInfo = { rpcName: 'ListSwaps', batch: false, nostr: false, batchSize: 0} const info: Types.RequestInfo = { rpcName: 'ListTxSwaps', batch: false, nostr: false, batchSize: 0}
const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
let authCtx: Types.AuthContext = {} let authCtx: Types.AuthContext = {}
try { try {
if (!methods.ListSwaps) throw new Error('method: ListSwaps is not implemented') if (!methods.ListTxSwaps) throw new Error('method: ListTxSwaps is not implemented')
const authContext = await opts.UserAuthGuard(req.headers['authorization']) const authContext = await opts.UserAuthGuard(req.headers['authorization'])
authCtx = authContext authCtx = authContext
stats.guard = process.hrtime.bigint() stats.guard = process.hrtime.bigint()
stats.validate = stats.guard stats.validate = stats.guard
const query = req.query const query = req.query
const params = req.params const params = req.params
const response = await methods.ListSwaps({rpcName:'ListSwaps', ctx:authContext }) const response = await methods.ListTxSwaps({rpcName:'ListTxSwaps', ctx:authContext })
stats.handle = process.hrtime.bigint() stats.handle = process.hrtime.bigint()
res.json({status: 'OK', ...response}) res.json({status: 'OK', ...response})
opts.metricsCallback([{ ...info, ...stats, ...authContext }]) opts.metricsCallback([{ ...info, ...stats, ...authContext }])
@ -1793,6 +1834,28 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
opts.metricsCallback([{ ...info, ...stats, ...authContext }]) opts.metricsCallback([{ ...info, ...stats, ...authContext }])
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
}) })
if (!opts.allowNotImplementedMethods && !methods.PayAdminInvoiceSwap) throw new Error('method: PayAdminInvoiceSwap is not implemented')
app.post('/api/admin/swap/invoice/pay', async (req, res) => {
const info: Types.RequestInfo = { rpcName: 'PayAdminInvoiceSwap', batch: false, nostr: false, batchSize: 0}
const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
let authCtx: Types.AuthContext = {}
try {
if (!methods.PayAdminInvoiceSwap) throw new Error('method: PayAdminInvoiceSwap is not implemented')
const authContext = await opts.AdminAuthGuard(req.headers['authorization'])
authCtx = authContext
stats.guard = process.hrtime.bigint()
const request = req.body
const error = Types.PayAdminInvoiceSwapRequestValidate(request)
stats.validate = process.hrtime.bigint()
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)
const query = req.query
const params = req.params
const response = await methods.PayAdminInvoiceSwap({rpcName:'PayAdminInvoiceSwap', ctx:authContext , req: request})
stats.handle = process.hrtime.bigint()
res.json({status: 'OK', ...response})
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
})
if (!opts.allowNotImplementedMethods && !methods.PayAdminTransactionSwap) throw new Error('method: PayAdminTransactionSwap is not implemented') if (!opts.allowNotImplementedMethods && !methods.PayAdminTransactionSwap) throw new Error('method: PayAdminTransactionSwap is not implemented')
app.post('/api/admin/swap/transaction/pay', async (req, res) => { app.post('/api/admin/swap/transaction/pay', async (req, res) => {
const info: Types.RequestInfo = { rpcName: 'PayAdminTransactionSwap', batch: false, nostr: false, batchSize: 0} const info: Types.RequestInfo = { rpcName: 'PayAdminTransactionSwap', batch: false, nostr: false, batchSize: 0}

View file

@ -273,6 +273,20 @@ export default (params: ClientParams) => ({
} }
return { status: 'ERROR', reason: 'invalid response' } return { status: 'ERROR', reason: 'invalid response' }
}, },
GetAdminInvoiceSwapQuotes: async (request: Types.InvoiceSwapRequest): Promise<ResultError | ({ status: 'OK' }& Types.InvoiceSwapQuoteList)> => {
const auth = await params.retrieveAdminAuth()
if (auth === null) throw new Error('retrieveAdminAuth() returned null')
let finalRoute = '/api/admin/swap/invoice/quote'
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
if (data.status === 'OK') {
const result = data
if(!params.checkResult) return { status: 'OK', ...result }
const error = Types.InvoiceSwapQuoteListValidate(result)
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
}
return { status: 'ERROR', reason: 'invalid response' }
},
GetAdminTransactionSwapQuotes: async (request: Types.TransactionSwapRequest): Promise<ResultError | ({ status: 'OK' }& Types.TransactionSwapQuoteList)> => { GetAdminTransactionSwapQuotes: async (request: Types.TransactionSwapRequest): Promise<ResultError | ({ status: 'OK' }& Types.TransactionSwapQuoteList)> => {
const auth = await params.retrieveAdminAuth() const auth = await params.retrieveAdminAuth()
if (auth === null) throw new Error('retrieveAdminAuth() returned null') if (auth === null) throw new Error('retrieveAdminAuth() returned null')
@ -620,7 +634,7 @@ export default (params: ClientParams) => ({
GetTransactionSwapQuotes: async (request: Types.TransactionSwapRequest): Promise<ResultError | ({ status: 'OK' }& Types.TransactionSwapQuoteList)> => { GetTransactionSwapQuotes: async (request: Types.TransactionSwapRequest): Promise<ResultError | ({ status: 'OK' }& Types.TransactionSwapQuoteList)> => {
const auth = await params.retrieveUserAuth() const auth = await params.retrieveUserAuth()
if (auth === null) throw new Error('retrieveUserAuth() returned null') if (auth === null) throw new Error('retrieveUserAuth() returned null')
let finalRoute = '/api/user/swap/quote' let finalRoute = '/api/user/swap/transaction/quote'
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
if (data.status === 'ERROR' && typeof data.reason === 'string') return data if (data.status === 'ERROR' && typeof data.reason === 'string') return data
if (data.status === 'OK') { if (data.status === 'OK') {
@ -781,16 +795,30 @@ export default (params: ClientParams) => ({
} }
return { status: 'ERROR', reason: 'invalid response' } return { status: 'ERROR', reason: 'invalid response' }
}, },
ListAdminSwaps: async (): Promise<ResultError | ({ status: 'OK' }& Types.SwapsList)> => { ListAdminInvoiceSwaps: async (): Promise<ResultError | ({ status: 'OK' }& Types.InvoiceSwapsList)> => {
const auth = await params.retrieveAdminAuth() const auth = await params.retrieveAdminAuth()
if (auth === null) throw new Error('retrieveAdminAuth() returned null') if (auth === null) throw new Error('retrieveAdminAuth() returned null')
let finalRoute = '/api/admin/swap/list' let finalRoute = '/api/admin/swap/invoice/list'
const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } }) const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } })
if (data.status === 'ERROR' && typeof data.reason === 'string') return data if (data.status === 'ERROR' && typeof data.reason === 'string') return data
if (data.status === 'OK') { if (data.status === 'OK') {
const result = data const result = data
if(!params.checkResult) return { status: 'OK', ...result } if(!params.checkResult) return { status: 'OK', ...result }
const error = Types.SwapsListValidate(result) const error = Types.InvoiceSwapsListValidate(result)
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
}
return { status: 'ERROR', reason: 'invalid response' }
},
ListAdminTxSwaps: async (): Promise<ResultError | ({ status: 'OK' }& Types.TxSwapsList)> => {
const auth = await params.retrieveAdminAuth()
if (auth === null) throw new Error('retrieveAdminAuth() returned null')
let finalRoute = '/api/admin/swap/transaction/list'
const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } })
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
if (data.status === 'OK') {
const result = data
if(!params.checkResult) return { status: 'OK', ...result }
const error = Types.TxSwapsListValidate(result)
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
} }
return { status: 'ERROR', reason: 'invalid response' } return { status: 'ERROR', reason: 'invalid response' }
@ -809,16 +837,16 @@ export default (params: ClientParams) => ({
} }
return { status: 'ERROR', reason: 'invalid response' } return { status: 'ERROR', reason: 'invalid response' }
}, },
ListSwaps: async (): Promise<ResultError | ({ status: 'OK' }& Types.SwapsList)> => { ListTxSwaps: async (): Promise<ResultError | ({ status: 'OK' }& Types.TxSwapsList)> => {
const auth = await params.retrieveUserAuth() const auth = await params.retrieveUserAuth()
if (auth === null) throw new Error('retrieveUserAuth() returned null') if (auth === null) throw new Error('retrieveUserAuth() returned null')
let finalRoute = '/api/user/swap/list' let finalRoute = '/api/user/swap/transaction/list'
const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } }) const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } })
if (data.status === 'ERROR' && typeof data.reason === 'string') return data if (data.status === 'ERROR' && typeof data.reason === 'string') return data
if (data.status === 'OK') { if (data.status === 'OK') {
const result = data const result = data
if(!params.checkResult) return { status: 'OK', ...result } if(!params.checkResult) return { status: 'OK', ...result }
const error = Types.SwapsListValidate(result) const error = Types.TxSwapsListValidate(result)
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
} }
return { status: 'ERROR', reason: 'invalid response' } return { status: 'ERROR', reason: 'invalid response' }
@ -909,7 +937,21 @@ export default (params: ClientParams) => ({
} }
return { status: 'ERROR', reason: 'invalid response' } return { status: 'ERROR', reason: 'invalid response' }
}, },
PayAdminTransactionSwap: async (request: Types.PayAdminTransactionSwapRequest): Promise<ResultError | ({ status: 'OK' }& Types.AdminSwapResponse)> => { PayAdminInvoiceSwap: async (request: Types.PayAdminInvoiceSwapRequest): Promise<ResultError | ({ status: 'OK' }& Types.AdminInvoiceSwapResponse)> => {
const auth = await params.retrieveAdminAuth()
if (auth === null) throw new Error('retrieveAdminAuth() returned null')
let finalRoute = '/api/admin/swap/invoice/pay'
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
if (data.status === 'OK') {
const result = data
if(!params.checkResult) return { status: 'OK', ...result }
const error = Types.AdminInvoiceSwapResponseValidate(result)
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
}
return { status: 'ERROR', reason: 'invalid response' }
},
PayAdminTransactionSwap: async (request: Types.PayAdminTransactionSwapRequest): Promise<ResultError | ({ status: 'OK' }& Types.AdminTxSwapResponse)> => {
const auth = await params.retrieveAdminAuth() const auth = await params.retrieveAdminAuth()
if (auth === null) throw new Error('retrieveAdminAuth() returned null') if (auth === null) throw new Error('retrieveAdminAuth() returned null')
let finalRoute = '/api/admin/swap/transaction/pay' let finalRoute = '/api/admin/swap/transaction/pay'
@ -918,7 +960,7 @@ export default (params: ClientParams) => ({
if (data.status === 'OK') { if (data.status === 'OK') {
const result = data const result = data
if(!params.checkResult) return { status: 'OK', ...result } if(!params.checkResult) return { status: 'OK', ...result }
const error = Types.AdminSwapResponseValidate(result) const error = Types.AdminTxSwapResponseValidate(result)
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
} }
return { status: 'ERROR', reason: 'invalid response' } return { status: 'ERROR', reason: 'invalid response' }

View file

@ -230,6 +230,21 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
} }
return { status: 'ERROR', reason: 'invalid response' } return { status: 'ERROR', reason: 'invalid response' }
}, },
GetAdminInvoiceSwapQuotes: async (request: Types.InvoiceSwapRequest): Promise<ResultError | ({ status: 'OK' }& Types.InvoiceSwapQuoteList)> => {
const auth = await params.retrieveNostrAdminAuth()
if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null')
const nostrRequest: NostrRequest = {}
nostrRequest.body = request
const data = await send(params.pubDestination, {rpcName:'GetAdminInvoiceSwapQuotes',authIdentifier:auth, ...nostrRequest })
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
if (data.status === 'OK') {
const result = data
if(!params.checkResult) return { status: 'OK', ...result }
const error = Types.InvoiceSwapQuoteListValidate(result)
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
}
return { status: 'ERROR', reason: 'invalid response' }
},
GetAdminTransactionSwapQuotes: async (request: Types.TransactionSwapRequest): Promise<ResultError | ({ status: 'OK' }& Types.TransactionSwapQuoteList)> => { GetAdminTransactionSwapQuotes: async (request: Types.TransactionSwapRequest): Promise<ResultError | ({ status: 'OK' }& Types.TransactionSwapQuoteList)> => {
const auth = await params.retrieveNostrAdminAuth() const auth = await params.retrieveNostrAdminAuth()
if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null') if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null')
@ -666,16 +681,30 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
} }
return { status: 'ERROR', reason: 'invalid response' } return { status: 'ERROR', reason: 'invalid response' }
}, },
ListAdminSwaps: async (): Promise<ResultError | ({ status: 'OK' }& Types.SwapsList)> => { ListAdminInvoiceSwaps: async (): Promise<ResultError | ({ status: 'OK' }& Types.InvoiceSwapsList)> => {
const auth = await params.retrieveNostrAdminAuth() const auth = await params.retrieveNostrAdminAuth()
if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null') if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null')
const nostrRequest: NostrRequest = {} const nostrRequest: NostrRequest = {}
const data = await send(params.pubDestination, {rpcName:'ListAdminSwaps',authIdentifier:auth, ...nostrRequest }) const data = await send(params.pubDestination, {rpcName:'ListAdminInvoiceSwaps',authIdentifier:auth, ...nostrRequest })
if (data.status === 'ERROR' && typeof data.reason === 'string') return data if (data.status === 'ERROR' && typeof data.reason === 'string') return data
if (data.status === 'OK') { if (data.status === 'OK') {
const result = data const result = data
if(!params.checkResult) return { status: 'OK', ...result } if(!params.checkResult) return { status: 'OK', ...result }
const error = Types.SwapsListValidate(result) const error = Types.InvoiceSwapsListValidate(result)
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
}
return { status: 'ERROR', reason: 'invalid response' }
},
ListAdminTxSwaps: async (): Promise<ResultError | ({ status: 'OK' }& Types.TxSwapsList)> => {
const auth = await params.retrieveNostrAdminAuth()
if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null')
const nostrRequest: NostrRequest = {}
const data = await send(params.pubDestination, {rpcName:'ListAdminTxSwaps',authIdentifier:auth, ...nostrRequest })
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
if (data.status === 'OK') {
const result = data
if(!params.checkResult) return { status: 'OK', ...result }
const error = Types.TxSwapsListValidate(result)
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
} }
return { status: 'ERROR', reason: 'invalid response' } return { status: 'ERROR', reason: 'invalid response' }
@ -694,16 +723,16 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
} }
return { status: 'ERROR', reason: 'invalid response' } return { status: 'ERROR', reason: 'invalid response' }
}, },
ListSwaps: async (): Promise<ResultError | ({ status: 'OK' }& Types.SwapsList)> => { ListTxSwaps: async (): Promise<ResultError | ({ status: 'OK' }& Types.TxSwapsList)> => {
const auth = await params.retrieveNostrUserAuth() const auth = await params.retrieveNostrUserAuth()
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
const nostrRequest: NostrRequest = {} const nostrRequest: NostrRequest = {}
const data = await send(params.pubDestination, {rpcName:'ListSwaps',authIdentifier:auth, ...nostrRequest }) const data = await send(params.pubDestination, {rpcName:'ListTxSwaps',authIdentifier:auth, ...nostrRequest })
if (data.status === 'ERROR' && typeof data.reason === 'string') return data if (data.status === 'ERROR' && typeof data.reason === 'string') return data
if (data.status === 'OK') { if (data.status === 'OK') {
const result = data const result = data
if(!params.checkResult) return { status: 'OK', ...result } if(!params.checkResult) return { status: 'OK', ...result }
const error = Types.SwapsListValidate(result) const error = Types.TxSwapsListValidate(result)
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
} }
return { status: 'ERROR', reason: 'invalid response' } return { status: 'ERROR', reason: 'invalid response' }
@ -798,7 +827,22 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
} }
return { status: 'ERROR', reason: 'invalid response' } return { status: 'ERROR', reason: 'invalid response' }
}, },
PayAdminTransactionSwap: async (request: Types.PayAdminTransactionSwapRequest): Promise<ResultError | ({ status: 'OK' }& Types.AdminSwapResponse)> => { PayAdminInvoiceSwap: async (request: Types.PayAdminInvoiceSwapRequest): Promise<ResultError | ({ status: 'OK' }& Types.AdminInvoiceSwapResponse)> => {
const auth = await params.retrieveNostrAdminAuth()
if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null')
const nostrRequest: NostrRequest = {}
nostrRequest.body = request
const data = await send(params.pubDestination, {rpcName:'PayAdminInvoiceSwap',authIdentifier:auth, ...nostrRequest })
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
if (data.status === 'OK') {
const result = data
if(!params.checkResult) return { status: 'OK', ...result }
const error = Types.AdminInvoiceSwapResponseValidate(result)
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
}
return { status: 'ERROR', reason: 'invalid response' }
},
PayAdminTransactionSwap: async (request: Types.PayAdminTransactionSwapRequest): Promise<ResultError | ({ status: 'OK' }& Types.AdminTxSwapResponse)> => {
const auth = await params.retrieveNostrAdminAuth() const auth = await params.retrieveNostrAdminAuth()
if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null') if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null')
const nostrRequest: NostrRequest = {} const nostrRequest: NostrRequest = {}
@ -808,7 +852,7 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
if (data.status === 'OK') { if (data.status === 'OK') {
const result = data const result = data
if(!params.checkResult) return { status: 'OK', ...result } if(!params.checkResult) return { status: 'OK', ...result }
const error = Types.AdminSwapResponseValidate(result) const error = Types.AdminTxSwapResponseValidate(result)
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
} }
return { status: 'ERROR', reason: 'invalid response' } return { status: 'ERROR', reason: 'invalid response' }

View file

@ -427,12 +427,12 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
} }
break break
case 'ListSwaps': case 'ListTxSwaps':
if (!methods.ListSwaps) { if (!methods.ListTxSwaps) {
throw new Error('method not defined: ListSwaps') throw new Error('method not defined: ListTxSwaps')
} else { } else {
opStats.validate = opStats.guard opStats.validate = opStats.guard
const res = await methods.ListSwaps({...operation, ctx}); responses.push({ status: 'OK', ...res }) const res = await methods.ListTxSwaps({...operation, ctx}); responses.push({ status: 'OK', ...res })
opStats.handle = process.hrtime.bigint() opStats.handle = process.hrtime.bigint()
callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
} }
@ -687,6 +687,22 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
opts.metricsCallback([{ ...info, ...stats, ...authContext }]) opts.metricsCallback([{ ...info, ...stats, ...authContext }])
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
break break
case 'GetAdminInvoiceSwapQuotes':
try {
if (!methods.GetAdminInvoiceSwapQuotes) throw new Error('method: GetAdminInvoiceSwapQuotes is not implemented')
const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier)
stats.guard = process.hrtime.bigint()
authCtx = authContext
const request = req.body
const error = Types.InvoiceSwapRequestValidate(request)
stats.validate = process.hrtime.bigint()
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
const response = await methods.GetAdminInvoiceSwapQuotes({rpcName:'GetAdminInvoiceSwapQuotes', ctx:authContext , req: request})
stats.handle = process.hrtime.bigint()
res({status: 'OK', ...response})
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
break
case 'GetAdminTransactionSwapQuotes': case 'GetAdminTransactionSwapQuotes':
try { try {
if (!methods.GetAdminTransactionSwapQuotes) throw new Error('method: GetAdminTransactionSwapQuotes is not implemented') if (!methods.GetAdminTransactionSwapQuotes) throw new Error('method: GetAdminTransactionSwapQuotes is not implemented')
@ -1122,14 +1138,27 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
opts.metricsCallback([{ ...info, ...stats, ...authContext }]) opts.metricsCallback([{ ...info, ...stats, ...authContext }])
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
break break
case 'ListAdminSwaps': case 'ListAdminInvoiceSwaps':
try { try {
if (!methods.ListAdminSwaps) throw new Error('method: ListAdminSwaps is not implemented') if (!methods.ListAdminInvoiceSwaps) throw new Error('method: ListAdminInvoiceSwaps is not implemented')
const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier) const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier)
stats.guard = process.hrtime.bigint() stats.guard = process.hrtime.bigint()
authCtx = authContext authCtx = authContext
stats.validate = stats.guard stats.validate = stats.guard
const response = await methods.ListAdminSwaps({rpcName:'ListAdminSwaps', ctx:authContext }) const response = await methods.ListAdminInvoiceSwaps({rpcName:'ListAdminInvoiceSwaps', ctx:authContext })
stats.handle = process.hrtime.bigint()
res({status: 'OK', ...response})
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
break
case 'ListAdminTxSwaps':
try {
if (!methods.ListAdminTxSwaps) throw new Error('method: ListAdminTxSwaps is not implemented')
const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier)
stats.guard = process.hrtime.bigint()
authCtx = authContext
stats.validate = stats.guard
const response = await methods.ListAdminTxSwaps({rpcName:'ListAdminTxSwaps', ctx:authContext })
stats.handle = process.hrtime.bigint() stats.handle = process.hrtime.bigint()
res({status: 'OK', ...response}) res({status: 'OK', ...response})
opts.metricsCallback([{ ...info, ...stats, ...authContext }]) opts.metricsCallback([{ ...info, ...stats, ...authContext }])
@ -1148,14 +1177,14 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
opts.metricsCallback([{ ...info, ...stats, ...authContext }]) opts.metricsCallback([{ ...info, ...stats, ...authContext }])
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
break break
case 'ListSwaps': case 'ListTxSwaps':
try { try {
if (!methods.ListSwaps) throw new Error('method: ListSwaps is not implemented') if (!methods.ListTxSwaps) throw new Error('method: ListTxSwaps is not implemented')
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
stats.guard = process.hrtime.bigint() stats.guard = process.hrtime.bigint()
authCtx = authContext authCtx = authContext
stats.validate = stats.guard stats.validate = stats.guard
const response = await methods.ListSwaps({rpcName:'ListSwaps', ctx:authContext }) const response = await methods.ListTxSwaps({rpcName:'ListTxSwaps', ctx:authContext })
stats.handle = process.hrtime.bigint() stats.handle = process.hrtime.bigint()
res({status: 'OK', ...response}) res({status: 'OK', ...response})
opts.metricsCallback([{ ...info, ...stats, ...authContext }]) opts.metricsCallback([{ ...info, ...stats, ...authContext }])
@ -1254,6 +1283,22 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
opts.metricsCallback([{ ...info, ...stats, ...authContext }]) opts.metricsCallback([{ ...info, ...stats, ...authContext }])
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
break break
case 'PayAdminInvoiceSwap':
try {
if (!methods.PayAdminInvoiceSwap) throw new Error('method: PayAdminInvoiceSwap is not implemented')
const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier)
stats.guard = process.hrtime.bigint()
authCtx = authContext
const request = req.body
const error = Types.PayAdminInvoiceSwapRequestValidate(request)
stats.validate = process.hrtime.bigint()
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
const response = await methods.PayAdminInvoiceSwap({rpcName:'PayAdminInvoiceSwap', ctx:authContext , req: request})
stats.handle = process.hrtime.bigint()
res({status: 'OK', ...response})
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
break
case 'PayAdminTransactionSwap': case 'PayAdminTransactionSwap':
try { try {
if (!methods.PayAdminTransactionSwap) throw new Error('method: PayAdminTransactionSwap is not implemented') if (!methods.PayAdminTransactionSwap) throw new Error('method: PayAdminTransactionSwap is not implemented')

View file

@ -7,8 +7,8 @@ export type RequestMetric = AuthContext & RequestInfo & RequestStats & { error?:
export type AdminContext = { export type AdminContext = {
admin_id: string admin_id: string
} }
export type AdminMethodInputs = AddApp_Input | AddPeer_Input | AuthApp_Input | BanUser_Input | CloseChannel_Input | CreateOneTimeInviteLink_Input | GetAdminTransactionSwapQuotes_Input | GetInviteLinkState_Input | GetSeed_Input | ListAdminSwaps_Input | ListChannels_Input | LndGetInfo_Input | OpenChannel_Input | PayAdminTransactionSwap_Input | UpdateChannelPolicy_Input export type AdminMethodInputs = AddApp_Input | AddPeer_Input | AuthApp_Input | BanUser_Input | CloseChannel_Input | CreateOneTimeInviteLink_Input | GetAdminInvoiceSwapQuotes_Input | GetAdminTransactionSwapQuotes_Input | GetInviteLinkState_Input | GetSeed_Input | ListAdminInvoiceSwaps_Input | ListAdminTxSwaps_Input | ListChannels_Input | LndGetInfo_Input | OpenChannel_Input | PayAdminInvoiceSwap_Input | PayAdminTransactionSwap_Input | UpdateChannelPolicy_Input
export type AdminMethodOutputs = AddApp_Output | AddPeer_Output | AuthApp_Output | BanUser_Output | CloseChannel_Output | CreateOneTimeInviteLink_Output | GetAdminTransactionSwapQuotes_Output | GetInviteLinkState_Output | GetSeed_Output | ListAdminSwaps_Output | ListChannels_Output | LndGetInfo_Output | OpenChannel_Output | PayAdminTransactionSwap_Output | UpdateChannelPolicy_Output export type AdminMethodOutputs = AddApp_Output | AddPeer_Output | AuthApp_Output | BanUser_Output | CloseChannel_Output | CreateOneTimeInviteLink_Output | GetAdminInvoiceSwapQuotes_Output | GetAdminTransactionSwapQuotes_Output | GetInviteLinkState_Output | GetSeed_Output | ListAdminInvoiceSwaps_Output | ListAdminTxSwaps_Output | ListChannels_Output | LndGetInfo_Output | OpenChannel_Output | PayAdminInvoiceSwap_Output | PayAdminTransactionSwap_Output | UpdateChannelPolicy_Output
export type AppContext = { export type AppContext = {
app_id: string app_id: string
} }
@ -35,8 +35,8 @@ export type UserContext = {
app_user_id: string app_user_id: string
user_id: string user_id: string
} }
export type UserMethodInputs = AddProduct_Input | AddUserOffer_Input | AuthorizeManage_Input | BanDebit_Input | DecodeInvoice_Input | DeleteUserOffer_Input | EditDebit_Input | EnrollAdminToken_Input | EnrollMessagingToken_Input | GetDebitAuthorizations_Input | GetHttpCreds_Input | GetLNURLChannelLink_Input | GetLnurlPayLink_Input | GetLnurlWithdrawLink_Input | GetManageAuthorizations_Input | GetPaymentState_Input | GetTransactionSwapQuotes_Input | GetUserInfo_Input | GetUserOffer_Input | GetUserOfferInvoices_Input | GetUserOffers_Input | GetUserOperations_Input | ListSwaps_Input | NewAddress_Input | NewInvoice_Input | NewProductInvoice_Input | PayAddress_Input | PayInvoice_Input | ResetDebit_Input | ResetManage_Input | RespondToDebit_Input | UpdateCallbackUrl_Input | UpdateUserOffer_Input | UserHealth_Input export type UserMethodInputs = AddProduct_Input | AddUserOffer_Input | AuthorizeManage_Input | BanDebit_Input | DecodeInvoice_Input | DeleteUserOffer_Input | EditDebit_Input | EnrollAdminToken_Input | EnrollMessagingToken_Input | GetDebitAuthorizations_Input | GetHttpCreds_Input | GetLNURLChannelLink_Input | GetLnurlPayLink_Input | GetLnurlWithdrawLink_Input | GetManageAuthorizations_Input | GetPaymentState_Input | GetTransactionSwapQuotes_Input | GetUserInfo_Input | GetUserOffer_Input | GetUserOfferInvoices_Input | GetUserOffers_Input | GetUserOperations_Input | ListTxSwaps_Input | NewAddress_Input | NewInvoice_Input | NewProductInvoice_Input | PayAddress_Input | PayInvoice_Input | ResetDebit_Input | ResetManage_Input | RespondToDebit_Input | UpdateCallbackUrl_Input | UpdateUserOffer_Input | UserHealth_Input
export type UserMethodOutputs = AddProduct_Output | AddUserOffer_Output | AuthorizeManage_Output | BanDebit_Output | DecodeInvoice_Output | DeleteUserOffer_Output | EditDebit_Output | EnrollAdminToken_Output | EnrollMessagingToken_Output | GetDebitAuthorizations_Output | GetHttpCreds_Output | GetLNURLChannelLink_Output | GetLnurlPayLink_Output | GetLnurlWithdrawLink_Output | GetManageAuthorizations_Output | GetPaymentState_Output | GetTransactionSwapQuotes_Output | GetUserInfo_Output | GetUserOffer_Output | GetUserOfferInvoices_Output | GetUserOffers_Output | GetUserOperations_Output | ListSwaps_Output | NewAddress_Output | NewInvoice_Output | NewProductInvoice_Output | PayAddress_Output | PayInvoice_Output | ResetDebit_Output | ResetManage_Output | RespondToDebit_Output | UpdateCallbackUrl_Output | UpdateUserOffer_Output | UserHealth_Output export type UserMethodOutputs = AddProduct_Output | AddUserOffer_Output | AuthorizeManage_Output | BanDebit_Output | DecodeInvoice_Output | DeleteUserOffer_Output | EditDebit_Output | EnrollAdminToken_Output | EnrollMessagingToken_Output | GetDebitAuthorizations_Output | GetHttpCreds_Output | GetLNURLChannelLink_Output | GetLnurlPayLink_Output | GetLnurlWithdrawLink_Output | GetManageAuthorizations_Output | GetPaymentState_Output | GetTransactionSwapQuotes_Output | GetUserInfo_Output | GetUserOffer_Output | GetUserOfferInvoices_Output | GetUserOffers_Output | GetUserOperations_Output | ListTxSwaps_Output | NewAddress_Output | NewInvoice_Output | NewProductInvoice_Output | PayAddress_Output | PayInvoice_Output | ResetDebit_Output | ResetManage_Output | RespondToDebit_Output | UpdateCallbackUrl_Output | UpdateUserOffer_Output | UserHealth_Output
export type AuthContext = AdminContext | AppContext | GuestContext | GuestWithPubContext | MetricsContext | UserContext export type AuthContext = AdminContext | AppContext | GuestContext | GuestWithPubContext | MetricsContext | UserContext
export type AddApp_Input = {rpcName:'AddApp', req: AddAppRequest} export type AddApp_Input = {rpcName:'AddApp', req: AddAppRequest}
@ -99,6 +99,9 @@ export type EnrollAdminToken_Output = ResultError | { status: 'OK' }
export type EnrollMessagingToken_Input = {rpcName:'EnrollMessagingToken', req: MessagingToken} export type EnrollMessagingToken_Input = {rpcName:'EnrollMessagingToken', req: MessagingToken}
export type EnrollMessagingToken_Output = ResultError | { status: 'OK' } export type EnrollMessagingToken_Output = ResultError | { status: 'OK' }
export type GetAdminInvoiceSwapQuotes_Input = {rpcName:'GetAdminInvoiceSwapQuotes', req: InvoiceSwapRequest}
export type GetAdminInvoiceSwapQuotes_Output = ResultError | ({ status: 'OK' } & InvoiceSwapQuoteList)
export type GetAdminTransactionSwapQuotes_Input = {rpcName:'GetAdminTransactionSwapQuotes', req: TransactionSwapRequest} export type GetAdminTransactionSwapQuotes_Input = {rpcName:'GetAdminTransactionSwapQuotes', req: TransactionSwapRequest}
export type GetAdminTransactionSwapQuotes_Output = ResultError | ({ status: 'OK' } & TransactionSwapQuoteList) export type GetAdminTransactionSwapQuotes_Output = ResultError | ({ status: 'OK' } & TransactionSwapQuoteList)
@ -238,14 +241,17 @@ export type Health_Output = ResultError | { status: 'OK' }
export type LinkNPubThroughToken_Input = {rpcName:'LinkNPubThroughToken', req: LinkNPubThroughTokenRequest} export type LinkNPubThroughToken_Input = {rpcName:'LinkNPubThroughToken', req: LinkNPubThroughTokenRequest}
export type LinkNPubThroughToken_Output = ResultError | { status: 'OK' } export type LinkNPubThroughToken_Output = ResultError | { status: 'OK' }
export type ListAdminSwaps_Input = {rpcName:'ListAdminSwaps'} export type ListAdminInvoiceSwaps_Input = {rpcName:'ListAdminInvoiceSwaps'}
export type ListAdminSwaps_Output = ResultError | ({ status: 'OK' } & SwapsList) export type ListAdminInvoiceSwaps_Output = ResultError | ({ status: 'OK' } & InvoiceSwapsList)
export type ListAdminTxSwaps_Input = {rpcName:'ListAdminTxSwaps'}
export type ListAdminTxSwaps_Output = ResultError | ({ status: 'OK' } & TxSwapsList)
export type ListChannels_Input = {rpcName:'ListChannels'} export type ListChannels_Input = {rpcName:'ListChannels'}
export type ListChannels_Output = ResultError | ({ status: 'OK' } & LndChannels) export type ListChannels_Output = ResultError | ({ status: 'OK' } & LndChannels)
export type ListSwaps_Input = {rpcName:'ListSwaps'} export type ListTxSwaps_Input = {rpcName:'ListTxSwaps'}
export type ListSwaps_Output = ResultError | ({ status: 'OK' } & SwapsList) export type ListTxSwaps_Output = ResultError | ({ status: 'OK' } & TxSwapsList)
export type LndGetInfo_Input = {rpcName:'LndGetInfo', req: LndGetInfoRequest} export type LndGetInfo_Input = {rpcName:'LndGetInfo', req: LndGetInfoRequest}
export type LndGetInfo_Output = ResultError | ({ status: 'OK' } & LndGetInfoResponse) export type LndGetInfo_Output = ResultError | ({ status: 'OK' } & LndGetInfoResponse)
@ -268,8 +274,11 @@ export type OpenChannel_Output = ResultError | ({ status: 'OK' } & OpenChannelRe
export type PayAddress_Input = {rpcName:'PayAddress', req: PayAddressRequest} export type PayAddress_Input = {rpcName:'PayAddress', req: PayAddressRequest}
export type PayAddress_Output = ResultError | ({ status: 'OK' } & PayAddressResponse) export type PayAddress_Output = ResultError | ({ status: 'OK' } & PayAddressResponse)
export type PayAdminInvoiceSwap_Input = {rpcName:'PayAdminInvoiceSwap', req: PayAdminInvoiceSwapRequest}
export type PayAdminInvoiceSwap_Output = ResultError | ({ status: 'OK' } & AdminInvoiceSwapResponse)
export type PayAdminTransactionSwap_Input = {rpcName:'PayAdminTransactionSwap', req: PayAdminTransactionSwapRequest} export type PayAdminTransactionSwap_Input = {rpcName:'PayAdminTransactionSwap', req: PayAdminTransactionSwapRequest}
export type PayAdminTransactionSwap_Output = ResultError | ({ status: 'OK' } & AdminSwapResponse) export type PayAdminTransactionSwap_Output = ResultError | ({ status: 'OK' } & AdminTxSwapResponse)
export type PayAppUserInvoice_Input = {rpcName:'PayAppUserInvoice', req: PayAppUserInvoiceRequest} export type PayAppUserInvoice_Input = {rpcName:'PayAppUserInvoice', req: PayAppUserInvoiceRequest}
export type PayAppUserInvoice_Output = ResultError | ({ status: 'OK' } & PayInvoiceResponse) export type PayAppUserInvoice_Output = ResultError | ({ status: 'OK' } & PayInvoiceResponse)
@ -357,6 +366,7 @@ export type ServerMethods = {
EncryptionExchange?: (req: EncryptionExchange_Input & {ctx: GuestContext }) => Promise<void> EncryptionExchange?: (req: EncryptionExchange_Input & {ctx: GuestContext }) => Promise<void>
EnrollAdminToken?: (req: EnrollAdminToken_Input & {ctx: UserContext }) => Promise<void> EnrollAdminToken?: (req: EnrollAdminToken_Input & {ctx: UserContext }) => Promise<void>
EnrollMessagingToken?: (req: EnrollMessagingToken_Input & {ctx: UserContext }) => Promise<void> EnrollMessagingToken?: (req: EnrollMessagingToken_Input & {ctx: UserContext }) => Promise<void>
GetAdminInvoiceSwapQuotes?: (req: GetAdminInvoiceSwapQuotes_Input & {ctx: AdminContext }) => Promise<InvoiceSwapQuoteList>
GetAdminTransactionSwapQuotes?: (req: GetAdminTransactionSwapQuotes_Input & {ctx: AdminContext }) => Promise<TransactionSwapQuoteList> GetAdminTransactionSwapQuotes?: (req: GetAdminTransactionSwapQuotes_Input & {ctx: AdminContext }) => Promise<TransactionSwapQuoteList>
GetApp?: (req: GetApp_Input & {ctx: AppContext }) => Promise<Application> GetApp?: (req: GetApp_Input & {ctx: AppContext }) => Promise<Application>
GetAppUser?: (req: GetAppUser_Input & {ctx: AppContext }) => Promise<AppUser> GetAppUser?: (req: GetAppUser_Input & {ctx: AppContext }) => Promise<AppUser>
@ -397,16 +407,18 @@ export type ServerMethods = {
HandleLnurlWithdraw?: (req: HandleLnurlWithdraw_Input & {ctx: GuestContext }) => Promise<void> HandleLnurlWithdraw?: (req: HandleLnurlWithdraw_Input & {ctx: GuestContext }) => Promise<void>
Health?: (req: Health_Input & {ctx: GuestContext }) => Promise<void> Health?: (req: Health_Input & {ctx: GuestContext }) => Promise<void>
LinkNPubThroughToken?: (req: LinkNPubThroughToken_Input & {ctx: GuestWithPubContext }) => Promise<void> LinkNPubThroughToken?: (req: LinkNPubThroughToken_Input & {ctx: GuestWithPubContext }) => Promise<void>
ListAdminSwaps?: (req: ListAdminSwaps_Input & {ctx: AdminContext }) => Promise<SwapsList> ListAdminInvoiceSwaps?: (req: ListAdminInvoiceSwaps_Input & {ctx: AdminContext }) => Promise<InvoiceSwapsList>
ListAdminTxSwaps?: (req: ListAdminTxSwaps_Input & {ctx: AdminContext }) => Promise<TxSwapsList>
ListChannels?: (req: ListChannels_Input & {ctx: AdminContext }) => Promise<LndChannels> ListChannels?: (req: ListChannels_Input & {ctx: AdminContext }) => Promise<LndChannels>
ListSwaps?: (req: ListSwaps_Input & {ctx: UserContext }) => Promise<SwapsList> ListTxSwaps?: (req: ListTxSwaps_Input & {ctx: UserContext }) => Promise<TxSwapsList>
LndGetInfo?: (req: LndGetInfo_Input & {ctx: AdminContext }) => Promise<LndGetInfoResponse> LndGetInfo?: (req: LndGetInfo_Input & {ctx: AdminContext }) => Promise<LndGetInfoResponse>
NewAddress?: (req: NewAddress_Input & {ctx: UserContext }) => Promise<NewAddressResponse> NewAddress?: (req: NewAddress_Input & {ctx: UserContext }) => Promise<NewAddressResponse>
NewInvoice?: (req: NewInvoice_Input & {ctx: UserContext }) => Promise<NewInvoiceResponse> NewInvoice?: (req: NewInvoice_Input & {ctx: UserContext }) => Promise<NewInvoiceResponse>
NewProductInvoice?: (req: NewProductInvoice_Input & {ctx: UserContext }) => Promise<NewInvoiceResponse> NewProductInvoice?: (req: NewProductInvoice_Input & {ctx: UserContext }) => Promise<NewInvoiceResponse>
OpenChannel?: (req: OpenChannel_Input & {ctx: AdminContext }) => Promise<OpenChannelResponse> OpenChannel?: (req: OpenChannel_Input & {ctx: AdminContext }) => Promise<OpenChannelResponse>
PayAddress?: (req: PayAddress_Input & {ctx: UserContext }) => Promise<PayAddressResponse> PayAddress?: (req: PayAddress_Input & {ctx: UserContext }) => Promise<PayAddressResponse>
PayAdminTransactionSwap?: (req: PayAdminTransactionSwap_Input & {ctx: AdminContext }) => Promise<AdminSwapResponse> PayAdminInvoiceSwap?: (req: PayAdminInvoiceSwap_Input & {ctx: AdminContext }) => Promise<AdminInvoiceSwapResponse>
PayAdminTransactionSwap?: (req: PayAdminTransactionSwap_Input & {ctx: AdminContext }) => Promise<AdminTxSwapResponse>
PayAppUserInvoice?: (req: PayAppUserInvoice_Input & {ctx: AppContext }) => Promise<PayInvoiceResponse> PayAppUserInvoice?: (req: PayAppUserInvoice_Input & {ctx: AppContext }) => Promise<PayInvoiceResponse>
PayInvoice?: (req: PayInvoice_Input & {ctx: UserContext }) => Promise<PayInvoiceResponse> PayInvoice?: (req: PayInvoice_Input & {ctx: UserContext }) => Promise<PayInvoiceResponse>
PingSubProcesses?: (req: PingSubProcesses_Input & {ctx: MetricsContext }) => Promise<void> PingSubProcesses?: (req: PingSubProcesses_Input & {ctx: MetricsContext }) => Promise<void>
@ -671,17 +683,35 @@ export const AddProductRequestValidate = (o?: AddProductRequest, opts: AddProduc
return null return null
} }
export type AdminSwapResponse = { export type AdminInvoiceSwapResponse = {
tx_id: string
}
export const AdminInvoiceSwapResponseOptionalFields: [] = []
export type AdminInvoiceSwapResponseOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: []
tx_id_CustomCheck?: (v: string) => boolean
}
export const AdminInvoiceSwapResponseValidate = (o?: AdminInvoiceSwapResponse, opts: AdminInvoiceSwapResponseOptions = {}, path: string = 'AdminInvoiceSwapResponse::root.'): Error | null => {
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
if (typeof o.tx_id !== 'string') return new Error(`${path}.tx_id: is not a string`)
if (opts.tx_id_CustomCheck && !opts.tx_id_CustomCheck(o.tx_id)) return new Error(`${path}.tx_id: custom check failed`)
return null
}
export type AdminTxSwapResponse = {
network_fee: number network_fee: number
tx_id: string tx_id: string
} }
export const AdminSwapResponseOptionalFields: [] = [] export const AdminTxSwapResponseOptionalFields: [] = []
export type AdminSwapResponseOptions = OptionsBaseMessage & { export type AdminTxSwapResponseOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: [] checkOptionalsAreSet?: []
network_fee_CustomCheck?: (v: number) => boolean network_fee_CustomCheck?: (v: number) => boolean
tx_id_CustomCheck?: (v: string) => boolean tx_id_CustomCheck?: (v: string) => boolean
} }
export const AdminSwapResponseValidate = (o?: AdminSwapResponse, opts: AdminSwapResponseOptions = {}, path: string = 'AdminSwapResponse::root.'): Error | null => { export const AdminTxSwapResponseValidate = (o?: AdminTxSwapResponse, opts: AdminTxSwapResponseOptions = {}, path: string = 'AdminTxSwapResponse::root.'): Error | null => {
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
@ -2088,6 +2118,185 @@ export const HttpCredsValidate = (o?: HttpCreds, opts: HttpCredsOptions = {}, pa
return null return null
} }
export type InvoiceSwapOperation = {
failure_reason?: string
invoice_paid: string
operation_payment?: UserOperation
swap_operation_id: string
tx_id: string
}
export type InvoiceSwapOperationOptionalField = 'failure_reason' | 'operation_payment'
export const InvoiceSwapOperationOptionalFields: InvoiceSwapOperationOptionalField[] = ['failure_reason', 'operation_payment']
export type InvoiceSwapOperationOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: InvoiceSwapOperationOptionalField[]
failure_reason_CustomCheck?: (v?: string) => boolean
invoice_paid_CustomCheck?: (v: string) => boolean
operation_payment_Options?: UserOperationOptions
swap_operation_id_CustomCheck?: (v: string) => boolean
tx_id_CustomCheck?: (v: string) => boolean
}
export const InvoiceSwapOperationValidate = (o?: InvoiceSwapOperation, opts: InvoiceSwapOperationOptions = {}, path: string = 'InvoiceSwapOperation::root.'): Error | null => {
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
if ((o.failure_reason || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('failure_reason')) && typeof o.failure_reason !== 'string') return new Error(`${path}.failure_reason: is not a string`)
if (opts.failure_reason_CustomCheck && !opts.failure_reason_CustomCheck(o.failure_reason)) return new Error(`${path}.failure_reason: custom check failed`)
if (typeof o.invoice_paid !== 'string') return new Error(`${path}.invoice_paid: is not a string`)
if (opts.invoice_paid_CustomCheck && !opts.invoice_paid_CustomCheck(o.invoice_paid)) return new Error(`${path}.invoice_paid: custom check failed`)
if (typeof o.operation_payment === 'object' || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('operation_payment')) {
const operation_paymentErr = UserOperationValidate(o.operation_payment, opts.operation_payment_Options, `${path}.operation_payment`)
if (operation_paymentErr !== null) return operation_paymentErr
}
if (typeof o.swap_operation_id !== 'string') return new Error(`${path}.swap_operation_id: is not a string`)
if (opts.swap_operation_id_CustomCheck && !opts.swap_operation_id_CustomCheck(o.swap_operation_id)) return new Error(`${path}.swap_operation_id: custom check failed`)
if (typeof o.tx_id !== 'string') return new Error(`${path}.tx_id: is not a string`)
if (opts.tx_id_CustomCheck && !opts.tx_id_CustomCheck(o.tx_id)) return new Error(`${path}.tx_id: custom check failed`)
return null
}
export type InvoiceSwapQuote = {
address: string
chain_fee_sats: number
invoice: string
invoice_amount_sats: number
service_fee_sats: number
service_url: string
swap_fee_sats: number
swap_operation_id: string
transaction_amount_sats: number
tx_id: string
}
export const InvoiceSwapQuoteOptionalFields: [] = []
export type InvoiceSwapQuoteOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: []
address_CustomCheck?: (v: string) => boolean
chain_fee_sats_CustomCheck?: (v: number) => boolean
invoice_CustomCheck?: (v: string) => boolean
invoice_amount_sats_CustomCheck?: (v: number) => boolean
service_fee_sats_CustomCheck?: (v: number) => boolean
service_url_CustomCheck?: (v: string) => boolean
swap_fee_sats_CustomCheck?: (v: number) => boolean
swap_operation_id_CustomCheck?: (v: string) => boolean
transaction_amount_sats_CustomCheck?: (v: number) => boolean
tx_id_CustomCheck?: (v: string) => boolean
}
export const InvoiceSwapQuoteValidate = (o?: InvoiceSwapQuote, opts: InvoiceSwapQuoteOptions = {}, path: string = 'InvoiceSwapQuote::root.'): Error | null => {
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
if (typeof o.address !== 'string') return new Error(`${path}.address: is not a string`)
if (opts.address_CustomCheck && !opts.address_CustomCheck(o.address)) return new Error(`${path}.address: custom check failed`)
if (typeof o.chain_fee_sats !== 'number') return new Error(`${path}.chain_fee_sats: is not a number`)
if (opts.chain_fee_sats_CustomCheck && !opts.chain_fee_sats_CustomCheck(o.chain_fee_sats)) return new Error(`${path}.chain_fee_sats: custom check failed`)
if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`)
if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`)
if (typeof o.invoice_amount_sats !== 'number') return new Error(`${path}.invoice_amount_sats: is not a number`)
if (opts.invoice_amount_sats_CustomCheck && !opts.invoice_amount_sats_CustomCheck(o.invoice_amount_sats)) return new Error(`${path}.invoice_amount_sats: custom check failed`)
if (typeof o.service_fee_sats !== 'number') return new Error(`${path}.service_fee_sats: is not a number`)
if (opts.service_fee_sats_CustomCheck && !opts.service_fee_sats_CustomCheck(o.service_fee_sats)) return new Error(`${path}.service_fee_sats: custom check failed`)
if (typeof o.service_url !== 'string') return new Error(`${path}.service_url: is not a string`)
if (opts.service_url_CustomCheck && !opts.service_url_CustomCheck(o.service_url)) return new Error(`${path}.service_url: custom check failed`)
if (typeof o.swap_fee_sats !== 'number') return new Error(`${path}.swap_fee_sats: is not a number`)
if (opts.swap_fee_sats_CustomCheck && !opts.swap_fee_sats_CustomCheck(o.swap_fee_sats)) return new Error(`${path}.swap_fee_sats: custom check failed`)
if (typeof o.swap_operation_id !== 'string') return new Error(`${path}.swap_operation_id: is not a string`)
if (opts.swap_operation_id_CustomCheck && !opts.swap_operation_id_CustomCheck(o.swap_operation_id)) return new Error(`${path}.swap_operation_id: custom check failed`)
if (typeof o.transaction_amount_sats !== 'number') return new Error(`${path}.transaction_amount_sats: is not a number`)
if (opts.transaction_amount_sats_CustomCheck && !opts.transaction_amount_sats_CustomCheck(o.transaction_amount_sats)) return new Error(`${path}.transaction_amount_sats: custom check failed`)
if (typeof o.tx_id !== 'string') return new Error(`${path}.tx_id: is not a string`)
if (opts.tx_id_CustomCheck && !opts.tx_id_CustomCheck(o.tx_id)) return new Error(`${path}.tx_id: custom check failed`)
return null
}
export type InvoiceSwapQuoteList = {
quotes: InvoiceSwapQuote[]
}
export const InvoiceSwapQuoteListOptionalFields: [] = []
export type InvoiceSwapQuoteListOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: []
quotes_ItemOptions?: InvoiceSwapQuoteOptions
quotes_CustomCheck?: (v: InvoiceSwapQuote[]) => boolean
}
export const InvoiceSwapQuoteListValidate = (o?: InvoiceSwapQuoteList, opts: InvoiceSwapQuoteListOptions = {}, path: string = 'InvoiceSwapQuoteList::root.'): Error | null => {
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
if (!Array.isArray(o.quotes)) return new Error(`${path}.quotes: is not an array`)
for (let index = 0; index < o.quotes.length; index++) {
const quotesErr = InvoiceSwapQuoteValidate(o.quotes[index], opts.quotes_ItemOptions, `${path}.quotes[${index}]`)
if (quotesErr !== null) return quotesErr
}
if (opts.quotes_CustomCheck && !opts.quotes_CustomCheck(o.quotes)) return new Error(`${path}.quotes: custom check failed`)
return null
}
export type InvoiceSwapRequest = {
invoice: string
}
export const InvoiceSwapRequestOptionalFields: [] = []
export type InvoiceSwapRequestOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: []
invoice_CustomCheck?: (v: string) => boolean
}
export const InvoiceSwapRequestValidate = (o?: InvoiceSwapRequest, opts: InvoiceSwapRequestOptions = {}, path: string = 'InvoiceSwapRequest::root.'): Error | null => {
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`)
if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`)
return null
}
export type InvoiceSwapsList = {
quotes: InvoiceSwapQuote[]
swaps: InvoiceSwapOperation[]
}
export const InvoiceSwapsListOptionalFields: [] = []
export type InvoiceSwapsListOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: []
quotes_ItemOptions?: InvoiceSwapQuoteOptions
quotes_CustomCheck?: (v: InvoiceSwapQuote[]) => boolean
swaps_ItemOptions?: InvoiceSwapOperationOptions
swaps_CustomCheck?: (v: InvoiceSwapOperation[]) => boolean
}
export const InvoiceSwapsListValidate = (o?: InvoiceSwapsList, opts: InvoiceSwapsListOptions = {}, path: string = 'InvoiceSwapsList::root.'): Error | null => {
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
if (!Array.isArray(o.quotes)) return new Error(`${path}.quotes: is not an array`)
for (let index = 0; index < o.quotes.length; index++) {
const quotesErr = InvoiceSwapQuoteValidate(o.quotes[index], opts.quotes_ItemOptions, `${path}.quotes[${index}]`)
if (quotesErr !== null) return quotesErr
}
if (opts.quotes_CustomCheck && !opts.quotes_CustomCheck(o.quotes)) return new Error(`${path}.quotes: custom check failed`)
if (!Array.isArray(o.swaps)) return new Error(`${path}.swaps: is not an array`)
for (let index = 0; index < o.swaps.length; index++) {
const swapsErr = InvoiceSwapOperationValidate(o.swaps[index], opts.swaps_ItemOptions, `${path}.swaps[${index}]`)
if (swapsErr !== null) return swapsErr
}
if (opts.swaps_CustomCheck && !opts.swaps_CustomCheck(o.swaps)) return new Error(`${path}.swaps: custom check failed`)
return null
}
export type LatestBundleMetricReq = { export type LatestBundleMetricReq = {
limit?: number limit?: number
} }
@ -3308,6 +3517,29 @@ export const PayAddressResponseValidate = (o?: PayAddressResponse, opts: PayAddr
return null return null
} }
export type PayAdminInvoiceSwapRequest = {
sat_per_v_byte: number
swap_operation_id: string
}
export const PayAdminInvoiceSwapRequestOptionalFields: [] = []
export type PayAdminInvoiceSwapRequestOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: []
sat_per_v_byte_CustomCheck?: (v: number) => boolean
swap_operation_id_CustomCheck?: (v: string) => boolean
}
export const PayAdminInvoiceSwapRequestValidate = (o?: PayAdminInvoiceSwapRequest, opts: PayAdminInvoiceSwapRequestOptions = {}, path: string = 'PayAdminInvoiceSwapRequest::root.'): Error | null => {
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
if (typeof o.sat_per_v_byte !== 'number') return new Error(`${path}.sat_per_v_byte: is not a number`)
if (opts.sat_per_v_byte_CustomCheck && !opts.sat_per_v_byte_CustomCheck(o.sat_per_v_byte)) return new Error(`${path}.sat_per_v_byte: custom check failed`)
if (typeof o.swap_operation_id !== 'string') return new Error(`${path}.swap_operation_id: is not a string`)
if (opts.swap_operation_id_CustomCheck && !opts.swap_operation_id_CustomCheck(o.swap_operation_id)) return new Error(`${path}.swap_operation_id: custom check failed`)
return null
}
export type PayAdminTransactionSwapRequest = { export type PayAdminTransactionSwapRequest = {
address: string address: string
swap_operation_id: string swap_operation_id: string
@ -3917,76 +4149,6 @@ export const SingleMetricReqValidate = (o?: SingleMetricReq, opts: SingleMetricR
return null return null
} }
export type SwapOperation = {
address_paid: string
failure_reason?: string
operation_payment?: UserOperation
swap_operation_id: string
}
export type SwapOperationOptionalField = 'failure_reason' | 'operation_payment'
export const SwapOperationOptionalFields: SwapOperationOptionalField[] = ['failure_reason', 'operation_payment']
export type SwapOperationOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: SwapOperationOptionalField[]
address_paid_CustomCheck?: (v: string) => boolean
failure_reason_CustomCheck?: (v?: string) => boolean
operation_payment_Options?: UserOperationOptions
swap_operation_id_CustomCheck?: (v: string) => boolean
}
export const SwapOperationValidate = (o?: SwapOperation, opts: SwapOperationOptions = {}, path: string = 'SwapOperation::root.'): Error | null => {
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
if (typeof o.address_paid !== 'string') return new Error(`${path}.address_paid: is not a string`)
if (opts.address_paid_CustomCheck && !opts.address_paid_CustomCheck(o.address_paid)) return new Error(`${path}.address_paid: custom check failed`)
if ((o.failure_reason || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('failure_reason')) && typeof o.failure_reason !== 'string') return new Error(`${path}.failure_reason: is not a string`)
if (opts.failure_reason_CustomCheck && !opts.failure_reason_CustomCheck(o.failure_reason)) return new Error(`${path}.failure_reason: custom check failed`)
if (typeof o.operation_payment === 'object' || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('operation_payment')) {
const operation_paymentErr = UserOperationValidate(o.operation_payment, opts.operation_payment_Options, `${path}.operation_payment`)
if (operation_paymentErr !== null) return operation_paymentErr
}
if (typeof o.swap_operation_id !== 'string') return new Error(`${path}.swap_operation_id: is not a string`)
if (opts.swap_operation_id_CustomCheck && !opts.swap_operation_id_CustomCheck(o.swap_operation_id)) return new Error(`${path}.swap_operation_id: custom check failed`)
return null
}
export type SwapsList = {
quotes: TransactionSwapQuote[]
swaps: SwapOperation[]
}
export const SwapsListOptionalFields: [] = []
export type SwapsListOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: []
quotes_ItemOptions?: TransactionSwapQuoteOptions
quotes_CustomCheck?: (v: TransactionSwapQuote[]) => boolean
swaps_ItemOptions?: SwapOperationOptions
swaps_CustomCheck?: (v: SwapOperation[]) => boolean
}
export const SwapsListValidate = (o?: SwapsList, opts: SwapsListOptions = {}, path: string = 'SwapsList::root.'): Error | null => {
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
if (!Array.isArray(o.quotes)) return new Error(`${path}.quotes: is not an array`)
for (let index = 0; index < o.quotes.length; index++) {
const quotesErr = TransactionSwapQuoteValidate(o.quotes[index], opts.quotes_ItemOptions, `${path}.quotes[${index}]`)
if (quotesErr !== null) return quotesErr
}
if (opts.quotes_CustomCheck && !opts.quotes_CustomCheck(o.quotes)) return new Error(`${path}.quotes: custom check failed`)
if (!Array.isArray(o.swaps)) return new Error(`${path}.swaps: is not an array`)
for (let index = 0; index < o.swaps.length; index++) {
const swapsErr = SwapOperationValidate(o.swaps[index], opts.swaps_ItemOptions, `${path}.swaps[${index}]`)
if (swapsErr !== null) return swapsErr
}
if (opts.swaps_CustomCheck && !opts.swaps_CustomCheck(o.swaps)) return new Error(`${path}.swaps: custom check failed`)
return null
}
export type TransactionSwapQuote = { export type TransactionSwapQuote = {
chain_fee_sats: number chain_fee_sats: number
invoice_amount_sats: number invoice_amount_sats: number
@ -4076,6 +4238,76 @@ export const TransactionSwapRequestValidate = (o?: TransactionSwapRequest, opts:
return null return null
} }
export type TxSwapOperation = {
address_paid: string
failure_reason?: string
operation_payment?: UserOperation
swap_operation_id: string
}
export type TxSwapOperationOptionalField = 'failure_reason' | 'operation_payment'
export const TxSwapOperationOptionalFields: TxSwapOperationOptionalField[] = ['failure_reason', 'operation_payment']
export type TxSwapOperationOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: TxSwapOperationOptionalField[]
address_paid_CustomCheck?: (v: string) => boolean
failure_reason_CustomCheck?: (v?: string) => boolean
operation_payment_Options?: UserOperationOptions
swap_operation_id_CustomCheck?: (v: string) => boolean
}
export const TxSwapOperationValidate = (o?: TxSwapOperation, opts: TxSwapOperationOptions = {}, path: string = 'TxSwapOperation::root.'): Error | null => {
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
if (typeof o.address_paid !== 'string') return new Error(`${path}.address_paid: is not a string`)
if (opts.address_paid_CustomCheck && !opts.address_paid_CustomCheck(o.address_paid)) return new Error(`${path}.address_paid: custom check failed`)
if ((o.failure_reason || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('failure_reason')) && typeof o.failure_reason !== 'string') return new Error(`${path}.failure_reason: is not a string`)
if (opts.failure_reason_CustomCheck && !opts.failure_reason_CustomCheck(o.failure_reason)) return new Error(`${path}.failure_reason: custom check failed`)
if (typeof o.operation_payment === 'object' || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('operation_payment')) {
const operation_paymentErr = UserOperationValidate(o.operation_payment, opts.operation_payment_Options, `${path}.operation_payment`)
if (operation_paymentErr !== null) return operation_paymentErr
}
if (typeof o.swap_operation_id !== 'string') return new Error(`${path}.swap_operation_id: is not a string`)
if (opts.swap_operation_id_CustomCheck && !opts.swap_operation_id_CustomCheck(o.swap_operation_id)) return new Error(`${path}.swap_operation_id: custom check failed`)
return null
}
export type TxSwapsList = {
quotes: TransactionSwapQuote[]
swaps: TxSwapOperation[]
}
export const TxSwapsListOptionalFields: [] = []
export type TxSwapsListOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: []
quotes_ItemOptions?: TransactionSwapQuoteOptions
quotes_CustomCheck?: (v: TransactionSwapQuote[]) => boolean
swaps_ItemOptions?: TxSwapOperationOptions
swaps_CustomCheck?: (v: TxSwapOperation[]) => boolean
}
export const TxSwapsListValidate = (o?: TxSwapsList, opts: TxSwapsListOptions = {}, path: string = 'TxSwapsList::root.'): Error | null => {
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
if (!Array.isArray(o.quotes)) return new Error(`${path}.quotes: is not an array`)
for (let index = 0; index < o.quotes.length; index++) {
const quotesErr = TransactionSwapQuoteValidate(o.quotes[index], opts.quotes_ItemOptions, `${path}.quotes[${index}]`)
if (quotesErr !== null) return quotesErr
}
if (opts.quotes_CustomCheck && !opts.quotes_CustomCheck(o.quotes)) return new Error(`${path}.quotes: custom check failed`)
if (!Array.isArray(o.swaps)) return new Error(`${path}.swaps: is not an array`)
for (let index = 0; index < o.swaps.length; index++) {
const swapsErr = TxSwapOperationValidate(o.swaps[index], opts.swaps_ItemOptions, `${path}.swaps[${index}]`)
if (swapsErr !== null) return swapsErr
}
if (opts.swaps_CustomCheck && !opts.swaps_CustomCheck(o.swaps)) return new Error(`${path}.swaps: custom check failed`)
return null
}
export type UpdateChannelPolicyRequest = { export type UpdateChannelPolicyRequest = {
policy: ChannelPolicy policy: ChannelPolicy
update: UpdateChannelPolicyRequest_update update: UpdateChannelPolicyRequest_update

View file

@ -175,6 +175,27 @@ service LightningPub {
option (nostr) = true; option (nostr) = true;
} }
rpc GetAdminInvoiceSwapQuotes(structs.InvoiceSwapRequest) returns (structs.InvoiceSwapQuoteList) {
option (auth_type) = "Admin";
option (http_method) = "post";
option (http_route) = "/api/admin/swap/invoice/quote";
option (nostr) = true;
}
rpc ListAdminInvoiceSwaps(structs.Empty) returns (structs.InvoiceSwapsList) {
option (auth_type) = "Admin";
option (http_method) = "post";
option (http_route) = "/api/admin/swap/invoice/list";
option (nostr) = true;
}
rpc PayAdminInvoiceSwap(structs.PayAdminInvoiceSwapRequest) returns (structs.AdminInvoiceSwapResponse) {
option (auth_type) = "Admin";
option (http_method) = "post";
option (http_route) = "/api/admin/swap/invoice/pay";
option (nostr) = true;
}
rpc GetAdminTransactionSwapQuotes(structs.TransactionSwapRequest) returns (structs.TransactionSwapQuoteList) { rpc GetAdminTransactionSwapQuotes(structs.TransactionSwapRequest) returns (structs.TransactionSwapQuoteList) {
option (auth_type) = "Admin"; option (auth_type) = "Admin";
option (http_method) = "post"; option (http_method) = "post";
@ -182,17 +203,17 @@ service LightningPub {
option (nostr) = true; option (nostr) = true;
} }
rpc PayAdminTransactionSwap(structs.PayAdminTransactionSwapRequest) returns (structs.AdminSwapResponse) { rpc PayAdminTransactionSwap(structs.PayAdminTransactionSwapRequest) returns (structs.AdminTxSwapResponse) {
option (auth_type) = "Admin"; option (auth_type) = "Admin";
option (http_method) = "post"; option (http_method) = "post";
option (http_route) = "/api/admin/swap/transaction/pay"; option (http_route) = "/api/admin/swap/transaction/pay";
option (nostr) = true; option (nostr) = true;
} }
rpc ListAdminSwaps(structs.Empty) returns (structs.SwapsList) { rpc ListAdminTxSwaps(structs.Empty) returns (structs.TxSwapsList) {
option (auth_type) = "Admin"; option (auth_type) = "Admin";
option (http_method) = "post"; option (http_method) = "post";
option (http_route) = "/api/admin/swap/list"; option (http_route) = "/api/admin/swap/transaction/list";
option (nostr) = true; option (nostr) = true;
} }
@ -520,14 +541,14 @@ service LightningPub {
rpc GetTransactionSwapQuotes(structs.TransactionSwapRequest) returns (structs.TransactionSwapQuoteList){ rpc GetTransactionSwapQuotes(structs.TransactionSwapRequest) returns (structs.TransactionSwapQuoteList){
option (auth_type) = "User"; option (auth_type) = "User";
option (http_method) = "post"; option (http_method) = "post";
option (http_route) = "/api/user/swap/quote"; option (http_route) = "/api/user/swap/transaction/quote";
option (nostr) = true; option (nostr) = true;
} }
rpc ListSwaps(structs.Empty) returns (structs.SwapsList){ rpc ListTxSwaps(structs.Empty) returns (structs.TxSwapsList){
option (auth_type) = "User"; option (auth_type) = "User";
option (http_method) = "post"; option (http_method) = "post";
option (http_route) = "/api/user/swap/list"; option (http_route) = "/api/user/swap/transaction/list";
option (nostr) = true; option (nostr) = true;
} }

View file

@ -833,6 +833,49 @@ message MessagingToken {
string firebase_messaging_token = 2; string firebase_messaging_token = 2;
} }
message InvoiceSwapRequest {
string invoice = 1;
}
message InvoiceSwapQuote {
string swap_operation_id = 1;
string invoice = 2;
int64 invoice_amount_sats = 3;
string address = 4;
int64 transaction_amount_sats = 5;
int64 chain_fee_sats = 6;
int64 service_fee_sats = 7;
string service_url = 8;
int64 swap_fee_sats = 9;
string tx_id = 10;
}
message InvoiceSwapQuoteList {
repeated InvoiceSwapQuote quotes = 1;
}
message InvoiceSwapOperation {
string swap_operation_id = 1;
optional UserOperation operation_payment = 2;
optional string failure_reason = 3;
string invoice_paid = 4;
string tx_id = 5;
}
message InvoiceSwapsList {
repeated InvoiceSwapOperation swaps = 1;
repeated InvoiceSwapQuote quotes = 2;
}
message PayAdminInvoiceSwapRequest {
string swap_operation_id = 1;
int64 sat_per_v_byte = 2;
}
message AdminInvoiceSwapResponse {
string tx_id = 1;
}
message TransactionSwapRequest { message TransactionSwapRequest {
int64 transaction_amount_sats = 2; int64 transaction_amount_sats = 2;
} }
@ -857,20 +900,20 @@ message TransactionSwapQuoteList {
repeated TransactionSwapQuote quotes = 1; repeated TransactionSwapQuote quotes = 1;
} }
message AdminSwapResponse { message AdminTxSwapResponse {
string tx_id = 1; string tx_id = 1;
int64 network_fee = 2; int64 network_fee = 2;
} }
message SwapOperation { message TxSwapOperation {
string swap_operation_id = 1; string swap_operation_id = 1;
optional UserOperation operation_payment = 2; optional UserOperation operation_payment = 2;
optional string failure_reason = 3; optional string failure_reason = 3;
string address_paid = 4; string address_paid = 4;
} }
message SwapsList { message TxSwapsList {
repeated SwapOperation swaps = 1; repeated TxSwapOperation swaps = 1;
repeated TransactionSwapQuote quotes = 2; repeated TransactionSwapQuote quotes = 2;
} }

View file

@ -11,10 +11,38 @@ import { getLogger, PubLogger, ERROR } from '../../helpers/logger.js';
import { loggedGet, loggedPost } from './swapHelpers.js'; import { loggedGet, loggedPost } from './swapHelpers.js';
import { BTCNetwork } from '../../main/settings.js'; import { BTCNetwork } from '../../main/settings.js';
type InvoiceSwapResponse = { id: string, claimPublicKey: string, swapTree: string } /* type InvoiceSwapFees = {
type InvoiceSwapInfo = { paymentHash: string, keys: ECPairInterface } hash: string,
type InvoiceSwapData = { createdResponse: InvoiceSwapResponse, info: InvoiceSwapInfo } rate: number,
limits: {
maximal: number,
minimal: number,
maximalZeroConf: number
},
fees: {
percentage: number,
minerFees: number,
}
} */
type InvoiceSwapFees = {
percentage: number,
minerFees: number,
}
type InvoiceSwapFeesRes = {
BTC?: {
BTC?: {
fees: InvoiceSwapFees
}
}
}
type InvoiceSwapResponse = {
id: string, claimPublicKey: string, swapTree: string, timeoutBlockHeight: number,
expectedAmount: number, address: string
}
type InvoiceSwapInfo = { paymentHash: string, keys: ECPairInterface }
export type InvoiceSwapData = { createdResponse: InvoiceSwapResponse, info: InvoiceSwapInfo }
export class SubmarineSwaps { export class SubmarineSwaps {
private httpUrl: string private httpUrl: string
@ -33,8 +61,23 @@ export class SubmarineSwaps {
return this.wsUrl return this.wsUrl
} }
SwapInvoice = async (invoice: string, paymentHash: string) => { GetFees = async (): Promise<{ ok: true, fees: InvoiceSwapFees, } | { ok: false, error: string }> => {
const url = `${this.httpUrl}/v2/swap/submarine`
const feesRes = await loggedGet<InvoiceSwapFeesRes>(this.log, url)
if (!feesRes.ok) {
return { ok: false, error: feesRes.error }
}
if (!feesRes.data.BTC?.BTC?.fees) {
return { ok: false, error: 'No fees found for BTC to BTC swap' }
}
return { ok: true, fees: feesRes.data.BTC.BTC.fees }
}
SwapInvoice = async (invoice: string): Promise<{ ok: true, createdResponse: InvoiceSwapResponse, pubkey: string, privKey: string } | { ok: false, error: string }> => {
const keys = ECPairFactory(ecc).makeRandom() const keys = ECPairFactory(ecc).makeRandom()
if (!keys.privateKey) {
return { ok: false, error: 'Failed to generate keys' }
}
const refundPublicKey = Buffer.from(keys.publicKey).toString('hex') const refundPublicKey = Buffer.from(keys.publicKey).toString('hex')
const req = { invoice, to: 'BTC', from: 'BTC', refundPublicKey } const req = { invoice, to: 'BTC', from: 'BTC', refundPublicKey }
const url = `${this.httpUrl}/v2/swap/submarine` const url = `${this.httpUrl}/v2/swap/submarine`
@ -46,21 +89,25 @@ export class SubmarineSwaps {
const createdResponse = createdResponseRes.data const createdResponse = createdResponseRes.data
this.log('Created invoice swap'); this.log('Created invoice swap');
this.log(createdResponse); this.log(createdResponse);
return {
ok: true, createdResponse,
pubkey: refundPublicKey,
privKey: Buffer.from(keys.privateKey).toString('hex')
}
} }
SubscribeToInvoiceSwap = async (data: InvoiceSwapData, swapDone: (result: { ok: true, txId: string } | { ok: false, error: string }) => void) => { SubscribeToInvoiceSwap = (data: InvoiceSwapData, swapDone: (result: { ok: true } | { ok: false, error: string }) => void, waitingTx: () => void) => {
const webSocket = new ws(`${this.wsUrl}/v2/ws`) const webSocket = new ws(`${this.wsUrl}/v2/ws`)
const subReq = { op: 'subscribe', channel: 'swap.update', args: [data.createdResponse.id] } const subReq = { op: 'subscribe', channel: 'swap.update', args: [data.createdResponse.id] }
webSocket.on('open', () => { webSocket.on('open', () => {
webSocket.send(JSON.stringify(subReq)) webSocket.send(JSON.stringify(subReq))
}) })
let txId = "", isDone = false let isDone = false
const done = () => { const done = () => {
isDone = true isDone = true
webSocket.close() webSocket.close()
swapDone({ ok: true, txId }) swapDone({ ok: true })
} }
webSocket.on('error', (err) => { webSocket.on('error', (err) => {
this.log(ERROR, 'Error in WebSocket', err.message) this.log(ERROR, 'Error in WebSocket', err.message)
@ -73,16 +120,19 @@ export class SubmarineSwaps {
}) })
webSocket.on('message', async (rawMsg) => { webSocket.on('message', async (rawMsg) => {
try { try {
await this.handleSwapInvoiceMessage(rawMsg, data, done) await this.handleSwapInvoiceMessage(rawMsg, data, done, waitingTx)
} catch (err: any) { } catch (err: any) {
this.log(ERROR, 'Error handling invoice WebSocket message', err.message) this.log(ERROR, 'Error handling invoice WebSocket message', err.message)
webSocket.close() webSocket.close()
return return
} }
}); });
return () => {
webSocket.close()
}
} }
handleSwapInvoiceMessage = async (rawMsg: ws.RawData, data: InvoiceSwapData, closeWebSocket: () => void) => { handleSwapInvoiceMessage = async (rawMsg: ws.RawData, data: InvoiceSwapData, closeWebSocket: () => void, waitingTx: () => void) => {
const msg = JSON.parse(rawMsg.toString('utf-8')); const msg = JSON.parse(rawMsg.toString('utf-8'));
if (msg.event !== 'update') { if (msg.event !== 'update') {
return; return;
@ -94,6 +144,7 @@ export class SubmarineSwaps {
// "invoice.set" means Boltz is waiting for an onchain transaction to be sent // "invoice.set" means Boltz is waiting for an onchain transaction to be sent
case 'invoice.set': case 'invoice.set':
this.log('Waiting for onchain transaction'); this.log('Waiting for onchain transaction');
waitingTx()
return; return;
// Create a partial signature to allow Boltz to do a key path spend to claim the mainchain coins // Create a partial signature to allow Boltz to do a key path spend to claim the mainchain coins
case 'transaction.claim.pending': case 'transaction.claim.pending':

View file

@ -7,7 +7,8 @@ import Storage from '../../storage/index.js';
import LND from '../lnd.js'; import LND from '../lnd.js';
import { UserInvoicePayment } from '../../storage/entity/UserInvoicePayment.js'; import { UserInvoicePayment } from '../../storage/entity/UserInvoicePayment.js';
import { ReverseSwaps, TransactionSwapData } from './reverseSwaps.js'; import { ReverseSwaps, TransactionSwapData } from './reverseSwaps.js';
import { SubmarineSwaps } from './submarineSwaps.js'; import { SubmarineSwaps, InvoiceSwapData } from './submarineSwaps.js';
import { InvoiceSwap } from '../../storage/entity/InvoiceSwap.js';
export class Swaps { export class Swaps {
@ -16,6 +17,7 @@ export class Swaps {
subSwappers: Record<string, SubmarineSwaps> subSwappers: Record<string, SubmarineSwaps>
storage: Storage storage: Storage
lnd: LND lnd: LND
waitingSwaps: Record<string, boolean> = {}
log = getLogger({ component: 'swaps' }) log = getLogger({ component: 'swaps' })
constructor(settings: SettingsManager, storage: Storage) { constructor(settings: SettingsManager, storage: Storage) {
this.settings = settings this.settings = settings
@ -45,7 +47,7 @@ export class Swaps {
return keys return keys
} }
GetInvoiceSwapQuotes = async (appUserId: string, payments: UserInvoicePayment[], getServiceFee: (amt: number) => number): Promise<Types.InvoiceSwapQuote[]> => { GetInvoiceSwapQuotes = async (appUserId: string, invoice: string): Promise<Types.InvoiceSwapQuote[]> => {
if (!this.settings.getSettings().swapsSettings.enableSwaps) { if (!this.settings.getSettings().swapsSettings.enableSwaps) {
throw new Error("Swaps are not enabled") throw new Error("Swaps are not enabled")
} }
@ -53,13 +55,178 @@ export class Swaps {
if (swappers.length === 0) { if (swappers.length === 0) {
throw new Error("No swap services available") throw new Error("No swap services available")
} }
const res = await Promise.allSettled(swappers.map(sw => this.getInvoiceSwapQuote(sw, appUserId, payments, getServiceFee))) const res = await Promise.allSettled(swappers.map(sw => this.getInvoiceSwapQuote(sw, appUserId, invoice)))
const failures: string[] = [] const failures: string[] = []
const success: Types.InvoiceSwapQuote[] = [] const success: Types.InvoiceSwapQuote[] = []
for (const r of res) { } for (const r of res) {
if (r.status === 'fulfilled') {
success.push(r.value)
} else {
failures.push(r.reason.message ? r.reason.message : r.reason.toString())
}
}
if (success.length === 0) {
throw new Error(failures.join("\n"))
}
return success
} }
ListTxSwaps = async (appUserId: string, payments: UserInvoicePayment[], newOp: (p: UserInvoicePayment) => Types.UserOperation | undefined, getServiceFee: (amt: number) => number): Promise<Types.SwapsList> => { ListInvoiceSwaps = async (appUserId: string): Promise<Types.InvoiceSwapsList> => {
const completedSwaps = await this.storage.paymentStorage.ListCompletedInvoiceSwaps(appUserId)
const pendingSwaps = await this.storage.paymentStorage.ListPendingInvoiceSwaps(appUserId)
return {
swaps: completedSwaps.map(s => {
return {
invoice_paid: s.invoice,
swap_operation_id: s.swap_operation_id,
failure_reason: s.failure_reason,
tx_id: s.tx_id,
}
}),
quotes: pendingSwaps.map(s => {
return {
swap_operation_id: s.swap_operation_id,
invoice: s.invoice,
invoice_amount_sats: s.invoice_amount,
address: s.address,
transaction_amount_sats: s.transaction_amount,
chain_fee_sats: s.chain_fee_sats,
service_fee_sats: 0,
service_url: s.service_url,
swap_fee_sats: s.swap_fee_sats,
tx_id: s.tx_id,
}
})
}
}
PayInvoiceSwap = async (appUserId: string, swapOpId: string, satPerVByte: number, payAddress: (address: string, amt: number) => Promise<{ txId: string }>): Promise<void> => {
if (!this.settings.getSettings().swapsSettings.enableSwaps) {
throw new Error("Swaps are not enabled")
}
if (!swapOpId) {
throw new Error("swap operation id is required")
}
if (!satPerVByte) {
throw new Error("sat per v byte is required")
}
const swap = await this.storage.paymentStorage.GetInvoiceSwap(swapOpId, appUserId)
if (!swap) {
throw new Error("swap not found")
}
const swapper = this.subSwappers[swap.service_url]
if (!swapper) {
throw new Error("swapper service not found")
}
if (this.waitingSwaps[swapOpId]) {
throw new Error("swap already in progress")
}
this.waitingSwaps[swapOpId] = true
const data = this.getInvoiceSwapData(swap)
let txId = ""
const close = swapper.SubscribeToInvoiceSwap(data, async (result) => {
if (result.ok) {
await this.storage.paymentStorage.FinalizeInvoiceSwap(swapOpId)
this.log("invoice swap completed", { swapOpId, txId })
} else {
await this.storage.paymentStorage.FailInvoiceSwap(swapOpId, result.error, txId)
this.log("invoice swap failed", { swapOpId, error: result.error })
}
}, () => payAddress(swap.address, swap.transaction_amount).then(res => { txId = res.txId }).catch(err => { close(); this.log("error paying address", err) }))
}
ResumeInvoiceSwaps = async () => {
this.log("resuming invoice swaps")
const swaps = await this.storage.paymentStorage.ListUnfinishedInvoiceSwaps()
this.log("resuming", swaps.length, "invoice swaps")
for (const swap of swaps) {
this.resumeInvoiceSwap(swap)
}
}
private resumeInvoiceSwap = (swap: InvoiceSwap) => {
// const swap = await this.storage.paymentStorage.GetInvoiceSwap(swapOpId, appUserId)
if (!swap || !swap.tx_id || swap.used) {
throw new Error("swap to resume not found, or does not have a tx id")
}
const swapper = this.subSwappers[swap.service_url]
if (!swapper) {
throw new Error("swapper service not found")
}
const data = this.getInvoiceSwapData(swap)
swapper.SubscribeToInvoiceSwap(data, async (result) => {
if (result.ok) {
await this.storage.paymentStorage.FinalizeInvoiceSwap(swap.swap_operation_id)
this.log("invoice swap completed", { swapOpId: swap.swap_operation_id, txId: swap.tx_id })
} else {
await this.storage.paymentStorage.FailInvoiceSwap(swap.swap_operation_id, result.error)
this.log("invoice swap failed", { swapOpId: swap.swap_operation_id, error: result.error })
}
}, () => { throw new Error("swap tx already paid") })
}
private getInvoiceSwapData = (swap: InvoiceSwap) => {
return {
createdResponse: {
address: swap.address,
claimPublicKey: swap.claim_public_key,
id: swap.swap_quote_id,
swapTree: swap.swap_tree,
timeoutBlockHeight: swap.timeout_block_height,
expectedAmount: swap.transaction_amount,
},
info: {
keys: this.GetKeys(swap.ephemeral_private_key),
paymentHash: swap.payment_hash,
}
}
}
private async getInvoiceSwapQuote(swapper: SubmarineSwaps, appUserId: string, invoice: string): Promise<Types.InvoiceSwapQuote> {
const feesRes = await swapper.GetFees()
if (!feesRes.ok) {
throw new Error(feesRes.error)
}
const decoded = await this.lnd.DecodeInvoice(invoice)
const amt = decoded.numSatoshis
const fee = Math.ceil((feesRes.fees.percentage / 100) * amt) + feesRes.fees.minerFees
const res = await swapper.SwapInvoice(invoice)
if (!res.ok) {
throw new Error(res.error)
}
const newSwap = await this.storage.paymentStorage.AddInvoiceSwap({
app_user_id: appUserId,
swap_quote_id: res.createdResponse.id,
swap_tree: JSON.stringify(res.createdResponse.swapTree),
timeout_block_height: res.createdResponse.timeoutBlockHeight,
ephemeral_public_key: res.pubkey,
ephemeral_private_key: res.privKey,
invoice: invoice,
invoice_amount: amt,
transaction_amount: res.createdResponse.expectedAmount,
swap_fee_sats: fee,
chain_fee_sats: 0,
service_url: swapper.getHttpUrl(),
address: res.createdResponse.address,
claim_public_key: res.createdResponse.claimPublicKey,
payment_hash: decoded.paymentHash,
})
return {
swap_operation_id: newSwap.swap_operation_id,
invoice: invoice,
invoice_amount_sats: amt,
address: res.createdResponse.address,
transaction_amount_sats: res.createdResponse.expectedAmount,
chain_fee_sats: 0,
service_fee_sats: 0,
service_url: swapper.getHttpUrl(),
swap_fee_sats: fee,
tx_id: newSwap.tx_id,
}
}
ListTxSwaps = async (appUserId: string, payments: UserInvoicePayment[], newOp: (p: UserInvoicePayment) => Types.UserOperation | undefined, getServiceFee: (amt: number) => number): Promise<Types.TxSwapsList> => {
const completedSwaps = await this.storage.paymentStorage.ListCompletedTxSwaps(appUserId, payments) const completedSwaps = await this.storage.paymentStorage.ListCompletedTxSwaps(appUserId, payments)
const pendingSwaps = await this.storage.paymentStorage.ListPendingTransactionSwaps(appUserId) const pendingSwaps = await this.storage.paymentStorage.ListPendingTransactionSwaps(appUserId)
return { return {

View file

@ -260,15 +260,36 @@ export class AdminManager {
} }
} }
async ListAdminSwaps(): Promise<Types.SwapsList> { async ListAdminInvoiceSwaps(): Promise<Types.InvoiceSwapsList> {
return this.swaps.ListSwaps("admin", [], p => undefined, amt => 0) return this.swaps.ListInvoiceSwaps("admin")
}
async GetAdminInvoiceSwapQuotes(req: Types.InvoiceSwapRequest): Promise<Types.InvoiceSwapQuoteList> {
const quotes = await this.swaps.GetInvoiceSwapQuotes("admin", req.invoice)
return { quotes }
}
async PayAdminInvoiceSwap(req: Types.PayAdminInvoiceSwapRequest): Promise<Types.AdminInvoiceSwapResponse> {
const txId = await new Promise<string>(res => {
this.swaps.PayInvoiceSwap("admin", req.swap_operation_id, req.sat_per_v_byte, async (addr, amt) => {
const tx = await this.lnd.PayAddress(addr, amt, req.sat_per_v_byte, "", { useProvider: false, from: 'system' })
this.log("paid admin invoice swap", { swapOpId: req.swap_operation_id, txId: tx.txid })
res(tx.txid)
return { txId: tx.txid }
})
})
return { tx_id: txId }
}
async ListAdminTxSwaps(): Promise<Types.TxSwapsList> {
return this.swaps.ListTxSwaps("admin", [], p => undefined, amt => 0)
} }
async GetAdminTransactionSwapQuotes(req: Types.TransactionSwapRequest): Promise<Types.TransactionSwapQuoteList> { async GetAdminTransactionSwapQuotes(req: Types.TransactionSwapRequest): Promise<Types.TransactionSwapQuoteList> {
const quotes = await this.swaps.GetTxSwapQuotes("admin", req.transaction_amount_sats, () => 0) const quotes = await this.swaps.GetTxSwapQuotes("admin", req.transaction_amount_sats, () => 0)
return { quotes } return { quotes }
} }
async PayAdminTransactionSwap(req: Types.PayAdminTransactionSwapRequest): Promise<Types.AdminSwapResponse> { async PayAdminTransactionSwap(req: Types.PayAdminTransactionSwapRequest): Promise<Types.AdminTxSwapResponse> {
const routingFloor = this.settings.getSettings().lndSettings.routingFeeFloor const routingFloor = this.settings.getSettings().lndSettings.routingFeeFloor
const routingLimit = this.settings.getSettings().lndSettings.routingFeeLimitBps / 10000 const routingLimit = this.settings.getSettings().lndSettings.routingFeeLimitBps / 10000

View file

@ -394,6 +394,7 @@ export default class {
const j = JSON.stringify(op) const j = JSON.stringify(op)
const encrypted = nip44.encrypt(j, ck) const encrypted = nip44.encrypt(j, ck)
const encryptedData: { encrypted: string, app_npub_hex: string } = { encrypted, app_npub_hex: app.nostr_public_key } const encryptedData: { encrypted: string, app_npub_hex: string } = { encrypted, app_npub_hex: app.nostr_public_key }
this.notificationsManager.SendNotification(JSON.stringify(encryptedData), tokens, { this.notificationsManager.SendNotification(JSON.stringify(encryptedData), tokens, {
pubkey: app.nostr_public_key!, pubkey: app.nostr_public_key!,
privateKey: app.nostr_private_key! privateKey: app.nostr_private_key!

View file

@ -79,6 +79,7 @@ export const initMainHandler = async (log: PubLogger, settingsManager: SettingsM
await mainHandler.paymentManager.CleanupOldUnpaidInvoices() await mainHandler.paymentManager.CleanupOldUnpaidInvoices()
await mainHandler.appUserManager.CleanupInactiveUsers() await mainHandler.appUserManager.CleanupInactiveUsers()
await mainHandler.appUserManager.CleanupNeverActiveUsers() await mainHandler.appUserManager.CleanupNeverActiveUsers()
await swaps.ResumeInvoiceSwaps()
await mainHandler.paymentManager.watchDog.Start() await mainHandler.paymentManager.watchDog.Start()
return { mainHandler, apps, localProviderClient, wizard, adminManager } return { mainHandler, apps, localProviderClient, wizard, adminManager }
} }

View file

@ -18,7 +18,7 @@ import { LiquidityManager } from './liquidityManager.js'
import { Utils } from '../helpers/utilsWrapper.js' import { Utils } from '../helpers/utilsWrapper.js'
import { UserInvoicePayment } from '../storage/entity/UserInvoicePayment.js' import { UserInvoicePayment } from '../storage/entity/UserInvoicePayment.js'
import SettingsManager from './settingsManager.js' import SettingsManager from './settingsManager.js'
import { Swaps, TransactionSwapData } from '../lnd/swaps/swaps.js' import { Swaps } from '../lnd/swaps/swaps.js'
import { Transaction, OutputDetail } from '../../../proto/lnd/lightning.js' import { Transaction, OutputDetail } from '../../../proto/lnd/lightning.js'
import { LndAddress } from '../lnd/lnd.js' import { LndAddress } from '../lnd/lnd.js'
import Metrics from '../metrics/index.js' import Metrics from '../metrics/index.js'
@ -617,7 +617,7 @@ export default class {
} }
} }
async ListSwaps(ctx: Types.UserContext): Promise<Types.SwapsList> { async ListTxSwaps(ctx: Types.UserContext): Promise<Types.TxSwapsList> {
const payments = await this.storage.paymentStorage.ListTxSwapPayments(ctx.app_user_id) const payments = await this.storage.paymentStorage.ListTxSwapPayments(ctx.app_user_id)
const app = await this.storage.applicationStorage.GetApplication(ctx.app_id) const app = await this.storage.applicationStorage.GetApplication(ctx.app_id)
const isManagedUser = ctx.user_id !== app.owner.user_id const isManagedUser = ctx.user_id !== app.owner.user_id

View file

@ -106,6 +106,26 @@ export default (mainHandler: Main): Types.ServerMethods => {
if (err != null) throw new Error(err.message) if (err != null) throw new Error(err.message)
return mainHandler.adminManager.PayAdminTransactionSwap(req) return mainHandler.adminManager.PayAdminTransactionSwap(req)
}, },
ListAdminTxSwaps: async ({ ctx }) => {
return mainHandler.adminManager.ListAdminTxSwaps()
},
GetAdminInvoiceSwapQuotes: async ({ ctx, req }) => {
const err = Types.InvoiceSwapRequestValidate(req, {
invoice_CustomCheck: invoice => invoice !== ''
})
if (err != null) throw new Error(err.message)
return mainHandler.adminManager.GetAdminInvoiceSwapQuotes(req)
},
ListAdminInvoiceSwaps: async ({ ctx }) => {
return mainHandler.adminManager.ListAdminInvoiceSwaps()
},
PayAdminInvoiceSwap: async ({ ctx, req }) => {
const err = Types.PayAdminInvoiceSwapRequestValidate(req, {
swap_operation_id_CustomCheck: id => id !== '',
})
if (err != null) throw new Error(err.message)
return mainHandler.adminManager.PayAdminInvoiceSwap(req)
},
GetProvidersDisruption: async () => { GetProvidersDisruption: async () => {
return mainHandler.metricsManager.GetProvidersDisruption() return mainHandler.metricsManager.GetProvidersDisruption()
}, },
@ -145,9 +165,7 @@ export default (mainHandler: Main): Types.ServerMethods => {
GetUserOperations: async ({ ctx, req }) => { GetUserOperations: async ({ ctx, req }) => {
return mainHandler.paymentManager.GetUserOperations(ctx.user_id, req) return mainHandler.paymentManager.GetUserOperations(ctx.user_id, req)
}, },
ListAdminSwaps: async ({ ctx }) => {
return mainHandler.adminManager.ListAdminSwaps()
},
GetPaymentState: async ({ ctx, req }) => { GetPaymentState: async ({ ctx, req }) => {
const err = Types.GetPaymentStateRequestValidate(req, { const err = Types.GetPaymentStateRequestValidate(req, {
invoice_CustomCheck: invoice => invoice !== "" invoice_CustomCheck: invoice => invoice !== ""
@ -165,8 +183,8 @@ export default (mainHandler: Main): Types.ServerMethods => {
if (err != null) throw new Error(err.message) if (err != null) throw new Error(err.message)
return mainHandler.paymentManager.PayAddress(ctx, req) return mainHandler.paymentManager.PayAddress(ctx, req)
}, },
ListSwaps: async ({ ctx }) => { ListTxSwaps: async ({ ctx }) => {
return mainHandler.paymentManager.ListSwaps(ctx) return mainHandler.paymentManager.ListTxSwaps(ctx)
}, },
GetTransactionSwapQuotes: async ({ ctx, req }) => { GetTransactionSwapQuotes: async ({ ctx, req }) => {
return mainHandler.paymentManager.GetTransactionSwapQuotes(ctx, req) return mainHandler.paymentManager.GetTransactionSwapQuotes(ctx, req)

View file

@ -16,10 +16,16 @@ export class InvoiceSwap {
swap_tree: string swap_tree: string
@Column() @Column()
lockup_address: string claim_public_key: string
@Column() @Column()
refund_public_key: string payment_hash: string
/* @Column()
lockup_address: string */
/* @Column()
refund_public_key: string */
@Column() @Column()
timeout_block_height: number timeout_block_height: number
@ -39,12 +45,14 @@ export class InvoiceSwap {
@Column() @Column()
chain_fee_sats: number chain_fee_sats: number
@Column()
preimage: string
@Column() @Column()
ephemeral_public_key: string ephemeral_public_key: string
@Column()
address: string
// the private key is used on to perform a swap, it does not hold any funds once the swap is completed // the private key is used on to perform a swap, it does not hold any funds once the swap is completed
// the swap should only last a few seconds, so it is not a security risk to store the private key in the database // the swap should only last a few seconds, so it is not a security risk to store the private key in the database
// the key is stored here mostly for recovery purposes, in case something goes wrong with the swap // the key is stored here mostly for recovery purposes, in case something goes wrong with the swap
@ -54,14 +62,17 @@ export class InvoiceSwap {
@Column({ default: false }) @Column({ default: false })
used: boolean used: boolean
@Column({ default: "" })
preimage: string
@Column({ default: "" }) @Column({ default: "" })
failure_reason: string failure_reason: string
@Column({ default: "" }) @Column({ default: "" })
tx_id: string tx_id: string
@Column({ default: "" }) /* @Column({ default: "" })
address_paid: string address_paid: string */
@Column({ default: "" }) @Column({ default: "" })
service_url: string service_url: string

View file

@ -0,0 +1,30 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class InvoiceSwaps1769529793283 implements MigrationInterface {
name = 'InvoiceSwaps1769529793283'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "invoice_swap" ("swap_operation_id" varchar PRIMARY KEY NOT NULL, "app_user_id" varchar NOT NULL, "swap_quote_id" varchar NOT NULL, "swap_tree" varchar NOT NULL, "claim_public_key" varchar NOT NULL, "payment_hash" varchar NOT NULL, "timeout_block_height" integer NOT NULL, "invoice" varchar NOT NULL, "invoice_amount" integer NOT NULL, "transaction_amount" integer NOT NULL, "swap_fee_sats" integer NOT NULL, "chain_fee_sats" integer NOT NULL, "ephemeral_public_key" varchar NOT NULL, "address" varchar NOT NULL, "ephemeral_private_key" varchar NOT NULL, "used" boolean NOT NULL DEFAULT (0), "preimage" varchar NOT NULL DEFAULT (''), "failure_reason" varchar NOT NULL DEFAULT (''), "tx_id" varchar NOT NULL DEFAULT (''), "service_url" varchar NOT NULL DEFAULT (''), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')))`);
await queryRunner.query(`DROP INDEX "recv_invoice_paid_serial"`);
await queryRunner.query(`DROP INDEX "IDX_a131e6b58f084f1340538681b5"`);
await queryRunner.query(`CREATE TABLE "temporary_user_receiving_invoice" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "invoice" varchar NOT NULL, "expires_at_unix" integer NOT NULL, "paid_at_unix" integer NOT NULL DEFAULT (0), "internal" boolean NOT NULL DEFAULT (0), "paidByLnd" boolean NOT NULL DEFAULT (0), "callbackUrl" varchar NOT NULL DEFAULT (''), "paid_amount" integer NOT NULL DEFAULT (0), "service_fee" integer NOT NULL DEFAULT (0), "zap_info" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "productProductId" varchar, "payerSerialId" integer, "linkedApplicationSerialId" integer, "liquidityProvider" varchar, "payer_data" text, "offer_id" varchar NOT NULL DEFAULT (''), "rejectUnauthorized" boolean NOT NULL DEFAULT (1), "bearer_token" varchar NOT NULL DEFAULT (''), "clink_requester_pub" varchar, "clink_requester_event_id" varchar, CONSTRAINT "FK_2c0dfb3483f3e5e7e3cdd5dc71f" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_5263bde2a519db9ea608b702ec8" FOREIGN KEY ("productProductId") REFERENCES "product" ("product_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_d4bb1e4c60e8a869f1f43ca2e31" FOREIGN KEY ("payerSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_714a8b7d4f89f8a802ca181b789" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_user_receiving_invoice"("serial_id", "invoice", "expires_at_unix", "paid_at_unix", "internal", "paidByLnd", "callbackUrl", "paid_amount", "service_fee", "zap_info", "created_at", "updated_at", "userSerialId", "productProductId", "payerSerialId", "linkedApplicationSerialId", "liquidityProvider", "payer_data", "offer_id", "rejectUnauthorized", "bearer_token", "clink_requester_pub", "clink_requester_event_id") SELECT "serial_id", "invoice", "expires_at_unix", "paid_at_unix", "internal", "paidByLnd", "callbackUrl", "paid_amount", "service_fee", "zap_info", "created_at", "updated_at", "userSerialId", "productProductId", "payerSerialId", "linkedApplicationSerialId", "liquidityProvider", "payer_data", "offer_id", "rejectUnauthorized", "bearer_token", "clink_requester_pub", "clink_requester_event_id" FROM "user_receiving_invoice"`);
await queryRunner.query(`DROP TABLE "user_receiving_invoice"`);
await queryRunner.query(`ALTER TABLE "temporary_user_receiving_invoice" RENAME TO "user_receiving_invoice"`);
await queryRunner.query(`CREATE INDEX "recv_invoice_paid_serial" ON "user_receiving_invoice" ("userSerialId", "paid_at_unix", "serial_id") WHERE paid_at_unix > 0`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a131e6b58f084f1340538681b5" ON "user_receiving_invoice" ("invoice") `);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP INDEX "IDX_a131e6b58f084f1340538681b5"`);
await queryRunner.query(`DROP INDEX "recv_invoice_paid_serial"`);
await queryRunner.query(`ALTER TABLE "user_receiving_invoice" RENAME TO "temporary_user_receiving_invoice"`);
await queryRunner.query(`CREATE TABLE "user_receiving_invoice" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "invoice" varchar NOT NULL, "expires_at_unix" integer NOT NULL, "paid_at_unix" integer NOT NULL DEFAULT (0), "internal" boolean NOT NULL DEFAULT (0), "paidByLnd" boolean NOT NULL DEFAULT (0), "callbackUrl" varchar NOT NULL DEFAULT (''), "paid_amount" integer NOT NULL DEFAULT (0), "service_fee" integer NOT NULL DEFAULT (0), "zap_info" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "productProductId" varchar, "payerSerialId" integer, "linkedApplicationSerialId" integer, "liquidityProvider" varchar, "payer_data" text, "offer_id" varchar NOT NULL DEFAULT (''), "rejectUnauthorized" boolean NOT NULL DEFAULT (1), "bearer_token" varchar NOT NULL DEFAULT (''), "clink_requester_pub" varchar(64), "clink_requester_event_id" varchar(64), CONSTRAINT "FK_2c0dfb3483f3e5e7e3cdd5dc71f" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_5263bde2a519db9ea608b702ec8" FOREIGN KEY ("productProductId") REFERENCES "product" ("product_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_d4bb1e4c60e8a869f1f43ca2e31" FOREIGN KEY ("payerSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_714a8b7d4f89f8a802ca181b789" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "user_receiving_invoice"("serial_id", "invoice", "expires_at_unix", "paid_at_unix", "internal", "paidByLnd", "callbackUrl", "paid_amount", "service_fee", "zap_info", "created_at", "updated_at", "userSerialId", "productProductId", "payerSerialId", "linkedApplicationSerialId", "liquidityProvider", "payer_data", "offer_id", "rejectUnauthorized", "bearer_token", "clink_requester_pub", "clink_requester_event_id") SELECT "serial_id", "invoice", "expires_at_unix", "paid_at_unix", "internal", "paidByLnd", "callbackUrl", "paid_amount", "service_fee", "zap_info", "created_at", "updated_at", "userSerialId", "productProductId", "payerSerialId", "linkedApplicationSerialId", "liquidityProvider", "payer_data", "offer_id", "rejectUnauthorized", "bearer_token", "clink_requester_pub", "clink_requester_event_id" FROM "temporary_user_receiving_invoice"`);
await queryRunner.query(`DROP TABLE "temporary_user_receiving_invoice"`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a131e6b58f084f1340538681b5" ON "user_receiving_invoice" ("invoice") `);
await queryRunner.query(`CREATE INDEX "recv_invoice_paid_serial" ON "user_receiving_invoice" ("userSerialId", "paid_at_unix", "serial_id") WHERE paid_at_unix > 0`);
await queryRunner.query(`DROP TABLE "invoice_swap"`);
}
}

View file

@ -32,6 +32,7 @@ import { TxSwapAddress1764779178945 } from './1764779178945-tx_swap_address.js'
import { ClinkRequester1765497600000 } from './1765497600000-clink_requester.js' import { ClinkRequester1765497600000 } from './1765497600000-clink_requester.js'
import { TrackedProviderHeight1766504040000 } from './1766504040000-tracked_provider_height.js' import { TrackedProviderHeight1766504040000 } from './1766504040000-tracked_provider_height.js'
import { SwapsServiceUrl1768413055036 } from './1768413055036-swaps_service_url.js' import { SwapsServiceUrl1768413055036 } from './1768413055036-swaps_service_url.js'
import { InvoiceSwaps1769529793283 } from './1769529793283-invoice_swaps.js'
export const allMigrations = [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, export const allMigrations = [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189,
@ -39,7 +40,7 @@ export const allMigrations = [Initial1703170309875, LspOrder1718387847693, Liqui
DebitToPub1727105758354, UserCbUrl1727112281043, UserOffer1733502626042, ManagementGrant1751307732346, ManagementGrantBanned1751989251513, DebitToPub1727105758354, UserCbUrl1727112281043, UserOffer1733502626042, ManagementGrant1751307732346, ManagementGrantBanned1751989251513,
InvoiceCallbackUrls1752425992291, OldSomethingLeftover1753106599604, UserReceivingInvoiceIdx1753109184611, AppUserDevice1753285173175, InvoiceCallbackUrls1752425992291, OldSomethingLeftover1753106599604, UserReceivingInvoiceIdx1753109184611, AppUserDevice1753285173175,
UserAccess1759426050669, AddBlindToUserOffer1760000000000, ApplicationAvatarUrl1761000001000, AdminSettings1761683639419, TxSwap1762890527098, UserAccess1759426050669, AddBlindToUserOffer1760000000000, ApplicationAvatarUrl1761000001000, AdminSettings1761683639419, TxSwap1762890527098,
TxSwapAddress1764779178945, ClinkRequester1765497600000, TrackedProviderHeight1766504040000, SwapsServiceUrl1768413055036] TxSwapAddress1764779178945, ClinkRequester1765497600000, TrackedProviderHeight1766504040000, SwapsServiceUrl1768413055036, InvoiceSwaps1769529793283]
export const allMetricsMigrations = [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195, BalanceEvents1724860966825, RootOps1732566440447, RootOpsTime1745428134124, ChannelEvents1750777346411] export const allMetricsMigrations = [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195, BalanceEvents1724860966825, RootOps1732566440447, RootOpsTime1745428134124, ChannelEvents1750777346411]
/* export const TypeOrmMigrationRunner = async (log: PubLogger, storageManager: Storage, settings: DbSettings, arg: string | undefined): Promise<boolean> => { /* export const TypeOrmMigrationRunner = async (log: PubLogger, storageManager: Storage, settings: DbSettings, arg: string | undefined): Promise<boolean> => {

View file

@ -473,20 +473,20 @@ export default class {
return this.dbs.FindOne<TransactionSwap>('TransactionSwap', { where: { swap_operation_id: swapOperationId, used: false, app_user_id: appUserId } }, txId) return this.dbs.FindOne<TransactionSwap>('TransactionSwap', { where: { swap_operation_id: swapOperationId, used: false, app_user_id: appUserId } }, txId)
} }
async FinalizeTransactionSwap(swapOperationId: string, address: string, txId: string) { async FinalizeTransactionSwap(swapOperationId: string, address: string, chainTxId: string, txId?: string) {
return this.dbs.Update<TransactionSwap>('TransactionSwap', { swap_operation_id: swapOperationId }, { return this.dbs.Update<TransactionSwap>('TransactionSwap', { swap_operation_id: swapOperationId }, {
used: true, used: true,
tx_id: txId, tx_id: chainTxId,
address_paid: address, address_paid: address,
}) }, txId)
} }
async FailTransactionSwap(swapOperationId: string, address: string, failureReason: string) { async FailTransactionSwap(swapOperationId: string, address: string, failureReason: string, txId?: string) {
return this.dbs.Update<TransactionSwap>('TransactionSwap', { swap_operation_id: swapOperationId }, { return this.dbs.Update<TransactionSwap>('TransactionSwap', { swap_operation_id: swapOperationId }, {
used: true, used: true,
failure_reason: failureReason, failure_reason: failureReason,
address_paid: address, address_paid: address,
}) }, txId)
} }
async DeleteTransactionSwap(swapOperationId: string, txId?: string) { async DeleteTransactionSwap(swapOperationId: string, txId?: string) {
@ -522,7 +522,51 @@ export default class {
} }
async GetInvoiceSwap(swapOperationId: string, appUserId: string, txId?: string) { async GetInvoiceSwap(swapOperationId: string, appUserId: string, txId?: string) {
return this.dbs.FindOne<InvoiceSwap>('InvoiceSwap', { where: { swap_operation_id: swapOperationId, used: false, app_user_id: appUserId } }, txId) const swap = await this.dbs.FindOne<InvoiceSwap>('InvoiceSwap', { where: { swap_operation_id: swapOperationId, used: false, app_user_id: appUserId } }, txId)
if (!swap || swap.tx_id) {
return null
}
return swap
}
async FinalizeInvoiceSwap(swapOperationId: string, txId?: string) {
return this.dbs.Update<InvoiceSwap>('InvoiceSwap', { swap_operation_id: swapOperationId }, {
used: true,
}, txId)
}
async SetInvoiceSwapTxId(swapOperationId: string, chainTxId: string, txId?: string) {
return this.dbs.Update<InvoiceSwap>('InvoiceSwap', { swap_operation_id: swapOperationId }, {
tx_id: chainTxId,
}, txId)
}
async FailInvoiceSwap(swapOperationId: string, failureReason: string, txId?: string) {
return this.dbs.Update<InvoiceSwap>('InvoiceSwap', { swap_operation_id: swapOperationId }, {
used: true,
failure_reason: failureReason,
}, txId)
}
async DeleteInvoiceSwap(swapOperationId: string, txId?: string) {
return this.dbs.Delete<InvoiceSwap>('InvoiceSwap', { swap_operation_id: swapOperationId }, txId)
}
async DeleteExpiredInvoiceSwaps(currentHeight: number, txId?: string) {
return this.dbs.Delete<InvoiceSwap>('InvoiceSwap', { timeout_block_height: LessThan(currentHeight) }, txId)
}
async ListCompletedInvoiceSwaps(appUserId: string, txId?: string) {
return this.dbs.Find<InvoiceSwap>('InvoiceSwap', { where: { used: true, app_user_id: appUserId } }, txId)
}
async ListPendingInvoiceSwaps(appUserId: string, txId?: string) {
return this.dbs.Find<InvoiceSwap>('InvoiceSwap', { where: { used: false, app_user_id: appUserId } }, txId)
}
async ListUnfinishedInvoiceSwaps(txId?: string) {
const swaps = await this.dbs.Find<InvoiceSwap>('InvoiceSwap', { where: { used: false } }, txId)
return swaps.filter(s => !s.tx_id)
} }
} }