Skip to content

Commit

Permalink
fix: tx pagination
Browse files Browse the repository at this point in the history
  • Loading branch information
UncleSamtoshi committed Nov 13, 2023
1 parent 8779294 commit d26a48b
Show file tree
Hide file tree
Showing 21 changed files with 360 additions and 487 deletions.
44 changes: 33 additions & 11 deletions core/api/src/app/accounts/get-account-transactions-for-contact.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { memoSharingConfig } from "@/config"
import { MAX_PAGINATION_PAGE_SIZE, memoSharingConfig } from "@/config"
import { LedgerError } from "@/domain/ledger"
import { checkedToPaginatedQueryArgs } from "@/domain/primitives"
import { WalletTransactionHistory } from "@/domain/wallets"

import { getNonEndUserWalletIds, LedgerService } from "@/services/ledger"
Expand All @@ -8,29 +9,50 @@ import { WalletsRepository } from "@/services/mongoose"
export const getAccountTransactionsForContact = async ({
account,
contactUsername,
paginationArgs,
rawPaginationArgs,
}: {
account: Account
contactUsername: Username
paginationArgs?: PaginationArgs
}): Promise<PaginatedArray<WalletTransaction> | ApplicationError> => {
rawPaginationArgs: {
first?: number | null
last?: number | null
before?: string | null
after?: string | null
}
}): Promise<PaginatedQueryResult<WalletTransaction> | ApplicationError> => {
const paginationArgs = checkedToPaginatedQueryArgs({
paginationArgs: rawPaginationArgs,
maxPageSize: MAX_PAGINATION_PAGE_SIZE,
})

if (paginationArgs instanceof Error) return paginationArgs

const ledger = LedgerService()

const wallets = await WalletsRepository().listByAccountId(account.id)
if (wallets instanceof Error) return wallets

const resp = await ledger.getTransactionsByWalletIdAndContactUsername({
const ledgerTxs = await ledger.getTransactionsByWalletIdAndContactUsername({
walletIds: wallets.map((wallet) => wallet.id),
contactUsername,
paginationArgs,
})
if (resp instanceof LedgerError) return resp
if (ledgerTxs instanceof LedgerError) return ledgerTxs

const nonEndUserWalletIds = Object.values(await getNonEndUserWalletIds())

const txEdges = ledgerTxs.edges.map((edge) => {
const { transactions } = WalletTransactionHistory.fromLedger({
ledgerTransactions: [edge.node],
nonEndUserWalletIds,
memoSharingConfig,
})

const confirmedHistory = WalletTransactionHistory.fromLedger({
ledgerTransactions: resp.slice,
nonEndUserWalletIds: Object.values(await getNonEndUserWalletIds()),
memoSharingConfig,
return {
cursor: edge.cursor,
node: transactions[0],
}
})

return { slice: confirmedHistory.transactions, total: resp.total }
return { ...ledgerTxs, edges: txEdges }
}
40 changes: 25 additions & 15 deletions core/api/src/app/accounts/get-transactions-for-account.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,44 @@
import { getTransactionsForWallets } from "../wallets"

import { PartialResult } from "../partial-result"

import { AccountValidator } from "@/domain/accounts"
import { RepositoryError } from "@/domain/errors"
import { WalletsRepository } from "@/services/mongoose"

export const getTransactionsForAccountByWalletIds = async ({
account,
walletIds,
paginationArgs,
rawPaginationArgs,
}: {
account: Account
walletIds: WalletId[]
paginationArgs?: PaginationArgs
}): Promise<PartialResult<PaginatedArray<WalletTransaction>>> => {
walletIds?: WalletId[]
rawPaginationArgs: {
first?: number | null
last?: number | null
before?: string | null
after?: string | null
}
}): Promise<PaginatedQueryResult<WalletTransaction> | ApplicationError> => {
const walletsRepo = WalletsRepository()

const wallets: Wallet[] = []
for (const walletId of walletIds) {
const wallet = await walletsRepo.findById(walletId)
if (wallet instanceof RepositoryError) return PartialResult.err(wallet)

const accountValidator = AccountValidator(account)
if (accountValidator instanceof Error) return PartialResult.err(accountValidator)
const validateWallet = accountValidator.validateWalletForAccount(wallet)
if (validateWallet instanceof Error) return PartialResult.err(validateWallet)
if (walletIds) {
for (const walletId of walletIds) {
const wallet = await walletsRepo.findById(walletId)
if (wallet instanceof RepositoryError) return wallet

const accountValidator = AccountValidator(account)
if (accountValidator instanceof Error) return accountValidator
const validateWallet = accountValidator.validateWalletForAccount(wallet)
if (validateWallet instanceof Error) return validateWallet

wallets.push(wallet)
wallets.push(wallet)
}
} else {
const accountWallets = await walletsRepo.listByAccountId(account.id)
if (accountWallets instanceof RepositoryError) return accountWallets
wallets.push(...accountWallets)
}

return getTransactionsForWallets({ wallets, paginationArgs })
return getTransactionsForWallets({ wallets, rawPaginationArgs })
}
75 changes: 37 additions & 38 deletions core/api/src/app/wallets/get-transactions-by-addresses.ts
Original file line number Diff line number Diff line change
@@ -1,61 +1,60 @@
import { memoSharingConfig } from "@/config"
import { PartialResult } from "@/app/partial-result"
import { MAX_PAGINATION_PAGE_SIZE, memoSharingConfig } from "@/config"

import { LedgerError } from "@/domain/ledger"
import { WalletTransactionHistory } from "@/domain/wallets"
import { CouldNotFindError } from "@/domain/errors"

import { getNonEndUserWalletIds, LedgerService } from "@/services/ledger"
import { WalletOnChainPendingReceiveRepository } from "@/services/mongoose"
import { checkedToPaginatedQueryArgs } from "@/domain/primitives"

export const getTransactionsForWalletsByAddresses = async ({
wallets,
addresses,
paginationArgs,
rawPaginationArgs,
}: {
wallets: Wallet[]
addresses: OnChainAddress[]
paginationArgs?: PaginationArgs
}): Promise<PartialResult<PaginatedArray<WalletTransaction>>> => {
const walletIds = wallets.map((wallet) => wallet.id)
rawPaginationArgs: {
first?: number | null
last?: number | null
before?: string | null
after?: string | null
}
}): Promise<PaginatedQueryResult<WalletTransaction> | ApplicationError> => {
const paginationArgs = checkedToPaginatedQueryArgs({
paginationArgs: rawPaginationArgs,
maxPageSize: MAX_PAGINATION_PAGE_SIZE,
})

let pendingHistory =
await WalletOnChainPendingReceiveRepository().listByWalletIdsAndAddresses({
walletIds,
addresses,
})
if (pendingHistory instanceof Error) {
if (pendingHistory instanceof CouldNotFindError) {
pendingHistory = []
} else {
return PartialResult.err(pendingHistory)
}
if (paginationArgs instanceof Error) {
return paginationArgs
}

const confirmedLedgerTxns = await LedgerService().getTransactionsByWalletIds({
const walletIds = wallets.map((wallet) => wallet.id)

const ledgerTxs = await LedgerService().getTransactionsByWalletIdsAndAddresses({
walletIds,
paginationArgs,
addresses,
})
if (confirmedLedgerTxns instanceof LedgerError) {
return PartialResult.partial(
{ slice: pendingHistory, total: pendingHistory.length },
confirmedLedgerTxns,
)

if (ledgerTxs instanceof LedgerError) {
return ledgerTxs
}
const ledgerTransactions = confirmedLedgerTxns.slice.filter(
(tx) => tx.address && addresses.includes(tx.address),
)

const confirmedHistory = WalletTransactionHistory.fromLedger({
ledgerTransactions,
nonEndUserWalletIds: Object.values(await getNonEndUserWalletIds()),
memoSharingConfig,
})

const transactions = [...pendingHistory, ...confirmedHistory.transactions]
const nonEndUserWalletIds = Object.values(await getNonEndUserWalletIds())

const txEdges = ledgerTxs.edges.map((edge) => {
const { transactions } = WalletTransactionHistory.fromLedger({
ledgerTransactions: [edge.node],
nonEndUserWalletIds,
memoSharingConfig,
})

return PartialResult.ok({
slice: transactions,
total: transactions.length,
return {
cursor: edge.cursor,
node: transactions[0],
}
})

return { ...ledgerTxs, edges: txEdges }
}
66 changes: 32 additions & 34 deletions core/api/src/app/wallets/get-transactions-for-wallet.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,53 @@
import { memoSharingConfig } from "@/config"
import { PartialResult } from "@/app/partial-result"
import { MAX_PAGINATION_PAGE_SIZE, memoSharingConfig } from "@/config"

import { LedgerError } from "@/domain/ledger"
import { WalletTransactionHistory } from "@/domain/wallets"
import { CouldNotFindError } from "@/domain/errors"

import { getNonEndUserWalletIds, LedgerService } from "@/services/ledger"
import { WalletOnChainPendingReceiveRepository } from "@/services/mongoose"
import { checkedToPaginatedQueryArgs } from "@/domain/primitives"

export const getTransactionsForWallets = async ({
wallets,
paginationArgs,
rawPaginationArgs,
}: {
wallets: Wallet[]
paginationArgs?: PaginationArgs
}): Promise<PartialResult<PaginatedArray<WalletTransaction>>> => {
const walletIds = wallets.map((wallet) => wallet.id)

let pendingHistory = await WalletOnChainPendingReceiveRepository().listByWalletIds({
walletIds,
})
if (pendingHistory instanceof Error) {
if (pendingHistory instanceof CouldNotFindError) {
pendingHistory = []
} else {
return PartialResult.err(pendingHistory)
}
rawPaginationArgs: {
first?: number | null
last?: number | null
before?: string | null
after?: string | null
}
}): Promise<PaginatedQueryResult<WalletTransaction> | ApplicationError> => {
const paginationArgs = checkedToPaginatedQueryArgs({
paginationArgs: rawPaginationArgs,
maxPageSize: MAX_PAGINATION_PAGE_SIZE,
})

if (paginationArgs instanceof Error) return paginationArgs

const confirmedLedgerTxns = await LedgerService().getTransactionsByWalletIds({
const walletIds = wallets.map((wallet) => wallet.id)

const ledgerTxs = await LedgerService().getTransactionsByWalletIds({
walletIds,
paginationArgs,
})

if (confirmedLedgerTxns instanceof LedgerError) {
return PartialResult.partial(
{ slice: pendingHistory, total: pendingHistory.length },
confirmedLedgerTxns,
)
}
if (ledgerTxs instanceof LedgerError) return ledgerTxs

const confirmedHistory = WalletTransactionHistory.fromLedger({
ledgerTransactions: confirmedLedgerTxns.slice,
nonEndUserWalletIds: Object.values(await getNonEndUserWalletIds()),
memoSharingConfig,
})
const nonEndUserWalletIds = Object.values(await getNonEndUserWalletIds())

const transactions = [...pendingHistory, ...confirmedHistory.transactions]
const txEdges = ledgerTxs.edges.map((edge) => {
const { transactions } = WalletTransactionHistory.fromLedger({
ledgerTransactions: [edge.node],
nonEndUserWalletIds,
memoSharingConfig,
})

return PartialResult.ok({
slice: transactions,
total: confirmedLedgerTxns.total + pendingHistory.length,
return {
cursor: edge.cursor,
node: transactions[0],
}
})

return { ...ledgerTxs, edges: txEdges }
}
22 changes: 16 additions & 6 deletions core/api/src/domain/ledger/index.types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ type LedgerError = import("./errors").LedgerError
type FeeDifferenceError = import("./errors").FeeDifferenceError
type LedgerServiceError = import("./errors").LedgerServiceError

type PaginationArgs = import("graphql-relay").ConnectionArguments

declare const liabilitiesWalletId: unique symbol
type LiabilitiesWalletId = string & { [liabilitiesWalletId]: never }

Expand Down Expand Up @@ -250,20 +248,32 @@ interface ILedgerService {
paymentHash: PaymentHash
}): Promise<LedgerTransaction<WalletCurrency>[] | LedgerServiceError>

getTransactionsByWalletIdsAndAddresses(args: {
walletIds: WalletId[]
addresses: OnChainAddress[]
paginationArgs: PaginatedQueryArgs
}): Promise<
PaginatedQueryResult<LedgerTransaction<WalletCurrency>> | LedgerServiceError
>

getTransactionsByWalletId(
walletId: WalletId,
): Promise<LedgerTransaction<WalletCurrency>[] | LedgerServiceError>

getTransactionsByWalletIds(args: {
walletIds: WalletId[]
paginationArgs?: PaginationArgs
}): Promise<PaginatedArray<LedgerTransaction<WalletCurrency>> | LedgerServiceError>
paginationArgs: PaginatedQueryArgs
}): Promise<
PaginatedQueryResult<LedgerTransaction<WalletCurrency>> | LedgerServiceError
>

getTransactionsByWalletIdAndContactUsername(args: {
walletIds: WalletId[]
contactUsername: Username
paginationArgs?: PaginationArgs
}): Promise<PaginatedArray<LedgerTransaction<WalletCurrency>> | LedgerServiceError>
paginationArgs: PaginatedQueryArgs
}): Promise<
PaginatedQueryResult<LedgerTransaction<WalletCurrency>> | LedgerServiceError
>

listPendingPayments(
walletId: WalletId,
Expand Down
4 changes: 2 additions & 2 deletions core/api/src/domain/wallet-on-chain/index.types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ interface IWalletOnChainAddressesRepository {

type ListWalletOnChainPendingReceiveArgs = {
walletIds: WalletId[]
paginationArgs?: PaginationArgs
paginationArgs?: PaginatedQueryArgs
}

type ListWalletOnChainPendingReceiveByAddressesArgs = {
walletIds: WalletId[]
addresses: OnChainAddress[]
paginationArgs?: PaginationArgs
paginationArgs?: PaginatedQueryArgs
}

type PersistWalletOnChainPendingReceiveArgs = WalletOnChainPendingTransaction
Expand Down
Loading

0 comments on commit d26a48b

Please sign in to comment.