Skip to content

Commit

Permalink
662/mk/use open payments types (#1024)
Browse files Browse the repository at this point in the history
* feat(open-payments): export the different IncomingPayment types

* feat(backend): use open-payment types for IncomingPayment

* feat(backend): use open-payment types for Connection

* feat(backend): use open-payment types for OutgoingPayment

* feat(backend): use open-payment types for Quote

* chore(backend): fix IncomingPayments.toOpenPaymentsType

* chore(open-payments): update mocks

* chore(backend): formatting

* chore(backend): add better typing for incomingPayment.toOpenPaymentsType

* chore(backend): remove QuoteJSON

* chore(open-payments): fix mocks

* chore(backend): fix IncomingPayment types

* chore(open-payments): fix incoming payment types

* chore(backend): fix incoming payment method

* chore(backend): make toOpenPaymentsType async

* chore(backend): getUrl for OutgoingPayment

* chore(backend): fix tests with async toOpenPaymentsType

* chore(backend): return undefined instead of null

* chore(backend): add awaits where necessary

* chore(open-payments): make getBody async

* chore(backend): fix outgoingPayment model method

* chore(backend): fix list tests

* chore(backend): update receiver tests

* chore(backend): make toOpenPaymentType sync (#1056)

* chore(backend): make toOpenPaymentType sync

* chore(backend): make quote.toOpenPaymentsType sync

* chore(backend): convert tests to sync

* chore(backend): update tests

* chore(backend): remove $formatJson where applicable

* chore(backend): remove $formatJson where applicable

* chore(backend): add test for incomingPayment model

* chore(backend): fix incomingPayment model test

* chore(open-payments): use suggestion

* chore(backend): fix test

* chore(backend): use suggestion
  • Loading branch information
mkurapov authored Feb 2, 2023
1 parent 4df802b commit 8a2dff6
Show file tree
Hide file tree
Showing 28 changed files with 487 additions and 350 deletions.
7 changes: 5 additions & 2 deletions packages/backend/src/graphql/resolvers/receiver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import { AppServices } from '../../app'
import { initIocContainer } from '../..'
import { Config } from '../../config/app'
import { Amount, serializeAmount } from '../../open_payments/amount'
import { mockIncomingPayment, mockPaymentPointer } from 'open-payments'
import {
mockIncomingPaymentWithConnection,
mockPaymentPointer
} from 'open-payments'
import { CreateReceiverResponse } from '../generated/graphql'
import { ReceiverService } from '../../open_payments/receiver/service'
import { Receiver } from '../../open_payments/receiver/model'
Expand Down Expand Up @@ -49,7 +52,7 @@ describe('Receiver Resolver', (): void => {
incomingAmount
}): Promise<void> => {
const receiver = Receiver.fromIncomingPayment(
mockIncomingPayment({
mockIncomingPaymentWithConnection({
id: `${paymentPointer.id}/incoming-payments/${uuid()}`,
paymentPointer: paymentPointer.id,
description,
Expand Down
18 changes: 0 additions & 18 deletions packages/backend/src/open_payments/connection/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,6 @@ import { IlpAddress } from 'ilp-packet'
import { ILPStreamConnection } from 'open-payments'
import { IncomingPayment } from '../payment/incoming/model'

export type ConnectionJSON = {
id: string
ilpAddress: IlpAddress
sharedSecret: string
assetCode: string
assetScale: number
}

export abstract class ConnectionBase {
protected constructor(
public readonly ilpAddress: IlpAddress,
Expand Down Expand Up @@ -55,16 +47,6 @@ export class Connection extends ConnectionBase {
return `${this.openPaymentsUrl}/connections/${this.id}`
}

public toJSON(): ConnectionJSON {
return {
id: this.url,
ilpAddress: this.ilpAddress,
sharedSecret: base64url(this.sharedSecret),
assetCode: this.assetCode,
assetScale: this.assetScale
}
}

public toOpenPaymentsType(): ILPStreamConnection {
return {
id: this.url,
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/open_payments/connection/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ async function getConnection(
): Promise<void> {
const connection = deps.connectionService.get(ctx.incomingPayment)
if (!connection) return ctx.throw(404)
ctx.body = connection.toJSON()
ctx.body = connection.toOpenPaymentsType()
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ describe('Connection Service', (): void => {
expect(connection.url).toEqual(
`${Config.openPaymentsUrl}/connections/${incomingPayment.connectionId}`
)
expect(connection.toJSON()).toEqual({
expect(connection.toOpenPaymentsType()).toEqual({
id: connection.url,
ilpAddress: connection.ilpAddress,
sharedSecret: base64url(connection.sharedSecret || ''),
Expand Down
127 changes: 127 additions & 0 deletions packages/backend/src/open_payments/payment/incoming/model.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { IocContract } from '@adonisjs/fold'
import { createTestApp, TestContainer } from '../../../tests/app'
import { Config, IAppConfig } from '../../../config/app'
import { initIocContainer } from '../../..'
import { AppServices } from '../../../app'
import { createIncomingPayment } from '../../../tests/incomingPayment'
import { createPaymentPointer } from '../../../tests/paymentPointer'
import { truncateTables } from '../../../tests/tableManager'
import { Connection } from '../../connection/model'
import { serializeAmount } from '../../amount'
import { IlpAddress } from 'ilp-packet'
import { IncomingPayment } from './model'

describe('Incoming Payment Model', (): void => {
let deps: IocContract<AppServices>
let appContainer: TestContainer
let config: IAppConfig

beforeAll(async (): Promise<void> => {
deps = initIocContainer(Config)
appContainer = await createTestApp(deps)
config = await deps.use('config')
})

afterEach(async (): Promise<void> => {
jest.useRealTimers()
await truncateTables(appContainer.knex)
})

afterAll(async (): Promise<void> => {
await appContainer.shutdown()
})

describe('toOpenPaymentsType', () => {
test('returns incoming payment without connection provided', async () => {
const paymentPointer = await createPaymentPointer(deps)
const incomingPayment = await createIncomingPayment(deps, {
paymentPointerId: paymentPointer.id,
description: 'my payment'
})

expect(incomingPayment.toOpenPaymentsType(paymentPointer)).toEqual({
id: `${paymentPointer.url}${IncomingPayment.urlPath}/${incomingPayment.id}`,
paymentPointer: paymentPointer.url,
completed: incomingPayment.completed,
receivedAmount: serializeAmount(incomingPayment.receivedAmount),
incomingAmount: incomingPayment.incomingAmount
? serializeAmount(incomingPayment.incomingAmount)
: undefined,
expiresAt: incomingPayment.expiresAt.toISOString(),
description: incomingPayment.description ?? undefined,
externalRef: incomingPayment.externalRef ?? undefined,
updatedAt: incomingPayment.updatedAt.toISOString(),
createdAt: incomingPayment.createdAt.toISOString()
})
})

test('returns incoming payment with connection as string', async () => {
const paymentPointer = await createPaymentPointer(deps)
const incomingPayment = await createIncomingPayment(deps, {
paymentPointerId: paymentPointer.id,
description: 'my payment'
})

const connection = `${config.openPaymentsUrl}/connections/${incomingPayment.connectionId}`

expect(
incomingPayment.toOpenPaymentsType(paymentPointer, connection)
).toEqual({
id: `${paymentPointer.url}${IncomingPayment.urlPath}/${incomingPayment.id}`,
paymentPointer: paymentPointer.url,
completed: incomingPayment.completed,
receivedAmount: serializeAmount(incomingPayment.receivedAmount),
incomingAmount: incomingPayment.incomingAmount
? serializeAmount(incomingPayment.incomingAmount)
: undefined,
expiresAt: incomingPayment.expiresAt.toISOString(),
description: incomingPayment.description ?? undefined,
externalRef: incomingPayment.externalRef ?? undefined,
updatedAt: incomingPayment.updatedAt.toISOString(),
createdAt: incomingPayment.createdAt.toISOString(),
ilpStreamConnection: connection
})
})

test('returns incoming payment with connection as object', async () => {
const paymentPointer = await createPaymentPointer(deps)
const incomingPayment = await createIncomingPayment(deps, {
paymentPointerId: paymentPointer.id,
description: 'my payment'
})

const connection = Connection.fromPayment({
payment: incomingPayment,
openPaymentsUrl: config.openPaymentsUrl,
credentials: {
ilpAddress: 'test.ilp' as IlpAddress,
sharedSecret: Buffer.from('')
}
})

expect(
incomingPayment.toOpenPaymentsType(paymentPointer, connection)
).toEqual({
id: `${paymentPointer.url}${IncomingPayment.urlPath}/${incomingPayment.id}`,
paymentPointer: paymentPointer.url,
completed: incomingPayment.completed,
receivedAmount: serializeAmount(incomingPayment.receivedAmount),
incomingAmount: incomingPayment.incomingAmount
? serializeAmount(incomingPayment.incomingAmount)
: undefined,
expiresAt: incomingPayment.expiresAt.toISOString(),
description: incomingPayment.description ?? undefined,
externalRef: incomingPayment.externalRef ?? undefined,
updatedAt: incomingPayment.updatedAt.toISOString(),
createdAt: incomingPayment.createdAt.toISOString(),
ilpStreamConnection: {
id: `${config.openPaymentsUrl}/connections/${incomingPayment.connectionId}`,
ilpAddress: 'test.ilp',
sharedSecret: expect.any(String),
assetCode: incomingPayment.asset.code,
assetScale: incomingPayment.asset.scale
}
})
})
})
})
112 changes: 54 additions & 58 deletions packages/backend/src/open_payments/payment/incoming/model.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Model, ModelOptions, Pojo, QueryContext } from 'objection'
import { Model, ModelOptions, QueryContext } from 'objection'
import { v4 as uuid } from 'uuid'

import { Amount, AmountJSON, serializeAmount } from '../../amount'
import { Connection, ConnectionJSON } from '../../connection/model'
import { Connection } from '../../connection/model'
import {
PaymentPointer,
PaymentPointerSubresource
Expand All @@ -11,7 +11,11 @@ import { Asset } from '../../../asset/model'
import { LiquidityAccount, OnCreditOptions } from '../../../accounting/service'
import { ConnectorAccount } from '../../../connector/core/rafiki'
import { WebhookEvent } from '../../../webhook/model'
import { IncomingPayment as OpenPaymentsIncomingPayment } from 'open-payments'
import {
IncomingPayment as OpenPaymentsIncomingPayment,
IncomingPaymentWithConnection as OpenPaymentsIncomingPaymentWithConnection,
IncomingPaymentWithConnectionUrl as OpenPaymentsIncomingPaymentWithConnectionUrl
} from 'open-payments'

export enum IncomingPaymentEventType {
IncomingPaymentExpired = 'incoming_payment.expired',
Expand Down Expand Up @@ -80,7 +84,6 @@ export class IncomingPayment
}
}

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

public get url(): string {
return `${this.paymentPointer.url}${IncomingPayment.urlPath}/${this.id}`
public getUrl(paymentPointer: PaymentPointer): string {
return `${paymentPointer.url}${IncomingPayment.urlPath}/${this.id}`
}

public async onCredit({
Expand Down Expand Up @@ -211,67 +214,60 @@ export class IncomingPayment
}
}

$formatJson(json: Pojo): Pojo {
json = super.$formatJson(json)
const payment: Pojo = {
id: json.id,
receivedAmount: {
...json.receivedAmount,
value: json.receivedAmount.value.toString()
},
completed: json.completed,
createdAt: json.createdAt,
updatedAt: json.updatedAt,
expiresAt: json.expiresAt.toISOString()
}
if (json.incomingAmount) {
payment.incomingAmount = {
...json.incomingAmount,
value: json.incomingAmount.value.toString()
}
}
if (json.description) {
payment.description = json.description
}
if (json.externalRef) {
payment.externalRef = json.externalRef
}
return payment
}

public toOpenPaymentsType({
ilpStreamConnection
}: {
public toOpenPaymentsType(
paymentPointer: PaymentPointer
): OpenPaymentsIncomingPayment
public toOpenPaymentsType(
paymentPointer: PaymentPointer,
ilpStreamConnection: Connection
}): OpenPaymentsIncomingPayment {
return {
id: this.url,
paymentPointer: this.paymentPointer.url,
): OpenPaymentsIncomingPaymentWithConnection
public toOpenPaymentsType(
paymentPointer: PaymentPointer,
ilpStreamConnection: string
): OpenPaymentsIncomingPaymentWithConnectionUrl
public toOpenPaymentsType(
paymentPointer: PaymentPointer,
ilpStreamConnection?: Connection | string
):
| OpenPaymentsIncomingPaymentWithConnection
| OpenPaymentsIncomingPaymentWithConnectionUrl

public toOpenPaymentsType(
paymentPointer: PaymentPointer,
ilpStreamConnection?: Connection | string
):
| OpenPaymentsIncomingPayment
| OpenPaymentsIncomingPaymentWithConnection
| OpenPaymentsIncomingPaymentWithConnectionUrl {
const baseIncomingPayment: OpenPaymentsIncomingPayment = {
id: this.getUrl(paymentPointer),
paymentPointer: paymentPointer.url,
incomingAmount: this.incomingAmount
? serializeAmount(this.incomingAmount)
: undefined,
receivedAmount: serializeAmount(this.receivedAmount),
completed: this.completed,
description: this.description ?? undefined,
externalRef: this.externalRef ?? undefined,
createdAt: this.createdAt.toISOString(),
updatedAt: this.updatedAt.toISOString(),
expiresAt: this.expiresAt.toISOString(),
expiresAt: this.expiresAt.toISOString()
}

if (!ilpStreamConnection) {
return baseIncomingPayment
}

if (typeof ilpStreamConnection === 'string') {
return {
...baseIncomingPayment,
ilpStreamConnection
}
}

return {
...baseIncomingPayment,
ilpStreamConnection: ilpStreamConnection.toOpenPaymentsType()
}
}
}

// TODO: disallow undefined
// https://github.com/interledger/rafiki/issues/594
export type IncomingPaymentJSON = {
id: string
paymentPointer: string
incomingAmount?: AmountJSON
receivedAmount: AmountJSON
completed: boolean
description?: string
externalRef?: string
createdAt: string
updatedAt: string
expiresAt?: string
ilpStreamConnection?: ConnectionJSON | string
}
Loading

0 comments on commit 8a2dff6

Please sign in to comment.