From e6d916d7c5e3bc50eb6ab51ffdada696fcf8ef79 Mon Sep 17 00:00:00 2001 From: Blair Currey <12960453+BlairCurrey@users.noreply.github.com> Date: Wed, 14 Aug 2024 22:53:06 -0400 Subject: [PATCH 1/4] feat(backend): track if receiver is local --- .../src/graphql/resolvers/receiver.test.ts | 6 +- .../src/open_payments/receiver/model.test.ts | 9 ++- .../src/open_payments/receiver/model.ts | 10 ++- .../open_payments/receiver/service.test.ts | 12 ++- .../src/open_payments/receiver/service.ts | 74 ++++++++++--------- packages/backend/src/tests/outgoingPayment.ts | 6 +- packages/backend/src/tests/receiver.ts | 3 +- 7 files changed, 70 insertions(+), 50 deletions(-) diff --git a/packages/backend/src/graphql/resolvers/receiver.test.ts b/packages/backend/src/graphql/resolvers/receiver.test.ts index 2ee01cb326..caa2cb32ef 100644 --- a/packages/backend/src/graphql/resolvers/receiver.test.ts +++ b/packages/backend/src/graphql/resolvers/receiver.test.ts @@ -60,7 +60,8 @@ describe('Receiver Resolver', (): void => { incomingAmount: incomingAmount ? serializeAmount(incomingAmount) : undefined - }) + }), + false ) const createSpy = jest @@ -253,7 +254,8 @@ describe('Receiver Resolver', (): void => { id: `${walletAddress.id}/incoming-payments/${uuid()}`, walletAddress: walletAddress.id, incomingAmount: amount ? serializeAmount(amount) : undefined - }) + }), + false ) test('returns receiver', async (): Promise => { diff --git a/packages/backend/src/open_payments/receiver/model.test.ts b/packages/backend/src/open_payments/receiver/model.test.ts index c062e1370c..c033251b32 100644 --- a/packages/backend/src/open_payments/receiver/model.test.ts +++ b/packages/backend/src/open_payments/receiver/model.test.ts @@ -50,7 +50,8 @@ describe('Receiver Model', (): void => { incomingPayment.toOpenPaymentsTypeWithMethods( walletAddress, streamCredentials - ) + ), + false ) expect(receiver).toEqual({ @@ -96,7 +97,7 @@ describe('Receiver Model', (): void => { streamCredentials ) - expect(() => new Receiver(openPaymentsIncomingPayment)).toThrow( + expect(() => new Receiver(openPaymentsIncomingPayment, false)).toThrow( 'Cannot create receiver from completed incoming payment' ) }) @@ -116,7 +117,7 @@ describe('Receiver Model', (): void => { streamCredentials ) - expect(() => new Receiver(openPaymentsIncomingPayment)).toThrow( + expect(() => new Receiver(openPaymentsIncomingPayment, false)).toThrow( 'Cannot create receiver from expired incoming payment' ) }) @@ -137,7 +138,7 @@ describe('Receiver Model', (): void => { streamCredentials ) - expect(() => new Receiver(openPaymentsIncomingPayment)).toThrow( + expect(() => new Receiver(openPaymentsIncomingPayment, false)).toThrow( 'Invalid ILP address on ilp payment method' ) }) diff --git a/packages/backend/src/open_payments/receiver/model.ts b/packages/backend/src/open_payments/receiver/model.ts index f8b226d066..5afbc22cc7 100644 --- a/packages/backend/src/open_payments/receiver/model.ts +++ b/packages/backend/src/open_payments/receiver/model.ts @@ -29,8 +29,15 @@ export class Receiver { public readonly assetCode: string public readonly assetScale: number public readonly incomingPayment: ReceiverIncomingPayment + public readonly isLocal: boolean - constructor(incomingPayment: OpenPaymentsIncomingPaymentWithPaymentMethod) { + constructor( + incomingPayment: OpenPaymentsIncomingPaymentWithPaymentMethod, + // TODO: lookup incomingPayment where isLocal is used instead of tracking isLocal here? + // not sure how simple the check can be. url matches resource server? + // exists in local db? exists in local db AND has stream creds (how its checked in receiverService.getReceiver)? + isLocal: boolean + ) { if (incomingPayment.completed) { throw new Error('Cannot create receiver from completed incoming payment') } @@ -76,6 +83,7 @@ export class Receiver { createdAt: new Date(incomingPayment.createdAt), updatedAt: new Date(incomingPayment.updatedAt) } + this.isLocal = isLocal } public get asset(): AssetOptions { diff --git a/packages/backend/src/open_payments/receiver/service.test.ts b/packages/backend/src/open_payments/receiver/service.test.ts index 088d6812d0..7c0c32b8c1 100644 --- a/packages/backend/src/open_payments/receiver/service.test.ts +++ b/packages/backend/src/open_payments/receiver/service.test.ts @@ -114,7 +114,8 @@ describe('Receiver Service', (): void => { sharedSecret: expect.any(String) } ] - } + }, + isLocal: true }) }) @@ -260,7 +261,8 @@ describe('Receiver Service', (): void => { sharedSecret: expect.any(String) } ] - } + }, + isLocal: false }) if (!existingGrant) { expect(clientRequestGrantSpy).toHaveBeenCalledWith( @@ -480,7 +482,8 @@ describe('Receiver Service', (): void => { sharedSecret: expect.any(String) } ] - } + }, + isLocal: false }) expect(remoteIncomingPaymentServiceSpy).toHaveBeenCalledWith({ @@ -573,7 +576,8 @@ describe('Receiver Service', (): void => { sharedSecret: expect.any(String) } ] - } + }, + isLocal: true }) expect(incomingPaymentCreateSpy).toHaveBeenCalledWith({ diff --git a/packages/backend/src/open_payments/receiver/service.ts b/packages/backend/src/open_payments/receiver/service.ts index 8f3ab7c28f..fe2cd8ca4d 100644 --- a/packages/backend/src/open_payments/receiver/service.ts +++ b/packages/backend/src/open_payments/receiver/service.ts @@ -74,8 +74,9 @@ async function createReceiver( const localWalletAddress = await deps.walletAddressService.getByUrl( args.walletAddressUrl ) + const isLocal = !!localWalletAddress - const incomingPaymentOrError = localWalletAddress + const incomingPaymentOrError = isLocal ? await createLocalIncomingPayment(deps, args, localWalletAddress) : await deps.remoteIncomingPaymentService.create(args) @@ -84,7 +85,7 @@ async function createReceiver( } try { - return new Receiver(incomingPaymentOrError) + return new Receiver(incomingPaymentOrError, isLocal) } catch (error) { const errorMessage = 'Could not create receiver from incoming payment' deps.logger.error( @@ -147,10 +148,27 @@ async function getReceiver( deps: ServiceDependencies, url: string ): Promise { - const incomingPayment = await getIncomingPayment(deps, url) - if (incomingPayment) { - return new Receiver(incomingPayment) + try { + const localIncomingPayment = await getLocalIncomingPayment({ + deps, + url + }) + if (localIncomingPayment) { + return new Receiver(localIncomingPayment, true) + } + + const remoteIncomingPayment = await getRemoteIncomingPayment(deps, url) + if (remoteIncomingPayment) { + return new Receiver(remoteIncomingPayment, false) + } + } catch (error) { + deps.logger.error( + { errorMessage: error instanceof Error && error.message }, + 'Could not get incoming payment' + ) } + + return undefined } function parseIncomingPaymentUrl( @@ -167,49 +185,33 @@ function parseIncomingPaymentUrl( } } -async function getIncomingPayment( +async function getRemoteIncomingPayment( deps: ServiceDependencies, url: string ): Promise { - try { - const urlParseResult = parseIncomingPaymentUrl(url) - if (!urlParseResult) { - return undefined - } - - const localIncomingPayment = await getLocalIncomingPayment({ - deps, - id: urlParseResult.id + const grant = await getIncomingPaymentGrant(deps, url) + if (!grant) { + throw new Error('Could not find grant') + } else { + return await deps.openPaymentsClient.incomingPayment.get({ + url, + accessToken: grant.accessToken }) - if (localIncomingPayment) { - return localIncomingPayment - } - - const grant = await getIncomingPaymentGrant(deps, url) - if (!grant) { - throw new Error('Could not find grant') - } else { - return await deps.openPaymentsClient.incomingPayment.get({ - url, - accessToken: grant.accessToken - }) - } - } catch (error) { - deps.logger.error( - { errorMessage: error instanceof Error && error.message }, - 'Could not get incoming payment' - ) - return undefined } } async function getLocalIncomingPayment({ deps, - id + url }: { deps: ServiceDependencies - id: string + url: string }): Promise { + const { id } = parseIncomingPaymentUrl(url) ?? {} + if (!id) { + return undefined + } + const incomingPayment = await deps.incomingPaymentService.get({ id }) diff --git a/packages/backend/src/tests/outgoingPayment.ts b/packages/backend/src/tests/outgoingPayment.ts index f28b38e694..451f33e6bb 100644 --- a/packages/backend/src/tests/outgoingPayment.ts +++ b/packages/backend/src/tests/outgoingPayment.ts @@ -56,7 +56,8 @@ export async function createOutgoingPayment( incomingPayment.toOpenPaymentsTypeWithMethods( walletAddress, streamCredentials - ) + ), + false ) ) } @@ -124,7 +125,8 @@ export async function createOutgoingPaymentWithReceiver( incomingPayment.toOpenPaymentsTypeWithMethods( args.receivingWalletAddress, streamCredentials - ) + ), + false ) const outgoingPayment = await createOutgoingPayment(deps, { diff --git a/packages/backend/src/tests/receiver.ts b/packages/backend/src/tests/receiver.ts index 3cd6b7a8c8..218051e70d 100644 --- a/packages/backend/src/tests/receiver.ts +++ b/packages/backend/src/tests/receiver.ts @@ -22,6 +22,7 @@ export async function createReceiver( incomingPayment.toOpenPaymentsTypeWithMethods( walletAddress, streamCredentialsService.get(incomingPayment)! - ) + ), + false ) } From 1626c4f396f56b9749e45862d18382e1420adf8f Mon Sep 17 00:00:00 2001 From: Blair Currey <12960453+BlairCurrey@users.noreply.github.com> Date: Wed, 14 Aug 2024 23:04:24 -0400 Subject: [PATCH 2/4] chore(backend): rm todo --- packages/backend/src/open_payments/receiver/model.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/backend/src/open_payments/receiver/model.ts b/packages/backend/src/open_payments/receiver/model.ts index 5afbc22cc7..30156ee847 100644 --- a/packages/backend/src/open_payments/receiver/model.ts +++ b/packages/backend/src/open_payments/receiver/model.ts @@ -33,9 +33,6 @@ export class Receiver { constructor( incomingPayment: OpenPaymentsIncomingPaymentWithPaymentMethod, - // TODO: lookup incomingPayment where isLocal is used instead of tracking isLocal here? - // not sure how simple the check can be. url matches resource server? - // exists in local db? exists in local db AND has stream creds (how its checked in receiverService.getReceiver)? isLocal: boolean ) { if (incomingPayment.completed) { From 3c89686325e5b3f0e7229746d735ba5493d3b51f Mon Sep 17 00:00:00 2001 From: Blair Currey <12960453+BlairCurrey@users.noreply.github.com> Date: Thu, 15 Aug 2024 11:20:51 -0400 Subject: [PATCH 3/4] fix(backend): receiver model test --- packages/backend/src/open_payments/receiver/model.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/open_payments/receiver/model.test.ts b/packages/backend/src/open_payments/receiver/model.test.ts index c033251b32..8c79ace484 100644 --- a/packages/backend/src/open_payments/receiver/model.test.ts +++ b/packages/backend/src/open_payments/receiver/model.test.ts @@ -42,6 +42,7 @@ describe('Receiver Model', (): void => { const incomingPayment = await createIncomingPayment(deps, { walletAddressId: walletAddress.id }) + const isLocal = false const streamCredentials = streamCredentialsService.get(incomingPayment) assert(streamCredentials) @@ -51,7 +52,7 @@ describe('Receiver Model', (): void => { walletAddress, streamCredentials ), - false + isLocal ) expect(receiver).toEqual({ @@ -75,7 +76,8 @@ describe('Receiver Model', (): void => { sharedSecret: base64url(streamCredentials.sharedSecret) } ] - } + }, + isLocal }) }) From cf241ad2004aeac967e46dd0d1147c14e20e4078 Mon Sep 17 00:00:00 2001 From: Blair Currey <12960453+BlairCurrey@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:04:06 -0400 Subject: [PATCH 4/4] test(backend): set isLocal to true in receiver model test --- packages/backend/src/open_payments/receiver/model.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/src/open_payments/receiver/model.test.ts b/packages/backend/src/open_payments/receiver/model.test.ts index 8c79ace484..0255c615f0 100644 --- a/packages/backend/src/open_payments/receiver/model.test.ts +++ b/packages/backend/src/open_payments/receiver/model.test.ts @@ -42,7 +42,7 @@ describe('Receiver Model', (): void => { const incomingPayment = await createIncomingPayment(deps, { walletAddressId: walletAddress.id }) - const isLocal = false + const isLocal = true const streamCredentials = streamCredentialsService.get(incomingPayment) assert(streamCredentials)