Add kyc level 2#587
Conversation
✅ Deploy Preview for pendulum-pay ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
| } | ||
|
|
||
| const lastEventCached = await eventPoller.getLatestEventForUser(subaccount.id); | ||
| const lastEventCached = await eventPoller.getLatestEventForUser(subaccount.id, 'KYC'); |
There was a problem hiding this comment.
I was thinking it might be a great idea to create an enum, like SubscriptionEvents, to include values such as KYC and other related events. This way, we can avoid scattering strings throughout the codebase, making our code cleaner and easier to maintain.
| export const WALLETCONNECT_ASSETHUB_ID = 'polkadot:68d56f15f85d3136970ec16946040bc1'; | ||
|
|
||
| export const TRANSFER_WAITING_TIME_SECONDS = 6000; | ||
| export const BRLA_MAXIMUM_LEVEL_2_AMOUNT_UNITS = 1000000; |
There was a problem hiding this comment.
can we link brla docs for the future reference?
There was a problem hiding this comment.
This level is not known, at least to me, so it was a placeholder to test. I'll add a comment.
| const { setRampKycStarted, resetRampState } = useRampActions(); | ||
|
|
||
| const offrampKycLevel2Started = useRampKycLevel2Started(); | ||
| const desiredLevel = offrampKycLevel2Started ? 2 : 1; |
There was a problem hiding this comment.
I was wondering if we could implement an enum for KYCLevels instead of using magic numbers?
This might help make the code more readable and maintainable.
There was a problem hiding this comment.
True, I'll add one for the numbers in this component.
| if (isValidCnpj(taxId)) { | ||
| await createSubaccount({ | ||
| ...formData, | ||
| // eslint-disable-next-line @typescript-eslint/no-non-null-assertion |
There was a problem hiding this comment.
Please just add a condition like
if (!formData.partnerCpf) {
throw new Error('useKYCProcess: Partner CPF must be defined at this point');
}
| validSetter(false); | ||
| return; | ||
| } | ||
| if (!ALLOWED_TYPES.includes(file.type)) { |
There was a problem hiding this comment.
I think we should enhance our file validation, the file.type can be spoofed and we should also check for the file extension like:
const extension = `.${getFileExtension(file.name)}`;
if (!ALLOWED_EXTENSIONS.includes(extension.toLowerCase())) {
We could also use Zod for the validation.
There was a problem hiding this comment.
Let's add this to our todo's and once we are sure about the restrictions that brla imposes on the images (regarding size, etc), we can add this improvement. Wdyt?
There was a problem hiding this comment.
Pull Request Overview
This pull request implements a new KYC level 2 component and integrates level 2 handling into the overall KYC flow for both companies (using CNPJ) and individuals (CPF). Key changes include adding a dedicated document upload component for level 2, updating the KYC process hook and related UI components, and extending backend models, endpoints, and migrations to support KYC level 2 verification.
Reviewed Changes
Copilot reviewed 41 out of 41 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| frontend/src/constants/constants.ts | Added constant for maximum level 2 KYC amount. |
| frontend/src/components/Ramp/Onramp/index.tsx | Removed an unused hook import. |
| frontend/src/components/BrlaComponents/VerificationStatus/index.tsx | Updated status prop and styling to differentiate between level 1 and level 2. |
| frontend/src/components/BrlaComponents/KYCLevel2Form/index.tsx | Introduced the new document upload UI component for KYC level 2. |
| frontend/src/components/BrlaComponents/KYCForm/index.tsx | Updated form fields and flow based on account type and KYC level. |
| frontend/src/components/BrlaComponents/BrlaField/index.tsx | Extended field options with company-specific fields. |
| api/src/models/kycLevel2.model.ts & migrations | Added new model and migration for KYC level 2 data storage. |
| api/src/api/services/kyc/kyc.service.ts & others | Integrated new endpoints and service logic to request and manage KYC level 2 verification. |
| api/src/api/controllers/brla.controller.ts | Updated subaccount creation and introduced the startKYC2 endpoint. |
ebma
left a comment
There was a problem hiding this comment.
Looking great overall, nice job 👍
I left a few comments, mostly minor stuff.
| router.route('/createSubaccount').post(validataSubaccountCreation, brlaController.createSubaccount); | ||
|
|
||
| router.route('/triggerPayIn').post(validateTriggerPayIn, brlaController.triggerPayIn); | ||
| router.route('/startKYC2').post(brlaController.startKYC2); |
There was a problem hiding this comment.
Just for the sake of it, why don't we add a validate... function like we do for any other post request.
| }, | ||
| "companyName": { | ||
| "required": "Company name is required", | ||
| "minLength": "Company name must be at least 3 characters", |
There was a problem hiding this comment.
no idea, just copy the other validations. I don't think brla checks this right?
There was a problem hiding this comment.
I think they do actually. But we'll see.
There was a problem hiding this comment.
Pull Request Overview
This PR extends the KYC flow to support Level 2 verification for both companies and individuals, enabling registration via CNPJ and allowing previously rejected users to reattempt verification. Key changes include the introduction of a new migration for the kyc_level_2 table, additions to API endpoints and services to support KYC Level 2, and updates to related validators and controllers.
Reviewed Changes
Copilot reviewed 48 out of 48 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| api/src/database/migrations/001-initial-schema.ts | Adds the kyc_level_2 table and corresponding indexes to support KYC Level 2. |
| api/src/constants/constants.ts | Updates BRLA_BASE_URL port configuration. |
| api/src/api/services/transactions/onrampTransactions.ts | Formats nonce calculation for clarity. |
| api/src/api/services/ramp/quote.service.ts | Improves formatting in funding amount logic. |
| api/src/api/services/phases/* | Minor formatting and parameter adjustments in several phase handlers. |
| api/src/api/services/pendulum/apiManager.ts | Standardizes object formatting in promise resolves. |
| api/src/api/services/moonbeam/balance.ts | Adjusts import formatting and parameter definitions. |
| api/src/api/services/kyc/kyc.service.ts | Introduces KYC Level 2 logic and integrates a new endpoint call. |
| api/src/api/services/brla/* | Updates types, mappings, and endpoints to include KYC Level 2 and retry flows. |
| api/src/api/routes/v1/* | Replaces the triggerPayIn route with startKYC2 and updates generics formatting. |
| api/src/api/middlewares/validators.ts | Adds a startKYC2Validator to validate document type for KYC Level 2. |
| api/src/api/controllers/brla.controller.ts | Integrates KYC Level 2 flows in subaccount creation and KYC status retrieval. |
| res.status(400).json({ error: 'Subaccount already created' }); | ||
| return; | ||
| } else if (subaccount && subaccount.kyc.level === 0) { | ||
| console.log('subaccountPayload', subaccountPayload); |
There was a problem hiding this comment.
[nitpick] Consider removing or replacing the debug console.log statement with structured logging (e.g., using logger.info) to avoid potential performance or security concerns in production.
There was a problem hiding this comment.
I think it's not a bad idea to leave this for debugging using backend logs.
There was a problem hiding this comment.
Right, we can leave it. We could still change the line to use the logger instance that we have. We should always try to use that logger over simple console.logs in our backend because the logger will use the respective configuration (it's logging to file as well as console). I also forget about this often though.
There was a problem hiding this comment.
true, I forgot we added this after the migration.
| console.error('Validation flags were true, but file data is missing. This is a bug.'); | ||
| return; | ||
| } | ||
| console.log('CNH upload URL:', response.uploadUrls); |
| const amountNum = Number(executionInput.quote.inputAmount); | ||
| const remainingLimitNum = Number(remainingLimitInUnits); | ||
| if (amountNum > remainingLimitNum) { | ||
| if (true) { |
Changes summary
cnpjby filling the extra fields required. If registered viacnpj, the kyc flow will go directly to the level 2 screen after a successful level 1 verification.cpfusers are now prompted with the level 2 screen after confirming a ramp that will go above the level 1 limits.Code changes
useKYCProcesshook, to handle both level 1 and level 2 logic.PIXKYCFormcomponent.cnpj.Backend