From 2db18dbf6f0dd19c89fbaca3df92d80f59a41481 Mon Sep 17 00:00:00 2001 From: Sabine Schaller Date: Mon, 31 Jul 2023 14:30:38 +0200 Subject: [PATCH 01/15] feat: add properties for quoting --- openapi/resource-server.yaml | 325 ++++++++++++++++++++++++----------- 1 file changed, 223 insertions(+), 102 deletions(-) diff --git a/openapi/resource-server.yaml b/openapi/resource-server.yaml index 3520ec6d..9f7fd695 100644 --- a/openapi/resource-server.yaml +++ b/openapi/resource-server.yaml @@ -167,7 +167,8 @@ paths: assetScale: 2 completed: false expiresAt: '2022-02-03T23:20:50.52Z' - metadata: { externalRef: 'INV2022-02-0137' } + metadata: + externalRef: INV2022-02-0137 ilpStreamConnection: id: 'https://openpayments.guide/connections/ff394f02-7b7b-45e2-b645-51d04e7c345c' ilpAddress: g.ilp.iwuyge987y.98y08y @@ -185,10 +186,11 @@ paths: application/json: schema: type: object + additionalProperties: false properties: incomingAmount: - description: The maximum amount that should be paid into the payment pointer under this incoming payment. $ref: ./schemas.yaml#/components/schemas/amount + description: The maximum amount that should be paid into the payment pointer under this incoming payment. expiresAt: type: string description: The date and time when payments into the incoming payment must no longer be accepted. @@ -196,9 +198,10 @@ paths: writeOnly: true metadata: type: object - additionalProperties: true description: Additional metadata associated with the incoming payment. (Optional) - additionalProperties: false + feeStructure: + type: boolean + description: Request receiving fee structure examples: Create incoming payment for $25 to pay invoice INV2022-02-0137: value: @@ -206,7 +209,9 @@ paths: value: '2500' assetCode: USD assetScale: 2 - metadata: { externalRef: 'INV2022-02-0137' } + metadata: + externalRef: INV2022-02-0137 + feeStructure: true description: |- A subset of the incoming payments schema is accepted as input to create a new incoming payment. @@ -268,10 +273,8 @@ paths: createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: - { - description: 'Hi Mo, this is for the cappuccino I bought for you the other day.', - externalRef: 'Coffee w/ Mo on 10 March 22' - } + description: 'Hi Mo, this is for the cappuccino I bought for you the other day.' + externalRef: Coffee w/ Mo on 10 March 22 completed: true - id: 'https://openpayments.guide/alice/incoming-payments/32abc219-3dc3-44ec-a225-790cacfca8fa' paymentPointer: 'https://openpayments.guide/alice/' @@ -284,9 +287,7 @@ paths: createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: - { - description: 'I love your website, Alice! Thanks for the great content' - } + description: 'I love your website, Alice! Thanks for the great content' completed: false backward pagination: value: @@ -308,9 +309,7 @@ paths: createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: - { - description: 'I love your website, Alice! Thanks for the great content' - } + description: 'I love your website, Alice! Thanks for the great content' - id: 'https://openpayments.guide/alice/incoming-payments/016da9d5-c9a4-4c80-a354-86b915a04ff8' paymentPointer: 'https://openpayments.guide/alice/' incomingAmount: @@ -327,10 +326,8 @@ paths: createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: - { - description: 'Hi Mo, this is for the cappuccino I bought for you the other day.', - externalRef: 'Coffee w/ Mo on 10 March 22' - } + description: 'Hi Mo, this is for the cappuccino I bought for you the other day.' + externalRef: Coffee w/ Mo on 10 March 22 '401': $ref: '#/components/responses/401' '403': @@ -364,8 +361,8 @@ paths: paymentPointer: 'https://openpayments.guide/alice/' failed: false receiver: 'https://openpayments.guide/bob/incoming-payments/48884225-b393-4872-90de-1b737e2491c2' - sendAmount: - value: '2500' + maxSendAmount: + value: '2600' assetCode: USD assetScale: 2 receiveAmount: @@ -376,7 +373,17 @@ paths: value: '0' assetCode: USD assetScale: 2 - metadata: { description: Thank you for the shoes. } + fees: + sendFeeAmount: + value: '100' + assetCode: USD + assetScale: 2 + receiveFeeAmount: + value: '0' + assetCode: USD + assetScale: 2 + metadata: + description: Thank you for the shoes. createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' '401': @@ -390,7 +397,8 @@ paths: Create an outgoing payment based on a quote: value: quoteId: 'https://openpayments.guide/alice/quotes/ab03296b-0c8b-4776-b94e-7ee27d868d4d' - metadata: { externalRef: 'INV2022-02-0137' } + metadata: + externalRef: INV2022-02-0137 schema: type: object properties: @@ -452,27 +460,34 @@ paths: value: '2500' assetCode: USD assetScale: 2 - sendAmount: - value: '2500' + maxSendAmount: + value: '2600' assetCode: USD assetScale: 2 sentAmount: value: '2500' assetCode: USD assetScale: 2 + fees: + sendFeeAmount: + value: '100' + assetCode: USD + assetScale: 2 + receiveFeeAmount: + value: '0' + assetCode: USD + assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: - { - description: 'APlusVideo subscription', - externalRef: 'customer: 847458475' - } + description: APlusVideo subscription + externalRef: 'customer: 847458475' - id: 'https://openpayments.guide/alice/outgoing-payments/0cffa5a4-58fd-4cc8-8e01-7145c72bf07c' paymentPointer: 'https://openpayments.guide/alice/' failed: false receiver: 'https://openpayments.guide/shoeshop/incoming-payments/2fe92c6f-ef0d-487c-8759-3784eae6bce9' - sendAmount: - value: '7026' + maxSendAmount: + value: '7126' assetCode: USD assetScale: 2 receiveAmount: @@ -483,13 +498,20 @@ paths: value: '7026' assetCode: USD assetScale: 2 + fees: + sendFeeAmount: + value: '100' + assetCode: USD + assetScale: 2 + receiveFeeAmount: + value: '0' + assetCode: USD + assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: - { - description: 'Thank you for your purchase at ShoeShop!', - externalRef: 'INV2022-8943756' - } + description: Thank you for your purchase at ShoeShop! + externalRef: INV2022-8943756 backward pagination: value: pagination: @@ -502,8 +524,8 @@ paths: paymentPointer: 'https://openpayments.guide/alice/' failed: false receiver: 'https://openpayments.guide/shoeshop/incoming-payments/2fe92c6f-ef0d-487c-8759-3784eae6bce9' - sendAmount: - value: '7026' + maxSendAmount: + value: '7126' assetCode: USD assetScale: 2 receiveAmount: @@ -514,13 +536,20 @@ paths: value: '7026' assetCode: USD assetScale: 2 + fees: + sendFeeAmount: + value: '100' + assetCode: USD + assetScale: 2 + receiveFeeAmount: + value: '0' + assetCode: USD + assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: - { - description: 'Thank you for your purchase at ShoeShop!', - externalRef: 'INV2022-8943756' - } + description: Thank you for your purchase at ShoeShop! + externalRef: INV2022-8943756 - id: 'https://openpayments.guide/alice/outgoing-payments/8c68d3cc-0a0f-4216-98b4-4fa44a6c88cf' paymentPointer: 'https://openpayments.guide/alice/' failed: false @@ -529,21 +558,28 @@ paths: value: '2500' assetCode: USD assetScale: 2 - sendAmount: - value: '2500' + maxSendAmount: + value: '2600' assetCode: USD assetScale: 2 sentAmount: value: '2500' assetCode: USD assetScale: 2 + fees: + sendFeeAmount: + value: '100' + assetCode: USD + assetScale: 2 + receiveFeeAmount: + value: '0' + assetCode: USD + assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: - { - description: 'APlusVideo subscription', - externalRef: 'customer: 847458475' - } + description: APlusVideo subscription + externalRef: 'customer: 847458475' '401': $ref: '#/components/responses/401' '403': @@ -576,7 +612,7 @@ paths: id: 'https://openpayments.guide/alice/quotes/8c68d3cc-0a0f-4216-98b4-4fa44a6c88cf' paymentPointer: 'https://openpayments.guide/alice/' receiver: 'https://openpayments.guide/aplusvideo/incoming-payments/45d495ad-b763-4882-88d7-aa14d261686e' - sendAmount: + maxSendAmount: value: '2500' assetCode: USD assetScale: 2 @@ -584,6 +620,15 @@ paths: value: '2198' assetCode: EUR assetScale: 2 + fees: + sendFeeAmount: + value: '100' + assetCode: USD + assetScale: 2 + receiveFeeAmount: + value: '0' + assetCode: USD + assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' expiresAt: '2022-04-12T23:20:50.52Z' '400': @@ -641,7 +686,6 @@ paths: - receiver - sendAmount additionalProperties: false - description: |- A subset of the quotes schema is accepted as input to create a new quote. @@ -683,10 +727,8 @@ paths: createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: - { - description: 'Thanks for the flowers!', - externalRef: 'INV-12876' - } + description: Thanks for the flowers! + externalRef: INV-12876 ilpStreamConnection: id: 'https://openpayments.guide/connections/4a1b0150-db73-49e8-8713-628baa4a17ff' ilpAddress: g.ilp.iwuyge987y.98y08y @@ -737,10 +779,8 @@ paths: createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: - { - description: 'Hi Mo, this is for the cappuccino I bought for you the other day.', - externalRef: 'Coffee w/ Mo on 10 March 2' - } + description: 'Hi Mo, this is for the cappuccino I bought for you the other day.' + externalRef: Coffee w/ Mo on 10 March 2 '401': $ref: '#/components/responses/401' '403': @@ -776,7 +816,7 @@ paths: paymentPointer: 'https://openpayments.guide/bob/' failed: false receiver: 'https://openpayments.guide/alice/incoming-payments/2f1b0150-db73-49e8-8713-628baa4a17ff' - sendAmount: + maxSendAmount: value: '2500' assetCode: USD assetScale: 2 @@ -788,13 +828,20 @@ paths: value: '1205' assetCode: USD assetScale: 2 + fees: + sendFeeAmount: + value: '100' + assetCode: USD + assetScale: 2 + receiveFeeAmount: + value: '0' + assetCode: USD + assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: - { - description: 'Thanks for the flowers!', - externalRef: 'INV-12876' - } + description: Thanks for the flowers! + externalRef: INV-12876 '401': $ref: '#/components/responses/401' '403': @@ -826,7 +873,7 @@ paths: id: 'https://openpayments.guide/bob/quotes/3859b39e-4666-4ce5-8745-72f1864c5371' paymentPointer: 'https://openpayments.guide/bob/' receiver: 'https://openpayments.guide/alice/incoming-payments/2f1b0150-db73-49e8-8713-628baa4a17ff' - sendAmount: + maxSendAmount: value: '2500' assetCode: USD assetScale: 2 @@ -834,6 +881,15 @@ paths: value: '2198' assetCode: EUR assetScale: 2 + fees: + sendFeeAmount: + value: '100' + assetCode: USD + assetScale: 2 + receiveFeeAmount: + value: '0' + assetCode: USD + assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' expiresAt: '2022-04-12T23:20:50.52Z' '401': @@ -962,10 +1018,8 @@ components: createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: - { - description: 'Hi Mo, this is for the cappuccino I bought for you the other day.', - externalRef: 'Coffee w/ Mo on 10 March 22' - } + description: 'Hi Mo, this is for the cappuccino I bought for you the other day.' + externalRef: Coffee w/ Mo on 10 March 22 - id: 'https://openpayments.guide/alice/incoming-payments/456da9d5-c9a4-4c80-a354-86b915a04ff8' paymentPointer: 'https://openpayments.guide/alice/' incomingAmount: @@ -995,19 +1049,21 @@ components: description: Describes whether the incoming payment has completed receiving fund. default: false incomingAmount: - description: The maximum amount that should be paid into the payment pointer under this incoming payment. $ref: ./schemas.yaml#/components/schemas/amount + description: The maximum amount that should be paid into the payment pointer under this incoming payment. receivedAmount: - description: The total amount that has been paid into the payment pointer under this incoming payment. $ref: ./schemas.yaml#/components/schemas/amount + description: The total amount that has been paid into the payment pointer under this incoming payment. expiresAt: type: string description: The date and time when payments under this incoming payment will no longer be accepted. format: date-time metadata: type: object - additionalProperties: true description: Additional metadata associated with the incoming payment. (Optional) + feeStructure: + $ref: '#/components/schemas/feeStructure' + description: Fixed and variable receiving Account Servicing Entity fees. createdAt: type: string format: date-time @@ -1043,10 +1099,8 @@ components: createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: - { - description: 'Hi Mo, this is for the cappuccino I bought for you the other day.', - externalRef: 'Coffee w/ Mo on 10 March 22' - } + description: 'Hi Mo, this is for the cappuccino I bought for you the other day.' + externalRef: Coffee w/ Mo on 10 March 22 ilpStreamConnection: id: 'https://openpayments.guide/connections/032da9d5-c9a4-4c80-a354-86b915a04ff8' ilpApddress: g.ilp.iwuyge987y.98y08y @@ -1100,40 +1154,55 @@ components: value: '2500' assetCode: USD assetScale: 2 - sendAmount: - value: '2500' + maxSendAmount: + value: '2600' assetCode: USD assetScale: 2 sentAmount: value: '2500' assetCode: USD assetScale: 2 + fees: + sendFeeAmount: + value: '100' + assetCode: USD + assetScale: 2 + receiveFeeAmount: + value: '0' + assetCode: USD + assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: - { - description: 'APlusVideo subscription', - externalRef: 'customer: 847458475' - } + description: APlusVideo subscription + externalRef: 'customer: 847458475' - id: 'https://openpayments.guide/alice/outgoing-payments/0cffa5a4-58fd-4cc8-8e01-7145c72bf07c' paymentPointer: 'https://openpayments.guide/alice/' failed: false receiver: 'https://openpayments.guide/shoeshop/2fe92c6f-ef0d-487c-8759-3784eae6bce9' - sendAmount: - value: '7026' + maxSendAmount: + value: '7126' assetCode: USD assetScale: 2 sentAmount: value: '7026' assetCode: USD assetScale: 2 + fees: + sendFeeAmount: + value: '100' + assetCode: USD + assetScale: 2 + receiveFeeAmount: + value: '0' + assetCode: USD + assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: - { - description: 'Thank you for your purchase at ShoeShop!', - externalRef: 'INV2022-8943756' - } + description: Thank you for your purchase at ShoeShop! + externalRef: INV2022-8943756 + additionalProperties: false properties: id: type: string @@ -1155,21 +1224,23 @@ components: description: Describes whether the payment failed to send its full amount. default: false receiver: - description: The URL of the incoming payment or ILP STREAM Connection that is being paid. $ref: ./schemas.yaml#/components/schemas/receiver + description: The URL of the incoming payment or ILP STREAM Connection that is being paid. receiveAmount: - description: The total amount that should be received by the receiver when this outgoing payment has been paid. $ref: ./schemas.yaml#/components/schemas/amount - sendAmount: - description: The total amount that should be sent when this outgoing payment has been paid. + description: The total amount that should be received by the receiver when this outgoing payment has been paid. + maxSendAmount: $ref: ./schemas.yaml#/components/schemas/amount + description: The total amount that should be deducted from the sender's account when this outgoing payment has been paid. sentAmount: - description: The total amount that has been sent under this outgoing payment. $ref: ./schemas.yaml#/components/schemas/amount + description: The total amount that has been sent under this outgoing payment. metadata: type: object - additionalProperties: true description: Additional metadata associated with the outgoing payment. (Optional) + fees: + $ref: '#/components/schemas/fees' + description: Fee structure createdAt: type: string format: date-time @@ -1182,12 +1253,12 @@ components: - id - paymentPointer - receiver - - sendAmount - receiveAmount + - maxSendAmount - sentAmount + - fees - createdAt - updatedAt - additionalProperties: false quote: title: Quote description: A **quote** resource represents the quoted amount details with which an Outgoing Payment may be created. @@ -1200,23 +1271,45 @@ components: value: '2500' assetCode: USD assetScale: 2 - sendAmount: + maxSendAmount: + value: '2600' + assetCode: USD + assetScale: 2 + sentAmount: value: '2500' assetCode: USD assetScale: 2 + fees: + sendFeeAmount: + value: '100' + assetCode: USD + assetScale: 2 + receiveFeeAmount: + value: '0' + assetCode: USD + assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' expiresAt: '2022-04-12T23:20:50.52Z' - id: 'https://openpayments.guide/alice/quotes/8c68d3cc-0a0f-4216-98b4-4fa44a6c88cf' paymentPointer: 'https://openpayments.guide/alice/' receiver: 'https://openpayments.guide/aplusvideo/incoming-payments/45d495ad-b763-4882-88d7-aa14d261686e' - sendAmount: - value: '2500' + maxSendAmount: + value: '7126' assetCode: USD assetScale: 2 - receiveAmount: - value: '2198' - assetCode: EUR + sentAmount: + value: '7026' + assetCode: USD assetScale: 2 + fees: + sendFeeAmount: + value: '100' + assetCode: USD + assetScale: 2 + receiveFeeAmount: + value: '0' + assetCode: USD + assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' expiresAt: '2022-04-12T23:20:50.52Z' additionalProperties: false @@ -1233,10 +1326,16 @@ components: readOnly: true receiver: $ref: ./schemas.yaml#/components/schemas/receiver + description: The URL of the incoming payment or ILP STREAM Connection that the quote is created for. receiveAmount: $ref: ./schemas.yaml#/components/schemas/amount - sendAmount: + description: The total amount that should be received by the receiver when the corresponding outgoing payment has been paid. + maxSendAmount: $ref: ./schemas.yaml#/components/schemas/amount + description: 'The total amount that should be deducted from the sender''s account when the corresponding outgoing payment has been paid. ' + fees: + $ref: '#/components/schemas/fees' + description: Fee structure expiresAt: type: string description: The date and time when the calculated `sendAmount` is no longer valid. @@ -1250,7 +1349,8 @@ components: - paymentPointer - receiver - receiveAmount - - sendAmount + - maxSendAmount + - fees - createdAt page-info: description: '' @@ -1324,6 +1424,27 @@ components: kty: OKP crv: Ed25519 x: oy0L_vTygNE4IogRyn_F5GmHXdqYVjIXkWs2jky7zsI + feeStructure: + title: feeStructure + type: object + properties: + fixed: + $ref: ./schemas.yaml#/components/schemas/amount + percentage: + type: string + fees: + title: fees + type: object + properties: + sendFeeAmount: + $ref: ./schemas.yaml#/components/schemas/amount + description: Sending Accoung Servicing Entity's fees + ILP network fees + receiveFeeAmount: + $ref: ./schemas.yaml#/components/schemas/amount + description: Receiving Account Servicing Entity's fees. They are zero if sender does not pay receiving fees. + required: + - sendFeeAmount + - receiveFeeAmount securitySchemes: GNAP: name: Authorization From 4defa145bb207efcc65334c67e81f85d4340a5b3 Mon Sep 17 00:00:00 2001 From: Sabine Schaller Date: Mon, 31 Jul 2023 14:37:12 +0200 Subject: [PATCH 02/15] fix: formatting --- openapi/resource-server.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi/resource-server.yaml b/openapi/resource-server.yaml index 9f7fd695..6f4a3121 100644 --- a/openapi/resource-server.yaml +++ b/openapi/resource-server.yaml @@ -1332,7 +1332,7 @@ components: description: The total amount that should be received by the receiver when the corresponding outgoing payment has been paid. maxSendAmount: $ref: ./schemas.yaml#/components/schemas/amount - description: 'The total amount that should be deducted from the sender''s account when the corresponding outgoing payment has been paid. ' + description: "The total amount that should be deducted from the sender's account when the corresponding outgoing payment has been paid. " fees: $ref: '#/components/schemas/fees' description: Fee structure From daa0c4c23c8839440e62121ff161b1afd405f8d4 Mon Sep 17 00:00:00 2001 From: Sabine Schaller Date: Mon, 31 Jul 2023 14:53:18 +0200 Subject: [PATCH 03/15] fix: types --- .../generated/resource-server-types.ts | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/packages/open-payments/src/openapi/generated/resource-server-types.ts b/packages/open-payments/src/openapi/generated/resource-server-types.ts index 9f091529..ade259e7 100644 --- a/packages/open-payments/src/openapi/generated/resource-server-types.ts +++ b/packages/open-payments/src/openapi/generated/resource-server-types.ts @@ -190,6 +190,8 @@ export interface components { expiresAt?: string; /** @description Additional metadata associated with the incoming payment. (Optional) */ metadata?: { [key: string]: unknown }; + /** @description Fixed and variable receiving Account Servicing Entity fees. */ + feeStructure?: components["schemas"]["feeStructure"]; /** * Format: date-time * @description The date and time when the incoming payment was created. @@ -245,12 +247,14 @@ export interface components { receiver: external["schemas.yaml"]["components"]["schemas"]["receiver"]; /** @description The total amount that should be received by the receiver when this outgoing payment has been paid. */ receiveAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; - /** @description The total amount that should be sent when this outgoing payment has been paid. */ - sendAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; + /** @description The total amount that should be deducted from the sender's account when this outgoing payment has been paid. */ + maxSendAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; /** @description The total amount that has been sent under this outgoing payment. */ sentAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; /** @description Additional metadata associated with the outgoing payment. (Optional) */ metadata?: { [key: string]: unknown }; + /** @description Fee structure */ + fees: components["schemas"]["fees"]; /** * Format: date-time * @description The date and time when the outgoing payment was created. @@ -277,9 +281,14 @@ export interface components { * @description The URL of the payment pointer from which this quote's payment would be sent. */ paymentPointer: string; + /** @description The URL of the incoming payment or ILP STREAM Connection that the quote is created for. */ receiver: external["schemas.yaml"]["components"]["schemas"]["receiver"]; + /** @description The total amount that should be received by the receiver when the corresponding outgoing payment has been paid. */ receiveAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; - sendAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; + /** @description The total amount that should be deducted from the sender's account when the corresponding outgoing payment has been paid. */ + maxSendAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; + /** @description Fee structure */ + fees: components["schemas"]["fees"]; /** @description The date and time when the calculated `sendAmount` is no longer valid. */ expiresAt?: string; /** @@ -312,6 +321,18 @@ export interface components { /** @description The base64 url-encoded public key. */ x: string; }; + /** feeStructure */ + feeStructure: { + fixed?: external["schemas.yaml"]["components"]["schemas"]["amount"]; + percentage?: string; + }; + /** fees */ + fees: { + /** @description Sending Accoung Servicing Entity's fees + ILP network fees */ + sendFeeAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; + /** @description Receiving Account Servicing Entity's fees. They are zero if sender does not pay receiving fees. */ + receiveFeeAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; + }; }; responses: { /** Authorization required */ @@ -476,6 +497,8 @@ export interface operations { expiresAt?: string; /** @description Additional metadata associated with the incoming payment. (Optional) */ metadata?: { [key: string]: unknown }; + /** @description Request receiving fee structure */ + feeStructure?: boolean; }; }; }; From 12221584e881d9b8a4ab6566c331f7c06fefbf57 Mon Sep 17 00:00:00 2001 From: Sabine Schaller Date: Mon, 31 Jul 2023 15:24:56 +0200 Subject: [PATCH 04/15] fix: op package with new types --- .../src/client/outgoing-payment.ts | 10 +++---- packages/open-payments/src/test/helpers.ts | 28 +++++++++++++++++-- packages/open-payments/src/types.ts | 2 +- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/packages/open-payments/src/client/outgoing-payment.ts b/packages/open-payments/src/client/outgoing-payment.ts index 8a1b1b5a..8a5fa636 100644 --- a/packages/open-payments/src/client/outgoing-payment.ts +++ b/packages/open-payments/src/client/outgoing-payment.ts @@ -176,19 +176,19 @@ export const listOutgoingPayments = async ( export const validateOutgoingPayment = ( payment: OutgoingPayment ): OutgoingPayment => { - const { sendAmount, sentAmount } = payment + const { maxSendAmount, sentAmount } = payment if ( - sendAmount.assetCode !== sentAmount.assetCode || - sendAmount.assetScale !== sentAmount.assetScale + maxSendAmount.assetCode !== sentAmount.assetCode || + maxSendAmount.assetScale !== sentAmount.assetScale ) { throw new Error( 'Asset code or asset scale of sending amount does not match sent amount' ) } - if (BigInt(sendAmount.value) < BigInt(sentAmount.value)) { + if (BigInt(maxSendAmount.value) < BigInt(sentAmount.value)) { throw new Error('Amount sent is larger than maximum amount to send') } - if (sendAmount.value === sentAmount.value && payment.failed) { + if (maxSendAmount.value === sentAmount.value && payment.failed) { throw new Error('Amount to send matches sent amount but payment failed') } diff --git a/packages/open-payments/src/test/helpers.ts b/packages/open-payments/src/test/helpers.ts index 8851ba0d..bf2c25b8 100644 --- a/packages/open-payments/src/test/helpers.ts +++ b/packages/open-payments/src/test/helpers.ts @@ -154,7 +154,7 @@ export const mockOutgoingPayment = ( id: `https://example.com/.well-known/pay/outgoing-payments/${uuid()}`, paymentPointer: 'https://example.com/.well-known/pay', failed: false, - sendAmount: { + maxSendAmount: { assetCode: 'USD', assetScale: 2, value: '10' @@ -169,6 +169,18 @@ export const mockOutgoingPayment = ( assetScale: 2, value: '10' }, + fees: { + sendFeeAmount: { + assetCode: 'USD', + assetScale: 2, + value: '0' + }, + receiveFeeAmount: { + assetCode: 'USD', + assetScale: 2, + value: '0' + } + }, quoteId: uuid(), receiver: uuid(), metadata: { externalRef: 'INV #1', description: 'some description' }, @@ -286,7 +298,7 @@ export const mockQuote = (overrides?: Partial): Quote => ({ id: `https://example.com/.well-known/pay/quotes/${uuid()}`, receiver: 'https://example.com/.well-known/peer', paymentPointer: 'https://example.com/.well-known/pay', - sendAmount: { + maxSendAmount: { value: '100', assetCode: 'USD', assetScale: 2 @@ -296,6 +308,18 @@ export const mockQuote = (overrides?: Partial): Quote => ({ assetCode: 'USD', assetScale: 2 }, + fees: { + sendFeeAmount: { + assetCode: 'USD', + assetScale: 2, + value: '0' + }, + receiveFeeAmount: { + assetCode: 'USD', + assetScale: 2, + value: '0' + } + }, createdAt: new Date().toISOString(), expiresAt: new Date(Date.now() + 60_000).toISOString(), ...overrides diff --git a/packages/open-payments/src/types.ts b/packages/open-payments/src/types.ts index e93c700a..8b8923a8 100644 --- a/packages/open-payments/src/types.ts +++ b/packages/open-payments/src/types.ts @@ -52,7 +52,7 @@ type QuoteArgsBase = { receiver: RSOperations['create-quote']['requestBody']['content']['application/json']['receiver'] } type QuoteArgsWithSendAmount = QuoteArgsBase & { - sendAmount?: RSComponents['schemas']['quote']['sendAmount'] + sendAmount?: RSComponents['schemas']['quote']['maxSendAmount'] receiveAmount?: never } type QuoteArgsWithReceiveAmount = QuoteArgsBase & { From dea5221394037d7887f8a9a130a5e48b826ec340 Mon Sep 17 00:00:00 2001 From: Sabine Schaller Date: Mon, 31 Jul 2023 15:35:19 +0200 Subject: [PATCH 05/15] chore: add changeset --- .changeset/tender-ravens-breathe.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/tender-ravens-breathe.md diff --git a/.changeset/tender-ravens-breathe.md b/.changeset/tender-ravens-breathe.md new file mode 100644 index 00000000..1a4707ee --- /dev/null +++ b/.changeset/tender-ravens-breathe.md @@ -0,0 +1,5 @@ +--- +'@interledger/open-payments': minor +--- + +Adding properties for new quoting mechanism From e6994b3648be3b560ae035bba1d20a279027be70 Mon Sep 17 00:00:00 2001 From: Sabine Schaller Date: Mon, 31 Jul 2023 15:43:02 +0200 Subject: [PATCH 06/15] fix: tests --- .../src/client/outgoing-payment.test.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/open-payments/src/client/outgoing-payment.test.ts b/packages/open-payments/src/client/outgoing-payment.test.ts index 8c104745..0fd23875 100644 --- a/packages/open-payments/src/client/outgoing-payment.test.ts +++ b/packages/open-payments/src/client/outgoing-payment.test.ts @@ -62,7 +62,7 @@ describe('outgoing-payment', (): void => { test('throws if outgoing payment does not pass validation', async (): Promise => { const outgoingPayment = mockOutgoingPayment({ - sendAmount: { + maxSendAmount: { assetCode: 'USD', assetScale: 3, value: '5' @@ -194,7 +194,7 @@ describe('outgoing-payment', (): void => { test('throws if an outgoing payment does not pass validation', async (): Promise => { const invalidOutgoingPayment = mockOutgoingPayment({ - sendAmount: { + maxSendAmount: { assetCode: 'CAD', assetScale: 2, value: '5' @@ -291,7 +291,7 @@ describe('outgoing-payment', (): void => { test('throws if outgoing payment does not pass validation', async (): Promise => { const outgoingPayment = mockOutgoingPayment({ - sendAmount: { + maxSendAmount: { assetCode: 'USD', assetScale: 3, value: '5' @@ -361,7 +361,7 @@ describe('outgoing-payment', (): void => { test('throws if send amount and sent amount asset scales are different', async (): Promise => { const outgoingPayment = mockOutgoingPayment({ - sendAmount: { + maxSendAmount: { assetCode: 'USD', assetScale: 3, value: '5' @@ -380,7 +380,7 @@ describe('outgoing-payment', (): void => { test('throws if send amount and sent amount asset codes are different', async (): Promise => { const outgoingPayment = mockOutgoingPayment({ - sendAmount: { + maxSendAmount: { assetCode: 'CAD', assetScale: 2, value: '5' @@ -399,7 +399,7 @@ describe('outgoing-payment', (): void => { test('throws if sent amount is larger than send amount', async (): Promise => { const outgoingPayment = mockOutgoingPayment({ - sendAmount: { + maxSendAmount: { assetCode: 'USD', assetScale: 2, value: '5' @@ -418,7 +418,7 @@ describe('outgoing-payment', (): void => { test('throws if sent amount equals send amount, but payment has failed', async (): Promise => { const outgoingPayment = mockOutgoingPayment({ - sendAmount: { + maxSendAmount: { assetCode: 'USD', assetScale: 2, value: '5' From 66e4ae93c93c12fe94386be693947a6faf6351a5 Mon Sep 17 00:00:00 2001 From: Sabine Schaller Date: Wed, 23 Aug 2023 09:57:37 +0200 Subject: [PATCH 07/15] chore: remove fees, rename (max)sendAmount -> debit Amount --- openapi/auth-server.yaml | 10 +- openapi/resource-server.yaml | 176 ++---------------- .../src/client/outgoing-payment.test.ts | 14 +- .../src/client/outgoing-payment.ts | 10 +- .../openapi/generated/auth-server-types.ts | 2 +- .../generated/resource-server-types.ts | 24 +-- packages/open-payments/src/test/helpers.ts | 28 +-- 7 files changed, 38 insertions(+), 226 deletions(-) diff --git a/openapi/auth-server.yaml b/openapi/auth-server.yaml index 7da138aa..9972feb1 100644 --- a/openapi/auth-server.yaml +++ b/openapi/auth-server.yaml @@ -112,7 +112,7 @@ paths: limits: receiver: 'https://openpayments.guide/connections/45a0d0ee-26dc-4c66-89e0-01fbf93156f7' interval: 'R12/2019-08-24T14:15:22Z/P1M' - sendAmount: + debitAmount: value: '500' assetCode: USD assetScale: 2 @@ -180,7 +180,7 @@ paths: limits: receiver: 'https://openpayments.guide/bob/incoming-payments/48884225-b393-4872-90de-1b737e2491c2' interval: 'R12/2019-08-24T14:15:22Z/P1M' - sendAmount: + debitAmount: value: '500' assetCode: USD assetScale: 2 @@ -275,7 +275,7 @@ paths: limits: interval: 'R12/2019-08-24T14:15:22Z/P1M' receiver: 'https://openpayments.guide/bob/incoming-payments/48884225-b393-4872-90de-1b737e2491c2' - sendAmount: + debitAmount: value: '500' assetCode: USD assetScale: 2 @@ -515,7 +515,7 @@ components: properties: receiver: $ref: './schemas.yaml#/components/schemas/receiver' - sendAmount: + debitAmount: $ref: './schemas.yaml#/components/schemas/amount' receiveAmount: $ref: './schemas.yaml#/components/schemas/amount' @@ -526,7 +526,7 @@ components: required: - interval - required: - - sendAmount + - debitAmount - required: - receiveAmount securitySchemes: diff --git a/openapi/resource-server.yaml b/openapi/resource-server.yaml index 6f4a3121..b0133e2e 100644 --- a/openapi/resource-server.yaml +++ b/openapi/resource-server.yaml @@ -199,9 +199,6 @@ paths: metadata: type: object description: Additional metadata associated with the incoming payment. (Optional) - feeStructure: - type: boolean - description: Request receiving fee structure examples: Create incoming payment for $25 to pay invoice INV2022-02-0137: value: @@ -211,7 +208,6 @@ paths: assetScale: 2 metadata: externalRef: INV2022-02-0137 - feeStructure: true description: |- A subset of the incoming payments schema is accepted as input to create a new incoming payment. @@ -361,7 +357,7 @@ paths: paymentPointer: 'https://openpayments.guide/alice/' failed: false receiver: 'https://openpayments.guide/bob/incoming-payments/48884225-b393-4872-90de-1b737e2491c2' - maxSendAmount: + debitAmount: value: '2600' assetCode: USD assetScale: 2 @@ -373,15 +369,6 @@ paths: value: '0' assetCode: USD assetScale: 2 - fees: - sendFeeAmount: - value: '100' - assetCode: USD - assetScale: 2 - receiveFeeAmount: - value: '0' - assetCode: USD - assetScale: 2 metadata: description: Thank you for the shoes. createdAt: '2022-03-12T23:20:50.52Z' @@ -460,7 +447,7 @@ paths: value: '2500' assetCode: USD assetScale: 2 - maxSendAmount: + debitAmount: value: '2600' assetCode: USD assetScale: 2 @@ -468,15 +455,6 @@ paths: value: '2500' assetCode: USD assetScale: 2 - fees: - sendFeeAmount: - value: '100' - assetCode: USD - assetScale: 2 - receiveFeeAmount: - value: '0' - assetCode: USD - assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: @@ -486,7 +464,7 @@ paths: paymentPointer: 'https://openpayments.guide/alice/' failed: false receiver: 'https://openpayments.guide/shoeshop/incoming-payments/2fe92c6f-ef0d-487c-8759-3784eae6bce9' - maxSendAmount: + debitAmount: value: '7126' assetCode: USD assetScale: 2 @@ -498,15 +476,6 @@ paths: value: '7026' assetCode: USD assetScale: 2 - fees: - sendFeeAmount: - value: '100' - assetCode: USD - assetScale: 2 - receiveFeeAmount: - value: '0' - assetCode: USD - assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: @@ -524,7 +493,7 @@ paths: paymentPointer: 'https://openpayments.guide/alice/' failed: false receiver: 'https://openpayments.guide/shoeshop/incoming-payments/2fe92c6f-ef0d-487c-8759-3784eae6bce9' - maxSendAmount: + debitAmount: value: '7126' assetCode: USD assetScale: 2 @@ -536,15 +505,6 @@ paths: value: '7026' assetCode: USD assetScale: 2 - fees: - sendFeeAmount: - value: '100' - assetCode: USD - assetScale: 2 - receiveFeeAmount: - value: '0' - assetCode: USD - assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: @@ -558,7 +518,7 @@ paths: value: '2500' assetCode: USD assetScale: 2 - maxSendAmount: + debitAmount: value: '2600' assetCode: USD assetScale: 2 @@ -566,15 +526,6 @@ paths: value: '2500' assetCode: USD assetScale: 2 - fees: - sendFeeAmount: - value: '100' - assetCode: USD - assetScale: 2 - receiveFeeAmount: - value: '0' - assetCode: USD - assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: @@ -612,7 +563,7 @@ paths: id: 'https://openpayments.guide/alice/quotes/8c68d3cc-0a0f-4216-98b4-4fa44a6c88cf' paymentPointer: 'https://openpayments.guide/alice/' receiver: 'https://openpayments.guide/aplusvideo/incoming-payments/45d495ad-b763-4882-88d7-aa14d261686e' - maxSendAmount: + debitAmount: value: '2500' assetCode: USD assetScale: 2 @@ -620,15 +571,6 @@ paths: value: '2198' assetCode: EUR assetScale: 2 - fees: - sendFeeAmount: - value: '100' - assetCode: USD - assetScale: 2 - receiveFeeAmount: - value: '0' - assetCode: USD - assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' expiresAt: '2022-04-12T23:20:50.52Z' '400': @@ -816,7 +758,7 @@ paths: paymentPointer: 'https://openpayments.guide/bob/' failed: false receiver: 'https://openpayments.guide/alice/incoming-payments/2f1b0150-db73-49e8-8713-628baa4a17ff' - maxSendAmount: + debitAmount: value: '2500' assetCode: USD assetScale: 2 @@ -828,15 +770,6 @@ paths: value: '1205' assetCode: USD assetScale: 2 - fees: - sendFeeAmount: - value: '100' - assetCode: USD - assetScale: 2 - receiveFeeAmount: - value: '0' - assetCode: USD - assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: @@ -873,7 +806,7 @@ paths: id: 'https://openpayments.guide/bob/quotes/3859b39e-4666-4ce5-8745-72f1864c5371' paymentPointer: 'https://openpayments.guide/bob/' receiver: 'https://openpayments.guide/alice/incoming-payments/2f1b0150-db73-49e8-8713-628baa4a17ff' - maxSendAmount: + debitAmount: value: '2500' assetCode: USD assetScale: 2 @@ -881,15 +814,6 @@ paths: value: '2198' assetCode: EUR assetScale: 2 - fees: - sendFeeAmount: - value: '100' - assetCode: USD - assetScale: 2 - receiveFeeAmount: - value: '0' - assetCode: USD - assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' expiresAt: '2022-04-12T23:20:50.52Z' '401': @@ -1061,9 +985,6 @@ components: metadata: type: object description: Additional metadata associated with the incoming payment. (Optional) - feeStructure: - $ref: '#/components/schemas/feeStructure' - description: Fixed and variable receiving Account Servicing Entity fees. createdAt: type: string format: date-time @@ -1154,7 +1075,7 @@ components: value: '2500' assetCode: USD assetScale: 2 - maxSendAmount: + debitAmount: value: '2600' assetCode: USD assetScale: 2 @@ -1162,15 +1083,6 @@ components: value: '2500' assetCode: USD assetScale: 2 - fees: - sendFeeAmount: - value: '100' - assetCode: USD - assetScale: 2 - receiveFeeAmount: - value: '0' - assetCode: USD - assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: @@ -1180,7 +1092,7 @@ components: paymentPointer: 'https://openpayments.guide/alice/' failed: false receiver: 'https://openpayments.guide/shoeshop/2fe92c6f-ef0d-487c-8759-3784eae6bce9' - maxSendAmount: + debitAmount: value: '7126' assetCode: USD assetScale: 2 @@ -1188,15 +1100,6 @@ components: value: '7026' assetCode: USD assetScale: 2 - fees: - sendFeeAmount: - value: '100' - assetCode: USD - assetScale: 2 - receiveFeeAmount: - value: '0' - assetCode: USD - assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' updatedAt: '2022-04-01T10:24:36.11Z' metadata: @@ -1229,7 +1132,7 @@ components: receiveAmount: $ref: ./schemas.yaml#/components/schemas/amount description: The total amount that should be received by the receiver when this outgoing payment has been paid. - maxSendAmount: + debitAmount: $ref: ./schemas.yaml#/components/schemas/amount description: The total amount that should be deducted from the sender's account when this outgoing payment has been paid. sentAmount: @@ -1238,9 +1141,6 @@ components: metadata: type: object description: Additional metadata associated with the outgoing payment. (Optional) - fees: - $ref: '#/components/schemas/fees' - description: Fee structure createdAt: type: string format: date-time @@ -1254,9 +1154,8 @@ components: - paymentPointer - receiver - receiveAmount - - maxSendAmount + - debitAmount - sentAmount - - fees - createdAt - updatedAt quote: @@ -1271,7 +1170,7 @@ components: value: '2500' assetCode: USD assetScale: 2 - maxSendAmount: + debitAmount: value: '2600' assetCode: USD assetScale: 2 @@ -1279,21 +1178,12 @@ components: value: '2500' assetCode: USD assetScale: 2 - fees: - sendFeeAmount: - value: '100' - assetCode: USD - assetScale: 2 - receiveFeeAmount: - value: '0' - assetCode: USD - assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' expiresAt: '2022-04-12T23:20:50.52Z' - id: 'https://openpayments.guide/alice/quotes/8c68d3cc-0a0f-4216-98b4-4fa44a6c88cf' paymentPointer: 'https://openpayments.guide/alice/' receiver: 'https://openpayments.guide/aplusvideo/incoming-payments/45d495ad-b763-4882-88d7-aa14d261686e' - maxSendAmount: + debitAmount: value: '7126' assetCode: USD assetScale: 2 @@ -1301,15 +1191,6 @@ components: value: '7026' assetCode: USD assetScale: 2 - fees: - sendFeeAmount: - value: '100' - assetCode: USD - assetScale: 2 - receiveFeeAmount: - value: '0' - assetCode: USD - assetScale: 2 createdAt: '2022-03-12T23:20:50.52Z' expiresAt: '2022-04-12T23:20:50.52Z' additionalProperties: false @@ -1330,12 +1211,9 @@ components: receiveAmount: $ref: ./schemas.yaml#/components/schemas/amount description: The total amount that should be received by the receiver when the corresponding outgoing payment has been paid. - maxSendAmount: + debitAmount: $ref: ./schemas.yaml#/components/schemas/amount description: "The total amount that should be deducted from the sender's account when the corresponding outgoing payment has been paid. " - fees: - $ref: '#/components/schemas/fees' - description: Fee structure expiresAt: type: string description: The date and time when the calculated `sendAmount` is no longer valid. @@ -1349,8 +1227,7 @@ components: - paymentPointer - receiver - receiveAmount - - maxSendAmount - - fees + - debitAmount - createdAt page-info: description: '' @@ -1424,27 +1301,6 @@ components: kty: OKP crv: Ed25519 x: oy0L_vTygNE4IogRyn_F5GmHXdqYVjIXkWs2jky7zsI - feeStructure: - title: feeStructure - type: object - properties: - fixed: - $ref: ./schemas.yaml#/components/schemas/amount - percentage: - type: string - fees: - title: fees - type: object - properties: - sendFeeAmount: - $ref: ./schemas.yaml#/components/schemas/amount - description: Sending Accoung Servicing Entity's fees + ILP network fees - receiveFeeAmount: - $ref: ./schemas.yaml#/components/schemas/amount - description: Receiving Account Servicing Entity's fees. They are zero if sender does not pay receiving fees. - required: - - sendFeeAmount - - receiveFeeAmount securitySchemes: GNAP: name: Authorization diff --git a/packages/open-payments/src/client/outgoing-payment.test.ts b/packages/open-payments/src/client/outgoing-payment.test.ts index 0fd23875..d72ae947 100644 --- a/packages/open-payments/src/client/outgoing-payment.test.ts +++ b/packages/open-payments/src/client/outgoing-payment.test.ts @@ -62,7 +62,7 @@ describe('outgoing-payment', (): void => { test('throws if outgoing payment does not pass validation', async (): Promise => { const outgoingPayment = mockOutgoingPayment({ - maxSendAmount: { + debitAmount: { assetCode: 'USD', assetScale: 3, value: '5' @@ -194,7 +194,7 @@ describe('outgoing-payment', (): void => { test('throws if an outgoing payment does not pass validation', async (): Promise => { const invalidOutgoingPayment = mockOutgoingPayment({ - maxSendAmount: { + debitAmount: { assetCode: 'CAD', assetScale: 2, value: '5' @@ -291,7 +291,7 @@ describe('outgoing-payment', (): void => { test('throws if outgoing payment does not pass validation', async (): Promise => { const outgoingPayment = mockOutgoingPayment({ - maxSendAmount: { + debitAmount: { assetCode: 'USD', assetScale: 3, value: '5' @@ -361,7 +361,7 @@ describe('outgoing-payment', (): void => { test('throws if send amount and sent amount asset scales are different', async (): Promise => { const outgoingPayment = mockOutgoingPayment({ - maxSendAmount: { + debitAmount: { assetCode: 'USD', assetScale: 3, value: '5' @@ -380,7 +380,7 @@ describe('outgoing-payment', (): void => { test('throws if send amount and sent amount asset codes are different', async (): Promise => { const outgoingPayment = mockOutgoingPayment({ - maxSendAmount: { + debitAmount: { assetCode: 'CAD', assetScale: 2, value: '5' @@ -399,7 +399,7 @@ describe('outgoing-payment', (): void => { test('throws if sent amount is larger than send amount', async (): Promise => { const outgoingPayment = mockOutgoingPayment({ - maxSendAmount: { + debitAmount: { assetCode: 'USD', assetScale: 2, value: '5' @@ -418,7 +418,7 @@ describe('outgoing-payment', (): void => { test('throws if sent amount equals send amount, but payment has failed', async (): Promise => { const outgoingPayment = mockOutgoingPayment({ - maxSendAmount: { + debitAmount: { assetCode: 'USD', assetScale: 2, value: '5' diff --git a/packages/open-payments/src/client/outgoing-payment.ts b/packages/open-payments/src/client/outgoing-payment.ts index 8a5fa636..7c72cded 100644 --- a/packages/open-payments/src/client/outgoing-payment.ts +++ b/packages/open-payments/src/client/outgoing-payment.ts @@ -176,19 +176,19 @@ export const listOutgoingPayments = async ( export const validateOutgoingPayment = ( payment: OutgoingPayment ): OutgoingPayment => { - const { maxSendAmount, sentAmount } = payment + const { debitAmount, sentAmount } = payment if ( - maxSendAmount.assetCode !== sentAmount.assetCode || - maxSendAmount.assetScale !== sentAmount.assetScale + debitAmount.assetCode !== sentAmount.assetCode || + debitAmount.assetScale !== sentAmount.assetScale ) { throw new Error( 'Asset code or asset scale of sending amount does not match sent amount' ) } - if (BigInt(maxSendAmount.value) < BigInt(sentAmount.value)) { + if (BigInt(debitAmount.value) < BigInt(sentAmount.value)) { throw new Error('Amount sent is larger than maximum amount to send') } - if (maxSendAmount.value === sentAmount.value && payment.failed) { + if (debitAmount.value === sentAmount.value && payment.failed) { throw new Error('Amount to send matches sent amount but payment failed') } diff --git a/packages/open-payments/src/openapi/generated/auth-server-types.ts b/packages/open-payments/src/openapi/generated/auth-server-types.ts index 23474523..ab0a5ac1 100644 --- a/packages/open-payments/src/openapi/generated/auth-server-types.ts +++ b/packages/open-payments/src/openapi/generated/auth-server-types.ts @@ -166,7 +166,7 @@ export interface components { */ "limits-outgoing": Partial & { receiver?: external["schemas.yaml"]["components"]["schemas"]["receiver"]; - sendAmount?: external["schemas.yaml"]["components"]["schemas"]["amount"]; + debitAmount?: external["schemas.yaml"]["components"]["schemas"]["amount"]; receiveAmount?: external["schemas.yaml"]["components"]["schemas"]["amount"]; interval?: components["schemas"]["interval"]; }; diff --git a/packages/open-payments/src/openapi/generated/resource-server-types.ts b/packages/open-payments/src/openapi/generated/resource-server-types.ts index ade259e7..ab095b4a 100644 --- a/packages/open-payments/src/openapi/generated/resource-server-types.ts +++ b/packages/open-payments/src/openapi/generated/resource-server-types.ts @@ -190,8 +190,6 @@ export interface components { expiresAt?: string; /** @description Additional metadata associated with the incoming payment. (Optional) */ metadata?: { [key: string]: unknown }; - /** @description Fixed and variable receiving Account Servicing Entity fees. */ - feeStructure?: components["schemas"]["feeStructure"]; /** * Format: date-time * @description The date and time when the incoming payment was created. @@ -248,13 +246,11 @@ export interface components { /** @description The total amount that should be received by the receiver when this outgoing payment has been paid. */ receiveAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; /** @description The total amount that should be deducted from the sender's account when this outgoing payment has been paid. */ - maxSendAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; + debitAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; /** @description The total amount that has been sent under this outgoing payment. */ sentAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; /** @description Additional metadata associated with the outgoing payment. (Optional) */ metadata?: { [key: string]: unknown }; - /** @description Fee structure */ - fees: components["schemas"]["fees"]; /** * Format: date-time * @description The date and time when the outgoing payment was created. @@ -286,9 +282,7 @@ export interface components { /** @description The total amount that should be received by the receiver when the corresponding outgoing payment has been paid. */ receiveAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; /** @description The total amount that should be deducted from the sender's account when the corresponding outgoing payment has been paid. */ - maxSendAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; - /** @description Fee structure */ - fees: components["schemas"]["fees"]; + debitAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; /** @description The date and time when the calculated `sendAmount` is no longer valid. */ expiresAt?: string; /** @@ -321,18 +315,6 @@ export interface components { /** @description The base64 url-encoded public key. */ x: string; }; - /** feeStructure */ - feeStructure: { - fixed?: external["schemas.yaml"]["components"]["schemas"]["amount"]; - percentage?: string; - }; - /** fees */ - fees: { - /** @description Sending Accoung Servicing Entity's fees + ILP network fees */ - sendFeeAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; - /** @description Receiving Account Servicing Entity's fees. They are zero if sender does not pay receiving fees. */ - receiveFeeAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; - }; }; responses: { /** Authorization required */ @@ -497,8 +479,6 @@ export interface operations { expiresAt?: string; /** @description Additional metadata associated with the incoming payment. (Optional) */ metadata?: { [key: string]: unknown }; - /** @description Request receiving fee structure */ - feeStructure?: boolean; }; }; }; diff --git a/packages/open-payments/src/test/helpers.ts b/packages/open-payments/src/test/helpers.ts index bf2c25b8..aea886b9 100644 --- a/packages/open-payments/src/test/helpers.ts +++ b/packages/open-payments/src/test/helpers.ts @@ -154,7 +154,7 @@ export const mockOutgoingPayment = ( id: `https://example.com/.well-known/pay/outgoing-payments/${uuid()}`, paymentPointer: 'https://example.com/.well-known/pay', failed: false, - maxSendAmount: { + debitAmount: { assetCode: 'USD', assetScale: 2, value: '10' @@ -169,18 +169,6 @@ export const mockOutgoingPayment = ( assetScale: 2, value: '10' }, - fees: { - sendFeeAmount: { - assetCode: 'USD', - assetScale: 2, - value: '0' - }, - receiveFeeAmount: { - assetCode: 'USD', - assetScale: 2, - value: '0' - } - }, quoteId: uuid(), receiver: uuid(), metadata: { externalRef: 'INV #1', description: 'some description' }, @@ -298,7 +286,7 @@ export const mockQuote = (overrides?: Partial): Quote => ({ id: `https://example.com/.well-known/pay/quotes/${uuid()}`, receiver: 'https://example.com/.well-known/peer', paymentPointer: 'https://example.com/.well-known/pay', - maxSendAmount: { + debitAmount: { value: '100', assetCode: 'USD', assetScale: 2 @@ -308,18 +296,6 @@ export const mockQuote = (overrides?: Partial): Quote => ({ assetCode: 'USD', assetScale: 2 }, - fees: { - sendFeeAmount: { - assetCode: 'USD', - assetScale: 2, - value: '0' - }, - receiveFeeAmount: { - assetCode: 'USD', - assetScale: 2, - value: '0' - } - }, createdAt: new Date().toISOString(), expiresAt: new Date(Date.now() + 60_000).toISOString(), ...overrides From 299b5563e40e99447b60408c8e6a352d3a4cd6c6 Mon Sep 17 00:00:00 2001 From: Sabine Schaller Date: Wed, 23 Aug 2023 10:02:36 +0200 Subject: [PATCH 08/15] fix: build --- packages/open-payments/src/types.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/open-payments/src/types.ts b/packages/open-payments/src/types.ts index 8b8923a8..834dd0ee 100644 --- a/packages/open-payments/src/types.ts +++ b/packages/open-payments/src/types.ts @@ -51,16 +51,16 @@ export type Quote = RSComponents['schemas']['quote'] type QuoteArgsBase = { receiver: RSOperations['create-quote']['requestBody']['content']['application/json']['receiver'] } -type QuoteArgsWithSendAmount = QuoteArgsBase & { - sendAmount?: RSComponents['schemas']['quote']['maxSendAmount'] +type QuoteArgsWithDebitAmount = QuoteArgsBase & { + debitAmount?: RSComponents['schemas']['quote']['debitAmount'] receiveAmount?: never } type QuoteArgsWithReceiveAmount = QuoteArgsBase & { - sendAmount?: never + debitAmount?: never receiveAmount?: RSComponents['schemas']['quote']['receiveAmount'] } export type CreateQuoteArgs = - | QuoteArgsWithSendAmount + | QuoteArgsWithDebitAmount | QuoteArgsWithReceiveAmount export const getASPath =

(path: P): string => From 22564abbe077ec0e081b382b1f6770e1db856250 Mon Sep 17 00:00:00 2001 From: Sabine Schaller Date: Wed, 23 Aug 2023 10:06:46 +0200 Subject: [PATCH 09/15] fix: amount description --- openapi/auth-server.yaml | 2 ++ openapi/schemas.yaml | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/openapi/auth-server.yaml b/openapi/auth-server.yaml index 9972feb1..791f704c 100644 --- a/openapi/auth-server.yaml +++ b/openapi/auth-server.yaml @@ -516,8 +516,10 @@ components: receiver: $ref: './schemas.yaml#/components/schemas/receiver' debitAmount: + description: 'All amounts are maxima, i.e. multiple payments can be created under a grant as long as the total amounts of these payments do not exceed the maximum amount per interval as specified in the grant.' $ref: './schemas.yaml#/components/schemas/amount' receiveAmount: + description: 'All amounts are maxima, i.e. multiple payments can be created under a grant as long as the total amounts of these payments do not exceed the maximum amount per interval as specified in the grant.' $ref: './schemas.yaml#/components/schemas/amount' interval: $ref: '#/components/schemas/interval' diff --git a/openapi/schemas.yaml b/openapi/schemas.yaml index 7b3b5aa5..8a14d434 100644 --- a/openapi/schemas.yaml +++ b/openapi/schemas.yaml @@ -14,7 +14,6 @@ components: amount: title: amount type: object - description: 'All amounts are maxima, i.e. multiple payments can be created under a grant as long as the total amounts of these payments do not exceed the maximum amount per interval as specified in the grant.' properties: value: type: string From 2d3e9d19366f2154125116a7aa8ee83c4936e869 Mon Sep 17 00:00:00 2001 From: Sabine Schaller Date: Wed, 23 Aug 2023 10:11:43 +0200 Subject: [PATCH 10/15] fix: generate types --- .../src/openapi/generated/auth-server-types.ts | 7 +++---- .../src/openapi/generated/resource-server-types.ts | 5 +---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/open-payments/src/openapi/generated/auth-server-types.ts b/packages/open-payments/src/openapi/generated/auth-server-types.ts index ab0a5ac1..a91ec977 100644 --- a/packages/open-payments/src/openapi/generated/auth-server-types.ts +++ b/packages/open-payments/src/openapi/generated/auth-server-types.ts @@ -166,7 +166,9 @@ export interface components { */ "limits-outgoing": Partial & { receiver?: external["schemas.yaml"]["components"]["schemas"]["receiver"]; + /** @description All amounts are maxima, i.e. multiple payments can be created under a grant as long as the total amounts of these payments do not exceed the maximum amount per interval as specified in the grant. */ debitAmount?: external["schemas.yaml"]["components"]["schemas"]["amount"]; + /** @description All amounts are maxima, i.e. multiple payments can be created under a grant as long as the total amounts of these payments do not exceed the maximum amount per interval as specified in the grant. */ receiveAmount?: external["schemas.yaml"]["components"]["schemas"]["amount"]; interval?: components["schemas"]["interval"]; }; @@ -312,10 +314,7 @@ export interface external { paths: {}; components: { schemas: { - /** - * amount - * @description All amounts are maxima, i.e. multiple payments can be created under a grant as long as the total amounts of these payments do not exceed the maximum amount per interval as specified in the grant. - */ + /** amount */ amount: { /** * Format: uint64 diff --git a/packages/open-payments/src/openapi/generated/resource-server-types.ts b/packages/open-payments/src/openapi/generated/resource-server-types.ts index ab095b4a..dcb8a102 100644 --- a/packages/open-payments/src/openapi/generated/resource-server-types.ts +++ b/packages/open-payments/src/openapi/generated/resource-server-types.ts @@ -723,10 +723,7 @@ export interface external { paths: {}; components: { schemas: { - /** - * amount - * @description All amounts are maxima, i.e. multiple payments can be created under a grant as long as the total amounts of these payments do not exceed the maximum amount per interval as specified in the grant. - */ + /** amount */ amount: { /** * Format: uint64 From 8b0f1fa4b92edcd2d8885e62e47d07b76b951868 Mon Sep 17 00:00:00 2001 From: Sabine Schaller Date: Wed, 6 Sep 2023 09:30:25 +0200 Subject: [PATCH 11/15] fix: remaining `sendAmount`s --- openapi/resource-server.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openapi/resource-server.yaml b/openapi/resource-server.yaml index b0133e2e..5c6df506 100644 --- a/openapi/resource-server.yaml +++ b/openapi/resource-server.yaml @@ -403,7 +403,7 @@ paths: description: |- A subset of the outgoing payments schema is accepted as input to create a new outgoing payment. - The `sendAmount` must use the same `assetCode` and `assetScale` as the payment pointer. + The `debitAmount` must use the same `assetCode` and `assetScale` as the payment pointer. required: true description: |- An **outgoing payment** is a sub-resource of a payment pointer. It represents a payment from the payment pointer. @@ -586,7 +586,7 @@ paths: Create fixed-send-amount quote for $25 to an ILP STREAM connection: value: receiver: 'https://openpayments.guide/connections/45a0d0ee-26dc-4c66-89e0-01fbf93156f7' - sendAmount: + debitAmount: value: '2500' assetCode: USD assetScale: 2 @@ -621,17 +621,17 @@ paths: properties: receiver: $ref: ./schemas.yaml#/components/schemas/receiver - sendAmount: + debitAmount: description: The fixed amount that would be sent from the sending payment pointer given a successful outgoing payment. $ref: ./schemas.yaml#/components/schemas/amount required: - receiver - - sendAmount + - debitAmount additionalProperties: false description: |- A subset of the quotes schema is accepted as input to create a new quote. - The quote must be created with a (`sendAmount` xor `receiveAmount`) unless the `receiver` is an Incoming Payment which has an `incomingAmount`. + The quote must be created with a (`debitAmount` xor `receiveAmount`) unless the `receiver` is an Incoming Payment which has an `incomingAmount`. required: true description: A **quote** is a sub-resource of a payment pointer. It represents a quote for a payment from the payment pointer. parameters: @@ -1216,7 +1216,7 @@ components: description: "The total amount that should be deducted from the sender's account when the corresponding outgoing payment has been paid. " expiresAt: type: string - description: The date and time when the calculated `sendAmount` is no longer valid. + description: The date and time when the calculated `debitAmount` is no longer valid. readOnly: true createdAt: type: string From 9b49453629426cdcc941eb69e85f610278664282 Mon Sep 17 00:00:00 2001 From: Sabine Schaller Date: Wed, 6 Sep 2023 09:37:16 +0200 Subject: [PATCH 12/15] chore: versioning --- .changeset/tender-ravens-breathe.md | 2 +- openapi/auth-server.yaml | 2 +- openapi/resource-server.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.changeset/tender-ravens-breathe.md b/.changeset/tender-ravens-breathe.md index 1a4707ee..192d146f 100644 --- a/.changeset/tender-ravens-breathe.md +++ b/.changeset/tender-ravens-breathe.md @@ -1,5 +1,5 @@ --- -'@interledger/open-payments': minor +'@interledger/open-payments': major --- Adding properties for new quoting mechanism diff --git a/openapi/auth-server.yaml b/openapi/auth-server.yaml index 791f704c..f04009ee 100644 --- a/openapi/auth-server.yaml +++ b/openapi/auth-server.yaml @@ -1,7 +1,7 @@ openapi: 3.1.0 info: title: Open Payments Authorization Server - version: '1.0' + version: '1.1' license: name: Apache 2.0 identifier: Apache-2.0 diff --git a/openapi/resource-server.yaml b/openapi/resource-server.yaml index 5c6df506..b652d24e 100644 --- a/openapi/resource-server.yaml +++ b/openapi/resource-server.yaml @@ -1,7 +1,7 @@ openapi: 3.1.0 info: title: Open Payments - version: '1.1' + version: '1.2' license: name: Apache 2.0 identifier: Apache-2.0 From 2c77d1f4b8cd20ac9fdfb38d298636eeee797817 Mon Sep 17 00:00:00 2001 From: Sabine Schaller Date: Wed, 6 Sep 2023 09:49:43 +0200 Subject: [PATCH 13/15] fix: generate types --- .../src/openapi/generated/resource-server-types.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/open-payments/src/openapi/generated/resource-server-types.ts b/packages/open-payments/src/openapi/generated/resource-server-types.ts index dcb8a102..9157c59e 100644 --- a/packages/open-payments/src/openapi/generated/resource-server-types.ts +++ b/packages/open-payments/src/openapi/generated/resource-server-types.ts @@ -283,7 +283,7 @@ export interface components { receiveAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; /** @description The total amount that should be deducted from the sender's account when the corresponding outgoing payment has been paid. */ debitAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; - /** @description The date and time when the calculated `sendAmount` is no longer valid. */ + /** @description The date and time when the calculated `debitAmount` is no longer valid. */ expiresAt?: string; /** * Format: date-time @@ -542,7 +542,7 @@ export interface operations { /** * A subset of the outgoing payments schema is accepted as input to create a new outgoing payment. * - * The `sendAmount` must use the same `assetCode` and `assetScale` as the payment pointer. + * The `debitAmount` must use the same `assetCode` and `assetScale` as the payment pointer. */ requestBody: { content: { @@ -583,7 +583,7 @@ export interface operations { /** * A subset of the quotes schema is accepted as input to create a new quote. * - * The quote must be created with a (`sendAmount` xor `receiveAmount`) unless the `receiver` is an Incoming Payment which has an `incomingAmount`. + * The quote must be created with a (`debitAmount` xor `receiveAmount`) unless the `receiver` is an Incoming Payment which has an `incomingAmount`. */ requestBody: { content: { @@ -599,7 +599,7 @@ export interface operations { | { receiver: external["schemas.yaml"]["components"]["schemas"]["receiver"]; /** @description The fixed amount that would be sent from the sending payment pointer given a successful outgoing payment. */ - sendAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; + debitAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; }; }; }; From 2d4c9050ab362b9e738fc7d97490a998739d0ee8 Mon Sep 17 00:00:00 2001 From: Sabine Schaller Date: Wed, 6 Sep 2023 10:11:46 +0200 Subject: [PATCH 14/15] fix: server urls --- openapi/resource-server.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openapi/resource-server.yaml b/openapi/resource-server.yaml index b652d24e..fcfe71a0 100644 --- a/openapi/resource-server.yaml +++ b/openapi/resource-server.yaml @@ -36,12 +36,12 @@ servers: description: 'Server for when Payment Pointer has a pathname (ie https://openpayments.guide/alice)' variables: paymentPointer: - default: openpayments.guide/alice + default: https://openpayments.guide/alice - url: '{paymentPointer}/.well-known/pay' description: 'Server for when Payment Pointer has no pathname (ie https://openpayments.guide)' variables: paymentPointer: - default: openpayments.guide + default: https://openpayments.guide tags: - name: payment-pointer description: payment pointer operations From e40d55a5f88297bb2e7396d5472ef4f4af41798c Mon Sep 17 00:00:00 2001 From: Sabine Schaller Date: Wed, 6 Sep 2023 10:53:49 +0200 Subject: [PATCH 15/15] fix: replace final sendAmount --- packages/open-payments/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/open-payments/README.md b/packages/open-payments/README.md index 7a82420e..f19377bb 100644 --- a/packages/open-payments/README.md +++ b/packages/open-payments/README.md @@ -179,7 +179,7 @@ const quote = await client.quote.create( { receiver: incomingPayment.id } ) -// quote.sendAmount.value = '5200' +// quote.debitAmount.value = '5200' ``` 5. Create `OutgoingPayment` grant & start interaction flow: