From 0a6c72aca0f0ea7357356bacef8d9a0c4d73afb1 Mon Sep 17 00:00:00 2001 From: Max Kurapov Date: Tue, 25 Jun 2024 09:46:14 +0200 Subject: [PATCH 1/3] chore(auth): return objects during GNAP errors (#2779) * chore(auth): return object on gnap error * chore(auth): remove unused file * chore(bruno): add conditionals to post-request scripts to not hide errors --- .../Continuation Request.bru | 6 ++-- .../Create Incoming Payment.bru | 28 +++++++++------- .../Create Outgoing Payment.bru | 9 +++-- .../Get receiver wallet address.bru | 6 +++- .../Get sender wallet address.bru | 7 +++- .../Open Payments/Continuation Request.bru | 6 ++-- .../Open Payments/Create Incoming Payment.bru | 5 ++- .../Open Payments/Create Outgoing Payment.bru | 5 ++- .../Examples/Open Payments/Create Quote.bru | 8 +++-- .../Get receiver wallet address.bru | 8 +++-- .../Get sender wallet address.bru | 6 +++- .../Web Monetization/Continuation Request.bru | 6 ++-- .../Create Incoming Payment.bru | 25 +++++++------- .../Create Outgoing Payment 1.bru | 6 ++-- .../Create Outgoing Payment 2.bru | 4 ++- .../Create Outgoing Payment 3.bru | 4 ++- .../Get receiver wallet address.bru | 7 +++- .../Get sender wallet address.bru | 6 +++- .../Create Incoming Payment.bru | 5 ++- .../Create Outgoing Payment.bru | 5 ++- .../Quotes/Create Quote.bru | 10 +++--- bruno/collections/Rafiki/scripts.js | 14 +++++--- packages/auth/src/shared/gnapErrors.test.ts | 33 +++++++++++-------- packages/auth/src/shared/gnapErrors.ts | 23 ++++++++++--- packages/auth/src/tests/errors.ts | 13 -------- 25 files changed, 161 insertions(+), 94 deletions(-) delete mode 100644 packages/auth/src/tests/errors.ts diff --git a/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Continuation Request.bru b/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Continuation Request.bru index c75d5df7ea..01d39ebf3f 100644 --- a/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Continuation Request.bru +++ b/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Continuation Request.bru @@ -21,9 +21,9 @@ script:pre-request { } script:post-response { - const body = res.getBody(); - bru.setEnvVar("accessToken", body.access_token.value); - bru.setEnvVar("tokenId", body.access_token.manage.split('/').pop()) + const scripts = require('./scripts'); + + scripts.storeTokenDetails(); } tests { diff --git a/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Create Incoming Payment.bru b/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Create Incoming Payment.bru index 1851537335..6fffd0742c 100644 --- a/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Create Incoming Payment.bru +++ b/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Create Incoming Payment.bru @@ -36,20 +36,24 @@ script:pre-request { script:post-response { const body = res.getBody(); - bru.setEnvVar("incomingPaymentId", body.id.split("/").pop()); - bru.setEnvVar("incomingPaymentUrl", body.id); - bru.setEnvVar("debitAmount", JSON.stringify({ - "value": "500", - "assetCode": "USD", - "assetScale": 2 - })) + if (body?.id) { + bru.setEnvVar("incomingPaymentId", body.id.split("/").pop()); + bru.setEnvVar("incomingPaymentUrl", body.id); + + bru.setEnvVar("debitAmount", JSON.stringify({ + "value": "500", + "assetCode": "USD", + "assetScale": 2 + })) + + bru.setEnvVar("receiveAmount", JSON.stringify({ + "value": "500", + "assetCode": "USD", + "assetScale": 2 + })) + } - bru.setEnvVar("receiveAmount", JSON.stringify({ - "value": "500", - "assetCode": "USD", - "assetScale": 2 - })) } tests { diff --git a/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Create Outgoing Payment.bru b/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Create Outgoing Payment.bru index 5095764d0f..4d9e3a2a63 100644 --- a/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Create Outgoing Payment.bru +++ b/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Create Outgoing Payment.bru @@ -35,11 +35,10 @@ script:pre-request { script:post-response { const body = res.getBody(); - console.log(res.status) - console.log(res.statusText) - console.log({body}) - bru.setEnvVar("outgoingPaymentId", body.id.split("/").pop()); - + + if (body?.id) { + bru.setEnvVar("outgoingPaymentId", body.id.split("/").pop()); + } } tests { diff --git a/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Get receiver wallet address.bru b/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Get receiver wallet address.bru index 8f2e84a2ee..5b9b0277a9 100644 --- a/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Get receiver wallet address.bru +++ b/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Get receiver wallet address.bru @@ -23,7 +23,11 @@ script:pre-request { script:post-response { const url = require('url') - const body = res.body + if (res.getStatus() !== 200) { + return + } + + const body = res.getBody() bru.setEnvVar("receiverAssetCode", body?.assetCode) bru.setEnvVar("receiverAssetScale", body?.assetScale) diff --git a/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Get sender wallet address.bru b/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Get sender wallet address.bru index fe4b6f2fd3..384cfa6282 100644 --- a/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Get sender wallet address.bru +++ b/bruno/collections/Rafiki/Examples/Open Payments Without Quote/Get sender wallet address.bru @@ -23,7 +23,12 @@ script:pre-request { script:post-response { const url = require('url') - const body = res.body + if (res.getStatus() !== 200) { + return + } + + const body = res.getBody() + bru.setEnvVar("senderAssetCode", body?.assetCode) bru.setEnvVar("senderAssetScale", body?.assetScale) diff --git a/bruno/collections/Rafiki/Examples/Open Payments/Continuation Request.bru b/bruno/collections/Rafiki/Examples/Open Payments/Continuation Request.bru index c75d5df7ea..01d39ebf3f 100644 --- a/bruno/collections/Rafiki/Examples/Open Payments/Continuation Request.bru +++ b/bruno/collections/Rafiki/Examples/Open Payments/Continuation Request.bru @@ -21,9 +21,9 @@ script:pre-request { } script:post-response { - const body = res.getBody(); - bru.setEnvVar("accessToken", body.access_token.value); - bru.setEnvVar("tokenId", body.access_token.manage.split('/').pop()) + const scripts = require('./scripts'); + + scripts.storeTokenDetails(); } tests { diff --git a/bruno/collections/Rafiki/Examples/Open Payments/Create Incoming Payment.bru b/bruno/collections/Rafiki/Examples/Open Payments/Create Incoming Payment.bru index 553c9ef622..afc6464ee6 100644 --- a/bruno/collections/Rafiki/Examples/Open Payments/Create Incoming Payment.bru +++ b/bruno/collections/Rafiki/Examples/Open Payments/Create Incoming Payment.bru @@ -41,7 +41,10 @@ script:pre-request { script:post-response { const body = res.getBody(); - bru.setEnvVar("incomingPaymentId", body.id.split("/").pop()); + + if (body?.id) { + bru.setEnvVar("incomingPaymentId", body.id.split("/").pop()); + } } diff --git a/bruno/collections/Rafiki/Examples/Open Payments/Create Outgoing Payment.bru b/bruno/collections/Rafiki/Examples/Open Payments/Create Outgoing Payment.bru index 58601494f7..e14eaa6536 100644 --- a/bruno/collections/Rafiki/Examples/Open Payments/Create Outgoing Payment.bru +++ b/bruno/collections/Rafiki/Examples/Open Payments/Create Outgoing Payment.bru @@ -34,7 +34,10 @@ script:pre-request { script:post-response { const body = res.getBody(); - bru.setEnvVar("outgoingPaymentId", body.id.split("/").pop()); + + if (body?.id) { + bru.setEnvVar("outgoingPaymentId", body.id.split("/").pop()); + } } diff --git a/bruno/collections/Rafiki/Examples/Open Payments/Create Quote.bru b/bruno/collections/Rafiki/Examples/Open Payments/Create Quote.bru index f7c3ea5995..a7708217f4 100644 --- a/bruno/collections/Rafiki/Examples/Open Payments/Create Quote.bru +++ b/bruno/collections/Rafiki/Examples/Open Payments/Create Quote.bru @@ -32,9 +32,11 @@ script:pre-request { script:post-response { const body = res.getBody(); - bru.setEnvVar("quoteId", body.id.split("/").pop()); - bru.setEnvVar("quoteDebitAmount", JSON.stringify(body.debitAmount)) - bru.setEnvVar("quoteReceiveAmount", JSON.stringify(body.receiveAmount)) + if (body?.id) { + bru.setEnvVar("quoteId", body.id.split("/").pop()); + bru.setEnvVar("quoteDebitAmount", JSON.stringify(body.debitAmount)) + bru.setEnvVar("quoteReceiveAmount", JSON.stringify(body.receiveAmount)) + } } diff --git a/bruno/collections/Rafiki/Examples/Open Payments/Get receiver wallet address.bru b/bruno/collections/Rafiki/Examples/Open Payments/Get receiver wallet address.bru index 8f2e84a2ee..9e5acc50c4 100644 --- a/bruno/collections/Rafiki/Examples/Open Payments/Get receiver wallet address.bru +++ b/bruno/collections/Rafiki/Examples/Open Payments/Get receiver wallet address.bru @@ -22,8 +22,12 @@ script:pre-request { script:post-response { const url = require('url') - - const body = res.body + + if (res.getStatus() !== 200) { + return + } + + const body = res.getBody() bru.setEnvVar("receiverAssetCode", body?.assetCode) bru.setEnvVar("receiverAssetScale", body?.assetScale) diff --git a/bruno/collections/Rafiki/Examples/Open Payments/Get sender wallet address.bru b/bruno/collections/Rafiki/Examples/Open Payments/Get sender wallet address.bru index fe4b6f2fd3..9665a40e32 100644 --- a/bruno/collections/Rafiki/Examples/Open Payments/Get sender wallet address.bru +++ b/bruno/collections/Rafiki/Examples/Open Payments/Get sender wallet address.bru @@ -23,7 +23,11 @@ script:pre-request { script:post-response { const url = require('url') - const body = res.body + if (res.getStatus() !== 200) { + return + } + + const body = res.getBody() bru.setEnvVar("senderAssetCode", body?.assetCode) bru.setEnvVar("senderAssetScale", body?.assetScale) diff --git a/bruno/collections/Rafiki/Examples/Web Monetization/Continuation Request.bru b/bruno/collections/Rafiki/Examples/Web Monetization/Continuation Request.bru index c75d5df7ea..01d39ebf3f 100644 --- a/bruno/collections/Rafiki/Examples/Web Monetization/Continuation Request.bru +++ b/bruno/collections/Rafiki/Examples/Web Monetization/Continuation Request.bru @@ -21,9 +21,9 @@ script:pre-request { } script:post-response { - const body = res.getBody(); - bru.setEnvVar("accessToken", body.access_token.value); - bru.setEnvVar("tokenId", body.access_token.manage.split('/').pop()) + const scripts = require('./scripts'); + + scripts.storeTokenDetails(); } tests { diff --git a/bruno/collections/Rafiki/Examples/Web Monetization/Create Incoming Payment.bru b/bruno/collections/Rafiki/Examples/Web Monetization/Create Incoming Payment.bru index 360ad36aea..071e7df0be 100644 --- a/bruno/collections/Rafiki/Examples/Web Monetization/Create Incoming Payment.bru +++ b/bruno/collections/Rafiki/Examples/Web Monetization/Create Incoming Payment.bru @@ -36,17 +36,20 @@ script:pre-request { script:post-response { const body = res.getBody(); - bru.setEnvVar("incomingPaymentId", body.id.split("/").pop()); - bru.setEnvVar("quoteDebitAmount", JSON.stringify({ - value: "99999999999999", - assetCode: "USD", - assetScale: 2 - })) - bru.setEnvVar("quoteReceiveAmount", JSON.stringify({ - value: "99999999999999", - assetCode: "USD", - assetScale: 2 - })) + + if (body?.id) { + bru.setEnvVar("incomingPaymentId", body.id.split("/").pop()); + bru.setEnvVar("quoteDebitAmount", JSON.stringify({ + value: "99999999999999", + assetCode: "USD", + assetScale: 2 + })) + bru.setEnvVar("quoteReceiveAmount", JSON.stringify({ + value: "99999999999999", + assetCode: "USD", + assetScale: 2 + })) + } } tests { diff --git a/bruno/collections/Rafiki/Examples/Web Monetization/Create Outgoing Payment 1.bru b/bruno/collections/Rafiki/Examples/Web Monetization/Create Outgoing Payment 1.bru index d05b060e22..6bdb591816 100644 --- a/bruno/collections/Rafiki/Examples/Web Monetization/Create Outgoing Payment 1.bru +++ b/bruno/collections/Rafiki/Examples/Web Monetization/Create Outgoing Payment 1.bru @@ -40,8 +40,10 @@ script:pre-request { script:post-response { const body = res.getBody(); - bru.setEnvVar("outgoingPaymentId", body.id.split("/").pop()); - + + if (body?.id) { + bru.setEnvVar("outgoingPaymentId", body.id.split("/").pop()); + } } tests { diff --git a/bruno/collections/Rafiki/Examples/Web Monetization/Create Outgoing Payment 2.bru b/bruno/collections/Rafiki/Examples/Web Monetization/Create Outgoing Payment 2.bru index 32cce4c122..6dce96ac06 100644 --- a/bruno/collections/Rafiki/Examples/Web Monetization/Create Outgoing Payment 2.bru +++ b/bruno/collections/Rafiki/Examples/Web Monetization/Create Outgoing Payment 2.bru @@ -40,8 +40,10 @@ script:pre-request { script:post-response { const body = res.getBody(); - bru.setEnvVar("outgoingPaymentId", body.id.split("/").pop()); + if (body?.id) { + bru.setEnvVar("outgoingPaymentId", body.id.split("/").pop()); + } } tests { diff --git a/bruno/collections/Rafiki/Examples/Web Monetization/Create Outgoing Payment 3.bru b/bruno/collections/Rafiki/Examples/Web Monetization/Create Outgoing Payment 3.bru index a37a54d190..814d2171de 100644 --- a/bruno/collections/Rafiki/Examples/Web Monetization/Create Outgoing Payment 3.bru +++ b/bruno/collections/Rafiki/Examples/Web Monetization/Create Outgoing Payment 3.bru @@ -40,8 +40,10 @@ script:pre-request { script:post-response { const body = res.getBody(); - bru.setEnvVar("outgoingPaymentId", body.id.split("/").pop()); + if (body?.id) { + bru.setEnvVar("outgoingPaymentId", body.id.split("/").pop()); + } } tests { diff --git a/bruno/collections/Rafiki/Examples/Web Monetization/Get receiver wallet address.bru b/bruno/collections/Rafiki/Examples/Web Monetization/Get receiver wallet address.bru index 8f2e84a2ee..d59f39b24f 100644 --- a/bruno/collections/Rafiki/Examples/Web Monetization/Get receiver wallet address.bru +++ b/bruno/collections/Rafiki/Examples/Web Monetization/Get receiver wallet address.bru @@ -23,7 +23,12 @@ script:pre-request { script:post-response { const url = require('url') - const body = res.body + if (res.getStatus() !== 200) { + return + } + + const body = res.getBody() + bru.setEnvVar("receiverAssetCode", body?.assetCode) bru.setEnvVar("receiverAssetScale", body?.assetScale) diff --git a/bruno/collections/Rafiki/Examples/Web Monetization/Get sender wallet address.bru b/bruno/collections/Rafiki/Examples/Web Monetization/Get sender wallet address.bru index fe4b6f2fd3..9665a40e32 100644 --- a/bruno/collections/Rafiki/Examples/Web Monetization/Get sender wallet address.bru +++ b/bruno/collections/Rafiki/Examples/Web Monetization/Get sender wallet address.bru @@ -23,7 +23,11 @@ script:pre-request { script:post-response { const url = require('url') - const body = res.body + if (res.getStatus() !== 200) { + return + } + + const body = res.getBody() bru.setEnvVar("senderAssetCode", body?.assetCode) bru.setEnvVar("senderAssetScale", body?.assetScale) diff --git a/bruno/collections/Rafiki/Open Payments APIs/Incoming Payments/Create Incoming Payment.bru b/bruno/collections/Rafiki/Open Payments APIs/Incoming Payments/Create Incoming Payment.bru index c72e3cd91f..c718828e1c 100644 --- a/bruno/collections/Rafiki/Open Payments APIs/Incoming Payments/Create Incoming Payment.bru +++ b/bruno/collections/Rafiki/Open Payments APIs/Incoming Payments/Create Incoming Payment.bru @@ -42,7 +42,10 @@ script:pre-request { script:post-response { const body = res.getBody(); - bru.setEnvVar("incomingPaymentId", body.id.split("/").pop()); + + if (body?.id) { + bru.setEnvVar("incomingPaymentId", body.id.split("/").pop()); + } } tests { diff --git a/bruno/collections/Rafiki/Open Payments APIs/Outgoing Payments/Create Outgoing Payment.bru b/bruno/collections/Rafiki/Open Payments APIs/Outgoing Payments/Create Outgoing Payment.bru index c0e404ad13..62ec4793f7 100644 --- a/bruno/collections/Rafiki/Open Payments APIs/Outgoing Payments/Create Outgoing Payment.bru +++ b/bruno/collections/Rafiki/Open Payments APIs/Outgoing Payments/Create Outgoing Payment.bru @@ -35,7 +35,10 @@ script:pre-request { script:post-response { const body = res.getBody(); - bru.setEnvVar("outgoingPaymentId", body.id.split("/").pop()); + + if (body?.id) { + bru.setEnvVar("outgoingPaymentId", body.id.split("/").pop()); + } } tests { diff --git a/bruno/collections/Rafiki/Open Payments APIs/Quotes/Create Quote.bru b/bruno/collections/Rafiki/Open Payments APIs/Quotes/Create Quote.bru index 9059ff40f9..1e53624a2c 100644 --- a/bruno/collections/Rafiki/Open Payments APIs/Quotes/Create Quote.bru +++ b/bruno/collections/Rafiki/Open Payments APIs/Quotes/Create Quote.bru @@ -37,10 +37,12 @@ script:pre-request { script:post-response { const body = res.getBody(); - bru.setEnvVar("quoteId", body.id.split("/").pop()); - bru.setEnvVar("quoteDebitAmount", JSON.stringify(body.debitAmount)) - bru.setEnvVar("quoteReceiveAmount", JSON.stringify(body.receiveAmount)) - + + if (body?.id) { + bru.setEnvVar("quoteId", body.id.split("/").pop()); + bru.setEnvVar("quoteDebitAmount", JSON.stringify(body.debitAmount)) + bru.setEnvVar("quoteReceiveAmount", JSON.stringify(body.receiveAmount)) + } } tests { diff --git a/bruno/collections/Rafiki/scripts.js b/bruno/collections/Rafiki/scripts.js index d53ba17b91..8ea6b7a614 100644 --- a/bruno/collections/Rafiki/scripts.js +++ b/bruno/collections/Rafiki/scripts.js @@ -147,10 +147,16 @@ const scripts = { storeTokenDetails: function () { const body = res.getBody() - bru.setEnvVar('accessToken', body?.access_token?.value) - bru.setEnvVar('continueToken', body.continue.access_token.value) - bru.setEnvVar('continueId', body.continue.uri.split('/').pop()) - bru.setEnvVar('tokenId', body?.access_token?.manage.split('/').pop()) + + if (body?.access_token) { + bru.setEnvVar('accessToken', body.access_token.value) + bru.setEnvVar('tokenId', body.access_token.manage.split('/').pop()) + } + + if (body?.continue) { + bru.setEnvVar('continueToken', body.continue.access_token.value) + bru.setEnvVar('continueId', body.continue.uri.split('/').pop()) + } }, loadWalletAddressIdsIntoVariables: async function () { diff --git a/packages/auth/src/shared/gnapErrors.test.ts b/packages/auth/src/shared/gnapErrors.test.ts index 17eb654d44..8afe168ed1 100644 --- a/packages/auth/src/shared/gnapErrors.test.ts +++ b/packages/auth/src/shared/gnapErrors.test.ts @@ -38,14 +38,13 @@ describe('gnapServerErrorMiddleware', (): void => { throw error }) - const ctxThrowSpy = jest.spyOn(ctx, 'throw') - - await expect(gnapServerErrorMiddleware(ctx, next)).rejects.toMatchObject({ - status: error.status, - message: error.message + await expect(gnapServerErrorMiddleware(ctx, next)).resolves.toBeUndefined() + expect(ctx.body).toEqual({ + error: { + description: error.message + } }) - - expect(ctxThrowSpy).toHaveBeenCalledWith(error.status, error.message) + expect(ctx.status).toBe(error.status) expect(next).toHaveBeenCalledTimes(1) }) @@ -59,19 +58,27 @@ describe('gnapServerErrorMiddleware', (): void => { throw error }) - const ctxThrowSpy = jest.spyOn(ctx, 'throw') - - await expect(gnapServerErrorMiddleware(ctx, next)).rejects.toMatchObject({ - status: error.status, + await expect(gnapServerErrorMiddleware(ctx, next)).resolves.toBeUndefined() + expect(ctx.body).toEqual({ error: { code: error.code, description: error.message } }) + expect(ctx.status).toBe(error.status) + expect(next).toHaveBeenCalledTimes(1) + }) - expect(ctxThrowSpy).toHaveBeenCalledWith(error.status, error.code, { - error: { code: error.code, description: error.message } + test('handles unknown error', async (): Promise => { + const error = new Error('unexpected') + const next = jest.fn().mockImplementationOnce(() => { + throw error }) + + const ctxThrowSpy = jest.spyOn(ctx, 'throw') + + await expect(gnapServerErrorMiddleware(ctx, next)).rejects.toThrow() + expect(ctxThrowSpy).toHaveBeenCalledWith(500) expect(next).toHaveBeenCalledTimes(1) }) }) diff --git a/packages/auth/src/shared/gnapErrors.ts b/packages/auth/src/shared/gnapErrors.ts index 947f7eaf94..1f6444c421 100644 --- a/packages/auth/src/shared/gnapErrors.ts +++ b/packages/auth/src/shared/gnapErrors.ts @@ -57,10 +57,19 @@ export async function gnapServerErrorMiddleware( 'Received error when handling Open Payments GNAP request' ) - ctx.throw(err.status, err.code, { - error: { code: err.code, description: err.message } - }) - } else if (err instanceof OpenAPIValidatorMiddlewareError) { + const gnapErrorResponse: GNAPErrorResponse = { + error: { + code: err.code, + description: err.message + } + } + + ctx.status = err.status + ctx.body = gnapErrorResponse + return + } + + if (err instanceof OpenAPIValidatorMiddlewareError) { const finalStatus = err.status || 400 logger.info( @@ -72,7 +81,11 @@ export async function gnapServerErrorMiddleware( 'Received OpenAPI validation error when handling Open Payments GNAP request' ) - ctx.throw(finalStatus, err.message) + ctx.status = finalStatus + ctx.body = { + error: { description: err.message } + } + return } logger.error( diff --git a/packages/auth/src/tests/errors.ts b/packages/auth/src/tests/errors.ts deleted file mode 100644 index 9e9cfec806..0000000000 --- a/packages/auth/src/tests/errors.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { GNAPErrorCode, GNAPErrorResponse } from '../shared/gnapErrors' - -export function generateGNAPErrorResponse( - code: GNAPErrorCode, - description?: string -): GNAPErrorResponse { - return { - error: { - code, - description - } - } -} From d5c7860fff26c29480fcf6d63c16bb63398169c8 Mon Sep 17 00:00:00 2001 From: Tadej Golobic Date: Tue, 25 Jun 2024 12:27:15 +0200 Subject: [PATCH 2/3] feat(backend)!: update and rename env variables (#2749) * feat(backend)!: update env variables * feat(localenv): update backend env variables * test(integration): update backend env variables * feat(backend)!: rename SPS_ENABLE env variable * test(integration): update backend env variables * fix(telemetry): shutdown only if enabled in config * docs(integration): update env variables default values * feat(localenv): enable telemetry * fix(localenv): docker dompose connector address url variable * feat(backend): revert default tigerbeetle value * feat(backend): sps payment pointer rename * feat(docs): rename sps payment pointer * feat(localenv): dummy uuid for keyid * chore(lint): everything * chore(env): rename ilp connector address to ilp connector url --- localenv/cloud-nine-wallet/docker-compose.yml | 5 +- localenv/happy-life-bank/docker-compose.yml | 5 +- packages/backend/jest.config.js | 11 +++ packages/backend/src/app.ts | 2 +- packages/backend/src/config/app.ts | 74 +++++++++---------- .../graphql/resolvers/auto-peering.test.ts | 10 +-- packages/backend/src/index.ts | 6 +- .../ilp/auto-peering/routes.test.ts | 6 +- .../payment-method/ilp/auto-peering/routes.ts | 2 +- .../ilp/auto-peering/service.test.ts | 52 ++++++------- .../ilp/auto-peering/service.ts | 20 ++--- .../ilp/spsp/middleware.test.ts | 22 +++--- .../concepts/interledger-protocol/peering.md | 4 +- .../content/docs/integration/deployment.md | 22 +++--- .../cloud-nine-wallet/docker-compose.yml | 3 + .../happy-life-bank/docker-compose.yml | 3 + 16 files changed, 134 insertions(+), 113 deletions(-) diff --git a/localenv/cloud-nine-wallet/docker-compose.yml b/localenv/cloud-nine-wallet/docker-compose.yml index 93aec29a01..9595c89bc6 100644 --- a/localenv/cloud-nine-wallet/docker-compose.yml +++ b/localenv/cloud-nine-wallet/docker-compose.yml @@ -72,8 +72,9 @@ services: EXCHANGE_RATES_URL: http://cloud-nine-wallet/rates REDIS_URL: redis://shared-redis:6379/0 WALLET_ADDRESS_URL: ${CLOUD_NINE_WALLET_ADDRESS_URL:-https://cloud-nine-wallet-backend/.well-known/pay} - ILP_CONNECTOR_ADDRESS: ${CLOUD_NINE_CONNECTOR_URL} - ENABLE_TELEMETRY: false + ILP_CONNECTOR_URL: ${CLOUD_NINE_CONNECTOR_URL} + ENABLE_TELEMETRY: true + KEY_ID: 7097F83B-CB84-469E-96C6-2141C72E22C0 depends_on: - shared-database - shared-redis diff --git a/localenv/happy-life-bank/docker-compose.yml b/localenv/happy-life-bank/docker-compose.yml index 4fb4bb0ef0..20f4e203b0 100644 --- a/localenv/happy-life-bank/docker-compose.yml +++ b/localenv/happy-life-bank/docker-compose.yml @@ -41,6 +41,7 @@ services: ports: - "4000:80" - "4001:3001" + - "4002:3002" - '9231:9229' networks: - rafiki @@ -58,6 +59,7 @@ services: AUTH_SERVER_GRANT_URL: ${HAPPY_LIFE_BANK_AUTH_SERVER_DOMAIN:-http://happy-life-bank-auth:3006} AUTH_SERVER_INTROSPECTION_URL: http://happy-life-bank-auth:3007 ILP_ADDRESS: test.happy-life-bank + ILP_CONNECTOR_URL: http://127.0.0.1:4002 STREAM_SECRET: BjPXtnd00G2mRQwP/8ZpwyZASOch5sUXT5o0iR5b5wU= API_SECRET: iyIgCprjb9uL8wFckR+pLEkJWMB7FJhgkvqhTQR/964= WEBHOOK_URL: http://happy-life-bank/webhooks @@ -65,7 +67,8 @@ services: EXCHANGE_RATES_URL: http://happy-life-bank/rates REDIS_URL: redis://shared-redis:6379/2 WALLET_ADDRESS_URL: ${HAPPY_LIFE_BANK_WALLET_ADDRESS_URL:-https://happy-life-bank-backend/.well-known/pay} - ENABLE_TELEMETRY: false + ENABLE_TELEMETRY: true + KEY_ID: 53f2d913-e98a-40b9-b270-372d0547f23d depends_on: - cloud-nine-backend happy-life-auth: diff --git a/packages/backend/jest.config.js b/packages/backend/jest.config.js index 8f933f9a4c..492a6e5e30 100644 --- a/packages/backend/jest.config.js +++ b/packages/backend/jest.config.js @@ -5,6 +5,17 @@ const baseConfig = require('../../jest.config.base.js') const packageName = require('./package.json').name process.env.LOG_LEVEL = 'silent' +process.env.INSTANCE_NAME = 'Rafiki' +process.env.KEY_ID = 'myKey' +process.env.OPEN_PAYMENTS_URL = 'http://127.0.0.1:3000' +process.env.ILP_CONNECTOR_URL = 'http://127.0.0.1:3002' +process.env.ILP_ADDRESS = 'test.rafiki' +process.env.AUTH_SERVER_GRANT_URL = 'http://127.0.0.1:3006' +process.env.AUTH_SERVER_INTROSPECTION_URL = 'http://127.0.0.1:3007/' +process.env.WEBHOOK_URL = 'http://127.0.0.1:4001/webhook' +process.env.STREAM_SECRET = '2/PxuRFV9PAp0yJlnAifJ+1OxujjjI16lN+DBnLNRLA=' +process.env.USE_TIGERBEETLE = false +process.env.ENABLE_TELEMETRY = false module.exports = { ...baseConfig, diff --git a/packages/backend/src/app.ts b/packages/backend/src/app.ts index a6a2c642c3..149da7190a 100644 --- a/packages/backend/src/app.ts +++ b/packages/backend/src/app.ts @@ -661,7 +661,7 @@ export class App { router.get( WALLET_ADDRESS_PATH, getWalletAddressUrlFromPath, - createSpspMiddleware(this.config.spspEnabled), + createSpspMiddleware(this.config.enableSpspPaymentPointers), createValidatorMiddleware( walletAddressServerSpec, { diff --git a/packages/backend/src/config/app.ts b/packages/backend/src/config/app.ts index ee2711c931..9e5659115c 100644 --- a/packages/backend/src/config/app.ts +++ b/packages/backend/src/config/app.ts @@ -1,12 +1,15 @@ import { loadOrGenerateKey } from '@interledger/http-signature-utils' -import * as crypto from 'crypto' import dotenv from 'dotenv' import * as fs from 'fs' import { ConnectionOptions } from 'tls' -function envString(name: string, value: string): string { +function envString(name: string, defaultValue?: string): string { const envValue = process.env[name] - return envValue == null ? value : envValue + + if (envValue) return envValue + if (defaultValue) return defaultValue + + throw new Error(`Environment variable ${name} must be set.`) } function envStringArray(name: string, value: string[]): string[] { @@ -35,9 +38,18 @@ dotenv.config({ path: process.env.ENV_FILE || '.env' }) +let privateKeyFileEnv +try { + privateKeyFileEnv = envString('PRIVATE_KEY_FILE') +} catch (err) { + /* empty */ +} + +const privateKeyFileValue = loadOrGenerateKey(privateKeyFileEnv) + export const Config = { logLevel: envString('LOG_LEVEL', 'info'), - enableTelemetry: envBool('ENABLE_TELEMETRY', true), + enableTelemetry: envBool('ENABLE_TELEMETRY', false), livenet: envBool('LIVENET', false), openTelemetryCollectors: envStringArray( 'OPEN_TELEMETRY_COLLECTOR_URLS', @@ -59,7 +71,7 @@ export const Config = { 86_400_000 ), adminPort: envInt('ADMIN_PORT', 3001), - openPaymentsUrl: envString('OPEN_PAYMENTS_URL', 'http://127.0.0.1:3000'), + openPaymentsUrl: envString('OPEN_PAYMENTS_URL'), openPaymentsPort: envInt('OPEN_PAYMENTS_PORT', 3003), connectorPort: envInt('CONNECTOR_PORT', 3002), autoPeeringServerPort: envInt('AUTO_PEERING_SERVER_PORT', 3005), @@ -80,21 +92,15 @@ export const Config = { trustProxy: envBool('TRUST_PROXY', false), redisUrl: envString('REDIS_URL', 'redis://127.0.0.1:6379'), redisTls: parseRedisTlsConfig( - envString('REDIS_TLS_CA_FILE_PATH', ''), - envString('REDIS_TLS_KEY_FILE_PATH', ''), - envString('REDIS_TLS_CERT_FILE_PATH', '') + process.env.REDIS_TLS_CA_FILE_PATH, + process.env.REDIS_TLS_KEY_FILE_PATH, + process.env.REDIS_TLS_CERT_FILE_PATH ), - ilpAddress: envString('ILP_ADDRESS', 'test.rafiki'), - ilpConnectorAddress: envString( - 'ILP_CONNECTOR_ADDRESS', - 'http://127.0.0.1:3002' - ), - instanceName: envString('INSTANCE_NAME', 'Rafiki'), - streamSecret: process.env.STREAM_SECRET - ? Buffer.from(process.env.STREAM_SECRET, 'base64') - : crypto.randomBytes(32), - - useTigerbeetle: envBool('USE_TIGERBEETLE', false), + ilpAddress: envString('ILP_ADDRESS'), + ilpConnectorUrl: envString('ILP_CONNECTOR_URL'), + instanceName: envString('INSTANCE_NAME'), + streamSecret: Buffer.from(process.env.STREAM_SECRET || '', 'base64'), + useTigerbeetle: envBool('USE_TIGERBEETLE', true), tigerbeetleClusterId: envInt('TIGERBEETLE_CLUSTER_ID', 0), tigerbeetleReplicaAddresses: process.env.TIGERBEETLE_REPLICA_ADDRESSES ? process.env.TIGERBEETLE_REPLICA_ADDRESSES.split(',') @@ -109,14 +115,8 @@ export const Config = { walletAddressWorkers: envInt('WALLET_ADDRESS_WORKERS', 1), walletAddressWorkerIdle: envInt('WALLET_ADDRESS_WORKER_IDLE', 200), // milliseconds - authServerGrantUrl: envString( - 'AUTH_SERVER_GRANT_URL', - 'http://127.0.0.1:3006' - ), - authServerIntrospectionUrl: envString( - 'AUTH_SERVER_INTROSPECTION_URL', - 'http://127.0.0.1:3007/' - ), + authServerGrantUrl: envString('AUTH_SERVER_GRANT_URL'), + authServerIntrospectionUrl: envString('AUTH_SERVER_INTROSPECTION_URL'), outgoingPaymentWorkers: envInt('OUTGOING_PAYMENT_WORKERS', 4), outgoingPaymentWorkerIdle: envInt('OUTGOING_PAYMENT_WORKER_IDLE', 200), // milliseconds @@ -126,7 +126,7 @@ export const Config = { webhookWorkers: envInt('WEBHOOK_WORKERS', 1), webhookWorkerIdle: envInt('WEBHOOK_WORKER_IDLE', 200), // milliseconds - webhookUrl: envString('WEBHOOK_URL', 'http://127.0.0.1:4001/webhook'), + webhookUrl: envString('WEBHOOK_URL'), webhookTimeout: envInt('WEBHOOK_TIMEOUT', 2000), // milliseconds webhookMaxRetry: envInt('WEBHOOK_MAX_RETRY', 10), @@ -142,8 +142,8 @@ export const Config = { adminApiSignatureVersion: envInt('API_SIGNATURE_VERSION', 1), adminApiSignatureTtl: envInt('ADMIN_API_SIGNATURE_TTL_SECONDS', 30), - keyId: envString('KEY_ID', 'rafiki'), - privateKey: loadOrGenerateKey(envString('PRIVATE_KEY_FILE', '')), + keyId: envString('KEY_ID'), + privateKey: privateKeyFileValue, graphQLIdempotencyKeyLockMs: envInt('GRAPHQL_IDEMPOTENCY_KEY_LOCK_MS', 2000), graphQLIdempotencyKeyTtlMs: envInt( @@ -166,27 +166,27 @@ export const Config = { 'INCOMING_PAYMENT_EXPIRY_MAX_MS', 2592000000 ), // 30 days - spspEnabled: envBool('ENABLE_SPSP', true) + enableSpspPaymentPointers: envBool('ENABLE_SPSP_PAYMENT_POINTERS', true) } function parseRedisTlsConfig( - caFile: string, - keyFile: string, - certFile: string + caFile?: string, + keyFile?: string, + certFile?: string ): ConnectionOptions | undefined { const options: ConnectionOptions = {} // self-signed certs. - if (caFile !== '') { + if (caFile) { options.ca = fs.readFileSync(caFile) options.rejectUnauthorized = false } - if (certFile !== '') { + if (certFile) { options.cert = fs.readFileSync(certFile) } - if (keyFile !== '') { + if (keyFile) { options.key = fs.readFileSync(keyFile) } diff --git a/packages/backend/src/graphql/resolvers/auto-peering.test.ts b/packages/backend/src/graphql/resolvers/auto-peering.test.ts index 86f0f0a0ad..3a073130d3 100644 --- a/packages/backend/src/graphql/resolvers/auto-peering.test.ts +++ b/packages/backend/src/graphql/resolvers/auto-peering.test.ts @@ -112,7 +112,7 @@ describe('Auto Peering Resolvers', (): void => { const peerDetails = { staticIlpAddress: 'test.peer2', - ilpConnectorAddress: 'http://peer-two.com', + ilpConnectorUrl: 'http://peer-two.com', name: 'Test Peer', httpToken: 'httpToken' } @@ -137,7 +137,7 @@ describe('Auto Peering Resolvers', (): void => { outgoing: { __typename: 'HttpOutgoing', authToken: expect.any(String), - endpoint: peerDetails.ilpConnectorAddress + endpoint: peerDetails.ilpConnectorUrl } }, maxPacketAmount: input.maxPacketAmount?.toString(), @@ -153,7 +153,7 @@ describe('Auto Peering Resolvers', (): void => { const peerDetails = { staticIlpAddress: 'test.peer2', - ilpConnectorAddress: 'http://peer-two.com', + ilpConnectorUrl: 'http://peer-two.com', name: 'Test Peer', httpToken: 'httpToken' } @@ -187,7 +187,7 @@ describe('Auto Peering Resolvers', (): void => { outgoing: { __typename: 'HttpOutgoing', authToken: expect.any(String), - endpoint: peerDetails.ilpConnectorAddress + endpoint: peerDetails.ilpConnectorUrl } }, maxPacketAmount: input.maxPacketAmount?.toString(), @@ -221,7 +221,7 @@ describe('Auto Peering Resolvers', (): void => { outgoing: { __typename: 'HttpOutgoing', authToken: expect.any(String), - endpoint: peerDetails.ilpConnectorAddress + endpoint: peerDetails.ilpConnectorUrl } }, maxPacketAmount: secondInput.maxPacketAmount?.toString(), diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 346e9bb277..bf7c82be33 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -511,9 +511,9 @@ export const gracefulShutdown = async ( await redis.quit() redis.disconnect() - const telemetry = await container.use('telemetry') - if (telemetry) { - await telemetry.shutdown() + if (config.enableTelemetry) { + const telemetry = await container.use('telemetry') + telemetry?.shutdown() } } diff --git a/packages/backend/src/payment-method/ilp/auto-peering/routes.test.ts b/packages/backend/src/payment-method/ilp/auto-peering/routes.test.ts index f3bc49b3a9..d861ec8841 100644 --- a/packages/backend/src/payment-method/ilp/auto-peering/routes.test.ts +++ b/packages/backend/src/payment-method/ilp/auto-peering/routes.test.ts @@ -39,7 +39,7 @@ describe('Auto Peering Routes', (): void => { url: `/`, body: { staticIlpAddress: 'test.rafiki-money', - ilpConnectorAddress: 'http://peer.rafiki.money', + ilpConnectorUrl: 'http://peer.rafiki.money', asset: { code: asset.code, scale: asset.scale }, httpToken: 'someHttpToken', maxPacketAmount: 1000, @@ -53,7 +53,7 @@ describe('Auto Peering Routes', (): void => { expect(ctx.status).toBe(200) expect(ctx.body).toEqual({ staticIlpAddress: config.ilpAddress, - ilpConnectorAddress: config.ilpConnectorAddress, + ilpConnectorUrl: config.ilpConnectorUrl, httpToken: expect.any(String), name: config.instanceName }) @@ -65,7 +65,7 @@ describe('Auto Peering Routes', (): void => { url: `/`, body: { staticIlpAddress: 'test.rafiki-money', - ilpConnectorAddress: 'http://peer.rafiki.money', + ilpConnectorUrl: 'http://peer.rafiki.money', asset: { code: 'ABC', scale: 2 }, httpToken: 'someHttpToken' } diff --git a/packages/backend/src/payment-method/ilp/auto-peering/routes.ts b/packages/backend/src/payment-method/ilp/auto-peering/routes.ts index c6dd9a9fb6..1ec0197eaf 100644 --- a/packages/backend/src/payment-method/ilp/auto-peering/routes.ts +++ b/packages/backend/src/payment-method/ilp/auto-peering/routes.ts @@ -5,7 +5,7 @@ import { AutoPeeringService } from './service' interface PeeringRequestArgs { staticIlpAddress: string - ilpConnectorAddress: string + ilpConnectorUrl: string asset: { code: string; scale: number } httpToken: string maxPacketAmount?: number diff --git a/packages/backend/src/payment-method/ilp/auto-peering/service.test.ts b/packages/backend/src/payment-method/ilp/auto-peering/service.test.ts index 7789d20101..af2c2e2282 100644 --- a/packages/backend/src/payment-method/ilp/auto-peering/service.test.ts +++ b/packages/backend/src/payment-method/ilp/auto-peering/service.test.ts @@ -51,7 +51,7 @@ describe('Auto Peering Service', (): void => { const args: PeeringRequestArgs = { staticIlpAddress: 'test.rafiki-money', - ilpConnectorAddress: 'http://peer.rafiki.money', + ilpConnectorUrl: 'http://peer.rafiki.money', asset: { code: asset.code, scale: asset.scale }, httpToken: 'someHttpToken', name: 'Rafiki Money', @@ -64,7 +64,7 @@ describe('Auto Peering Service', (): void => { autoPeeringService.acceptPeeringRequest(args) ).resolves.toEqual({ staticIlpAddress: config.ilpAddress, - ilpConnectorAddress: config.ilpConnectorAddress, + ilpConnectorUrl: config.ilpConnectorUrl, httpToken: expect.any(String), name: config.instanceName }) @@ -78,7 +78,7 @@ describe('Auto Peering Service', (): void => { incoming: { authTokens: [args.httpToken] }, outgoing: { authToken: expect.any(String), - endpoint: args.ilpConnectorAddress + endpoint: args.ilpConnectorUrl } } }) @@ -89,7 +89,7 @@ describe('Auto Peering Service', (): void => { const args: PeeringRequestArgs = { staticIlpAddress: 'test.rafiki-money', - ilpConnectorAddress: 'http://peer.rafiki.money', + ilpConnectorUrl: 'http://peer.rafiki.money', asset: { code: asset.code, scale: asset.scale }, httpToken: 'someHttpToken', name: 'Rafiki Money' @@ -101,7 +101,7 @@ describe('Auto Peering Service', (): void => { autoPeeringService.acceptPeeringRequest(args) ).resolves.toEqual({ staticIlpAddress: config.ilpAddress, - ilpConnectorAddress: config.ilpConnectorAddress, + ilpConnectorUrl: config.ilpConnectorUrl, httpToken: expect.any(String), name: config.instanceName }) @@ -111,7 +111,7 @@ describe('Auto Peering Service', (): void => { autoPeeringService.acceptPeeringRequest(args) ).resolves.toEqual({ staticIlpAddress: config.ilpAddress, - ilpConnectorAddress: config.ilpConnectorAddress, + ilpConnectorUrl: config.ilpConnectorUrl, httpToken: expect.any(String), name: config.instanceName }) @@ -122,7 +122,7 @@ describe('Auto Peering Service', (): void => { incoming: { authTokens: [args.httpToken] }, outgoing: { authToken: expect.any(String), - endpoint: args.ilpConnectorAddress + endpoint: args.ilpConnectorUrl } } }) @@ -132,7 +132,7 @@ describe('Auto Peering Service', (): void => { test('returns error if unknown asset', async (): Promise => { const args: PeeringRequestArgs = { staticIlpAddress: 'test.rafiki-money', - ilpConnectorAddress: 'http://peer.rafiki.money', + ilpConnectorUrl: 'http://peer.rafiki.money', asset: { code: 'USD', scale: 2 }, httpToken: 'someHttpToken' } @@ -147,7 +147,7 @@ describe('Auto Peering Service', (): void => { const args: PeeringRequestArgs = { staticIlpAddress: 'test.rafiki-money', - ilpConnectorAddress: 'invalid', + ilpConnectorUrl: 'invalid', asset: { code: asset.code, scale: asset.scale }, httpToken: 'someHttpToken' } @@ -162,7 +162,7 @@ describe('Auto Peering Service', (): void => { const args: PeeringRequestArgs = { staticIlpAddress: 'invalid', - ilpConnectorAddress: 'http://peer.rafiki.money', + ilpConnectorUrl: 'http://peer.rafiki.money', asset: { code: asset.code, scale: asset.scale }, httpToken: 'someHttpToken' } @@ -177,7 +177,7 @@ describe('Auto Peering Service', (): void => { const args: PeeringRequestArgs = { staticIlpAddress: 'test.rafiki-money', - ilpConnectorAddress: 'http://peer.rafiki.money', + ilpConnectorUrl: 'http://peer.rafiki.money', asset: { code: asset.code, scale: asset.scale }, httpToken: 'someHttpToken' } @@ -219,7 +219,7 @@ describe('Auto Peering Service', (): void => { const peerDetails: PeeringDetails = { staticIlpAddress: 'test.peer2', - ilpConnectorAddress: 'http://peer-two.com', + ilpConnectorUrl: 'http://peer-two.com', httpToken: 'peerHttpToken', name: 'Peer 2' } @@ -232,7 +232,7 @@ describe('Auto Peering Service', (): void => { scale: asset.scale }, httpToken: expect.any(String), - ilpConnectorAddress: config.ilpConnectorAddress, + ilpConnectorUrl: config.ilpConnectorUrl, maxPacketAmount: Number(args.maxPacketAmount), name: config.instanceName, staticIlpAddress: config.ilpAddress @@ -255,7 +255,7 @@ describe('Auto Peering Service', (): void => { authTokens: [peerDetails.httpToken] }, outgoing: { - endpoint: peerDetails.ilpConnectorAddress, + endpoint: peerDetails.ilpConnectorUrl, authToken: expect.any(String) } }, @@ -280,7 +280,7 @@ describe('Auto Peering Service', (): void => { const peerDetails: PeeringDetails = { staticIlpAddress: 'test.peer2', - ilpConnectorAddress: 'http://peer-two.com', + ilpConnectorUrl: 'http://peer-two.com', httpToken: 'peerHttpToken', name: 'Peer 2' } @@ -293,7 +293,7 @@ describe('Auto Peering Service', (): void => { scale: asset.scale }, httpToken: expect.any(String), - ilpConnectorAddress: config.ilpConnectorAddress, + ilpConnectorUrl: config.ilpConnectorUrl, maxPacketAmount: Number(args.maxPacketAmount), name: config.instanceName, staticIlpAddress: config.ilpAddress @@ -326,7 +326,7 @@ describe('Auto Peering Service', (): void => { const peerDetails: PeeringDetails = { staticIlpAddress: 'test.peer2', - ilpConnectorAddress: 'http://peer-two.com', + ilpConnectorUrl: 'http://peer-two.com', httpToken: 'peerHttpToken', name: 'Peer 2' } @@ -339,7 +339,7 @@ describe('Auto Peering Service', (): void => { scale: asset.scale }, httpToken: expect.any(String), - ilpConnectorAddress: config.ilpConnectorAddress, + ilpConnectorUrl: config.ilpConnectorUrl, maxPacketAmount: Number(args.maxPacketAmount), name: config.instanceName, staticIlpAddress: config.ilpAddress @@ -366,7 +366,7 @@ describe('Auto Peering Service', (): void => { const peerDetails: PeeringDetails = { staticIlpAddress: 'test.peer2', - ilpConnectorAddress: 'http://peer-two.com', + ilpConnectorUrl: 'http://peer-two.com', httpToken: 'peerHttpToken', name: 'Peer 2' } @@ -387,7 +387,7 @@ describe('Auto Peering Service', (): void => { authTokens: [peerDetails.httpToken] }, outgoing: { - endpoint: peerDetails.ilpConnectorAddress, + endpoint: peerDetails.ilpConnectorUrl, authToken: expect.any(String) } }, @@ -477,7 +477,7 @@ describe('Auto Peering Service', (): void => { const peerDetails: PeeringDetails = { staticIlpAddress: '', - ilpConnectorAddress: 'http://peer-two.com', + ilpConnectorUrl: 'http://peer-two.com', httpToken: 'peerHttpToken', name: 'Peer 2' } @@ -500,7 +500,7 @@ describe('Auto Peering Service', (): void => { const peerDetails: PeeringDetails = { staticIlpAddress: 'test.peer2', - ilpConnectorAddress: '', + ilpConnectorUrl: '', httpToken: 'peerHttpToken', name: 'Peer 2' } @@ -523,7 +523,7 @@ describe('Auto Peering Service', (): void => { const peerDetails: PeeringDetails = { staticIlpAddress: 'test.peer2', - ilpConnectorAddress: 'http://peer-two.com', + ilpConnectorUrl: 'http://peer-two.com', httpToken: uuid(), name: 'Peer 2' } @@ -579,7 +579,7 @@ describe('Auto Peering Service', (): void => { const peerDetails: PeeringDetails = { staticIlpAddress: 'test.peer2', - ilpConnectorAddress: 'http://peer-two.com', + ilpConnectorUrl: 'http://peer-two.com', httpToken: uuid(), name: 'Peer 2' } @@ -617,7 +617,7 @@ describe('Auto Peering Service', (): void => { const peerDetails: PeeringDetails = { staticIlpAddress: 'test.peer2', - ilpConnectorAddress: 'http://peer-two.com', + ilpConnectorUrl: 'http://peer-two.com', httpToken: uuid(), name: 'Peer 2' } @@ -649,7 +649,7 @@ describe('Auto Peering Service', (): void => { const peerDetails: PeeringDetails = { staticIlpAddress: 'test.peer2', - ilpConnectorAddress: 'http://peer-two.com', + ilpConnectorUrl: 'http://peer-two.com', httpToken: 'peerHttpToken', name: 'Peer 2' } diff --git a/packages/backend/src/payment-method/ilp/auto-peering/service.ts b/packages/backend/src/payment-method/ilp/auto-peering/service.ts index ea9f77ba6b..31d1e60ea9 100644 --- a/packages/backend/src/payment-method/ilp/auto-peering/service.ts +++ b/packages/backend/src/payment-method/ilp/auto-peering/service.ts @@ -11,7 +11,7 @@ import { isTransferError } from '../../../accounting/errors' export interface PeeringDetails { staticIlpAddress: string - ilpConnectorAddress: string + ilpConnectorUrl: string httpToken: string name: string } @@ -27,7 +27,7 @@ export interface InitiatePeeringRequestArgs { export interface PeeringRequestArgs { staticIlpAddress: string - ilpConnectorAddress: string + ilpConnectorUrl: string asset: { code: string; scale: number } httpToken: string maxPacketAmount?: number @@ -36,7 +36,7 @@ export interface PeeringRequestArgs { interface UpdatePeerArgs { staticIlpAddress: string - ilpConnectorAddress: string + ilpConnectorUrl: string assetId: string incomingHttpToken: string outgoingHttpToken: string @@ -96,7 +96,7 @@ async function initiatePeeringRequest( const outgoingHttpToken = uuid() const peeringDetailsOrError = await sendPeeringRequest(deps, peerUrl, { - ilpConnectorAddress: deps.config.ilpConnectorAddress, + ilpConnectorUrl: deps.config.ilpConnectorUrl, staticIlpAddress: deps.config.ilpAddress, asset: { code: asset.code, scale: asset.scale }, httpToken: outgoingHttpToken, @@ -120,7 +120,7 @@ async function initiatePeeringRequest( }, outgoing: { authToken: outgoingHttpToken, - endpoint: peeringDetailsOrError.ilpConnectorAddress + endpoint: peeringDetailsOrError.ilpConnectorUrl } } }) @@ -139,7 +139,7 @@ async function initiatePeeringRequest( assetId: asset.id, outgoingHttpToken, incomingHttpToken: peeringDetailsOrError.httpToken, - ilpConnectorAddress: peeringDetailsOrError.ilpConnectorAddress + ilpConnectorUrl: peeringDetailsOrError.ilpConnectorUrl }) : createdPeerOrError @@ -243,7 +243,7 @@ async function acceptPeeringRequest( authTokens: [args.httpToken] }, outgoing: { - endpoint: args.ilpConnectorAddress, + endpoint: args.ilpConnectorUrl, authToken: outgoingHttpToken } }, @@ -262,7 +262,7 @@ async function acceptPeeringRequest( assetId: asset.id, outgoingHttpToken, incomingHttpToken: args.httpToken, - ilpConnectorAddress: args.ilpConnectorAddress + ilpConnectorUrl: args.ilpConnectorUrl }) : createdPeerOrError @@ -275,7 +275,7 @@ async function acceptPeeringRequest( } return { - ilpConnectorAddress: deps.config.ilpConnectorAddress, + ilpConnectorUrl: deps.config.ilpConnectorUrl, staticIlpAddress: deps.config.ilpAddress, httpToken: peerOrError.http.outgoing.authToken, name: deps.config.instanceName @@ -306,7 +306,7 @@ async function updatePeer( incoming: { authTokens: [args.incomingHttpToken] }, outgoing: { authToken: args.outgoingHttpToken, - endpoint: args.ilpConnectorAddress + endpoint: args.ilpConnectorUrl } } }) diff --git a/packages/backend/src/payment-method/ilp/spsp/middleware.test.ts b/packages/backend/src/payment-method/ilp/spsp/middleware.test.ts index 4a70a5fcd9..9a4705f9c6 100644 --- a/packages/backend/src/payment-method/ilp/spsp/middleware.test.ts +++ b/packages/backend/src/payment-method/ilp/spsp/middleware.test.ts @@ -56,24 +56,24 @@ describe('SPSP Middleware', (): void => { }) test.each` - header | spspEnabled | description - ${'application/json'} | ${true} | ${'calls next'} - ${'application/json'} | ${false} | ${'calls next'} - ${'application/spsp4+json'} | ${true} | ${'calls SPSP route'} - ${'application/spsp4+json'} | ${false} | ${'calls next'} - ${'*/*'} | ${true} | ${'calls next'} - ${'*/*'} | ${false} | ${'calls next'} + header | enableSpspPaymentPointers | description + ${'application/json'} | ${true} | ${'calls next'} + ${'application/json'} | ${false} | ${'calls next'} + ${'application/spsp4+json'} | ${true} | ${'calls SPSP route'} + ${'application/spsp4+json'} | ${false} | ${'calls next'} + ${'*/*'} | ${true} | ${'calls next'} + ${'*/*'} | ${false} | ${'calls next'} `( - '$description for accept header: $header and spspEnabled: $spspEnabled', - async ({ header, spspEnabled }): Promise => { + '$description for accept header: $header and enableSpspPaymentPointers: $enableSpspPaymentPointers', + async ({ header, enableSpspPaymentPointers }): Promise => { const spspSpy = jest .spyOn(spspRoutes, 'get') .mockResolvedValueOnce(undefined) ctx.headers['accept'] = header - const spspMiddleware = createSpspMiddleware(spspEnabled) + const spspMiddleware = createSpspMiddleware(enableSpspPaymentPointers) await expect(spspMiddleware(ctx, next)).resolves.toBeUndefined() - if (spspEnabled && header == 'application/spsp4+json') { + if (enableSpspPaymentPointers && header == 'application/spsp4+json') { expect(spspSpy).toHaveBeenCalledTimes(1) expect(next).not.toHaveBeenCalled() expect(ctx.paymentTag).toEqual(walletAddress.id) diff --git a/packages/documentation/src/content/docs/concepts/interledger-protocol/peering.md b/packages/documentation/src/content/docs/concepts/interledger-protocol/peering.md index 43fe14afd1..de7994149b 100644 --- a/packages/documentation/src/content/docs/concepts/interledger-protocol/peering.md +++ b/packages/documentation/src/content/docs/concepts/interledger-protocol/peering.md @@ -362,14 +362,14 @@ with the input being: } ``` -Calling this mutation will exchange ILP peering information (`staticIlpAddress` `ilpConnectorAddress`, auth tokens) automatically. The instance being peered with will issue a default amount of liquidity, and you can begin sending payments to wallet addresses at the other Rafiki instance. +Calling this mutation will exchange ILP peering information (`staticIlpAddress` `ilpConnectorUrl`, auth tokens) automatically. The instance being peered with will issue a default amount of liquidity, and you can begin sending payments to wallet addresses at the other Rafiki instance. ### Prerequisites Before making the `createOrUpdatePeerByUrl` request, a few `backend` environment variables about your Rafiki instance need to be configured: 1. `ILP_ADDRESS`: The static ILP address of your Rafiki instance. This should already be defined in order to support ILP payments. -2. `ILP_CONNECTOR_ADDRESS`: The full address of the ILP connector that will receive ILP packets. Locally and by default, it is on `0.0.0.0:3002`. +2. `ILP_CONNECTOR_URL`: The full address of the ILP connector that will receive ILP packets. Locally and by default, it is on `0.0.0.0:3002`. 3. `INSTANCE_NAME`: The name of your Rafiki instance. This is how your peer will identify you. ### How to enable auto-peering diff --git a/packages/documentation/src/content/docs/integration/deployment.md b/packages/documentation/src/content/docs/integration/deployment.md index cb032692f1..d1615e985c 100644 --- a/packages/documentation/src/content/docs/integration/deployment.md +++ b/packages/documentation/src/content/docs/integration/deployment.md @@ -55,28 +55,28 @@ Now, the Admin UI can be found on localhost:3010. | Variable | Helm Value Name | Default | Description | | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ADMIN_PORT` | backend.port.admin | `3001` | Admin API GraphQL Server port | -| `AUTH_SERVER_GRANT_URL` | | `http://127.0.0.1:3006` | endpoint on the Open Payments Auth Server to request a grant | -| `AUTH_SERVER_INTROSPECTION_URL` | | `http://127.0.0.1:3007` | endpoint on the Open Payments Auth Server to introspect an access token | +| `AUTH_SERVER_GRANT_URL` | | `undefined` | endpoint on the Open Payments Auth Server to request a grant | +| `AUTH_SERVER_INTROSPECTION_URL` | | `undefined` | endpoint on the Open Payments Auth Server to introspect an access token | | `AUTO_PEERING_SERVER_PORT` | | `3005` | If [auto-peering](/concepts/interledger-protocol/peering#auto-peering) is enabled, its server will use this port | | `CONNECTOR_PORT` | backend.port.connector | `3002` | port of the ILP connector for for sending packets over ILP over HTTP | | `DATABASE_URL` | backend.postgresql.host, backend.postgresql.port, backend.postgresql.username, backend.postgresql.database, backend.postgresql.password | `postgresql://postgres:password@localhost:5432/development` | Postgres database URL of database storing the resource data; For Helm, these components are provided individually. | | `ENABLE_AUTO_PEERING` | | `false` | Flag to enable auto peering. View [documentation](/concepts/interledger-protocol/peering#auto-peering). | -| `ENABLE_SPSP` | | `true` | enables [SPSP](/reference/glossary#simple-payments-setup-protocol-spsp) route | +| `ENABLE_SPSP_PAYMENT_POINTERS` | | `true` | enables [SPSP](/reference/glossary#simple-payments-setup-protocol-spsp) route | | `EXCHANGE_RATES_LIFETIME` | backend.lifetime.exchangeRate | `15_000` | time in milliseconds the exchange rates provided by the ASE via the EXCHANGE_RATES_URL are valid for | | `EXCHANGE_RATES_URL` | backend.serviceUrls.EXCHANGE_RATES_URL | `undefined` | endpoint on the Account Servicing Entity to request exchange rates | | `GRAPHQL_IDEMPOTENCY_KEY_TTL_MS` | backend.idempotencyTTL | `86400000` | TTL in milliseconds for idempotencyKey on GraphQL mutations (Admin API). Default: 24hrs | | `GRAPHQL_IDEMPOTENCY_KEY_LOCK_MS` | | `2000` | TTL in milliseconds for idempotencyKey concurrency lock on GraphQL mutations (Admin API) | -| `ILP_ADDRESS` | backend.ilp.address | `test.rafiki` | ILP address of this Rafiki instance | -| `ILP_CONNECTOR_ADDRESS` | | `http://127.0.0.1:3002` | The ILP connector address where ILP packets are received. Communicated during [auto-peering](/concepts/interledger-protocol/peering#auto-peering) | +| `ILP_ADDRESS` | backend.ilp.address | `undefined` | ILP address of this Rafiki instance | +| `ILP_CONNECTOR_URL` | | `undefined` | The ILP connector address where ILP packets are received. Communicated during [auto-peering](/concepts/interledger-protocol/peering#auto-peering) | | `INCOMING_PAYMENT_EXPIRY_MAX_MS` | | `2592000000` | Maximum milliseconds into the future incoming payments expiry can be set to on creation. Default: 30 days | | `INCOMING_PAYMENT_WORKERS` | backend.workers.incomingPayment | `1` | number of workers processing incoming payment requests | | `INCOMING_PAYMENT_WORKER_IDLE` | backend.workerIdle | `200` | time in milliseconds that INCOMING_PAYMENT_WORKERS will wait until they check an empty incoming payment request queue again | -| `INSTANCE_NAME` | | `Rafiki` | this Rafiki instance's name used to communicate for [auto-peering](/concepts/interledger-protocol/peering#auto-peering) | -| `KEY_ID` | backend.key.id | `rafiki` | this Rafiki instance's client key id | +| `INSTANCE_NAME` | | `undefined` | this Rafiki instance's name used to communicate for [auto-peering](/concepts/interledger-protocol/peering#auto-peering) | +| `KEY_ID` | backend.key.id | `undefined` | this Rafiki instance's client key id | | `LOG_LEVEL` | backend.logLevel | `info` | [Pino Log Level](https://getpino.io/#/docs/api?id=levels) | | `NODE_ENV` | backend.nodeEnv | `development` | node environment, `development`, `test`, or `production` | | `OPEN_PAYMENTS_PORT` | backend.port.openPayments | `3003` | port of the Open Payments resource server port | -| `OPEN_PAYMENTS_URL` | backend.serviceUrls.OPEN_PAYMENTS_URL | `http://127.0.0.1:3003` | public endpoint of this Open Payments Resource Server | +| `OPEN_PAYMENTS_URL` | backend.serviceUrls.OPEN_PAYMENTS_URL | `undefined` | public endpoint of this Open Payments Resource Server | | `OUTGOING_PAYMENT_WORKERS` | backend.workers.outgoingPayment | `4` | number of workers processing outgoing payment requests | | `OUTGOING_PAYMENT_WORKER_IDLE` | backend.workerIdle | `200` | time in milliseconds that OUTGOING_PAYMENT_WORKERS will wait until they check an empty outgoing payment request queue again | | `PRIVATE_KEY_FILE` | backend.key.file | `undefined` | the path to this Rafiki instance's client private key | @@ -88,11 +88,11 @@ Now, the Admin UI can be found on localhost:3010. | `SIGNATURE_SECRET` | backend.quoteSignatureSecret | `undefined` | secret to generate request header signatures for webhook event requests | | `SIGNATURE_VERSION` | | `1` | version number to generate request header signatures for webhook event requests | | `SLIPPAGE` | backend.ilp.slippage | `0.01` | accepted ILP rate fluctuation, default 1% | -| `STREAM_SECRET` | backend.ilp.streamSecret | 32 random bytes | seed secret to generate shared STREAM secrets | +| `STREAM_SECRET` | backend.ilp.streamSecret | undefined | seed secret to generate shared STREAM secrets | | `TIGERBEETLE_CLUSTER_ID` | | `0` | Tigerbeetle cluster ID picked by the system that starts the TigerBeetle cluster to create a [Tigerbeetle client](https://docs.tigerbeetle.com/clients/node#creating-a-client) | | `TIGERBEETLE_REPLICA_ADDRESSES` | | `3004` | Tigerbeetle replica addresses for all replicas in the cluster, which are comma separated IP addresses/ports, to create a [Tigerbeetle client](https://docs.tigerbeetle.com/clients/node#creating-a-client) | | `TRUST_PROXY` | | `false` | flag to use X-Forwarded-Proto header to determine if connections is secure | -| `USE_TIGERBEETLE` | | `false` | flag - use TigerBeetle or Postgres for accounting | +| `USE_TIGERBEETLE` | | `true` | flag - use TigerBeetle or Postgres for accounting | | `WALLET_ADDRESS_DEACTIVATION_PAYMENT_GRACE_PERIOD_MS` | | `86400000` | time in milliseconds into the future to set expiration of open incoming payments when deactivating wallet address. Default: 1 days | | `WALLET_ADDRESS_LOOKUP_TIMEOUT_MS` | | `1500` | time in milliseconds the ASE has to create a missing wallet address until timeout | | `WALLET_ADDRESS_POLLING_FREQUENCY_MS` | | `100` | frequency of polling while waiting for ASE to create a missing wallet address | @@ -101,7 +101,7 @@ Now, the Admin UI can be found on localhost:3010. | `WALLET_ADDRESS_WORKER_IDLE` | backend.workerIdle | `200` | time in milliseconds that WALLET_ADDRESS_WORKERS will wait until they check an empty wallet address request queue again | | `WEBHOOK_MAX_RETRY` | backend.webhookMaxRetry | `10` | maximum number of times Rafiki backend retries sending a certain webhook event to the configured WEBHOOK_URL | | `WEBHOOK_TIMEOUT` | backend.lifetime.webhook | `2000` | milliseconds | -| `WEBHOOK_URL` | backend.serviceUrls.WEBHOOK_URL | `http://127.0.0.1:4001/webhook` | endpoint on the Account Servicing Entity that consumes webhook events | +| `WEBHOOK_URL` | backend.serviceUrls.WEBHOOK_URL | `undefined` | endpoint on the Account Servicing Entity that consumes webhook events | | `WEBHOOK_WORKERS` | backend.workers.webhook | `1` | number of workers processing webhook events | | `WEBHOOK_WORKER_IDLE` | backend.workerIdle | `200` | time in milliseconds that WEBHOOK_WORKERS will wait until they check an empty webhook event queue again | | `WITHDRAWAL_THROTTLE_DELAY` | backend.withdrawalThrottleDelay | `undefined` | delay in liquidity withdrawal processing | diff --git a/test/integration/testenv/cloud-nine-wallet/docker-compose.yml b/test/integration/testenv/cloud-nine-wallet/docker-compose.yml index cd42756e39..090b75257e 100644 --- a/test/integration/testenv/cloud-nine-wallet/docker-compose.yml +++ b/test/integration/testenv/cloud-nine-wallet/docker-compose.yml @@ -19,6 +19,7 @@ services: environment: LOG_LEVEL: debug NODE_ENV: development + INSTANCE_NAME: 'Rafiki' CONNECTOR_PORT: 3102 ADMIN_PORT: 3101 OPEN_PAYMENTS_PORT: 3100 @@ -31,10 +32,12 @@ services: AUTH_SERVER_INTROSPECTION_URL: http://cloud-nine-wallet-test-auth:3107 AUTH_SERVER_GRANT_URL: http://cloud-nine-wallet-test-auth:3106 ILP_ADDRESS: test.cloud-nine-wallet-test + ILP_CONNECTOR_URL: http://127.0.0.1:3102 STREAM_SECRET: BjPXtnd00G2mRQwP/8ZpwyZASOch5sUXT5o0iR5b5wU= WEBHOOK_URL: http://host.docker.internal:8888/webhooks EXCHANGE_RATES_URL: http://host.docker.internal:8888/rates REDIS_URL: redis://shared-redis:6379/0 + USE_TIGERBEETLE: false volumes: - ../private-key.pem:/workspace/private-key.pem depends_on: diff --git a/test/integration/testenv/happy-life-bank/docker-compose.yml b/test/integration/testenv/happy-life-bank/docker-compose.yml index 09121fa9b2..91c84487c1 100644 --- a/test/integration/testenv/happy-life-bank/docker-compose.yml +++ b/test/integration/testenv/happy-life-bank/docker-compose.yml @@ -17,6 +17,7 @@ services: environment: NODE_ENV: development LOG_LEVEL: debug + INSTANCE_NAME: 'Happy Life Test' OPEN_PAYMENTS_URL: https://happy-life-bank-test-backend:4100 WALLET_ADDRESS_URL: https://happy-life-bank-test-backend:4100/.well-known/pay ADMIN_PORT: 4101 @@ -29,10 +30,12 @@ services: KEY_ID: keyid-97a3a431-8ee1-48fc-ac85-70e2f5eba8e5 PRIVATE_KEY_FILE: /workspace/private-key.pem ILP_ADDRESS: test.happy-life-bank-test + ILP_CONNECTOR_URL: http://127.0.0.1:4102 STREAM_SECRET: BjPXtnd00G2mRQwP/8ZpwyZASOch5sUXT5o0iR5b5wU= WEBHOOK_URL: http://host.docker.internal:8889/webhooks EXCHANGE_RATES_URL: http://host.docker.internal:8889/rates REDIS_URL: redis://shared-redis:6379/2 + USE_TIGERBEETLE: false volumes: - ../private-key.pem:/workspace/private-key.pem depends_on: From c8c0457980e3714fb4761a7238bf6d3246a896f6 Mon Sep 17 00:00:00 2001 From: Nathan Lie Date: Tue, 25 Jun 2024 07:09:29 -0700 Subject: [PATCH 3/3] feat(backend)!: logging plugin for graphql resolvers, remove error resolver responses (#2768) * feat: add logging plugin * wip: update graphql schema * chore: update asset resolvers * wip: update autopeering resolvers * feat: further simplify asset resolver * feat: update fee resolvers * fix: autopeering tests * feat: update incoming payments * fix: improve error handling on incoming payment resolver * feat: update outgoing payment resolvers * feat: update peer resolvers * feat: update quote resolvers * feat: update receiver resolvers * feat: update wallet address resolvers * feat: update wallet address key resolvers * feat(wip): backend graphql logs * feat(backend): updated logs for graphql resolvers, remove code & message from resolver responses * update frontend types * chore: formatting * feat: update integration tests * fix: rebase induced test errors * fix: frontend wallet address update * fix: reinstate and fix removed test * fix: change some payment gql error codes * feat: change liquidity response to just return success * fix: bigints, integration query * fix: integration tests * fix: asset test * fix: delete unnecessary code * fix: test for graphqlerror instead of apolloerror * chore: formatting * fix: inspect error object in tests --------- Co-authored-by: Sabine Schaller --- .../Create Outgoing Payment.bru | 3 - .../Create Quote.bru | 2 - ...ate Receiver (remote Incoming Payment).bru | 3 - .../Create Outgoing Payment.bru | 3 - .../Peer-to-Peer Payment/Create Quote.bru | 2 - ...ate Receiver -remote Incoming Payment-.bru | 3 - .../Cancel Outgoing Payment.bru | 49 +- .../Create Asset Liquidity Withdrawal.bru | 3 - .../Rafiki/Rafiki Admin APIs/Create Asset.bru | 3 - .../Create Incoming Payment Withdrawal.bru | 5 +- .../Create Incoming Payment.bru | 3 - .../Create Or Update Peer By Url.bru | 3 - ...Outgoing Payment From Incoming Payment.bru | 3 - .../Create Outgoing Payment Withdrawal.bru | 5 +- .../Create Outgoing Payment.bru | 3 - .../Create Peer Liquidity Withdrawal.bru | 3 - .../Rafiki/Rafiki Admin APIs/Create Peer.bru | 3 - .../Rafiki/Rafiki Admin APIs/Create Quote.bru | 2 - ...ate Receiver (remote Incoming Payment).bru | 3 - .../Create Wallet Address Key.bru | 3 - .../Create Wallet Address Withdrawal.bru | 4 - .../Create Wallet Address.bru | 5 +- .../Rafiki/Rafiki Admin APIs/Delete Asset.bru | 11 +- .../Rafiki/Rafiki Admin APIs/Delete Peer.bru | 2 - .../Deposit Asset Liquidity.bru | 3 - .../Deposit Event Liquidity.bru | 3 - .../Deposit Outgoing Payment Liquidity.bru | 3 - .../Deposit Peer Liquidity.bru | 5 +- .../Post Liquidity Withdrawal.bru | 3 - .../Revoke Wallet Address Key.bru | 3 - .../Rafiki/Rafiki Admin APIs/Set Fee.bru | 3 - .../Trigger Wallet Address Events.bru | 3 - .../Rafiki/Rafiki Admin APIs/Update Asset.bru | 3 - .../Rafiki/Rafiki Admin APIs/Update Peer.bru | 3 - .../Update Wallet Address.bru | 3 - .../Void Liquidity Withdrawal.bru | 3 - .../Withdraw Event Liquidity.bru | 3 - .../Rafiki Admin Auth APIs/Revoke Grant.bru | 4 +- .../app/lib/requesters.ts | 18 +- .../app/lib/webhooks.server.ts | 19 +- .../generated/graphql.ts | 172 +- packages/backend/src/accounting/errors.ts | 51 + packages/backend/src/app.ts | 4 + packages/backend/src/asset/errors.ts | 12 +- packages/backend/src/fee/errors.ts | 12 +- packages/backend/src/graphql/errors/index.ts | 9 + .../src/graphql/generated/graphql.schema.json | 1280 +------- .../backend/src/graphql/generated/graphql.ts | 172 +- .../src/graphql/middleware/index.test.ts | 120 +- packages/backend/src/graphql/plugin/index.ts | 58 + .../src/graphql/resolvers/asset.test.ts | 370 ++- .../backend/src/graphql/resolvers/asset.ts | 154 +- .../graphql/resolvers/auto-peering.test.ts | 152 +- .../src/graphql/resolvers/auto-peering.ts | 40 +- .../backend/src/graphql/resolvers/fee.test.ts | 206 +- packages/backend/src/graphql/resolvers/fee.ts | 37 +- .../resolvers/incoming_payment.test.ts | 150 +- .../src/graphql/resolvers/incoming_payment.ts | 62 +- .../src/graphql/resolvers/liquidity.test.ts | 2803 +++++++++-------- .../src/graphql/resolvers/liquidity.ts | 906 +++--- .../resolvers/outgoing_payment.test.ts | 335 +- .../src/graphql/resolvers/outgoing_payment.ts | 127 +- .../src/graphql/resolvers/peer.test.ts | 455 +-- .../backend/src/graphql/resolvers/peer.ts | 121 +- .../src/graphql/resolvers/quote.test.ts | 127 +- .../backend/src/graphql/resolvers/quote.ts | 50 +- .../src/graphql/resolvers/receiver.test.ts | 205 +- .../backend/src/graphql/resolvers/receiver.ts | 53 +- .../resolvers/walletAddressKey.test.ts | 159 +- .../src/graphql/resolvers/walletAddressKey.ts | 76 +- .../graphql/resolvers/wallet_address.test.ts | 427 ++- .../src/graphql/resolvers/wallet_address.ts | 106 +- packages/backend/src/graphql/schema.graphql | 95 +- .../open_payments/payment/incoming/errors.ts | 16 +- .../payment/incoming/routes.test.ts | 4 +- .../open_payments/payment/incoming/routes.ts | 10 +- .../payment/incoming_remote/errors.ts | 11 +- .../open_payments/payment/outgoing/errors.ts | 29 +- .../payment/outgoing/routes.test.ts | 4 +- .../open_payments/payment/outgoing/routes.ts | 8 +- .../backend/src/open_payments/quote/errors.ts | 14 +- .../backend/src/open_payments/quote/routes.ts | 4 +- .../src/open_payments/receiver/errors.ts | 3 +- .../open_payments/wallet_address/errors.ts | 10 +- .../payment-method/ilp/auto-peering/errors.ts | 31 +- .../ilp/auto-peering/routes.test.ts | 6 +- .../payment-method/ilp/auto-peering/routes.ts | 4 +- .../src/payment-method/ilp/peer/errors.ts | 18 +- packages/frontend/app/generated/graphql.ts | 206 +- packages/frontend/app/lib/api/asset.server.ts | 54 +- .../frontend/app/lib/api/payments.server.ts | 3 - packages/frontend/app/lib/api/peer.server.ts | 17 +- .../app/lib/api/wallet-address.server.ts | 14 +- .../assets.$assetId.deposit-liquidity.tsx | 6 +- .../frontend/app/routes/assets.$assetId.tsx | 13 +- .../assets.$assetId.withdraw-liquidity.tsx | 6 +- .../frontend/app/routes/assets.create.tsx | 6 +- ....$incomingPaymentId.withdraw-liquidity.tsx | 3 +- ...g.$outgoingPaymentId.deposit-liquidity.tsx | 3 +- ....$outgoingPaymentId.withdraw-liquidity.tsx | 3 +- .../peers.$peerId.deposit-liquidity.tsx | 6 +- .../frontend/app/routes/peers.$peerId.tsx | 8 +- .../peers.$peerId.withdraw-liquidity.tsx | 6 +- packages/frontend/app/routes/peers.create.tsx | 6 +- .../wallet-addresses.$walletAddressId.tsx | 5 +- ...es.$walletAddressId.withdraw-liquidity.tsx | 5 +- .../app/routes/wallet-addresses.create.tsx | 6 +- .../src/generated/graphql.ts | 172 +- .../src/requesters.ts | 44 +- packages/mock-account-service-lib/src/seed.ts | 12 +- test/integration/lib/admin-client.ts | 12 - test/integration/lib/generated/graphql.ts | 172 +- test/integration/lib/integration-server.ts | 5 +- test/integration/lib/test-actions/admin.ts | 3 - 114 files changed, 4208 insertions(+), 6077 deletions(-) create mode 100644 packages/backend/src/graphql/errors/index.ts create mode 100644 packages/backend/src/graphql/plugin/index.ts diff --git a/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Cross Currency Payment/Create Outgoing Payment.bru b/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Cross Currency Payment/Create Outgoing Payment.bru index 274c637fa6..891e215064 100644 --- a/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Cross Currency Payment/Create Outgoing Payment.bru +++ b/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Cross Currency Payment/Create Outgoing Payment.bru @@ -13,8 +13,6 @@ post { body:graphql { mutation CreateOutgoingPayment($input: CreateOutgoingPaymentInput!) { createOutgoingPayment(input: $input) { - code - message payment { createdAt error @@ -40,7 +38,6 @@ body:graphql { state stateAttempts } - success } } } diff --git a/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Cross Currency Payment/Create Quote.bru b/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Cross Currency Payment/Create Quote.bru index 9369e20c59..419f0d4424 100644 --- a/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Cross Currency Payment/Create Quote.bru +++ b/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Cross Currency Payment/Create Quote.bru @@ -13,8 +13,6 @@ post { body:graphql { mutation CreateQuote($input: CreateQuoteInput!) { createQuote(input: $input) { - code - message quote { createdAt expiresAt diff --git a/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Cross Currency Payment/Create Receiver (remote Incoming Payment).bru b/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Cross Currency Payment/Create Receiver (remote Incoming Payment).bru index 47df598515..df6e3561fd 100644 --- a/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Cross Currency Payment/Create Receiver (remote Incoming Payment).bru +++ b/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Cross Currency Payment/Create Receiver (remote Incoming Payment).bru @@ -13,8 +13,6 @@ post { body:graphql { mutation CreateReceiver($input: CreateReceiverInput!) { createReceiver(input: $input) { - code - message receiver { completed createdAt @@ -34,7 +32,6 @@ body:graphql { } updatedAt } - success } } } diff --git a/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Payment/Create Outgoing Payment.bru b/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Payment/Create Outgoing Payment.bru index 274c637fa6..891e215064 100644 --- a/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Payment/Create Outgoing Payment.bru +++ b/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Payment/Create Outgoing Payment.bru @@ -13,8 +13,6 @@ post { body:graphql { mutation CreateOutgoingPayment($input: CreateOutgoingPaymentInput!) { createOutgoingPayment(input: $input) { - code - message payment { createdAt error @@ -40,7 +38,6 @@ body:graphql { state stateAttempts } - success } } } diff --git a/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Payment/Create Quote.bru b/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Payment/Create Quote.bru index 9369e20c59..419f0d4424 100644 --- a/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Payment/Create Quote.bru +++ b/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Payment/Create Quote.bru @@ -13,8 +13,6 @@ post { body:graphql { mutation CreateQuote($input: CreateQuoteInput!) { createQuote(input: $input) { - code - message quote { createdAt expiresAt diff --git a/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Payment/Create Receiver -remote Incoming Payment-.bru b/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Payment/Create Receiver -remote Incoming Payment-.bru index a6e4c14083..a060c1e4fc 100644 --- a/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Payment/Create Receiver -remote Incoming Payment-.bru +++ b/bruno/collections/Rafiki/Examples/Admin API - only locally/Peer-to-Peer Payment/Create Receiver -remote Incoming Payment-.bru @@ -13,8 +13,6 @@ post { body:graphql { mutation CreateReceiver($input: CreateReceiverInput!) { createReceiver(input: $input) { - code - message receiver { completed createdAt @@ -34,7 +32,6 @@ body:graphql { } updatedAt } - success } } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Cancel Outgoing Payment.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Cancel Outgoing Payment.bru index c1ae36e746..9d3dc30452 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Cancel Outgoing Payment.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Cancel Outgoing Payment.bru @@ -13,9 +13,52 @@ post { body:graphql { mutation CancelOutgoingPayment($input: CancelOutgoingPaymentInput!) { cancelOutgoingPayment(input: $input) { - code - message - success + payment { + createdAt + error + metadata + id + walletAddressId + quote { + createdAt + expiresAt + highEstimatedExchangeRate + id + lowEstimatedExchangeRate + maxPacketAmount + minExchangeRate + walletAddressId + receiveAmount { + assetCode + assetScale + value + } + receiver + debitAmount { + assetCode + assetScale + value + } + } + receiveAmount { + assetCode + assetScale + value + } + receiver + debitAmount { + assetCode + assetScale + value + } + sentAmount { + assetCode + assetScale + value + } + state + stateAttempts + } } } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Asset Liquidity Withdrawal.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Asset Liquidity Withdrawal.bru index 3ee4d48766..552163a6ea 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Asset Liquidity Withdrawal.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Asset Liquidity Withdrawal.bru @@ -13,10 +13,7 @@ post { body:graphql { mutation CreateAssetLiquidityWithdrawal ($input: CreateAssetLiquidityWithdrawalInput!) { createAssetLiquidityWithdrawal(input: $input) { - code success - message - error } } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Asset.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Asset.bru index 4a39ff032b..347917ce31 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Asset.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Asset.bru @@ -21,9 +21,6 @@ body:graphql { withdrawalThreshold liquidityThreshold } - code - message - success } } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Incoming Payment Withdrawal.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Incoming Payment Withdrawal.bru index 97752f81f3..3c8243c573 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Incoming Payment Withdrawal.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Incoming Payment Withdrawal.bru @@ -13,10 +13,7 @@ post { body:graphql { mutation CreateIncomingPaymentWithdrawal($input: CreateIncomingPaymentWithdrawalInput!) { createIncomingPaymentWithdrawal(input: $input) { - code - error - message - success + success } } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Incoming Payment.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Incoming Payment.bru index d382f38253..9ba6c4873b 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Incoming Payment.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Incoming Payment.bru @@ -13,8 +13,6 @@ post { body:graphql { mutation CreateIncomingPayment ($input: CreateIncomingPaymentInput!) { createIncomingPayment(input: $input) { - code - message payment { createdAt expiresAt @@ -33,7 +31,6 @@ body:graphql { } state } - success } } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Or Update Peer By Url.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Or Update Peer By Url.bru index de6e5a43d8..f4aa8577a6 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Or Update Peer By Url.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Or Update Peer By Url.bru @@ -13,9 +13,6 @@ post { body:graphql { mutation CreateOrUpdatePeerByUrl ($input: CreateOrUpdatePeerByUrlInput!) { createOrUpdatePeerByUrl (input: $input) { - code - message - success peer { id name diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Outgoing Payment From Incoming Payment.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Outgoing Payment From Incoming Payment.bru index 6715f7a651..3bbdab9300 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Outgoing Payment From Incoming Payment.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Outgoing Payment From Incoming Payment.bru @@ -13,8 +13,6 @@ post { body:graphql { mutation CreateOutgoingPaymentFromIncomingPayment($input: CreateOutgoingPaymentFromIncomingPaymentInput!) { createOutgoingPaymentFromIncomingPayment(input: $input) { - code - message payment { createdAt error @@ -61,7 +59,6 @@ body:graphql { state stateAttempts } - success } } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Outgoing Payment Withdrawal.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Outgoing Payment Withdrawal.bru index 832a1ae9f7..2e063f382f 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Outgoing Payment Withdrawal.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Outgoing Payment Withdrawal.bru @@ -13,10 +13,7 @@ post { body:graphql { mutation CreateOutgoingPaymentWithdrawal($input: CreateOutgoingPaymentWithdrawalInput!) { createOutgoingPaymentWithdrawal(input: $input) { - code - error - message - success + success } } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Outgoing Payment.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Outgoing Payment.bru index 275ce0b1bc..4f331a360c 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Outgoing Payment.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Outgoing Payment.bru @@ -13,8 +13,6 @@ post { body:graphql { mutation CreateOutgoingPayment($input: CreateOutgoingPaymentInput!) { createOutgoingPayment(input: $input) { - code - message payment { createdAt error @@ -61,7 +59,6 @@ body:graphql { state stateAttempts } - success } } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Peer Liquidity Withdrawal.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Peer Liquidity Withdrawal.bru index d11e557709..d4fcc195a9 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Peer Liquidity Withdrawal.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Peer Liquidity Withdrawal.bru @@ -13,10 +13,7 @@ post { body:graphql { mutation CreatePeerLiquidityWithdrawal ($input: CreatePeerLiquidityWithdrawalInput!) { createPeerLiquidityWithdrawal(input: $input) { - code success - message - error } } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Peer.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Peer.bru index f781efc61b..77cbc4164c 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Peer.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Peer.bru @@ -13,9 +13,6 @@ post { body:graphql { mutation CreatePeer ($input: CreatePeerInput!) { createPeer (input: $input) { - code - message - success peer { id name diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Quote.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Quote.bru index 81fcd937ca..9588bf3218 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Quote.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Quote.bru @@ -13,8 +13,6 @@ post { body:graphql { mutation CreateQuote($input: CreateQuoteInput!) { createQuote(input: $input) { - code - message quote { createdAt expiresAt diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Receiver (remote Incoming Payment).bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Receiver (remote Incoming Payment).bru index 516e898d10..b29949ef3c 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Receiver (remote Incoming Payment).bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Receiver (remote Incoming Payment).bru @@ -13,8 +13,6 @@ post { body:graphql { mutation CreateReceiver($input: CreateReceiverInput!) { createReceiver(input: $input) { - code - message receiver { completed createdAt @@ -34,7 +32,6 @@ body:graphql { } updatedAt } - success } } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Wallet Address Key.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Wallet Address Key.bru index a803187bd9..1588f72353 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Wallet Address Key.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Wallet Address Key.bru @@ -13,9 +13,6 @@ post { body:graphql { mutation CreateWalletAddressKey ($input: CreateWalletAddressKeyInput!) { createWalletAddressKey(input: $input) { - code - message - success walletAddressKey { id revoked diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Wallet Address Withdrawal.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Wallet Address Withdrawal.bru index ff377ab90a..974d5b386a 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Wallet Address Withdrawal.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Wallet Address Withdrawal.bru @@ -13,10 +13,6 @@ post { body:graphql { mutation CreateWalletAddressWithdrawal($input: CreateWalletAddressWithdrawalInput!) { createWalletAddressWithdrawal(input: $input) { - code - error - message - success withdrawal { amount id diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Wallet Address.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Wallet Address.bru index c3eb9808d5..f7923fd835 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Create Wallet Address.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Create Wallet Address.bru @@ -13,9 +13,6 @@ post { body:graphql { mutation CreateWalletAddres($input: CreateWalletAddressInput!) { createWalletAddress(input: $input) { - code - success - message walletAddress { id createdAt @@ -57,7 +54,7 @@ script:pre-request { const { nanoid } = require("nanoid"); const scripts = require('./scripts'); - bru.setVar('randomId', nanoid()); + bru.setVar("randomId", nanoid()); scripts.addApiSignatureHeader(); } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Delete Asset.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Delete Asset.bru index 8aa988638f..b35ceab5e9 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Delete Asset.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Delete Asset.bru @@ -13,9 +13,14 @@ post { body:graphql { mutation DeleteAsset($input: DeleteAssetInput!) { deleteAsset(input: $input) { - code - message - success + asset { + code + createdAt + id + scale + withdrawalThreshold + liquidityThreshold + } } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Delete Peer.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Delete Peer.bru index bd8385b05c..3abd964f40 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Delete Peer.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Delete Peer.bru @@ -13,8 +13,6 @@ post { body:graphql { mutation DeletePeer($input: DeletePeerInput!) { deletePeer(input: $input) { - code - message success } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Deposit Asset Liquidity.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Deposit Asset Liquidity.bru index 9718c60753..038029f179 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Deposit Asset Liquidity.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Deposit Asset Liquidity.bru @@ -13,10 +13,7 @@ post { body:graphql { mutation DepositAssetLiquidity ($input: DepositAssetLiquidityInput!) { depositAssetLiquidity(input: $input) { - code success - message - error } } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Deposit Event Liquidity.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Deposit Event Liquidity.bru index 7172470130..48751deca0 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Deposit Event Liquidity.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Deposit Event Liquidity.bru @@ -13,9 +13,6 @@ post { body:graphql { mutation DepositEventLiquidity($input: DepositEventLiquidityInput!) { depositEventLiquidity(input: $input) { - code - error - message success } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Deposit Outgoing Payment Liquidity.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Deposit Outgoing Payment Liquidity.bru index 7e7b48c401..a02bc5b8c6 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Deposit Outgoing Payment Liquidity.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Deposit Outgoing Payment Liquidity.bru @@ -13,9 +13,6 @@ post { body:graphql { mutation DepositOutgoingPaymentLiquidity($input: DepositOutgoingPaymentLiquidityInput!) { depositOutgoingPaymentLiquidity(input: $input) { - code - error - message success } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Deposit Peer Liquidity.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Deposit Peer Liquidity.bru index 84da018d9b..3b2ae41c07 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Deposit Peer Liquidity.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Deposit Peer Liquidity.bru @@ -13,10 +13,7 @@ post { body:graphql { mutation DepositPeerLiquidity ($input: DepositPeerLiquidityInput!) { depositPeerLiquidity(input: $input) { - code - success - message - error + success } } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Post Liquidity Withdrawal.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Post Liquidity Withdrawal.bru index f4916f076f..6fae5f0df5 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Post Liquidity Withdrawal.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Post Liquidity Withdrawal.bru @@ -13,9 +13,6 @@ post { body:graphql { mutation PostLiquidityWithdrawal($input: PostLiquidityWithdrawalInput!) { postLiquidityWithdrawal(input: $input) { - code - error - message success } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Revoke Wallet Address Key.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Revoke Wallet Address Key.bru index a8757f516d..ceb230c859 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Revoke Wallet Address Key.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Revoke Wallet Address Key.bru @@ -13,9 +13,6 @@ post { body:graphql { mutation RevokeWalletAddressKey ($input: RevokeWalletAddressKeyInput!) { revokeWalletAddressKey (input: $input) { - code - message - success walletAddressKey { id revoked diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Set Fee.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Set Fee.bru index 82f657bb2e..2055395df6 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Set Fee.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Set Fee.bru @@ -13,9 +13,6 @@ post { body:graphql { mutation SetFee($input: SetFeeInput!) { setFee(input: $input) { - code - success - message fee { id assetId diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Trigger Wallet Address Events.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Trigger Wallet Address Events.bru index c0df1c700a..3c8515ca8f 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Trigger Wallet Address Events.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Trigger Wallet Address Events.bru @@ -13,10 +13,7 @@ post { body:graphql { mutation TriggerWalletAddressEvents($input: TriggerWalletAddressEventsInput!) { triggerWalletAddressEvents(input: $input) { - code count - message - success } } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Update Asset.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Update Asset.bru index 3c70f63fbc..f527f0ac9e 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Update Asset.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Update Asset.bru @@ -21,9 +21,6 @@ body:graphql { withdrawalThreshold liquidityThreshold } - code - message - success } } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Update Peer.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Update Peer.bru index 5d37f8c50a..3bc84e7cb7 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Update Peer.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Update Peer.bru @@ -13,9 +13,6 @@ post { body:graphql { mutation UpdatePeer ($input: UpdatePeerInput!){ updatePeer(input: $input) { - code - success - message peer { id name diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Update Wallet Address.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Update Wallet Address.bru index 68f9024d9a..ddfc0376e2 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Update Wallet Address.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Update Wallet Address.bru @@ -13,8 +13,6 @@ post { body:graphql { mutation UpdateWalletAddress($input: UpdateWalletAddressInput!) { updateWalletAddress(input: $input) { - code - message walletAddress { id asset { @@ -29,7 +27,6 @@ body:graphql { createdAt status } - success } } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Void Liquidity Withdrawal.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Void Liquidity Withdrawal.bru index 1e65b829d9..8b8448bbe8 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Void Liquidity Withdrawal.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Void Liquidity Withdrawal.bru @@ -13,9 +13,6 @@ post { body:graphql { mutation VoidLiquidityWithdrawal($input: VoidLiquidityWithdrawalInput!) { voidLiquidityWithdrawal(input: $input) { - code - error - message success } } diff --git a/bruno/collections/Rafiki/Rafiki Admin APIs/Withdraw Event Liquidity.bru b/bruno/collections/Rafiki/Rafiki Admin APIs/Withdraw Event Liquidity.bru index de9cc95c34..1dfdf8466b 100644 --- a/bruno/collections/Rafiki/Rafiki Admin APIs/Withdraw Event Liquidity.bru +++ b/bruno/collections/Rafiki/Rafiki Admin APIs/Withdraw Event Liquidity.bru @@ -13,9 +13,6 @@ post { body:graphql { mutation WithdrawEventLiquidity($input: WithdrawEventLiquidityInput!) { withdrawEventLiquidity(input: $input) { - code - error - message success } } diff --git a/bruno/collections/Rafiki/Rafiki Admin Auth APIs/Revoke Grant.bru b/bruno/collections/Rafiki/Rafiki Admin Auth APIs/Revoke Grant.bru index cb655b332b..6b0f15b374 100644 --- a/bruno/collections/Rafiki/Rafiki Admin Auth APIs/Revoke Grant.bru +++ b/bruno/collections/Rafiki/Rafiki Admin Auth APIs/Revoke Grant.bru @@ -13,9 +13,7 @@ post { body:graphql { mutation revokeGrant($input: RevokeGrantInput!) { revokeGrant(input: $input) { - code - message - success + id } } } diff --git a/localenv/mock-account-servicing-entity/app/lib/requesters.ts b/localenv/mock-account-servicing-entity/app/lib/requesters.ts index 311d6cc261..0cb583f4e7 100644 --- a/localenv/mock-account-servicing-entity/app/lib/requesters.ts +++ b/localenv/mock-account-servicing-entity/app/lib/requesters.ts @@ -18,10 +18,7 @@ export async function depositPeerLiquidity( const depositPeerLiquidityMutation = gql` mutation DepositPeerLiquidity($input: DepositPeerLiquidityInput!) { depositPeerLiquidity(input: $input) { - code success - message - error } } ` @@ -40,7 +37,7 @@ export async function depositPeerLiquidity( }) .then(({ data }): LiquidityMutationResponse => { console.log(data) - if (!data.depositPeerLiquidity.success) { + if (!data.depositPeerLiquidity) { throw new Error('Data was empty') } return data.depositPeerLiquidity @@ -55,10 +52,7 @@ export async function depositAssetLiquidity( const depositAssetLiquidityMutation = gql` mutation DepositAssetLiquidity($input: DepositAssetLiquidityInput!) { depositAssetLiquidity(input: $input) { - code success - message - error } } ` @@ -77,7 +71,7 @@ export async function depositAssetLiquidity( }) .then(({ data }): LiquidityMutationResponse => { console.log(data) - if (!data.depositAssetLiquidity.success) { + if (!data.depositAssetLiquidity) { throw new Error('Data was empty') } return data.depositAssetLiquidity @@ -92,9 +86,6 @@ export async function createWalletAddress( const createWalletAddressMutation = gql` mutation CreateWalletAddress($input: CreateWalletAddressInput!) { createWalletAddress(input: $input) { - code - success - message walletAddress { id url @@ -120,10 +111,7 @@ export async function createWalletAddress( .then(({ data }) => { console.log(data) - if ( - !data.createWalletAddress.success || - !data.createWalletAddress.walletAddress - ) { + if (!data.createWalletAddress.walletAddress) { throw new Error('Data was empty') } diff --git a/localenv/mock-account-servicing-entity/app/lib/webhooks.server.ts b/localenv/mock-account-servicing-entity/app/lib/webhooks.server.ts index 28f46af534..72c44fd7fc 100644 --- a/localenv/mock-account-servicing-entity/app/lib/webhooks.server.ts +++ b/localenv/mock-account-servicing-entity/app/lib/webhooks.server.ts @@ -83,9 +83,9 @@ export async function handleOutgoingPaymentCreated(wh: Webhook) { mutation: gql` mutation CancelOutgoingPayment($input: CancelOutgoingPaymentInput!) { cancelOutgoingPayment(input: $input) { - code - success - message + payment { + id + } } } `, @@ -107,10 +107,7 @@ export async function handleOutgoingPaymentCreated(wh: Webhook) { $input: DepositOutgoingPaymentLiquidityInput! ) { depositOutgoingPaymentLiquidity(input: $input) { - code success - message - error } } `, @@ -159,10 +156,7 @@ export async function handleIncomingPaymentCompletedExpired(wh: Webhook) { $input: CreateIncomingPaymentWithdrawalInput! ) { createIncomingPaymentWithdrawal(input: $input) { - code success - message - error } } `, @@ -208,10 +202,6 @@ export async function handleWalletAddressWebMonetization(wh: Webhook) { $input: CreateWalletAddressWithdrawalInput! ) { createWalletAddressWithdrawal(input: $input) { - code - error - message - success withdrawal { amount id @@ -247,10 +237,7 @@ export async function handleWalletAddressWebMonetization(wh: Webhook) { $input: PostLiquidityWithdrawalInput! ) { postLiquidityWithdrawal(input: $input) { - code success - message - error } } `, diff --git a/localenv/mock-account-servicing-entity/generated/graphql.ts b/localenv/mock-account-servicing-entity/generated/graphql.ts index af780bc3ad..46f7835344 100644 --- a/localenv/mock-account-servicing-entity/generated/graphql.ts +++ b/localenv/mock-account-servicing-entity/generated/graphql.ts @@ -92,12 +92,9 @@ export type AssetEdge = { node: Asset; }; -export type AssetMutationResponse = MutationResponse & { +export type AssetMutationResponse = { __typename?: 'AssetMutationResponse'; asset?: Maybe; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; }; export type AssetsConnection = { @@ -186,12 +183,9 @@ export type CreateOrUpdatePeerByUrlInput = { peerUrl: Scalars['String']['input']; }; -export type CreateOrUpdatePeerByUrlMutationResponse = MutationResponse & { +export type CreateOrUpdatePeerByUrlMutationResponse = { __typename?: 'CreateOrUpdatePeerByUrlMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; peer?: Maybe; - success: Scalars['Boolean']['output']; }; export type CreateOutgoingPaymentFromIncomingPaymentInput = { @@ -259,12 +253,9 @@ export type CreatePeerLiquidityWithdrawalInput = { timeoutSeconds: Scalars['UInt64']['input']; }; -export type CreatePeerMutationResponse = MutationResponse & { +export type CreatePeerMutationResponse = { __typename?: 'CreatePeerMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; peer?: Maybe; - success: Scalars['Boolean']['output']; }; export type CreateQuoteInput = { @@ -295,10 +286,7 @@ export type CreateReceiverInput = { export type CreateReceiverResponse = { __typename?: 'CreateReceiverResponse'; - code: Scalars['String']['output']; - message?: Maybe; receiver?: Maybe; - success: Scalars['Boolean']['output']; }; export type CreateWalletAddressInput = { @@ -322,19 +310,13 @@ export type CreateWalletAddressKeyInput = { walletAddressId: Scalars['String']['input']; }; -export type CreateWalletAddressKeyMutationResponse = MutationResponse & { +export type CreateWalletAddressKeyMutationResponse = { __typename?: 'CreateWalletAddressKeyMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddressKey?: Maybe; }; -export type CreateWalletAddressMutationResponse = MutationResponse & { +export type CreateWalletAddressMutationResponse = { __typename?: 'CreateWalletAddressMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddress?: Maybe; }; @@ -360,11 +342,9 @@ export type DeleteAssetInput = { idempotencyKey?: InputMaybe; }; -export type DeleteAssetMutationResponse = MutationResponse & { +export type DeleteAssetMutationResponse = { __typename?: 'DeleteAssetMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; + asset?: Maybe; }; export type DeletePeerInput = { @@ -373,10 +353,8 @@ export type DeletePeerInput = { idempotencyKey?: InputMaybe; }; -export type DeletePeerMutationResponse = MutationResponse & { +export type DeletePeerMutationResponse = { __typename?: 'DeletePeerMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; success: Scalars['Boolean']['output']; }; @@ -533,10 +511,7 @@ export type IncomingPaymentEdge = { export type IncomingPaymentResponse = { __typename?: 'IncomingPaymentResponse'; - code: Scalars['String']['output']; - message?: Maybe; payment?: Maybe; - success: Scalars['Boolean']['output']; }; export enum IncomingPaymentState { @@ -596,11 +571,8 @@ export enum LiquidityError { UnknownWalletAddress = 'UnknownWalletAddress' } -export type LiquidityMutationResponse = MutationResponse & { +export type LiquidityMutationResponse = { __typename?: 'LiquidityMutationResponse'; - code: Scalars['String']['output']; - error?: Maybe; - message: Scalars['String']['output']; success: Scalars['Boolean']['output']; }; @@ -836,12 +808,6 @@ export type MutationWithdrawEventLiquidityArgs = { input: WithdrawEventLiquidityInput; }; -export type MutationResponse = { - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; -}; - export type OutgoingPayment = BasePayment & Model & { __typename?: 'OutgoingPayment'; /** Information about the wallet address of the Open Payments client that created the outgoing payment. */ @@ -886,10 +852,7 @@ export type OutgoingPaymentEdge = { export type OutgoingPaymentResponse = { __typename?: 'OutgoingPaymentResponse'; - code: Scalars['String']['output']; - message?: Maybe; payment?: Maybe; - success: Scalars['Boolean']['output']; }; export enum OutgoingPaymentState { @@ -1150,10 +1113,7 @@ export type QuoteEdge = { export type QuoteResponse = { __typename?: 'QuoteResponse'; - code: Scalars['String']['output']; - message?: Maybe; quote?: Maybe; - success: Scalars['Boolean']['output']; }; export type Receiver = { @@ -1185,11 +1145,8 @@ export type RevokeWalletAddressKeyInput = { idempotencyKey?: InputMaybe; }; -export type RevokeWalletAddressKeyMutationResponse = MutationResponse & { +export type RevokeWalletAddressKeyMutationResponse = { __typename?: 'RevokeWalletAddressKeyMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddressKey?: Maybe; }; @@ -1204,12 +1161,9 @@ export type SetFeeInput = { type: FeeType; }; -export type SetFeeResponse = MutationResponse & { +export type SetFeeResponse = { __typename?: 'SetFeeResponse'; - code: Scalars['String']['output']; fee?: Maybe; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; }; export enum SortOrder { @@ -1219,13 +1173,6 @@ export enum SortOrder { Desc = 'DESC' } -export type TransferMutationResponse = MutationResponse & { - __typename?: 'TransferMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; -}; - export type TriggerWalletAddressEventsInput = { /** Unique key to ensure duplicate or retried requests are processed only once. See [idempotence](https://en.wikipedia.org/wiki/Idempotence) */ idempotencyKey?: InputMaybe; @@ -1233,13 +1180,10 @@ export type TriggerWalletAddressEventsInput = { limit: Scalars['Int']['input']; }; -export type TriggerWalletAddressEventsMutationResponse = MutationResponse & { +export type TriggerWalletAddressEventsMutationResponse = { __typename?: 'TriggerWalletAddressEventsMutationResponse'; - code: Scalars['String']['output']; /** Number of events triggered */ count?: Maybe; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; }; export type UpdateAssetInput = { @@ -1270,12 +1214,9 @@ export type UpdatePeerInput = { staticIlpAddress?: InputMaybe; }; -export type UpdatePeerMutationResponse = MutationResponse & { +export type UpdatePeerMutationResponse = { __typename?: 'UpdatePeerMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; peer?: Maybe; - success: Scalars['Boolean']['output']; }; export type UpdateWalletAddressInput = { @@ -1291,11 +1232,8 @@ export type UpdateWalletAddressInput = { status?: InputMaybe; }; -export type UpdateWalletAddressMutationResponse = MutationResponse & { +export type UpdateWalletAddressMutationResponse = { __typename?: 'UpdateWalletAddressMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddress?: Maybe; }; @@ -1419,12 +1357,8 @@ export type WalletAddressWithdrawal = { walletAddress: WalletAddress; }; -export type WalletAddressWithdrawalMutationResponse = MutationResponse & { +export type WalletAddressWithdrawalMutationResponse = { __typename?: 'WalletAddressWithdrawalMutationResponse'; - code: Scalars['String']['output']; - error?: Maybe; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; withdrawal?: Maybe; }; @@ -1541,7 +1475,6 @@ export type DirectiveResolverFn> = { BasePayment: ( Partial ) | ( Partial ) | ( Partial ); Model: ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ); - MutationResponse: ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ); }; /** Mapping between all available schema types and the resolvers types */ @@ -1614,7 +1547,6 @@ export type ResolversTypes = { LiquidityMutationResponse: ResolverTypeWrapper>; Model: ResolverTypeWrapper['Model']>; Mutation: ResolverTypeWrapper<{}>; - MutationResponse: ResolverTypeWrapper['MutationResponse']>; OutgoingPayment: ResolverTypeWrapper>; OutgoingPaymentConnection: ResolverTypeWrapper>; OutgoingPaymentEdge: ResolverTypeWrapper>; @@ -1642,7 +1574,6 @@ export type ResolversTypes = { SetFeeResponse: ResolverTypeWrapper>; SortOrder: ResolverTypeWrapper>; String: ResolverTypeWrapper>; - TransferMutationResponse: ResolverTypeWrapper>; TriggerWalletAddressEventsInput: ResolverTypeWrapper>; TriggerWalletAddressEventsMutationResponse: ResolverTypeWrapper>; UInt8: ResolverTypeWrapper>; @@ -1733,7 +1664,6 @@ export type ResolversParentTypes = { LiquidityMutationResponse: Partial; Model: ResolversInterfaceTypes['Model']; Mutation: {}; - MutationResponse: ResolversInterfaceTypes['MutationResponse']; OutgoingPayment: Partial; OutgoingPaymentConnection: Partial; OutgoingPaymentEdge: Partial; @@ -1758,7 +1688,6 @@ export type ResolversParentTypes = { SetFeeInput: Partial; SetFeeResponse: Partial; String: Partial; - TransferMutationResponse: Partial; TriggerWalletAddressEventsInput: Partial; TriggerWalletAddressEventsMutationResponse: Partial; UInt8: Partial; @@ -1820,9 +1749,6 @@ export type AssetEdgeResolvers = { asset?: Resolver, ParentType, ContextType>; - code?: Resolver; - message?: Resolver; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -1842,55 +1768,36 @@ export type BasePaymentResolvers = { - code?: Resolver; - message?: Resolver; peer?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type CreatePeerMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; peer?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type CreateReceiverResponseResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; receiver?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type CreateWalletAddressKeyMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddressKey?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type CreateWalletAddressMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddress?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type DeleteAssetMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; + asset?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type DeletePeerMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -1955,10 +1862,7 @@ export type IncomingPaymentEdgeResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; payment?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -1976,9 +1880,6 @@ export type JwkResolvers = { - code?: Resolver; - error?: Resolver, ParentType, ContextType>; - message?: Resolver; success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2023,13 +1924,6 @@ export type MutationResolvers, ParentType, ContextType, RequireFields>; }; -export type MutationResponseResolvers = { - __resolveType: TypeResolveFn<'AssetMutationResponse' | 'CreateOrUpdatePeerByUrlMutationResponse' | 'CreatePeerMutationResponse' | 'CreateWalletAddressKeyMutationResponse' | 'CreateWalletAddressMutationResponse' | 'DeleteAssetMutationResponse' | 'DeletePeerMutationResponse' | 'LiquidityMutationResponse' | 'RevokeWalletAddressKeyMutationResponse' | 'SetFeeResponse' | 'TransferMutationResponse' | 'TriggerWalletAddressEventsMutationResponse' | 'UpdatePeerMutationResponse' | 'UpdateWalletAddressMutationResponse' | 'WalletAddressWithdrawalMutationResponse', ParentType, ContextType>; - code?: Resolver; - message?: Resolver; - success?: Resolver; -}; - export type OutgoingPaymentResolvers = { client?: Resolver, ParentType, ContextType>; createdAt?: Resolver; @@ -2061,10 +1955,7 @@ export type OutgoingPaymentEdgeResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; payment?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2168,10 +2059,7 @@ export type QuoteEdgeResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; quote?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2189,33 +2077,17 @@ export type ReceiverResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddressKey?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type SetFeeResponseResolvers = { - code?: Resolver; fee?: Resolver, ParentType, ContextType>; - message?: Resolver; - success?: Resolver; - __isTypeOf?: IsTypeOfResolverFn; -}; - -export type TransferMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type TriggerWalletAddressEventsMutationResponseResolvers = { - code?: Resolver; count?: Resolver, ParentType, ContextType>; - message?: Resolver; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2228,17 +2100,11 @@ export interface UInt64ScalarConfig extends GraphQLScalarTypeConfig = { - code?: Resolver; - message?: Resolver; peer?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type UpdateWalletAddressMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddress?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2294,10 +2160,6 @@ export type WalletAddressWithdrawalResolvers = { - code?: Resolver; - error?: Resolver, ParentType, ContextType>; - message?: Resolver; - success?: Resolver; withdrawal?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2357,7 +2219,6 @@ export type Resolvers = { LiquidityMutationResponse?: LiquidityMutationResponseResolvers; Model?: ModelResolvers; Mutation?: MutationResolvers; - MutationResponse?: MutationResponseResolvers; OutgoingPayment?: OutgoingPaymentResolvers; OutgoingPaymentConnection?: OutgoingPaymentConnectionResolvers; OutgoingPaymentEdge?: OutgoingPaymentEdgeResolvers; @@ -2377,7 +2238,6 @@ export type Resolvers = { Receiver?: ReceiverResolvers; RevokeWalletAddressKeyMutationResponse?: RevokeWalletAddressKeyMutationResponseResolvers; SetFeeResponse?: SetFeeResponseResolvers; - TransferMutationResponse?: TransferMutationResponseResolvers; TriggerWalletAddressEventsMutationResponse?: TriggerWalletAddressEventsMutationResponseResolvers; UInt8?: GraphQLScalarType; UInt64?: GraphQLScalarType; diff --git a/packages/backend/src/accounting/errors.ts b/packages/backend/src/accounting/errors.ts index cddf1ca1ba..fc3cc3ffc9 100644 --- a/packages/backend/src/accounting/errors.ts +++ b/packages/backend/src/accounting/errors.ts @@ -1,3 +1,5 @@ +import { GraphQLErrorCode } from '../graphql/errors' + export class CreateAccountError extends Error { constructor(public code: number) { super('CreateAccountError code=' + code) @@ -33,6 +35,55 @@ export enum TransferError { UnknownDestinationAccount = 'UnknownDestinationAccount' } +export const errorToCode: { + [key in TransferError]: GraphQLErrorCode +} = { + [TransferError.AlreadyPosted]: GraphQLErrorCode.Conflict, + [TransferError.AlreadyVoided]: GraphQLErrorCode.Conflict, + [TransferError.DifferentAssets]: GraphQLErrorCode.Forbidden, + [TransferError.InsufficientBalance]: GraphQLErrorCode.Forbidden, + [TransferError.InsufficientDebitBalance]: GraphQLErrorCode.Forbidden, + [TransferError.InsufficientLiquidity]: GraphQLErrorCode.Forbidden, + [TransferError.InvalidAmount]: GraphQLErrorCode.BadUserInput, + [TransferError.InvalidId]: GraphQLErrorCode.BadUserInput, + [TransferError.InvalidSourceAmount]: GraphQLErrorCode.BadUserInput, + [TransferError.InvalidDestinationAmount]: GraphQLErrorCode.BadUserInput, + [TransferError.InvalidTimeout]: GraphQLErrorCode.BadUserInput, + [TransferError.SameAccounts]: GraphQLErrorCode.Forbidden, + [TransferError.TransferExists]: GraphQLErrorCode.Duplicate, + [TransferError.TransferExpired]: GraphQLErrorCode.Forbidden, + [TransferError.UnknownTransfer]: GraphQLErrorCode.NotFound, + [TransferError.UnknownError]: GraphQLErrorCode.InternalServerError, + [TransferError.UnknownSourceAccount]: GraphQLErrorCode.NotFound, + [TransferError.UnknownDestinationAccount]: GraphQLErrorCode.NotFound +} + +export const errorToMessage: { + [key in TransferError]: string +} = { + [TransferError.AlreadyPosted]: 'Transfer already posted', + [TransferError.AlreadyVoided]: 'Transfer already voided', + [TransferError.DifferentAssets]: 'Transfer accounts have different assets', + [TransferError.InsufficientBalance]: 'Insufficient transfer balance', + [TransferError.InsufficientDebitBalance]: + 'Insufficient transfer debit balance', + [TransferError.InsufficientLiquidity]: + 'Insufficient transfer liquidity available', + [TransferError.InvalidAmount]: 'Invalid transfer amount', + [TransferError.InvalidId]: 'Invalid transfer id', + [TransferError.InvalidSourceAmount]: 'Invalid source account amount', + [TransferError.InvalidDestinationAmount]: + 'Invalid destination account amount', + [TransferError.InvalidTimeout]: 'Invalid transfer timeout provided', + [TransferError.SameAccounts]: 'Transfer is between the same accounts', + [TransferError.TransferExists]: 'Transfer already exists', + [TransferError.TransferExpired]: 'Transfer already expired', + [TransferError.UnknownTransfer]: 'Unknown transfer', + [TransferError.UnknownError]: 'Internal server error', + [TransferError.UnknownSourceAccount]: 'Unknown source account', + [TransferError.UnknownDestinationAccount]: 'Unknown destination account' +} + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types export const isTransferError = (o: any): o is TransferError => Object.values(TransferError).includes(o) diff --git a/packages/backend/src/app.ts b/packages/backend/src/app.ts index 149da7190a..d20750eb35 100644 --- a/packages/backend/src/app.ts +++ b/packages/backend/src/app.ts @@ -97,6 +97,7 @@ import { getWalletAddressUrlFromPath } from './open_payments/wallet_address/middleware' +import { LoggingPlugin } from './graphql/plugin' export interface AppContextData { logger: Logger container: AppContainer @@ -341,12 +342,15 @@ export class App { }) const protection = armor.protect() + const loggingPlugin = new LoggingPlugin(this.logger) + // Setup Apollo this.apolloServer = new ApolloServer({ schema: schemaWithMiddleware, ...protection, plugins: [ ...protection.plugins, + loggingPlugin, ApolloServerPluginDrainHttpServer({ httpServer }) ], introspection: this.config.env !== 'production' diff --git a/packages/backend/src/asset/errors.ts b/packages/backend/src/asset/errors.ts index 100ccb141d..36334ab1fc 100644 --- a/packages/backend/src/asset/errors.ts +++ b/packages/backend/src/asset/errors.ts @@ -1,3 +1,5 @@ +import { GraphQLErrorCode } from '../graphql/errors' + export enum AssetError { DuplicateAsset = 'DuplicateAsset', UnknownAsset = 'UnknownAsset', @@ -9,17 +11,17 @@ export const isAssetError = (o: any): o is AssetError => Object.values(AssetError).includes(o) export const errorToCode: { - [key in AssetError]: number + [key in AssetError]: GraphQLErrorCode } = { - [AssetError.UnknownAsset]: 404, - [AssetError.DuplicateAsset]: 400, - [AssetError.CannotDeleteInUseAsset]: 400 + [AssetError.UnknownAsset]: GraphQLErrorCode.NotFound, + [AssetError.DuplicateAsset]: GraphQLErrorCode.Duplicate, + [AssetError.CannotDeleteInUseAsset]: GraphQLErrorCode.Forbidden } export const errorToMessage: { [key in AssetError]: string } = { - [AssetError.UnknownAsset]: 'unknown asset', + [AssetError.UnknownAsset]: 'Asset not found', [AssetError.DuplicateAsset]: 'Asset already exists', [AssetError.CannotDeleteInUseAsset]: 'Cannot delete! Asset in use.' } diff --git a/packages/backend/src/fee/errors.ts b/packages/backend/src/fee/errors.ts index 86dd75c726..5de9fb7fff 100644 --- a/packages/backend/src/fee/errors.ts +++ b/packages/backend/src/fee/errors.ts @@ -1,3 +1,5 @@ +import { GraphQLErrorCode } from '../graphql/errors' + export enum FeeError { UnknownAsset = 'UnknownAsset', InvalidBasisPointFee = 'InvalidBasisPointFee', @@ -9,17 +11,17 @@ export const isFeeError = (o: any): o is FeeError => Object.values(FeeError).includes(o) export const errorToCode: { - [key in FeeError]: number + [key in FeeError]: GraphQLErrorCode } = { - [FeeError.UnknownAsset]: 404, - [FeeError.InvalidBasisPointFee]: 400, - [FeeError.InvalidFixedFee]: 400 + [FeeError.UnknownAsset]: GraphQLErrorCode.NotFound, + [FeeError.InvalidBasisPointFee]: GraphQLErrorCode.BadUserInput, + [FeeError.InvalidFixedFee]: GraphQLErrorCode.BadUserInput } export const errorToMessage: { [key in FeeError]: string } = { - [FeeError.UnknownAsset]: 'unknown asset', + [FeeError.UnknownAsset]: 'Unknown asset', [FeeError.InvalidBasisPointFee]: 'Basis point fee must be between 0 and 10000', [FeeError.InvalidFixedFee]: 'Fixed fee must be greater than or equal to 0' diff --git a/packages/backend/src/graphql/errors/index.ts b/packages/backend/src/graphql/errors/index.ts new file mode 100644 index 0000000000..e19601440a --- /dev/null +++ b/packages/backend/src/graphql/errors/index.ts @@ -0,0 +1,9 @@ +export enum GraphQLErrorCode { + BadUserInput = 'BAD_USER_INPUT', + Duplicate = 'DUPLICATE', + Forbidden = 'FORBIDDEN', + Inactive = 'INACTIVE', + InternalServerError = 'INTERNAL_SERVER_ERROR', + NotFound = 'NOT_FOUND', + Conflict = 'CONFLICT' +} diff --git a/packages/backend/src/graphql/generated/graphql.schema.json b/packages/backend/src/graphql/generated/graphql.schema.json index c1c44db49e..30050b3cc7 100644 --- a/packages/backend/src/graphql/generated/graphql.schema.json +++ b/packages/backend/src/graphql/generated/graphql.schema.json @@ -534,64 +534,10 @@ }, "isDeprecated": false, "deprecationReason": null - }, - { - "name": "code", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "success", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null } ], "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "MutationResponse", - "ofType": null - } - ], + "interfaces": [], "enumValues": null, "possibleTypes": null }, @@ -1206,38 +1152,6 @@ "name": "CreateOrUpdatePeerByUrlMutationResponse", "description": null, "fields": [ - { - "name": "code", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "peer", "description": null, @@ -1249,32 +1163,10 @@ }, "isDeprecated": false, "deprecationReason": null - }, - { - "name": "success", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null } ], "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "MutationResponse", - "ofType": null - } - ], + "interfaces": [], "enumValues": null, "possibleTypes": null }, @@ -1702,38 +1594,6 @@ "name": "CreatePeerMutationResponse", "description": null, "fields": [ - { - "name": "code", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "peer", "description": null, @@ -1745,32 +1605,10 @@ }, "isDeprecated": false, "deprecationReason": null - }, - { - "name": "success", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null } ], "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "MutationResponse", - "ofType": null - } - ], + "interfaces": [], "enumValues": null, "possibleTypes": null }, @@ -1933,34 +1771,6 @@ "name": "CreateReceiverResponse", "description": null, "fields": [ - { - "name": "code", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "receiver", "description": null, @@ -1972,22 +1782,6 @@ }, "isDeprecated": false, "deprecationReason": null - }, - { - "name": "success", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null } ], "inputFields": null, @@ -2143,25 +1937,55 @@ "description": null, "fields": [ { - "name": "code", + "name": "walletAddressKey", "description": null, "args": [], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } + "kind": "OBJECT", + "name": "WalletAddressKey", + "ofType": null }, "isDeprecated": false, "deprecationReason": null - }, + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "CreateWalletAddressMutationResponse", + "description": null, + "fields": [ { - "name": "message", + "name": "walletAddress", "description": null, "args": [], + "type": { + "kind": "OBJECT", + "name": "WalletAddress", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INPUT_OBJECT", + "name": "CreateWalletAddressWithdrawalInput", + "description": null, + "fields": null, + "inputFields": [ + { + "name": "id", + "description": "The id of the withdrawal.", "type": { "kind": "NON_NULL", "name": null, @@ -2171,145 +1995,7 @@ "ofType": null } }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "success", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "walletAddressKey", - "description": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "WalletAddressKey", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "MutationResponse", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "CreateWalletAddressMutationResponse", - "description": null, - "fields": [ - { - "name": "code", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "success", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "walletAddress", - "description": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "WalletAddress", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "MutationResponse", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "CreateWalletAddressWithdrawalInput", - "description": null, - "fields": null, - "inputFields": [ - { - "name": "id", - "description": "The id of the withdrawal.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null, + "defaultValue": null, "isDeprecated": false, "deprecationReason": null }, @@ -2428,62 +2114,20 @@ "description": null, "fields": [ { - "name": "code", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "success", + "name": "asset", "description": null, "args": [], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } + "kind": "OBJECT", + "name": "Asset", + "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "MutationResponse", - "ofType": null - } - ], + "interfaces": [], "enumValues": null, "possibleTypes": null }, @@ -2531,38 +2175,6 @@ "name": "DeletePeerMutationResponse", "description": null, "fields": [ - { - "name": "code", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "success", "description": null, @@ -2581,13 +2193,7 @@ } ], "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "MutationResponse", - "ofType": null - } - ], + "interfaces": [], "enumValues": null, "possibleTypes": null }, @@ -3607,34 +3213,6 @@ "name": "IncomingPaymentResponse", "description": null, "fields": [ - { - "name": "code", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "payment", "description": null, @@ -3646,22 +3224,6 @@ }, "isDeprecated": false, "deprecationReason": null - }, - { - "name": "success", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null } ], "inputFields": null, @@ -4011,50 +3573,6 @@ "name": "LiquidityMutationResponse", "description": null, "fields": [ - { - "name": "code", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "error", - "description": null, - "args": [], - "type": { - "kind": "ENUM", - "name": "LiquidityError", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "success", "description": null, @@ -4073,13 +3591,7 @@ } ], "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "MutationResponse", - "ofType": null - } - ], + "interfaces": [], "enumValues": null, "possibleTypes": null }, @@ -5150,141 +4662,6 @@ "enumValues": null, "possibleTypes": null }, - { - "kind": "INTERFACE", - "name": "MutationResponse", - "description": null, - "fields": [ - { - "name": "code", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "success", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": [ - { - "kind": "OBJECT", - "name": "AssetMutationResponse", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "CreateOrUpdatePeerByUrlMutationResponse", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "CreatePeerMutationResponse", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "CreateWalletAddressKeyMutationResponse", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "CreateWalletAddressMutationResponse", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "DeleteAssetMutationResponse", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "DeletePeerMutationResponse", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "LiquidityMutationResponse", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "RevokeWalletAddressKeyMutationResponse", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "SetFeeResponse", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "TransferMutationResponse", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "TriggerWalletAddressEventsMutationResponse", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "UpdatePeerMutationResponse", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "UpdateWalletAddressMutationResponse", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "WalletAddressWithdrawalMutationResponse", - "ofType": null - } - ] - }, { "kind": "OBJECT", "name": "OutgoingPayment", @@ -5610,34 +4987,6 @@ "name": "OutgoingPaymentResponse", "description": null, "fields": [ - { - "name": "code", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "payment", "description": null, @@ -5649,22 +4998,6 @@ }, "isDeprecated": false, "deprecationReason": null - }, - { - "name": "success", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null } ], "inputFields": null, @@ -7262,15 +6595,38 @@ "description": null, "fields": [ { - "name": "code", + "name": "quote", "description": null, "args": [], + "type": { + "kind": "OBJECT", + "name": "Quote", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "Receiver", + "description": null, + "fields": [ + { + "name": "completed", + "description": "Describes whether the incoming payment has completed receiving funds.", + "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", - "name": "String", + "name": "Boolean", "ofType": null } }, @@ -7278,75 +6634,8 @@ "deprecationReason": null }, { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "quote", - "description": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Quote", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "success", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Receiver", - "description": null, - "fields": [ - { - "name": "completed", - "description": "Describes whether the incoming payment has completed receiving funds.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt", - "description": "Date-time of creation", + "name": "createdAt", + "description": "Date-time of creation", "args": [], "type": { "kind": "NON_NULL", @@ -7510,54 +6799,6 @@ "name": "RevokeWalletAddressKeyMutationResponse", "description": null, "fields": [ - { - "name": "code", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "success", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "walletAddressKey", "description": null, @@ -7572,13 +6813,7 @@ } ], "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "MutationResponse", - "ofType": null - } - ], + "interfaces": [], "enumValues": null, "possibleTypes": null }, @@ -7658,22 +6893,6 @@ "name": "SetFeeResponse", "description": null, "fields": [ - { - "name": "code", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "fee", "description": null, @@ -7685,48 +6904,10 @@ }, "isDeprecated": false, "deprecationReason": null - }, - { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "success", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null } ], "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "MutationResponse", - "ofType": null - } - ], + "interfaces": [], "enumValues": null, "possibleTypes": null }, @@ -7763,71 +6944,6 @@ "enumValues": null, "possibleTypes": null }, - { - "kind": "OBJECT", - "name": "TransferMutationResponse", - "description": null, - "fields": [ - { - "name": "code", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "success", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "MutationResponse", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, { "kind": "INPUT_OBJECT", "name": "TriggerWalletAddressEventsInput", @@ -7872,22 +6988,6 @@ "name": "TriggerWalletAddressEventsMutationResponse", "description": null, "fields": [ - { - "name": "code", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "count", "description": "Number of events triggered", @@ -7899,48 +6999,10 @@ }, "isDeprecated": false, "deprecationReason": null - }, - { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "success", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null } ], "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "MutationResponse", - "ofType": null - } - ], + "interfaces": [], "enumValues": null, "possibleTypes": null }, @@ -8131,38 +7193,6 @@ "name": "UpdatePeerMutationResponse", "description": null, "fields": [ - { - "name": "code", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "peer", "description": null, @@ -8174,32 +7204,10 @@ }, "isDeprecated": false, "deprecationReason": null - }, - { - "name": "success", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null } ], "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "MutationResponse", - "ofType": null - } - ], + "interfaces": [], "enumValues": null, "possibleTypes": null }, @@ -8291,54 +7299,6 @@ "name": "UpdateWalletAddressMutationResponse", "description": null, "fields": [ - { - "name": "code", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "success", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "walletAddress", "description": null, @@ -8353,13 +7313,7 @@ } ], "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "MutationResponse", - "ofType": null - } - ], + "interfaces": [], "enumValues": null, "possibleTypes": null }, @@ -9156,66 +8110,6 @@ "name": "WalletAddressWithdrawalMutationResponse", "description": null, "fields": [ - { - "name": "code", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "error", - "description": null, - "args": [], - "type": { - "kind": "ENUM", - "name": "LiquidityError", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "success", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "withdrawal", "description": null, @@ -9230,13 +8124,7 @@ } ], "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "MutationResponse", - "ofType": null - } - ], + "interfaces": [], "enumValues": null, "possibleTypes": null }, diff --git a/packages/backend/src/graphql/generated/graphql.ts b/packages/backend/src/graphql/generated/graphql.ts index af780bc3ad..46f7835344 100644 --- a/packages/backend/src/graphql/generated/graphql.ts +++ b/packages/backend/src/graphql/generated/graphql.ts @@ -92,12 +92,9 @@ export type AssetEdge = { node: Asset; }; -export type AssetMutationResponse = MutationResponse & { +export type AssetMutationResponse = { __typename?: 'AssetMutationResponse'; asset?: Maybe; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; }; export type AssetsConnection = { @@ -186,12 +183,9 @@ export type CreateOrUpdatePeerByUrlInput = { peerUrl: Scalars['String']['input']; }; -export type CreateOrUpdatePeerByUrlMutationResponse = MutationResponse & { +export type CreateOrUpdatePeerByUrlMutationResponse = { __typename?: 'CreateOrUpdatePeerByUrlMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; peer?: Maybe; - success: Scalars['Boolean']['output']; }; export type CreateOutgoingPaymentFromIncomingPaymentInput = { @@ -259,12 +253,9 @@ export type CreatePeerLiquidityWithdrawalInput = { timeoutSeconds: Scalars['UInt64']['input']; }; -export type CreatePeerMutationResponse = MutationResponse & { +export type CreatePeerMutationResponse = { __typename?: 'CreatePeerMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; peer?: Maybe; - success: Scalars['Boolean']['output']; }; export type CreateQuoteInput = { @@ -295,10 +286,7 @@ export type CreateReceiverInput = { export type CreateReceiverResponse = { __typename?: 'CreateReceiverResponse'; - code: Scalars['String']['output']; - message?: Maybe; receiver?: Maybe; - success: Scalars['Boolean']['output']; }; export type CreateWalletAddressInput = { @@ -322,19 +310,13 @@ export type CreateWalletAddressKeyInput = { walletAddressId: Scalars['String']['input']; }; -export type CreateWalletAddressKeyMutationResponse = MutationResponse & { +export type CreateWalletAddressKeyMutationResponse = { __typename?: 'CreateWalletAddressKeyMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddressKey?: Maybe; }; -export type CreateWalletAddressMutationResponse = MutationResponse & { +export type CreateWalletAddressMutationResponse = { __typename?: 'CreateWalletAddressMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddress?: Maybe; }; @@ -360,11 +342,9 @@ export type DeleteAssetInput = { idempotencyKey?: InputMaybe; }; -export type DeleteAssetMutationResponse = MutationResponse & { +export type DeleteAssetMutationResponse = { __typename?: 'DeleteAssetMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; + asset?: Maybe; }; export type DeletePeerInput = { @@ -373,10 +353,8 @@ export type DeletePeerInput = { idempotencyKey?: InputMaybe; }; -export type DeletePeerMutationResponse = MutationResponse & { +export type DeletePeerMutationResponse = { __typename?: 'DeletePeerMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; success: Scalars['Boolean']['output']; }; @@ -533,10 +511,7 @@ export type IncomingPaymentEdge = { export type IncomingPaymentResponse = { __typename?: 'IncomingPaymentResponse'; - code: Scalars['String']['output']; - message?: Maybe; payment?: Maybe; - success: Scalars['Boolean']['output']; }; export enum IncomingPaymentState { @@ -596,11 +571,8 @@ export enum LiquidityError { UnknownWalletAddress = 'UnknownWalletAddress' } -export type LiquidityMutationResponse = MutationResponse & { +export type LiquidityMutationResponse = { __typename?: 'LiquidityMutationResponse'; - code: Scalars['String']['output']; - error?: Maybe; - message: Scalars['String']['output']; success: Scalars['Boolean']['output']; }; @@ -836,12 +808,6 @@ export type MutationWithdrawEventLiquidityArgs = { input: WithdrawEventLiquidityInput; }; -export type MutationResponse = { - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; -}; - export type OutgoingPayment = BasePayment & Model & { __typename?: 'OutgoingPayment'; /** Information about the wallet address of the Open Payments client that created the outgoing payment. */ @@ -886,10 +852,7 @@ export type OutgoingPaymentEdge = { export type OutgoingPaymentResponse = { __typename?: 'OutgoingPaymentResponse'; - code: Scalars['String']['output']; - message?: Maybe; payment?: Maybe; - success: Scalars['Boolean']['output']; }; export enum OutgoingPaymentState { @@ -1150,10 +1113,7 @@ export type QuoteEdge = { export type QuoteResponse = { __typename?: 'QuoteResponse'; - code: Scalars['String']['output']; - message?: Maybe; quote?: Maybe; - success: Scalars['Boolean']['output']; }; export type Receiver = { @@ -1185,11 +1145,8 @@ export type RevokeWalletAddressKeyInput = { idempotencyKey?: InputMaybe; }; -export type RevokeWalletAddressKeyMutationResponse = MutationResponse & { +export type RevokeWalletAddressKeyMutationResponse = { __typename?: 'RevokeWalletAddressKeyMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddressKey?: Maybe; }; @@ -1204,12 +1161,9 @@ export type SetFeeInput = { type: FeeType; }; -export type SetFeeResponse = MutationResponse & { +export type SetFeeResponse = { __typename?: 'SetFeeResponse'; - code: Scalars['String']['output']; fee?: Maybe; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; }; export enum SortOrder { @@ -1219,13 +1173,6 @@ export enum SortOrder { Desc = 'DESC' } -export type TransferMutationResponse = MutationResponse & { - __typename?: 'TransferMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; -}; - export type TriggerWalletAddressEventsInput = { /** Unique key to ensure duplicate or retried requests are processed only once. See [idempotence](https://en.wikipedia.org/wiki/Idempotence) */ idempotencyKey?: InputMaybe; @@ -1233,13 +1180,10 @@ export type TriggerWalletAddressEventsInput = { limit: Scalars['Int']['input']; }; -export type TriggerWalletAddressEventsMutationResponse = MutationResponse & { +export type TriggerWalletAddressEventsMutationResponse = { __typename?: 'TriggerWalletAddressEventsMutationResponse'; - code: Scalars['String']['output']; /** Number of events triggered */ count?: Maybe; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; }; export type UpdateAssetInput = { @@ -1270,12 +1214,9 @@ export type UpdatePeerInput = { staticIlpAddress?: InputMaybe; }; -export type UpdatePeerMutationResponse = MutationResponse & { +export type UpdatePeerMutationResponse = { __typename?: 'UpdatePeerMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; peer?: Maybe; - success: Scalars['Boolean']['output']; }; export type UpdateWalletAddressInput = { @@ -1291,11 +1232,8 @@ export type UpdateWalletAddressInput = { status?: InputMaybe; }; -export type UpdateWalletAddressMutationResponse = MutationResponse & { +export type UpdateWalletAddressMutationResponse = { __typename?: 'UpdateWalletAddressMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddress?: Maybe; }; @@ -1419,12 +1357,8 @@ export type WalletAddressWithdrawal = { walletAddress: WalletAddress; }; -export type WalletAddressWithdrawalMutationResponse = MutationResponse & { +export type WalletAddressWithdrawalMutationResponse = { __typename?: 'WalletAddressWithdrawalMutationResponse'; - code: Scalars['String']['output']; - error?: Maybe; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; withdrawal?: Maybe; }; @@ -1541,7 +1475,6 @@ export type DirectiveResolverFn> = { BasePayment: ( Partial ) | ( Partial ) | ( Partial ); Model: ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ); - MutationResponse: ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ); }; /** Mapping between all available schema types and the resolvers types */ @@ -1614,7 +1547,6 @@ export type ResolversTypes = { LiquidityMutationResponse: ResolverTypeWrapper>; Model: ResolverTypeWrapper['Model']>; Mutation: ResolverTypeWrapper<{}>; - MutationResponse: ResolverTypeWrapper['MutationResponse']>; OutgoingPayment: ResolverTypeWrapper>; OutgoingPaymentConnection: ResolverTypeWrapper>; OutgoingPaymentEdge: ResolverTypeWrapper>; @@ -1642,7 +1574,6 @@ export type ResolversTypes = { SetFeeResponse: ResolverTypeWrapper>; SortOrder: ResolverTypeWrapper>; String: ResolverTypeWrapper>; - TransferMutationResponse: ResolverTypeWrapper>; TriggerWalletAddressEventsInput: ResolverTypeWrapper>; TriggerWalletAddressEventsMutationResponse: ResolverTypeWrapper>; UInt8: ResolverTypeWrapper>; @@ -1733,7 +1664,6 @@ export type ResolversParentTypes = { LiquidityMutationResponse: Partial; Model: ResolversInterfaceTypes['Model']; Mutation: {}; - MutationResponse: ResolversInterfaceTypes['MutationResponse']; OutgoingPayment: Partial; OutgoingPaymentConnection: Partial; OutgoingPaymentEdge: Partial; @@ -1758,7 +1688,6 @@ export type ResolversParentTypes = { SetFeeInput: Partial; SetFeeResponse: Partial; String: Partial; - TransferMutationResponse: Partial; TriggerWalletAddressEventsInput: Partial; TriggerWalletAddressEventsMutationResponse: Partial; UInt8: Partial; @@ -1820,9 +1749,6 @@ export type AssetEdgeResolvers = { asset?: Resolver, ParentType, ContextType>; - code?: Resolver; - message?: Resolver; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -1842,55 +1768,36 @@ export type BasePaymentResolvers = { - code?: Resolver; - message?: Resolver; peer?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type CreatePeerMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; peer?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type CreateReceiverResponseResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; receiver?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type CreateWalletAddressKeyMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddressKey?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type CreateWalletAddressMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddress?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type DeleteAssetMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; + asset?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type DeletePeerMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -1955,10 +1862,7 @@ export type IncomingPaymentEdgeResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; payment?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -1976,9 +1880,6 @@ export type JwkResolvers = { - code?: Resolver; - error?: Resolver, ParentType, ContextType>; - message?: Resolver; success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2023,13 +1924,6 @@ export type MutationResolvers, ParentType, ContextType, RequireFields>; }; -export type MutationResponseResolvers = { - __resolveType: TypeResolveFn<'AssetMutationResponse' | 'CreateOrUpdatePeerByUrlMutationResponse' | 'CreatePeerMutationResponse' | 'CreateWalletAddressKeyMutationResponse' | 'CreateWalletAddressMutationResponse' | 'DeleteAssetMutationResponse' | 'DeletePeerMutationResponse' | 'LiquidityMutationResponse' | 'RevokeWalletAddressKeyMutationResponse' | 'SetFeeResponse' | 'TransferMutationResponse' | 'TriggerWalletAddressEventsMutationResponse' | 'UpdatePeerMutationResponse' | 'UpdateWalletAddressMutationResponse' | 'WalletAddressWithdrawalMutationResponse', ParentType, ContextType>; - code?: Resolver; - message?: Resolver; - success?: Resolver; -}; - export type OutgoingPaymentResolvers = { client?: Resolver, ParentType, ContextType>; createdAt?: Resolver; @@ -2061,10 +1955,7 @@ export type OutgoingPaymentEdgeResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; payment?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2168,10 +2059,7 @@ export type QuoteEdgeResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; quote?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2189,33 +2077,17 @@ export type ReceiverResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddressKey?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type SetFeeResponseResolvers = { - code?: Resolver; fee?: Resolver, ParentType, ContextType>; - message?: Resolver; - success?: Resolver; - __isTypeOf?: IsTypeOfResolverFn; -}; - -export type TransferMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type TriggerWalletAddressEventsMutationResponseResolvers = { - code?: Resolver; count?: Resolver, ParentType, ContextType>; - message?: Resolver; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2228,17 +2100,11 @@ export interface UInt64ScalarConfig extends GraphQLScalarTypeConfig = { - code?: Resolver; - message?: Resolver; peer?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type UpdateWalletAddressMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddress?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2294,10 +2160,6 @@ export type WalletAddressWithdrawalResolvers = { - code?: Resolver; - error?: Resolver, ParentType, ContextType>; - message?: Resolver; - success?: Resolver; withdrawal?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2357,7 +2219,6 @@ export type Resolvers = { LiquidityMutationResponse?: LiquidityMutationResponseResolvers; Model?: ModelResolvers; Mutation?: MutationResolvers; - MutationResponse?: MutationResponseResolvers; OutgoingPayment?: OutgoingPaymentResolvers; OutgoingPaymentConnection?: OutgoingPaymentConnectionResolvers; OutgoingPaymentEdge?: OutgoingPaymentEdgeResolvers; @@ -2377,7 +2238,6 @@ export type Resolvers = { Receiver?: ReceiverResolvers; RevokeWalletAddressKeyMutationResponse?: RevokeWalletAddressKeyMutationResponseResolvers; SetFeeResponse?: SetFeeResponseResolvers; - TransferMutationResponse?: TransferMutationResponseResolvers; TriggerWalletAddressEventsMutationResponse?: TriggerWalletAddressEventsMutationResponseResolvers; UInt8?: GraphQLScalarType; UInt64?: GraphQLScalarType; diff --git a/packages/backend/src/graphql/middleware/index.test.ts b/packages/backend/src/graphql/middleware/index.test.ts index 977fa56d5c..9631870034 100644 --- a/packages/backend/src/graphql/middleware/index.test.ts +++ b/packages/backend/src/graphql/middleware/index.test.ts @@ -10,8 +10,13 @@ import { Config } from '../../config/app' import { truncateTables } from '../../tests/tableManager' import { AssetService } from '../../asset/service' import { randomAsset } from '../../tests/asset' -import { AssetMutationResponse, CreateAssetInput } from '../generated/graphql' +import { + AssetMutationResponse, + CreateAssetInput, + UpdateAssetInput +} from '../generated/graphql' import { GraphQLError } from 'graphql' +import { AssetError, errorToMessage, errorToCode } from '../../asset/errors' describe('GraphQL Middleware', (): void => { let deps: IocContract @@ -39,9 +44,6 @@ describe('GraphQL Middleware', (): void => { mutation: gql` mutation CreateAsset($input: CreateAssetInput!) { createAsset(input: $input) { - code - success - message asset { id code @@ -64,59 +66,96 @@ describe('GraphQL Middleware', (): void => { }) } + const callUpdateAssetMutation = async (input: UpdateAssetInput) => { + return appContainer.apolloClient + .mutate({ + mutation: gql` + mutation UpdateAsset($input: UpdateAssetInput!) { + updateAsset(input: $input) { + asset { + id + code + scale + withdrawalThreshold + } + } + } + `, + variables: { + input + } + }) + .then((query): AssetMutationResponse => { + if (query.data) { + return query.data.updateAsset + } else { + throw new Error('Data was empty') + } + }) + } + describe('idempotencyGraphQLMiddleware', (): void => { + let createInput: CreateAssetInput + let createResponse: AssetMutationResponse + + beforeEach(async (): Promise => { + createInput = { + ...randomAsset(), + idempotencyKey: uuid() + } + + createResponse = await callCreateAssetMutation(createInput) + assert.ok(createResponse.asset) + }) + test('returns original response on repeat call with same idempotency key', async (): Promise => { const idempotencyKey = uuid() - const input: CreateAssetInput = { - ...randomAsset(), + assert.ok(createResponse.asset) + const input: UpdateAssetInput = { + id: createResponse.asset.id, + withdrawalThreshold: BigInt(10), idempotencyKey } - const createAssetSpy = jest.spyOn(assetService, 'create') + const updateAssetSpy = jest.spyOn(assetService, 'update') - const initialResponse = await callCreateAssetMutation(input) + const initialResponse = await callUpdateAssetMutation(input) - expect(createAssetSpy).toHaveBeenCalledTimes(1) + expect(updateAssetSpy).toHaveBeenCalledTimes(1) assert.ok(initialResponse.asset) expect(initialResponse).toEqual({ __typename: 'AssetMutationResponse', - message: 'Created Asset', - success: true, - code: '200', asset: { __typename: 'Asset', id: initialResponse.asset.id, - code: input.code, - scale: input.scale, - withdrawalThreshold: null + code: createInput.code, + scale: createInput.scale, + withdrawalThreshold: '10' } }) await expect( assetService.get(initialResponse.asset.id) ).resolves.toMatchObject({ id: initialResponse.asset.id, - code: input.code, - scale: input.scale, - withdrawalThreshold: null + code: createInput.code, + scale: createInput.scale, + withdrawalThreshold: BigInt(10) }) - createAssetSpy.mockClear() + updateAssetSpy.mockClear() - const repeatResponse = await callCreateAssetMutation(input) + const repeatResponse = await callUpdateAssetMutation(input) - expect(createAssetSpy).not.toHaveBeenCalled() + expect(updateAssetSpy).not.toHaveBeenCalled() assert.ok(repeatResponse.asset) expect(repeatResponse).toEqual({ __typename: 'AssetMutationResponse', - message: 'Created Asset', - success: true, - code: '200', asset: { __typename: 'Asset', id: initialResponse.asset.id, code: initialResponse.asset.code, scale: initialResponse.asset.scale, - withdrawalThreshold: null + withdrawalThreshold: '10' } }) await expect( @@ -125,7 +164,7 @@ describe('GraphQL Middleware', (): void => { id: initialResponse.asset.id, code: initialResponse.asset.code, scale: initialResponse.asset.scale, - withdrawalThreshold: null + withdrawalThreshold: BigInt(10) }) }) @@ -143,9 +182,6 @@ describe('GraphQL Middleware', (): void => { assert.ok(initialResponse.asset) expect(initialResponse).toEqual({ __typename: 'AssetMutationResponse', - message: 'Created Asset', - success: true, - code: '200', asset: { __typename: 'Asset', id: initialResponse.asset.id, @@ -157,19 +193,19 @@ describe('GraphQL Middleware', (): void => { createAssetSpy.mockClear() - const repeatResponse = await callCreateAssetMutation({ + const repeatResponse = callCreateAssetMutation({ ...input, idempotencyKey: uuid() }) + await expect(repeatResponse).rejects.toThrow( + new GraphQLError(errorToMessage[AssetError.DuplicateAsset], { + extensions: { + code: errorToCode[AssetError.DuplicateAsset] + } + }) + ) expect(createAssetSpy).toHaveBeenCalledTimes(1) - expect(repeatResponse).toEqual({ - __typename: 'AssetMutationResponse', - message: 'Asset already exists', - success: false, - code: '409', - asset: null - }) }) test('throws if different input parameters for same idempotency key', async (): Promise => { @@ -184,9 +220,6 @@ describe('GraphQL Middleware', (): void => { assert.ok(initialResponse.asset) expect(initialResponse).toEqual({ __typename: 'AssetMutationResponse', - message: 'Created Asset', - success: true, - code: '200', asset: { __typename: 'Asset', id: initialResponse.asset.id, @@ -198,8 +231,8 @@ describe('GraphQL Middleware', (): void => { await expect( callCreateAssetMutation({ - ...input, - scale: (input.scale + 1) % 256 + ...randomAsset(), + idempotencyKey }) ).rejects.toThrow( `Incoming arguments are different than the original request for idempotencyKey: ${idempotencyKey}` @@ -229,9 +262,6 @@ describe('GraphQL Middleware', (): void => { status: 'fulfilled', value: { __typename: 'AssetMutationResponse', - message: 'Created Asset', - success: true, - code: '200', asset: { __typename: 'Asset', id: firstRequest.value?.asset?.id, diff --git a/packages/backend/src/graphql/plugin/index.ts b/packages/backend/src/graphql/plugin/index.ts new file mode 100644 index 0000000000..6ae8358612 --- /dev/null +++ b/packages/backend/src/graphql/plugin/index.ts @@ -0,0 +1,58 @@ +import { + ApolloServerPlugin, + GraphQLRequestContextDidEncounterErrors, + GraphQLRequestContextDidResolveOperation, + GraphQLRequestListener +} from '@apollo/server' +import { Logger } from 'pino' +import { v4 as uuid } from 'uuid' +import { GraphQLErrorCode } from '../errors' + +export class LoggingPlugin implements ApolloServerPlugin { + private logger + + constructor(logger: Logger) { + this.logger = logger + } + + async requestDidStart(): Promise> { + const requestId = uuid() + const logger = this.logger + let operation: string | null + + return { + async didResolveOperation( + context: GraphQLRequestContextDidResolveOperation + ) { + operation = context.operationName + logger.info({ + requestId, + operation + }) + }, + async didEncounterErrors( + context: GraphQLRequestContextDidEncounterErrors + ): Promise { + if (context.errors) { + context.errors.forEach((error) => { + if ( + error.extensions.code === GraphQLErrorCode.InternalServerError + ) { + logger.error({ + requestId, + variables: context.request.variables, + error + }) + } else { + logger.info({ + requestId, + variables: context.request.variables, + error + }) + } + }) + } + } + } + } +} diff --git a/packages/backend/src/graphql/resolvers/asset.test.ts b/packages/backend/src/graphql/resolvers/asset.test.ts index d31f8e9708..99d2f642ed 100644 --- a/packages/backend/src/graphql/resolvers/asset.test.ts +++ b/packages/backend/src/graphql/resolvers/asset.test.ts @@ -1,7 +1,6 @@ -import { gql } from '@apollo/client' +import { ApolloError, gql } from '@apollo/client' import assert from 'assert' import { v4 as uuid } from 'uuid' -import { ApolloError } from '@apollo/client' import { getPageTests } from './page.test' import { createTestApp, TestContainer } from '../../tests/app' @@ -32,6 +31,7 @@ import { Fee, FeeType } from '../../fee/model' import { isFeeError } from '../../fee/errors' import { createFee } from '../../tests/fee' import { createAsset } from '../../tests/asset' +import { GraphQLErrorCode } from '../errors' describe('Asset Resolvers', (): void => { let deps: IocContract @@ -86,9 +86,6 @@ describe('Asset Resolvers', (): void => { mutation: gql` mutation CreateAsset($input: CreateAssetInput!) { createAsset(input: $input) { - code - success - message asset { id code @@ -112,8 +109,6 @@ describe('Asset Resolvers', (): void => { } }) - expect(response.success).toBe(true) - expect(response.code).toEqual('200') assert.ok(response.asset) expect(response.asset).toEqual({ __typename: 'Asset', @@ -137,70 +132,81 @@ describe('Asset Resolvers', (): void => { test('Returns error for duplicate asset', async (): Promise => { const input = randomAsset() await expect(assetService.create(input)).resolves.toMatchObject(input) - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateAsset($input: CreateAssetInput!) { - createAsset(input: $input) { - code - success - message - asset { - id + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateAsset($input: CreateAssetInput!) { + createAsset(input: $input) { + asset { + id + } } } + `, + variables: { + input } - `, - variables: { - input - } - }) - .then((query): AssetMutationResponse => { - if (query.data) { - return query.data.createAsset - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('409') - expect(response.message).toEqual('Asset already exists') + }) + .then((query): AssetMutationResponse => { + if (query.data) { + return query.data.createAsset + } else { + throw new Error('Data was empty') + } + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[AssetError.DuplicateAsset], + extensions: expect.objectContaining({ + code: errorToCode[AssetError.DuplicateAsset] + }) + }) + ) + } }) - test('500', async (): Promise => { + test('handles unexpected error', async (): Promise => { jest .spyOn(assetService, 'create') .mockRejectedValueOnce(new Error('unexpected')) - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateAsset($input: CreateAssetInput!) { - createAsset(input: $input) { - code - success - message - asset { - id + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateAsset($input: CreateAssetInput!) { + createAsset(input: $input) { + asset { + id + } } } + `, + variables: { + input: randomAsset() } - `, - variables: { - input: randomAsset() - } - }) - .then((query): AssetMutationResponse => { - if (query.data) { - return query.data.createAsset - } else { - throw new Error('Data was empty') - } - }) - expect(response.code).toBe('500') - expect(response.success).toBe(false) - expect(response.message).toBe('Error trying to create asset') + }) + .then((query): AssetMutationResponse => { + if (query.data) { + return query.data.createAsset + } else { + throw new Error('Data was empty') + } + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'unexpected', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.InternalServerError + }) + }) + ) + } }) }) @@ -353,28 +359,38 @@ describe('Asset Resolvers', (): void => { }) test('Returns error for unknown asset', async (): Promise => { - const gqlQuery = appContainer.apolloClient - .query({ - query: gql` - query Asset($assetId: String!) { - asset(id: $assetId) { - id + try { + await appContainer.apolloClient + .query({ + query: gql` + query Asset($assetId: String!) { + asset(id: $assetId) { + id + } } + `, + variables: { + assetId: uuid() } - `, - variables: { - assetId: uuid() - } - }) - .then((query): Asset => { - if (query.data) { - return query.data.asset - } else { - throw new Error('Data was empty') - } - }) - - await expect(gqlQuery).rejects.toThrow(ApolloError) + }) + .then((query): Asset => { + if (query.data) { + return query.data.asset + } else { + throw new Error('Data was empty') + } + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[AssetError.UnknownAsset], + extensions: expect.objectContaining({ + code: errorToCode[AssetError.UnknownAsset] + }) + }) + ) + } }) }) @@ -558,9 +574,6 @@ describe('Asset Resolvers', (): void => { mutation: gql` mutation updateAsset($input: UpdateAssetInput!) { updateAsset(input: $input) { - code - success - message asset { id code @@ -587,8 +600,6 @@ describe('Asset Resolvers', (): void => { } }) - expect(response.success).toBe(true) - expect(response.code).toEqual('200') expect(response.asset).toEqual({ __typename: 'Asset', id: asset.id, @@ -613,39 +624,44 @@ describe('Asset Resolvers', (): void => { ) test('Returns error for unknown asset', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation updateAsset($input: UpdateAssetInput!) { - updateAsset(input: $input) { - code - success - message - asset { - id + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation updateAsset($input: UpdateAssetInput!) { + updateAsset(input: $input) { + asset { + id + } } } + `, + variables: { + input: { + id: uuid(), + withdrawalThreshold: BigInt(10), + liquidityThreshold: BigInt(100) + } } - `, - variables: { - input: { - id: uuid(), - withdrawalThreshold: BigInt(10), - liquidityThreshold: BigInt(100) + }) + .then((query): AssetMutationResponse => { + if (query.data) { + return query.data.updateAsset + } else { + throw new Error('Data was empty') } - } - }) - .then((query): AssetMutationResponse => { - if (query.data) { - return query.data.updateAsset - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('404') - expect(response.message).toEqual('Unknown asset') + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[AssetError.UnknownAsset], + extensions: expect.objectContaining({ + code: errorToCode[AssetError.UnknownAsset] + }) + }) + ) + } }) }) @@ -662,9 +678,9 @@ describe('Asset Resolvers', (): void => { mutation: gql` mutation DeleteAsset($input: DeleteAssetInput!) { deleteAsset(input: $input) { - code - success - message + asset { + id + } } } `, @@ -682,43 +698,47 @@ describe('Asset Resolvers', (): void => { } }) - expect(response.success).toBe(true) - expect(response.code).toEqual('200') - expect(response.message).toEqual('Asset deleted') + expect(response.asset?.id).toEqual(asset.id) await expect(assetService.get(asset.id)).resolves.toBeUndefined() }) test('Returns error for unknown asset', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation DeleteAsset($input: DeleteAssetInput!) { - deleteAsset(input: $input) { - code - success - message + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation DeleteAsset($input: DeleteAssetInput!) { + deleteAsset(input: $input) { + asset { + id + } + } + } + `, + variables: { + input: { + id: uuid() } } - `, - variables: { - input: { - id: uuid() + }) + .then((query): AssetMutationResponse => { + if (query.data) { + return query.data.deleteAsset + } else { + throw new Error('Data was empty') } - } - }) - .then((query): AssetMutationResponse => { - if (query.data) { - return query.data.deleteAsset - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual( - errorToCode[AssetError.UnknownAsset].toString() - ) - expect(response.message).toEqual(errorToMessage[AssetError.UnknownAsset]) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[AssetError.UnknownAsset], + extensions: expect.objectContaining({ + code: errorToCode[AssetError.UnknownAsset] + }) + }) + ) + } }) test('Returns error if unexpected error', async (): Promise => { @@ -726,34 +746,42 @@ describe('Asset Resolvers', (): void => { throw new Error('unexpected') }) - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation DeleteAsset($input: DeleteAssetInput!) { - deleteAsset(input: $input) { - code - success - message + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation DeleteAsset($input: DeleteAssetInput!) { + deleteAsset(input: $input) { + asset { + id + } + } + } + `, + variables: { + input: { + id: asset.id } } - `, - variables: { - input: { - id: asset.id + }) + .then((query): AssetMutationResponse => { + if (query.data) { + return query.data.deleteAsset + } else { + throw new Error('Data was empty') } - } - }) - .then((query): AssetMutationResponse => { - if (query.data) { - return query.data.deleteAsset - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('500') - expect(response.message).toEqual('Error trying to delete asset') + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'unexpected', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.InternalServerError + }) + }) + ) + } }) }) }) diff --git a/packages/backend/src/graphql/resolvers/asset.ts b/packages/backend/src/graphql/resolvers/asset.ts index 24075614a0..52a18a2b30 100644 --- a/packages/backend/src/graphql/resolvers/asset.ts +++ b/packages/backend/src/graphql/resolvers/asset.ts @@ -6,17 +6,14 @@ import { AssetResolvers } from '../generated/graphql' import { Asset } from '../../asset/model' -import { - AssetError, - isAssetError, - errorToCode, - errorToMessage -} from '../../asset/errors' +import { errorToCode, errorToMessage, isAssetError } from '../../asset/errors' import { ApolloContext } from '../../app' import { getPageInfo } from '../../shared/pagination' import { Pagination, SortOrder } from '../../shared/baseModel' import { feeToGraphql } from './fee' import { Fee, FeeType } from '../../fee/model' +import { GraphQLError } from 'graphql' +import { GraphQLErrorCode } from '../errors' export const getAssets: QueryResolvers['assets'] = async ( parent, @@ -50,7 +47,11 @@ export const getAsset: QueryResolvers['asset'] = async ( const assetService = await ctx.container.use('assetService') const asset = await assetService.get(args.id) if (!asset) { - throw new Error('No asset') + throw new GraphQLError('Asset not found', { + extensions: { + code: GraphQLErrorCode.NotFound + } + }) } return assetToGraphql(asset) } @@ -61,40 +62,17 @@ export const createAsset: MutationResolvers['createAsset'] = args, ctx ): Promise => { - try { - const assetService = await ctx.container.use('assetService') - const assetOrError = await assetService.create(args.input) - if (isAssetError(assetOrError)) { - switch (assetOrError) { - case AssetError.DuplicateAsset: - return { - code: '409', - message: 'Asset already exists', - success: false - } - default: - throw new Error(`AssetError: ${assetOrError}`) + const assetService = await ctx.container.use('assetService') + const assetOrError = await assetService.create(args.input) + if (isAssetError(assetOrError)) { + throw new GraphQLError(errorToMessage[assetOrError], { + extensions: { + code: errorToCode[assetOrError] } - } - return { - code: '200', - success: true, - message: 'Created Asset', - asset: assetToGraphql(assetOrError) - } - } catch (err) { - ctx.logger.error( - { - options: args.input, - err - }, - 'error creating asset' - ) - return { - code: '500', - message: 'Error trying to create asset', - success: false - } + }) + } + return { + asset: assetToGraphql(assetOrError) } } @@ -104,44 +82,21 @@ export const updateAsset: MutationResolvers['updateAsset'] = args, ctx ): Promise => { - try { - const assetService = await ctx.container.use('assetService') - const assetOrError = await assetService.update({ - id: args.input.id, - withdrawalThreshold: args.input.withdrawalThreshold ?? null, - liquidityThreshold: args.input.liquidityThreshold ?? null - }) - if (isAssetError(assetOrError)) { - switch (assetOrError) { - case AssetError.UnknownAsset: - return { - code: '404', - message: 'Unknown asset', - success: false - } - default: - throw new Error(`AssetError: ${assetOrError}`) + const assetService = await ctx.container.use('assetService') + const assetOrError = await assetService.update({ + id: args.input.id, + withdrawalThreshold: args.input.withdrawalThreshold ?? null, + liquidityThreshold: args.input.liquidityThreshold ?? null + }) + if (isAssetError(assetOrError)) { + throw new GraphQLError(errorToMessage[assetOrError], { + extensions: { + code: errorToCode[assetOrError] } - } - return { - code: '200', - success: true, - message: 'Updated Asset', - asset: assetToGraphql(assetOrError) - } - } catch (err) { - ctx.logger.error( - { - options: args.input, - err - }, - 'error updating asset' - ) - return { - code: '400', - message: 'Error trying to update asset', - success: false - } + }) + } + return { + asset: assetToGraphql(assetOrError) } } @@ -203,38 +158,21 @@ export const deleteAsset: MutationResolvers['deleteAsset'] = args, ctx ): Promise => { - try { - const assetService = await ctx.container.use('assetService') - const assetOrError = await assetService.delete({ - id: args.input.id, - deletedAt: new Date() - }) - - if (isAssetError(assetOrError)) { - return { - code: errorToCode[assetOrError].toString(), - message: errorToMessage[assetOrError], - success: false + const assetService = await ctx.container.use('assetService') + const assetOrError = await assetService.delete({ + id: args.input.id, + deletedAt: new Date() + }) + + if (isAssetError(assetOrError)) { + throw new GraphQLError(errorToMessage[assetOrError], { + extensions: { + code: errorToCode[assetOrError] } - } - return { - code: '200', - success: true, - message: 'Asset deleted' - } - } catch (err) { - ctx.logger.error( - { - id: args.input.id, - err - }, - 'error deleting asset' - ) - return { - code: '500', - message: 'Error trying to delete asset', - success: false - } + }) + } + return { + asset: assetToGraphql(assetOrError) } } diff --git a/packages/backend/src/graphql/resolvers/auto-peering.test.ts b/packages/backend/src/graphql/resolvers/auto-peering.test.ts index 3a073130d3..81c1191981 100644 --- a/packages/backend/src/graphql/resolvers/auto-peering.test.ts +++ b/packages/backend/src/graphql/resolvers/auto-peering.test.ts @@ -1,5 +1,5 @@ import { faker } from '@faker-js/faker' -import { gql } from '@apollo/client' +import { ApolloError, gql } from '@apollo/client' import assert from 'assert' import { createTestApp, TestContainer } from '../../tests/app' @@ -10,16 +10,16 @@ import { initIocContainer } from '../..' import { Config } from '../../config/app' import { truncateTables } from '../../tests/tableManager' import { - errorToCode, errorToMessage, + errorToCode, AutoPeeringError } from '../../payment-method/ilp/auto-peering/errors' import { createAsset } from '../../tests/asset' import { CreateOrUpdatePeerByUrlInput } from '../generated/graphql' import { AutoPeeringService } from '../../payment-method/ilp/auto-peering/service' import { v4 as uuid } from 'uuid' - -const nock = (global as unknown as { nock: typeof import('nock') }).nock +import nock from 'nock' +import { GraphQLErrorCode } from '../errors' describe('Auto Peering Resolvers', (): void => { let deps: IocContract @@ -47,9 +47,6 @@ describe('Auto Peering Resolvers', (): void => { $input: CreateOrUpdatePeerByUrlInput! ) { createOrUpdatePeerByUrl(input: $input) { - code - success - message peer { id asset { @@ -121,8 +118,6 @@ describe('Auto Peering Resolvers', (): void => { const response = await callCreateOrUpdatePeerByUrl(input) - expect(response.success).toBe(true) - expect(response.code).toEqual('200') assert.ok(response.peer) expect(response.peer).toEqual({ __typename: 'Peer', @@ -171,8 +166,6 @@ describe('Auto Peering Resolvers', (): void => { const response = await callCreateOrUpdatePeerByUrl(input) - expect(response.success).toBe(true) - expect(response.code).toEqual('200') assert.ok(response.peer) expect(response.peer).toEqual({ __typename: 'Peer', @@ -205,8 +198,6 @@ describe('Auto Peering Resolvers', (): void => { const secondResponse = await callCreateOrUpdatePeerByUrl(secondInput) - expect(secondResponse.success).toBe(true) - expect(secondResponse.code).toEqual('200') assert.ok(secondResponse.peer) expect(secondResponse.peer).toEqual({ __typename: 'Peer', @@ -244,85 +235,90 @@ describe('Auto Peering Resolvers', (): void => { ${AutoPeeringError.InvalidPeerUrl} ${AutoPeeringError.InvalidPeeringRequest} ${AutoPeeringError.LiquidityError} - `('4XX - $error', async ({ error }): Promise => { + `('Errors with $error', async ({ error: testError }): Promise => { jest .spyOn(autoPeeringService, 'initiatePeeringRequest') - .mockResolvedValueOnce(error) + .mockResolvedValueOnce(testError) const input = createOrUpdatePeerByUrlInput() - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateOrUpdatePeerByUrl( - $input: CreateOrUpdatePeerByUrlInput! - ) { - createOrUpdatePeerByUrl(input: $input) { - code - success - message - peer { - id + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateOrUpdatePeerByUrl( + $input: CreateOrUpdatePeerByUrlInput! + ) { + createOrUpdatePeerByUrl(input: $input) { + peer { + id + } } } + `, + variables: { + input } - `, - variables: { - input - } - }) - .then((query) => { - if (query.data) { - return query.data.createOrUpdatePeerByUrl - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual( - errorToCode[error as AutoPeeringError].toString() - ) - expect(response.message).toEqual( - errorToMessage[error as AutoPeeringError] - ) + }) + .then((query) => { + if (query.data) { + return query.data.createOrUpdatePeerByUrl + } else { + throw new Error('Data was empty') + } + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[testError as AutoPeeringError], + extensions: expect.objectContaining({ + code: errorToCode[testError as AutoPeeringError] + }) + }) + ) + } }) - test('500', async (): Promise => { + test('Internal server error', async (): Promise => { jest .spyOn(autoPeeringService, 'initiatePeeringRequest') - .mockImplementationOnce(async (_args) => { - throw new Error('unexpected') - }) + .mockRejectedValueOnce(new Error('unexpected')) - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateOrUpdatePeerByUrl( - $input: CreateOrUpdatePeerByUrlInput! - ) { - createOrUpdatePeerByUrl(input: $input) { - code - success - message - peer { - id + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateOrUpdatePeerByUrl( + $input: CreateOrUpdatePeerByUrlInput! + ) { + createOrUpdatePeerByUrl(input: $input) { + peer { + id + } } } + `, + variables: { + input: createOrUpdatePeerByUrlInput() } - `, - variables: { - input: createOrUpdatePeerByUrlInput() - } - }) - .then((query) => { - if (query.data) { - return query.data.createOrUpdatePeerByUrl - } else { - throw new Error('Data was empty') - } - }) - expect(response.code).toBe('500') - expect(response.success).toBe(false) - expect(response.message).toBe('Error trying to create peer') + }) + .then((query) => { + if (query.data) { + return query.data.createOrUpdatePeerByUrl + } else { + throw new Error('Data was empty') + } + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'unexpected', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.InternalServerError + }) + }) + ) + } }) }) }) diff --git a/packages/backend/src/graphql/resolvers/auto-peering.ts b/packages/backend/src/graphql/resolvers/auto-peering.ts index 004436be40..ebf6386aa9 100644 --- a/packages/backend/src/graphql/resolvers/auto-peering.ts +++ b/packages/backend/src/graphql/resolvers/auto-peering.ts @@ -8,6 +8,7 @@ import { isAutoPeeringError } from '../../payment-method/ilp/auto-peering/errors' import { peerToGraphql } from './peer' +import { GraphQLError } from 'graphql' export const createOrUpdatePeerByUrl: MutationResolvers['createOrUpdatePeerByUrl'] = async ( @@ -16,34 +17,17 @@ export const createOrUpdatePeerByUrl: MutationResolvers['createOr ctx ): Promise => { const autoPeeringService = await ctx.container.use('autoPeeringService') - return autoPeeringService - .initiatePeeringRequest(args.input) - .then((peerOrError: Peer | AutoPeeringError) => - isAutoPeeringError(peerOrError) - ? { - code: errorToCode[peerOrError].toString(), - success: false, - message: errorToMessage[peerOrError] - } - : { - code: '200', - success: true, - message: 'ILP peer created or updated', - peer: peerToGraphql(peerOrError) - } - ) - .catch((err) => { - ctx.logger.error( - { - options: args.input, - err - }, - 'error creating peer' - ) - return { - code: '500', - success: false, - message: 'Error trying to create peer' + const peerOrError: Peer | AutoPeeringError = + await autoPeeringService.initiatePeeringRequest(args.input) + if (isAutoPeeringError(peerOrError)) { + throw new GraphQLError(errorToMessage[peerOrError], { + extensions: { + code: errorToCode[peerOrError] } }) + } else { + return { + peer: peerToGraphql(peerOrError) + } + } } diff --git a/packages/backend/src/graphql/resolvers/fee.test.ts b/packages/backend/src/graphql/resolvers/fee.test.ts index 99954a97ef..13a14b9c05 100644 --- a/packages/backend/src/graphql/resolvers/fee.test.ts +++ b/packages/backend/src/graphql/resolvers/fee.test.ts @@ -4,13 +4,15 @@ import { initIocContainer } from '../..' import { Config } from '../../config/app' import { createTestApp, TestContainer } from '../../tests/app' import { truncateTables } from '../../tests/tableManager' -import { gql } from '@apollo/client' +import { ApolloError, gql } from '@apollo/client' import { SetFeeResponse } from '../generated/graphql' import { Asset } from '../../asset/model' import { createAsset } from '../../tests/asset' import { FeeType } from '../../fee/model' import { FeeService } from '../../fee/service' import { v4 } from 'uuid' +import { FeeError, errorToMessage, errorToCode } from '../../fee/errors' +import { GraphQLErrorCode } from '../errors' describe('Fee Resolvers', () => { let deps: IocContract @@ -52,9 +54,6 @@ describe('Fee Resolvers', () => { mutation: gql` mutation SetFee($input: SetFeeInput!) { setFee(input: $input) { - code - success - message fee { id assetId @@ -76,9 +75,6 @@ describe('Fee Resolvers', () => { } }) - expect(response.success).toBe(true) - expect(response.code).toEqual('200') - expect(response.message).toEqual('Fee set') expect(response.fee).toMatchObject({ __typename: 'Fee', assetId: input.assetId, @@ -97,39 +93,43 @@ describe('Fee Resolvers', () => { basisPoints: 100 } } - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation SetFee($input: SetFeeInput!) { - setFee(input: $input) { - code - success - message - fee { - id - assetId - type - fixed - basisPoints - createdAt + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation SetFee($input: SetFeeInput!) { + setFee(input: $input) { + fee { + id + assetId + type + fixed + basisPoints + createdAt + } } } + `, + variables: { input } + }) + .then((query): SetFeeResponse => { + if (query.data) { + return query.data.setFee + } else { + throw new Error('Data was empty') } - `, - variables: { input } - }) - .then((query): SetFeeResponse => { - if (query.data) { - return query.data.setFee - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('404') - expect(response.message).toEqual('unknown asset') - expect(response.fee).toBeNull() + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[FeeError.UnknownAsset], + extensions: expect.objectContaining({ + code: errorToCode[FeeError.UnknownAsset] + }) + }) + ) + } }) test('Returns error for invalid percent fee', async (): Promise => { @@ -141,44 +141,46 @@ describe('Fee Resolvers', () => { basisPoints: -10_000 } } - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation SetFee($input: SetFeeInput!) { - setFee(input: $input) { - code - success - message - fee { - id - assetId - type - fixed - basisPoints - createdAt + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation SetFee($input: SetFeeInput!) { + setFee(input: $input) { + fee { + id + assetId + type + fixed + basisPoints + createdAt + } } } + `, + variables: { input } + }) + .then((query): SetFeeResponse => { + if (query.data) { + return query.data.setFee + } else { + throw new Error('Data was empty') } - `, - variables: { input } - }) - .then((query): SetFeeResponse => { - if (query.data) { - return query.data.setFee - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('400') - expect(response.message).toEqual( - 'Basis point fee must be between 0 and 10000' - ) - expect(response.fee).toBeNull() + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[FeeError.InvalidBasisPointFee], + extensions: expect.objectContaining({ + code: errorToCode[FeeError.InvalidBasisPointFee] + }) + }) + ) + } }) - test('Returns 500 error for unhandled errors', async (): Promise => { + test('Returns internal server error for unhandled errors', async (): Promise => { jest.spyOn(feeService, 'create').mockImplementationOnce(async () => { throw new Error('Unknown error') }) @@ -190,39 +192,43 @@ describe('Fee Resolvers', () => { basisPoints: -10_000 } } - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation setFee($input: SetFeeInput!) { - setFee(input: $input) { - code - success - message - fee { - id - assetId - type - fixed - basisPoints - createdAt + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation setFee($input: SetFeeInput!) { + setFee(input: $input) { + fee { + id + assetId + type + fixed + basisPoints + createdAt + } } } + `, + variables: { input } + }) + .then((query): SetFeeResponse => { + if (query.data) { + return query.data.setFee + } else { + throw new Error('Data was empty') } - `, - variables: { input } - }) - .then((query): SetFeeResponse => { - if (query.data) { - return query.data.setFee - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('500') - expect(response.message).toEqual('Error trying to update fee') - expect(response.fee).toBeNull() + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Unknown error', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.InternalServerError + }) + }) + ) + } }) }) }) diff --git a/packages/backend/src/graphql/resolvers/fee.ts b/packages/backend/src/graphql/resolvers/fee.ts index 32d5afad19..71f8fffe93 100644 --- a/packages/backend/src/graphql/resolvers/fee.ts +++ b/packages/backend/src/graphql/resolvers/fee.ts @@ -6,6 +6,7 @@ import { import { ApolloContext } from '../../app' import { isFeeError, errorToCode, errorToMessage } from '../../fee/errors' import { Fee } from '../../fee/model' +import { GraphQLError } from 'graphql' export const setFee: MutationResolvers['setFee'] = async ( parent, @@ -13,35 +14,17 @@ export const setFee: MutationResolvers['setFee'] = async ( ctx ): Promise => { const feeService = await ctx.container.use('feeService') - try { - const feeOrError = await feeService.create(args.input) + const feeOrError = await feeService.create(args.input) - if (isFeeError(feeOrError)) { - return { - code: errorToCode[feeOrError].toString(), - success: false, - message: errorToMessage[feeOrError] + if (isFeeError(feeOrError)) { + throw new GraphQLError(errorToMessage[feeOrError], { + extensions: { + code: errorToCode[feeOrError] } - } - return { - code: '200', - success: true, - message: 'Fee set', - fee: feeToGraphql(feeOrError) - } - } catch (err) { - ctx.logger.error( - { - options: args.input, - err - }, - 'error updating fee' - ) - return { - code: '500', - success: false, - message: 'Error trying to update fee' - } + }) + } + return { + fee: feeToGraphql(feeOrError) } } diff --git a/packages/backend/src/graphql/resolvers/incoming_payment.test.ts b/packages/backend/src/graphql/resolvers/incoming_payment.test.ts index 5f005a1f8d..3278c9d58c 100644 --- a/packages/backend/src/graphql/resolvers/incoming_payment.test.ts +++ b/packages/backend/src/graphql/resolvers/incoming_payment.test.ts @@ -1,4 +1,4 @@ -import { gql } from '@apollo/client' +import { ApolloError, gql } from '@apollo/client' import { getPageTests } from './page.test' import { createTestApp, TestContainer } from '../../tests/app' import { IocContract } from '@adonisjs/fold' @@ -24,9 +24,11 @@ import { } from '../generated/graphql' import { IncomingPaymentError, - errorToMessage + errorToMessage, + errorToCode } from '../../open_payments/payment/incoming/errors' import { Amount, serializeAmount } from '../../open_payments/amount' +import { GraphQLErrorCode } from '../errors' describe('Incoming Payment Resolver', (): void => { let deps: IocContract @@ -100,7 +102,7 @@ describe('Incoming Payment Resolver', (): void => { ${undefined} | ${new Date(Date.now() + 30_000)} | ${false} | ${'expiresAt'} ${undefined} | ${undefined} | ${true} | ${'incomingAmount'} `( - '200 ($desc)', + 'Successfully creates an incoming payment with $desc', async ({ metadata, expiresAt, withAmount }): Promise => { const incomingAmount = withAmount ? amount : undefined const { id: walletAddressId } = await createWalletAddress(deps, { @@ -132,9 +134,6 @@ describe('Incoming Payment Resolver', (): void => { $input: CreateIncomingPaymentInput! ) { createIncomingPayment(input: $input) { - code - success - message payment { id walletAddressId @@ -166,9 +165,6 @@ describe('Incoming Payment Resolver', (): void => { expect(createSpy).toHaveBeenCalledWith(input) expect(query).toEqual({ __typename: 'IncomingPaymentResponse', - code: '200', - success: true, - message: null, payment: { __typename: 'IncomingPayment', id: payment.id, @@ -194,7 +190,7 @@ describe('Incoming Payment Resolver', (): void => { } ) - test('400', async (): Promise => { + test('Errors when unknown wallet address', async (): Promise => { const createSpy = jest .spyOn(incomingPaymentService, 'create') .mockResolvedValueOnce(IncomingPaymentError.UnknownWalletAddress) @@ -203,38 +199,42 @@ describe('Incoming Payment Resolver', (): void => { walletAddressId: uuid() } - const query = await appContainer.apolloClient - .query({ - query: gql` - mutation CreateIncomingPayment( - $input: CreateIncomingPaymentInput! - ) { - createIncomingPayment(input: $input) { - code - success - message - payment { - id - state + try { + await appContainer.apolloClient + .query({ + query: gql` + mutation CreateIncomingPayment( + $input: CreateIncomingPaymentInput! + ) { + createIncomingPayment(input: $input) { + payment { + id + state + } } } - } - `, - variables: { input } - }) - .then( - (query): IncomingPaymentResponse => query.data?.createIncomingPayment + `, + variables: { input } + }) + .then( + (query): IncomingPaymentResponse => + query.data?.createIncomingPayment + ) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[IncomingPaymentError.UnknownWalletAddress], + extensions: expect.objectContaining({ + code: errorToCode[IncomingPaymentError.UnknownWalletAddress] + }) + }) ) - expect(query.code).toBe('404') - expect(query.success).toBe(false) - expect(query.message).toBe( - errorToMessage[IncomingPaymentError.UnknownWalletAddress] - ) - expect(query.payment).toBeNull() - expect(createSpy).toHaveBeenCalledWith(input) + } + await expect(createSpy).toHaveBeenCalledWith(input) }) - test('500', async (): Promise => { + test('Internal server error', async (): Promise => { const createSpy = jest .spyOn(incomingPaymentService, 'create') .mockRejectedValueOnce(new Error('unexpected')) @@ -243,33 +243,39 @@ describe('Incoming Payment Resolver', (): void => { walletAddressId: uuid() } - const query = await appContainer.apolloClient - .query({ - query: gql` - mutation CreateIncomingPayment( - $input: CreateIncomingPaymentInput! - ) { - createIncomingPayment(input: $input) { - code - success - message - payment { - id - state + try { + await appContainer.apolloClient + .query({ + query: gql` + mutation CreateIncomingPayment( + $input: CreateIncomingPaymentInput! + ) { + createIncomingPayment(input: $input) { + payment { + id + state + } } } - } - `, - variables: { input } - }) - .then( - (query): IncomingPaymentResponse => query.data?.createIncomingPayment + `, + variables: { input } + }) + .then( + (query): IncomingPaymentResponse => + query.data?.createIncomingPayment + ) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'unexpected', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.InternalServerError + }) + }) ) - expect(createSpy).toHaveBeenCalledWith(input) - expect(query.code).toBe('500') - expect(query.success).toBe(false) - expect(query.message).toBe('Error trying to create incoming payment') - expect(query.payment).toBeNull() + } + await expect(createSpy).toHaveBeenCalledWith(input) }) }) @@ -304,7 +310,7 @@ describe('Incoming Payment Resolver', (): void => { // Query with each payment state const states: IncomingPaymentState[] = Object.values(IncomingPaymentState) - test.each(states)('200 - %s', async (state): Promise => { + test.each(states)('%s', async (state): Promise => { const expiresAt = new Date() jest .spyOn(incomingPaymentService, 'get') @@ -370,7 +376,7 @@ describe('Incoming Payment Resolver', (): void => { }) }) - test('200 - with added liquidity', async (): Promise => { + test('with added liquidity', async (): Promise => { await accountingService.createDeposit({ id: uuid(), account: payment, @@ -401,13 +407,13 @@ describe('Incoming Payment Resolver', (): void => { }) }) - test('404', async (): Promise => { + test('not found', async (): Promise => { jest .spyOn(incomingPaymentService, 'get') .mockImplementation(async () => undefined) - await expect( - appContainer.apolloClient.query({ + try { + await appContainer.apolloClient.query({ query: gql` query IncomingPayment($paymentId: String!) { incomingPayment(id: $paymentId) { @@ -417,7 +423,17 @@ describe('Incoming Payment Resolver', (): void => { `, variables: { paymentId: uuid() } }) - ).rejects.toThrow('payment does not exist') + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'payment does not exist', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.NotFound + }) + }) + ) + } }) }) }) diff --git a/packages/backend/src/graphql/resolvers/incoming_payment.ts b/packages/backend/src/graphql/resolvers/incoming_payment.ts index 213f6ac375..cde669d166 100644 --- a/packages/backend/src/graphql/resolvers/incoming_payment.ts +++ b/packages/backend/src/graphql/resolvers/incoming_payment.ts @@ -7,7 +7,6 @@ import { } from '../generated/graphql' import { IncomingPayment } from '../../open_payments/payment/incoming/model' import { - IncomingPaymentError, isIncomingPaymentError, errorToCode, errorToMessage @@ -15,6 +14,8 @@ import { import { ApolloContext } from '../../app' import { getPageInfo } from '../../shared/pagination' import { Pagination, SortOrder } from '../../shared/baseModel' +import { GraphQLError } from 'graphql' +import { GraphQLErrorCode } from '../errors' export const getIncomingPayment: QueryResolvers['incomingPayment'] = async (parent, args, ctx): Promise => { @@ -24,7 +25,13 @@ export const getIncomingPayment: QueryResolvers['incomingPayment' const payment = await incomingPaymentService.get({ id: args.id }) - if (!payment) throw new Error('payment does not exist') + if (!payment) { + throw new GraphQLError('payment does not exist', { + extensions: { + code: GraphQLErrorCode.NotFound + } + }) + } return paymentToGraphql(payment) } @@ -34,7 +41,13 @@ export const getWalletAddressIncomingPayments: WalletAddressResolvers => { - if (!parent.id) throw new Error('missing wallet address id') + if (!parent.id) { + throw new GraphQLError('missing wallet address id', { + extensions: { + code: GraphQLErrorCode.BadUserInput + } + }) + } const incomingPaymentService = await ctx.container.use( 'incomingPaymentService' ) @@ -75,33 +88,24 @@ export const createIncomingPayment: MutationResolvers['createInco const incomingPaymentService = await ctx.container.use( 'incomingPaymentService' ) - return incomingPaymentService - .create({ - walletAddressId: args.input.walletAddressId, - expiresAt: !args.input.expiresAt - ? undefined - : new Date(args.input.expiresAt), - incomingAmount: args.input.incomingAmount, - metadata: args.input.metadata + const incomingPaymentOrError = await incomingPaymentService.create({ + walletAddressId: args.input.walletAddressId, + expiresAt: !args.input.expiresAt + ? undefined + : new Date(args.input.expiresAt), + incomingAmount: args.input.incomingAmount, + metadata: args.input.metadata + }) + if (isIncomingPaymentError(incomingPaymentOrError)) { + throw new GraphQLError(errorToMessage[incomingPaymentOrError], { + extensions: { + code: errorToCode[incomingPaymentOrError] + } }) - .then((paymentOrErr: IncomingPayment | IncomingPaymentError) => - isIncomingPaymentError(paymentOrErr) - ? { - code: errorToCode[paymentOrErr].toString(), - success: false, - message: errorToMessage[paymentOrErr] - } - : { - code: '200', - success: true, - payment: paymentToGraphql(paymentOrErr) - } - ) - .catch(() => ({ - code: '500', - success: false, - message: 'Error trying to create incoming payment' - })) + } else + return { + payment: paymentToGraphql(incomingPaymentOrError) + } } export function paymentToGraphql( diff --git a/packages/backend/src/graphql/resolvers/liquidity.test.ts b/packages/backend/src/graphql/resolvers/liquidity.test.ts index 48ba6c2fde..26fdfdca3a 100644 --- a/packages/backend/src/graphql/resolvers/liquidity.test.ts +++ b/packages/backend/src/graphql/resolvers/liquidity.test.ts @@ -1,5 +1,5 @@ import assert from 'assert' -import { gql } from '@apollo/client' +import { ApolloError, gql } from '@apollo/client' import { Knex } from 'knex' import { v4 as uuid } from 'uuid' @@ -40,10 +40,10 @@ import { createPeer } from '../../tests/peer' import { truncateTables } from '../../tests/tableManager' import { WebhookEvent } from '../../webhook/model' import { - LiquidityError, LiquidityMutationResponse, WalletAddressWithdrawalMutationResponse } from '../generated/graphql' +import { GraphQLErrorCode } from '../errors' describe('Liquidity Resolvers', (): void => { let deps: IocContract @@ -73,21 +73,19 @@ describe('Liquidity Resolvers', (): void => { }) test('Can deposit liquidity to peer', async (): Promise => { + const id = uuid() const response = await appContainer.apolloClient .mutate({ mutation: gql` mutation DepositPeerLiquidity($input: DepositPeerLiquidityInput!) { depositPeerLiquidity(input: $input) { - code success - message - error } } `, variables: { input: { - id: uuid(), + id, peerId: peer.id, amount: '100', idempotencyKey: uuid() @@ -103,80 +101,90 @@ describe('Liquidity Resolvers', (): void => { }) expect(response.success).toBe(true) - expect(response.code).toEqual('200') - expect(response.error).toBeNull() }) test('Returns an error for invalid id', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation DepositPeerLiquidity($input: DepositPeerLiquidityInput!) { - depositPeerLiquidity(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation DepositPeerLiquidity( + $input: DepositPeerLiquidityInput! + ) { + depositPeerLiquidity(input: $input) { + success + } + } + `, + variables: { + input: { + id: 'not a uuid v4', + peerId: peer.id, + amount: '100', + idempotencyKey: uuid() } } - `, - variables: { - input: { - id: 'not a uuid v4', - peerId: peer.id, - amount: '100', - idempotencyKey: uuid() + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.depositPeerLiquidity + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.depositPeerLiquidity - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('400') - expect(response.message).toEqual('Invalid id') - expect(response.error).toEqual(LiquidityError.InvalidId) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Invalid transfer id', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.BadUserInput + }) + }) + ) + } }) test('Returns an error for unknown peer', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation DepositPeerLiquidity($input: DepositPeerLiquidityInput!) { - depositPeerLiquidity(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation DepositPeerLiquidity( + $input: DepositPeerLiquidityInput! + ) { + depositPeerLiquidity(input: $input) { + success + } + } + `, + variables: { + input: { + id: uuid(), + peerId: uuid(), + amount: '100', + idempotencyKey: uuid() } } - `, - variables: { - input: { - id: uuid(), - peerId: uuid(), - amount: '100', - idempotencyKey: uuid() + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.depositPeerLiquidity + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.depositPeerLiquidity - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('404') - expect(response.message).toEqual('Unknown peer') - expect(response.error).toEqual(LiquidityError.UnknownPeer) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'unknown peer', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.NotFound + }) + }) + ) + } }) test('Returns an error for existing transfer', async (): Promise => { @@ -188,75 +196,87 @@ describe('Liquidity Resolvers', (): void => { amount: BigInt(100) }) ).resolves.toBeUndefined() - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation DepositPeerLiquidity($input: DepositPeerLiquidityInput!) { - depositPeerLiquidity(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation DepositPeerLiquidity( + $input: DepositPeerLiquidityInput! + ) { + depositPeerLiquidity(input: $input) { + success + } + } + `, + variables: { + input: { + id, + peerId: peer.id, + amount: '100', + idempotencyKey: uuid() } } - `, - variables: { - input: { - id, - peerId: peer.id, - amount: '100', - idempotencyKey: uuid() + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.depositPeerLiquidity + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.depositPeerLiquidity - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('409') - expect(response.message).toEqual('Transfer exists') - expect(response.error).toEqual(LiquidityError.TransferExists) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Transfer already exists', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.Duplicate + }) + }) + ) + } }) test('Returns an error for zero amount', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation DepositPeerLiquidity($input: DepositPeerLiquidityInput!) { - depositPeerLiquidity(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation DepositPeerLiquidity( + $input: DepositPeerLiquidityInput! + ) { + depositPeerLiquidity(input: $input) { + success + } + } + `, + variables: { + input: { + id: 'not a uuid v4', + peerId: peer.id, + amount: '0', + idempotencyKey: uuid() } } - `, - variables: { - input: { - id: 'not a uuid v4', - peerId: peer.id, - amount: '0', - idempotencyKey: uuid() + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.depositPeerLiquidity + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.depositPeerLiquidity - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('400') - expect(response.message).toEqual('Amount is zero') - expect(response.error).toEqual(LiquidityError.AmountZero) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Transfer amount is zero', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.Forbidden + }) + }) + ) + } }) }) @@ -268,6 +288,7 @@ describe('Liquidity Resolvers', (): void => { }) test('Can deposit liquidity to asset', async (): Promise => { + const id = uuid() const response = await appContainer.apolloClient .mutate({ mutation: gql` @@ -275,16 +296,13 @@ describe('Liquidity Resolvers', (): void => { $input: DepositAssetLiquidityInput! ) { depositAssetLiquidity(input: $input) { - code success - message - error } } `, variables: { input: { - id: uuid(), + id, assetId: asset.id, amount: '100', idempotencyKey: uuid() @@ -300,84 +318,90 @@ describe('Liquidity Resolvers', (): void => { }) expect(response.success).toBe(true) - expect(response.code).toEqual('200') - expect(response.error).toBeNull() }) test('Returns an error for invalid id', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation DepositAssetLiquidity( - $input: DepositAssetLiquidityInput! - ) { - depositAssetLiquidity(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation DepositAssetLiquidity( + $input: DepositAssetLiquidityInput! + ) { + depositAssetLiquidity(input: $input) { + success + } + } + `, + variables: { + input: { + id: 'not a uuid', + assetId: asset.id, + amount: '100', + idempotencyKey: uuid() } } - `, - variables: { - input: { - id: 'not a uuid', - assetId: asset.id, - amount: '100', - idempotencyKey: uuid() + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.depositAssetLiquidity + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.depositAssetLiquidity - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('400') - expect(response.message).toEqual('Invalid id') - expect(response.error).toEqual(LiquidityError.InvalidId) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Invalid transfer id', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.BadUserInput + }) + }) + ) + } }) test('Returns an error for unknown asset', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation DepositAssetLiquidity( - $input: DepositAssetLiquidityInput! - ) { - depositAssetLiquidity(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation DepositAssetLiquidity( + $input: DepositAssetLiquidityInput! + ) { + depositAssetLiquidity(input: $input) { + success + } + } + `, + variables: { + input: { + id: uuid(), + assetId: uuid(), + amount: '100', + idempotencyKey: uuid() } } - `, - variables: { - input: { - id: uuid(), - assetId: uuid(), - amount: '100', - idempotencyKey: uuid() + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.depositAssetLiquidity + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.depositAssetLiquidity - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('404') - expect(response.message).toEqual('Unknown asset') - expect(response.error).toEqual(LiquidityError.UnknownAsset) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Unknown asset', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.NotFound + }) + }) + ) + } }) test('Returns an error for existing transfer', async (): Promise => { @@ -389,79 +413,87 @@ describe('Liquidity Resolvers', (): void => { amount: BigInt(100) }) ).resolves.toBeUndefined() - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation DepositAssetLiquidity( - $input: DepositAssetLiquidityInput! - ) { - depositAssetLiquidity(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation DepositAssetLiquidity( + $input: DepositAssetLiquidityInput! + ) { + depositAssetLiquidity(input: $input) { + success + } + } + `, + variables: { + input: { + id, + assetId: asset.id, + amount: '100', + idempotencyKey: uuid() } } - `, - variables: { - input: { - id, - assetId: asset.id, - amount: '100', - idempotencyKey: uuid() + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.depositAssetLiquidity + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.depositAssetLiquidity - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('409') - expect(response.message).toEqual('Transfer exists') - expect(response.error).toEqual(LiquidityError.TransferExists) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Transfer already exists', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.Duplicate + }) + }) + ) + } }) test('Returns an error for zero amount', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation DepositAssetLiquidity( - $input: DepositAssetLiquidityInput! - ) { - depositAssetLiquidity(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation DepositAssetLiquidity( + $input: DepositAssetLiquidityInput! + ) { + depositAssetLiquidity(input: $input) { + success + } + } + `, + variables: { + input: { + id: uuid(), + assetId: asset.id, + amount: '0', + idempotencyKey: uuid() } } - `, - variables: { - input: { - id: uuid(), - assetId: asset.id, - amount: '0', - idempotencyKey: uuid() + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.depositAssetLiquidity + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.depositAssetLiquidity - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('400') - expect(response.message).toEqual('Amount is zero') - expect(response.error).toEqual(LiquidityError.AmountZero) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Transfer amount is zero', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.Forbidden + }) + }) + ) + } }) }) @@ -481,6 +513,7 @@ describe('Liquidity Resolvers', (): void => { }) test('Can create liquidity withdrawal from peer', async (): Promise => { + const id = uuid() const response = await appContainer.apolloClient .mutate({ mutation: gql` @@ -488,16 +521,13 @@ describe('Liquidity Resolvers', (): void => { $input: CreatePeerLiquidityWithdrawalInput! ) { createPeerLiquidityWithdrawal(input: $input) { - code success - message - error } } `, variables: { input: { - id: uuid(), + id, peerId: peer.id, amount: startingBalance.toString(), idempotencyKey: uuid(), @@ -514,86 +544,92 @@ describe('Liquidity Resolvers', (): void => { }) expect(response.success).toBe(true) - expect(response.code).toEqual('200') - expect(response.error).toBeNull() }) test('Returns an error for unknown peer', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreatePeerLiquidityWithdrawal( - $input: CreatePeerLiquidityWithdrawalInput! - ) { - createPeerLiquidityWithdrawal(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreatePeerLiquidityWithdrawal( + $input: CreatePeerLiquidityWithdrawalInput! + ) { + createPeerLiquidityWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + id: uuid(), + peerId: uuid(), + amount: '100', + idempotencyKey: uuid(), + timeoutSeconds: 0 } } - `, - variables: { - input: { - id: uuid(), - peerId: uuid(), - amount: '100', - idempotencyKey: uuid(), - timeoutSeconds: 0 + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.createPeerLiquidityWithdrawal + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.createPeerLiquidityWithdrawal - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('404') - expect(response.message).toEqual('Unknown peer') - expect(response.error).toEqual(LiquidityError.UnknownPeer) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Unknown peer', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.NotFound + }) + }) + ) + } }) test('Returns an error for invalid id', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreatePeerLiquidityWithdrawal( - $input: CreatePeerLiquidityWithdrawalInput! - ) { - createPeerLiquidityWithdrawal(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreatePeerLiquidityWithdrawal( + $input: CreatePeerLiquidityWithdrawalInput! + ) { + createPeerLiquidityWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + id: 'not a uuid', + peerId: peer.id, + amount: startingBalance.toString(), + idempotencyKey: uuid(), + timeoutSeconds: 0 } } - `, - variables: { - input: { - id: 'not a uuid', - peerId: peer.id, - amount: startingBalance.toString(), - idempotencyKey: uuid(), - timeoutSeconds: 0 + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.createPeerLiquidityWithdrawal + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.createPeerLiquidityWithdrawal - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('400') - expect(response.message).toEqual('Invalid id') - expect(response.error).toEqual(LiquidityError.InvalidId) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Invalid transfer id', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.BadUserInput + }) + }) + ) + } }) test('Returns an error for existing transfer', async (): Promise => { @@ -605,69 +641,23 @@ describe('Liquidity Resolvers', (): void => { amount: 10n }) ).resolves.toBeUndefined() - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreatePeerLiquidityWithdrawal( - $input: CreatePeerLiquidityWithdrawalInput! - ) { - createPeerLiquidityWithdrawal(input: $input) { - code - success - message - error - } - } - `, - variables: { - input: { - id, - peerId: peer.id, - amount: startingBalance.toString(), - idempotencyKey: uuid(), - timeoutSeconds: 0 - } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.createPeerLiquidityWithdrawal - } else { - throw new Error('Data was empty') - } - }) - expect(response.success).toBe(false) - expect(response.code).toEqual('409') - expect(response.message).toEqual('Transfer exists') - expect(response.error).toEqual(LiquidityError.TransferExists) - }) - - test.each` - amount | code | message | error - ${startingBalance + BigInt(1)} | ${'403'} | ${'Insufficient balance'} | ${LiquidityError.InsufficientBalance} - ${BigInt(0)} | ${'400'} | ${'Amount is zero'} | ${LiquidityError.AmountZero} - `( - 'Returns error for $error', - async ({ amount, code, message, error }): Promise => { - const response = await appContainer.apolloClient + try { + await appContainer.apolloClient .mutate({ mutation: gql` mutation CreatePeerLiquidityWithdrawal( $input: CreatePeerLiquidityWithdrawalInput! ) { createPeerLiquidityWithdrawal(input: $input) { - code success - message - error } } `, variables: { input: { - id: uuid(), + id, peerId: peer.id, - amount: amount.toString(), + amount: startingBalance.toString(), idempotencyKey: uuid(), timeoutSeconds: 0 } @@ -680,24 +670,79 @@ describe('Liquidity Resolvers', (): void => { throw new Error('Data was empty') } }) - - expect(response.success).toBe(false) - expect(response.code).toEqual(code) - expect(response.message).toEqual(message) - expect(response.error).toEqual(error) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Transfer already exists', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.Duplicate + }) + }) + ) } - ) - }) - - describe('Create asset liquidity withdrawal', (): void => { - let asset: Asset - const startingBalance = BigInt(100) + }) - beforeEach(async (): Promise => { - asset = await createAsset(deps) - await expect( - accountingService.createDeposit({ - id: uuid(), + test.each` + amount | message | code + ${startingBalance + BigInt(1)} | ${'Insufficient transfer balance'} | ${GraphQLErrorCode.Forbidden} + ${BigInt(0)} | ${'Transfer amount is zero'} | ${GraphQLErrorCode.Forbidden} + `( + 'Returns error for $code', + async ({ amount, message, code }): Promise => { + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreatePeerLiquidityWithdrawal( + $input: CreatePeerLiquidityWithdrawalInput! + ) { + createPeerLiquidityWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + id: uuid(), + peerId: peer.id, + amount: amount.toString(), + idempotencyKey: uuid(), + timeoutSeconds: 0 + } + } + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.createPeerLiquidityWithdrawal + } else { + throw new Error('Data was empty') + } + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message, + extensions: expect.objectContaining({ + code + }) + }) + ) + } + } + ) + }) + + describe('Create asset liquidity withdrawal', (): void => { + let asset: Asset + const startingBalance = BigInt(100) + + beforeEach(async (): Promise => { + asset = await createAsset(deps) + await expect( + accountingService.createDeposit({ + id: uuid(), account: asset, amount: startingBalance }) @@ -705,6 +750,7 @@ describe('Liquidity Resolvers', (): void => { }) test('Can create liquidity withdrawal from asset', async (): Promise => { + const id = uuid() const response = await appContainer.apolloClient .mutate({ mutation: gql` @@ -712,16 +758,13 @@ describe('Liquidity Resolvers', (): void => { $input: CreateAssetLiquidityWithdrawalInput! ) { createAssetLiquidityWithdrawal(input: $input) { - code success - message - error } } `, variables: { input: { - id: uuid(), + id, assetId: asset.id, amount: startingBalance.toString(), idempotencyKey: uuid(), @@ -738,86 +781,92 @@ describe('Liquidity Resolvers', (): void => { }) expect(response.success).toBe(true) - expect(response.code).toEqual('200') - expect(response.error).toBeNull() }) test('Returns an error for unknown asset', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateAssetLiquidityWithdrawal( - $input: CreateAssetLiquidityWithdrawalInput! - ) { - createAssetLiquidityWithdrawal(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateAssetLiquidityWithdrawal( + $input: CreateAssetLiquidityWithdrawalInput! + ) { + createAssetLiquidityWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + id: uuid(), + assetId: uuid(), + amount: '100', + idempotencyKey: uuid(), + timeoutSeconds: 0 } } - `, - variables: { - input: { - id: uuid(), - assetId: uuid(), - amount: '100', - idempotencyKey: uuid(), - timeoutSeconds: 0 + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.createAssetLiquidityWithdrawal + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.createAssetLiquidityWithdrawal - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('404') - expect(response.message).toEqual('Unknown asset') - expect(response.error).toEqual(LiquidityError.UnknownAsset) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Unknown asset', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.NotFound + }) + }) + ) + } }) test('Returns an error for invalid id', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateAssetLiquidityWithdrawal( - $input: CreateAssetLiquidityWithdrawalInput! - ) { - createAssetLiquidityWithdrawal(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateAssetLiquidityWithdrawal( + $input: CreateAssetLiquidityWithdrawalInput! + ) { + createAssetLiquidityWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + id: 'not a uuid', + assetId: asset.id, + amount: startingBalance.toString(), + idempotencyKey: uuid(), + timeoutSeconds: 0 } } - `, - variables: { - input: { - id: 'not a uuid', - assetId: asset.id, - amount: startingBalance.toString(), - idempotencyKey: uuid(), - timeoutSeconds: 0 + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.createAssetLiquidityWithdrawal + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.createAssetLiquidityWithdrawal - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('400') - expect(response.message).toEqual('Invalid id') - expect(response.error).toEqual(LiquidityError.InvalidId) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Invalid transfer id', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.BadUserInput + }) + }) + ) + } }) test('Returns an error for existing transfer', async (): Promise => { @@ -829,69 +878,23 @@ describe('Liquidity Resolvers', (): void => { amount: BigInt(10) }) ).resolves.toBeUndefined() - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateAssetLiquidityWithdrawal( - $input: CreateAssetLiquidityWithdrawalInput! - ) { - createAssetLiquidityWithdrawal(input: $input) { - code - success - message - error - } - } - `, - variables: { - input: { - id, - assetId: asset.id, - amount: startingBalance.toString(), - idempotencyKey: uuid(), - timeoutSeconds: 0 - } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.createAssetLiquidityWithdrawal - } else { - throw new Error('Data was empty') - } - }) - expect(response.success).toBe(false) - expect(response.code).toEqual('409') - expect(response.message).toEqual('Transfer exists') - expect(response.error).toEqual(LiquidityError.TransferExists) - }) - - test.each` - amount | code | message | error - ${startingBalance + BigInt(1)} | ${'403'} | ${'Insufficient balance'} | ${LiquidityError.InsufficientBalance} - ${BigInt(0)} | ${'400'} | ${'Amount is zero'} | ${LiquidityError.AmountZero} - `( - 'Returns error for $error', - async ({ amount, code, message, error }): Promise => { - const response = await appContainer.apolloClient + try { + await appContainer.apolloClient .mutate({ mutation: gql` mutation CreateAssetLiquidityWithdrawal( $input: CreateAssetLiquidityWithdrawalInput! ) { createAssetLiquidityWithdrawal(input: $input) { - code success - message - error } } `, variables: { input: { - id: uuid(), + id, assetId: asset.id, - amount: amount.toString(), + amount: startingBalance.toString(), idempotencyKey: uuid(), timeoutSeconds: 0 } @@ -904,11 +907,66 @@ describe('Liquidity Resolvers', (): void => { throw new Error('Data was empty') } }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Transfer already exists', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.Duplicate + }) + }) + ) + } + }) - expect(response.success).toBe(false) - expect(response.code).toEqual(code) - expect(response.message).toEqual(message) - expect(response.error).toEqual(error) + test.each` + amount | message | code + ${startingBalance + BigInt(1)} | ${'Insufficient transfer balance'} | ${GraphQLErrorCode.Forbidden} + ${BigInt(0)} | ${'Transfer amount is zero'} | ${GraphQLErrorCode.Forbidden} + `( + 'Returns error for $error', + async ({ amount, code, message }): Promise => { + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateAssetLiquidityWithdrawal( + $input: CreateAssetLiquidityWithdrawalInput! + ) { + createAssetLiquidityWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + id: uuid(), + assetId: asset.id, + amount: amount.toString(), + idempotencyKey: uuid(), + timeoutSeconds: 0 + } + } + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.createAssetLiquidityWithdrawal + } else { + throw new Error('Data was empty') + } + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message, + extensions: expect.objectContaining({ + code + }) + }) + ) + } } ) }) @@ -940,10 +998,6 @@ describe('Liquidity Resolvers', (): void => { $input: CreateWalletAddressWithdrawalInput! ) { createWalletAddressWithdrawal(input: $input) { - code - success - message - error withdrawal { id amount @@ -971,9 +1025,6 @@ describe('Liquidity Resolvers', (): void => { } }) - expect(response.success).toBe(true) - expect(response.code).toEqual('200') - expect(response.error).toBeNull() expect(response.withdrawal).toMatchObject({ id, amount: amount.toString(), @@ -984,87 +1035,91 @@ describe('Liquidity Resolvers', (): void => { }) test('Returns an error for unknown wallet address', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateWalletAddressWithdrawal( - $input: CreateWalletAddressWithdrawalInput! - ) { - createWalletAddressWithdrawal(input: $input) { - code - success - message - error - withdrawal { - id + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateWalletAddressWithdrawal( + $input: CreateWalletAddressWithdrawalInput! + ) { + createWalletAddressWithdrawal(input: $input) { + withdrawal { + id + } } } + `, + variables: { + input: { + id: uuid(), + walletAddressId: uuid(), + idempotencyKey: uuid(), + timeoutSeconds: 0 + } } - `, - variables: { - input: { - id: uuid(), - walletAddressId: uuid(), - idempotencyKey: uuid(), - timeoutSeconds: 0 + }) + .then((query): WalletAddressWithdrawalMutationResponse => { + if (query.data) { + return query.data.createWalletAddressWithdrawal + } else { + throw new Error('Data was empty') } - } - }) - .then((query): WalletAddressWithdrawalMutationResponse => { - if (query.data) { - return query.data.createWalletAddressWithdrawal - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('404') - expect(response.message).toEqual('Unknown wallet address') - expect(response.error).toEqual(LiquidityError.UnknownWalletAddress) - expect(response.withdrawal).toBeNull() - }) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Unknown wallet address', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.NotFound + }) + }) + ) + } + }) test('Returns an error for invalid id', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateWalletAddressWithdrawal( - $input: CreateWalletAddressWithdrawalInput! - ) { - createWalletAddressWithdrawal(input: $input) { - code - success - message - error - withdrawal { - id + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateWalletAddressWithdrawal( + $input: CreateWalletAddressWithdrawalInput! + ) { + createWalletAddressWithdrawal(input: $input) { + withdrawal { + id + } } } + `, + variables: { + input: { + id: 'not a uuid', + walletAddressId: walletAddress.id, + idempotencyKey: uuid(), + timeoutSeconds: 0 + } } - `, - variables: { - input: { - id: 'not a uuid', - walletAddressId: walletAddress.id, - idempotencyKey: uuid(), - timeoutSeconds: 0 + }) + .then((query): WalletAddressWithdrawalMutationResponse => { + if (query.data) { + return query.data.createWalletAddressWithdrawal + } else { + throw new Error('Data was empty') } - } - }) - .then((query): WalletAddressWithdrawalMutationResponse => { - if (query.data) { - return query.data.createWalletAddressWithdrawal - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('400') - expect(response.message).toEqual('Invalid id') - expect(response.error).toEqual(LiquidityError.InvalidId) - expect(response.withdrawal).toBeNull() + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Invalid transfer id', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.BadUserInput + }) + }) + ) + } }) test('Returns an error for existing transfer', async (): Promise => { @@ -1076,44 +1131,47 @@ describe('Liquidity Resolvers', (): void => { amount: BigInt(10) }) ).resolves.toBeUndefined() - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateWalletAddressWithdrawal( - $input: CreateWalletAddressWithdrawalInput! - ) { - createWalletAddressWithdrawal(input: $input) { - code - success - message - error - withdrawal { - id + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateWalletAddressWithdrawal( + $input: CreateWalletAddressWithdrawalInput! + ) { + createWalletAddressWithdrawal(input: $input) { + withdrawal { + id + } } } + `, + variables: { + input: { + id, + walletAddressId: walletAddress.id, + idempotencyKey: uuid(), + timeoutSeconds: 0 + } } - `, - variables: { - input: { - id, - walletAddressId: walletAddress.id, - idempotencyKey: uuid(), - timeoutSeconds: 0 + }) + .then((query): WalletAddressWithdrawalMutationResponse => { + if (query.data) { + return query.data.createWalletAddressWithdrawal + } else { + throw new Error('Data was empty') } - } - }) - .then((query): WalletAddressWithdrawalMutationResponse => { - if (query.data) { - return query.data.createWalletAddressWithdrawal - } else { - throw new Error('Data was empty') - } - }) - expect(response.success).toBe(false) - expect(response.code).toEqual('409') - expect(response.message).toEqual('Transfer exists') - expect(response.error).toEqual(LiquidityError.TransferExists) - expect(response.withdrawal).toBeNull() + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Transfer already exists', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.Duplicate + }) + }) + ) + } }) test('Returns an error for empty balance', async (): Promise => { @@ -1125,44 +1183,47 @@ describe('Liquidity Resolvers', (): void => { timeout: 0 }) ).resolves.toBeUndefined() - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateWalletAddressWithdrawal( - $input: CreateWalletAddressWithdrawalInput! - ) { - createWalletAddressWithdrawal(input: $input) { - code - success - message - error - withdrawal { - id + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateWalletAddressWithdrawal( + $input: CreateWalletAddressWithdrawalInput! + ) { + createWalletAddressWithdrawal(input: $input) { + withdrawal { + id + } } } + `, + variables: { + input: { + id: uuid(), + walletAddressId: walletAddress.id, + idempotencyKey: uuid(), + timeoutSeconds: 0 + } } - `, - variables: { - input: { - id: uuid(), - walletAddressId: walletAddress.id, - idempotencyKey: uuid(), - timeoutSeconds: 0 + }) + .then((query): WalletAddressWithdrawalMutationResponse => { + if (query.data) { + return query.data.createWalletAddressWithdrawal + } else { + throw new Error('Data was empty') } - } - }) - .then((query): WalletAddressWithdrawalMutationResponse => { - if (query.data) { - return query.data.createWalletAddressWithdrawal - } else { - throw new Error('Data was empty') - } - }) - expect(response.success).toBe(false) - expect(response.code).toEqual('400') - expect(response.message).toEqual('Amount is zero') - expect(response.error).toEqual(LiquidityError.AmountZero) - expect(response.withdrawal).toBeNull() + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Transfer amount is zero', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.Forbidden + }) + }) + ) + } }) }) @@ -1200,10 +1261,7 @@ describe('Liquidity Resolvers', (): void => { $input: PostLiquidityWithdrawalInput! ) { postLiquidityWithdrawal(input: $input) { - code success - message - error } } `, @@ -1223,158 +1281,172 @@ describe('Liquidity Resolvers', (): void => { }) expect(response.success).toBe(true) - expect(response.code).toEqual('200') - expect(response.error).toBeNull() }) test("Can't post non-existent withdrawal", async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation PostLiquidityWithdrawal( - $input: PostLiquidityWithdrawalInput! - ) { - postLiquidityWithdrawal(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation PostLiquidityWithdrawal( + $input: PostLiquidityWithdrawalInput! + ) { + postLiquidityWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + withdrawalId: uuid(), + idempotencyKey: uuid() } } - `, - variables: { - input: { - withdrawalId: uuid(), - idempotencyKey: uuid() + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.postLiquidityWithdrawal + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.postLiquidityWithdrawal - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('404') - expect(response.message).toEqual('Unknown withdrawal') - expect(response.error).toEqual(LiquidityError.UnknownTransfer) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Unknown transfer', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.NotFound + }) + }) + ) + } }) test("Can't post invalid withdrawal id", async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation PostLiquidityWithdrawal( - $input: PostLiquidityWithdrawalInput! - ) { - postLiquidityWithdrawal(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation PostLiquidityWithdrawal( + $input: PostLiquidityWithdrawalInput! + ) { + postLiquidityWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + withdrawalId: 'not a uuid', + idempotencyKey: uuid() } } - `, - variables: { - input: { - withdrawalId: 'not a uuid', - idempotencyKey: uuid() + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.postLiquidityWithdrawal + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.postLiquidityWithdrawal - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('400') - expect(response.message).toEqual('Invalid id') - expect(response.error).toEqual(LiquidityError.InvalidId) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Invalid transfer id', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.BadUserInput + }) + }) + ) + } }) test("Can't post posted withdrawal", async (): Promise => { await expect( accountingService.postWithdrawal(withdrawalId) ).resolves.toBeUndefined() - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation PostLiquidityWithdrawal( - $input: PostLiquidityWithdrawalInput! - ) { - postLiquidityWithdrawal(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation PostLiquidityWithdrawal( + $input: PostLiquidityWithdrawalInput! + ) { + postLiquidityWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + withdrawalId, + idempotencyKey: uuid() } } - `, - variables: { - input: { - withdrawalId, - idempotencyKey: uuid() + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.postLiquidityWithdrawal + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.postLiquidityWithdrawal - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('409') - expect(response.message).toEqual('Withdrawal already posted') - expect(response.error).toEqual(LiquidityError.AlreadyPosted) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Transfer already posted', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.Conflict + }) + }) + ) + } }) test("Can't post voided withdrawal", async (): Promise => { await expect( accountingService.voidWithdrawal(withdrawalId) ).resolves.toBeUndefined() - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation PostLiquidityWithdrawal( - $input: PostLiquidityWithdrawalInput! - ) { - postLiquidityWithdrawal(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation PostLiquidityWithdrawal( + $input: PostLiquidityWithdrawalInput! + ) { + postLiquidityWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + withdrawalId, + idempotencyKey: uuid() } } - `, - variables: { - input: { - withdrawalId, - idempotencyKey: uuid() + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.postLiquidityWithdrawal + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.postLiquidityWithdrawal - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('409') - expect(response.message).toEqual('Withdrawal already voided') - expect(response.error).toEqual(LiquidityError.AlreadyVoided) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Transfer already voided', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.Conflict + }) + }) + ) + } }) } ) @@ -1398,174 +1470,22 @@ describe('Liquidity Resolvers', (): void => { await expect( accountingService.createWithdrawal({ ...deposit, - id: withdrawalId, - amount: BigInt(10), - timeout: timeoutTwoPhase - }) - ).resolves.toBeUndefined() - }) - - test(`Can void a(n) ${type} liquidity withdrawal`, async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation VoidLiquidityWithdrawal( - $input: VoidLiquidityWithdrawalInput! - ) { - voidLiquidityWithdrawal(input: $input) { - code - success - message - error - } - } - `, - variables: { - input: { - withdrawalId, - idempotencyKey: uuid() - } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.voidLiquidityWithdrawal - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(true) - expect(response.code).toEqual('200') - expect(response.error).toBeNull() - }) - - test("Can't void non-existent withdrawal", async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation VoidLiquidityWithdrawal( - $input: VoidLiquidityWithdrawalInput! - ) { - voidLiquidityWithdrawal(input: $input) { - code - success - message - error - } - } - `, - variables: { - input: { - withdrawalId: uuid(), - idempotencyKey: uuid() - } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.voidLiquidityWithdrawal - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('404') - expect(response.message).toEqual('Unknown withdrawal') - expect(response.error).toEqual(LiquidityError.UnknownTransfer) - }) - - test("Can't void invalid withdrawal id", async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation VoidLiquidityWithdrawal( - $input: VoidLiquidityWithdrawalInput! - ) { - voidLiquidityWithdrawal(input: $input) { - code - success - message - error - } - } - `, - variables: { - input: { - withdrawalId: 'not a uuid', - idempotencyKey: uuid() - } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.voidLiquidityWithdrawal - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('400') - expect(response.message).toEqual('Invalid id') - expect(response.error).toEqual(LiquidityError.InvalidId) - }) - - test("Can't void posted withdrawal", async (): Promise => { - await expect( - accountingService.postWithdrawal(withdrawalId) - ).resolves.toBeUndefined() - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation VoidLiquidityWithdrawal( - $input: VoidLiquidityWithdrawalInput! - ) { - voidLiquidityWithdrawal(input: $input) { - code - success - message - error - } - } - `, - variables: { - input: { - withdrawalId, - idempotencyKey: uuid() - } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.voidLiquidityWithdrawal - } else { - throw new Error('Data was empty') - } + id: withdrawalId, + amount: BigInt(10), + timeout: timeoutTwoPhase }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('409') - expect(response.message).toEqual('Withdrawal already posted') - expect(response.error).toEqual(LiquidityError.AlreadyPosted) + ).resolves.toBeUndefined() }) - test("Can't void voided withdrawal", async (): Promise => { - await expect( - accountingService.voidWithdrawal(withdrawalId) - ).resolves.toBeUndefined() + test(`Can void a(n) ${type} liquidity withdrawal`, async (): Promise => { const response = await appContainer.apolloClient .mutate({ mutation: gql` - mutation voidLiquidityWithdrawal( + mutation VoidLiquidityWithdrawal( $input: VoidLiquidityWithdrawalInput! ) { voidLiquidityWithdrawal(input: $input) { - code success - message - error } } `, @@ -1584,10 +1504,173 @@ describe('Liquidity Resolvers', (): void => { } }) - expect(response.success).toBe(false) - expect(response.code).toEqual('409') - expect(response.message).toEqual('Withdrawal already voided') - expect(response.error).toEqual(LiquidityError.AlreadyVoided) + expect(response.success).toBe(true) + }) + + test("Can't void non-existent withdrawal", async (): Promise => { + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation VoidLiquidityWithdrawal( + $input: VoidLiquidityWithdrawalInput! + ) { + voidLiquidityWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + withdrawalId: uuid(), + idempotencyKey: uuid() + } + } + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.voidLiquidityWithdrawal + } else { + throw new Error('Data was empty') + } + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Unknown transfer', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.NotFound + }) + }) + ) + } + }) + + test("Can't void invalid withdrawal id", async (): Promise => { + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation VoidLiquidityWithdrawal( + $input: VoidLiquidityWithdrawalInput! + ) { + voidLiquidityWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + withdrawalId: 'not a uuid', + idempotencyKey: uuid() + } + } + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.voidLiquidityWithdrawal + } else { + throw new Error('Data was empty') + } + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Invalid transfer id', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.BadUserInput + }) + }) + ) + } + }) + + test("Can't void posted withdrawal", async (): Promise => { + await expect( + accountingService.postWithdrawal(withdrawalId) + ).resolves.toBeUndefined() + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation VoidLiquidityWithdrawal( + $input: VoidLiquidityWithdrawalInput! + ) { + voidLiquidityWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + withdrawalId, + idempotencyKey: uuid() + } + } + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.voidLiquidityWithdrawal + } else { + throw new Error('Data was empty') + } + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Transfer already posted', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.Conflict + }) + }) + ) + } + }) + + test("Can't void voided withdrawal", async (): Promise => { + await expect( + accountingService.voidWithdrawal(withdrawalId) + ).resolves.toBeUndefined() + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation voidLiquidityWithdrawal( + $input: VoidLiquidityWithdrawalInput! + ) { + voidLiquidityWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + withdrawalId, + idempotencyKey: uuid() + } + } + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.voidLiquidityWithdrawal + } else { + throw new Error('Data was empty') + } + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Transfer already voided', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.Conflict + }) + }) + ) + } }) } ) @@ -1653,10 +1736,7 @@ describe('Liquidity Resolvers', (): void => { $input: DepositEventLiquidityInput! ) { depositEventLiquidity(input: $input) { - code success - message - error } } `, @@ -1676,8 +1756,6 @@ describe('Liquidity Resolvers', (): void => { }) expect(response.success).toBe(true) - expect(response.code).toEqual('200') - expect(response.error).toBeNull() assert.ok(payment.debitAmount) await expect(depositSpy).toHaveBeenCalledWith({ id: eventId, @@ -1690,39 +1768,43 @@ describe('Liquidity Resolvers', (): void => { }) test("Can't deposit for non-existent webhook event id", async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation DepositLiquidity( - $input: DepositEventLiquidityInput! - ) { - depositEventLiquidity(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation DepositLiquidity( + $input: DepositEventLiquidityInput! + ) { + depositEventLiquidity(input: $input) { + success + } + } + `, + variables: { + input: { + eventId: uuid(), + idempotencyKey: uuid() } } - `, - variables: { - input: { - eventId: uuid(), - idempotencyKey: uuid() + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.depositEventLiquidity + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.depositEventLiquidity - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('400') - expect(response.message).toEqual('Invalid id') - expect(response.error).toEqual(LiquidityError.InvalidId) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Invalid transfer id', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.BadUserInput + }) + }) + ) + } }) test('Returns an error for existing transfer', async (): Promise => { @@ -1733,39 +1815,43 @@ describe('Liquidity Resolvers', (): void => { amount: BigInt(100) }) ).resolves.toBeUndefined() - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation DepositLiquidity( - $input: DepositEventLiquidityInput! - ) { - depositEventLiquidity(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation DepositLiquidity( + $input: DepositEventLiquidityInput! + ) { + depositEventLiquidity(input: $input) { + success + } + } + `, + variables: { + input: { + eventId, + idempotencyKey: uuid() } } - `, - variables: { - input: { - eventId, - idempotencyKey: uuid() + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.depositEventLiquidity + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.depositEventLiquidity - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('409') - expect(response.message).toEqual('Transfer exists') - expect(response.error).toEqual(LiquidityError.TransferExists) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Transfer already exists', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.Duplicate + }) + }) + ) + } }) } ) @@ -1881,10 +1967,7 @@ describe('Liquidity Resolvers', (): void => { $input: WithdrawEventLiquidityInput! ) { withdrawEventLiquidity(input: $input) { - code success - message - error } } `, @@ -1904,83 +1987,89 @@ describe('Liquidity Resolvers', (): void => { }) expect(response.success).toBe(true) - expect(response.code).toEqual('200') - expect(response.error).toBeNull() }) test('Returns error for non-existent webhook event id', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation WithdrawLiquidity( - $input: WithdrawEventLiquidityInput! - ) { - withdrawEventLiquidity(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation WithdrawLiquidity( + $input: WithdrawEventLiquidityInput! + ) { + withdrawEventLiquidity(input: $input) { + success + } + } + `, + variables: { + input: { + eventId: uuid(), + idempotencyKey: uuid() } } - `, - variables: { - input: { - eventId: uuid(), - idempotencyKey: uuid() + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.withdrawEventLiquidity + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.withdrawEventLiquidity - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('400') - expect(response.message).toEqual('Invalid id') - expect(response.error).toEqual(LiquidityError.InvalidId) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Invalid transfer id', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.BadUserInput + }) + }) + ) + } }) test('Returns error for already completed withdrawal', async (): Promise => { await expect( accountingService.createWithdrawal(withdrawal) ).resolves.toBeUndefined() - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation WithdrawLiquidity( - $input: WithdrawEventLiquidityInput! - ) { - withdrawEventLiquidity(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation WithdrawLiquidity( + $input: WithdrawEventLiquidityInput! + ) { + withdrawEventLiquidity(input: $input) { + success + } + } + `, + variables: { + input: { + eventId, + idempotencyKey: uuid() } } - `, - variables: { - input: { - eventId, - idempotencyKey: uuid() + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.withdrawEventLiquidity + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.withdrawEventLiquidity - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('409') - expect(response.message).toEqual('Transfer exists') - expect(response.error).toEqual(LiquidityError.TransferExists) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Transfer already exists', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.Duplicate + }) + }) + ) + } }) } ) @@ -2065,10 +2154,7 @@ describe('Liquidity Resolvers', (): void => { $input: CreateIncomingPaymentWithdrawalInput! ) { createIncomingPaymentWithdrawal(input: $input) { - code success - message - error } } `, @@ -2089,8 +2175,6 @@ describe('Liquidity Resolvers', (): void => { }) expect(response.success).toBe(true) - expect(response.code).toEqual('200') - expect(response.error).toBeNull() expect( accountingService.getBalance(incomingPayment.id) ).resolves.toEqual(balance - amount) @@ -2110,77 +2194,85 @@ describe('Liquidity Resolvers', (): void => { amount } }) - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateIncomingPaymentWithdrawal( - $input: CreateIncomingPaymentWithdrawalInput! - ) { - createIncomingPaymentWithdrawal(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateIncomingPaymentWithdrawal( + $input: CreateIncomingPaymentWithdrawalInput! + ) { + createIncomingPaymentWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + incomingPaymentId: uuid(), + idempotencyKey: uuid(), + timeoutSeconds: 0 } } - `, - variables: { - input: { - incomingPaymentId: uuid(), - idempotencyKey: uuid(), - timeoutSeconds: 0 + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.createIncomingPaymentWithdrawal + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.createIncomingPaymentWithdrawal - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('400') - expect(response.message).toEqual('Invalid id') - expect(response.error).toEqual(LiquidityError.InvalidId) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Invalid transfer id', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.BadUserInput + }) + }) + ) + } }) test('Returns error when related webhook not found', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateIncomingPaymentWithdrawal( - $input: CreateIncomingPaymentWithdrawalInput! - ) { - createIncomingPaymentWithdrawal(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateIncomingPaymentWithdrawal( + $input: CreateIncomingPaymentWithdrawalInput! + ) { + createIncomingPaymentWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + incomingPaymentId: incomingPayment.id, + idempotencyKey: uuid(), + timeoutSeconds: 0 } } - `, - variables: { - input: { - incomingPaymentId: incomingPayment.id, - idempotencyKey: uuid(), - timeoutSeconds: 0 + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.createIncomingPaymentWithdrawal + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.createIncomingPaymentWithdrawal - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('400') - expect(response.message).toEqual('Invalid id') - expect(response.error).toEqual(LiquidityError.InvalidId) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Invalid transfer id', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.BadUserInput + }) + }) + ) + } }) test('Returns error for already completed withdrawal', async (): Promise => { @@ -2203,40 +2295,44 @@ describe('Liquidity Resolvers', (): void => { amount: amount }) ).resolves.toBeUndefined() - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateIncomingPaymentWithdrawal( - $input: CreateIncomingPaymentWithdrawalInput! - ) { - createIncomingPaymentWithdrawal(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateIncomingPaymentWithdrawal( + $input: CreateIncomingPaymentWithdrawalInput! + ) { + createIncomingPaymentWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + incomingPaymentId: incomingPayment.id, + idempotencyKey: uuid(), + timeoutSeconds: 0 } } - `, - variables: { - input: { - incomingPaymentId: incomingPayment.id, - idempotencyKey: uuid(), - timeoutSeconds: 0 + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.createIncomingPaymentWithdrawal + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.createIncomingPaymentWithdrawal - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('409') - expect(response.message).toEqual('Transfer exists') - expect(response.error).toEqual(LiquidityError.TransferExists) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Transfer already exists', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.Duplicate + }) + }) + ) + } }) }) }) @@ -2284,10 +2380,7 @@ describe('Liquidity Resolvers', (): void => { $input: CreateOutgoingPaymentWithdrawalInput! ) { createOutgoingPaymentWithdrawal(input: $input) { - code success - message - error } } `, @@ -2308,8 +2401,6 @@ describe('Liquidity Resolvers', (): void => { }) expect(response.success).toBe(true) - expect(response.code).toEqual('200') - expect(response.error).toBeNull() expect( accountingService.getBalance(outgoingPayment.id) ).resolves.toEqual(balance - amount) @@ -2318,39 +2409,44 @@ describe('Liquidity Resolvers', (): void => { describe('Cannot withdraw liquidity', () => { test('Returns error for non-existent outgoing payment id', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateOutgoingPaymentWithdrawal( - $input: CreateOutgoingPaymentWithdrawalInput! - ) { - createOutgoingPaymentWithdrawal(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateOutgoingPaymentWithdrawal( + $input: CreateOutgoingPaymentWithdrawalInput! + ) { + createOutgoingPaymentWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + outgoingPaymentId: uuid(), + idempotencyKey: uuid(), + timeoutSeconds: 0 } } - `, - variables: { - input: { - outgoingPaymentId: uuid(), - idempotencyKey: uuid(), - timeoutSeconds: 0 + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.createOutgoingPaymentWithdrawal + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.createOutgoingPaymentWithdrawal - } else { - throw new Error('Data was empty') - } - }) - expect(response.success).toBe(false) - expect(response.code).toEqual('400') - expect(response.message).toEqual('Invalid id') - expect(response.error).toEqual(LiquidityError.InvalidId) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Invalid transfer id', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.BadUserInput + }) + }) + ) + } }) test('Returns error when related webhook not found', async (): Promise => { @@ -2361,39 +2457,44 @@ describe('Liquidity Resolvers', (): void => { amount: amount }) ).resolves.toBeUndefined() - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateIncomingPaymentWithdrawal( - $input: CreateOutgoingPaymentWithdrawalInput! - ) { - createOutgoingPaymentWithdrawal(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateIncomingPaymentWithdrawal( + $input: CreateOutgoingPaymentWithdrawalInput! + ) { + createOutgoingPaymentWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + outgoingPaymentId: outgoingPayment.id, + idempotencyKey: uuid(), + timeoutSeconds: 0 } } - `, - variables: { - input: { - outgoingPaymentId: outgoingPayment.id, - idempotencyKey: uuid(), - timeoutSeconds: 0 + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.createOutgoingPaymentWithdrawal + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.createOutgoingPaymentWithdrawal - } else { - throw new Error('Data was empty') - } - }) - expect(response.success).toBe(false) - expect(response.code).toEqual('400') - expect(response.message).toEqual('Invalid id') - expect(response.error).toEqual(LiquidityError.InvalidId) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Invalid transfer id', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.BadUserInput + }) + }) + ) + } }) test('Returns error for already completed withdrawal', async (): Promise => { @@ -2415,39 +2516,44 @@ describe('Liquidity Resolvers', (): void => { amount: amount }) ).resolves.toBeUndefined() - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateOutgoingPaymentWithdrawal( - $input: CreateOutgoingPaymentWithdrawalInput! - ) { - createOutgoingPaymentWithdrawal(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateOutgoingPaymentWithdrawal( + $input: CreateOutgoingPaymentWithdrawalInput! + ) { + createOutgoingPaymentWithdrawal(input: $input) { + success + } + } + `, + variables: { + input: { + outgoingPaymentId: outgoingPayment.id, + idempotencyKey: uuid(), + timeoutSeconds: 0 } } - `, - variables: { - input: { - outgoingPaymentId: outgoingPayment.id, - idempotencyKey: uuid(), - timeoutSeconds: 0 + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.createOutgoingPaymentWithdrawal + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.createOutgoingPaymentWithdrawal - } else { - throw new Error('Data was empty') - } - }) - expect(response.success).toBe(false) - expect(response.code).toEqual('403') - expect(response.message).toEqual('Insufficient balance') - expect(response.error).toEqual(LiquidityError.InsufficientBalance) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Insufficient transfer balance', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.Forbidden + }) + }) + ) + } }) }) }) @@ -2480,10 +2586,7 @@ describe('Liquidity Resolvers', (): void => { $input: DepositOutgoingPaymentLiquidityInput! ) { depositOutgoingPaymentLiquidity(input: $input) { - code success - message - error } } `, @@ -2503,8 +2606,6 @@ describe('Liquidity Resolvers', (): void => { }) expect(response.success).toBe(true) - expect(response.code).toEqual('200') - expect(response.error).toBeNull() assert.ok(outgoingPayment.debitAmount) await expect(depositSpy).toHaveBeenCalledWith({ id: eventId, @@ -2517,39 +2618,43 @@ describe('Liquidity Resolvers', (): void => { }) test("Can't deposit for non-existent outgoing payment id", async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation DepositLiquidity( - $input: DepositOutgoingPaymentLiquidityInput! - ) { - depositOutgoingPaymentLiquidity(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation DepositLiquidity( + $input: DepositOutgoingPaymentLiquidityInput! + ) { + depositOutgoingPaymentLiquidity(input: $input) { + success + } + } + `, + variables: { + input: { + outgoingPaymentId: uuid(), + idempotencyKey: uuid() } } - `, - variables: { - input: { - outgoingPaymentId: uuid(), - idempotencyKey: uuid() + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.depositOutgoingPaymentLiquidity + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.depositOutgoingPaymentLiquidity - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('400') - expect(response.message).toEqual('Invalid id') - expect(response.error).toEqual(LiquidityError.InvalidId) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Invalid transfer id', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.BadUserInput + }) + }) + ) + } }) test('Returns an error for existing transfer', async (): Promise => { @@ -2560,39 +2665,43 @@ describe('Liquidity Resolvers', (): void => { amount: BigInt(100) }) ).resolves.toBeUndefined() - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation DepositLiquidity( - $input: DepositOutgoingPaymentLiquidityInput! - ) { - depositOutgoingPaymentLiquidity(input: $input) { - code - success - message - error + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation DepositLiquidity( + $input: DepositOutgoingPaymentLiquidityInput! + ) { + depositOutgoingPaymentLiquidity(input: $input) { + success + } + } + `, + variables: { + input: { + outgoingPaymentId: outgoingPayment.id, + idempotencyKey: uuid() } } - `, - variables: { - input: { - outgoingPaymentId: outgoingPayment.id, - idempotencyKey: uuid() + }) + .then((query): LiquidityMutationResponse => { + if (query.data) { + return query.data.depositOutgoingPaymentLiquidity + } else { + throw new Error('Data was empty') } - } - }) - .then((query): LiquidityMutationResponse => { - if (query.data) { - return query.data.depositOutgoingPaymentLiquidity - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('409') - expect(response.message).toEqual('Transfer exists') - expect(response.error).toEqual(LiquidityError.TransferExists) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Transfer already exists', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.Duplicate + }) + }) + ) + } }) } ) diff --git a/packages/backend/src/graphql/resolvers/liquidity.ts b/packages/backend/src/graphql/resolvers/liquidity.ts index df2e6d59fe..ba434e31ea 100644 --- a/packages/backend/src/graphql/resolvers/liquidity.ts +++ b/packages/backend/src/graphql/resolvers/liquidity.ts @@ -1,10 +1,10 @@ +import { GraphQLError } from 'graphql' +import { GraphQLErrorCode } from '../errors' import { walletAddressToGraphql } from './wallet_address' import { ResolversTypes, MutationResolvers, LiquidityError, - LiquidityMutationResponse, - WalletAddressWithdrawalMutationResponse, AssetResolvers, PeerResolvers, WalletAddressResolvers, @@ -14,15 +14,24 @@ import { } from '../generated/graphql' import { ApolloContext } from '../../app' import { - FundingError, + fundingErrorToMessage, + fundingErrorToCode, isFundingError } from '../../open_payments/payment/outgoing/errors' +import { + errorToCode as transferErrorToCode, + errorToMessage as transferErrorToMessage +} from '../../accounting/errors' import { isOutgoingPaymentEvent, OutgoingPaymentDepositType, OutgoingPaymentEventType } from '../../open_payments/payment/outgoing/model' -import { PeerError } from '../../payment-method/ilp/peer/errors' +import { + PeerError, + errorToMessage as peerErrorToMessage, + errorToCode as peerErrorToCode +} from '../../payment-method/ilp/peer/errors' import { IncomingPaymentEventType } from '../../open_payments/payment/incoming/model' export const getAssetLiquidity: AssetResolvers['liquidity'] = @@ -80,41 +89,36 @@ export const depositPeerLiquidity: MutationResolvers['depositPeer args, ctx ): Promise => { - try { - if (args.input.amount === BigInt(0)) { - return responses[LiquidityError.AmountZero] - } - const peerService = await ctx.container.use('peerService') - const peerOrError = await peerService.depositLiquidity({ - transferId: args.input.id, - peerId: args.input.peerId, - amount: args.input.amount + if (args.input.amount === BigInt(0)) { + throw new GraphQLError(errorToMessage[LiquidityError.AmountZero], { + extensions: { + code: errorToCode[LiquidityError.AmountZero] + } }) + } + const peerService = await ctx.container.use('peerService') + const peerOrError = await peerService.depositLiquidity({ + transferId: args.input.id, + peerId: args.input.peerId, + amount: args.input.amount + }) + + if (peerOrError === PeerError.UnknownPeer) { + throw new GraphQLError(peerErrorToMessage[peerOrError], { + extensions: { + code: peerErrorToCode[peerOrError] + } + }) + } else if (isLiquidityError(peerOrError)) { + throw new GraphQLError(errorToMessage[peerOrError], { + extensions: { + code: errorToCode[peerOrError] + } + }) + } - if (peerOrError === PeerError.UnknownPeer) { - return responses[LiquidityError.UnknownPeer] - } else if (isLiquidityError(peerOrError)) { - return errorToResponse(peerOrError) - } - - return { - code: '200', - success: true, - message: 'Added peer liquidity' - } - } catch (err) { - ctx.logger.error( - { - input: args.input, - err - }, - 'error adding peer liquidity' - ) - return { - code: '400', - message: 'Error trying to deposit peer liquidity', - success: false - } + return { + success: true } } @@ -124,42 +128,37 @@ export const depositAssetLiquidity: MutationResolvers['depositAss args, ctx ): Promise => { - try { - if (args.input.amount === BigInt(0)) { - return responses[LiquidityError.AmountZero] - } - const assetService = await ctx.container.use('assetService') - const asset = await assetService.get(args.input.assetId) - if (!asset) { - return responses[LiquidityError.UnknownAsset] - } - const accountingService = await ctx.container.use('accountingService') - const error = await accountingService.createDeposit({ - id: args.input.id, - account: asset, - amount: args.input.amount + if (args.input.amount === 0n) { + throw new GraphQLError(errorToMessage[LiquidityError.AmountZero], { + extensions: { + code: errorToCode[LiquidityError.AmountZero] + } + }) + } + const assetService = await ctx.container.use('assetService') + const asset = await assetService.get(args.input.assetId) + if (!asset) { + throw new GraphQLError(errorToMessage[LiquidityError.UnknownAsset], { + extensions: { + code: errorToCode[LiquidityError.UnknownAsset] + } + }) + } + const accountingService = await ctx.container.use('accountingService') + const error = await accountingService.createDeposit({ + id: args.input.id, + account: asset, + amount: args.input.amount + }) + if (error) { + throw new GraphQLError(transferErrorToMessage[error], { + extensions: { + code: transferErrorToCode[error] + } }) - if (error) { - return errorToResponse(error) - } - return { - code: '200', - success: true, - message: 'Added asset liquidity' - } - } catch (err) { - ctx.logger.error( - { - input: args.input, - err - }, - 'error adding asset liquidity' - ) - return { - code: '400', - message: 'Error trying to deposit asset liquidity', - success: false - } + } + return { + success: true } } @@ -169,44 +168,39 @@ export const createPeerLiquidityWithdrawal: MutationResolvers['cr args, ctx ): Promise => { - try { - const { amount, id, timeoutSeconds, peerId } = args.input - if (amount === BigInt(0)) { - return responses[LiquidityError.AmountZero] - } - const peerService = await ctx.container.use('peerService') - const peer = await peerService.get(peerId) - if (!peer) { - return responses[LiquidityError.UnknownPeer] - } - const accountingService = await ctx.container.use('accountingService') - const error = await accountingService.createWithdrawal({ - id, - account: peer, - amount, - timeout: Number(timeoutSeconds) + const { amount, id, timeoutSeconds, peerId } = args.input + if (args.input.amount === BigInt(0)) { + throw new GraphQLError(errorToMessage[LiquidityError.AmountZero], { + extensions: { + code: errorToCode[LiquidityError.AmountZero] + } + }) + } + const peerService = await ctx.container.use('peerService') + const peer = await peerService.get(peerId) + if (!peer) { + throw new GraphQLError(errorToMessage[LiquidityError.UnknownPeer], { + extensions: { + code: errorToCode[LiquidityError.UnknownPeer] + } }) - if (error) { - return errorToResponse(error) - } - return { - code: '200', - success: true, - message: 'Created peer liquidity withdrawal' - } - } catch (err) { - ctx.logger.error( - { - input: args.input, - err - }, - 'error creating peer liquidity withdrawal' - ) - return { - code: '400', - message: 'Error trying to create peer liquidity withdrawal', - success: false - } + } + const accountingService = await ctx.container.use('accountingService') + const error = await accountingService.createWithdrawal({ + id, + account: peer, + amount, + timeout: Number(timeoutSeconds) + }) + if (error) { + throw new GraphQLError(transferErrorToMessage[error], { + extensions: { + code: transferErrorToCode[error] + } + }) + } + return { + success: true } } @@ -216,44 +210,39 @@ export const createAssetLiquidityWithdrawal: MutationResolvers['c args, ctx ): Promise => { - try { - const { amount, id, timeoutSeconds, assetId } = args.input - if (amount === 0n) { - return responses[LiquidityError.AmountZero] - } - const assetService = await ctx.container.use('assetService') - const asset = await assetService.get(assetId) - if (!asset) { - return responses[LiquidityError.UnknownAsset] - } - const accountingService = await ctx.container.use('accountingService') - const error = await accountingService.createWithdrawal({ - id, - account: asset, - amount, - timeout: Number(timeoutSeconds) + const { amount, id, timeoutSeconds, assetId } = args.input + if (amount === 0n) { + throw new GraphQLError(errorToMessage[LiquidityError.AmountZero], { + extensions: { + code: errorToCode[LiquidityError.AmountZero] + } }) - if (error) { - return errorToResponse(error) - } - return { - code: '200', - success: true, - message: 'Created asset liquidity withdrawal' - } - } catch (err) { - ctx.logger.error( - { - input: args.input, - err - }, - 'error creating asset liquidity withdrawal' - ) - return { - code: '400', - message: 'Error trying to create asset liquidity withdrawal', - success: false - } + } + const assetService = await ctx.container.use('assetService') + const asset = await assetService.get(assetId) + if (!asset) { + throw new GraphQLError(errorToMessage[LiquidityError.UnknownAsset], { + extensions: { + code: errorToCode[LiquidityError.UnknownAsset] + } + }) + } + const accountingService = await ctx.container.use('accountingService') + const error = await accountingService.createWithdrawal({ + id, + account: asset, + amount, + timeout: Number(timeoutSeconds) + }) + if (error) { + throw new GraphQLError(transferErrorToMessage[error], { + extensions: { + code: transferErrorToCode[error] + } + }) + } + return { + success: true } } @@ -263,62 +252,49 @@ export const createWalletAddressWithdrawal: MutationResolvers['cr args, ctx ): Promise => { - try { - const { id, walletAddressId, timeoutSeconds } = args.input - const walletAddressService = await ctx.container.use( - 'walletAddressService' + const { id, walletAddressId, timeoutSeconds } = args.input + const walletAddressService = await ctx.container.use('walletAddressService') + const walletAddress = await walletAddressService.get(walletAddressId) + if (!walletAddress) { + throw new GraphQLError( + errorToMessage[LiquidityError.UnknownWalletAddress], + { + extensions: { + code: errorToCode[LiquidityError.UnknownWalletAddress] + } + } ) - const walletAddress = await walletAddressService.get(walletAddressId) - if (!walletAddress) { - return responses[ - LiquidityError.UnknownWalletAddress - ] as unknown as WalletAddressWithdrawalMutationResponse - } - const accountingService = await ctx.container.use('accountingService') - const amount = await accountingService.getBalance(walletAddress.id) - if (amount === undefined) - throw new Error( - `Could not get balance for wallet address liquidity account. It's likely the liquidity account does not exist.` - ) - else if (amount === 0n) { - return responses[ - LiquidityError.AmountZero - ] as unknown as WalletAddressWithdrawalMutationResponse - } - const error = await accountingService.createWithdrawal({ - id, - account: walletAddress, - amount, - timeout: Number(timeoutSeconds) + } + const accountingService = await ctx.container.use('accountingService') + const amount = await accountingService.getBalance(walletAddress.id) + if (amount === undefined) + throw new Error('missing incoming payment wallet address') + if (amount === 0n) { + throw new GraphQLError(errorToMessage[LiquidityError.AmountZero], { + extensions: { + code: errorToCode[LiquidityError.AmountZero] + } }) + } + const error = await accountingService.createWithdrawal({ + id, + account: walletAddress, + amount, + timeout: Number(timeoutSeconds) + }) - if (error) { - return errorToResponse( - error - ) as unknown as WalletAddressWithdrawalMutationResponse - } - return { - code: '200', - success: true, - message: 'Created account withdrawal', - withdrawal: { - id, - amount, - walletAddress: walletAddressToGraphql(walletAddress) + if (error) { + throw new GraphQLError(transferErrorToMessage[error], { + extensions: { + code: transferErrorToCode[error] } - } - } catch (err) { - ctx.logger.error( - { - input: args.input, - err - }, - 'error creating wallet address withdrawal' - ) - return { - code: '500', - message: 'Error trying to create wallet address withdrawal', - success: false + }) + } + return { + withdrawal: { + id, + amount, + walletAddress: walletAddressToGraphql(walletAddress) } } } @@ -334,12 +310,14 @@ export const postLiquidityWithdrawal: MutationResolvers['postLiqu args.input.withdrawalId ) if (error) { - return errorToResponse(error) + throw new GraphQLError(transferErrorToMessage[error], { + extensions: { + code: transferErrorToCode[error] + } + }) } return { - code: '200', - success: true, - message: 'Posted Withdrawal' + success: true } } @@ -354,12 +332,14 @@ export const voidLiquidityWithdrawal: MutationResolvers['voidLiqu args.input.withdrawalId ) if (error) { - return errorToResponse(error) + throw new GraphQLError(transferErrorToMessage[error], { + extensions: { + code: transferErrorToCode[error] + } + }) } return { - code: '200', - success: true, - message: 'Voided Withdrawal' + success: true } } @@ -376,48 +356,39 @@ export const depositEventLiquidity: MutationResolvers['depositEve args, ctx ): Promise => { - try { - const webhookService = await ctx.container.use('webhookService') - const event = await webhookService.getEvent(args.input.eventId) - if ( - !event || - !isOutgoingPaymentEvent(event) || - !isDepositEventType(event.type) - ) { - return responses[LiquidityError.InvalidId] - } - if (!event.data.debitAmount) { - throw new Error('missing debit amount') - } - const outgoingPaymentService = await ctx.container.use( - 'outgoingPaymentService' - ) - const paymentOrErr = await outgoingPaymentService.fund({ - id: event.data.id, - amount: BigInt(event.data.debitAmount.value), - transferId: event.id + const webhookService = await ctx.container.use('webhookService') + const event = await webhookService.getEvent(args.input.eventId) + if ( + !event || + !isOutgoingPaymentEvent(event) || + !isDepositEventType(event.type) + ) { + throw new GraphQLError(errorToMessage[LiquidityError.InvalidId], { + extensions: { + code: errorToCode[LiquidityError.InvalidId] + } }) - if (isFundingError(paymentOrErr)) { - return errorToResponse(paymentOrErr) - } - return { - code: '200', - success: true, - message: 'Deposited liquidity' - } - } catch (err) { - ctx.logger.error( - { - eventId: args.input.eventId, - err - }, - 'error depositing liquidity' - ) - return { - code: '400', - message: 'Error trying to deposit liquidity', - success: false - } + } + if (!event.data.debitAmount) { + throw new Error('missing debit amount') + } + const outgoingPaymentService = await ctx.container.use( + 'outgoingPaymentService' + ) + const paymentOrErr = await outgoingPaymentService.fund({ + id: event.data.id, + amount: BigInt(event.data.debitAmount.value), + transferId: event.id + }) + if (isFundingError(paymentOrErr)) { + throw new GraphQLError(fundingErrorToMessage[paymentOrErr], { + extensions: { + code: fundingErrorToCode[paymentOrErr] + } + }) + } + return { + success: true } } @@ -427,48 +398,39 @@ export const withdrawEventLiquidity: MutationResolvers['withdrawE args, ctx ): Promise => { - try { - const webhookService = await ctx.container.use('webhookService') - const event = await webhookService.getEvent(args.input.eventId) - if (!event || !event.withdrawal) { - return responses[LiquidityError.InvalidId] - } - const assetService = await ctx.container.use('assetService') - const asset = await assetService.get(event.withdrawal.assetId) - if (!asset) { - throw new Error('asset id does not map to asset') - } - const accountingService = await ctx.container.use('accountingService') - const error = await accountingService.createWithdrawal({ - id: event.id, - account: { - id: event.withdrawal.accountId, - asset - }, - amount: event.withdrawal.amount + const webhookService = await ctx.container.use('webhookService') + const event = await webhookService.getEvent(args.input.eventId) + if (!event || !event.withdrawal) { + throw new GraphQLError(errorToMessage[LiquidityError.InvalidId], { + extensions: { + code: errorToCode[LiquidityError.InvalidId] + } + }) + } + const assetService = await ctx.container.use('assetService') + const asset = await assetService.get(event.withdrawal.assetId) + if (!asset) { + throw new Error('asset id does not map to asset') + } + const accountingService = await ctx.container.use('accountingService') + const error = await accountingService.createWithdrawal({ + id: event.id, + account: { + id: event.withdrawal.accountId, + asset + }, + amount: event.withdrawal.amount + }) + if (error) { + throw new GraphQLError(transferErrorToMessage[error], { + extensions: { + code: transferErrorToCode[error] + } }) - if (error) { - return errorToResponse(error) - } - // TODO: check for and handle leftover incoming payment or payment balance - return { - code: '200', - success: true, - message: 'Withdrew liquidity' - } - } catch (err) { - ctx.logger.error( - { - eventId: args.input.eventId, - err - }, - 'error withdrawing liquidity' - ) - return { - code: '400', - message: 'Error trying to withdraw liquidity', - success: false - } + } + // TODO: check for and handle leftover incoming payment or payment balance + return { + success: true } } @@ -478,49 +440,40 @@ export const depositOutgoingPaymentLiquidity: MutationResolvers[' args, ctx ): Promise => { - try { - const { outgoingPaymentId } = args.input - const webhookService = await ctx.container.use('webhookService') - const event = await webhookService.getLatestByResourceId({ - outgoingPaymentId, - types: [OutgoingPaymentDepositType.PaymentCreated] + const { outgoingPaymentId } = args.input + const webhookService = await ctx.container.use('webhookService') + const event = await webhookService.getLatestByResourceId({ + outgoingPaymentId, + types: [OutgoingPaymentDepositType.PaymentCreated] + }) + if (!event || !isOutgoingPaymentEvent(event)) { + throw new GraphQLError(errorToMessage[LiquidityError.InvalidId], { + extensions: { + code: errorToCode[LiquidityError.InvalidId] + } }) - if (!event || !isOutgoingPaymentEvent(event)) { - return responses[LiquidityError.InvalidId] - } + } - if (!event.data.debitAmount) { - throw new Error('No debit amount') - } - const outgoingPaymentService = await ctx.container.use( - 'outgoingPaymentService' - ) - const paymentOrErr = await outgoingPaymentService.fund({ - id: outgoingPaymentId, - amount: BigInt(event.data.debitAmount.value), - transferId: event.id + if (!event.data.debitAmount) { + throw new Error('No debit amount') + } + const outgoingPaymentService = await ctx.container.use( + 'outgoingPaymentService' + ) + const paymentOrErr = await outgoingPaymentService.fund({ + id: outgoingPaymentId, + amount: BigInt(event.data.debitAmount.value), + transferId: event.id + }) + if (isFundingError(paymentOrErr)) { + throw new GraphQLError(fundingErrorToMessage[paymentOrErr], { + extensions: { + code: fundingErrorToCode[paymentOrErr] + } }) - if (isFundingError(paymentOrErr)) { - return errorToResponse(paymentOrErr) - } - return { - code: '200', - success: true, - message: 'Deposited liquidity' - } - } catch (err) { - ctx.logger.error( - { - outgoingPaymentId: args.input.outgoingPaymentId, - err - }, - 'error depositing liquidity' - ) - return { - code: '400', - message: 'Error trying to deposit liquidity', - success: false - } + } + return { + success: true } } @@ -531,57 +484,48 @@ export const createIncomingPaymentWithdrawal: MutationResolvers[' ctx ): Promise => { const { incomingPaymentId, timeoutSeconds } = args.input - try { - const incomingPaymentService = await ctx.container.use( - 'incomingPaymentService' - ) - const incomingPayment = await incomingPaymentService.get({ - id: incomingPaymentId - }) - const webhookService = await ctx.container.use('webhookService') - const event = await webhookService.getLatestByResourceId({ - incomingPaymentId, - types: [ - IncomingPaymentEventType.IncomingPaymentCompleted, - IncomingPaymentEventType.IncomingPaymentExpired - ] + const incomingPaymentService = await ctx.container.use( + 'incomingPaymentService' + ) + const incomingPayment = await incomingPaymentService.get({ + id: incomingPaymentId + }) + const webhookService = await ctx.container.use('webhookService') + const event = await webhookService.getLatestByResourceId({ + incomingPaymentId, + types: [ + IncomingPaymentEventType.IncomingPaymentCompleted, + IncomingPaymentEventType.IncomingPaymentExpired + ] + }) + if (!incomingPayment || !incomingPayment.receivedAmount || !event?.id) { + throw new GraphQLError(errorToMessage[LiquidityError.InvalidId], { + extensions: { + code: errorToCode[LiquidityError.InvalidId] + } }) - if (!incomingPayment || !incomingPayment.receivedAmount || !event?.id) { - return responses[LiquidityError.InvalidId] - } + } - const accountingService = await ctx.container.use('accountingService') - const error = await accountingService.createWithdrawal({ - id: event.id, - account: { - id: incomingPaymentId, - asset: incomingPayment.asset - }, - amount: incomingPayment.receivedAmount.value, - timeout: Number(timeoutSeconds) - }) + const accountingService = await ctx.container.use('accountingService') + const error = await accountingService.createWithdrawal({ + id: event.id, + account: { + id: incomingPaymentId, + asset: incomingPayment.asset + }, + amount: incomingPayment.receivedAmount.value, + timeout: Number(timeoutSeconds) + }) - if (error) { - return errorToResponse(error) - } - return { - code: '200', - success: true, - message: 'Withdrew liquidity' - } - } catch (error) { - ctx.logger.error( - { - incomingPaymentId, - error - }, - 'error withdrawing liquidity' - ) - return { - code: '400', - message: 'Error trying to withdraw liquidity', - success: false - } + if (error) { + throw new GraphQLError(fundingErrorToMessage[error], { + extensions: { + code: fundingErrorToCode[error] + } + }) + } + return { + success: true } } @@ -592,62 +536,60 @@ export const createOutgoingPaymentWithdrawal: MutationResolvers[' ctx ): Promise => { const { outgoingPaymentId, timeoutSeconds } = args.input - try { - const outgoingPaymentService = await ctx.container.use( - 'outgoingPaymentService' - ) - const outgoingPayment = await outgoingPaymentService.get({ - id: outgoingPaymentId - }) - const webhookService = await ctx.container.use('webhookService') - const event = await webhookService.getLatestByResourceId({ - outgoingPaymentId, - types: [ - OutgoingPaymentEventType.PaymentCompleted, - OutgoingPaymentEventType.PaymentFailed - ] - }) - if (!outgoingPayment || !event?.id) { - return responses[LiquidityError.InvalidId] - } - - const accountingService = await ctx.container.use('accountingService') - const balance = await accountingService.getBalance(outgoingPayment.id) - if (!balance) { - return responses[LiquidityError.InsufficientBalance] - } - - const error = await accountingService.createWithdrawal({ - id: event.id, - account: { - id: outgoingPaymentId, - asset: outgoingPayment.asset - }, - amount: balance, - timeout: Number(timeoutSeconds) + const outgoingPaymentService = await ctx.container.use( + 'outgoingPaymentService' + ) + const outgoingPayment = await outgoingPaymentService.get({ + id: outgoingPaymentId + }) + const webhookService = await ctx.container.use('webhookService') + const event = await webhookService.getLatestByResourceId({ + outgoingPaymentId, + types: [ + OutgoingPaymentEventType.PaymentCompleted, + OutgoingPaymentEventType.PaymentFailed + ] + }) + if (!outgoingPayment || !event?.id) { + throw new GraphQLError(errorToMessage[LiquidityError.InvalidId], { + extensions: { + code: errorToCode[LiquidityError.InvalidId] + } }) + } - if (error) { - return errorToResponse(error) - } - return { - code: '200', - success: true, - message: 'Withdrew liquidity' - } - } catch (error) { - ctx.logger.error( + const accountingService = await ctx.container.use('accountingService') + const balance = await accountingService.getBalance(outgoingPayment.id) + if (!balance) { + throw new GraphQLError( + errorToMessage[LiquidityError.InsufficientBalance], { - outgoingPaymentId, - error - }, - 'error withdrawing liquidity' + extensions: { + code: errorToCode[LiquidityError.InsufficientBalance] + } + } ) - return { - code: '400', - message: 'Error trying to withdraw liquidity', - success: false - } + } + + const error = await accountingService.createWithdrawal({ + id: event.id, + account: { + id: outgoingPaymentId, + asset: outgoingPayment.asset + }, + amount: balance, + timeout: Number(timeoutSeconds) + }) + + if (error) { + throw new GraphQLError(transferErrorToMessage[error], { + extensions: { + code: transferErrorToCode[error] + } + }) + } + return { + success: true } } @@ -655,86 +597,36 @@ export const createOutgoingPaymentWithdrawal: MutationResolvers[' const isLiquidityError = (o: any): o is LiquidityError => Object.values(LiquidityError).includes(o) -const errorToResponse = (error: FundingError): LiquidityMutationResponse => { - if (!isLiquidityError(error)) { - throw new Error(error) - } - return responses[error] +const errorToCode: { + [key in LiquidityError]: string +} = { + [LiquidityError.AlreadyPosted]: GraphQLErrorCode.Conflict, + [LiquidityError.AlreadyVoided]: GraphQLErrorCode.Conflict, + [LiquidityError.AmountZero]: GraphQLErrorCode.Forbidden, + [LiquidityError.InsufficientBalance]: GraphQLErrorCode.Forbidden, + [LiquidityError.InvalidId]: GraphQLErrorCode.BadUserInput, + [LiquidityError.TransferExists]: GraphQLErrorCode.Duplicate, + [LiquidityError.UnknownAsset]: GraphQLErrorCode.NotFound, + [LiquidityError.UnknownIncomingPayment]: GraphQLErrorCode.NotFound, + [LiquidityError.UnknownPayment]: GraphQLErrorCode.NotFound, + [LiquidityError.UnknownWalletAddress]: GraphQLErrorCode.NotFound, + [LiquidityError.UnknownPeer]: GraphQLErrorCode.NotFound, + [LiquidityError.UnknownTransfer]: GraphQLErrorCode.NotFound } -const responses: { - [key in LiquidityError]: LiquidityMutationResponse +const errorToMessage: { + [key in LiquidityError]: string } = { - [LiquidityError.AlreadyPosted]: { - code: '409', - message: 'Withdrawal already posted', - success: false, - error: LiquidityError.AlreadyPosted - }, - [LiquidityError.AlreadyVoided]: { - code: '409', - message: 'Withdrawal already voided', - success: false, - error: LiquidityError.AlreadyVoided - }, - [LiquidityError.AmountZero]: { - code: '400', - message: 'Amount is zero', - success: false, - error: LiquidityError.AmountZero - }, - [LiquidityError.InsufficientBalance]: { - code: '403', - message: 'Insufficient balance', - success: false, - error: LiquidityError.InsufficientBalance - }, - [LiquidityError.InvalidId]: { - code: '400', - message: 'Invalid id', - success: false, - error: LiquidityError.InvalidId - }, - [LiquidityError.TransferExists]: { - code: '409', - message: 'Transfer exists', - success: false, - error: LiquidityError.TransferExists - }, - [LiquidityError.UnknownWalletAddress]: { - code: '404', - message: 'Unknown wallet address', - success: false, - error: LiquidityError.UnknownWalletAddress - }, - [LiquidityError.UnknownAsset]: { - code: '404', - message: 'Unknown asset', - success: false, - error: LiquidityError.UnknownAsset - }, - [LiquidityError.UnknownIncomingPayment]: { - code: '404', - message: 'Unknown incoming payment', - success: false, - error: LiquidityError.UnknownIncomingPayment - }, - [LiquidityError.UnknownPayment]: { - code: '404', - message: 'Unknown outgoing payment', - success: false, - error: LiquidityError.UnknownPayment - }, - [LiquidityError.UnknownPeer]: { - code: '404', - message: 'Unknown peer', - success: false, - error: LiquidityError.UnknownPeer - }, - [LiquidityError.UnknownTransfer]: { - code: '404', - message: 'Unknown withdrawal', - success: false, - error: LiquidityError.UnknownTransfer - } + [LiquidityError.AlreadyPosted]: 'Transfer already posted', + [LiquidityError.AlreadyVoided]: 'Transfer already voided', + [LiquidityError.AmountZero]: 'Transfer amount is zero', + [LiquidityError.InsufficientBalance]: 'Insufficient transfer balance', + [LiquidityError.InvalidId]: 'Invalid transfer id', + [LiquidityError.TransferExists]: 'Transfer already exists', + [LiquidityError.UnknownAsset]: 'Unknown asset', + [LiquidityError.UnknownIncomingPayment]: 'Unknown incoming payment', + [LiquidityError.UnknownPayment]: 'Unknown transfer payment', + [LiquidityError.UnknownWalletAddress]: 'Unknown wallet address', + [LiquidityError.UnknownPeer]: 'Unknown peer', + [LiquidityError.UnknownTransfer]: 'Unknown transfer' } diff --git a/packages/backend/src/graphql/resolvers/outgoing_payment.test.ts b/packages/backend/src/graphql/resolvers/outgoing_payment.test.ts index 4d41cb3f12..e7ee1d1b20 100644 --- a/packages/backend/src/graphql/resolvers/outgoing_payment.test.ts +++ b/packages/backend/src/graphql/resolvers/outgoing_payment.test.ts @@ -1,4 +1,4 @@ -import { gql } from '@apollo/client' +import { ApolloError, gql } from '@apollo/client' import { PaymentError } from '@interledger/pay' import { v4 as uuid } from 'uuid' import * as Pay from '@interledger/pay' @@ -15,7 +15,8 @@ import { createWalletAddress } from '../../tests/walletAddress' import { truncateTables } from '../../tests/tableManager' import { OutgoingPaymentError, - errorToMessage + errorToMessage, + errorToCode } from '../../open_payments/payment/outgoing/errors' import { OutgoingPaymentService } from '../../open_payments/payment/outgoing/service' import { @@ -30,6 +31,7 @@ import { OutgoingPaymentState as SchemaPaymentState } from '../generated/graphql' import { faker } from '@faker-js/faker' +import { GraphQLErrorCode } from '../errors' describe('OutgoingPayment Resolvers', (): void => { let deps: IocContract @@ -99,7 +101,7 @@ describe('OutgoingPayment Resolvers', (): void => { [state, Pay.PaymentError.ReceiverProtocolViolation] ]) test.each(states)( - '200 - %s, error: %s', + '%s, error: %s', async (state, error): Promise => { const amountSent = BigInt(78) jest @@ -211,7 +213,7 @@ describe('OutgoingPayment Resolvers', (): void => { } ) - test('200 - with added liquidity', async (): Promise => { + test('with added liquidity', async (): Promise => { await accountingService.createDeposit({ id: uuid(), account: payment, @@ -242,13 +244,13 @@ describe('OutgoingPayment Resolvers', (): void => { }) }) - test('404', async (): Promise => { + test('not found', async (): Promise => { jest .spyOn(outgoingPaymentService, 'get') .mockImplementation(async () => undefined) - await expect( - appContainer.apolloClient.query({ + try { + await appContainer.apolloClient.query({ query: gql` query OutgoingPayment($paymentId: String!) { outgoingPayment(id: $paymentId) { @@ -258,7 +260,17 @@ describe('OutgoingPayment Resolvers', (): void => { `, variables: { paymentId: uuid() } }) - ).rejects.toThrow('payment does not exist') + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'payment does not exist', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.NotFound + }) + }) + ) + } }) }) @@ -268,7 +280,7 @@ describe('OutgoingPayment Resolvers', (): void => { externalRef: '202201' } - test('201 (metadata)', async (): Promise => { + test('success (metadata)', async (): Promise => { const { id: walletAddressId } = await createWalletAddress(deps, { assetId: asset.id }) @@ -290,8 +302,6 @@ describe('OutgoingPayment Resolvers', (): void => { $input: CreateOutgoingPaymentInput! ) { createOutgoingPayment(input: $input) { - code - success payment { id state @@ -306,13 +316,11 @@ describe('OutgoingPayment Resolvers', (): void => { ) expect(createSpy).toHaveBeenCalledWith(input) - expect(query.code).toBe('201') - expect(query.success).toBe(true) expect(query.payment?.id).toBe(payment.id) expect(query.payment?.state).toBe(SchemaPaymentState.Funding) }) - test('400', async (): Promise => { + test('Fails if walletAddress unknown', async (): Promise => { const createSpy = jest .spyOn(outgoingPaymentService, 'create') .mockResolvedValueOnce(OutgoingPaymentError.UnknownWalletAddress) @@ -322,38 +330,42 @@ describe('OutgoingPayment Resolvers', (): void => { quoteId: uuid() } - const query = await appContainer.apolloClient - .query({ - query: gql` - mutation CreateOutgoingPayment( - $input: CreateOutgoingPaymentInput! - ) { - createOutgoingPayment(input: $input) { - code - success - message - payment { - id - state + try { + await appContainer.apolloClient + .query({ + query: gql` + mutation CreateOutgoingPayment( + $input: CreateOutgoingPaymentInput! + ) { + createOutgoingPayment(input: $input) { + payment { + id + state + } } } - } - `, - variables: { input } - }) - .then( - (query): OutgoingPaymentResponse => query.data?.createOutgoingPayment + `, + variables: { input } + }) + .then( + (query): OutgoingPaymentResponse => + query.data?.createOutgoingPayment + ) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[OutgoingPaymentError.UnknownWalletAddress], + extensions: expect.objectContaining({ + code: errorToCode[OutgoingPaymentError.UnknownWalletAddress] + }) + }) ) - expect(query.code).toBe('404') - expect(query.success).toBe(false) - expect(query.message).toBe( - errorToMessage[OutgoingPaymentError.UnknownWalletAddress] - ) - expect(query.payment).toBeNull() - expect(createSpy).toHaveBeenCalledWith(input) + } + await expect(createSpy).toHaveBeenCalledWith(input) }) - test('500', async (): Promise => { + test('internal server error', async (): Promise => { const createSpy = jest .spyOn(outgoingPaymentService, 'create') .mockRejectedValueOnce(new Error('unexpected')) @@ -363,40 +375,46 @@ describe('OutgoingPayment Resolvers', (): void => { quoteId: uuid() } - const query = await appContainer.apolloClient - .query({ - query: gql` - mutation CreateOutgoingPayment( - $input: CreateOutgoingPaymentInput! - ) { - createOutgoingPayment(input: $input) { - code - success - message - payment { - id - state + try { + await appContainer.apolloClient + .query({ + query: gql` + mutation CreateOutgoingPayment( + $input: CreateOutgoingPaymentInput! + ) { + createOutgoingPayment(input: $input) { + payment { + id + state + } } } - } - `, - variables: { input } - }) - .then( - (query): OutgoingPaymentResponse => query.data?.createOutgoingPayment + `, + variables: { input } + }) + .then( + (query): OutgoingPaymentResponse => + query.data?.createOutgoingPayment + ) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'unexpected', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.InternalServerError + }) + }) ) + } expect(createSpy).toHaveBeenCalledWith(input) - expect(query.code).toBe('500') - expect(query.success).toBe(false) - expect(query.message).toBe('Error trying to create outgoing payment') - expect(query.payment).toBeNull() }) }) describe('Mutation.createOutgoingPaymentFromIncomingPayment', (): void => { const mockIncomingPaymentUrl = `https://${faker.internet.domainName()}/incoming-payments/${uuid()}` - test('201', async (): Promise => { + test('create', async (): Promise => { const walletAddress = await createWalletAddress(deps, { assetId: asset.id }) @@ -423,8 +441,6 @@ describe('OutgoingPayment Resolvers', (): void => { $input: CreateOutgoingPaymentFromIncomingPaymentInput! ) { createOutgoingPaymentFromIncomingPayment(input: $input) { - code - success payment { id state @@ -440,13 +456,11 @@ describe('OutgoingPayment Resolvers', (): void => { ) expect(createSpy).toHaveBeenCalledWith(input) - expect(query.code).toBe('201') - expect(query.success).toBe(true) expect(query.payment?.id).toBe(payment.id) expect(query.payment?.state).toBe(SchemaPaymentState.Funding) }) - test('400', async (): Promise => { + test('unknown wallet address', async (): Promise => { const createSpy = jest .spyOn(outgoingPaymentService, 'create') .mockResolvedValueOnce(OutgoingPaymentError.UnknownWalletAddress) @@ -461,39 +475,42 @@ describe('OutgoingPayment Resolvers', (): void => { } } - const query = await appContainer.apolloClient - .query({ - query: gql` - mutation CreateOutgoingPaymentFromIncomingPayment( - $input: CreateOutgoingPaymentFromIncomingPaymentInput! - ) { - createOutgoingPaymentFromIncomingPayment(input: $input) { - code - success - message - payment { - id - state + try { + await appContainer.apolloClient + .query({ + query: gql` + mutation CreateOutgoingPaymentFromIncomingPayment( + $input: CreateOutgoingPaymentFromIncomingPaymentInput! + ) { + createOutgoingPaymentFromIncomingPayment(input: $input) { + payment { + id + state + } } } - } - `, - variables: { input } - }) - .then( - (query): OutgoingPaymentResponse => - query.data?.createOutgoingPaymentFromIncomingPayment + `, + variables: { input } + }) + .then( + (query): OutgoingPaymentResponse => + query.data?.createOutgoingPaymentFromIncomingPayment + ) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[OutgoingPaymentError.UnknownWalletAddress], + extensions: expect.objectContaining({ + code: errorToCode[OutgoingPaymentError.UnknownWalletAddress] + }) + }) ) + } expect(createSpy).toHaveBeenCalledWith(input) - expect(query.code).toBe('404') - expect(query.success).toBe(false) - expect(query.message).toBe( - errorToMessage[OutgoingPaymentError.UnknownWalletAddress] - ) - expect(query.payment).toBeNull() }) - test('500', async (): Promise => { + test('unknown error', async (): Promise => { const createSpy = jest .spyOn(outgoingPaymentService, 'create') .mockRejectedValueOnce(new Error('unexpected')) @@ -508,34 +525,39 @@ describe('OutgoingPayment Resolvers', (): void => { } } - const query = await appContainer.apolloClient - .query({ - query: gql` - mutation CreateOutgoingPaymentFromIncomingPayment( - $input: CreateOutgoingPaymentFromIncomingPaymentInput! - ) { - createOutgoingPaymentFromIncomingPayment(input: $input) { - code - success - message - payment { - id - state + try { + await appContainer.apolloClient + .query({ + query: gql` + mutation CreateOutgoingPaymentFromIncomingPayment( + $input: CreateOutgoingPaymentFromIncomingPaymentInput! + ) { + createOutgoingPaymentFromIncomingPayment(input: $input) { + payment { + id + state + } } } - } - `, - variables: { input } - }) - .then( - (query): OutgoingPaymentResponse => - query.data?.createOutgoingPaymentFromIncomingPayment + `, + variables: { input } + }) + .then( + (query): OutgoingPaymentResponse => + query.data?.createOutgoingPaymentFromIncomingPayment + ) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'unexpected', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.InternalServerError + }) + }) ) + } expect(createSpy).toHaveBeenCalledWith(input) - expect(query.code).toBe('500') - expect(query.success).toBe(false) - expect(query.message).toBe('Error trying to create outgoing payment') - expect(query.payment).toBeNull() }) }) @@ -574,8 +596,6 @@ describe('OutgoingPayment Resolvers', (): void => { $input: CancelOutgoingPaymentInput! ) { cancelOutgoingPayment(input: $input) { - code - success payment { id state @@ -592,8 +612,6 @@ describe('OutgoingPayment Resolvers', (): void => { ) expect(cancelSpy).toHaveBeenCalledWith(input) - expect(mutationResponse.code).toBe('200') - expect(mutationResponse.success).toBe(true) expect(mutationResponse.payment).toEqual({ __typename: 'OutgoingPayment', id: input.id, @@ -605,52 +623,53 @@ describe('OutgoingPayment Resolvers', (): void => { } ) - const errors: [string, OutgoingPaymentError][] = [ - ['409', OutgoingPaymentError.WrongState], - ['404', OutgoingPaymentError.UnknownPayment] + const errors: [OutgoingPaymentError][] = [ + [OutgoingPaymentError.WrongState], + [OutgoingPaymentError.UnknownPayment] ] test.each(errors)( '%s - outgoing payment error', - async (statusCode, paymentError): Promise => { + async (paymentError): Promise => { const cancelSpy = jest .spyOn(outgoingPaymentService, 'cancel') .mockResolvedValueOnce(paymentError) const input = { id: uuid() } - const mutationResponse = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CancelOutgoingPayment( - $input: CancelOutgoingPaymentInput! - ) { - cancelOutgoingPayment(input: $input) { - code - message - success - payment { - id - state - metadata + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CancelOutgoingPayment( + $input: CancelOutgoingPaymentInput! + ) { + cancelOutgoingPayment(input: $input) { + payment { + id + state + metadata + } } } - } - `, - variables: { input } - }) - .then( - (query): OutgoingPaymentResponse => - query.data?.cancelOutgoingPayment + `, + variables: { input } + }) + .then( + (query): OutgoingPaymentResponse => + query.data?.cancelOutgoingPayment + ) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[paymentError], + extensions: expect.objectContaining({ + code: errorToCode[paymentError] + }) + }) ) - + } expect(cancelSpy).toHaveBeenCalledWith(input) - expect(mutationResponse).toEqual({ - __typename: 'OutgoingPaymentResponse', - code: statusCode, - message: errorToMessage[paymentError], - success: false, - payment: null - }) } ) }) diff --git a/packages/backend/src/graphql/resolvers/outgoing_payment.ts b/packages/backend/src/graphql/resolvers/outgoing_payment.ts index 20894fdeca..c4907b6e58 100644 --- a/packages/backend/src/graphql/resolvers/outgoing_payment.ts +++ b/packages/backend/src/graphql/resolvers/outgoing_payment.ts @@ -7,15 +7,16 @@ import { ResolversTypes } from '../generated/graphql' import { - OutgoingPaymentError, isOutgoingPaymentError, - errorToCode, - errorToMessage + errorToMessage, + errorToCode } from '../../open_payments/payment/outgoing/errors' import { OutgoingPayment } from '../../open_payments/payment/outgoing/model' import { ApolloContext } from '../../app' import { getPageInfo } from '../../shared/pagination' import { Pagination, SortOrder } from '../../shared/baseModel' +import { GraphQLError } from 'graphql' +import { GraphQLErrorCode } from '../errors' export const getOutgoingPayment: QueryResolvers['outgoingPayment'] = async (parent, args, ctx): Promise => { @@ -25,7 +26,13 @@ export const getOutgoingPayment: QueryResolvers['outgoingPayment' const payment = await outgoingPaymentService.get({ id: args.id }) - if (!payment) throw new Error('payment does not exist') + if (!payment) { + throw new GraphQLError('payment does not exist', { + extensions: { + code: GraphQLErrorCode.NotFound + } + }) + } return paymentToGraphql(payment) } @@ -39,26 +46,21 @@ export const cancelOutgoingPayment: MutationResolvers['cancelOutg 'outgoingPaymentService' ) - return outgoingPaymentService - .cancel(args.input) - .then((paymentOrError: OutgoingPayment | OutgoingPaymentError) => - isOutgoingPaymentError(paymentOrError) - ? { - code: errorToCode[paymentOrError].toString(), - success: false, - message: errorToMessage[paymentOrError] - } - : { - code: '200', - success: true, - payment: paymentToGraphql(paymentOrError) - } - ) - .catch(() => ({ - code: '500', - success: false, - message: 'Error trying to cancel outgoing payment' - })) + const outgoingPaymentOrError = await outgoingPaymentService.cancel( + args.input + ) + + if (isOutgoingPaymentError(outgoingPaymentOrError)) { + throw new GraphQLError(errorToMessage[outgoingPaymentOrError], { + extensions: { + code: errorToCode[outgoingPaymentOrError] + } + }) + } else { + return { + payment: paymentToGraphql(outgoingPaymentOrError) + } + } } export const createOutgoingPayment: MutationResolvers['createOutgoingPayment'] = @@ -70,26 +72,19 @@ export const createOutgoingPayment: MutationResolvers['createOutg const outgoingPaymentService = await ctx.container.use( 'outgoingPaymentService' ) - return outgoingPaymentService - .create(args.input) - .then((paymentOrErr: OutgoingPayment | OutgoingPaymentError) => - isOutgoingPaymentError(paymentOrErr) - ? { - code: errorToCode[paymentOrErr].toString(), - success: false, - message: errorToMessage[paymentOrErr] - } - : { - code: '201', - success: true, - payment: paymentToGraphql(paymentOrErr) - } - ) - .catch(() => ({ - code: '500', - success: false, - message: 'Error trying to create outgoing payment' - })) + const outgoingPaymentOrError = await outgoingPaymentService.create( + args.input + ) + if (isOutgoingPaymentError(outgoingPaymentOrError)) { + throw new GraphQLError(errorToMessage[outgoingPaymentOrError], { + extensions: { + code: errorToCode[outgoingPaymentOrError] + } + }) + } else + return { + payment: paymentToGraphql(outgoingPaymentOrError) + } } export const createOutgoingPaymentFromIncomingPayment: MutationResolvers['createOutgoingPaymentFromIncomingPayment'] = @@ -101,26 +96,22 @@ export const createOutgoingPaymentFromIncomingPayment: MutationResolvers - isOutgoingPaymentError(paymentOrErr) - ? { - code: errorToCode[paymentOrErr].toString(), - success: false, - message: errorToMessage[paymentOrErr] - } - : { - code: '201', - success: true, - payment: paymentToGraphql(paymentOrErr) - } - ) - .catch(() => ({ - code: '500', - success: false, - message: 'Error trying to create outgoing payment' - })) + + const outgoingPaymentOrError = await outgoingPaymentService.create( + args.input + ) + + if (isOutgoingPaymentError(outgoingPaymentOrError)) { + throw new GraphQLError(errorToMessage[outgoingPaymentOrError], { + extensions: { + code: errorToCode[outgoingPaymentOrError] + } + }) + } else { + return { + payment: paymentToGraphql(outgoingPaymentOrError) + } + } } export const getWalletAddressOutgoingPayments: WalletAddressResolvers['outgoingPayments'] = @@ -129,7 +120,13 @@ export const getWalletAddressOutgoingPayments: WalletAddressResolvers => { - if (!parent.id) throw new Error('missing wallet address id') + if (!parent.id) { + throw new GraphQLError('missing wallet address id', { + extensions: { + code: GraphQLErrorCode.BadUserInput + } + }) + } const outgoingPaymentService = await ctx.container.use( 'outgoingPaymentService' ) diff --git a/packages/backend/src/graphql/resolvers/peer.test.ts b/packages/backend/src/graphql/resolvers/peer.test.ts index a24997566b..deec0406af 100644 --- a/packages/backend/src/graphql/resolvers/peer.test.ts +++ b/packages/backend/src/graphql/resolvers/peer.test.ts @@ -1,8 +1,7 @@ import { faker } from '@faker-js/faker' -import { gql } from '@apollo/client' +import { ApolloError, gql } from '@apollo/client' import assert from 'assert' import { v4 as uuid } from 'uuid' -import { ApolloError } from '@apollo/client' import { getPageTests } from './page.test' import { createTestApp, TestContainer } from '../../tests/app' @@ -13,8 +12,8 @@ import { initIocContainer } from '../..' import { Config } from '../../config/app' import { truncateTables } from '../../tests/tableManager' import { - errorToCode, errorToMessage, + errorToCode, PeerError } from '../../payment-method/ilp/peer/errors' import { Peer as PeerModel } from '../../payment-method/ilp/peer/model' @@ -26,9 +25,11 @@ import { CreatePeerInput, CreatePeerMutationResponse, PeersConnection, - UpdatePeerMutationResponse + UpdatePeerMutationResponse, + DeletePeerMutationResponse } from '../generated/graphql' import { AccountingService } from '../../accounting/service' +import { GraphQLErrorCode } from '../errors' describe('Peer Resolvers', (): void => { let deps: IocContract @@ -83,9 +84,6 @@ describe('Peer Resolvers', (): void => { mutation: gql` mutation CreatePeer($input: CreatePeerInput!) { createPeer(input: $input) { - code - success - message peer { id asset { @@ -119,8 +117,6 @@ describe('Peer Resolvers', (): void => { } }) - expect(response.success).toBe(true) - expect(response.code).toEqual('200') assert.ok(response.peer) expect(response.peer).toEqual({ __typename: 'Peer', @@ -161,75 +157,86 @@ describe('Peer Resolvers', (): void => { ${PeerError.UnknownAsset} ${PeerError.DuplicatePeer} ${PeerError.InvalidInitialLiquidity} - `('4XX - $error', async ({ error }): Promise => { - jest.spyOn(peerService, 'create').mockResolvedValueOnce(error) + `('Error - $error', async ({ error: testError }): Promise => { + jest.spyOn(peerService, 'create').mockResolvedValueOnce(testError) const peer = randomPeer() - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreatePeer($input: CreatePeerInput!) { - createPeer(input: $input) { - code - success - message - peer { - id + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreatePeer($input: CreatePeerInput!) { + createPeer(input: $input) { + peer { + id + } } } + `, + variables: { + input: peer } - `, - variables: { - input: peer - } - }) - .then((query): CreatePeerMutationResponse => { - if (query.data) { - return query.data.createPeer - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual(errorToCode[error as PeerError].toString()) - expect(response.message).toEqual(errorToMessage[error as PeerError]) + }) + .then((query): CreatePeerMutationResponse => { + if (query.data) { + return query.data.createPeer + } else { + throw new Error('Data was empty') + } + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[testError as PeerError], + extensions: expect.objectContaining({ + code: errorToCode[testError as PeerError] + }) + }) + ) + } }) - test('500', async (): Promise => { + test('internal server error', async (): Promise => { jest .spyOn(peerService, 'create') .mockImplementationOnce(async (_args) => { throw new Error('unexpected') }) - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreatePeer($input: CreatePeerInput!) { - createPeer(input: $input) { - code - success - message - peer { - id + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreatePeer($input: CreatePeerInput!) { + createPeer(input: $input) { + peer { + id + } } } + `, + variables: { + input: randomPeer() } - `, - variables: { - input: randomPeer() - } - }) - .then((query): CreatePeerMutationResponse => { - if (query.data) { - return query.data.createPeer - } else { - throw new Error('Data was empty') - } - }) - expect(response.code).toBe('500') - expect(response.success).toBe(false) - expect(response.message).toBe('Error trying to create peer') + }) + .then((query): CreatePeerMutationResponse => { + if (query.data) { + return query.data.createPeer + } else { + throw new Error('Data was empty') + } + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'unexpected', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.InternalServerError + }) + }) + ) + } }) }) @@ -325,32 +332,42 @@ describe('Peer Resolvers', (): void => { }) test('Returns error for unknown peer', async (): Promise => { - const gqlQuery = appContainer.apolloClient - .query({ - query: gql` - query Peer($peerId: String!) { - peer(id: $peerId) { - id - asset { - code - scale + try { + await appContainer.apolloClient + .query({ + query: gql` + query Peer($peerId: String!) { + peer(id: $peerId) { + id + asset { + code + scale + } } } + `, + variables: { + peerId: uuid() } - `, - variables: { - peerId: uuid() - } - }) - .then((query): GraphQLPeer => { - if (query.data) { - return query.data.peer - } else { - throw new Error('Data was empty') - } - }) - - await expect(gqlQuery).rejects.toThrow(ApolloError) + }) + .then((query): GraphQLPeer => { + if (query.data) { + return query.data.peer + } else { + throw new Error('Data was empty') + } + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[PeerError.UnknownPeer], + extensions: expect.objectContaining({ + code: errorToCode[PeerError.UnknownPeer] + }) + }) + ) + } }) }) @@ -462,9 +479,6 @@ describe('Peer Resolvers', (): void => { mutation: gql` mutation UpdatePeer($input: UpdatePeerInput!) { updatePeer(input: $input) { - code - success - message peer { id maxPacketAmount @@ -493,8 +507,6 @@ describe('Peer Resolvers', (): void => { } }) - expect(response.success).toBe(true) - expect(response.code).toEqual('200') expect(response.peer).toEqual({ __typename: 'Peer', ...updateOptions, @@ -527,40 +539,45 @@ describe('Peer Resolvers', (): void => { ${PeerError.InvalidStaticIlpAddress} ${PeerError.InvalidHTTPEndpoint} ${PeerError.UnknownPeer} - `('4XX - $error', async ({ error }): Promise => { - jest.spyOn(peerService, 'update').mockResolvedValueOnce(error) - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation UpdatePeer($input: UpdatePeerInput!) { - updatePeer(input: $input) { - code - success - message - peer { - id + `('Error - $error', async ({ error: testError }): Promise => { + jest.spyOn(peerService, 'update').mockResolvedValueOnce(testError) + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation UpdatePeer($input: UpdatePeerInput!) { + updatePeer(input: $input) { + peer { + id + } } } + `, + variables: { + input: { + id: peer.id, + maxPacketAmount: '100' + } } - `, - variables: { - input: { - id: peer.id, - maxPacketAmount: '100' + }) + .then((query): UpdatePeerMutationResponse => { + if (query.data) { + return query.data.updatePeer + } else { + throw new Error('Data was empty') } - } - }) - .then((query): UpdatePeerMutationResponse => { - if (query.data) { - return query.data.updatePeer - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual(errorToCode[error as PeerError].toString()) - expect(response.message).toEqual(errorToMessage[error as PeerError]) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[testError as PeerError], + extensions: expect.objectContaining({ + code: errorToCode[testError as PeerError] + }) + }) + ) + } }) test('Returns error if unexpected error', async (): Promise => { @@ -568,47 +585,52 @@ describe('Peer Resolvers', (): void => { throw new Error('unexpected') }) - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation UpdatePeer($input: UpdatePeerInput!) { - updatePeer(input: $input) { - code - success - message - peer { - id - maxPacketAmount - http { - outgoing { - authToken - endpoint + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation UpdatePeer($input: UpdatePeerInput!) { + updatePeer(input: $input) { + peer { + id + maxPacketAmount + http { + outgoing { + authToken + endpoint + } } + staticIlpAddress + name } - staticIlpAddress - name } } + `, + variables: { + input: { + id: peer.id, + maxPacketAmount: '100' + } } - `, - variables: { - input: { - id: peer.id, - maxPacketAmount: '100' + }) + .then((query): UpdatePeerMutationResponse => { + if (query.data) { + return query.data.updatePeer + } else { + throw new Error('Data was empty') } - } - }) - .then((query): UpdatePeerMutationResponse => { - if (query.data) { - return query.data.updatePeer - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('500') - expect(response.message).toEqual('Error trying to update peer') + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'unexpected', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.InternalServerError + }) + }) + ) + } }) }) @@ -625,9 +647,7 @@ describe('Peer Resolvers', (): void => { mutation: gql` mutation DeletePeer($input: DeletePeerInput!) { deletePeer(input: $input) { - code success - message } } `, @@ -637,7 +657,7 @@ describe('Peer Resolvers', (): void => { } } }) - .then((query): UpdatePeerMutationResponse => { + .then((query): DeletePeerMutationResponse => { if (query.data) { return query.data.deletePeer } else { @@ -646,77 +666,84 @@ describe('Peer Resolvers', (): void => { }) expect(response.success).toBe(true) - expect(response.code).toEqual('200') - expect(response.message).toEqual('Deleted ILP Peer') await expect(peerService.get(peer.id)).resolves.toBeUndefined() }) test('Returns error for unknown peer', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation DeletePeer($input: DeletePeerInput!) { - deletePeer(input: $input) { - code - success - message + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation DeletePeer($input: DeletePeerInput!) { + deletePeer(input: $input) { + success + } + } + `, + variables: { + input: { + id: uuid() } } - `, - variables: { - input: { - id: uuid() + }) + .then((query): DeletePeerMutationResponse => { + if (query.data) { + return query.data.deletePeer + } else { + throw new Error('Data was empty') } - } - }) - .then((query): UpdatePeerMutationResponse => { - if (query.data) { - return query.data.deletePeer - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual( - errorToCode[PeerError.UnknownPeer].toString() - ) - expect(response.message).toEqual(errorToMessage[PeerError.UnknownPeer]) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[PeerError.UnknownPeer], + extensions: expect.objectContaining({ + code: errorToCode[PeerError.UnknownPeer] + }) + }) + ) + } }) test('Returns error if unexpected error', async (): Promise => { jest.spyOn(peerService, 'delete').mockImplementationOnce(async () => { throw new Error('unexpected') }) - - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation DeletePeer($input: DeletePeerInput!) { - deletePeer(input: $input) { - code - success - message + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation DeletePeer($input: DeletePeerInput!) { + deletePeer(input: $input) { + success + } + } + `, + variables: { + input: { + id: peer.id } } - `, - variables: { - input: { - id: peer.id + }) + .then((query): DeletePeerMutationResponse => { + if (query.data) { + return query.data.deletePeer + } else { + throw new Error('Data was empty') } - } - }) - .then((query): UpdatePeerMutationResponse => { - if (query.data) { - return query.data.deletePeer - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('500') - expect(response.message).toEqual('Error trying to delete peer') + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'unexpected', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.InternalServerError + }) + }) + ) + } }) }) }) diff --git a/packages/backend/src/graphql/resolvers/peer.ts b/packages/backend/src/graphql/resolvers/peer.ts index 2a93c09737..b2296b7a89 100644 --- a/packages/backend/src/graphql/resolvers/peer.ts +++ b/packages/backend/src/graphql/resolvers/peer.ts @@ -7,14 +7,15 @@ import { } from '../generated/graphql' import { Peer } from '../../payment-method/ilp/peer/model' import { - PeerError, isPeerError, errorToCode, - errorToMessage + errorToMessage, + PeerError } from '../../payment-method/ilp/peer/errors' import { ApolloContext } from '../../app' import { getPageInfo } from '../../shared/pagination' import { Pagination, SortOrder } from '../../shared/baseModel' +import { GraphQLError } from 'graphql' export const getPeers: QueryResolvers['peers'] = async ( parent, @@ -48,7 +49,11 @@ export const getPeer: QueryResolvers['peer'] = async ( const peerService = await ctx.container.use('peerService') const peer = await peerService.get(args.id) if (!peer) { - throw new Error('No peer') + throw new GraphQLError(errorToMessage[PeerError.UnknownPeer], { + extensions: { + code: errorToCode[PeerError.UnknownPeer] + } + }) } return peerToGraphql(peer) } @@ -60,36 +65,17 @@ export const createPeer: MutationResolvers['createPeer'] = ctx ): Promise => { const peerService = await ctx.container.use('peerService') - return peerService - .create(args.input) - .then((peerOrError: Peer | PeerError) => - isPeerError(peerOrError) - ? { - code: errorToCode[peerOrError].toString(), - success: false, - message: errorToMessage[peerOrError] - } - : { - code: '200', - success: true, - message: 'Created ILP Peer', - peer: peerToGraphql(peerOrError) - } - ) - .catch((err) => { - ctx.logger.error( - { - options: args.input, - err - }, - 'error creating peer' - ) - return { - code: '500', - success: false, - message: 'Error trying to create peer' + const peerOrError = await peerService.create(args.input) + if (isPeerError(peerOrError)) { + throw new GraphQLError(errorToMessage[peerOrError], { + extensions: { + code: errorToCode[peerOrError] } }) + } + return { + peer: peerToGraphql(peerOrError) + } } export const updatePeer: MutationResolvers['updatePeer'] = @@ -99,36 +85,17 @@ export const updatePeer: MutationResolvers['updatePeer'] = ctx ): Promise => { const peerService = await ctx.container.use('peerService') - return peerService - .update(args.input) - .then((peerOrError: Peer | PeerError) => - isPeerError(peerOrError) - ? { - code: errorToCode[peerOrError].toString(), - success: false, - message: errorToMessage[peerOrError] - } - : { - code: '200', - success: true, - message: 'Updated ILP Peer', - peer: peerToGraphql(peerOrError) - } - ) - .catch((err) => { - ctx.logger.error( - { - options: args.input, - err - }, - 'error updating peer' - ) - return { - code: '500', - message: 'Error trying to update peer', - success: false + const peerOrError = await peerService.update(args.input) + if (isPeerError(peerOrError)) { + throw new GraphQLError(errorToMessage[peerOrError], { + extensions: { + code: errorToCode[peerOrError] } }) + } + return { + peer: peerToGraphql(peerOrError) + } } export const deletePeer: MutationResolvers['deletePeer'] = @@ -138,35 +105,17 @@ export const deletePeer: MutationResolvers['deletePeer'] = ctx ): Promise => { const peerService = await ctx.container.use('peerService') - return peerService - .delete(args.input.id) - .then((peer: Peer | undefined) => - peer - ? { - code: '200', - success: true, - message: 'Deleted ILP Peer' - } - : { - code: errorToCode[PeerError.UnknownPeer].toString(), - success: false, - message: errorToMessage[PeerError.UnknownPeer] - } - ) - .catch((err) => { - ctx.logger.error( - { - id: args.input.id, - err - }, - 'error deleting peer' - ) - return { - code: '500', - message: 'Error trying to delete peer', - success: false + const peer = await peerService.delete(args.input.id) + if (!peer) { + throw new GraphQLError(errorToMessage[PeerError.UnknownPeer], { + extensions: { + code: errorToCode[PeerError.UnknownPeer] } }) + } + return { + success: true + } } export const peerToGraphql = (peer: Peer): SchemaPeer => ({ diff --git a/packages/backend/src/graphql/resolvers/quote.test.ts b/packages/backend/src/graphql/resolvers/quote.test.ts index 1f39f81952..8202a6f410 100644 --- a/packages/backend/src/graphql/resolvers/quote.test.ts +++ b/packages/backend/src/graphql/resolvers/quote.test.ts @@ -1,4 +1,4 @@ -import { gql } from '@apollo/client' +import { gql, ApolloError } from '@apollo/client' import { v4 as uuid } from 'uuid' import { getPageTests } from './page.test' @@ -12,11 +12,16 @@ import { createAsset } from '../../tests/asset' import { createWalletAddress } from '../../tests/walletAddress' import { createQuote } from '../../tests/quote' import { truncateTables } from '../../tests/tableManager' -import { QuoteError, errorToMessage } from '../../open_payments/quote/errors' +import { + QuoteError, + errorToMessage, + errorToCode +} from '../../open_payments/quote/errors' import { QuoteService } from '../../open_payments/quote/service' import { Quote as QuoteModel } from '../../open_payments/quote/model' import { Amount } from '../../open_payments/amount' import { CreateQuoteInput, Quote, QuoteResponse } from '../generated/graphql' +import { GraphQLErrorCode } from '../errors' describe('Quote Resolvers', (): void => { let deps: IocContract @@ -64,7 +69,7 @@ describe('Quote Resolvers', (): void => { } describe('Query.quote', (): void => { - test('200', async (): Promise => { + test('success', async (): Promise => { const { id: walletAddressId } = await createWalletAddress(deps, { assetId: asset.id }) @@ -129,11 +134,11 @@ describe('Quote Resolvers', (): void => { }) }) - test('404', async (): Promise => { + test('Not found', async (): Promise => { jest.spyOn(quoteService, 'get').mockImplementation(async () => undefined) - await expect( - appContainer.apolloClient.query({ + try { + await appContainer.apolloClient.query({ query: gql` query Quote($quoteId: String!) { quote(id: $quoteId) { @@ -143,7 +148,17 @@ describe('Quote Resolvers', (): void => { `, variables: { quoteId: uuid() } }) - ).rejects.toThrow('quote does not exist') + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'quote does not exist', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.NotFound + }) + }) + ) + } }) }) @@ -178,7 +193,7 @@ describe('Quote Resolvers', (): void => { ${true} | ${undefined} | ${'fixed send to incoming payment'} ${false} | ${receiveAmount} | ${'fixed receive to incoming payment'} ${false} | ${undefined} | ${'incoming payment'} - `('200 ($type)', async ({ withAmount, receiveAmount }): Promise => { + `('$type', async ({ withAmount, receiveAmount }): Promise => { const amount = withAmount ? debitAmount : undefined const { id: walletAddressId } = await createWalletAddress(deps, { assetId: asset.id @@ -206,8 +221,6 @@ describe('Quote Resolvers', (): void => { query: gql` mutation CreateQuote($input: CreateQuoteInput!) { createQuote(input: $input) { - code - success quote { id } @@ -219,64 +232,70 @@ describe('Quote Resolvers', (): void => { .then((query): QuoteResponse => query.data?.createQuote) expect(createSpy).toHaveBeenCalledWith({ ...input, method: 'ilp' }) - expect(query.code).toBe('200') - expect(query.success).toBe(true) expect(query.quote?.id).toBe(quote?.id) }) - test('400', async (): Promise => { - const query = await appContainer.apolloClient - .query({ - query: gql` - mutation CreateQuote($input: CreateQuoteInput!) { - createQuote(input: $input) { - code - success - message - quote { - id + test('unknown walletAddress', async (): Promise => { + try { + await appContainer.apolloClient + .query({ + query: gql` + mutation CreateQuote($input: CreateQuoteInput!) { + createQuote(input: $input) { + quote { + id + } } } - } - `, - variables: { input } - }) - .then((query): QuoteResponse => query.data?.createQuote) - expect(query.code).toBe('404') - expect(query.success).toBe(false) - expect(query.message).toBe( - errorToMessage[QuoteError.UnknownWalletAddress] - ) - expect(query.quote).toBeNull() + `, + variables: { input } + }) + .then((query): QuoteResponse => query.data?.createQuote) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[QuoteError.UnknownWalletAddress], + extensions: expect.objectContaining({ + code: errorToCode[QuoteError.UnknownWalletAddress] + }) + }) + ) + } }) - test('500', async (): Promise => { + test('unknown error', async (): Promise => { const createSpy = jest .spyOn(quoteService, 'create') .mockRejectedValueOnce(new Error('unexpected')) - const query = await appContainer.apolloClient - .query({ - query: gql` - mutation CreateQuote($input: CreateQuoteInput!) { - createQuote(input: $input) { - code - success - message - quote { - id + try { + await appContainer.apolloClient + .query({ + query: gql` + mutation CreateQuote($input: CreateQuoteInput!) { + createQuote(input: $input) { + quote { + id + } } } - } - `, - variables: { input } - }) - .then((query): QuoteResponse => query.data?.createQuote) + `, + variables: { input } + }) + .then((query): QuoteResponse => query.data?.createQuote) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'unexpected', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.InternalServerError + }) + }) + ) + } expect(createSpy).toHaveBeenCalledWith({ ...input, method: 'ilp' }) - expect(query.code).toBe('500') - expect(query.success).toBe(false) - expect(query.message).toBe('Error trying to create quote') - expect(query.quote).toBeNull() }) }) diff --git a/packages/backend/src/graphql/resolvers/quote.ts b/packages/backend/src/graphql/resolvers/quote.ts index 32bd77056a..638c0fecde 100644 --- a/packages/backend/src/graphql/resolvers/quote.ts +++ b/packages/backend/src/graphql/resolvers/quote.ts @@ -6,7 +6,6 @@ import { ResolversTypes } from '../generated/graphql' import { - QuoteError, isQuoteError, errorToCode, errorToMessage @@ -16,6 +15,8 @@ import { ApolloContext } from '../../app' import { getPageInfo } from '../../shared/pagination' import { Pagination, SortOrder } from '../../shared/baseModel' import { CreateQuoteOptions } from '../../open_payments/quote/service' +import { GraphQLError } from 'graphql' +import { GraphQLErrorCode } from '../errors' export const getQuote: QueryResolvers['quote'] = async ( parent, @@ -26,7 +27,13 @@ export const getQuote: QueryResolvers['quote'] = async ( const quote = await quoteService.get({ id: args.id }) - if (!quote) throw new Error('quote does not exist') + if (!quote) { + throw new GraphQLError('quote does not exist', { + extensions: { + code: GraphQLErrorCode.NotFound + } + }) + } return quoteToGraphql(quote) } @@ -41,31 +48,28 @@ export const createQuote: MutationResolvers['createQuote'] = if (args.input.debitAmount) options.debitAmount = args.input.debitAmount if (args.input.receiveAmount) options.receiveAmount = args.input.receiveAmount - return quoteService - .create(options) - .then((quoteOrErr: Quote | QuoteError) => - isQuoteError(quoteOrErr) - ? { - code: errorToCode[quoteOrErr].toString(), - success: false, - message: errorToMessage[quoteOrErr] - } - : { - code: '200', - success: true, - quote: quoteToGraphql(quoteOrErr) - } - ) - .catch(() => ({ - code: '500', - success: false, - message: 'Error trying to create quote' - })) + const quoteOrError = await quoteService.create(options) + if (isQuoteError(quoteOrError)) { + throw new GraphQLError(errorToMessage[quoteOrError], { + extensions: { + code: errorToCode[quoteOrError] + } + }) + } else + return { + quote: quoteToGraphql(quoteOrError) + } } export const getWalletAddressQuotes: WalletAddressResolvers['quotes'] = async (parent, args, ctx): Promise => { - if (!parent.id) throw new Error('missing wallet address id') + if (!parent.id) { + throw new GraphQLError('missing wallet address id', { + extensions: { + code: GraphQLErrorCode.BadUserInput + } + }) + } const quoteService = await ctx.container.use('quoteService') const { sortOrder, ...pagination } = args const order = sortOrder === 'ASC' ? SortOrder.Asc : SortOrder.Desc diff --git a/packages/backend/src/graphql/resolvers/receiver.test.ts b/packages/backend/src/graphql/resolvers/receiver.test.ts index 42339016e8..8b0988ea90 100644 --- a/packages/backend/src/graphql/resolvers/receiver.test.ts +++ b/packages/backend/src/graphql/resolvers/receiver.test.ts @@ -1,4 +1,4 @@ -import { gql } from '@apollo/client' +import { ApolloError, gql } from '@apollo/client' import { v4 as uuid } from 'uuid' import { createTestApp, TestContainer } from '../../tests/app' import { IocContract } from '@adonisjs/fold' @@ -13,7 +13,12 @@ import { import { CreateReceiverResponse } from '../generated/graphql' import { ReceiverService } from '../../open_payments/receiver/service' import { Receiver } from '../../open_payments/receiver/model' -import { ReceiverError } from '../../open_payments/receiver/errors' +import { + ReceiverError, + errorToMessage, + errorToCode +} from '../../open_payments/receiver/errors' +import { GraphQLErrorCode } from '../errors' describe('Receiver Resolver', (): void => { let deps: IocContract @@ -74,9 +79,6 @@ describe('Receiver Resolver', (): void => { query: gql` mutation CreateReceiver($input: CreateReceiverInput!) { createReceiver(input: $input) { - code - success - message receiver { id walletAddressUrl @@ -106,9 +108,6 @@ describe('Receiver Resolver', (): void => { expect(createSpy).toHaveBeenCalledWith(input) expect(query).toEqual({ __typename: 'CreateReceiverResponse', - code: '200', - success: true, - message: null, receiver: { __typename: 'Receiver', id: receiver.incomingPayment?.id, @@ -144,48 +143,49 @@ describe('Receiver Resolver', (): void => { walletAddressUrl: walletAddress.id } - const query = await appContainer.apolloClient - .query({ - query: gql` - mutation CreateReceiver($input: CreateReceiverInput!) { - createReceiver(input: $input) { - code - success - message - receiver { - id - walletAddressUrl - completed - expiresAt - incomingAmount { - value - assetCode - assetScale - } - receivedAmount { - value - assetCode - assetScale + try { + await appContainer.apolloClient + .query({ + query: gql` + mutation CreateReceiver($input: CreateReceiverInput!) { + createReceiver(input: $input) { + receiver { + id + walletAddressUrl + completed + expiresAt + incomingAmount { + value + assetCode + assetScale + } + receivedAmount { + value + assetCode + assetScale + } + metadata + createdAt + updatedAt } - metadata - createdAt - updatedAt } } - } - `, - variables: { input } - }) - .then((query): CreateReceiverResponse => query.data?.createReceiver) - + `, + variables: { input } + }) + .then((query): CreateReceiverResponse => query.data?.createReceiver) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage(ReceiverError.UnknownWalletAddress), + extensions: expect.objectContaining({ + code: errorToCode(ReceiverError.UnknownWalletAddress) + }) + }) + ) + } expect(createSpy).toHaveBeenCalledWith(input) - expect(query).toEqual({ - __typename: 'CreateReceiverResponse', - code: '404', - success: false, - message: 'unknown wallet address', - receiver: null - }) }) test('returns error if error thrown when creating receiver', async (): Promise => { @@ -199,48 +199,49 @@ describe('Receiver Resolver', (): void => { walletAddressUrl: walletAddress.id } - const query = await appContainer.apolloClient - .query({ - query: gql` - mutation CreateReceiver($input: CreateReceiverInput!) { - createReceiver(input: $input) { - code - success - message - receiver { - id - walletAddressUrl - completed - expiresAt - incomingAmount { - value - assetCode - assetScale - } - receivedAmount { - value - assetCode - assetScale + try { + await appContainer.apolloClient + .query({ + query: gql` + mutation CreateReceiver($input: CreateReceiverInput!) { + createReceiver(input: $input) { + receiver { + id + walletAddressUrl + completed + expiresAt + incomingAmount { + value + assetCode + assetScale + } + receivedAmount { + value + assetCode + assetScale + } + metadata + createdAt + updatedAt } - metadata - createdAt - updatedAt } } - } - `, - variables: { input } - }) - .then((query): CreateReceiverResponse => query.data?.createReceiver) - + `, + variables: { input } + }) + .then((query): CreateReceiverResponse => query.data?.createReceiver) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Cannot create receiver', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.InternalServerError + }) + }) + ) + } expect(createSpy).toHaveBeenCalledWith(input) - expect(query).toEqual({ - __typename: 'CreateReceiverResponse', - code: '500', - success: false, - message: 'Error trying to create receiver', - receiver: null - }) }) }) @@ -312,23 +313,35 @@ describe('Receiver Resolver', (): void => { }) }) - test('404', async (): Promise => { + test('not found', async (): Promise => { jest .spyOn(receiverService, 'get') .mockImplementation(async () => undefined) - await expect( - appContainer.apolloClient.query({ - query: gql` - query GetReceiver($id: String!) { - receiver(id: $id) { - id + try { + await expect( + appContainer.apolloClient.query({ + query: gql` + query GetReceiver($id: String!) { + receiver(id: $id) { + id + } } - } - `, - variables: { id: uuid() } - }) - ).rejects.toThrow('receiver does not exist') + `, + variables: { id: uuid() } + }) + ).rejects.toThrow('receiver does not exist') + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'receiver does not exist', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.NotFound + }) + }) + ) + } }) }) }) diff --git a/packages/backend/src/graphql/resolvers/receiver.ts b/packages/backend/src/graphql/resolvers/receiver.ts index b2e10fc7ce..b9002c30f1 100644 --- a/packages/backend/src/graphql/resolvers/receiver.ts +++ b/packages/backend/src/graphql/resolvers/receiver.ts @@ -11,6 +11,8 @@ import { errorToCode as receiverErrorToCode, errorToMessage as receiverErrorToMessage } from '../../open_payments/receiver/errors' +import { GraphQLError } from 'graphql' +import { GraphQLErrorCode } from '../errors' export const getReceiver: QueryResolvers['receiver'] = async ( _, @@ -21,7 +23,11 @@ export const getReceiver: QueryResolvers['receiver'] = async ( const receiver = await receiverService.get(args.id) if (!receiver) { ctx.logger.error(`Receiver "${args.id}" was not found.`) - throw new Error('receiver does not exist') + throw new GraphQLError('receiver does not exist', { + extensions: { + code: GraphQLErrorCode.NotFound + } + }) } return receiverToGraphql(receiver) } @@ -30,38 +36,25 @@ export const createReceiver: MutationResolvers['createReceiver'] async (_, args, ctx): Promise => { const receiverService = await ctx.container.use('receiverService') - try { - const receiverOrError = await receiverService.create({ - walletAddressUrl: args.input.walletAddressUrl, - expiresAt: args.input.expiresAt - ? new Date(args.input.expiresAt) - : undefined, - incomingAmount: args.input.incomingAmount, - metadata: args.input.metadata - }) + const receiverOrError = await receiverService.create({ + walletAddressUrl: args.input.walletAddressUrl, + expiresAt: args.input.expiresAt + ? new Date(args.input.expiresAt) + : undefined, + incomingAmount: args.input.incomingAmount, + metadata: args.input.metadata + }) - if (isReceiverError(receiverOrError)) { - return { - code: receiverErrorToCode(receiverOrError).toString(), - success: false, - message: receiverErrorToMessage(receiverOrError) + if (isReceiverError(receiverOrError)) { + throw new GraphQLError(receiverErrorToMessage(receiverOrError), { + extensions: { + code: receiverErrorToCode(receiverOrError) } - } - - return { - code: '200', - success: true, - receiver: receiverToGraphql(receiverOrError) - } - } catch (err) { - const errorMessage = 'Error trying to create receiver' - ctx.logger.error({ err, args }, errorMessage) + }) + } - return { - code: '500', - success: false, - message: errorMessage - } + return { + receiver: receiverToGraphql(receiverOrError) } } diff --git a/packages/backend/src/graphql/resolvers/walletAddressKey.test.ts b/packages/backend/src/graphql/resolvers/walletAddressKey.test.ts index c0f0fbf272..69db46f44b 100644 --- a/packages/backend/src/graphql/resolvers/walletAddressKey.test.ts +++ b/packages/backend/src/graphql/resolvers/walletAddressKey.test.ts @@ -1,5 +1,5 @@ import assert from 'assert' -import { gql } from '@apollo/client' +import { ApolloError, gql } from '@apollo/client' import { generateJwk } from '@interledger/http-signature-utils' import { v4 as uuid } from 'uuid' @@ -19,6 +19,7 @@ import { WalletAddressKeyService } from '../../open_payments/wallet_address/key/ import { createWalletAddress } from '../../tests/walletAddress' import { getPageTests } from './page.test' import { createWalletAddressKey } from '../../tests/walletAddressKey' +import { GraphQLErrorCode } from '../errors' const TEST_KEY = generateJwk({ keyId: uuid() }) @@ -58,9 +59,6 @@ describe('Wallet Address Key Resolvers', (): void => { $input: CreateWalletAddressKeyInput! ) { createWalletAddressKey(input: $input) { - code - success - message walletAddressKey { id walletAddressId @@ -89,8 +87,6 @@ describe('Wallet Address Key Resolvers', (): void => { } }) - expect(response.success).toBe(true) - expect(response.code).toEqual('200') assert.ok(response.walletAddressKey) expect(response.walletAddressKey).toMatchObject({ __typename: 'WalletAddressKey', @@ -103,7 +99,7 @@ describe('Wallet Address Key Resolvers', (): void => { }) }) - test('500', async (): Promise => { + test('internal server error', async (): Promise => { jest .spyOn(walletAddressKeyService, 'create') .mockImplementationOnce(async (_args) => { @@ -117,45 +113,51 @@ describe('Wallet Address Key Resolvers', (): void => { jwk: TEST_KEY } - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateWalletAddressKey( - $input: CreateWalletAddressKeyInput! - ) { - createWalletAddressKey(input: $input) { - code - success - message - walletAddressKey { - id - walletAddressId - jwk { - kid - x - alg - kty - crv + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateWalletAddressKey( + $input: CreateWalletAddressKeyInput! + ) { + createWalletAddressKey(input: $input) { + walletAddressKey { + id + walletAddressId + jwk { + kid + x + alg + kty + crv + } + createdAt } - createdAt } } + `, + variables: { + input } - `, - variables: { - input - } - }) - .then((query): CreateWalletAddressKeyMutationResponse => { - if (query.data) { - return query.data.createWalletAddressKey - } else { - throw new Error('Data was empty') - } - }) - expect(response.code).toBe('500') - expect(response.success).toBe(false) - expect(response.message).toBe('Error trying to create wallet address key') + }) + .then((query): CreateWalletAddressKeyMutationResponse => { + if (query.data) { + return query.data.createWalletAddressKey + } else { + throw new Error('Data was empty') + } + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'unexpected', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.InternalServerError + }) + }) + ) + } }) }) @@ -175,9 +177,6 @@ describe('Wallet Address Key Resolvers', (): void => { $input: RevokeWalletAddressKeyInput! ) { revokeWalletAddressKey(input: $input) { - code - success - message walletAddressKey { id walletAddressId @@ -207,8 +206,6 @@ describe('Wallet Address Key Resolvers', (): void => { } }) - expect(response.success).toBe(true) - expect(response.code).toBe('200') assert.ok(response.walletAddressKey) expect(response.walletAddressKey).toMatchObject({ __typename: 'WalletAddressKey', @@ -222,42 +219,46 @@ describe('Wallet Address Key Resolvers', (): void => { }) }) - test('Returns 404 if key does not exist', async (): Promise => { - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation revokeWalletAddressKey( - $input: RevokeWalletAddressKeyInput! - ) { - revokeWalletAddressKey(input: $input) { - code - success - message - walletAddressKey { - id - walletAddressId + test('Returns not found if key does not exist', async (): Promise => { + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation revokeWalletAddressKey( + $input: RevokeWalletAddressKeyInput! + ) { + revokeWalletAddressKey(input: $input) { + walletAddressKey { + id + walletAddressId + } } } + `, + variables: { + input: { + id: uuid() + } } - `, - variables: { - input: { - id: uuid() + }) + .then((query): RevokeWalletAddressKeyMutationResponse => { + if (query.data) { + return query.data.revokeWalletAddressKey + } else { + throw new Error('Data was empty') } - } - }) - .then((query): RevokeWalletAddressKeyMutationResponse => { - if (query.data) { - return query.data.revokeWalletAddressKey - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toBe('404') - expect(response.message).toBe('Wallet address key not found') - expect(response.walletAddressKey).toBeNull() + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'Wallet address key not found', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.NotFound + }) + }) + ) + } }) }) diff --git a/packages/backend/src/graphql/resolvers/walletAddressKey.ts b/packages/backend/src/graphql/resolvers/walletAddressKey.ts index d037115f45..7ac40042dc 100644 --- a/packages/backend/src/graphql/resolvers/walletAddressKey.ts +++ b/packages/backend/src/graphql/resolvers/walletAddressKey.ts @@ -10,6 +10,8 @@ import { } from '../generated/graphql' import { ApolloContext } from '../../app' import { WalletAddressKey } from '../../open_payments/wallet_address/key/model' +import { GraphQLError } from 'graphql' +import { GraphQLErrorCode } from '../errors' import { Pagination } from '../../shared/baseModel' import { getPageInfo } from '../../shared/pagination' @@ -56,39 +58,20 @@ export const revokeWalletAddressKey: MutationResolvers['revokeWal args, ctx ): Promise => { - try { - const walletAddressKeyService = await ctx.container.use( - 'walletAddressKeyService' - ) - const key = await walletAddressKeyService.revoke(args.input.id) - if (!key) { - return { - code: '404', - success: false, - message: 'Wallet address key not found' + const walletAddressKeyService = await ctx.container.use( + 'walletAddressKeyService' + ) + const key = await walletAddressKeyService.revoke(args.input.id) + if (!key) { + throw new GraphQLError('Wallet address key not found', { + extensions: { + code: GraphQLErrorCode.NotFound } - } - - return { - code: '200', - success: true, - message: 'Wallet address key revoked', - walletAddressKey: walletAddressKeyToGraphql(key) - } - } catch (err) { - ctx.logger.error( - { - options: args.input.id, - err - }, - 'error revoking wallet address key' - ) + }) + } - return { - code: '500', - message: 'Error trying to revoke wallet address key', - success: false - } + return { + walletAddressKey: walletAddressKeyToGraphql(key) } } @@ -98,33 +81,14 @@ export const createWalletAddressKey: MutationResolvers['createWal args, ctx ): Promise => { - try { - const walletAddressKeyService = await ctx.container.use( - 'walletAddressKeyService' - ) - - const key = await walletAddressKeyService.create(args.input) + const walletAddressKeyService = await ctx.container.use( + 'walletAddressKeyService' + ) - return { - code: '200', - success: true, - message: 'Added Key To Wallet Address', - walletAddressKey: walletAddressKeyToGraphql(key) - } - } catch (err) { - ctx.logger.error( - { - options: args.input, - err - }, - 'error creating wallet address key' - ) + const key = await walletAddressKeyService.create(args.input) - return { - code: '500', - message: 'Error trying to create wallet address key', - success: false - } + return { + walletAddressKey: walletAddressKeyToGraphql(key) } } diff --git a/packages/backend/src/graphql/resolvers/wallet_address.test.ts b/packages/backend/src/graphql/resolvers/wallet_address.test.ts index da3f318a93..d57e3d71b4 100644 --- a/packages/backend/src/graphql/resolvers/wallet_address.test.ts +++ b/packages/backend/src/graphql/resolvers/wallet_address.test.ts @@ -1,8 +1,7 @@ import assert from 'assert' -import { gql } from '@apollo/client' +import { gql, ApolloError } from '@apollo/client' import { Knex } from 'knex' import { v4 as uuid } from 'uuid' -import { ApolloError } from '@apollo/client' import { createTestApp, TestContainer } from '../../tests/app' import { IocContract } from '@adonisjs/fold' @@ -13,8 +12,8 @@ import { Config } from '../../config/app' import { truncateTables } from '../../tests/tableManager' import { WalletAddressError, - errorToCode, - errorToMessage + errorToMessage, + errorToCode } from '../../open_payments/wallet_address/errors' import { WalletAddress as WalletAddressModel, @@ -35,6 +34,7 @@ import { } from '../generated/graphql' import { getPageTests } from './page.test' import { WalletAddressAdditionalProperty } from '../../open_payments/wallet_address/additional_property/model' +import { GraphQLErrorCode } from '../errors' describe('Wallet Address Resolvers', (): void => { let deps: IocContract @@ -83,9 +83,6 @@ describe('Wallet Address Resolvers', (): void => { mutation: gql` mutation CreateWalletAddress($input: CreateWalletAddressInput!) { createWalletAddress(input: $input) { - code - success - message walletAddress { id asset { @@ -110,8 +107,6 @@ describe('Wallet Address Resolvers', (): void => { } }) - expect(response.success).toBe(true) - expect(response.code).toEqual('200') assert.ok(response.walletAddress) expect(response.walletAddress).toEqual({ __typename: 'WalletAddress', @@ -154,9 +149,6 @@ describe('Wallet Address Resolvers', (): void => { mutation: gql` mutation CreateWalletAddress($input: CreateWalletAddressInput!) { createWalletAddress(input: $input) { - code - success - message walletAddress { id asset { @@ -186,8 +178,6 @@ describe('Wallet Address Resolvers', (): void => { } }) - expect(response.success).toBe(true) - expect(response.code).toEqual('200') assert.ok(response.walletAddress) expect(response.walletAddress).toEqual({ __typename: 'WalletAddress', @@ -220,85 +210,94 @@ describe('Wallet Address Resolvers', (): void => { error ${WalletAddressError.InvalidUrl} ${WalletAddressError.UnknownAsset} - `('4XX - $error', async ({ error }): Promise => { - jest.spyOn(walletAddressService, 'create').mockResolvedValueOnce(error) - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateWalletAddress($input: CreateWalletAddressInput!) { - createWalletAddress(input: $input) { - code - success - message - walletAddress { - id - asset { - code - scale + `('Error - $error', async ({ error: testError }): Promise => { + jest + .spyOn(walletAddressService, 'create') + .mockResolvedValueOnce(testError) + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateWalletAddress($input: CreateWalletAddressInput!) { + createWalletAddress(input: $input) { + walletAddress { + id + asset { + code + scale + } } } } + `, + variables: { + input } - `, - variables: { - input - } - }) - .then((query): CreateWalletAddressMutationResponse => { - if (query.data) { - return query.data.createWalletAddress - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual( - errorToCode[error as WalletAddressError].toString() - ) - expect(response.message).toEqual( - errorToMessage[error as WalletAddressError] - ) + }) + .then((query): CreateWalletAddressMutationResponse => { + if (query.data) { + return query.data.createWalletAddress + } else { + throw new Error('Data was empty') + } + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[testError as WalletAddressError], + extensions: expect.objectContaining({ + code: errorToCode[testError as WalletAddressError] + }) + }) + ) + } }) - test('500', async (): Promise => { + test('internal server error', async (): Promise => { jest .spyOn(walletAddressService, 'create') .mockImplementationOnce(async (_args) => { throw new Error('unexpected') }) - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation CreateWalletAddress($input: CreateWalletAddressInput!) { - createWalletAddress(input: $input) { - code - success - message - walletAddress { - id - asset { - code - scale + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation CreateWalletAddress($input: CreateWalletAddressInput!) { + createWalletAddress(input: $input) { + walletAddress { + id + asset { + code + scale + } } } } + `, + variables: { + input } - `, - variables: { - input - } - }) - .then((query): CreateWalletAddressMutationResponse => { - if (query.data) { - return query.data.createWalletAddress - } else { - throw new Error('Data was empty') - } - }) - expect(response.code).toBe('500') - expect(response.success).toBe(false) - expect(response.message).toBe('Error trying to create wallet address') + }) + .then((query): CreateWalletAddressMutationResponse => { + if (query.data) { + return query.data.createWalletAddress + } else { + throw new Error('Data was empty') + } + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'unexpected', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.InternalServerError + }) + }) + ) + } }) }) @@ -320,9 +319,6 @@ describe('Wallet Address Resolvers', (): void => { mutation: gql` mutation UpdateWalletAddress($input: UpdateWalletAddressInput!) { updateWalletAddress(input: $input) { - code - success - message walletAddress { id status @@ -348,8 +344,6 @@ describe('Wallet Address Resolvers', (): void => { } }) - expect(response.success).toBe(true) - expect(response.code).toEqual('200') expect(response.walletAddress).toEqual({ __typename: 'WalletAddress', ...updateOptions, @@ -391,9 +385,6 @@ describe('Wallet Address Resolvers', (): void => { mutation: gql` mutation UpdateWalletAddress($input: UpdateWalletAddressInput!) { updateWalletAddress(input: $input) { - code - success - message walletAddress { id additionalProperties { @@ -417,8 +408,6 @@ describe('Wallet Address Resolvers', (): void => { } }) - expect(response.success).toBe(true) - expect(response.code).toEqual('200') expect(response.walletAddress?.additionalProperties).toEqual( updateOptions.additionalProperties.map((property) => { return { @@ -461,9 +450,6 @@ describe('Wallet Address Resolvers', (): void => { mutation: gql` mutation UpdateWalletAddress($input: UpdateWalletAddressInput!) { updateWalletAddress(input: $input) { - code - success - message walletAddress { id additionalProperties { @@ -487,8 +473,6 @@ describe('Wallet Address Resolvers', (): void => { } }) - expect(response.success).toBe(true) - expect(response.code).toEqual('200') // Does not include additional properties from create that were not also in the update expect(response.walletAddress?.additionalProperties).toEqual( updateOptions.additionalProperties.map((property) => { @@ -520,9 +504,6 @@ describe('Wallet Address Resolvers', (): void => { mutation: gql` mutation UpdateWalletAddress($input: UpdateWalletAddressInput!) { updateWalletAddress(input: $input) { - code - success - message walletAddress { id additionalProperties { @@ -546,8 +527,6 @@ describe('Wallet Address Resolvers', (): void => { } }) - expect(response.success).toBe(true) - expect(response.code).toEqual('200') expect(response.walletAddress?.additionalProperties).toEqual([]) }) }) @@ -557,44 +536,47 @@ describe('Wallet Address Resolvers', (): void => { ${WalletAddressError.InvalidUrl} ${WalletAddressError.UnknownAsset} ${WalletAddressError.UnknownWalletAddress} - `('4XX - $error', async ({ error }): Promise => { - jest.spyOn(walletAddressService, 'update').mockResolvedValueOnce(error) - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation UpdateWalletAddress($input: UpdateWalletAddressInput!) { - updateWalletAddress(input: $input) { - code - success - message - walletAddress { - id + `('$error', async ({ error: testError }): Promise => { + jest + .spyOn(walletAddressService, 'update') + .mockResolvedValueOnce(testError) + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation UpdateWalletAddress($input: UpdateWalletAddressInput!) { + updateWalletAddress(input: $input) { + walletAddress { + id + } } } + `, + variables: { + input: { + id: walletAddress.id, + status: WalletAddressStatus.Inactive + } } - `, - variables: { - input: { - id: walletAddress.id, - status: WalletAddressStatus.Inactive + }) + .then((query): UpdateWalletAddressMutationResponse => { + if (query.data) { + return query.data.updateWalletAddress + } else { + throw new Error('Data was empty') } - } - }) - .then((query): UpdateWalletAddressMutationResponse => { - if (query.data) { - return query.data.updateWalletAddress - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual( - errorToCode[error as WalletAddressError].toString() - ) - expect(response.message).toEqual( - errorToMessage[error as WalletAddressError] - ) + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[testError as WalletAddressError], + extensions: expect.objectContaining({ + code: errorToCode[testError as WalletAddressError] + }) + }) + ) + } }) test('Returns error if unexpected error', async (): Promise => { @@ -603,38 +585,43 @@ describe('Wallet Address Resolvers', (): void => { .mockImplementationOnce(async () => { throw new Error('unexpected') }) - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation UpdateWalletAddress($input: UpdateWalletAddressInput!) { - updateWalletAddress(input: $input) { - code - success - message - walletAddress { - id + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation UpdateWalletAddress($input: UpdateWalletAddressInput!) { + updateWalletAddress(input: $input) { + walletAddress { + id + } } } + `, + variables: { + input: { + id: walletAddress.id, + status: WalletAddressStatus.Inactive + } } - `, - variables: { - input: { - id: walletAddress.id, - status: WalletAddressStatus.Inactive + }) + .then((query): UpdateWalletAddressMutationResponse => { + if (query.data) { + return query.data.updateWalletAddress + } else { + throw new Error('Data was empty') } - } - }) - .then((query): UpdateWalletAddressMutationResponse => { - if (query.data) { - return query.data.updateWalletAddress - } else { - throw new Error('Data was empty') - } - }) - - expect(response.success).toBe(false) - expect(response.code).toEqual('500') - expect(response.message).toEqual('Error trying to update wallet address') + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'unexpected', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.InternalServerError + }) + }) + ) + } }) }) @@ -724,28 +711,38 @@ describe('Wallet Address Resolvers', (): void => { ) test('Returns error for unknown wallet address', async (): Promise => { - const gqlQuery = appContainer.apolloClient - .query({ - query: gql` - query WalletAddress($walletAddressId: String!) { - walletAddress(id: $walletAddressId) { - id + try { + await appContainer.apolloClient + .query({ + query: gql` + query WalletAddress($walletAddressId: String!) { + walletAddress(id: $walletAddressId) { + id + } } + `, + variables: { + walletAddressId: uuid() } - `, - variables: { - walletAddressId: uuid() - } - }) - .then((query): WalletAddress => { - if (query.data) { - return query.data.walletAddress - } else { - throw new Error('Data was empty') - } - }) - - await expect(gqlQuery).rejects.toThrow(ApolloError) + }) + .then((query): WalletAddress => { + if (query.data) { + return query.data.walletAddress + } else { + throw new Error('Data was empty') + } + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: errorToMessage[WalletAddressError.UnknownWalletAddress], + extensions: expect.objectContaining({ + code: errorToCode[WalletAddressError.UnknownWalletAddress] + }) + }) + ) + } }) getPageTests({ @@ -844,9 +841,6 @@ describe('Wallet Address Resolvers', (): void => { $input: TriggerWalletAddressEventsInput! ) { triggerWalletAddressEvents(input: $input) { - code - success - message count } } @@ -866,8 +860,6 @@ describe('Wallet Address Resolvers', (): void => { } }) - expect(response.success).toBe(true) - expect(response.code).toEqual('200') expect(response.count).toEqual(count) await expect( WalletAddressEvent.query(knex).where({ @@ -885,43 +877,46 @@ describe('Wallet Address Resolvers', (): void => { } ) - test('500', async (): Promise => { + test('internal server error', async (): Promise => { jest .spyOn(walletAddressService, 'triggerEvents') .mockRejectedValueOnce(new Error('unexpected')) - const response = await appContainer.apolloClient - .mutate({ - mutation: gql` - mutation TriggerWalletAddressEvents( - $input: TriggerWalletAddressEventsInput! - ) { - triggerWalletAddressEvents(input: $input) { - code - success - message - count + try { + await appContainer.apolloClient + .mutate({ + mutation: gql` + mutation TriggerWalletAddressEvents( + $input: TriggerWalletAddressEventsInput! + ) { + triggerWalletAddressEvents(input: $input) { + count + } + } + `, + variables: { + input: { + limit: 1 } } - `, - variables: { - input: { - limit: 1 + }) + .then((query): TriggerWalletAddressEventsMutationResponse => { + if (query.data) { + return query.data.triggerWalletAddressEvents + } else { + throw new Error('Data was empty') } - } - }) - .then((query): TriggerWalletAddressEventsMutationResponse => { - if (query.data) { - return query.data.triggerWalletAddressEvents - } else { - throw new Error('Data was empty') - } - }) - expect(response.code).toBe('500') - expect(response.success).toBe(false) - expect(response.message).toBe( - 'Error trying to trigger wallet address events' - ) - expect(response.count).toBeNull() + }) + } catch (error) { + expect(error).toBeInstanceOf(ApolloError) + expect((error as ApolloError).graphQLErrors).toContainEqual( + expect.objectContaining({ + message: 'unexpected', + extensions: expect.objectContaining({ + code: GraphQLErrorCode.InternalServerError + }) + }) + ) + } }) }) }) diff --git a/packages/backend/src/graphql/resolvers/wallet_address.ts b/packages/backend/src/graphql/resolvers/wallet_address.ts index 965a19af0d..1731699fc9 100644 --- a/packages/backend/src/graphql/resolvers/wallet_address.ts +++ b/packages/backend/src/graphql/resolvers/wallet_address.ts @@ -1,3 +1,5 @@ +import { GraphQLError } from 'graphql' + import { assetToGraphql } from './asset' import { QueryResolvers, @@ -55,7 +57,14 @@ export const getWalletAddress: QueryResolvers['walletAddress'] = const walletAddressService = await ctx.container.use('walletAddressService') const walletAddress = await walletAddressService.get(args.id) if (!walletAddress) { - throw new Error('No wallet address') + throw new GraphQLError( + errorToMessage[WalletAddressError.UnknownWalletAddress], + { + extensions: { + code: errorToCode[WalletAddressError.UnknownWalletAddress] + } + } + ) } return walletAddressToGraphql(walletAddress) } @@ -83,28 +92,20 @@ export const createWalletAddress: MutationResolvers['createWallet publicName: args.input.publicName, url: args.input.url } - return walletAddressService - .create(options) - .then((walletAddressOrError: WalletAddress | WalletAddressError) => - isWalletAddressError(walletAddressOrError) - ? { - code: errorToCode[walletAddressOrError].toString(), - success: false, - message: errorToMessage[walletAddressOrError] - } - : { - code: '200', - success: true, - message: 'Created wallet address', - walletAddress: walletAddressToGraphql(walletAddressOrError) - } - ) - .catch(() => ({ - code: '500', - success: false, - message: 'Error trying to create wallet address' - })) + + const walletAddressOrError = await walletAddressService.create(options) + if (isWalletAddressError(walletAddressOrError)) { + throw new GraphQLError(errorToMessage[walletAddressOrError], { + extensions: { + code: errorToCode[walletAddressOrError] + } + }) + } + return { + walletAddress: walletAddressToGraphql(walletAddressOrError) + } } + export const updateWalletAddress: MutationResolvers['updateWalletAddress'] = async ( parent, @@ -127,27 +128,18 @@ export const updateWalletAddress: MutationResolvers['updateWallet } ) } - return walletAddressService - .update(updateOptions) - .then((walletAddressOrError: WalletAddress | WalletAddressError) => - isWalletAddressError(walletAddressOrError) - ? { - code: errorToCode[walletAddressOrError].toString(), - success: false, - message: errorToMessage[walletAddressOrError] - } - : { - code: '200', - success: true, - message: 'Updated wallet address', - walletAddress: walletAddressToGraphql(walletAddressOrError) - } - ) - .catch(() => ({ - code: '500', - success: false, - message: 'Error trying to update wallet address' - })) + const walletAddressOrError = + await walletAddressService.update(updateOptions) + if (isWalletAddressError(walletAddressOrError)) { + throw new GraphQLError(errorToMessage[walletAddressOrError], { + extensions: { + code: errorToCode[walletAddressOrError] + } + }) + } + return { + walletAddress: walletAddressToGraphql(walletAddressOrError) + } } export const triggerWalletAddressEvents: MutationResolvers['triggerWalletAddressEvents'] = @@ -156,30 +148,10 @@ export const triggerWalletAddressEvents: MutationResolvers['trigg args, ctx ): Promise => { - try { - const walletAddressService = await ctx.container.use( - 'walletAddressService' - ) - const count = await walletAddressService.triggerEvents(args.input.limit) - return { - code: '200', - success: true, - message: 'Triggered Wallet Address Events', - count - } - } catch (err) { - ctx.logger.error( - { - options: args.input.limit, - err - }, - 'error triggering wallet address events' - ) - return { - code: '500', - message: 'Error trying to trigger wallet address events', - success: false - } + const walletAddressService = await ctx.container.use('walletAddressService') + const count = await walletAddressService.triggerEvents(args.input.limit) + return { + count } } diff --git a/packages/backend/src/graphql/schema.graphql b/packages/backend/src/graphql/schema.graphql index def3b5cc2a..f355841f72 100644 --- a/packages/backend/src/graphql/schema.graphql +++ b/packages/backend/src/graphql/schema.graphql @@ -952,9 +952,6 @@ input CreateQuoteInput { } type QuoteResponse { - code: String! - success: Boolean! - message: String quote: Quote } @@ -1016,23 +1013,14 @@ input CreateReceiverInput { } type OutgoingPaymentResponse { - code: String! - success: Boolean! - message: String payment: OutgoingPayment } type IncomingPaymentResponse { - code: String! - success: Boolean! - message: String payment: IncomingPayment } type CreateReceiverResponse { - code: String! - success: Boolean! - message: String receiver: Receiver } @@ -1206,116 +1194,63 @@ interface Model { createdAt: String! } -type CreateWalletAddressMutationResponse implements MutationResponse { - code: String! - success: Boolean! - message: String! +type CreateWalletAddressMutationResponse { walletAddress: WalletAddress } -type UpdateWalletAddressMutationResponse implements MutationResponse { - code: String! - success: Boolean! - message: String! +type UpdateWalletAddressMutationResponse { walletAddress: WalletAddress } -type TriggerWalletAddressEventsMutationResponse implements MutationResponse { - code: String! - success: Boolean! - message: String! +type TriggerWalletAddressEventsMutationResponse { "Number of events triggered" count: Int } -type AssetMutationResponse implements MutationResponse { - code: String! - success: Boolean! - message: String! +type AssetMutationResponse { asset: Asset } -type DeleteAssetMutationResponse implements MutationResponse { - code: String! - success: Boolean! - message: String! +type DeleteAssetMutationResponse { + asset: Asset } -type CreatePeerMutationResponse implements MutationResponse { - code: String! - success: Boolean! - message: String! +type CreatePeerMutationResponse { peer: Peer } -type CreateOrUpdatePeerByUrlMutationResponse implements MutationResponse { - code: String! - success: Boolean! - message: String! +type CreateOrUpdatePeerByUrlMutationResponse { peer: Peer } -type UpdatePeerMutationResponse implements MutationResponse { - code: String! - success: Boolean! - message: String! +type UpdatePeerMutationResponse { peer: Peer } -type DeletePeerMutationResponse implements MutationResponse { - code: String! +type DeletePeerMutationResponse { success: Boolean! - message: String! } -type TransferMutationResponse implements MutationResponse { - code: String! +type LiquidityMutationResponse { success: Boolean! - message: String! } -type LiquidityMutationResponse implements MutationResponse { - code: String! - success: Boolean! - message: String! - error: LiquidityError -} - -type WalletAddressWithdrawalMutationResponse implements MutationResponse { - code: String! - success: Boolean! - message: String! - error: LiquidityError +type WalletAddressWithdrawalMutationResponse { withdrawal: WalletAddressWithdrawal } -type CreateWalletAddressKeyMutationResponse implements MutationResponse { - code: String! - success: Boolean! - message: String! +type CreateWalletAddressKeyMutationResponse { walletAddressKey: WalletAddressKey } -type RevokeWalletAddressKeyMutationResponse implements MutationResponse { - code: String! - success: Boolean! - message: String! +type RevokeWalletAddressKeyMutationResponse { walletAddressKey: WalletAddressKey } -type SetFeeResponse implements MutationResponse { - code: String! - success: Boolean! - message: String! +type SetFeeResponse { fee: Fee } -interface MutationResponse { - code: String! - success: Boolean! - message: String! -} - scalar UInt8 scalar UInt64 scalar JSONObject diff --git a/packages/backend/src/open_payments/payment/incoming/errors.ts b/packages/backend/src/open_payments/payment/incoming/errors.ts index 3ad27737a5..6d6ea90bbc 100644 --- a/packages/backend/src/open_payments/payment/incoming/errors.ts +++ b/packages/backend/src/open_payments/payment/incoming/errors.ts @@ -1,3 +1,5 @@ +import { GraphQLErrorCode } from '../../../graphql/errors' + export enum IncomingPaymentError { UnknownWalletAddress = 'UnknownWalletAddress', InvalidAmount = 'InvalidAmount', @@ -12,7 +14,7 @@ export enum IncomingPaymentError { export const isIncomingPaymentError = (o: any): o is IncomingPaymentError => Object.values(IncomingPaymentError).includes(o) -export const errorToCode: { +export const errorToHTTPCode: { [key in IncomingPaymentError]: number } = { [IncomingPaymentError.UnknownWalletAddress]: 404, @@ -24,6 +26,18 @@ export const errorToCode: { [IncomingPaymentError.InactiveWalletAddress]: 400 } +export const errorToCode: { + [key in IncomingPaymentError]: GraphQLErrorCode +} = { + [IncomingPaymentError.UnknownWalletAddress]: GraphQLErrorCode.NotFound, + [IncomingPaymentError.InvalidAmount]: GraphQLErrorCode.BadUserInput, + [IncomingPaymentError.UnknownPayment]: GraphQLErrorCode.NotFound, + [IncomingPaymentError.InvalidState]: GraphQLErrorCode.BadUserInput, + [IncomingPaymentError.InvalidExpiry]: GraphQLErrorCode.BadUserInput, + [IncomingPaymentError.WrongState]: GraphQLErrorCode.Conflict, + [IncomingPaymentError.InactiveWalletAddress]: GraphQLErrorCode.Inactive +} + export const errorToMessage: { [key in IncomingPaymentError]: string } = { diff --git a/packages/backend/src/open_payments/payment/incoming/routes.test.ts b/packages/backend/src/open_payments/payment/incoming/routes.test.ts index d6357e0b62..72835eae3b 100644 --- a/packages/backend/src/open_payments/payment/incoming/routes.test.ts +++ b/packages/backend/src/open_payments/payment/incoming/routes.test.ts @@ -20,7 +20,7 @@ import { createAsset } from '../../../tests/asset' import { createIncomingPayment } from '../../../tests/incomingPayment' import { createWalletAddress } from '../../../tests/walletAddress' import { Asset } from '../../../asset/model' -import { IncomingPaymentError, errorToCode, errorToMessage } from './errors' +import { IncomingPaymentError, errorToHTTPCode, errorToMessage } from './errors' import { IncomingPaymentService } from './service' import { IncomingPaymentWithPaymentMethods as OpenPaymentsIncomingPaymentWithPaymentMethods } from '@interledger/open-payments' @@ -176,7 +176,7 @@ describe('Incoming Payment Routes', (): void => { .mockResolvedValueOnce(error) await expect(incomingPaymentRoutes.create(ctx)).rejects.toMatchObject({ message: errorToMessage[error], - status: errorToCode[error] + status: errorToHTTPCode[error] }) expect(createSpy).toHaveBeenCalledWith({ walletAddressId: walletAddress.id diff --git a/packages/backend/src/open_payments/payment/incoming/routes.ts b/packages/backend/src/open_payments/payment/incoming/routes.ts index c348184f06..eecbc1db5a 100644 --- a/packages/backend/src/open_payments/payment/incoming/routes.ts +++ b/packages/backend/src/open_payments/payment/incoming/routes.ts @@ -8,7 +8,11 @@ import { } from '../../../app' import { IAppConfig } from '../../../config/app' import { IncomingPaymentService } from './service' -import { errorToCode, errorToMessage, isIncomingPaymentError } from './errors' +import { + errorToHTTPCode, + errorToMessage, + isIncomingPaymentError +} from './errors' import { AmountJSON, parseAmount } from '../../amount' import { listSubresource } from '../../wallet_address/routes' import { StreamCredentialsService } from '../../../payment-method/ilp/stream-credentials/service' @@ -139,7 +143,7 @@ async function createIncomingPayment( if (isIncomingPaymentError(incomingPaymentOrError)) { throw new OpenPaymentsServerRouteError( - errorToCode[incomingPaymentOrError], + errorToHTTPCode[incomingPaymentOrError], errorToMessage[incomingPaymentOrError] ) } @@ -164,7 +168,7 @@ async function completeIncomingPayment( if (isIncomingPaymentError(incomingPaymentOrError)) { throw new OpenPaymentsServerRouteError( - errorToCode[incomingPaymentOrError], + errorToHTTPCode[incomingPaymentOrError], errorToMessage[incomingPaymentOrError] ) } diff --git a/packages/backend/src/open_payments/payment/incoming_remote/errors.ts b/packages/backend/src/open_payments/payment/incoming_remote/errors.ts index 81b22a70d1..599ef02183 100644 --- a/packages/backend/src/open_payments/payment/incoming_remote/errors.ts +++ b/packages/backend/src/open_payments/payment/incoming_remote/errors.ts @@ -1,3 +1,5 @@ +import { GraphQLErrorCode } from '../../../graphql/errors' + export enum RemoteIncomingPaymentError { UnknownWalletAddress = 'UnknownWalletAddress', InvalidRequest = 'InvalidRequest', @@ -10,7 +12,7 @@ export const isRemoteIncomingPaymentError = ( ): o is RemoteIncomingPaymentError => Object.values(RemoteIncomingPaymentError).includes(o) -export const errorToCode: { +export const errorToHTTPCode: { [key in RemoteIncomingPaymentError]: number } = { [RemoteIncomingPaymentError.UnknownWalletAddress]: 404, @@ -18,6 +20,13 @@ export const errorToCode: { [RemoteIncomingPaymentError.InvalidGrant]: 500 } +export const errorToCode: { + [key in RemoteIncomingPaymentError]: GraphQLErrorCode +} = { + [RemoteIncomingPaymentError.UnknownWalletAddress]: GraphQLErrorCode.NotFound, + [RemoteIncomingPaymentError.InvalidRequest]: GraphQLErrorCode.BadUserInput, + [RemoteIncomingPaymentError.InvalidGrant]: GraphQLErrorCode.Forbidden +} export const errorToMessage: { [key in RemoteIncomingPaymentError]: string } = { diff --git a/packages/backend/src/open_payments/payment/outgoing/errors.ts b/packages/backend/src/open_payments/payment/outgoing/errors.ts index 606906e610..3537daeb01 100644 --- a/packages/backend/src/open_payments/payment/outgoing/errors.ts +++ b/packages/backend/src/open_payments/payment/outgoing/errors.ts @@ -1,4 +1,9 @@ -import { TransferError } from '../../../accounting/errors' +import { + TransferError, + errorToMessage as transferErrorToMessage, + errorToCode as transferErrorToCode +} from '../../../accounting/errors' +import { GraphQLErrorCode } from '../../../graphql/errors' import { PaymentMethodHandlerError } from '../../../payment-method/handler/errors' import { QuoteError } from '../../quote/errors' @@ -31,7 +36,7 @@ export const quoteErrorToOutgoingPaymentError: Record< export const isOutgoingPaymentError = (o: any): o is OutgoingPaymentError => Object.values(OutgoingPaymentError).includes(o) -export const errorToCode: { +export const errorToHTTPCode: { [key in OutgoingPaymentError]: number } = { [OutgoingPaymentError.UnknownWalletAddress]: 404, @@ -46,6 +51,21 @@ export const errorToCode: { [OutgoingPaymentError.InvalidReceiver]: 400 } +export const errorToCode: { + [key in OutgoingPaymentError]: GraphQLErrorCode +} = { + [OutgoingPaymentError.UnknownWalletAddress]: GraphQLErrorCode.NotFound, + [OutgoingPaymentError.UnknownPayment]: GraphQLErrorCode.NotFound, + [OutgoingPaymentError.UnknownQuote]: GraphQLErrorCode.NotFound, + [OutgoingPaymentError.WrongState]: GraphQLErrorCode.Conflict, + [OutgoingPaymentError.InvalidQuote]: GraphQLErrorCode.BadUserInput, + [OutgoingPaymentError.InsufficientGrant]: GraphQLErrorCode.Forbidden, + [OutgoingPaymentError.InactiveWalletAddress]: GraphQLErrorCode.Inactive, + [OutgoingPaymentError.InvalidAmount]: GraphQLErrorCode.BadUserInput, + [OutgoingPaymentError.NegativeReceiveAmount]: GraphQLErrorCode.BadUserInput, + [OutgoingPaymentError.InvalidReceiver]: GraphQLErrorCode.BadUserInput +} + export const errorToMessage: { [key in OutgoingPaymentError]: string } = { @@ -63,6 +83,11 @@ export const errorToMessage: { export const FundingError = { ...OutgoingPaymentError, ...TransferError } export type FundingError = OutgoingPaymentError | TransferError +export const fundingErrorToMessage = { + ...errorToMessage, + ...transferErrorToMessage +} +export const fundingErrorToCode = { ...errorToCode, ...transferErrorToCode } // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types export const isFundingError = (o: any): o is FundingError => diff --git a/packages/backend/src/open_payments/payment/outgoing/routes.test.ts b/packages/backend/src/open_payments/payment/outgoing/routes.test.ts index 9eb2a2961e..f30dab4641 100644 --- a/packages/backend/src/open_payments/payment/outgoing/routes.test.ts +++ b/packages/backend/src/open_payments/payment/outgoing/routes.test.ts @@ -10,7 +10,6 @@ import { initIocContainer } from '../../..' import { AppServices, CreateContext } from '../../../app' import { truncateTables } from '../../../tests/tableManager' import { createAsset } from '../../../tests/asset' -import { errorToCode, errorToMessage, OutgoingPaymentError } from './errors' import { CreateFromIncomingPayment, CreateFromQuote, @@ -18,6 +17,7 @@ import { OutgoingPaymentService, BaseOptions as CreateOutgoingPaymentBaseOptions } from './service' +import { errorToHTTPCode, errorToMessage, OutgoingPaymentError } from './errors' import { OutgoingPayment, OutgoingPaymentState } from './model' import { OutgoingPaymentRoutes, CreateBody } from './routes' import { serializeAmount } from '../../amount' @@ -295,7 +295,7 @@ describe('Outgoing Payment Routes', (): void => { } catch (err) { assert(err instanceof OpenPaymentsServerRouteError) expect(err.message).toBe(errorToMessage[error]) - expect(err.status).toBe(errorToCode[error]) + expect(err.status).toBe(errorToHTTPCode[error]) } expect(createSpy).toHaveBeenCalledWith({ diff --git a/packages/backend/src/open_payments/payment/outgoing/routes.ts b/packages/backend/src/open_payments/payment/outgoing/routes.ts index 935ab2470b..e39e0c3baf 100644 --- a/packages/backend/src/open_payments/payment/outgoing/routes.ts +++ b/packages/backend/src/open_payments/payment/outgoing/routes.ts @@ -6,7 +6,11 @@ import { OutgoingPaymentService, BaseOptions as OutgoingPaymentCreateBaseOptions } from './service' -import { isOutgoingPaymentError, errorToCode, errorToMessage } from './errors' +import { + isOutgoingPaymentError, + errorToHTTPCode, + errorToMessage +} from './errors' import { OutgoingPayment } from './model' import { listSubresource } from '../../wallet_address/routes' import { @@ -127,7 +131,7 @@ async function createOutgoingPayment( if (isOutgoingPaymentError(outgoingPaymentOrError)) { throw new OpenPaymentsServerRouteError( - errorToCode[outgoingPaymentOrError], + errorToHTTPCode[outgoingPaymentOrError], errorToMessage[outgoingPaymentOrError] ) } diff --git a/packages/backend/src/open_payments/quote/errors.ts b/packages/backend/src/open_payments/quote/errors.ts index efb67e14c9..2e624ead9f 100644 --- a/packages/backend/src/open_payments/quote/errors.ts +++ b/packages/backend/src/open_payments/quote/errors.ts @@ -1,3 +1,5 @@ +import { GraphQLErrorCode } from '../../graphql/errors' + export enum QuoteError { UnknownWalletAddress = 'UnknownWalletAddress', InvalidAmount = 'InvalidAmount', @@ -10,7 +12,7 @@ export enum QuoteError { export const isQuoteError = (o: any): o is QuoteError => Object.values(QuoteError).includes(o) -export const errorToCode: { +export const errorToHTTPCode: { [key in QuoteError]: number } = { [QuoteError.UnknownWalletAddress]: 404, @@ -20,6 +22,16 @@ export const errorToCode: { [QuoteError.NegativeReceiveAmount]: 400 } +export const errorToCode: { + [key in QuoteError]: GraphQLErrorCode +} = { + [QuoteError.UnknownWalletAddress]: GraphQLErrorCode.NotFound, + [QuoteError.InvalidAmount]: GraphQLErrorCode.BadUserInput, + [QuoteError.InvalidReceiver]: GraphQLErrorCode.BadUserInput, + [QuoteError.InactiveWalletAddress]: GraphQLErrorCode.Inactive, + [QuoteError.NegativeReceiveAmount]: GraphQLErrorCode.BadUserInput +} + export const errorToMessage: { [key in QuoteError]: string } = { diff --git a/packages/backend/src/open_payments/quote/routes.ts b/packages/backend/src/open_payments/quote/routes.ts index 9f828dc28b..d0069280fc 100644 --- a/packages/backend/src/open_payments/quote/routes.ts +++ b/packages/backend/src/open_payments/quote/routes.ts @@ -3,7 +3,7 @@ import { Logger } from 'pino' import { ReadContext, CreateContext } from '../../app' import { IAppConfig } from '../../config/app' import { CreateQuoteOptions, QuoteService } from './service' -import { isQuoteError, errorToCode, errorToMessage } from './errors' +import { isQuoteError, errorToHTTPCode, errorToMessage } from './errors' import { Quote } from './model' import { AmountJSON, parseAmount } from '../amount' import { Quote as OpenPaymentsQuote } from '@interledger/open-payments' @@ -96,7 +96,7 @@ async function createQuote( if (isQuoteError(quoteOrErr)) { throw new OpenPaymentsServerRouteError( - errorToCode[quoteOrErr], + errorToHTTPCode[quoteOrErr], errorToMessage[quoteOrErr] ) } diff --git a/packages/backend/src/open_payments/receiver/errors.ts b/packages/backend/src/open_payments/receiver/errors.ts index 6f655764d1..a8e624a686 100644 --- a/packages/backend/src/open_payments/receiver/errors.ts +++ b/packages/backend/src/open_payments/receiver/errors.ts @@ -1,3 +1,4 @@ +import { GraphQLErrorCode } from '../../graphql/errors' import { errorToMessage as incomingPaymentErrorToMessage, errorToCode as incomingPaymentErrorToCode, @@ -20,7 +21,7 @@ export const ReceiverError = { export const isReceiverError = (o: any): o is ReceiverError => Object.values(ReceiverError).includes(o) -export const errorToCode = (error: ReceiverError): number => +export const errorToCode = (error: ReceiverError): GraphQLErrorCode => isIncomingPaymentError(error) ? incomingPaymentErrorToCode[error] : remoteIncomingPaymentErrorToCode[error] diff --git a/packages/backend/src/open_payments/wallet_address/errors.ts b/packages/backend/src/open_payments/wallet_address/errors.ts index 083b7e39dd..f6775dcb21 100644 --- a/packages/backend/src/open_payments/wallet_address/errors.ts +++ b/packages/backend/src/open_payments/wallet_address/errors.ts @@ -1,3 +1,5 @@ +import { GraphQLErrorCode } from '../../graphql/errors' + export enum WalletAddressError { InvalidUrl = 'InvalidUrl', UnknownAsset = 'UnknownAsset', @@ -9,11 +11,11 @@ export const isWalletAddressError = (o: any): o is WalletAddressError => Object.values(WalletAddressError).includes(o) export const errorToCode: { - [key in WalletAddressError]: number + [key in WalletAddressError]: GraphQLErrorCode } = { - [WalletAddressError.InvalidUrl]: 400, - [WalletAddressError.UnknownAsset]: 400, - [WalletAddressError.UnknownWalletAddress]: 404 + [WalletAddressError.InvalidUrl]: GraphQLErrorCode.BadUserInput, + [WalletAddressError.UnknownAsset]: GraphQLErrorCode.BadUserInput, + [WalletAddressError.UnknownWalletAddress]: GraphQLErrorCode.NotFound } export const errorToMessage: { diff --git a/packages/backend/src/payment-method/ilp/auto-peering/errors.ts b/packages/backend/src/payment-method/ilp/auto-peering/errors.ts index ddc5252b08..c6df6c2ded 100644 --- a/packages/backend/src/payment-method/ilp/auto-peering/errors.ts +++ b/packages/backend/src/payment-method/ilp/auto-peering/errors.ts @@ -1,3 +1,5 @@ +import { GraphQLErrorCode } from '../../../graphql/errors' + export enum AutoPeeringError { InvalidIlpConfiguration = 'InvalidIlpConfiguration', InvalidPeerIlpConfiguration = 'InvalidPeerIlpConfiguration', @@ -13,15 +15,16 @@ export const isAutoPeeringError = (o: any): o is AutoPeeringError => Object.values(AutoPeeringError).includes(o) export const errorToCode: { - [key in AutoPeeringError]: number + [key in AutoPeeringError]: GraphQLErrorCode } = { - [AutoPeeringError.InvalidIlpConfiguration]: 400, - [AutoPeeringError.InvalidPeerIlpConfiguration]: 400, - [AutoPeeringError.UnknownAsset]: 404, - [AutoPeeringError.PeerUnsupportedAsset]: 400, - [AutoPeeringError.InvalidPeerUrl]: 400, - [AutoPeeringError.InvalidPeeringRequest]: 400, - [AutoPeeringError.LiquidityError]: 400 + [AutoPeeringError.InvalidIlpConfiguration]: GraphQLErrorCode.BadUserInput, + [AutoPeeringError.InvalidPeerIlpConfiguration]: + GraphQLErrorCode.InternalServerError, + [AutoPeeringError.UnknownAsset]: GraphQLErrorCode.NotFound, + [AutoPeeringError.PeerUnsupportedAsset]: GraphQLErrorCode.BadUserInput, + [AutoPeeringError.InvalidPeerUrl]: GraphQLErrorCode.NotFound, + [AutoPeeringError.InvalidPeeringRequest]: GraphQLErrorCode.BadUserInput, + [AutoPeeringError.LiquidityError]: GraphQLErrorCode.InternalServerError } export const errorToMessage: { @@ -37,3 +40,15 @@ export const errorToMessage: { [AutoPeeringError.InvalidPeeringRequest]: 'Invalid peering request', [AutoPeeringError.LiquidityError]: 'Could not deposit liquidity to peer' } + +export const errorToHttpCode: { + [key in AutoPeeringError]: number +} = { + [AutoPeeringError.InvalidIlpConfiguration]: 400, + [AutoPeeringError.InvalidPeerIlpConfiguration]: 400, + [AutoPeeringError.UnknownAsset]: 404, + [AutoPeeringError.PeerUnsupportedAsset]: 400, + [AutoPeeringError.InvalidPeerUrl]: 400, + [AutoPeeringError.InvalidPeeringRequest]: 400, + [AutoPeeringError.LiquidityError]: 400 +} diff --git a/packages/backend/src/payment-method/ilp/auto-peering/routes.test.ts b/packages/backend/src/payment-method/ilp/auto-peering/routes.test.ts index d861ec8841..2a5f16b2a7 100644 --- a/packages/backend/src/payment-method/ilp/auto-peering/routes.test.ts +++ b/packages/backend/src/payment-method/ilp/auto-peering/routes.test.ts @@ -6,7 +6,7 @@ import { createTestApp, TestContainer } from '../../../tests/app' import { createAsset } from '../../../tests/asset' import { createContext } from '../../../tests/context' import { truncateTables } from '../../../tests/tableManager' -import { AutoPeeringError, errorToCode, errorToMessage } from './errors' +import { AutoPeeringError, errorToHttpCode, errorToMessage } from './errors' import { AutoPeeringRoutes, PeerRequestContext } from './routes' describe('Auto Peering Routes', (): void => { @@ -74,10 +74,10 @@ describe('Auto Peering Routes', (): void => { await expect( autoPeeringRoutes.acceptPeerRequest(ctx) ).resolves.toBeUndefined() - expect(ctx.status).toBe(errorToCode[AutoPeeringError.UnknownAsset]) + expect(ctx.status).toBe(errorToHttpCode[AutoPeeringError.UnknownAsset]) expect(ctx.body).toEqual({ error: { - code: errorToCode[AutoPeeringError.UnknownAsset], + code: errorToHttpCode[AutoPeeringError.UnknownAsset], message: errorToMessage[AutoPeeringError.UnknownAsset], type: AutoPeeringError.UnknownAsset } diff --git a/packages/backend/src/payment-method/ilp/auto-peering/routes.ts b/packages/backend/src/payment-method/ilp/auto-peering/routes.ts index 1ec0197eaf..46afe0ea01 100644 --- a/packages/backend/src/payment-method/ilp/auto-peering/routes.ts +++ b/packages/backend/src/payment-method/ilp/auto-peering/routes.ts @@ -1,6 +1,6 @@ import { AppContext } from '../../../app' import { BaseService } from '../../../shared/baseService' -import { errorToCode, errorToMessage, isAutoPeeringError } from './errors' +import { errorToHttpCode, errorToMessage, isAutoPeeringError } from './errors' import { AutoPeeringService } from './service' interface PeeringRequestArgs { @@ -49,7 +49,7 @@ async function acceptPeerRequest( await deps.autoPeeringService.acceptPeeringRequest(ctx.request.body) if (isAutoPeeringError(peeringDetailsOrError)) { - const errorCode = errorToCode[peeringDetailsOrError] + const errorCode = errorToHttpCode[peeringDetailsOrError] ctx.status = errorCode ctx.body = { error: { diff --git a/packages/backend/src/payment-method/ilp/peer/errors.ts b/packages/backend/src/payment-method/ilp/peer/errors.ts index 634f70b80a..1c73d6fd8f 100644 --- a/packages/backend/src/payment-method/ilp/peer/errors.ts +++ b/packages/backend/src/payment-method/ilp/peer/errors.ts @@ -1,3 +1,5 @@ +import { GraphQLErrorCode } from '../../../graphql/errors' + export enum PeerError { DuplicateIncomingToken = 'DuplicateIncomingToken', DuplicatePeer = 'DuplicatePeer', @@ -13,15 +15,15 @@ export const isPeerError = (o: any): o is PeerError => Object.values(PeerError).includes(o) export const errorToCode: { - [key in PeerError]: number + [key in PeerError]: GraphQLErrorCode } = { - [PeerError.DuplicateIncomingToken]: 409, - [PeerError.DuplicatePeer]: 409, - [PeerError.InvalidStaticIlpAddress]: 400, - [PeerError.InvalidHTTPEndpoint]: 400, - [PeerError.UnknownAsset]: 400, - [PeerError.UnknownPeer]: 404, - [PeerError.InvalidInitialLiquidity]: 400 + [PeerError.DuplicateIncomingToken]: GraphQLErrorCode.Duplicate, + [PeerError.DuplicatePeer]: GraphQLErrorCode.Duplicate, + [PeerError.InvalidStaticIlpAddress]: GraphQLErrorCode.BadUserInput, + [PeerError.InvalidHTTPEndpoint]: GraphQLErrorCode.BadUserInput, + [PeerError.UnknownAsset]: GraphQLErrorCode.NotFound, + [PeerError.UnknownPeer]: GraphQLErrorCode.NotFound, + [PeerError.InvalidInitialLiquidity]: GraphQLErrorCode.BadUserInput } export const errorToMessage: { diff --git a/packages/frontend/app/generated/graphql.ts b/packages/frontend/app/generated/graphql.ts index 4596b7a67b..6ea2f94b0f 100644 --- a/packages/frontend/app/generated/graphql.ts +++ b/packages/frontend/app/generated/graphql.ts @@ -92,12 +92,9 @@ export type AssetEdge = { node: Asset; }; -export type AssetMutationResponse = MutationResponse & { +export type AssetMutationResponse = { __typename?: 'AssetMutationResponse'; asset?: Maybe; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; }; export type AssetsConnection = { @@ -186,12 +183,9 @@ export type CreateOrUpdatePeerByUrlInput = { peerUrl: Scalars['String']['input']; }; -export type CreateOrUpdatePeerByUrlMutationResponse = MutationResponse & { +export type CreateOrUpdatePeerByUrlMutationResponse = { __typename?: 'CreateOrUpdatePeerByUrlMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; peer?: Maybe; - success: Scalars['Boolean']['output']; }; export type CreateOutgoingPaymentFromIncomingPaymentInput = { @@ -259,12 +253,9 @@ export type CreatePeerLiquidityWithdrawalInput = { timeoutSeconds: Scalars['UInt64']['input']; }; -export type CreatePeerMutationResponse = MutationResponse & { +export type CreatePeerMutationResponse = { __typename?: 'CreatePeerMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; peer?: Maybe; - success: Scalars['Boolean']['output']; }; export type CreateQuoteInput = { @@ -295,10 +286,7 @@ export type CreateReceiverInput = { export type CreateReceiverResponse = { __typename?: 'CreateReceiverResponse'; - code: Scalars['String']['output']; - message?: Maybe; receiver?: Maybe; - success: Scalars['Boolean']['output']; }; export type CreateWalletAddressInput = { @@ -322,19 +310,13 @@ export type CreateWalletAddressKeyInput = { walletAddressId: Scalars['String']['input']; }; -export type CreateWalletAddressKeyMutationResponse = MutationResponse & { +export type CreateWalletAddressKeyMutationResponse = { __typename?: 'CreateWalletAddressKeyMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddressKey?: Maybe; }; -export type CreateWalletAddressMutationResponse = MutationResponse & { +export type CreateWalletAddressMutationResponse = { __typename?: 'CreateWalletAddressMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddress?: Maybe; }; @@ -360,11 +342,9 @@ export type DeleteAssetInput = { idempotencyKey?: InputMaybe; }; -export type DeleteAssetMutationResponse = MutationResponse & { +export type DeleteAssetMutationResponse = { __typename?: 'DeleteAssetMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; + asset?: Maybe; }; export type DeletePeerInput = { @@ -373,10 +353,8 @@ export type DeletePeerInput = { idempotencyKey?: InputMaybe; }; -export type DeletePeerMutationResponse = MutationResponse & { +export type DeletePeerMutationResponse = { __typename?: 'DeletePeerMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; success: Scalars['Boolean']['output']; }; @@ -533,10 +511,7 @@ export type IncomingPaymentEdge = { export type IncomingPaymentResponse = { __typename?: 'IncomingPaymentResponse'; - code: Scalars['String']['output']; - message?: Maybe; payment?: Maybe; - success: Scalars['Boolean']['output']; }; export enum IncomingPaymentState { @@ -596,11 +571,8 @@ export enum LiquidityError { UnknownWalletAddress = 'UnknownWalletAddress' } -export type LiquidityMutationResponse = MutationResponse & { +export type LiquidityMutationResponse = { __typename?: 'LiquidityMutationResponse'; - code: Scalars['String']['output']; - error?: Maybe; - message: Scalars['String']['output']; success: Scalars['Boolean']['output']; }; @@ -836,12 +808,6 @@ export type MutationWithdrawEventLiquidityArgs = { input: WithdrawEventLiquidityInput; }; -export type MutationResponse = { - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; -}; - export type OutgoingPayment = BasePayment & Model & { __typename?: 'OutgoingPayment'; /** Information about the wallet address of the Open Payments client that created the outgoing payment. */ @@ -886,10 +852,7 @@ export type OutgoingPaymentEdge = { export type OutgoingPaymentResponse = { __typename?: 'OutgoingPaymentResponse'; - code: Scalars['String']['output']; - message?: Maybe; payment?: Maybe; - success: Scalars['Boolean']['output']; }; export enum OutgoingPaymentState { @@ -1150,10 +1113,7 @@ export type QuoteEdge = { export type QuoteResponse = { __typename?: 'QuoteResponse'; - code: Scalars['String']['output']; - message?: Maybe; quote?: Maybe; - success: Scalars['Boolean']['output']; }; export type Receiver = { @@ -1185,11 +1145,8 @@ export type RevokeWalletAddressKeyInput = { idempotencyKey?: InputMaybe; }; -export type RevokeWalletAddressKeyMutationResponse = MutationResponse & { +export type RevokeWalletAddressKeyMutationResponse = { __typename?: 'RevokeWalletAddressKeyMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddressKey?: Maybe; }; @@ -1204,12 +1161,9 @@ export type SetFeeInput = { type: FeeType; }; -export type SetFeeResponse = MutationResponse & { +export type SetFeeResponse = { __typename?: 'SetFeeResponse'; - code: Scalars['String']['output']; fee?: Maybe; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; }; export enum SortOrder { @@ -1219,13 +1173,6 @@ export enum SortOrder { Desc = 'DESC' } -export type TransferMutationResponse = MutationResponse & { - __typename?: 'TransferMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; -}; - export type TriggerWalletAddressEventsInput = { /** Unique key to ensure duplicate or retried requests are processed only once. See [idempotence](https://en.wikipedia.org/wiki/Idempotence) */ idempotencyKey?: InputMaybe; @@ -1233,13 +1180,10 @@ export type TriggerWalletAddressEventsInput = { limit: Scalars['Int']['input']; }; -export type TriggerWalletAddressEventsMutationResponse = MutationResponse & { +export type TriggerWalletAddressEventsMutationResponse = { __typename?: 'TriggerWalletAddressEventsMutationResponse'; - code: Scalars['String']['output']; /** Number of events triggered */ count?: Maybe; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; }; export type UpdateAssetInput = { @@ -1270,12 +1214,9 @@ export type UpdatePeerInput = { staticIlpAddress?: InputMaybe; }; -export type UpdatePeerMutationResponse = MutationResponse & { +export type UpdatePeerMutationResponse = { __typename?: 'UpdatePeerMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; peer?: Maybe; - success: Scalars['Boolean']['output']; }; export type UpdateWalletAddressInput = { @@ -1291,11 +1232,8 @@ export type UpdateWalletAddressInput = { status?: InputMaybe; }; -export type UpdateWalletAddressMutationResponse = MutationResponse & { +export type UpdateWalletAddressMutationResponse = { __typename?: 'UpdateWalletAddressMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddress?: Maybe; }; @@ -1419,12 +1357,8 @@ export type WalletAddressWithdrawal = { walletAddress: WalletAddress; }; -export type WalletAddressWithdrawalMutationResponse = MutationResponse & { +export type WalletAddressWithdrawalMutationResponse = { __typename?: 'WalletAddressWithdrawalMutationResponse'; - code: Scalars['String']['output']; - error?: Maybe; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; withdrawal?: Maybe; }; @@ -1541,7 +1475,6 @@ export type DirectiveResolverFn> = { BasePayment: ( Partial ) | ( Partial ) | ( Partial ); Model: ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ); - MutationResponse: ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ); }; /** Mapping between all available schema types and the resolvers types */ @@ -1614,7 +1547,6 @@ export type ResolversTypes = { LiquidityMutationResponse: ResolverTypeWrapper>; Model: ResolverTypeWrapper['Model']>; Mutation: ResolverTypeWrapper<{}>; - MutationResponse: ResolverTypeWrapper['MutationResponse']>; OutgoingPayment: ResolverTypeWrapper>; OutgoingPaymentConnection: ResolverTypeWrapper>; OutgoingPaymentEdge: ResolverTypeWrapper>; @@ -1642,7 +1574,6 @@ export type ResolversTypes = { SetFeeResponse: ResolverTypeWrapper>; SortOrder: ResolverTypeWrapper>; String: ResolverTypeWrapper>; - TransferMutationResponse: ResolverTypeWrapper>; TriggerWalletAddressEventsInput: ResolverTypeWrapper>; TriggerWalletAddressEventsMutationResponse: ResolverTypeWrapper>; UInt8: ResolverTypeWrapper>; @@ -1733,7 +1664,6 @@ export type ResolversParentTypes = { LiquidityMutationResponse: Partial; Model: ResolversInterfaceTypes['Model']; Mutation: {}; - MutationResponse: ResolversInterfaceTypes['MutationResponse']; OutgoingPayment: Partial; OutgoingPaymentConnection: Partial; OutgoingPaymentEdge: Partial; @@ -1758,7 +1688,6 @@ export type ResolversParentTypes = { SetFeeInput: Partial; SetFeeResponse: Partial; String: Partial; - TransferMutationResponse: Partial; TriggerWalletAddressEventsInput: Partial; TriggerWalletAddressEventsMutationResponse: Partial; UInt8: Partial; @@ -1820,9 +1749,6 @@ export type AssetEdgeResolvers = { asset?: Resolver, ParentType, ContextType>; - code?: Resolver; - message?: Resolver; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -1842,55 +1768,36 @@ export type BasePaymentResolvers = { - code?: Resolver; - message?: Resolver; peer?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type CreatePeerMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; peer?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type CreateReceiverResponseResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; receiver?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type CreateWalletAddressKeyMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddressKey?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type CreateWalletAddressMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddress?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type DeleteAssetMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; + asset?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type DeletePeerMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -1955,10 +1862,7 @@ export type IncomingPaymentEdgeResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; payment?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -1976,9 +1880,6 @@ export type JwkResolvers = { - code?: Resolver; - error?: Resolver, ParentType, ContextType>; - message?: Resolver; success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2023,13 +1924,6 @@ export type MutationResolvers, ParentType, ContextType, RequireFields>; }; -export type MutationResponseResolvers = { - __resolveType: TypeResolveFn<'AssetMutationResponse' | 'CreateOrUpdatePeerByUrlMutationResponse' | 'CreatePeerMutationResponse' | 'CreateWalletAddressKeyMutationResponse' | 'CreateWalletAddressMutationResponse' | 'DeleteAssetMutationResponse' | 'DeletePeerMutationResponse' | 'LiquidityMutationResponse' | 'RevokeWalletAddressKeyMutationResponse' | 'SetFeeResponse' | 'TransferMutationResponse' | 'TriggerWalletAddressEventsMutationResponse' | 'UpdatePeerMutationResponse' | 'UpdateWalletAddressMutationResponse' | 'WalletAddressWithdrawalMutationResponse', ParentType, ContextType>; - code?: Resolver; - message?: Resolver; - success?: Resolver; -}; - export type OutgoingPaymentResolvers = { client?: Resolver, ParentType, ContextType>; createdAt?: Resolver; @@ -2061,10 +1955,7 @@ export type OutgoingPaymentEdgeResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; payment?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2168,10 +2059,7 @@ export type QuoteEdgeResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; quote?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2189,33 +2077,17 @@ export type ReceiverResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddressKey?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type SetFeeResponseResolvers = { - code?: Resolver; fee?: Resolver, ParentType, ContextType>; - message?: Resolver; - success?: Resolver; - __isTypeOf?: IsTypeOfResolverFn; -}; - -export type TransferMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type TriggerWalletAddressEventsMutationResponseResolvers = { - code?: Resolver; count?: Resolver, ParentType, ContextType>; - message?: Resolver; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2228,17 +2100,11 @@ export interface UInt64ScalarConfig extends GraphQLScalarTypeConfig = { - code?: Resolver; - message?: Resolver; peer?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type UpdateWalletAddressMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddress?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2294,10 +2160,6 @@ export type WalletAddressWithdrawalResolvers = { - code?: Resolver; - error?: Resolver, ParentType, ContextType>; - message?: Resolver; - success?: Resolver; withdrawal?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2357,7 +2219,6 @@ export type Resolvers = { LiquidityMutationResponse?: LiquidityMutationResponseResolvers; Model?: ModelResolvers; Mutation?: MutationResolvers; - MutationResponse?: MutationResponseResolvers; OutgoingPayment?: OutgoingPaymentResolvers; OutgoingPaymentConnection?: OutgoingPaymentConnectionResolvers; OutgoingPaymentEdge?: OutgoingPaymentEdgeResolvers; @@ -2377,7 +2238,6 @@ export type Resolvers = { Receiver?: ReceiverResolvers; RevokeWalletAddressKeyMutationResponse?: RevokeWalletAddressKeyMutationResponseResolvers; SetFeeResponse?: SetFeeResponseResolvers; - TransferMutationResponse?: TransferMutationResponseResolvers; TriggerWalletAddressEventsMutationResponse?: TriggerWalletAddressEventsMutationResponseResolvers; UInt8?: GraphQLScalarType; UInt64?: GraphQLScalarType; @@ -2430,42 +2290,42 @@ export type CreateAssetMutationVariables = Exact<{ }>; -export type CreateAssetMutation = { __typename?: 'Mutation', createAsset: { __typename?: 'AssetMutationResponse', code: string, success: boolean, message: string, asset?: { __typename?: 'Asset', id: string } | null } }; +export type CreateAssetMutation = { __typename?: 'Mutation', createAsset: { __typename?: 'AssetMutationResponse', asset?: { __typename?: 'Asset', id: string, code: string, scale: number, withdrawalThreshold?: bigint | null, liquidity?: bigint | null, createdAt: string, sendingFee?: { __typename?: 'Fee', basisPoints: number, fixed: bigint, createdAt: string } | null } | null } }; export type UpdateAssetMutationVariables = Exact<{ input: UpdateAssetInput; }>; -export type UpdateAssetMutation = { __typename?: 'Mutation', updateAsset: { __typename?: 'AssetMutationResponse', code: string, success: boolean, message: string } }; +export type UpdateAssetMutation = { __typename?: 'Mutation', updateAsset: { __typename?: 'AssetMutationResponse', asset?: { __typename?: 'Asset', id: string, code: string, scale: number, withdrawalThreshold?: bigint | null, liquidity?: bigint | null, createdAt: string, sendingFee?: { __typename?: 'Fee', basisPoints: number, fixed: bigint, createdAt: string } | null } | null } }; export type SetFeeMutationVariables = Exact<{ input: SetFeeInput; }>; -export type SetFeeMutation = { __typename?: 'Mutation', setFee: { __typename?: 'SetFeeResponse', code: string, message: string, success: boolean, fee?: { __typename?: 'Fee', assetId: string, basisPoints: number, createdAt: string, fixed: bigint, id: string, type: FeeType } | null } }; +export type SetFeeMutation = { __typename?: 'Mutation', setFee: { __typename?: 'SetFeeResponse', fee?: { __typename?: 'Fee', assetId: string, basisPoints: number, createdAt: string, fixed: bigint, id: string, type: FeeType } | null } }; export type DepositAssetLiquidityMutationVariables = Exact<{ input: DepositAssetLiquidityInput; }>; -export type DepositAssetLiquidityMutation = { __typename?: 'Mutation', depositAssetLiquidity?: { __typename?: 'LiquidityMutationResponse', code: string, success: boolean, message: string, error?: LiquidityError | null } | null }; +export type DepositAssetLiquidityMutation = { __typename?: 'Mutation', depositAssetLiquidity?: { __typename?: 'LiquidityMutationResponse', success: boolean } | null }; export type WithdrawAssetLiquidityVariables = Exact<{ input: CreateAssetLiquidityWithdrawalInput; }>; -export type WithdrawAssetLiquidity = { __typename?: 'Mutation', createAssetLiquidityWithdrawal?: { __typename?: 'LiquidityMutationResponse', code: string, success: boolean, message: string, error?: LiquidityError | null } | null }; +export type WithdrawAssetLiquidity = { __typename?: 'Mutation', createAssetLiquidityWithdrawal?: { __typename?: 'LiquidityMutationResponse', success: boolean } | null }; export type DeleteAssetMutationVariables = Exact<{ input: DeleteAssetInput; }>; -export type DeleteAssetMutation = { __typename?: 'Mutation', deleteAsset: { __typename?: 'DeleteAssetMutationResponse', code: string, success: boolean, message: string } }; +export type DeleteAssetMutation = { __typename?: 'Mutation', deleteAsset: { __typename?: 'DeleteAssetMutationResponse', asset?: { __typename?: 'Asset', id: string, code: string, scale: number, withdrawalThreshold?: bigint | null, liquidity?: bigint | null, createdAt: string, sendingFee?: { __typename?: 'Fee', basisPoints: number, fixed: bigint, createdAt: string } | null } | null } }; export type GetIncomingPaymentVariables = Exact<{ id: Scalars['String']['input']; @@ -2497,21 +2357,21 @@ export type DepositOutgoingPaymentLiquidityVariables = Exact<{ }>; -export type DepositOutgoingPaymentLiquidity = { __typename?: 'Mutation', depositOutgoingPaymentLiquidity?: { __typename?: 'LiquidityMutationResponse', success: boolean, message: string } | null }; +export type DepositOutgoingPaymentLiquidity = { __typename?: 'Mutation', depositOutgoingPaymentLiquidity?: { __typename?: 'LiquidityMutationResponse', success: boolean } | null }; export type CreateOutgoingPaymentWithdrawalVariables = Exact<{ input: CreateOutgoingPaymentWithdrawalInput; }>; -export type CreateOutgoingPaymentWithdrawal = { __typename?: 'Mutation', createOutgoingPaymentWithdrawal?: { __typename?: 'LiquidityMutationResponse', success: boolean, message: string } | null }; +export type CreateOutgoingPaymentWithdrawal = { __typename?: 'Mutation', createOutgoingPaymentWithdrawal?: { __typename?: 'LiquidityMutationResponse', success: boolean } | null }; export type CreateIncomingPaymentWithdrawalVariables = Exact<{ input: CreateIncomingPaymentWithdrawalInput; }>; -export type CreateIncomingPaymentWithdrawal = { __typename?: 'Mutation', createIncomingPaymentWithdrawal?: { __typename?: 'LiquidityMutationResponse', success: boolean, message: string } | null }; +export type CreateIncomingPaymentWithdrawal = { __typename?: 'Mutation', createIncomingPaymentWithdrawal?: { __typename?: 'LiquidityMutationResponse', success: boolean } | null }; export type GetPeerQueryVariables = Exact<{ id: Scalars['String']['input']; @@ -2535,35 +2395,35 @@ export type CreatePeerMutationVariables = Exact<{ }>; -export type CreatePeerMutation = { __typename?: 'Mutation', createPeer: { __typename?: 'CreatePeerMutationResponse', code: string, success: boolean, message: string, peer?: { __typename?: 'Peer', id: string } | null } }; +export type CreatePeerMutation = { __typename?: 'Mutation', createPeer: { __typename?: 'CreatePeerMutationResponse', peer?: { __typename?: 'Peer', id: string } | null } }; export type UpdatePeerMutationVariables = Exact<{ input: UpdatePeerInput; }>; -export type UpdatePeerMutation = { __typename?: 'Mutation', updatePeer: { __typename?: 'UpdatePeerMutationResponse', code: string, success: boolean, message: string } }; +export type UpdatePeerMutation = { __typename?: 'Mutation', updatePeer: { __typename?: 'UpdatePeerMutationResponse', peer?: { __typename?: 'Peer', id: string } | null } }; export type DeletePeerMutationVariables = Exact<{ input: DeletePeerInput; }>; -export type DeletePeerMutation = { __typename?: 'Mutation', deletePeer: { __typename?: 'DeletePeerMutationResponse', code: string, success: boolean, message: string } }; +export type DeletePeerMutation = { __typename?: 'Mutation', deletePeer: { __typename?: 'DeletePeerMutationResponse', success: boolean } }; export type DepositPeerLiquidityMutationVariables = Exact<{ input: DepositPeerLiquidityInput; }>; -export type DepositPeerLiquidityMutation = { __typename?: 'Mutation', depositPeerLiquidity?: { __typename?: 'LiquidityMutationResponse', code: string, success: boolean, message: string, error?: LiquidityError | null } | null }; +export type DepositPeerLiquidityMutation = { __typename?: 'Mutation', depositPeerLiquidity?: { __typename?: 'LiquidityMutationResponse', success: boolean } | null }; export type WithdrawPeerLiquidityVariables = Exact<{ input: CreatePeerLiquidityWithdrawalInput; }>; -export type WithdrawPeerLiquidity = { __typename?: 'Mutation', createPeerLiquidityWithdrawal?: { __typename?: 'LiquidityMutationResponse', code: string, success: boolean, message: string, error?: LiquidityError | null } | null }; +export type WithdrawPeerLiquidity = { __typename?: 'Mutation', createPeerLiquidityWithdrawal?: { __typename?: 'LiquidityMutationResponse', success: boolean } | null }; export type GetWalletAddressQueryVariables = Exact<{ id: Scalars['String']['input']; @@ -2587,21 +2447,21 @@ export type UpdateWalletAddressMutationVariables = Exact<{ }>; -export type UpdateWalletAddressMutation = { __typename?: 'Mutation', updateWalletAddress: { __typename?: 'UpdateWalletAddressMutationResponse', code: string, message: string, success: boolean } }; +export type UpdateWalletAddressMutation = { __typename?: 'Mutation', updateWalletAddress: { __typename?: 'UpdateWalletAddressMutationResponse', walletAddress?: { __typename?: 'WalletAddress', id: string } | null } }; export type CreateWalletAddressMutationVariables = Exact<{ input: CreateWalletAddressInput; }>; -export type CreateWalletAddressMutation = { __typename?: 'Mutation', createWalletAddress: { __typename?: 'CreateWalletAddressMutationResponse', code: string, success: boolean, message: string, walletAddress?: { __typename?: 'WalletAddress', id: string } | null } }; +export type CreateWalletAddressMutation = { __typename?: 'Mutation', createWalletAddress: { __typename?: 'CreateWalletAddressMutationResponse', walletAddress?: { __typename?: 'WalletAddress', id: string } | null } }; export type CreateWalletAddressWithdrawalVariables = Exact<{ input: CreateWalletAddressWithdrawalInput; }>; -export type CreateWalletAddressWithdrawal = { __typename?: 'Mutation', createWalletAddressWithdrawal?: { __typename?: 'WalletAddressWithdrawalMutationResponse', success: boolean, message: string } | null }; +export type CreateWalletAddressWithdrawal = { __typename?: 'Mutation', createWalletAddressWithdrawal?: { __typename?: 'WalletAddressWithdrawalMutationResponse', withdrawal?: { __typename?: 'WalletAddressWithdrawal', id: string } | null } | null }; export type ListWebhookEventsVariables = Exact<{ after?: InputMaybe; diff --git a/packages/frontend/app/lib/api/asset.server.ts b/packages/frontend/app/lib/api/asset.server.ts index 8140e098aa..25935c531f 100644 --- a/packages/frontend/app/lib/api/asset.server.ts +++ b/packages/frontend/app/lib/api/asset.server.ts @@ -142,11 +142,18 @@ export const createAsset = async (args: CreateAssetInput) => { mutation: gql` mutation CreateAssetMutation($input: CreateAssetInput!) { createAsset(input: $input) { - code - success - message asset { id + code + scale + withdrawalThreshold + liquidity + sendingFee { + basisPoints + fixed + createdAt + } + createdAt } } } @@ -167,9 +174,19 @@ export const updateAsset = async (args: UpdateAssetInput) => { mutation: gql` mutation UpdateAssetMutation($input: UpdateAssetInput!) { updateAsset(input: $input) { - code - success - message + asset { + id + code + scale + withdrawalThreshold + liquidity + sendingFee { + basisPoints + fixed + createdAt + } + createdAt + } } } `, @@ -189,7 +206,6 @@ export const setFee = async (args: SetFeeInput) => { mutation: gql` mutation SetFeeMutation($input: SetFeeInput!) { setFee(input: $input) { - code fee { assetId basisPoints @@ -198,8 +214,6 @@ export const setFee = async (args: SetFeeInput) => { id type } - message - success } } `, @@ -223,10 +237,7 @@ export const depositAssetLiquidity = async ( $input: DepositAssetLiquidityInput! ) { depositAssetLiquidity(input: $input) { - code success - message - error } } `, @@ -250,10 +261,7 @@ export const withdrawAssetLiquidity = async ( $input: CreateAssetLiquidityWithdrawalInput! ) { createAssetLiquidityWithdrawal(input: $input) { - code success - message - error } } `, @@ -292,9 +300,19 @@ export const deleteAsset = async (args: DeleteAssetInput) => { mutation: gql` mutation DeleteAssetMutation($input: DeleteAssetInput!) { deleteAsset(input: $input) { - code - success - message + asset { + id + code + scale + withdrawalThreshold + liquidity + sendingFee { + basisPoints + fixed + createdAt + } + createdAt + } } } `, diff --git a/packages/frontend/app/lib/api/payments.server.ts b/packages/frontend/app/lib/api/payments.server.ts index 11540e527e..8c330d10a2 100644 --- a/packages/frontend/app/lib/api/payments.server.ts +++ b/packages/frontend/app/lib/api/payments.server.ts @@ -152,7 +152,6 @@ export const depositOutgoingPaymentLiquidity = async ( ) { depositOutgoingPaymentLiquidity(input: $input) { success - message } } `, @@ -177,7 +176,6 @@ export const createOutgoingPaymentWithdrawal = async ( ) { createOutgoingPaymentWithdrawal(input: $input) { success - message } } `, @@ -202,7 +200,6 @@ export const createIncomingPaymentWithdrawal = async ( ) { createIncomingPaymentWithdrawal(input: $input) { success - message } } `, diff --git a/packages/frontend/app/lib/api/peer.server.ts b/packages/frontend/app/lib/api/peer.server.ts index 990b58290f..fd064ed0c5 100644 --- a/packages/frontend/app/lib/api/peer.server.ts +++ b/packages/frontend/app/lib/api/peer.server.ts @@ -111,9 +111,6 @@ export const createPeer = async (args: CreatePeerInput) => { mutation: gql` mutation CreatePeerMutation($input: CreatePeerInput!) { createPeer(input: $input) { - code - success - message peer { id } @@ -136,9 +133,9 @@ export const updatePeer = async (args: UpdatePeerInput) => { mutation: gql` mutation UpdatePeerMutation($input: UpdatePeerInput!) { updatePeer(input: $input) { - code - success - message + peer { + id + } } } `, @@ -158,9 +155,7 @@ export const deletePeer = async (args: MutationDeletePeerArgs) => { mutation: gql` mutation DeletePeerMutation($input: DeletePeerInput!) { deletePeer(input: $input) { - code success - message } } `, @@ -180,10 +175,7 @@ export const depositPeerLiquidity = async (args: DepositPeerLiquidityInput) => { $input: DepositPeerLiquidityInput! ) { depositPeerLiquidity(input: $input) { - code success - message - error } } `, @@ -207,10 +199,7 @@ export const withdrawPeerLiquidity = async ( $input: CreatePeerLiquidityWithdrawalInput! ) { createPeerLiquidityWithdrawal(input: $input) { - code success - message - error } } `, diff --git a/packages/frontend/app/lib/api/wallet-address.server.ts b/packages/frontend/app/lib/api/wallet-address.server.ts index 50e6dca4a0..bf3e680ca4 100644 --- a/packages/frontend/app/lib/api/wallet-address.server.ts +++ b/packages/frontend/app/lib/api/wallet-address.server.ts @@ -92,9 +92,9 @@ export const updateWalletAddress = async (args: UpdateWalletAddressInput) => { mutation: gql` mutation UpdateWalletAddressMutation($input: UpdateWalletAddressInput!) { updateWalletAddress(input: $input) { - code - message - success + walletAddress { + id + } } } `, @@ -114,9 +114,6 @@ export const createWalletAddress = async (args: CreateWalletAddressInput) => { mutation: gql` mutation CreateWalletAddressMutation($input: CreateWalletAddressInput!) { createWalletAddress(input: $input) { - code - success - message walletAddress { id } @@ -143,8 +140,9 @@ export const createWalletAddressWithdrawal = async ( $input: CreateWalletAddressWithdrawalInput! ) { createWalletAddressWithdrawal(input: $input) { - success - message + withdrawal { + id + } } } `, diff --git a/packages/frontend/app/routes/assets.$assetId.deposit-liquidity.tsx b/packages/frontend/app/routes/assets.$assetId.deposit-liquidity.tsx index 011dffcd2d..64b86ac5aa 100644 --- a/packages/frontend/app/routes/assets.$assetId.deposit-liquidity.tsx +++ b/packages/frontend/app/routes/assets.$assetId.deposit-liquidity.tsx @@ -67,9 +67,7 @@ export async function action({ request, params }: ActionFunctionArgs) { return setMessageAndRedirect({ session, message: { - content: - response?.message ?? - 'Could not deposit asset liquidity. Please try again!', + content: 'Could not deposit asset liquidity. Please try again!', type: 'error' }, location: '.' @@ -79,7 +77,7 @@ export async function action({ request, params }: ActionFunctionArgs) { return setMessageAndRedirect({ session, message: { - content: response.message, + content: 'Deposited asset liquidity.', type: 'success' }, location: '..' diff --git a/packages/frontend/app/routes/assets.$assetId.tsx b/packages/frontend/app/routes/assets.$assetId.tsx index c23fb98ca3..2181fb0484 100644 --- a/packages/frontend/app/routes/assets.$assetId.tsx +++ b/packages/frontend/app/routes/assets.$assetId.tsx @@ -301,9 +301,9 @@ export async function action({ request }: ActionFunctionArgs) { : { withdrawalThreshold: undefined }) }) - if (!response?.success) { + if (!response?.asset) { actionResponse.errors.general.message = [ - response?.message ?? 'Could not update asset. Please try again!' + 'Could not update asset. Please try again!' ] return json({ ...actionResponse }, { status: 400 }) } @@ -327,10 +327,9 @@ export async function action({ request }: ActionFunctionArgs) { } }) - if (!response?.success) { + if (!response?.fee) { actionResponse.errors.sendingFee.message = [ - response?.message ?? - 'Could not update asset sending fee. Please try again!' + 'Could not update asset sending fee. Please try again!' ] return json({ ...actionResponse }, { status: 400 }) } @@ -351,11 +350,11 @@ export async function action({ request }: ActionFunctionArgs) { } const response = await deleteAsset({ id: result.data.id }) - if (!response?.success) { + if (!response?.asset) { return setMessageAndRedirect({ session, message: { - content: response?.message || 'Could not delete Asset.', + content: 'Could not delete Asset.', type: 'error' }, location: '.' diff --git a/packages/frontend/app/routes/assets.$assetId.withdraw-liquidity.tsx b/packages/frontend/app/routes/assets.$assetId.withdraw-liquidity.tsx index 2bf52d24f4..c8b4a8d7a1 100644 --- a/packages/frontend/app/routes/assets.$assetId.withdraw-liquidity.tsx +++ b/packages/frontend/app/routes/assets.$assetId.withdraw-liquidity.tsx @@ -68,9 +68,7 @@ export async function action({ request, params }: ActionFunctionArgs) { return setMessageAndRedirect({ session, message: { - content: - response?.message ?? - 'Could not withdraw asset liquidity. Please try again!', + content: 'Could not withdraw asset liquidity. Please try again!', type: 'error' }, location: '.' @@ -80,7 +78,7 @@ export async function action({ request, params }: ActionFunctionArgs) { return setMessageAndRedirect({ session, message: { - content: response.message, + content: 'Successfully withdrew asset liquidity.', type: 'success' }, location: '..' diff --git a/packages/frontend/app/routes/assets.create.tsx b/packages/frontend/app/routes/assets.create.tsx index a89d51257f..de77d8b603 100644 --- a/packages/frontend/app/routes/assets.create.tsx +++ b/packages/frontend/app/routes/assets.create.tsx @@ -104,10 +104,8 @@ export async function action({ request }: ActionFunctionArgs) { : { withdrawalThreshold: undefined }) }) - if (!response?.success) { - errors.message = [ - response?.message ?? 'Could not create asset. Please try again!' - ] + if (!response?.asset) { + errors.message = ['Could not create asset. Please try again!'] return json({ errors }, { status: 400 }) } diff --git a/packages/frontend/app/routes/payments.incoming.$incomingPaymentId.withdraw-liquidity.tsx b/packages/frontend/app/routes/payments.incoming.$incomingPaymentId.withdraw-liquidity.tsx index 8fe1ba6635..66c4bea3f6 100644 --- a/packages/frontend/app/routes/payments.incoming.$incomingPaymentId.withdraw-liquidity.tsx +++ b/packages/frontend/app/routes/payments.incoming.$incomingPaymentId.withdraw-liquidity.tsx @@ -54,7 +54,6 @@ export async function action({ request, params }: ActionFunctionArgs) { session, message: { content: - response?.message ?? 'Could not withdraw incoming payment liquidity. Please try again!', type: 'error' }, @@ -65,7 +64,7 @@ export async function action({ request, params }: ActionFunctionArgs) { return setMessageAndRedirect({ session, message: { - content: response.message, + content: 'Withdrew incoming payment liquidity.', type: 'success' }, location: '..' diff --git a/packages/frontend/app/routes/payments.outgoing.$outgoingPaymentId.deposit-liquidity.tsx b/packages/frontend/app/routes/payments.outgoing.$outgoingPaymentId.deposit-liquidity.tsx index e9b0242331..e16ad39ff9 100644 --- a/packages/frontend/app/routes/payments.outgoing.$outgoingPaymentId.deposit-liquidity.tsx +++ b/packages/frontend/app/routes/payments.outgoing.$outgoingPaymentId.deposit-liquidity.tsx @@ -55,7 +55,6 @@ export async function action({ request, params }: ActionFunctionArgs) { session, message: { content: - response?.message ?? 'Could not deposit outgoing payment liquidity. Please try again!', type: 'error' }, @@ -66,7 +65,7 @@ export async function action({ request, params }: ActionFunctionArgs) { return setMessageAndRedirect({ session, message: { - content: response.message, + content: 'Deposited outgoing payment liquidity.', type: 'success' }, location: '..' diff --git a/packages/frontend/app/routes/payments.outgoing.$outgoingPaymentId.withdraw-liquidity.tsx b/packages/frontend/app/routes/payments.outgoing.$outgoingPaymentId.withdraw-liquidity.tsx index f8f0eb993f..0740ea309e 100644 --- a/packages/frontend/app/routes/payments.outgoing.$outgoingPaymentId.withdraw-liquidity.tsx +++ b/packages/frontend/app/routes/payments.outgoing.$outgoingPaymentId.withdraw-liquidity.tsx @@ -56,7 +56,6 @@ export async function action({ request, params }: ActionFunctionArgs) { session, message: { content: - response?.message ?? 'Could not withdraw outgoing payment liquidity. Please try again!', type: 'error' }, @@ -67,7 +66,7 @@ export async function action({ request, params }: ActionFunctionArgs) { return setMessageAndRedirect({ session, message: { - content: response.message, + content: 'Withdrew outgoing payment liquidity.', type: 'success' }, location: '..' diff --git a/packages/frontend/app/routes/peers.$peerId.deposit-liquidity.tsx b/packages/frontend/app/routes/peers.$peerId.deposit-liquidity.tsx index f411562a14..3b1fbd2558 100644 --- a/packages/frontend/app/routes/peers.$peerId.deposit-liquidity.tsx +++ b/packages/frontend/app/routes/peers.$peerId.deposit-liquidity.tsx @@ -67,9 +67,7 @@ export async function action({ request, params }: ActionFunctionArgs) { return setMessageAndRedirect({ session, message: { - content: - response?.message ?? - 'Could not deposit peer liquidity. Please try again!', + content: 'Could not deposit peer liquidity. Please try again!', type: 'error' }, location: '.' @@ -79,7 +77,7 @@ export async function action({ request, params }: ActionFunctionArgs) { return setMessageAndRedirect({ session, message: { - content: response.message, + content: 'Deposited peer liquidity.', type: 'success' }, location: '..' diff --git a/packages/frontend/app/routes/peers.$peerId.tsx b/packages/frontend/app/routes/peers.$peerId.tsx index 71497ca386..03fa16b501 100644 --- a/packages/frontend/app/routes/peers.$peerId.tsx +++ b/packages/frontend/app/routes/peers.$peerId.tsx @@ -418,9 +418,9 @@ export async function action({ request }: ActionFunctionArgs) { : { maxPacketAmount: undefined }) }) - if (!response?.success) { + if (!response?.peer) { actionResponse.errors.general.message = [ - response?.message ?? 'Could not update peer. Please try again!' + 'Could not update peer. Please try again!' ] return json({ ...actionResponse }, { status: 400 }) } @@ -455,9 +455,9 @@ export async function action({ request }: ActionFunctionArgs) { } }) - if (!response?.success) { + if (!response?.peer) { actionResponse.errors.general.message = [ - response?.message ?? 'Could not update peer. Please try again!' + 'Could not update peer. Please try again!' ] return json({ ...actionResponse }, { status: 400 }) } diff --git a/packages/frontend/app/routes/peers.$peerId.withdraw-liquidity.tsx b/packages/frontend/app/routes/peers.$peerId.withdraw-liquidity.tsx index d48a558e14..228651adc9 100644 --- a/packages/frontend/app/routes/peers.$peerId.withdraw-liquidity.tsx +++ b/packages/frontend/app/routes/peers.$peerId.withdraw-liquidity.tsx @@ -68,9 +68,7 @@ export async function action({ request, params }: ActionFunctionArgs) { return setMessageAndRedirect({ session, message: { - content: - response?.message ?? - 'Could not withdraw peer liquidity. Please try again!', + content: 'Could not withdraw peer liquidity. Please try again!', type: 'error' }, location: '.' @@ -80,7 +78,7 @@ export async function action({ request, params }: ActionFunctionArgs) { return setMessageAndRedirect({ session, message: { - content: response.message, + content: 'Withdrew peer liquidity', type: 'success' }, location: '..' diff --git a/packages/frontend/app/routes/peers.create.tsx b/packages/frontend/app/routes/peers.create.tsx index c76d4b90ff..c643078f58 100644 --- a/packages/frontend/app/routes/peers.create.tsx +++ b/packages/frontend/app/routes/peers.create.tsx @@ -264,10 +264,8 @@ export async function action({ request }: ActionFunctionArgs) { : { maxPacketAmount: undefined }) }) - if (!response?.success) { - errors.message = [ - response?.message ?? 'Could not create peer. Please try again!' - ] + if (!response?.peer) { + errors.message = ['Could not create peer. Please try again!'] return json({ errors }, { status: 400 }) } diff --git a/packages/frontend/app/routes/wallet-addresses.$walletAddressId.tsx b/packages/frontend/app/routes/wallet-addresses.$walletAddressId.tsx index 6ded79ef61..f7850b56cf 100644 --- a/packages/frontend/app/routes/wallet-addresses.$walletAddressId.tsx +++ b/packages/frontend/app/routes/wallet-addresses.$walletAddressId.tsx @@ -239,10 +239,9 @@ export async function action({ request }: ActionFunctionArgs) { ...result.data }) - if (!response?.success) { + if (!response?.walletAddress) { actionResponse.errors.message = [ - response?.message ?? - 'Could not update the wallet address. Please try again!' + 'Could not update the wallet address. Please try again!' ] return json({ ...actionResponse }, { status: 400 }) } diff --git a/packages/frontend/app/routes/wallet-addresses.$walletAddressId.withdraw-liquidity.tsx b/packages/frontend/app/routes/wallet-addresses.$walletAddressId.withdraw-liquidity.tsx index 8f15df05db..e54a93ea6b 100644 --- a/packages/frontend/app/routes/wallet-addresses.$walletAddressId.withdraw-liquidity.tsx +++ b/packages/frontend/app/routes/wallet-addresses.$walletAddressId.withdraw-liquidity.tsx @@ -50,12 +50,11 @@ export async function action({ request, params }: ActionFunctionArgs) { timeoutSeconds: BigInt(0) }) - if (!response?.success) { + if (!response?.withdrawal) { return setMessageAndRedirect({ session, message: { content: - response?.message ?? 'Could not withdraw wallet address liquidity. Please try again!', type: 'error' }, @@ -66,7 +65,7 @@ export async function action({ request, params }: ActionFunctionArgs) { return setMessageAndRedirect({ session, message: { - content: response.message, + content: 'Withdrew wallet address liquidity.', type: 'success' }, location: '..' diff --git a/packages/frontend/app/routes/wallet-addresses.create.tsx b/packages/frontend/app/routes/wallet-addresses.create.tsx index 1d938c54af..08b2935c65 100644 --- a/packages/frontend/app/routes/wallet-addresses.create.tsx +++ b/packages/frontend/app/routes/wallet-addresses.create.tsx @@ -116,10 +116,8 @@ export async function action({ request }: ActionFunctionArgs) { additionalProperties: [] }) - if (!response?.success) { - errors.message = [ - response?.message ?? 'Could not create wallet address. Please try again!' - ] + if (!response?.walletAddress) { + errors.message = ['Could not create wallet address. Please try again!'] return json({ errors }, { status: 400 }) } diff --git a/packages/mock-account-service-lib/src/generated/graphql.ts b/packages/mock-account-service-lib/src/generated/graphql.ts index af780bc3ad..46f7835344 100644 --- a/packages/mock-account-service-lib/src/generated/graphql.ts +++ b/packages/mock-account-service-lib/src/generated/graphql.ts @@ -92,12 +92,9 @@ export type AssetEdge = { node: Asset; }; -export type AssetMutationResponse = MutationResponse & { +export type AssetMutationResponse = { __typename?: 'AssetMutationResponse'; asset?: Maybe; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; }; export type AssetsConnection = { @@ -186,12 +183,9 @@ export type CreateOrUpdatePeerByUrlInput = { peerUrl: Scalars['String']['input']; }; -export type CreateOrUpdatePeerByUrlMutationResponse = MutationResponse & { +export type CreateOrUpdatePeerByUrlMutationResponse = { __typename?: 'CreateOrUpdatePeerByUrlMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; peer?: Maybe; - success: Scalars['Boolean']['output']; }; export type CreateOutgoingPaymentFromIncomingPaymentInput = { @@ -259,12 +253,9 @@ export type CreatePeerLiquidityWithdrawalInput = { timeoutSeconds: Scalars['UInt64']['input']; }; -export type CreatePeerMutationResponse = MutationResponse & { +export type CreatePeerMutationResponse = { __typename?: 'CreatePeerMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; peer?: Maybe; - success: Scalars['Boolean']['output']; }; export type CreateQuoteInput = { @@ -295,10 +286,7 @@ export type CreateReceiverInput = { export type CreateReceiverResponse = { __typename?: 'CreateReceiverResponse'; - code: Scalars['String']['output']; - message?: Maybe; receiver?: Maybe; - success: Scalars['Boolean']['output']; }; export type CreateWalletAddressInput = { @@ -322,19 +310,13 @@ export type CreateWalletAddressKeyInput = { walletAddressId: Scalars['String']['input']; }; -export type CreateWalletAddressKeyMutationResponse = MutationResponse & { +export type CreateWalletAddressKeyMutationResponse = { __typename?: 'CreateWalletAddressKeyMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddressKey?: Maybe; }; -export type CreateWalletAddressMutationResponse = MutationResponse & { +export type CreateWalletAddressMutationResponse = { __typename?: 'CreateWalletAddressMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddress?: Maybe; }; @@ -360,11 +342,9 @@ export type DeleteAssetInput = { idempotencyKey?: InputMaybe; }; -export type DeleteAssetMutationResponse = MutationResponse & { +export type DeleteAssetMutationResponse = { __typename?: 'DeleteAssetMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; + asset?: Maybe; }; export type DeletePeerInput = { @@ -373,10 +353,8 @@ export type DeletePeerInput = { idempotencyKey?: InputMaybe; }; -export type DeletePeerMutationResponse = MutationResponse & { +export type DeletePeerMutationResponse = { __typename?: 'DeletePeerMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; success: Scalars['Boolean']['output']; }; @@ -533,10 +511,7 @@ export type IncomingPaymentEdge = { export type IncomingPaymentResponse = { __typename?: 'IncomingPaymentResponse'; - code: Scalars['String']['output']; - message?: Maybe; payment?: Maybe; - success: Scalars['Boolean']['output']; }; export enum IncomingPaymentState { @@ -596,11 +571,8 @@ export enum LiquidityError { UnknownWalletAddress = 'UnknownWalletAddress' } -export type LiquidityMutationResponse = MutationResponse & { +export type LiquidityMutationResponse = { __typename?: 'LiquidityMutationResponse'; - code: Scalars['String']['output']; - error?: Maybe; - message: Scalars['String']['output']; success: Scalars['Boolean']['output']; }; @@ -836,12 +808,6 @@ export type MutationWithdrawEventLiquidityArgs = { input: WithdrawEventLiquidityInput; }; -export type MutationResponse = { - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; -}; - export type OutgoingPayment = BasePayment & Model & { __typename?: 'OutgoingPayment'; /** Information about the wallet address of the Open Payments client that created the outgoing payment. */ @@ -886,10 +852,7 @@ export type OutgoingPaymentEdge = { export type OutgoingPaymentResponse = { __typename?: 'OutgoingPaymentResponse'; - code: Scalars['String']['output']; - message?: Maybe; payment?: Maybe; - success: Scalars['Boolean']['output']; }; export enum OutgoingPaymentState { @@ -1150,10 +1113,7 @@ export type QuoteEdge = { export type QuoteResponse = { __typename?: 'QuoteResponse'; - code: Scalars['String']['output']; - message?: Maybe; quote?: Maybe; - success: Scalars['Boolean']['output']; }; export type Receiver = { @@ -1185,11 +1145,8 @@ export type RevokeWalletAddressKeyInput = { idempotencyKey?: InputMaybe; }; -export type RevokeWalletAddressKeyMutationResponse = MutationResponse & { +export type RevokeWalletAddressKeyMutationResponse = { __typename?: 'RevokeWalletAddressKeyMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddressKey?: Maybe; }; @@ -1204,12 +1161,9 @@ export type SetFeeInput = { type: FeeType; }; -export type SetFeeResponse = MutationResponse & { +export type SetFeeResponse = { __typename?: 'SetFeeResponse'; - code: Scalars['String']['output']; fee?: Maybe; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; }; export enum SortOrder { @@ -1219,13 +1173,6 @@ export enum SortOrder { Desc = 'DESC' } -export type TransferMutationResponse = MutationResponse & { - __typename?: 'TransferMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; -}; - export type TriggerWalletAddressEventsInput = { /** Unique key to ensure duplicate or retried requests are processed only once. See [idempotence](https://en.wikipedia.org/wiki/Idempotence) */ idempotencyKey?: InputMaybe; @@ -1233,13 +1180,10 @@ export type TriggerWalletAddressEventsInput = { limit: Scalars['Int']['input']; }; -export type TriggerWalletAddressEventsMutationResponse = MutationResponse & { +export type TriggerWalletAddressEventsMutationResponse = { __typename?: 'TriggerWalletAddressEventsMutationResponse'; - code: Scalars['String']['output']; /** Number of events triggered */ count?: Maybe; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; }; export type UpdateAssetInput = { @@ -1270,12 +1214,9 @@ export type UpdatePeerInput = { staticIlpAddress?: InputMaybe; }; -export type UpdatePeerMutationResponse = MutationResponse & { +export type UpdatePeerMutationResponse = { __typename?: 'UpdatePeerMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; peer?: Maybe; - success: Scalars['Boolean']['output']; }; export type UpdateWalletAddressInput = { @@ -1291,11 +1232,8 @@ export type UpdateWalletAddressInput = { status?: InputMaybe; }; -export type UpdateWalletAddressMutationResponse = MutationResponse & { +export type UpdateWalletAddressMutationResponse = { __typename?: 'UpdateWalletAddressMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddress?: Maybe; }; @@ -1419,12 +1357,8 @@ export type WalletAddressWithdrawal = { walletAddress: WalletAddress; }; -export type WalletAddressWithdrawalMutationResponse = MutationResponse & { +export type WalletAddressWithdrawalMutationResponse = { __typename?: 'WalletAddressWithdrawalMutationResponse'; - code: Scalars['String']['output']; - error?: Maybe; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; withdrawal?: Maybe; }; @@ -1541,7 +1475,6 @@ export type DirectiveResolverFn> = { BasePayment: ( Partial ) | ( Partial ) | ( Partial ); Model: ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ); - MutationResponse: ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ); }; /** Mapping between all available schema types and the resolvers types */ @@ -1614,7 +1547,6 @@ export type ResolversTypes = { LiquidityMutationResponse: ResolverTypeWrapper>; Model: ResolverTypeWrapper['Model']>; Mutation: ResolverTypeWrapper<{}>; - MutationResponse: ResolverTypeWrapper['MutationResponse']>; OutgoingPayment: ResolverTypeWrapper>; OutgoingPaymentConnection: ResolverTypeWrapper>; OutgoingPaymentEdge: ResolverTypeWrapper>; @@ -1642,7 +1574,6 @@ export type ResolversTypes = { SetFeeResponse: ResolverTypeWrapper>; SortOrder: ResolverTypeWrapper>; String: ResolverTypeWrapper>; - TransferMutationResponse: ResolverTypeWrapper>; TriggerWalletAddressEventsInput: ResolverTypeWrapper>; TriggerWalletAddressEventsMutationResponse: ResolverTypeWrapper>; UInt8: ResolverTypeWrapper>; @@ -1733,7 +1664,6 @@ export type ResolversParentTypes = { LiquidityMutationResponse: Partial; Model: ResolversInterfaceTypes['Model']; Mutation: {}; - MutationResponse: ResolversInterfaceTypes['MutationResponse']; OutgoingPayment: Partial; OutgoingPaymentConnection: Partial; OutgoingPaymentEdge: Partial; @@ -1758,7 +1688,6 @@ export type ResolversParentTypes = { SetFeeInput: Partial; SetFeeResponse: Partial; String: Partial; - TransferMutationResponse: Partial; TriggerWalletAddressEventsInput: Partial; TriggerWalletAddressEventsMutationResponse: Partial; UInt8: Partial; @@ -1820,9 +1749,6 @@ export type AssetEdgeResolvers = { asset?: Resolver, ParentType, ContextType>; - code?: Resolver; - message?: Resolver; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -1842,55 +1768,36 @@ export type BasePaymentResolvers = { - code?: Resolver; - message?: Resolver; peer?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type CreatePeerMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; peer?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type CreateReceiverResponseResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; receiver?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type CreateWalletAddressKeyMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddressKey?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type CreateWalletAddressMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddress?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type DeleteAssetMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; + asset?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type DeletePeerMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -1955,10 +1862,7 @@ export type IncomingPaymentEdgeResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; payment?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -1976,9 +1880,6 @@ export type JwkResolvers = { - code?: Resolver; - error?: Resolver, ParentType, ContextType>; - message?: Resolver; success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2023,13 +1924,6 @@ export type MutationResolvers, ParentType, ContextType, RequireFields>; }; -export type MutationResponseResolvers = { - __resolveType: TypeResolveFn<'AssetMutationResponse' | 'CreateOrUpdatePeerByUrlMutationResponse' | 'CreatePeerMutationResponse' | 'CreateWalletAddressKeyMutationResponse' | 'CreateWalletAddressMutationResponse' | 'DeleteAssetMutationResponse' | 'DeletePeerMutationResponse' | 'LiquidityMutationResponse' | 'RevokeWalletAddressKeyMutationResponse' | 'SetFeeResponse' | 'TransferMutationResponse' | 'TriggerWalletAddressEventsMutationResponse' | 'UpdatePeerMutationResponse' | 'UpdateWalletAddressMutationResponse' | 'WalletAddressWithdrawalMutationResponse', ParentType, ContextType>; - code?: Resolver; - message?: Resolver; - success?: Resolver; -}; - export type OutgoingPaymentResolvers = { client?: Resolver, ParentType, ContextType>; createdAt?: Resolver; @@ -2061,10 +1955,7 @@ export type OutgoingPaymentEdgeResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; payment?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2168,10 +2059,7 @@ export type QuoteEdgeResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; quote?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2189,33 +2077,17 @@ export type ReceiverResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddressKey?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type SetFeeResponseResolvers = { - code?: Resolver; fee?: Resolver, ParentType, ContextType>; - message?: Resolver; - success?: Resolver; - __isTypeOf?: IsTypeOfResolverFn; -}; - -export type TransferMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type TriggerWalletAddressEventsMutationResponseResolvers = { - code?: Resolver; count?: Resolver, ParentType, ContextType>; - message?: Resolver; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2228,17 +2100,11 @@ export interface UInt64ScalarConfig extends GraphQLScalarTypeConfig = { - code?: Resolver; - message?: Resolver; peer?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type UpdateWalletAddressMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddress?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2294,10 +2160,6 @@ export type WalletAddressWithdrawalResolvers = { - code?: Resolver; - error?: Resolver, ParentType, ContextType>; - message?: Resolver; - success?: Resolver; withdrawal?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2357,7 +2219,6 @@ export type Resolvers = { LiquidityMutationResponse?: LiquidityMutationResponseResolvers; Model?: ModelResolvers; Mutation?: MutationResolvers; - MutationResponse?: MutationResponseResolvers; OutgoingPayment?: OutgoingPaymentResolvers; OutgoingPaymentConnection?: OutgoingPaymentConnectionResolvers; OutgoingPaymentEdge?: OutgoingPaymentEdgeResolvers; @@ -2377,7 +2238,6 @@ export type Resolvers = { Receiver?: ReceiverResolvers; RevokeWalletAddressKeyMutationResponse?: RevokeWalletAddressKeyMutationResponseResolvers; SetFeeResponse?: SetFeeResponseResolvers; - TransferMutationResponse?: TransferMutationResponseResolvers; TriggerWalletAddressEventsMutationResponse?: TriggerWalletAddressEventsMutationResponseResolvers; UInt8?: GraphQLScalarType; UInt64?: GraphQLScalarType; diff --git a/packages/mock-account-service-lib/src/requesters.ts b/packages/mock-account-service-lib/src/requesters.ts index 515c196073..e6edd93bb9 100644 --- a/packages/mock-account-service-lib/src/requesters.ts +++ b/packages/mock-account-service-lib/src/requesters.ts @@ -117,9 +117,6 @@ export async function createAsset( const createAssetMutation = gql` mutation CreateAsset($input: CreateAssetInput!) { createAsset(input: $input) { - code - success - message asset { id code @@ -142,7 +139,7 @@ export async function createAsset( variables: createAssetInput }) .then(({ data }): AssetMutationResponse => { - if (!data.createAsset.success) { + if (!data.createAsset.asset) { throw new Error('Data was empty') } return data.createAsset @@ -162,9 +159,6 @@ export async function createPeer( const createPeerMutation = gql` mutation CreatePeer($input: CreatePeerInput!) { createPeer(input: $input) { - code - success - message peer { id } @@ -190,7 +184,7 @@ export async function createPeer( }) .then(({ data }): CreatePeerMutationResponse => { logger.debug(data) - if (!data.createPeer.success) { + if (!data.createPeer.peer) { throw new Error('Data was empty') } return data.createPeer @@ -206,9 +200,6 @@ export async function createAutoPeer( const createAutoPeerMutation = gql` mutation CreateOrUpdatePeerByUrl($input: CreateOrUpdatePeerByUrlInput!) { createOrUpdatePeerByUrl(input: $input) { - code - success - message peer { id name @@ -237,7 +228,7 @@ export async function createAutoPeer( variables: createPeerInput }) .then(({ data }): CreateOrUpdatePeerByUrlMutationResponse => { - if (!data.createOrUpdatePeerByUrl.success) { + if (!data.createOrUpdatePeerByUrl.peer) { logger.debug(data.createOrUpdatePeerByUrl) throw new Error(`Data was empty for assetId: ${assetId}`) } @@ -255,10 +246,7 @@ export async function depositPeerLiquidity( const depositPeerLiquidityMutation = gql` mutation DepositPeerLiquidity($input: DepositPeerLiquidityInput!) { depositPeerLiquidity(input: $input) { - code success - message - error } } ` @@ -277,7 +265,7 @@ export async function depositPeerLiquidity( }) .then(({ data }): LiquidityMutationResponse => { logger.debug(data) - if (!data.depositPeerLiquidity.success) { + if (!data.depositPeerLiquidity) { throw new Error('Data was empty') } return data.depositPeerLiquidity @@ -294,10 +282,7 @@ export async function depositAssetLiquidity( const depositAssetLiquidityMutation = gql` mutation DepositAssetLiquidity($input: DepositAssetLiquidityInput!) { depositAssetLiquidity(input: $input) { - code success - message - error } } ` @@ -316,7 +301,7 @@ export async function depositAssetLiquidity( }) .then(({ data }): LiquidityMutationResponse => { logger.debug(data) - if (!data.depositAssetLiquidity.success) { + if (!data.depositAssetLiquidity) { throw new Error('Data was empty') } return data.depositAssetLiquidity @@ -333,9 +318,6 @@ export async function createWalletAddress( const createWalletAddressMutation = gql` mutation CreateWalletAddress($input: CreateWalletAddressInput!) { createWalletAddress(input: $input) { - code - success - message walletAddress { id url @@ -361,10 +343,7 @@ export async function createWalletAddress( .then(({ data }) => { logger.debug(data) - if ( - !data.createWalletAddress.success || - !data.createWalletAddress.walletAddress - ) { + if (!data.createWalletAddress.walletAddress) { throw new Error('Data was empty') } @@ -386,9 +365,9 @@ export async function createWalletAddressKey( const createWalletAddressKeyMutation = gql` mutation CreateWalletAddressKey($input: CreateWalletAddressKeyInput!) { createWalletAddressKey(input: $input) { - code - success - message + walletAddressKey { + id + } } } ` @@ -406,7 +385,7 @@ export async function createWalletAddressKey( }) .then(({ data }): CreateWalletAddressKeyMutationResponse => { logger.debug(data) - if (!data.createWalletAddressKey.success) { + if (!data.createWalletAddressKey.walletAddressKey) { throw new Error('Data was empty') } return data.createWalletAddressKey @@ -424,9 +403,6 @@ export async function setFee( const setFeeMutation = gql` mutation SetFee($input: SetFeeInput!) { setFee(input: $input) { - code - success - message fee { id assetId diff --git a/packages/mock-account-service-lib/src/seed.ts b/packages/mock-account-service-lib/src/seed.ts index 50a82a2615..eb1fc20515 100644 --- a/packages/mock-account-service-lib/src/seed.ts +++ b/packages/mock-account-service-lib/src/seed.ts @@ -48,14 +48,10 @@ export async function setupFromSeed( throw new Error('asset not defined') } - const initialLiquidity = await depositAssetLiquidity( - asset.id, - liquidity, - v4() - ) + await depositAssetLiquidity(asset.id, liquidity, v4()) assets[code] = asset - logger.debug({ asset, initialLiquidity }) + logger.debug({ asset, liquidity }) const { fees } = config.seed const fee = fees.find((fee) => fee.asset === code && fee.scale == scale) @@ -80,12 +76,12 @@ export async function setupFromSeed( throw new Error('peer response not defined') } const transferUid = v4() - const liquidity = await depositPeerLiquidity( + await depositPeerLiquidity( peerResponse.id, peer.initialLiquidity, transferUid ) - return [peerResponse, liquidity] + return [peerResponse, peer.initialLiquidity] }) ) diff --git a/test/integration/lib/admin-client.ts b/test/integration/lib/admin-client.ts index 42e2314e96..08f176ad67 100644 --- a/test/integration/lib/admin-client.ts +++ b/test/integration/lib/admin-client.ts @@ -30,8 +30,6 @@ export class AdminClient { mutation: gql` mutation CreateReceiver($input: CreateReceiverInput!) { createReceiver(input: $input) { - code - message receiver { completed createdAt @@ -51,7 +49,6 @@ export class AdminClient { } updatedAt } - success } } `, @@ -68,8 +65,6 @@ export class AdminClient { mutation: gql` mutation CreateQuote($input: CreateQuoteInput!) { createQuote(input: $input) { - code - message quote { createdAt expiresAt @@ -109,8 +104,6 @@ export class AdminClient { mutation: gql` mutation CreateOutgoingPayment($input: CreateOutgoingPaymentInput!) { createOutgoingPayment(input: $input) { - code - message payment { createdAt error @@ -136,7 +129,6 @@ export class AdminClient { state stateAttempts } - success } } `, @@ -231,10 +223,7 @@ export class AdminClient { $input: DepositOutgoingPaymentLiquidityInput! ) { depositOutgoingPaymentLiquidity(input: $input) { - code success - message - error } } `, @@ -253,7 +242,6 @@ export class AdminClient { mutation: gql` mutation CreateWalletAddress($input: CreateWalletAddressInput!) { createWalletAddress(input: $input) { - success walletAddress { id url diff --git a/test/integration/lib/generated/graphql.ts b/test/integration/lib/generated/graphql.ts index af780bc3ad..46f7835344 100644 --- a/test/integration/lib/generated/graphql.ts +++ b/test/integration/lib/generated/graphql.ts @@ -92,12 +92,9 @@ export type AssetEdge = { node: Asset; }; -export type AssetMutationResponse = MutationResponse & { +export type AssetMutationResponse = { __typename?: 'AssetMutationResponse'; asset?: Maybe; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; }; export type AssetsConnection = { @@ -186,12 +183,9 @@ export type CreateOrUpdatePeerByUrlInput = { peerUrl: Scalars['String']['input']; }; -export type CreateOrUpdatePeerByUrlMutationResponse = MutationResponse & { +export type CreateOrUpdatePeerByUrlMutationResponse = { __typename?: 'CreateOrUpdatePeerByUrlMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; peer?: Maybe; - success: Scalars['Boolean']['output']; }; export type CreateOutgoingPaymentFromIncomingPaymentInput = { @@ -259,12 +253,9 @@ export type CreatePeerLiquidityWithdrawalInput = { timeoutSeconds: Scalars['UInt64']['input']; }; -export type CreatePeerMutationResponse = MutationResponse & { +export type CreatePeerMutationResponse = { __typename?: 'CreatePeerMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; peer?: Maybe; - success: Scalars['Boolean']['output']; }; export type CreateQuoteInput = { @@ -295,10 +286,7 @@ export type CreateReceiverInput = { export type CreateReceiverResponse = { __typename?: 'CreateReceiverResponse'; - code: Scalars['String']['output']; - message?: Maybe; receiver?: Maybe; - success: Scalars['Boolean']['output']; }; export type CreateWalletAddressInput = { @@ -322,19 +310,13 @@ export type CreateWalletAddressKeyInput = { walletAddressId: Scalars['String']['input']; }; -export type CreateWalletAddressKeyMutationResponse = MutationResponse & { +export type CreateWalletAddressKeyMutationResponse = { __typename?: 'CreateWalletAddressKeyMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddressKey?: Maybe; }; -export type CreateWalletAddressMutationResponse = MutationResponse & { +export type CreateWalletAddressMutationResponse = { __typename?: 'CreateWalletAddressMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddress?: Maybe; }; @@ -360,11 +342,9 @@ export type DeleteAssetInput = { idempotencyKey?: InputMaybe; }; -export type DeleteAssetMutationResponse = MutationResponse & { +export type DeleteAssetMutationResponse = { __typename?: 'DeleteAssetMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; + asset?: Maybe; }; export type DeletePeerInput = { @@ -373,10 +353,8 @@ export type DeletePeerInput = { idempotencyKey?: InputMaybe; }; -export type DeletePeerMutationResponse = MutationResponse & { +export type DeletePeerMutationResponse = { __typename?: 'DeletePeerMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; success: Scalars['Boolean']['output']; }; @@ -533,10 +511,7 @@ export type IncomingPaymentEdge = { export type IncomingPaymentResponse = { __typename?: 'IncomingPaymentResponse'; - code: Scalars['String']['output']; - message?: Maybe; payment?: Maybe; - success: Scalars['Boolean']['output']; }; export enum IncomingPaymentState { @@ -596,11 +571,8 @@ export enum LiquidityError { UnknownWalletAddress = 'UnknownWalletAddress' } -export type LiquidityMutationResponse = MutationResponse & { +export type LiquidityMutationResponse = { __typename?: 'LiquidityMutationResponse'; - code: Scalars['String']['output']; - error?: Maybe; - message: Scalars['String']['output']; success: Scalars['Boolean']['output']; }; @@ -836,12 +808,6 @@ export type MutationWithdrawEventLiquidityArgs = { input: WithdrawEventLiquidityInput; }; -export type MutationResponse = { - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; -}; - export type OutgoingPayment = BasePayment & Model & { __typename?: 'OutgoingPayment'; /** Information about the wallet address of the Open Payments client that created the outgoing payment. */ @@ -886,10 +852,7 @@ export type OutgoingPaymentEdge = { export type OutgoingPaymentResponse = { __typename?: 'OutgoingPaymentResponse'; - code: Scalars['String']['output']; - message?: Maybe; payment?: Maybe; - success: Scalars['Boolean']['output']; }; export enum OutgoingPaymentState { @@ -1150,10 +1113,7 @@ export type QuoteEdge = { export type QuoteResponse = { __typename?: 'QuoteResponse'; - code: Scalars['String']['output']; - message?: Maybe; quote?: Maybe; - success: Scalars['Boolean']['output']; }; export type Receiver = { @@ -1185,11 +1145,8 @@ export type RevokeWalletAddressKeyInput = { idempotencyKey?: InputMaybe; }; -export type RevokeWalletAddressKeyMutationResponse = MutationResponse & { +export type RevokeWalletAddressKeyMutationResponse = { __typename?: 'RevokeWalletAddressKeyMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddressKey?: Maybe; }; @@ -1204,12 +1161,9 @@ export type SetFeeInput = { type: FeeType; }; -export type SetFeeResponse = MutationResponse & { +export type SetFeeResponse = { __typename?: 'SetFeeResponse'; - code: Scalars['String']['output']; fee?: Maybe; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; }; export enum SortOrder { @@ -1219,13 +1173,6 @@ export enum SortOrder { Desc = 'DESC' } -export type TransferMutationResponse = MutationResponse & { - __typename?: 'TransferMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; -}; - export type TriggerWalletAddressEventsInput = { /** Unique key to ensure duplicate or retried requests are processed only once. See [idempotence](https://en.wikipedia.org/wiki/Idempotence) */ idempotencyKey?: InputMaybe; @@ -1233,13 +1180,10 @@ export type TriggerWalletAddressEventsInput = { limit: Scalars['Int']['input']; }; -export type TriggerWalletAddressEventsMutationResponse = MutationResponse & { +export type TriggerWalletAddressEventsMutationResponse = { __typename?: 'TriggerWalletAddressEventsMutationResponse'; - code: Scalars['String']['output']; /** Number of events triggered */ count?: Maybe; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; }; export type UpdateAssetInput = { @@ -1270,12 +1214,9 @@ export type UpdatePeerInput = { staticIlpAddress?: InputMaybe; }; -export type UpdatePeerMutationResponse = MutationResponse & { +export type UpdatePeerMutationResponse = { __typename?: 'UpdatePeerMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; peer?: Maybe; - success: Scalars['Boolean']['output']; }; export type UpdateWalletAddressInput = { @@ -1291,11 +1232,8 @@ export type UpdateWalletAddressInput = { status?: InputMaybe; }; -export type UpdateWalletAddressMutationResponse = MutationResponse & { +export type UpdateWalletAddressMutationResponse = { __typename?: 'UpdateWalletAddressMutationResponse'; - code: Scalars['String']['output']; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; walletAddress?: Maybe; }; @@ -1419,12 +1357,8 @@ export type WalletAddressWithdrawal = { walletAddress: WalletAddress; }; -export type WalletAddressWithdrawalMutationResponse = MutationResponse & { +export type WalletAddressWithdrawalMutationResponse = { __typename?: 'WalletAddressWithdrawalMutationResponse'; - code: Scalars['String']['output']; - error?: Maybe; - message: Scalars['String']['output']; - success: Scalars['Boolean']['output']; withdrawal?: Maybe; }; @@ -1541,7 +1475,6 @@ export type DirectiveResolverFn> = { BasePayment: ( Partial ) | ( Partial ) | ( Partial ); Model: ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ); - MutationResponse: ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ) | ( Partial ); }; /** Mapping between all available schema types and the resolvers types */ @@ -1614,7 +1547,6 @@ export type ResolversTypes = { LiquidityMutationResponse: ResolverTypeWrapper>; Model: ResolverTypeWrapper['Model']>; Mutation: ResolverTypeWrapper<{}>; - MutationResponse: ResolverTypeWrapper['MutationResponse']>; OutgoingPayment: ResolverTypeWrapper>; OutgoingPaymentConnection: ResolverTypeWrapper>; OutgoingPaymentEdge: ResolverTypeWrapper>; @@ -1642,7 +1574,6 @@ export type ResolversTypes = { SetFeeResponse: ResolverTypeWrapper>; SortOrder: ResolverTypeWrapper>; String: ResolverTypeWrapper>; - TransferMutationResponse: ResolverTypeWrapper>; TriggerWalletAddressEventsInput: ResolverTypeWrapper>; TriggerWalletAddressEventsMutationResponse: ResolverTypeWrapper>; UInt8: ResolverTypeWrapper>; @@ -1733,7 +1664,6 @@ export type ResolversParentTypes = { LiquidityMutationResponse: Partial; Model: ResolversInterfaceTypes['Model']; Mutation: {}; - MutationResponse: ResolversInterfaceTypes['MutationResponse']; OutgoingPayment: Partial; OutgoingPaymentConnection: Partial; OutgoingPaymentEdge: Partial; @@ -1758,7 +1688,6 @@ export type ResolversParentTypes = { SetFeeInput: Partial; SetFeeResponse: Partial; String: Partial; - TransferMutationResponse: Partial; TriggerWalletAddressEventsInput: Partial; TriggerWalletAddressEventsMutationResponse: Partial; UInt8: Partial; @@ -1820,9 +1749,6 @@ export type AssetEdgeResolvers = { asset?: Resolver, ParentType, ContextType>; - code?: Resolver; - message?: Resolver; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -1842,55 +1768,36 @@ export type BasePaymentResolvers = { - code?: Resolver; - message?: Resolver; peer?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type CreatePeerMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; peer?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type CreateReceiverResponseResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; receiver?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type CreateWalletAddressKeyMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddressKey?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type CreateWalletAddressMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddress?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type DeleteAssetMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; + asset?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type DeletePeerMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -1955,10 +1862,7 @@ export type IncomingPaymentEdgeResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; payment?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -1976,9 +1880,6 @@ export type JwkResolvers = { - code?: Resolver; - error?: Resolver, ParentType, ContextType>; - message?: Resolver; success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2023,13 +1924,6 @@ export type MutationResolvers, ParentType, ContextType, RequireFields>; }; -export type MutationResponseResolvers = { - __resolveType: TypeResolveFn<'AssetMutationResponse' | 'CreateOrUpdatePeerByUrlMutationResponse' | 'CreatePeerMutationResponse' | 'CreateWalletAddressKeyMutationResponse' | 'CreateWalletAddressMutationResponse' | 'DeleteAssetMutationResponse' | 'DeletePeerMutationResponse' | 'LiquidityMutationResponse' | 'RevokeWalletAddressKeyMutationResponse' | 'SetFeeResponse' | 'TransferMutationResponse' | 'TriggerWalletAddressEventsMutationResponse' | 'UpdatePeerMutationResponse' | 'UpdateWalletAddressMutationResponse' | 'WalletAddressWithdrawalMutationResponse', ParentType, ContextType>; - code?: Resolver; - message?: Resolver; - success?: Resolver; -}; - export type OutgoingPaymentResolvers = { client?: Resolver, ParentType, ContextType>; createdAt?: Resolver; @@ -2061,10 +1955,7 @@ export type OutgoingPaymentEdgeResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; payment?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2168,10 +2059,7 @@ export type QuoteEdgeResolvers = { - code?: Resolver; - message?: Resolver, ParentType, ContextType>; quote?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2189,33 +2077,17 @@ export type ReceiverResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddressKey?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; export type SetFeeResponseResolvers = { - code?: Resolver; fee?: Resolver, ParentType, ContextType>; - message?: Resolver; - success?: Resolver; - __isTypeOf?: IsTypeOfResolverFn; -}; - -export type TransferMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type TriggerWalletAddressEventsMutationResponseResolvers = { - code?: Resolver; count?: Resolver, ParentType, ContextType>; - message?: Resolver; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2228,17 +2100,11 @@ export interface UInt64ScalarConfig extends GraphQLScalarTypeConfig = { - code?: Resolver; - message?: Resolver; peer?: Resolver, ParentType, ContextType>; - success?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type UpdateWalletAddressMutationResponseResolvers = { - code?: Resolver; - message?: Resolver; - success?: Resolver; walletAddress?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2294,10 +2160,6 @@ export type WalletAddressWithdrawalResolvers = { - code?: Resolver; - error?: Resolver, ParentType, ContextType>; - message?: Resolver; - success?: Resolver; withdrawal?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2357,7 +2219,6 @@ export type Resolvers = { LiquidityMutationResponse?: LiquidityMutationResponseResolvers; Model?: ModelResolvers; Mutation?: MutationResolvers; - MutationResponse?: MutationResponseResolvers; OutgoingPayment?: OutgoingPaymentResolvers; OutgoingPaymentConnection?: OutgoingPaymentConnectionResolvers; OutgoingPaymentEdge?: OutgoingPaymentEdgeResolvers; @@ -2377,7 +2238,6 @@ export type Resolvers = { Receiver?: ReceiverResolvers; RevokeWalletAddressKeyMutationResponse?: RevokeWalletAddressKeyMutationResponseResolvers; SetFeeResponse?: SetFeeResponseResolvers; - TransferMutationResponse?: TransferMutationResponseResolvers; TriggerWalletAddressEventsMutationResponse?: TriggerWalletAddressEventsMutationResponseResolvers; UInt8?: GraphQLScalarType; UInt64?: GraphQLScalarType; diff --git a/test/integration/lib/integration-server.ts b/test/integration/lib/integration-server.ts index 1c5ccd4616..54ba96559c 100644 --- a/test/integration/lib/integration-server.ts +++ b/test/integration/lib/integration-server.ts @@ -134,9 +134,6 @@ export class WebhookEventHandler { }) const { walletAddress } = response - if (!response.success) { - throw new Error('Failed to create wallet address') - } if (!walletAddress) { throw new Error('Could not get wallet address') } @@ -175,7 +172,7 @@ export class WebhookEventHandler { idempotencyKey: crypto.randomUUID() }) - if (response.code !== '200') { + if (!response.success) { const msg = 'Deposit outgoing payment liquidity failed' throw new Error(msg) } diff --git a/test/integration/lib/test-actions/admin.ts b/test/integration/lib/test-actions/admin.ts index c4fffe5f99..15dc6114d6 100644 --- a/test/integration/lib/test-actions/admin.ts +++ b/test/integration/lib/test-actions/admin.ts @@ -57,7 +57,6 @@ async function createReceiver( const response = await sendingASE.adminClient.createReceiver(createReceiverInput) - expect(response.code).toBe('200') assert(response.receiver) await pollCondition( @@ -90,7 +89,6 @@ async function createQuote( receiver: receiver.id }) - expect(response.code).toBe('200') assert(response.quote) return response.quote @@ -111,7 +109,6 @@ async function createOutgoingPayment( quoteId: quote.id }) - expect(response.code).toBe('201') assert(response.payment) await pollCondition(