-
Notifications
You must be signed in to change notification settings - Fork 81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
938/mk/create receiver #986
Conversation
const { paymentPointerUrl } = args | ||
const grant = await getGrant(deps, paymentPointerUrl, [ | ||
AccessAction.Create, | ||
AccessAction.ReadAll |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to have a GetRemoteIncomingPayment
query in the Admin API in addition to this "Create" one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created separate issue, I'll mark it as nice-to-have:
CC @wilsonianb
openPaymentsClient: AuthenticatedClient | ||
} | ||
|
||
export async function createRemoteIncomingPaymentService( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In a separate PR, I want the ReceiverService
to use this service to fetch remote incoming payments, since it has some similar logic currently. (ReceiverService
determines whether an incoming payment (or connection) is local and remote, and fetches either)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if the mutation was instead CreateReceiver
?
I like the idea of making it clear what the purpose of this is.
We could add a ReceiverService.create
(which could create locally or remotely) but still move remote management to RemoteIncomingPaymentService
if we wanted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔
- Are you suggesting we also remove
CreateIncomingPayment
and consolidate both remote and incoming payment creation withCreateReceiver
? - If not, is it confusing having both
CreateIncomingPayment
andCreateReceiver
? Could someone get confused why are they different at first glance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking we have both
CreateIncomingPayment
for a user to get paidCreateReceiver
for a user to pay someone
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does fit in well with the quote creation, receiver
attribute as well.
RemoteIncomingPayment
GraphQL type can also be also a Receiver
instead, going to make that change
@@ -0,0 +1,92 @@ | |||
import { v4 as uuid } from 'uuid' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took this from the open-payments
package, since I wanted to mock the results from the open-payments
client calls. I could also export these mocks directly from the library if that feels like a better solution
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm good with exported mocks
|
||
const grantOptions = { | ||
authServer: paymentPointer.authServer, | ||
accessType: 'incoming-payment' as const, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was hoping 👆 would allow 👇 but 😞
accessType: 'incoming-payment' as const, | |
accessType: AccessType.IncomingPayment, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does allow AccessType.IncomingPayment
, but I still need to do as
incoming-payment` when making the call for the grant request below
@@ -0,0 +1,92 @@ | |||
import { v4 as uuid } from 'uuid' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm good with exported mocks
openPaymentsClient: AuthenticatedClient | ||
} | ||
|
||
export async function createRemoteIncomingPaymentService( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if the mutation was instead CreateReceiver
?
I like the idea of making it clear what the purpose of this is.
We could add a ReceiverService.create
(which could create locally or remotely) but still move remote management to RemoteIncomingPaymentService
if we wanted.
* feat(backend): add create method for receiverService * chore(backend): createRemoteIncomingPayment mutation -> createReceiver mutation * chore(backend): update ReceiverService tests to use mocks when fetching remote incoming payments * chore(backend): use open-payments mocks * chore(backend): fix receiver tests * chore(backend): update receiver tests * chore(backend): couple more updated tests
@@ -245,7 +245,7 @@ export class IncomingPayment | |||
ilpStreamConnection: Connection | |||
}): OpenPaymentsIncomingPayment { | |||
return { | |||
id: this.id, | |||
id: this.url, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Copying comment from other PR for visibility):
OpenPayment API IncomingPayments return the full url instead of just the uuid. This reflects what is done in the IncomingPaymentRoutes, but standardizes it when converting between IncomingPayment model and what Open Payments expects
@@ -155,6 +157,8 @@ export interface AppServices { | |||
paymentPointerKeyRoutes: Promise<PaymentPointerKeyRoutes> | |||
paymentPointerRoutes: Promise<PaymentPointerRoutes> | |||
incomingPaymentService: Promise<IncomingPaymentService> | |||
remoteIncomingPaymentService: Promise<RemoteIncomingPaymentService> | |||
receiverService: Promise<ReceiverService> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not new, just adding so we get proper typing when we resolve this dependency
return incomingPaymentOrError.toOpenPaymentsType({ | ||
ilpStreamConnection: connection | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once I split out the IncomingPayment
types in open-payments
with and without the ilpStreamConnection
The corresponding connection fetching will (should?) be optional
Will also update the Postman collection once this is merged in |
# Conflicts: # packages/backend/src/app.ts
} | ||
} | ||
|
||
async function getGrant( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we somehow consolidate this and
async function getIncomingPaymentGrant( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, for sure. I was going to do that as a follow up so the PR was manageable
packages/backend/src/open_payments/payment/incoming_remote/service.ts
Outdated
Show resolved
Hide resolved
export interface RemoteIncomingPaymentService { | ||
create( | ||
args: CreateRemoteIncomingPaymentArgs | ||
): Promise<OpenPaymentsIncomingPayment> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
): Promise<OpenPaymentsIncomingPayment> | |
): Promise<OpenPaymentsIncomingPayment | IncomingPaymentError> |
to be able to return IncomingPaymentError.UnknownPaymentPointer
(instead of throwing) and return the corresponding code and message in the createReceiver
resolver
export enum IncomingPaymentError { | |
UnknownPaymentPointer = 'UnknownPaymentPointer', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, do you mean
// ReceiverService
async function createLocalIncomingPayment(
deps: ServiceDependencies,
args: CreateReceiverArgs,
paymentPointer: PaymentPointer
): Promise<OpenPaymentsIncomingPayment | IncomingPaymentError> <---
instead? RemotePaymentService
can only return the OpenPaymentsIncomingPayment
since it uses the client
edit: I see what you mean, although I'd have to pass it all the way through and edit receiverService.create
return type as well 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if having a custom Error object with something like a userMessage
property would be a better approach
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I think it needs to be in RemotePaymentService
.
The payment pointer lookup in getGrant
should somehow bubble up an error to allow the resolver to return 4XX
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if having a custom Error object with something like a
userMessage
property would be a better approach
That'd probably work too. I'm just thinking through the lens of the other services' *Error
s.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, I'll give it a try 👍
const errorMessage = 'Could not get connection for local incoming payment' | ||
deps.logger.error({ incomingPaymentOrError }, errorMessage) | ||
|
||
throw new Error(errorMessage) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I can also return an additional type of ReceiverError
here as well, together with L93?
export const receiverErrorToCode = (error: ReceiverError): number => | ||
isIncomingPaymentError(error) | ||
? incomingPaymentErrorToCode[error] | ||
: remoteIncomingPaymentErrorToCode[error] | ||
|
||
export const receiverErrorToMessage = (error: ReceiverError): string => | ||
isIncomingPaymentError(error) | ||
? incomingPaymentErrorToMessage[error] | ||
: remoteIncomingPaymentErrorToMessage[error] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could have also just spread the two errorToMessage
/errorToCode
objects into a new receiver
errorToMessage
/errorToCode
object, but thought this was easier to follow
packages/backend/src/open_payments/payment/incoming_remote/service.test.ts
Outdated
Show resolved
Hide resolved
? serializeAmount(incomingAmount) | ||
: undefined | ||
}) | ||
) as Receiver |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be worth adding a createReceiver
(here or in tests/receiver
) that returns a guaranteed Receiver
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it would be better to have Receiver.fromIncomingPayment/fromConnection
to throw errors instead of returning undefined? It'll allow us to return error messages back to the caller
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 that or return Receiver | ReceiverError
😬
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ended up going with just throwing, will likely be changing out how the Receiver class works anyway if we want to go with type Receiver = IncomingPayment | Connection
expect(receiver).toBeUndefined() | ||
const connection = connectionService.get(incomingPayment) as Connection | ||
|
||
;(connection.ilpAddress as string) = 'not base 64 encoded' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this you or pnpm format
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pnpm format
Changes proposed in this pull request
CreateReceiver
mutation to GraphQL admin API, which allows creating a remote (or local) incoming paymentContext
Checklist
fixes #number