Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add properties for quoting #275

Merged
merged 15 commits into from
Sep 6, 2023
5 changes: 5 additions & 0 deletions .changeset/tender-ravens-breathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@interledger/open-payments': minor
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should be major since it contains breaking changes

Copy link
Member Author

Choose a reason for hiding this comment

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

I must have run the wrong command 🙃

Copy link
Member Author

Choose a reason for hiding this comment

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

It's technically still a major change, but it feels so minor...

Copy link
Contributor

@BlairCurrey BlairCurrey Aug 24, 2023

Choose a reason for hiding this comment

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

I think it should still be major since it's breaking, and I think we probably need to bump the resource-server.yaml and auth-server.yaml version as well. Thats how we handled it when I renamed a field here: #270. Although the spec version bump was a minor bump 🤔... don't quite remember that reasoning.

On the topic of it feeling minor, Max pointed to some relevant blog posts and hackernews discussion in this comment #270 (comment). I don't see any quick, easy wins there and think just doing a major bump still makes the most sense but it is interesting reading.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah +1 on making this a major since it is breaking.
The spec can stay minor IMO

---

Adding properties for new quoting mechanism
325 changes: 223 additions & 102 deletions openapi/resource-server.yaml

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions packages/open-payments/src/client/outgoing-payment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ describe('outgoing-payment', (): void => {

test('throws if outgoing payment does not pass validation', async (): Promise<void> => {
const outgoingPayment = mockOutgoingPayment({
sendAmount: {
maxSendAmount: {
assetCode: 'USD',
assetScale: 3,
value: '5'
Expand Down Expand Up @@ -194,7 +194,7 @@ describe('outgoing-payment', (): void => {

test('throws if an outgoing payment does not pass validation', async (): Promise<void> => {
const invalidOutgoingPayment = mockOutgoingPayment({
sendAmount: {
maxSendAmount: {
assetCode: 'CAD',
assetScale: 2,
value: '5'
Expand Down Expand Up @@ -291,7 +291,7 @@ describe('outgoing-payment', (): void => {

test('throws if outgoing payment does not pass validation', async (): Promise<void> => {
const outgoingPayment = mockOutgoingPayment({
sendAmount: {
maxSendAmount: {
assetCode: 'USD',
assetScale: 3,
value: '5'
Expand Down Expand Up @@ -361,7 +361,7 @@ describe('outgoing-payment', (): void => {

test('throws if send amount and sent amount asset scales are different', async (): Promise<void> => {
const outgoingPayment = mockOutgoingPayment({
sendAmount: {
maxSendAmount: {
assetCode: 'USD',
assetScale: 3,
value: '5'
Expand All @@ -380,7 +380,7 @@ describe('outgoing-payment', (): void => {

test('throws if send amount and sent amount asset codes are different', async (): Promise<void> => {
const outgoingPayment = mockOutgoingPayment({
sendAmount: {
maxSendAmount: {
assetCode: 'CAD',
assetScale: 2,
value: '5'
Expand All @@ -399,7 +399,7 @@ describe('outgoing-payment', (): void => {

test('throws if sent amount is larger than send amount', async (): Promise<void> => {
const outgoingPayment = mockOutgoingPayment({
sendAmount: {
maxSendAmount: {
assetCode: 'USD',
assetScale: 2,
value: '5'
Expand All @@ -418,7 +418,7 @@ describe('outgoing-payment', (): void => {

test('throws if sent amount equals send amount, but payment has failed', async (): Promise<void> => {
const outgoingPayment = mockOutgoingPayment({
sendAmount: {
maxSendAmount: {
assetCode: 'USD',
assetScale: 2,
value: '5'
Expand Down
10 changes: 5 additions & 5 deletions packages/open-payments/src/client/outgoing-payment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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;
/**
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
};
};
};
Expand Down
28 changes: 26 additions & 2 deletions packages/open-payments/src/test/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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' },
Expand Down Expand Up @@ -286,7 +298,7 @@ export const mockQuote = (overrides?: Partial<Quote>): 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
Expand All @@ -296,6 +308,18 @@ export const mockQuote = (overrides?: Partial<Quote>): 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
Expand Down
2 changes: 1 addition & 1 deletion packages/open-payments/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 & {
Expand Down