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

662/mk/use open payments types #1024

Merged
merged 33 commits into from
Feb 2, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c3ccd88
feat(open-payments): export the different IncomingPayment types
mkurapov Jan 24, 2023
3415f5f
feat(backend): use open-payment types for IncomingPayment
mkurapov Jan 24, 2023
4693a79
feat(backend): use open-payment types for Connection
mkurapov Jan 24, 2023
c633b30
feat(backend): use open-payment types for OutgoingPayment
mkurapov Jan 24, 2023
909462a
feat(backend): use open-payment types for Quote
mkurapov Jan 24, 2023
8feaacb
chore(backend): fix IncomingPayments.toOpenPaymentsType
mkurapov Jan 24, 2023
5300073
chore(open-payments): update mocks
mkurapov Jan 24, 2023
01a0ba0
chore(backend): formatting
mkurapov Jan 24, 2023
36d8b8e
chore(backend): add better typing for incomingPayment.toOpenPaymentsType
mkurapov Jan 25, 2023
d04f994
chore(backend): remove QuoteJSON
mkurapov Jan 25, 2023
379aee8
Merge branch 'main' into 662/mk/use-open-payments-types
mkurapov Jan 25, 2023
11fa542
chore(open-payments): fix mocks
mkurapov Jan 25, 2023
27cfdde
chore(backend): fix IncomingPayment types
mkurapov Jan 25, 2023
4efddb3
chore(open-payments): fix incoming payment types
mkurapov Jan 25, 2023
dc051ec
chore(backend): fix incoming payment method
mkurapov Jan 25, 2023
0fddf9e
chore(backend): make toOpenPaymentsType async
mkurapov Jan 28, 2023
ad57048
chore(backend): getUrl for OutgoingPayment
mkurapov Jan 28, 2023
d48dc0a
chore(backend): fix tests with async toOpenPaymentsType
mkurapov Jan 28, 2023
9302bad
chore(backend): return undefined instead of null
mkurapov Jan 28, 2023
5e5d4e8
chore(backend): add awaits where necessary
mkurapov Jan 28, 2023
25972d3
chore(open-payments): make getBody async
mkurapov Jan 28, 2023
4800c80
chore(backend): fix outgoingPayment model method
mkurapov Jan 28, 2023
cf95410
chore(backend): fix list tests
mkurapov Jan 28, 2023
9a967f1
chore(backend): update receiver tests
mkurapov Jan 28, 2023
e5f3c03
Merge branch 'main' into 662/mk/use-open-payments-types
mkurapov Feb 1, 2023
5733224
chore(backend): make toOpenPaymentType sync (#1056)
mkurapov Feb 1, 2023
28a34df
chore(backend): remove $formatJson where applicable
mkurapov Feb 2, 2023
5e95486
chore(backend): remove $formatJson where applicable
mkurapov Feb 2, 2023
b6d25c6
chore(backend): add test for incomingPayment model
mkurapov Feb 2, 2023
09a0c10
chore(backend): fix incomingPayment model test
mkurapov Feb 2, 2023
c079942
chore(open-payments): use suggestion
mkurapov Feb 2, 2023
c55e586
chore(backend): fix test
mkurapov Feb 2, 2023
fc311e2
chore(backend): use suggestion
mkurapov Feb 2, 2023
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
34 changes: 21 additions & 13 deletions packages/backend/src/open_payments/payment/incoming/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ export class IncomingPayment
}
}

public paymentPointer!: PaymentPointer
Copy link
Contributor Author

@mkurapov mkurapov Jan 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no non-null assertion since we can start removing withGraphFetched('paymentPointer') from the DB calls

public description?: string
public expiresAt!: Date
public state!: IncomingPaymentState
Expand Down Expand Up @@ -131,8 +130,15 @@ export class IncomingPayment
this.receivedAmountValue = amount.value
}

public get url(): string {
return `${this.paymentPointer.url}${IncomingPayment.urlPath}/${this.id}`
public async getUrl(fetchedPaymentPointer?: PaymentPointer): Promise<string> {
Copy link
Contributor Author

@mkurapov mkurapov Jan 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding fetchedPaymentPointer in-case you already have the paymentPointer and don't want to grab it again, like in toOpenPaymentsType

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if callers just assigned incomingPayment.paymentPointer = fetchedPaymentPointer, so that getUrl+getPaymentPointer only dealt with whether this.paymentPointer is defined or not?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taking a step back, if/when we change subresource urls to not include the payment pointer, we'll no longer need an async getUrl.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm hesitant to do that, since
a) we either have to change the type definitions of getUrl/toOpenPaymentsType to possibly return undefined, or throw inside the method if paymentPointer isn't defined
b) it's not entirely clear that the caller has to do that in order to make these methods work.

Maybe we can

  1. have toOpenPaymentsType take in a paymentPointer (this would also make it sync), it would require passing in ctx.paymentPointer in most places but I think that's ok
  2. A bit more complicated, but we make a separate <subresource>WithPaymentPointer class that constructs a new model with the paymentPointer defined, although I'm not sure the additional boilerplate is worth it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify, I'm only suggesting changing getUrl to

Suggested change
public async getUrl(fetchedPaymentPointer?: PaymentPointer): Promise<string> {
public async getUrl(): Promise<string> {

and callers can optionally define incomingPayment.paymentPointer to avoid $relatedQuery in getPaymentPointer.

const paymentPointer =
fetchedPaymentPointer || (await this.getPaymentPointer())

return `${paymentPointer.url}${IncomingPayment.urlPath}/${this.id}`
}

public async getPaymentPointer(): Promise<PaymentPointer> {
return this.paymentPointer ?? (await this.$relatedQuery('paymentPointer'))
}

public async onCredit({
Expand Down Expand Up @@ -243,22 +249,24 @@ export class IncomingPayment
return payment
}

public toOpenPaymentsType(): OpenPaymentsIncomingPayment
public toOpenPaymentsType(
public async toOpenPaymentsType(): Promise<OpenPaymentsIncomingPayment>
public async toOpenPaymentsType(
ilpStreamConnection: Connection
): OpenPaymentsIncomingPaymentWithConnection
public toOpenPaymentsType(
): Promise<OpenPaymentsIncomingPaymentWithConnection>
public async toOpenPaymentsType(
ilpStreamConnection: string
): OpenPaymentsIncomingPaymentWithConnectionUrl
public toOpenPaymentsType(
): Promise<OpenPaymentsIncomingPaymentWithConnectionUrl>
public async toOpenPaymentsType(
ilpStreamConnection?: Connection | string
):
): Promise<
| OpenPaymentsIncomingPayment
| OpenPaymentsIncomingPaymentWithConnection
| OpenPaymentsIncomingPaymentWithConnectionUrl {
| OpenPaymentsIncomingPaymentWithConnectionUrl
> {
const paymentPointer = await this.getPaymentPointer()
const baseIncomingPayment: OpenPaymentsIncomingPayment = {
id: this.url,
paymentPointer: this.paymentPointer.url,
id: await this.getUrl(paymentPointer),
paymentPointer: paymentPointer.url,
incomingAmount: this.incomingAmount
? serializeAmount(this.incomingAmount)
: undefined,
Expand Down
54 changes: 28 additions & 26 deletions packages/backend/src/open_payments/payment/incoming/routes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,31 +82,33 @@ describe('Incoming Payment Routes', (): void => {
externalRef
}),
get: (ctx) => incomingPaymentRoutes.get(ctx),
getBody: (incomingPayment, list) => ({
id: incomingPayment.url,
paymentPointer: paymentPointer.url,
completed: false,
incomingAmount:
incomingPayment.incomingAmount &&
serializeAmount(incomingPayment.incomingAmount),
description: incomingPayment.description,
expiresAt: incomingPayment.expiresAt.toISOString(),
createdAt: incomingPayment.createdAt.toISOString(),
updatedAt: incomingPayment.updatedAt.toISOString(),
receivedAmount: serializeAmount(incomingPayment.receivedAmount),
externalRef: '#123',
ilpStreamConnection: list
? `${config.openPaymentsUrl}/connections/${incomingPayment.connectionId}`
: {
id: `${config.openPaymentsUrl}/connections/${incomingPayment.connectionId}`,
ilpAddress: expect.stringMatching(
/^test\.rafiki\.[a-zA-Z0-9_-]{95}$/
),
sharedSecret: expect.stringMatching(/^[a-zA-Z0-9-_]{43}$/),
assetCode: incomingPayment.receivedAmount.assetCode,
assetScale: incomingPayment.receivedAmount.assetScale
}
}),
getBody: async (incomingPayment, list) => {
return {
id: await incomingPayment.getUrl(),
paymentPointer: paymentPointer.url,
completed: false,
incomingAmount:
incomingPayment.incomingAmount &&
serializeAmount(incomingPayment.incomingAmount),
description: incomingPayment.description,
expiresAt: incomingPayment.expiresAt.toISOString(),
createdAt: incomingPayment.createdAt.toISOString(),
updatedAt: incomingPayment.updatedAt.toISOString(),
receivedAmount: serializeAmount(incomingPayment.receivedAmount),
externalRef: '#123',
ilpStreamConnection: list
? `${config.openPaymentsUrl}/connections/${incomingPayment.connectionId}`
: {
id: `${config.openPaymentsUrl}/connections/${incomingPayment.connectionId}`,
ilpAddress: expect.stringMatching(
/^test\.rafiki\.[a-zA-Z0-9_-]{95}$/
),
sharedSecret: expect.stringMatching(/^[a-zA-Z0-9-_]{43}$/),
assetCode: incomingPayment.receivedAmount.assetCode,
assetScale: incomingPayment.receivedAmount.assetScale
}
}
},
list: (ctx) => incomingPaymentRoutes.list(ctx),
urlPath: IncomingPayment.urlPath
})
Expand Down Expand Up @@ -263,7 +265,7 @@ describe('Incoming Payment Routes', (): void => {
await expect(incomingPaymentRoutes.complete(ctx)).resolves.toBeUndefined()
expect(ctx.response).toSatisfyApiSpec()
expect(ctx.body).toEqual({
id: incomingPayment.url,
id: await incomingPayment.getUrl(),
paymentPointer: paymentPointer.url,
incomingAmount: {
value: '123',
Expand Down
21 changes: 13 additions & 8 deletions packages/backend/src/open_payments/payment/outgoing/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { DbErrors } from 'objection-db-errors'
import { LiquidityAccount } from '../../../accounting/service'
import { Asset } from '../../../asset/model'
import { ConnectorAccount } from '../../../connector/core/rafiki'
import { PaymentPointerSubresource } from '../../payment_pointer/model'
import {
PaymentPointerSubresource,
PaymentPointer
} from '../../payment_pointer/model'
import { Quote } from '../../quote/model'
import { Amount, AmountJSON, serializeAmount } from '../../amount'
import { WebhookEvent } from '../../../webhook/model'
Expand Down Expand Up @@ -73,10 +76,6 @@ export class OutgoingPayment
return this.quote.asset
}

public get url(): string {
return `${this.paymentPointerId}${OutgoingPayment.urlPath}/${this.id}`
}

public get failed(): boolean {
mkurapov marked this conversation as resolved.
Show resolved Hide resolved
return this.state === OutgoingPaymentState.Failed
}
Expand Down Expand Up @@ -178,10 +177,16 @@ export class OutgoingPayment
}
}
mkurapov marked this conversation as resolved.
Show resolved Hide resolved

public toOpenPaymentsType(): OpenPaymentsOutgoingPayment {
public async getPaymentPointer(): Promise<PaymentPointer> {
return this.paymentPointer ?? (await this.$relatedQuery('paymentPointer'))
}

mkurapov marked this conversation as resolved.
Show resolved Hide resolved
public async toOpenPaymentsType(): Promise<OpenPaymentsOutgoingPayment> {
const paymentPointer = await this.getPaymentPointer()

return {
id: this.url,
paymentPointer: this.paymentPointerId,
id: `${paymentPointer.url}${OutgoingPayment.urlPath}/${this.id}`,
paymentPointer: paymentPointer.id,
quoteId: this.quote.id,
receiveAmount: serializeAmount(this.receiveAmount),
sendAmount: serializeAmount(this.sendAmount),
Expand Down
10 changes: 5 additions & 5 deletions packages/backend/src/open_payments/payment/outgoing/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ async function getOutgoingPayment(
ctx.throw(500, 'Error trying to get outgoing payment')
}
if (!outgoingPayment) return ctx.throw(404)
ctx.body = outgoingPaymentToBody(outgoingPayment)
ctx.body = await outgoingPaymentToBody(outgoingPayment)
}

export type CreateBody = {
Expand Down Expand Up @@ -84,7 +84,7 @@ async function createOutgoingPayment(
return ctx.throw(errorToCode[paymentOrErr], errorToMessage[paymentOrErr])
}
ctx.status = 201
ctx.body = outgoingPaymentToBody(paymentOrErr)
ctx.body = await outgoingPaymentToBody(paymentOrErr)
}

async function listOutgoingPayments(
Expand All @@ -95,15 +95,15 @@ async function listOutgoingPayments(
await listSubresource({
ctx,
getPaymentPointerPage: deps.outgoingPaymentService.getPaymentPointerPage,
toBody: (payment) => outgoingPaymentToBody(payment)
toBody: outgoingPaymentToBody
})
} catch (_) {
ctx.throw(500, 'Error trying to list outgoing payments')
}
}

function outgoingPaymentToBody(
async function outgoingPaymentToBody(
outgoingPayment: OutgoingPayment
): OpenPaymentsOutgoingPayment {
): Promise<OpenPaymentsOutgoingPayment> {
return outgoingPayment.toOpenPaymentsType()
}
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ describe('OutgoingPaymentService', (): void => {
incomingPayment = await createIncomingPayment(deps, {
paymentPointerId: receiverPaymentPointer.id
})
receiver = incomingPayment.url
receiver = await incomingPayment.getUrl()

amtDelivered = BigInt(0)
})
Expand Down Expand Up @@ -858,7 +858,9 @@ describe('OutgoingPaymentService', (): void => {
const fetchedReceiver = connectionService.getUrl(incomingPayment)
assert.ok(fetchedReceiver)
const paymentId = await setup({
receiver: toConnection ? fetchedReceiver : incomingPayment.url,
receiver: toConnection
? fetchedReceiver
: await incomingPayment.getUrl(),
receiveAmount
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,10 @@ type RouteTestsOptions<M> = Omit<
> & {
getPaymentPointer: () => Promise<PaymentPointer>
get: (ctx: ReadContext) => Promise<void>
getBody: (model: M, list?: boolean) => Record<string, unknown>
getBody: (
model: M,
list?: boolean
) => Record<string, unknown> | Promise<Record<string, unknown>>
list?: (ctx: ListContext) => Promise<void>
urlPath: string
}
Expand Down Expand Up @@ -230,7 +233,7 @@ export const getRouteTests = <M extends PaymentPointerSubresource>({
expect(ctx.response).toSatisfyApiSpec()
}
expect(ctx.body).toEqual({
result: expectedMatch ? [getBody(expectedMatch, true)] : [],
result: expectedMatch ? [await getBody(expectedMatch, true)] : [],
pagination: {
hasPreviousPage: false,
hasNextPage: false,
Expand Down
8 changes: 5 additions & 3 deletions packages/backend/src/open_payments/payment_pointer/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ export async function getPaymentPointer(
interface ListSubresourceOptions<M extends PaymentPointerSubresource> {
ctx: ListContext
getPaymentPointerPage: PaymentPointerSubresourceService<M>['getPaymentPointerPage']
toBody: (model: M) => Record<string, unknown>
toBody:
| ((model: M) => Record<string, unknown>)
| ((model: M) => Promise<Record<string, unknown>>)
}

export const listSubresource = async <M extends PaymentPointerSubresource>({
Expand All @@ -66,9 +68,9 @@ export const listSubresource = async <M extends PaymentPointerSubresource>({
)
const result = {
pagination: pageInfo,
result: page.map((item: M) => {
result: page.map(async (item: M) => {
item.paymentPointer = ctx.paymentPointer
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are fetching paymentPointer on the fly (whenever it's missing), this line isn't necessary

return toBody(item)
return await toBody(item)
})
}
ctx.body = result
Expand Down
24 changes: 18 additions & 6 deletions packages/backend/src/open_payments/quote/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { Model, Pojo } from 'objection'
import * as Pay from '@interledger/pay'

import { Amount, serializeAmount } from '../amount'
import { PaymentPointerSubresource } from '../payment_pointer/model'
import {
PaymentPointer,
PaymentPointerSubresource
} from '../payment_pointer/model'
import { Asset } from '../../asset/model'
import { Quote as OpenPaymentsQuote } from 'open-payments'

Expand Down Expand Up @@ -44,8 +47,15 @@ export class Quote extends PaymentPointerSubresource {

private sendAmountValue!: bigint

public get url(): string {
return `${this.paymentPointerId}${Quote.urlPath}/${this.id}`
public async getPaymentPointer(): Promise<PaymentPointer> {
return this.paymentPointer ?? (await this.$relatedQuery('paymentPointer'))
}

public async getUrl(fetchedPaymentPointer?: PaymentPointer): Promise<string> {
const paymentPointer =
fetchedPaymentPointer || (await this.getPaymentPointer())

return `${paymentPointer.url}${Quote.urlPath}/${this.id}`
}

public get sendAmount(): Amount {
Expand Down Expand Up @@ -154,10 +164,12 @@ export class Quote extends PaymentPointerSubresource {
}
}

public toOpenPaymentsType(): OpenPaymentsQuote {
public async toOpenPaymentsType(): Promise<OpenPaymentsQuote> {
const paymentPointer = await this.getPaymentPointer()

return {
id: this.url,
paymentPointer: this.paymentPointerId,
id: await this.getUrl(paymentPointer),
paymentPointer: paymentPointer.url,
receiveAmount: serializeAmount(this.receiveAmount),
sendAmount: serializeAmount(this.sendAmount),
receiver: this.receiver,
Expand Down
4 changes: 2 additions & 2 deletions packages/backend/src/open_payments/quote/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ async function createQuote(
}

ctx.status = 201
ctx.body = quoteToBody(quoteOrErr)
ctx.body = await quoteToBody(quoteOrErr)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ctx.body = await quoteToBody(quoteOrErr)
ctx.body = await quoteOrErr.toOpenPaymentsType()

Remove quoteToBody

} catch (err) {
if (isQuoteError(err)) {
return ctx.throw(errorToCode[err], errorToMessage[err])
Expand All @@ -90,6 +90,6 @@ async function createQuote(
}
}

function quoteToBody(quote: Quote): OpenPaymentsQuote {
async function quoteToBody(quote: Quote): Promise<OpenPaymentsQuote> {
return quote.toOpenPaymentsType()
}
12 changes: 6 additions & 6 deletions packages/backend/src/open_payments/quote/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ describe('QuoteService', (): void => {
paymentPointerId,
receiver: toConnection
? connectionService.getUrl(incomingPayment)
: incomingPayment.url
: await incomingPayment.getUrl()
}
if (sendAmount) options.sendAmount = sendAmount
if (receiveAmount) options.receiveAmount = receiveAmount
Expand Down Expand Up @@ -575,7 +575,7 @@ describe('QuoteService', (): void => {
})
const options: CreateQuoteOptions = {
paymentPointerId,
receiver: incomingPayment.url,
receiver: await incomingPayment.getUrl(),
receiveAmount
}
const expected: ExpectedQuote = {
Expand Down Expand Up @@ -653,11 +653,11 @@ describe('QuoteService', (): void => {
async ({ sendAmount, receiveAmount }): Promise<void> => {
const options: CreateQuoteOptions = {
paymentPointerId,
receiver: (
receiver: await (
await createIncomingPayment(deps, {
paymentPointerId: receivingPaymentPointer.id
})
).url
).getUrl()
}
if (sendAmount) options.sendAmount = sendAmount
if (receiveAmount) options.receiveAmount = receiveAmount
Expand All @@ -675,11 +675,11 @@ describe('QuoteService', (): void => {
await expect(
quoteService.create({
paymentPointerId,
receiver: (
receiver: await (
await createIncomingPayment(deps, {
paymentPointerId: receivingPaymentPointer.id
})
).url,
).getUrl(),
sendAmount
})
).rejects.toThrow('missing prices')
Expand Down