Skip to content

Commit

Permalink
feat: remove payment pointer from resource url (#291)
Browse files Browse the repository at this point in the history
* feat: remove payment pointer from resource url

* feat: remove wallet address from examples, update tests

* feat: add changeset

* feat: remove accountId from most tests

* fix(spec): disallow additional properties in the response

* feat(spec): set default and maximum values for pagination

* feat(tests): bump resource server spec version

* feat: remove ilpStreamConnection

remove ilpStreamConnection and all associated schemas
to replace it with a broader "payment methods" implementation
for incoming payment

* feat: generate types

* refactor: remove anything related to ilpStreamConnection

---------

Co-authored-by: Ömer Talha Özdemir <[email protected]>
  • Loading branch information
njlie and Ömer Talha Özdemir authored Sep 22, 2023
1 parent 5d39b2e commit 4e98e06
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 389 deletions.
5 changes: 5 additions & 0 deletions .changeset/moody-students-greet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@interledger/openapi': minor
---

Removed payment pointer/wallet address from resource urls
190 changes: 36 additions & 154 deletions openapi/resource-server.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion openapi/schemas.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,5 @@ components:
format: uri
pattern: '^https://(.+)/(incoming-payments|connections)/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'
examples:
- 'https://openpayments.guide/alice/incoming-payments/08394f02-7b7b-45e2-b645-51d04e7c330c'
- 'https://openpayments.guide/incoming-payments/08394f02-7b7b-45e2-b645-51d04e7c330c'
- 'https://openpayments.guide/connections/016da9d5-c9a4-4c80-a354-86b915a04ff8'
85 changes: 16 additions & 69 deletions packages/open-payments/src/client/incoming-payment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,8 @@ import {
import { OpenAPI, HttpMethod, createOpenAPI } from '@interledger/openapi'
import {
defaultAxiosInstance,
mockILPStreamConnection,
mockIncomingPayment,
mockIncomingPaymentPaginationResult,
mockIncomingPaymentWithConnection,
mockIncomingPaymentWithConnectionUrl,
mockOpenApiResponseValidators,
silentLogger
} from '../test/helpers'
Expand Down Expand Up @@ -44,13 +41,14 @@ describe('incoming-payment', (): void => {

const axiosInstance = defaultAxiosInstance
const logger = silentLogger
const walletAddress = 'http://localhost:1000/.well-known/pay'
const walletAddress = 'http://localhost:1000/alice/.well-known/pay'
const serverAddress = 'http://localhost:1000'
const accessToken = 'accessToken'
const openApiValidators = mockOpenApiResponseValidators()

describe('getIncomingPayment', (): void => {
test('returns incoming payment if passes validation', async (): Promise<void> => {
const incomingPayment = mockIncomingPaymentWithConnection()
const incomingPayment = mockIncomingPayment()

nock(walletAddress)
.get('/incoming-payments/1')
Expand All @@ -68,7 +66,7 @@ describe('incoming-payment', (): void => {
})

test('throws if incoming payment does not pass validation', async (): Promise<void> => {
const incomingPayment = mockIncomingPaymentWithConnection({
const incomingPayment = mockIncomingPayment({
incomingAmount: {
assetCode: 'USD',
assetScale: 2,
Expand Down Expand Up @@ -101,7 +99,7 @@ describe('incoming-payment', (): void => {
})

test('throws if incoming payment does not pass open api validation', async (): Promise<void> => {
const incomingPayment = mockIncomingPaymentWithConnection()
const incomingPayment = mockIncomingPayment()

nock(walletAddress)
.get('/incoming-payments/1')
Expand Down Expand Up @@ -131,7 +129,7 @@ describe('incoming-payment', (): void => {
`(
'returns the incoming payment on success',
async ({ incomingAmount, expiresAt, metadata }): Promise<void> => {
const incomingPayment = mockIncomingPaymentWithConnection({
const incomingPayment = mockIncomingPayment({
incomingAmount,
expiresAt,
metadata
Expand Down Expand Up @@ -164,7 +162,7 @@ describe('incoming-payment', (): void => {
value: '10'
}

const incomingPayment = mockIncomingPaymentWithConnection({
const incomingPayment = mockIncomingPayment({
incomingAmount: amount,
receivedAmount: amount,
completed: false
Expand All @@ -186,7 +184,7 @@ describe('incoming-payment', (): void => {
})

test('throws if the created incoming payment does not pass open api validation', async (): Promise<void> => {
const incomingPayment = mockIncomingPaymentWithConnection()
const incomingPayment = mockIncomingPayment()

const scope = nock(walletAddress)
.post('/incoming-payments')
Expand All @@ -210,14 +208,14 @@ describe('incoming-payment', (): void => {
completed: true
})

const scope = nock(walletAddress)
const scope = nock(serverAddress)
.post(`/incoming-payments/${incomingPayment.id}/complete`)
.reply(200, incomingPayment)

const result = await completeIncomingPayment(
{ axiosInstance, logger },
{
url: `${walletAddress}/incoming-payments/${incomingPayment.id}`,
url: `${serverAddress}/incoming-payments/${incomingPayment.id}`,
accessToken
},
openApiValidators.successfulValidator
Expand Down Expand Up @@ -287,7 +285,7 @@ describe('incoming-payment', (): void => {
async ({ first, cursor }): Promise<void> => {
const incomingPaymentPaginationResult =
mockIncomingPaymentPaginationResult({
result: Array(first).fill(mockIncomingPaymentWithConnectionUrl())
result: Array(first).fill(mockIncomingPayment())
})

const scope = nock(walletAddress)
Expand Down Expand Up @@ -330,7 +328,7 @@ describe('incoming-payment', (): void => {
async ({ last, cursor }): Promise<void> => {
const incomingPaymentPaginationResult =
mockIncomingPaymentPaginationResult({
result: Array(last).fill(mockIncomingPaymentWithConnectionUrl())
result: Array(last).fill(mockIncomingPayment())
})

const scope = nock(walletAddress)
Expand Down Expand Up @@ -364,7 +362,7 @@ describe('incoming-payment', (): void => {
})

test('throws if an incoming payment does not pass validation', async (): Promise<void> => {
const incomingPayment = mockIncomingPaymentWithConnectionUrl({
const incomingPayment = mockIncomingPayment({
incomingAmount: {
assetCode: 'USD',
assetScale: 2,
Expand Down Expand Up @@ -520,55 +518,6 @@ describe('incoming-payment', (): void => {
'Incoming amount matches received amount but payment is not completed'
)
})

test('throws if receiving amount asset code is different that ilp connection asset code', async (): Promise<void> => {
const ilpStreamConnection = mockILPStreamConnection({
assetCode: 'CAD'
})

const incomingPayment = mockIncomingPaymentWithConnection({
incomingAmount: {
assetCode: 'USD',
assetScale: 2,
value: '5'
},
receivedAmount: {
assetCode: 'USD',
assetScale: 2,
value: '0'
},
ilpStreamConnection
})

expect(() => validateIncomingPayment(incomingPayment)).toThrow(
'Stream connection asset information does not match incoming payment asset information'
)
})

test('throws if receiving amount asset scale is different that ilp connection asset scale', async (): Promise<void> => {
const ilpStreamConnection = mockILPStreamConnection({
assetCode: 'USD',
assetScale: 1
})

const incomingPayment = mockIncomingPaymentWithConnection({
incomingAmount: {
assetCode: 'USD',
assetScale: 2,
value: '5'
},
receivedAmount: {
assetCode: 'USD',
assetScale: 2,
value: '0'
},
ilpStreamConnection
})

expect(() => validateIncomingPayment(incomingPayment)).toThrow(
'Stream connection asset information does not match incoming payment asset information'
)
})
})

describe('validateCreatedIncomingPayment', (): void => {
Expand Down Expand Up @@ -653,7 +602,7 @@ describe('incoming-payment', (): void => {

const getSpy = jest
.spyOn(requestors, 'get')
.mockResolvedValueOnce(mockIncomingPaymentWithConnection())
.mockResolvedValueOnce(mockIncomingPayment())

await createIncomingPaymentRoutes({
openApi,
Expand All @@ -679,7 +628,7 @@ describe('incoming-payment', (): void => {

const incomingPaymentPaginationResult =
mockIncomingPaymentPaginationResult({
result: [mockIncomingPaymentWithConnectionUrl()]
result: [mockIncomingPayment()]
})
const url = `${walletAddress}${getRSPath('/incoming-payments')}`

Expand Down Expand Up @@ -727,9 +676,7 @@ describe('incoming-payment', (): void => {

const postSpy = jest
.spyOn(requestors, 'post')
.mockResolvedValueOnce(
mockIncomingPaymentWithConnection(incomingPaymentCreateArgs)
)
.mockResolvedValueOnce(mockIncomingPayment(incomingPaymentCreateArgs))

await createIncomingPaymentRoutes({
openApi,
Expand Down
44 changes: 12 additions & 32 deletions packages/open-payments/src/client/incoming-payment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,16 @@ import {
getRSPath,
CreateIncomingPaymentArgs,
PaginationArgs,
IncomingPaymentPaginationResult,
IncomingPaymentWithConnectionUrl,
IncomingPaymentWithConnection
IncomingPaymentPaginationResult
} from '../types'
import { get, post } from './requests'

type AnyIncomingPayment =
| IncomingPayment
| IncomingPaymentWithConnection
| IncomingPaymentWithConnectionUrl

export interface IncomingPaymentRoutes {
get(args: ResourceRequestArgs): Promise<IncomingPaymentWithConnection>
get(args: ResourceRequestArgs): Promise<IncomingPayment>
create(
args: CollectionRequestArgs,
createArgs: CreateIncomingPaymentArgs
): Promise<IncomingPaymentWithConnection>
): Promise<IncomingPayment>
complete(args: ResourceRequestArgs): Promise<IncomingPayment>
list(
args: CollectionRequestArgs,
Expand All @@ -40,7 +33,7 @@ export const createIncomingPaymentRoutes = (
const { axiosInstance, openApi, logger } = deps

const getIncomingPaymentOpenApiValidator =
openApi.createResponseValidator<IncomingPaymentWithConnection>({
openApi.createResponseValidator<IncomingPayment>({
path: getRSPath('/incoming-payments/{id}'),
method: HttpMethod.GET
})
Expand Down Expand Up @@ -99,7 +92,7 @@ export const createIncomingPaymentRoutes = (
export const getIncomingPayment = async (
deps: BaseDeps,
args: ResourceRequestArgs,
validateOpenApiResponse: ResponseValidator<IncomingPaymentWithConnection>
validateOpenApiResponse: ResponseValidator<IncomingPayment>
) => {
const { axiosInstance, logger } = deps
const { url } = args
Expand Down Expand Up @@ -222,9 +215,9 @@ export const listIncomingPayment = async (
return incomingPayments
}

export const validateIncomingPayment = <T extends AnyIncomingPayment>(
payment: T
): T => {
export const validateIncomingPayment = (
payment: IncomingPayment
): IncomingPayment => {
if (payment.incomingAmount) {
const { incomingAmount, receivedAmount } = payment
if (
Expand All @@ -245,32 +238,19 @@ export const validateIncomingPayment = <T extends AnyIncomingPayment>(
}
}

if (
'ilpStreamConnection' in payment &&
typeof payment.ilpStreamConnection === 'object' &&
(payment.ilpStreamConnection.assetCode !==
payment.receivedAmount.assetCode ||
payment.ilpStreamConnection.assetScale !==
payment.receivedAmount.assetScale)
) {
throw new Error(
'Stream connection asset information does not match incoming payment asset information'
)
}

return payment
}

export const validateCreatedIncomingPayment = (
payment: IncomingPaymentWithConnection
): IncomingPaymentWithConnection => {
payment: IncomingPayment
): IncomingPayment => {
const { receivedAmount, completed } = payment

if (BigInt(receivedAmount.value) !== BigInt(0)) {
throw new Error('Received amount is a non-zero value.')
}

if (completed === true) {
if (completed) {
throw new Error('Can not create a completed incoming payment.')
}

Expand All @@ -282,7 +262,7 @@ export const validateCompletedIncomingPayment = (
): IncomingPayment => {
const { completed } = payment

if (completed === false) {
if (!completed) {
throw new Error('Incoming payment could not be completed.')
}

Expand Down
6 changes: 0 additions & 6 deletions packages/open-payments/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ export {
GrantRequest,
GrantContinuationRequest,
IncomingPayment,
IncomingPaymentWithConnection,
IncomingPaymentWithConnectionUrl,
ILPStreamConnection,
Quote,
OutgoingPayment,
PendingGrant,
Expand All @@ -28,11 +25,8 @@ export {
} from './client'

export {
mockILPStreamConnection,
mockWalletAddress,
mockIncomingPayment,
mockIncomingPaymentWithConnection,
mockIncomingPaymentWithConnectionUrl,
mockOutgoingPayment,
mockIncomingPaymentPaginationResult,
mockOutgoingPaymentPaginationResult,
Expand Down
Loading

0 comments on commit 4e98e06

Please sign in to comment.