Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: better expose invoices through gql api #3313

Merged
merged 19 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 48 additions & 2 deletions core/api/dev/apollo-federation/supergraph.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ interface Account
last: Int
walletIds: [WalletId]
): TransactionConnection
walletById(walletId: WalletId!): Wallet!
wallets: [Wallet!]!
}

Expand Down Expand Up @@ -178,9 +179,11 @@ type BTCWallet implements Wallet
"""A balance stored in BTC."""
balance: SignedAmount!
id: ID!
invoiceByPaymentHash(paymentHash: PaymentHash!): Invoice!

"""An unconfirmed incoming onchain balance."""
pendingIncomingBalance: SignedAmount!
transactionById(transactionId: ID!): Transaction!

"""A list of BTC transactions associated with this wallet."""
transactions(
Expand Down Expand Up @@ -212,6 +215,7 @@ type BTCWallet implements Wallet
"""Returns the last n items from the list."""
last: Int
): TransactionConnection
transactionsByPaymentHash(paymentHash: PaymentHash!): [Transaction!]!
walletCurrency: WalletCurrency!
}

Expand Down Expand Up @@ -324,6 +328,7 @@ type ConsumerAccount implements Account
last: Int
walletIds: [WalletId]
): TransactionConnection
walletById(walletId: WalletId!): Wallet!
wallets: [Wallet!]!
}

Expand Down Expand Up @@ -545,6 +550,25 @@ input IntraLedgerUsdPaymentSendInput
walletId: WalletId!
}

"""A lightning invoice."""
interface Invoice
@join__type(graph: PUBLIC)
{
"""The payment hash of the lightning invoice."""
paymentHash: PaymentHash!

"""The bolt11 invoice to be paid."""
paymentRequest: LnPaymentRequest!

"""
The payment secret of the lightning invoice. This is not the preimage of the payment hash.
"""
paymentSecret: LnPaymentSecret!

"""The payment status of the invoice."""
paymentStatus: InvoicePaymentStatus!
}

enum InvoicePaymentStatus
@join__type(graph: PUBLIC)
{
Expand Down Expand Up @@ -576,12 +600,14 @@ enum link__Purpose {
EXECUTION
}

type LnInvoice
type LnInvoice implements Invoice
@join__implements(graph: PUBLIC, interface: "Invoice")
@join__type(graph: PUBLIC)
{
paymentHash: PaymentHash!
paymentRequest: LnPaymentRequest!
paymentSecret: LnPaymentSecret!
paymentStatus: InvoicePaymentStatus!
satoshis: SatAmount
}

Expand Down Expand Up @@ -660,12 +686,14 @@ type LnInvoicePaymentStatusPayload
status: InvoicePaymentStatus
}

type LnNoAmountInvoice
type LnNoAmountInvoice implements Invoice
@join__implements(graph: PUBLIC, interface: "Invoice")
@join__type(graph: PUBLIC)
{
paymentHash: PaymentHash!
paymentRequest: LnPaymentRequest!
paymentSecret: LnPaymentSecret!
paymentStatus: InvoicePaymentStatus!
}

input LnNoAmountInvoiceCreateInput
Expand Down Expand Up @@ -1580,9 +1608,11 @@ type UsdWallet implements Wallet
accountId: ID!
balance: SignedAmount!
id: ID!
invoiceByPaymentHash(paymentHash: PaymentHash!): Invoice!

"""An unconfirmed incoming onchain balance."""
pendingIncomingBalance: SignedAmount!
transactionById(transactionId: ID!): Transaction!
transactions(
"""Returns the items in the list that come after the specified cursor."""
after: String
Expand Down Expand Up @@ -1612,6 +1642,7 @@ type UsdWallet implements Wallet
"""Returns the last n items from the list."""
last: Int
): TransactionConnection
transactionsByPaymentHash(paymentHash: PaymentHash!): [Transaction!]!
walletCurrency: WalletCurrency!
}

Expand Down Expand Up @@ -1879,7 +1910,14 @@ interface Wallet
accountId: ID!
balance: SignedAmount!
id: ID!
invoiceByPaymentHash(
"""
The lightning invoice with the matching paymentHash belonging to this wallet.
"""
paymentHash: PaymentHash!
): Invoice!
pendingIncomingBalance: SignedAmount!
transactionById(transactionId: ID!): Transaction!

"""
Transactions are ordered anti-chronologically,
Expand Down Expand Up @@ -1919,6 +1957,14 @@ interface Wallet
"""Returns the last n items from the list."""
last: Int
): TransactionConnection

"""
Returns the transactions that include this paymentHash. This should be a list of size one for a received lightning payment. This can be more that one transaction for a sent lightning payment.
"""
transactionsByPaymentHash(
"""The payment hash of the lightning invoice paid in this transaction."""
paymentHash: PaymentHash!
): [Transaction!]!
walletCurrency: WalletCurrency!
}

Expand Down
2 changes: 1 addition & 1 deletion core/api/src/app/payments/update-pending-payments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export const updatePendingPaymentByHash = wrapAsyncToRunInSpan({
paymentHash: PaymentHash
logger: Logger
}): Promise<void | ApplicationError> => {
const walletId = await LedgerService().getWalletIdByTransactionHash(paymentHash)
const walletId = await LedgerService().getWalletIdByPaymentHash(paymentHash)
if (walletId instanceof Error) return walletId

return updatePendingPaymentsByWalletId({
Expand Down
25 changes: 12 additions & 13 deletions core/api/src/app/wallets/add-invoice-for-wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const addInvoiceForSelf = async ({
walletAmount,
memo = "",
expiresIn,
}: AddInvoiceForSelfArgs): Promise<LnInvoice | ApplicationError> =>
}: AddInvoiceForSelfArgs): Promise<WalletInvoice | ApplicationError> =>
addInvoice({
walletId,
limitCheckFn: checkSelfWalletIdRateLimits,
Expand All @@ -45,7 +45,7 @@ const addInvoiceForSelf = async ({

export const addInvoiceForSelfForBtcWallet = async (
args: AddInvoiceForSelfForBtcWalletArgs,
): Promise<LnInvoice | ApplicationError> => {
): Promise<WalletInvoice | ApplicationError> => {
const walletId = checkedToWalletId(args.walletId)
if (walletId instanceof Error) return walletId

Expand All @@ -63,7 +63,7 @@ export const addInvoiceForSelfForBtcWallet = async (

export const addInvoiceForSelfForUsdWallet = async (
args: AddInvoiceForSelfForUsdWalletArgs,
): Promise<LnInvoice | ApplicationError> => {
): Promise<WalletInvoice | ApplicationError> => {
const walletId = checkedToWalletId(args.walletId)
if (walletId instanceof Error) return walletId

Expand All @@ -83,7 +83,7 @@ export const addInvoiceNoAmountForSelf = async ({
walletId,
memo = "",
expiresIn,
}: AddInvoiceNoAmountForSelfArgs): Promise<LnInvoice | ApplicationError> => {
}: AddInvoiceNoAmountForSelfArgs): Promise<WalletInvoice | ApplicationError> => {
const walletIdChecked = checkedToWalletId(walletId)
if (walletIdChecked instanceof Error) return walletIdChecked

Expand Down Expand Up @@ -118,7 +118,7 @@ const addInvoiceForRecipient = async ({
memo = "",
descriptionHash,
expiresIn,
}: AddInvoiceForRecipientArgs): Promise<LnInvoice | ApplicationError> =>
}: AddInvoiceForRecipientArgs): Promise<WalletInvoice | ApplicationError> =>
addInvoice({
walletId: recipientWalletId,
limitCheckFn: checkRecipientWalletIdRateLimits,
Expand All @@ -136,7 +136,7 @@ const addInvoiceForRecipient = async ({

export const addInvoiceForRecipientForBtcWallet = async (
args: AddInvoiceForRecipientForBtcWalletArgs,
): Promise<LnInvoice | ApplicationError> => {
): Promise<WalletInvoice | ApplicationError> => {
const recipientWalletId = checkedToWalletId(args.recipientWalletId)
if (recipientWalletId instanceof Error) return recipientWalletId

Expand All @@ -160,7 +160,7 @@ export const addInvoiceForRecipientForBtcWallet = async (

export const addInvoiceForRecipientForUsdWallet = async (
args: AddInvoiceForRecipientForUsdWalletArgs,
): Promise<LnInvoice | ApplicationError> => {
): Promise<WalletInvoice | ApplicationError> => {
const recipientWalletId = checkedToWalletId(args.recipientWalletId)
if (recipientWalletId instanceof Error) return recipientWalletId

Expand All @@ -184,7 +184,7 @@ export const addInvoiceForRecipientForUsdWallet = async (

export const addInvoiceForRecipientForUsdWalletAndBtcAmount = async (
args: AddInvoiceForRecipientForUsdWalletArgs,
): Promise<LnInvoice | ApplicationError> => {
): Promise<WalletInvoice | ApplicationError> => {
const recipientWalletId = checkedToWalletId(args.recipientWalletId)
if (recipientWalletId instanceof Error) return recipientWalletId

Expand All @@ -210,7 +210,7 @@ export const addInvoiceNoAmountForRecipient = async ({
recipientWalletId,
memo = "",
expiresIn,
}: AddInvoiceNoAmountForRecipientArgs): Promise<LnInvoice | ApplicationError> => {
}: AddInvoiceNoAmountForRecipientArgs): Promise<WalletInvoice | ApplicationError> => {
const walletId = checkedToWalletId(recipientWalletId)
if (walletId instanceof Error) return walletId

Expand Down Expand Up @@ -243,7 +243,7 @@ const addInvoice = async ({
walletId,
limitCheckFn,
buildWIBWithAmountFn,
}: AddInvoiceArgs): Promise<LnInvoice | ApplicationError> => {
}: AddInvoiceArgs): Promise<WalletInvoice | ApplicationError> => {
const wallet = await WalletsRepository().findById(walletId)
if (wallet instanceof Error) return wallet
const account = await AccountsRepository().findById(wallet.accountId)
Expand Down Expand Up @@ -275,12 +275,11 @@ const addInvoice = async ({

const invoice = await walletIBWithAmount.registerInvoice()
if (invoice instanceof Error) return invoice
const { walletInvoice, lnInvoice } = invoice

const persistedInvoice = await WalletInvoicesRepository().persistNew(walletInvoice)
const persistedInvoice = await WalletInvoicesRepository().persistNew(invoice)
if (persistedInvoice instanceof Error) return persistedInvoice

return lnInvoice
return invoice
}

const checkSelfWalletIdRateLimits = async (
Expand Down
16 changes: 16 additions & 0 deletions core/api/src/app/wallets/get-invoice-for-wallet-by-hash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { WalletInvoicesRepository } from "@/services/mongoose"

export const getInvoiceForWalletByPaymentHash = ({
walletId,
paymentHash,
}: {
walletId: WalletId
paymentHash: PaymentHash
}): Promise<WalletInvoice | ApplicationError> => {
const walletInvoicesRepository = WalletInvoicesRepository()

return walletInvoicesRepository.findForWalletByPaymentHash({
walletId,
paymentHash,
})
}
25 changes: 25 additions & 0 deletions core/api/src/app/wallets/get-transaction-by-id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,31 @@ import { checkedToLedgerTransactionId } from "@/domain/ledger"

import { getNonEndUserWalletIds, LedgerService } from "@/services/ledger"

export const getTransactionForWalletById = async ({
walletId,
transactionId: uncheckedTransactionId,
}: {
walletId: WalletId
transactionId: string
}): Promise<WalletTransaction | ApplicationError> => {
const ledger = LedgerService()

const ledgerTransactionId = checkedToLedgerTransactionId(uncheckedTransactionId)
if (ledgerTransactionId instanceof Error) return ledgerTransactionId

const ledgerTransaction = await ledger.getTransactionForWalletById({
walletId,
transactionId: ledgerTransactionId,
})
if (ledgerTransaction instanceof Error) return ledgerTransaction

return WalletTransactionHistory.fromLedger({
ledgerTransactions: [ledgerTransaction],
nonEndUserWalletIds: Object.values(await getNonEndUserWalletIds()),
memoSharingConfig,
}).transactions[0]
}

export const getTransactionById = async (
id: string,
): Promise<WalletTransaction | ApplicationError> => {
Expand Down
22 changes: 22 additions & 0 deletions core/api/src/app/wallets/get-transactions-by-hash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,28 @@ import { WalletTransactionHistory } from "@/domain/wallets"

import { getNonEndUserWalletIds, LedgerService } from "@/services/ledger"

export const getTransactionsForWalletByPaymentHash = async ({
walletId,
paymentHash,
}: {
walletId: WalletId
paymentHash: PaymentHash
}): Promise<WalletTransaction[] | ApplicationError> => {
const ledger = LedgerService()
const ledgerTransactions = await ledger.getTransactionsForWalletByPaymentHash({
walletId,
paymentHash,
})

if (ledgerTransactions instanceof Error) return ledgerTransactions

return WalletTransactionHistory.fromLedger({
ledgerTransactions,
nonEndUserWalletIds: Object.values(await getNonEndUserWalletIds()),
memoSharingConfig,
}).transactions
}

export const getTransactionsByHash = async (
hash: PaymentHash | OnChainTxHash,
): Promise<WalletTransaction[] | ApplicationError> => {
Expand Down
16 changes: 16 additions & 0 deletions core/api/src/app/wallets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export * from "./settle-payout-txn"
export * from "./update-legacy-on-chain-receipt"
export * from "./update-pending-invoices"
export * from "./validate"
export * from "./get-invoice-for-wallet-by-hash"

import { WalletsRepository } from "@/services/mongoose"

Expand All @@ -24,6 +25,21 @@ export const getWallet = async (walletId: WalletId) => {
return wallets.findById(walletId)
}

export const getWalletForAccountById = ({
accountId,
walletId,
}: {
accountId: AccountId
walletId: WalletId
}): Promise<Wallet | ApplicationError> => {
const wallets = WalletsRepository()

return wallets.findForAccountById({
accountId,
walletId,
})
}

export const listWalletsByAccountId = async (
accountId: AccountId,
): Promise<Wallet[] | RepositoryError> => {
Expand Down
Loading
Loading