diff --git a/apps/consent/app/graphql/generated.ts b/apps/consent/app/graphql/generated.ts index 0fb979af92..ed0d915a39 100644 --- a/apps/consent/app/graphql/generated.ts +++ b/apps/consent/app/graphql/generated.ts @@ -638,6 +638,7 @@ export type LnInvoiceCreateInput = { readonly amount: Scalars['SatAmount']['input']; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** Wallet ID for a BTC wallet belonging to the current account. */ @@ -650,6 +651,7 @@ export type LnInvoiceCreateOnBehalfOfRecipientInput = { readonly descriptionHash?: InputMaybe; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** Wallet ID for a BTC wallet which belongs to any account. */ @@ -716,6 +718,7 @@ export type LnNoAmountInvoice = Invoice & { export type LnNoAmountInvoiceCreateInput = { /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** ID for either a USD or BTC wallet belonging to the account of the current user. */ @@ -725,6 +728,7 @@ export type LnNoAmountInvoiceCreateInput = { export type LnNoAmountInvoiceCreateOnBehalfOfRecipientInput = { /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** ID for either a USD or BTC wallet which belongs to the account of any user. */ @@ -787,6 +791,7 @@ export type LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipientInput = { readonly descriptionHash?: InputMaybe; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. Acts as a note to the recipient. */ readonly memo?: InputMaybe; /** Wallet ID for a USD wallet which belongs to the account of any user. */ @@ -798,6 +803,7 @@ export type LnUsdInvoiceCreateInput = { readonly amount: Scalars['CentAmount']['input']; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** Wallet ID for a USD wallet belonging to the current user. */ @@ -810,6 +816,7 @@ export type LnUsdInvoiceCreateOnBehalfOfRecipientInput = { readonly descriptionHash?: InputMaybe; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. Acts as a note to the recipient. */ readonly memo?: InputMaybe; /** Wallet ID for a USD wallet which belongs to the account of any user. */ diff --git a/apps/dashboard/services/graphql/generated.ts b/apps/dashboard/services/graphql/generated.ts index f20118fd94..54844859fc 100644 --- a/apps/dashboard/services/graphql/generated.ts +++ b/apps/dashboard/services/graphql/generated.ts @@ -678,6 +678,7 @@ export type LnInvoiceCreateInput = { readonly amount: Scalars['SatAmount']['input']; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** Wallet ID for a BTC wallet belonging to the current account. */ @@ -690,6 +691,7 @@ export type LnInvoiceCreateOnBehalfOfRecipientInput = { readonly descriptionHash?: InputMaybe; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** Wallet ID for a BTC wallet which belongs to any account. */ @@ -756,6 +758,7 @@ export type LnNoAmountInvoice = Invoice & { export type LnNoAmountInvoiceCreateInput = { /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** ID for either a USD or BTC wallet belonging to the account of the current user. */ @@ -765,6 +768,7 @@ export type LnNoAmountInvoiceCreateInput = { export type LnNoAmountInvoiceCreateOnBehalfOfRecipientInput = { /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** ID for either a USD or BTC wallet which belongs to the account of any user. */ @@ -827,6 +831,7 @@ export type LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipientInput = { readonly descriptionHash?: InputMaybe; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. Acts as a note to the recipient. */ readonly memo?: InputMaybe; /** Wallet ID for a USD wallet which belongs to the account of any user. */ @@ -838,6 +843,7 @@ export type LnUsdInvoiceCreateInput = { readonly amount: Scalars['CentAmount']['input']; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** Wallet ID for a USD wallet belonging to the current user. */ @@ -850,6 +856,7 @@ export type LnUsdInvoiceCreateOnBehalfOfRecipientInput = { readonly descriptionHash?: InputMaybe; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. Acts as a note to the recipient. */ readonly memo?: InputMaybe; /** Wallet ID for a USD wallet which belongs to the account of any user. */ diff --git a/apps/map/services/galoy/graphql/generated.ts b/apps/map/services/galoy/graphql/generated.ts index 6b1e3b0601..c2fda7073f 100644 --- a/apps/map/services/galoy/graphql/generated.ts +++ b/apps/map/services/galoy/graphql/generated.ts @@ -638,6 +638,7 @@ export type LnInvoiceCreateInput = { readonly amount: Scalars['SatAmount']['input']; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** Wallet ID for a BTC wallet belonging to the current account. */ @@ -650,6 +651,7 @@ export type LnInvoiceCreateOnBehalfOfRecipientInput = { readonly descriptionHash?: InputMaybe; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** Wallet ID for a BTC wallet which belongs to any account. */ @@ -716,6 +718,7 @@ export type LnNoAmountInvoice = Invoice & { export type LnNoAmountInvoiceCreateInput = { /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** ID for either a USD or BTC wallet belonging to the account of the current user. */ @@ -725,6 +728,7 @@ export type LnNoAmountInvoiceCreateInput = { export type LnNoAmountInvoiceCreateOnBehalfOfRecipientInput = { /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** ID for either a USD or BTC wallet which belongs to the account of any user. */ @@ -787,6 +791,7 @@ export type LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipientInput = { readonly descriptionHash?: InputMaybe; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. Acts as a note to the recipient. */ readonly memo?: InputMaybe; /** Wallet ID for a USD wallet which belongs to the account of any user. */ @@ -798,6 +803,7 @@ export type LnUsdInvoiceCreateInput = { readonly amount: Scalars['CentAmount']['input']; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** Wallet ID for a USD wallet belonging to the current user. */ @@ -810,6 +816,7 @@ export type LnUsdInvoiceCreateOnBehalfOfRecipientInput = { readonly descriptionHash?: InputMaybe; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. Acts as a note to the recipient. */ readonly memo?: InputMaybe; /** Wallet ID for a USD wallet which belongs to the account of any user. */ diff --git a/apps/pay/lib/graphql/generated.ts b/apps/pay/lib/graphql/generated.ts index 0596d77678..9ec4ef0e33 100644 --- a/apps/pay/lib/graphql/generated.ts +++ b/apps/pay/lib/graphql/generated.ts @@ -637,6 +637,7 @@ export type LnInvoiceCreateInput = { readonly amount: Scalars['SatAmount']; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** Wallet ID for a BTC wallet belonging to the current account. */ @@ -649,6 +650,7 @@ export type LnInvoiceCreateOnBehalfOfRecipientInput = { readonly descriptionHash?: InputMaybe; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** Wallet ID for a BTC wallet which belongs to any account. */ @@ -715,6 +717,7 @@ export type LnNoAmountInvoice = Invoice & { export type LnNoAmountInvoiceCreateInput = { /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** ID for either a USD or BTC wallet belonging to the account of the current user. */ @@ -724,6 +727,7 @@ export type LnNoAmountInvoiceCreateInput = { export type LnNoAmountInvoiceCreateOnBehalfOfRecipientInput = { /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** ID for either a USD or BTC wallet which belongs to the account of any user. */ @@ -786,6 +790,7 @@ export type LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipientInput = { readonly descriptionHash?: InputMaybe; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. Acts as a note to the recipient. */ readonly memo?: InputMaybe; /** Wallet ID for a USD wallet which belongs to the account of any user. */ @@ -797,6 +802,7 @@ export type LnUsdInvoiceCreateInput = { readonly amount: Scalars['CentAmount']; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. */ readonly memo?: InputMaybe; /** Wallet ID for a USD wallet belonging to the current user. */ @@ -809,6 +815,7 @@ export type LnUsdInvoiceCreateOnBehalfOfRecipientInput = { readonly descriptionHash?: InputMaybe; /** Optional invoice expiration time in minutes. */ readonly expiresIn?: InputMaybe; + readonly externalId?: InputMaybe; /** Optional memo for the lightning invoice. Acts as a note to the recipient. */ readonly memo?: InputMaybe; /** Wallet ID for a USD wallet which belongs to the account of any user. */ diff --git a/bats/core/api/invoices.bats b/bats/core/api/invoices.bats index e4d6d05b36..87523eaf79 100644 --- a/bats/core/api/invoices.bats +++ b/bats/core/api/invoices.bats @@ -25,11 +25,13 @@ seed_invoices() { ) exec_graphql "$token_name" 'ln-invoice-create' "$variables" + external_id="seed-$RANDOM" variables=$( jq -n \ --arg wallet_id "$(read_value $btc_wallet_name)" \ --arg amount "$btc_amount" \ - '{input: {walletId: $wallet_id, amount: $amount}}' + --arg external_id "$external_id" \ + '{input: {walletId: $wallet_id, amount: $amount, externalId: $external_id}}' ) exec_graphql "$token_name" 'ln-invoice-create' "$variables" @@ -67,6 +69,31 @@ seed_invoices() { [[ "$num_errors" == "0" ]] || exit 1 } +@test "invoices: adding multiple invoices with same external id fails" { + token_name='alice' + btc_wallet_name="$token_name.btc_wallet_id" + btc_amount="1000" + external_id="external-id-$RANDOM" + + variables=$( + jq -n \ + --arg wallet_id "$(read_value $btc_wallet_name)" \ + --arg amount "$btc_amount" \ + --arg external_id "$external_id" \ + '{input: {walletId: $wallet_id, amount: $amount, externalId: $external_id}}' + ) + + exec_graphql "$token_name" 'ln-invoice-create' "$variables" + num_errors="$(graphql_output '.data.lnInvoiceCreate.errors | length')" + [[ "$num_errors" == "0" ]] || exit 1 + + exec_graphql "$token_name" 'ln-invoice-create' "$variables" + invoice="$(graphql_output '.data.lnInvoiceCreate.invoice')" + [[ "$invoice" == "null" ]] || exit 1 + error_msg="$(graphql_output '.data.lnInvoiceCreate.errors[0].message')" + [[ "${error_msg}" =~ "already exists" ]] || exit 1 +} + @test "invoices: get invoices for account" { token_name='alice' diff --git a/bats/core/api/ln-receive.bats b/bats/core/api/ln-receive.bats index 09a3b89810..007c5dc1db 100644 --- a/bats/core/api/ln-receive.bats +++ b/bats/core/api/ln-receive.bats @@ -46,11 +46,13 @@ usd_amount=50 num_callback_events_before=$(cat_callback | grep "$account_id" | wc -l) # Generate invoice + external_id="test-$RANDOM" variables=$( jq -n \ --arg wallet_id "$(read_value $btc_wallet_name)" \ --arg amount "$btc_amount" \ - '{input: {walletId: $wallet_id, amount: $amount}}' + --arg external_id "$external_id" \ + '{input: {walletId: $wallet_id, amount: $amount, externalId: $external_id}}' ) exec_graphql "$token_name" 'ln-invoice-create' "$variables" invoice="$(graphql_output '.data.lnInvoiceCreate.invoice')" @@ -165,7 +167,7 @@ usd_amount=50 | awk 'BEGIN{RS="callback │ "}{if(NR>1)print $0}' \ | jq -r '.transaction.externalId' ) - [[ "$external_id_from_callback" == "$payment_hash" ]] || exit 1 + [[ "$external_id_from_callback" == "$external_id" ]] || exit 1 } @test "ln-receive: settle via ln for USD wallet, invoice with amount" { diff --git a/core/api/src/graphql/public/root/mutation/ln-invoice-create-on-behalf-of-recipient.ts b/core/api/src/graphql/public/root/mutation/ln-invoice-create-on-behalf-of-recipient.ts index 80ecf0a2f1..5693aaf0de 100644 --- a/core/api/src/graphql/public/root/mutation/ln-invoice-create-on-behalf-of-recipient.ts +++ b/core/api/src/graphql/public/root/mutation/ln-invoice-create-on-behalf-of-recipient.ts @@ -8,6 +8,7 @@ import Minutes from "@/graphql/public/types/scalar/minutes" import WalletId from "@/graphql/shared/types/scalar/wallet-id" import SatAmount from "@/graphql/shared/types/scalar/sat-amount" import Hex32Bytes from "@/graphql/public/types/scalar/hex32bytes" +import TxExternalId from "@/graphql/shared/types/scalar/tx-external-id" import LnInvoicePayload from "@/graphql/public/types/payload/ln-invoice" import { mapAndParseErrorForGqlResponse } from "@/graphql/error-map" @@ -25,6 +26,7 @@ const LnInvoiceCreateOnBehalfOfRecipientInput = GT.Input({ type: Minutes, description: "Optional invoice expiration time in minutes.", }, + externalId: { type: TxExternalId }, }), }) @@ -40,8 +42,16 @@ const LnInvoiceCreateOnBehalfOfRecipientMutation = GT.Field({ input: { type: GT.NonNull(LnInvoiceCreateOnBehalfOfRecipientInput) }, }, resolve: async (_, args) => { - const { recipientWalletId, amount, memo, descriptionHash, expiresIn } = args.input - for (const input of [recipientWalletId, amount, memo, descriptionHash, expiresIn]) { + const { recipientWalletId, amount, memo, descriptionHash, expiresIn, externalId } = + args.input + for (const input of [ + recipientWalletId, + amount, + memo, + descriptionHash, + expiresIn, + externalId, + ]) { if (input instanceof Error) { return { errors: [{ message: input.message }] } } @@ -53,7 +63,7 @@ const LnInvoiceCreateOnBehalfOfRecipientMutation = GT.Field({ memo, descriptionHash, expiresIn, - externalId: undefined, + externalId, }) if (invoice instanceof Error) { diff --git a/core/api/src/graphql/public/root/mutation/ln-invoice-create.ts b/core/api/src/graphql/public/root/mutation/ln-invoice-create.ts index afcb977d59..522da0a394 100644 --- a/core/api/src/graphql/public/root/mutation/ln-invoice-create.ts +++ b/core/api/src/graphql/public/root/mutation/ln-invoice-create.ts @@ -7,6 +7,7 @@ import Memo from "@/graphql/shared/types/scalar/memo" import Minutes from "@/graphql/public/types/scalar/minutes" import WalletId from "@/graphql/shared/types/scalar/wallet-id" import SatAmount from "@/graphql/shared/types/scalar/sat-amount" +import TxExternalId from "@/graphql/shared/types/scalar/tx-external-id" import LnInvoicePayload from "@/graphql/public/types/payload/ln-invoice" import { mapAndParseErrorForGqlResponse } from "@/graphql/error-map" @@ -23,6 +24,7 @@ const LnInvoiceCreateInput = GT.Input({ type: Minutes, description: "Optional invoice expiration time in minutes.", }, + externalId: { type: TxExternalId }, }), }) @@ -38,9 +40,9 @@ const LnInvoiceCreateMutation = GT.Field({ input: { type: GT.NonNull(LnInvoiceCreateInput) }, }, resolve: async (_, args) => { - const { walletId, amount, memo, expiresIn } = args.input + const { walletId, amount, memo, expiresIn, externalId } = args.input - for (const input of [walletId, amount, memo, expiresIn]) { + for (const input of [walletId, amount, memo, expiresIn, externalId]) { if (input instanceof Error) { return { errors: [{ message: input.message }] } } @@ -51,7 +53,7 @@ const LnInvoiceCreateMutation = GT.Field({ amount, memo, expiresIn, - externalId: undefined, + externalId, }) if (invoice instanceof Error) { diff --git a/core/api/src/graphql/public/root/mutation/ln-noamount-invoice-create-on-behalf-of-recipient.ts b/core/api/src/graphql/public/root/mutation/ln-noamount-invoice-create-on-behalf-of-recipient.ts index 3532acca9d..fd9763565c 100644 --- a/core/api/src/graphql/public/root/mutation/ln-noamount-invoice-create-on-behalf-of-recipient.ts +++ b/core/api/src/graphql/public/root/mutation/ln-noamount-invoice-create-on-behalf-of-recipient.ts @@ -5,6 +5,7 @@ import { Wallets } from "@/app" import { GT } from "@/graphql/index" import Memo from "@/graphql/shared/types/scalar/memo" import Minutes from "@/graphql/public/types/scalar/minutes" +import TxExternalId from "@/graphql/shared/types/scalar/tx-external-id" import WalletId from "@/graphql/shared/types/scalar/wallet-id" import { mapAndParseErrorForGqlResponse } from "@/graphql/error-map" import LnNoAmountInvoicePayload from "@/graphql/public/types/payload/ln-noamount-invoice" @@ -22,6 +23,7 @@ const LnNoAmountInvoiceCreateOnBehalfOfRecipientInput = GT.Input({ type: Minutes, description: "Optional invoice expiration time in minutes.", }, + externalId: { type: TxExternalId }, }), }) @@ -37,9 +39,9 @@ const LnNoAmountInvoiceCreateOnBehalfOfRecipientMutation = GT.Field({ input: { type: GT.NonNull(LnNoAmountInvoiceCreateOnBehalfOfRecipientInput) }, }, resolve: async (_, args) => { - const { recipientWalletId, memo, expiresIn } = args.input + const { recipientWalletId, memo, expiresIn, externalId } = args.input - for (const input of [recipientWalletId, memo, expiresIn]) { + for (const input of [recipientWalletId, memo, expiresIn, externalId]) { if (input instanceof Error) { return { errors: [{ message: input.message }] } } @@ -49,7 +51,7 @@ const LnNoAmountInvoiceCreateOnBehalfOfRecipientMutation = GT.Field({ recipientWalletId, memo, expiresIn, - externalId: undefined, + externalId, }) if (invoice instanceof Error) { diff --git a/core/api/src/graphql/public/root/mutation/ln-noamount-invoice-create.ts b/core/api/src/graphql/public/root/mutation/ln-noamount-invoice-create.ts index d8673835a5..5cf4c8eb45 100644 --- a/core/api/src/graphql/public/root/mutation/ln-noamount-invoice-create.ts +++ b/core/api/src/graphql/public/root/mutation/ln-noamount-invoice-create.ts @@ -5,6 +5,7 @@ import { Wallets } from "@/app" import { GT } from "@/graphql/index" import Memo from "@/graphql/shared/types/scalar/memo" import Minutes from "@/graphql/public/types/scalar/minutes" +import TxExternalId from "@/graphql/shared/types/scalar/tx-external-id" import WalletId from "@/graphql/shared/types/scalar/wallet-id" import { mapAndParseErrorForGqlResponse } from "@/graphql/error-map" import LnNoAmountInvoicePayload from "@/graphql/public/types/payload/ln-noamount-invoice" @@ -22,6 +23,7 @@ const LnNoAmountInvoiceCreateInput = GT.Input({ type: Minutes, description: "Optional invoice expiration time in minutes.", }, + externalId: { type: TxExternalId }, }), }) @@ -37,9 +39,9 @@ const LnNoAmountInvoiceCreateMutation = GT.Field({ input: { type: GT.NonNull(LnNoAmountInvoiceCreateInput) }, }, resolve: async (_, args) => { - const { walletId, memo, expiresIn } = args.input + const { walletId, memo, expiresIn, externalId } = args.input - for (const input of [walletId, memo, expiresIn]) { + for (const input of [walletId, memo, expiresIn, externalId]) { if (input instanceof Error) { return { errors: [{ message: input.message }] } } @@ -49,7 +51,7 @@ const LnNoAmountInvoiceCreateMutation = GT.Field({ walletId, memo, expiresIn, - externalId: undefined, + externalId, }) if (invoice instanceof Error) { diff --git a/core/api/src/graphql/public/root/mutation/ln-usd-invoice-btc-denominated-create-on-behalf-of-recipient.ts b/core/api/src/graphql/public/root/mutation/ln-usd-invoice-btc-denominated-create-on-behalf-of-recipient.ts index d46d458c46..987f5aabd6 100644 --- a/core/api/src/graphql/public/root/mutation/ln-usd-invoice-btc-denominated-create-on-behalf-of-recipient.ts +++ b/core/api/src/graphql/public/root/mutation/ln-usd-invoice-btc-denominated-create-on-behalf-of-recipient.ts @@ -10,6 +10,7 @@ import Hex32Bytes from "@/graphql/public/types/scalar/hex32bytes" import SatAmount from "@/graphql/shared/types/scalar/sat-amount" import LnInvoicePayload from "@/graphql/public/types/payload/ln-invoice" import { mapAndParseErrorForGqlResponse } from "@/graphql/error-map" +import TxExternalId from "@/graphql/shared/types/scalar/tx-external-id" const LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipientInput = GT.Input({ name: "LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipientInput", @@ -29,6 +30,7 @@ const LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipientInput = GT.Input({ type: Minutes, description: "Optional invoice expiration time in minutes.", }, + externalId: { type: TxExternalId }, }), }) @@ -47,8 +49,16 @@ const LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipientMutation = GT.Field({ }, }, resolve: async (_, args) => { - const { recipientWalletId, amount, memo, descriptionHash, expiresIn } = args.input - for (const input of [recipientWalletId, amount, memo, descriptionHash, expiresIn]) { + const { recipientWalletId, amount, memo, descriptionHash, expiresIn, externalId } = + args.input + for (const input of [ + recipientWalletId, + amount, + memo, + descriptionHash, + expiresIn, + externalId, + ]) { if (input instanceof Error) { return { errors: [{ message: input.message }] } } @@ -60,7 +70,7 @@ const LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipientMutation = GT.Field({ memo, descriptionHash, expiresIn, - externalId: undefined, + externalId, }) if (invoice instanceof Error) { diff --git a/core/api/src/graphql/public/root/mutation/ln-usd-invoice-create-on-behalf-of-recipient.ts b/core/api/src/graphql/public/root/mutation/ln-usd-invoice-create-on-behalf-of-recipient.ts index 816560d88c..92d1770e1d 100644 --- a/core/api/src/graphql/public/root/mutation/ln-usd-invoice-create-on-behalf-of-recipient.ts +++ b/core/api/src/graphql/public/root/mutation/ln-usd-invoice-create-on-behalf-of-recipient.ts @@ -8,6 +8,7 @@ import Minutes from "@/graphql/public/types/scalar/minutes" import WalletId from "@/graphql/shared/types/scalar/wallet-id" import Hex32Bytes from "@/graphql/public/types/scalar/hex32bytes" import CentAmount from "@/graphql/public/types/scalar/cent-amount" +import TxExternalId from "@/graphql/shared/types/scalar/tx-external-id" import LnInvoicePayload from "@/graphql/public/types/payload/ln-invoice" import { mapAndParseErrorForGqlResponse } from "@/graphql/error-map" @@ -29,6 +30,7 @@ const LnUsdInvoiceCreateOnBehalfOfRecipientInput = GT.Input({ type: Minutes, description: "Optional invoice expiration time in minutes.", }, + externalId: { type: TxExternalId }, }), }) @@ -45,8 +47,16 @@ const LnUsdInvoiceCreateOnBehalfOfRecipientMutation = GT.Field({ input: { type: GT.NonNull(LnUsdInvoiceCreateOnBehalfOfRecipientInput) }, }, resolve: async (_, args) => { - const { recipientWalletId, amount, memo, descriptionHash, expiresIn } = args.input - for (const input of [recipientWalletId, amount, memo, descriptionHash, expiresIn]) { + const { recipientWalletId, amount, memo, descriptionHash, expiresIn, externalId } = + args.input + for (const input of [ + recipientWalletId, + amount, + memo, + descriptionHash, + expiresIn, + externalId, + ]) { if (input instanceof Error) { return { errors: [{ message: input.message }] } } @@ -58,7 +68,7 @@ const LnUsdInvoiceCreateOnBehalfOfRecipientMutation = GT.Field({ memo, descriptionHash, expiresIn, - externalId: undefined, + externalId, }) if (invoice instanceof Error) { diff --git a/core/api/src/graphql/public/root/mutation/ln-usd-invoice-create.ts b/core/api/src/graphql/public/root/mutation/ln-usd-invoice-create.ts index bfd65bd204..995fb89295 100644 --- a/core/api/src/graphql/public/root/mutation/ln-usd-invoice-create.ts +++ b/core/api/src/graphql/public/root/mutation/ln-usd-invoice-create.ts @@ -7,6 +7,7 @@ import Memo from "@/graphql/shared/types/scalar/memo" import Minutes from "@/graphql/public/types/scalar/minutes" import WalletId from "@/graphql/shared/types/scalar/wallet-id" import CentAmount from "@/graphql/public/types/scalar/cent-amount" +import TxExternalId from "@/graphql/shared/types/scalar/tx-external-id" import LnInvoicePayload from "@/graphql/public/types/payload/ln-invoice" import { mapAndParseErrorForGqlResponse } from "@/graphql/error-map" @@ -23,6 +24,7 @@ const LnUsdInvoiceCreateInput = GT.Input({ type: Minutes, description: "Optional invoice expiration time in minutes.", }, + externalId: { type: TxExternalId }, }), }) @@ -39,9 +41,9 @@ const LnUsdInvoiceCreateMutation = GT.Field({ input: { type: GT.NonNull(LnUsdInvoiceCreateInput) }, }, resolve: async (_, args) => { - const { walletId, amount, memo, expiresIn } = args.input + const { walletId, amount, memo, expiresIn, externalId } = args.input - for (const input of [walletId, amount, memo, expiresIn]) { + for (const input of [walletId, amount, memo, expiresIn, externalId]) { if (input instanceof Error) { return { errors: [{ message: input.message }] } } @@ -52,7 +54,7 @@ const LnUsdInvoiceCreateMutation = GT.Field({ amount, memo, expiresIn, - externalId: undefined, + externalId, }) if (invoice instanceof Error) { diff --git a/core/api/src/graphql/public/schema.graphql b/core/api/src/graphql/public/schema.graphql index 8884e7f96d..39ab4af17a 100644 --- a/core/api/src/graphql/public/schema.graphql +++ b/core/api/src/graphql/public/schema.graphql @@ -579,6 +579,7 @@ input LnInvoiceCreateInput { """Optional invoice expiration time in minutes.""" expiresIn: Minutes + externalId: TxExternalId """Optional memo for the lightning invoice.""" memo: Memo @@ -594,6 +595,7 @@ input LnInvoiceCreateOnBehalfOfRecipientInput { """Optional invoice expiration time in minutes.""" expiresIn: Minutes + externalId: TxExternalId """Optional memo for the lightning invoice.""" memo: Memo @@ -662,6 +664,7 @@ type LnNoAmountInvoice implements Invoice { input LnNoAmountInvoiceCreateInput { """Optional invoice expiration time in minutes.""" expiresIn: Minutes + externalId: TxExternalId """Optional memo for the lightning invoice.""" memo: Memo @@ -675,6 +678,7 @@ input LnNoAmountInvoiceCreateInput { input LnNoAmountInvoiceCreateOnBehalfOfRecipientInput { """Optional invoice expiration time in minutes.""" expiresIn: Minutes + externalId: TxExternalId """Optional memo for the lightning invoice.""" memo: Memo @@ -755,6 +759,7 @@ input LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipientInput { """Optional invoice expiration time in minutes.""" expiresIn: Minutes + externalId: TxExternalId """ Optional memo for the lightning invoice. Acts as a note to the recipient. @@ -771,6 +776,7 @@ input LnUsdInvoiceCreateInput { """Optional invoice expiration time in minutes.""" expiresIn: Minutes + externalId: TxExternalId """Optional memo for the lightning invoice.""" memo: Memo @@ -786,6 +792,7 @@ input LnUsdInvoiceCreateOnBehalfOfRecipientInput { """Optional invoice expiration time in minutes.""" expiresIn: Minutes + externalId: TxExternalId """ Optional memo for the lightning invoice. Acts as a note to the recipient. diff --git a/core/api/src/services/mongoose/schema.ts b/core/api/src/services/mongoose/schema.ts index ec01f3228c..3bb7332d8a 100644 --- a/core/api/src/services/mongoose/schema.ts +++ b/core/api/src/services/mongoose/schema.ts @@ -90,6 +90,7 @@ const walletInvoiceSchema = new Schema({ externalId: { type: String, + unique: true, validator: (v: string) => !(checkedToLedgerExternalId(v) instanceof Error), }, }) diff --git a/dev/config/apollo-federation/supergraph.graphql b/dev/config/apollo-federation/supergraph.graphql index e99e56a39c..3ced79a8f6 100644 --- a/dev/config/apollo-federation/supergraph.graphql +++ b/dev/config/apollo-federation/supergraph.graphql @@ -794,6 +794,7 @@ input LnInvoiceCreateInput """Optional invoice expiration time in minutes.""" expiresIn: Minutes + externalId: TxExternalId """Optional memo for the lightning invoice.""" memo: Memo @@ -811,6 +812,7 @@ input LnInvoiceCreateOnBehalfOfRecipientInput """Optional invoice expiration time in minutes.""" expiresIn: Minutes + externalId: TxExternalId """Optional memo for the lightning invoice.""" memo: Memo @@ -900,6 +902,7 @@ input LnNoAmountInvoiceCreateInput { """Optional invoice expiration time in minutes.""" expiresIn: Minutes + externalId: TxExternalId """Optional memo for the lightning invoice.""" memo: Memo @@ -915,6 +918,7 @@ input LnNoAmountInvoiceCreateOnBehalfOfRecipientInput { """Optional invoice expiration time in minutes.""" expiresIn: Minutes + externalId: TxExternalId """Optional memo for the lightning invoice.""" memo: Memo @@ -1025,6 +1029,7 @@ input LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipientInput """Optional invoice expiration time in minutes.""" expiresIn: Minutes + externalId: TxExternalId """ Optional memo for the lightning invoice. Acts as a note to the recipient. @@ -1043,6 +1048,7 @@ input LnUsdInvoiceCreateInput """Optional invoice expiration time in minutes.""" expiresIn: Minutes + externalId: TxExternalId """Optional memo for the lightning invoice.""" memo: Memo @@ -1060,6 +1066,7 @@ input LnUsdInvoiceCreateOnBehalfOfRecipientInput """Optional invoice expiration time in minutes.""" expiresIn: Minutes + externalId: TxExternalId """ Optional memo for the lightning invoice. Acts as a note to the recipient.