From d9ecce8c6ad7670837627529514aaea0dde6caaf Mon Sep 17 00:00:00 2001 From: Sam Peters Date: Mon, 9 Oct 2023 13:38:40 -0500 Subject: [PATCH] feat: add txByHash and txById --- .../dev/apollo-federation/supergraph.graphql | 6 +++ .../src/app/wallets/get-transaction-by-id.ts | 18 ++++++- .../app/wallets/get-transactions-by-hash.ts | 19 ++++++++ core/api/src/graphql/admin/schema.graphql | 6 +++ core/api/src/graphql/public/schema.graphql | 6 +++ .../graphql/shared/types/abstract/wallet.ts | 18 ++++++- .../graphql/shared/types/object/btc-wallet.ts | 48 ++++++++++++++++++- .../graphql/shared/types/object/usd-wallet.ts | 48 ++++++++++++++++++- .../gql/transaction-for-wallet-by-hash.gql | 3 +- .../bats/gql/transaction-for-wallet-by-id.gql | 3 +- core/api/test/bats/ln-receive.bats | 2 +- 11 files changed, 170 insertions(+), 7 deletions(-) diff --git a/core/api/dev/apollo-federation/supergraph.graphql b/core/api/dev/apollo-federation/supergraph.graphql index 5a209d8b333..8061b582c32 100644 --- a/core/api/dev/apollo-federation/supergraph.graphql +++ b/core/api/dev/apollo-federation/supergraph.graphql @@ -187,6 +187,8 @@ type BTCWallet implements Wallet """An unconfirmed incoming onchain balance.""" pendingIncomingBalance: SignedAmount! + transactionByHash(hash: PaymentHash!): Transaction! + transactionById(transactionId: ID!): Transaction! """A list of BTC transactions associated with this wallet.""" transactions( @@ -1593,6 +1595,8 @@ type UsdWallet implements Wallet """An unconfirmed incoming onchain balance.""" pendingIncomingBalance: SignedAmount! + transactionByHash(hash: PaymentHash!): Transaction! + transactionById(transactionId: ID!): Transaction! transactions( """Returns the items in the list that come after the specified cursor.""" after: String @@ -1904,6 +1908,8 @@ interface Wallet id: ID! invoiceByHash(paymentHash: PaymentHash!): LnInvoice! pendingIncomingBalance: SignedAmount! + transactionByHash(hash: PaymentHash!): Transaction! + transactionById(transactionId: ID!): Transaction! """ Transactions are ordered anti-chronologically, diff --git a/core/api/src/app/wallets/get-transaction-by-id.ts b/core/api/src/app/wallets/get-transaction-by-id.ts index b6a2143183a..f6eb4c38065 100644 --- a/core/api/src/app/wallets/get-transaction-by-id.ts +++ b/core/api/src/app/wallets/get-transaction-by-id.ts @@ -1,9 +1,25 @@ import { memoSharingConfig } from "@/config" import { WalletTransactionHistory } from "@/domain/wallets" -import { checkedToLedgerTransactionId } from "@/domain/ledger" +import { + checkedToLedgerTransactionId, + CouldNotFindTransactionError, +} from "@/domain/ledger" import { getNonEndUserWalletIds, LedgerService } from "@/services/ledger" +export const getTransactionForWalletById = async ({ + walletId, + transactionId: uncheckedTransactionId, +}: { + walletId: WalletId + transactionId: string +}): Promise => { + const transaction = await getTransactionById(uncheckedTransactionId) + if (transaction instanceof Error) return transaction + if (transaction.walletId !== walletId) return new CouldNotFindTransactionError() + return transaction +} + export const getTransactionById = async ( id: string, ): Promise => { diff --git a/core/api/src/app/wallets/get-transactions-by-hash.ts b/core/api/src/app/wallets/get-transactions-by-hash.ts index 38ebd41b039..8b2c57734fa 100644 --- a/core/api/src/app/wallets/get-transactions-by-hash.ts +++ b/core/api/src/app/wallets/get-transactions-by-hash.ts @@ -1,8 +1,27 @@ import { memoSharingConfig } from "@/config" +import { CouldNotFindTransactionError } from "@/domain/ledger" import { WalletTransactionHistory } from "@/domain/wallets" import { getNonEndUserWalletIds, LedgerService } from "@/services/ledger" +export const getTransactionForWalletByHash = async ({ + walletId, + hash, +}: { + walletId: WalletId + hash: PaymentHash | OnChainTxHash +}): Promise => { + const transactions = await getTransactionsByHash(hash) + if (transactions instanceof Error) return transactions + const transaction = transactions.find( + (transaction) => transaction.walletId === walletId, + ) + + if (!transaction) return new CouldNotFindTransactionError() + + return transaction +} + export const getTransactionsByHash = async ( hash: PaymentHash | OnChainTxHash, ): Promise => { diff --git a/core/api/src/graphql/admin/schema.graphql b/core/api/src/graphql/admin/schema.graphql index 639106e526a..f3aa8656eae 100644 --- a/core/api/src/graphql/admin/schema.graphql +++ b/core/api/src/graphql/admin/schema.graphql @@ -89,6 +89,8 @@ type BTCWallet implements Wallet { """An unconfirmed incoming onchain balance.""" pendingIncomingBalance: SignedAmount! + transactionByHash(hash: PaymentHash!): Transaction! + transactionById(transactionId: ID!): Transaction! """A list of BTC transactions associated with this wallet.""" transactions( @@ -409,6 +411,8 @@ type UsdWallet implements Wallet { """An unconfirmed incoming onchain balance.""" pendingIncomingBalance: SignedAmount! + transactionByHash(hash: PaymentHash!): Transaction! + transactionById(transactionId: ID!): Transaction! transactions( """Returns the items in the list that come after the specified cursor.""" after: String @@ -458,6 +462,8 @@ interface Wallet { id: ID! invoiceByHash(paymentHash: PaymentHash!): LnInvoice! pendingIncomingBalance: SignedAmount! + transactionByHash(hash: PaymentHash!): Transaction! + transactionById(transactionId: ID!): Transaction! """ Transactions are ordered anti-chronologically, diff --git a/core/api/src/graphql/public/schema.graphql b/core/api/src/graphql/public/schema.graphql index 12128682eb9..adb3706d103 100644 --- a/core/api/src/graphql/public/schema.graphql +++ b/core/api/src/graphql/public/schema.graphql @@ -130,6 +130,8 @@ type BTCWallet implements Wallet { """An unconfirmed incoming onchain balance.""" pendingIncomingBalance: SignedAmount! + transactionByHash(hash: PaymentHash!): Transaction! + transactionById(transactionId: ID!): Transaction! """A list of BTC transactions associated with this wallet.""" transactions( @@ -1254,6 +1256,8 @@ type UsdWallet implements Wallet { """An unconfirmed incoming onchain balance.""" pendingIncomingBalance: SignedAmount! + transactionByHash(hash: PaymentHash!): Transaction! + transactionById(transactionId: ID!): Transaction! transactions( """Returns the items in the list that come after the specified cursor.""" after: String @@ -1497,6 +1501,8 @@ interface Wallet { id: ID! invoiceByHash(paymentHash: PaymentHash!): LnInvoice! pendingIncomingBalance: SignedAmount! + transactionByHash(hash: PaymentHash!): Transaction! + transactionById(transactionId: ID!): Transaction! """ Transactions are ordered anti-chronologically, diff --git a/core/api/src/graphql/shared/types/abstract/wallet.ts b/core/api/src/graphql/shared/types/abstract/wallet.ts index e76fd7143d9..278e415dd31 100644 --- a/core/api/src/graphql/shared/types/abstract/wallet.ts +++ b/core/api/src/graphql/shared/types/abstract/wallet.ts @@ -1,6 +1,6 @@ import dedent from "dedent" -import { TransactionConnection } from "../object/transaction" +import Transaction, { TransactionConnection } from "../object/transaction" import WalletCurrency from "../scalar/wallet-currency" import SignedAmount from "../scalar/signed-amount" import OnChainAddress from "../scalar/on-chain-address" @@ -55,6 +55,22 @@ const IWallet = GT.Interface({ }, }, }, + transactionByHash: { + type: GT.NonNull(Transaction), + args: { + hash: { + type: GT.NonNull(PaymentHash) || GT.NonNull(OnChainAddress), + }, + }, + }, + transactionById: { + type: GT.NonNull(Transaction), + args: { + transactionId: { + type: GT.NonNullID, + }, + }, + }, }), }) diff --git a/core/api/src/graphql/shared/types/object/btc-wallet.ts b/core/api/src/graphql/shared/types/object/btc-wallet.ts index 29e32cf2c2f..cbd617f80b6 100644 --- a/core/api/src/graphql/shared/types/object/btc-wallet.ts +++ b/core/api/src/graphql/shared/types/object/btc-wallet.ts @@ -8,7 +8,7 @@ import OnChainAddress from "../scalar/on-chain-address" import PaymentHash from "../scalar/payment-hash" -import { TransactionConnection } from "./transaction" +import Transaction, { TransactionConnection } from "./transaction" import { GT } from "@/graphql/index" import { normalizePaymentAmount } from "@/graphql/shared/root/mutation" @@ -153,6 +153,52 @@ const BtcWallet = GT.Object({ return invoice }, }, + transactionByHash: { + type: GT.NonNull(Transaction), + args: { + hash: { + type: GT.NonNull(PaymentHash) || GT.NonNull(OnChainAddress), + }, + }, + resolve: async (source, args) => { + const { hash } = args + if (hash instanceof Error) throw hash + + const transaction = await Wallets.getTransactionForWalletByHash({ + walletId: source.id, + hash, + }) + + if (transaction instanceof Error) { + throw mapError(transaction) + } + + return transaction + }, + }, + transactionById: { + type: GT.NonNull(Transaction), + args: { + transactionId: { + type: GT.NonNullID, + }, + }, + resolve: async (source, args) => { + const { transactionId } = args + if (transactionId instanceof Error) throw transactionId + + const transaction = await Wallets.getTransactionForWalletById({ + walletId: source.id, + transactionId, + }) + + if (transaction instanceof Error) { + throw mapError(transaction) + } + + return transaction + }, + }, }), }) diff --git a/core/api/src/graphql/shared/types/object/usd-wallet.ts b/core/api/src/graphql/shared/types/object/usd-wallet.ts index 0db758e01e5..e656fa015f7 100644 --- a/core/api/src/graphql/shared/types/object/usd-wallet.ts +++ b/core/api/src/graphql/shared/types/object/usd-wallet.ts @@ -8,7 +8,7 @@ import OnChainAddress from "../scalar/on-chain-address" import PaymentHash from "../scalar/payment-hash" -import { TransactionConnection } from "./transaction" +import Transaction, { TransactionConnection } from "./transaction" import { GT } from "@/graphql/index" import { @@ -149,6 +149,52 @@ const UsdWallet = GT.Object({ return invoice }, }, + transactionByHash: { + type: GT.NonNull(Transaction), + args: { + hash: { + type: GT.NonNull(PaymentHash) || GT.NonNull(OnChainAddress), + }, + }, + resolve: async (source, args) => { + const { hash } = args + if (hash instanceof Error) throw hash + + const transaction = await Wallets.getTransactionForWalletByHash({ + walletId: source.id, + hash, + }) + + if (transaction instanceof Error) { + throw mapError(transaction) + } + + return transaction + }, + }, + transactionById: { + type: GT.NonNull(Transaction), + args: { + transactionId: { + type: GT.NonNullID, + }, + }, + resolve: async (source, args) => { + const { transactionId } = args + if (transactionId instanceof Error) throw transactionId + + const transaction = await Wallets.getTransactionForWalletById({ + walletId: source.id, + transactionId, + }) + + if (transaction instanceof Error) { + throw mapError(transaction) + } + + return transaction + }, + }, }), }) diff --git a/core/api/test/bats/gql/transaction-for-wallet-by-hash.gql b/core/api/test/bats/gql/transaction-for-wallet-by-hash.gql index b6c46968123..ce02e5fe143 100644 --- a/core/api/test/bats/gql/transaction-for-wallet-by-hash.gql +++ b/core/api/test/bats/gql/transaction-for-wallet-by-hash.gql @@ -1,8 +1,9 @@ -query transactionForWalletByHash($walletId: WalletId!, $hash: PaymentHash! | OnChainTxHash!) { +query transactionForWalletByHash($walletId: WalletId!, $hash: PaymentHash!) { me { defaultAccount { displayCurrency walletById(walletId: $walletId) { + id transactionByHash(hash: $hash) { __typename id diff --git a/core/api/test/bats/gql/transaction-for-wallet-by-id.gql b/core/api/test/bats/gql/transaction-for-wallet-by-id.gql index 5b1eb2bad30..cc5c946f05b 100644 --- a/core/api/test/bats/gql/transaction-for-wallet-by-id.gql +++ b/core/api/test/bats/gql/transaction-for-wallet-by-id.gql @@ -1,9 +1,10 @@ query transactionForWalletById($walletId: WalletId!, $transactionId: ID!) { me { defaultAccount { + id displayCurrency walletById(walletId: $walletId) { - transactionById(id: $transactionId) { + transactionById(transactionId: $transactionId) { __typename id status diff --git a/core/api/test/bats/ln-receive.bats b/core/api/test/bats/ln-receive.bats index 960c32b5821..5414761f570 100644 --- a/core/api/test/bats/ln-receive.bats +++ b/core/api/test/bats/ln-receive.bats @@ -98,7 +98,7 @@ usd_amount=50 jq -n \ --arg wallet_id "$(read_value $btc_wallet_name)" \ --arg payment_hash "$payment_hash" \ - '{walletId: $wallet_id, paymentHash: $payment_hash}' + '{walletId: $wallet_id, hash: $payment_hash}' ) exec_graphql "$token_name" 'transaction-for-wallet-by-hash' "$variables"