Skip to content

Conversation

@mainqueg
Copy link
Contributor

@mainqueg mainqueg commented Jan 23, 2026

closes #438


Open with Devin

Summary by CodeRabbit

  • New Features

    • KYC flows now accept a new "manteca" scope for GET and POST.
    • On-ramp/provider functionality consolidated into a unified "ramp" API (providers, limits, quotes, onboarding).
    • Webhook now recognizes USER_STATUS_UPDATE and processes payloads via credential-based flow with consistent 200 responses.
  • Bug Fixes / Reliability

    • Centralized error handling with clearer provider error codes and more consistent responses.
  • Tests

    • Extensive new tests covering manteca KYC, ramp endpoints, and webhook scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

@changeset-bot
Copy link

changeset-bot bot commented Jan 23, 2026

🦋 Changeset detected

Latest commit: af63981

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@exactly/server Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link

coderabbitai bot commented Jan 23, 2026

Walkthrough

Replaces the onramp router with a new ramp API, adds manteca provider support across providers/quotes/limits/onboarding, expands KYC scope to include "manteca" with mapped errors, refactors persona and ramp provider utilities, updates manteca webhook handling to credential-centric flows, and adds extensive tests and a changeset.

Changes

Cohort / File(s) Summary
Routing
server/api/index.ts
Mount swapped: removed ./onramp, added ./ramp.
Removed Onramp
server/api/onramp.ts
Deleted old onramp router, schemas, routes and exports.
Ramp API (new)
server/api/ramp.ts
New Hono router exposing GET /, GET /limits, GET /quote, POST / (onboarding); unified error codes and per-provider flows.
KYC API
server/api/kyc.ts
Added "manteca" to GET/POST scope; wrapped getPendingInquiryTemplate calls in try/catch mapping NOT_SUPPORTED → 400; adjusted template handling.
Manteca Webhooks
server/hooks/manteca.ts
Added USER_STATUS_UPDATE event; switched to credential/account-based flow, validated account, standardized explicit 200 responses, and updated Sentry/context usage.
Persona utils
server/utils/persona.ts
getPendingInquiryTemplate return type changed, added getDocumentForManteca, reordered BR id-class priority, and added scope validation errors import.
Manteca provider
server/utils/ramps/manteca.ts
Major refactor: getUser/getProvider signatures changed, return shapes simplified, legacy schemas/exports removed, new helpers and updated ErrorCodes/onboarding typings.
Bridge provider
server/utils/ramps/bridge.ts
Removed templateId from types; provider shape now nests currencies/cryptoCurrencies under onramp.
Shared ramp types
server/utils/ramps/shared.ts
Removed MISSING_INFORMATION from ProviderStatus; added onramp field to ProviderInfo; removed top-level currency/pending fields.
Tests (added/updated)
server/test/api/kyc.test.ts, server/test/api/ramp.test.ts, server/test/hooks/manteca.test.ts, server/test/utils/persona.test.ts
Large new test suites for manteca KYC, ramp endpoints, manteca webhook, and persona document selection (some duplicated blocks present).
Changeset
.changeset/wide-colts-wonder.md
Added patch changeset for @exactly/server with message "✨ support manteca inquiry".

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant RampAPI as Ramp API
    participant CredentialDB as Credential DB
    participant Manteca as Manteca Provider
    participant Bridge as Bridge Provider
    participant Persona as Persona Utils

    Client->>RampAPI: GET /ramp or POST /ramp (onboarding)
    RampAPI->>CredentialDB: resolve credential & account
    alt providers aggregation
        RampAPI->>Manteca: getProvider(account, country?)
        RampAPI->>Bridge: getProvider(account, country?)
        Manteca-->>RampAPI: provider info
        Bridge-->>RampAPI: provider info
        RampAPI-->>Client: 200 { providers: { manteca, bridge } }
    else onboarding
        RampAPI->>Persona: getPendingInquiryTemplate(referenceId, scope)
        alt provider = manteca
            RampAPI->>Manteca: mantecaOnboarding(account, credentialId)
            Manteca-->>RampAPI: result / errors
        else provider = bridge
            RampAPI->>Bridge: bridgeOnboarding({ credentialId, customerId, acceptedTermsId })
            Bridge-->>RampAPI: result / errors
        end
        RampAPI-->>Client: 200 { code: "ok" } or 400 { code: ... }
    end
Loading
sequenceDiagram
    participant Client as Client
    participant KYC as KYC Endpoint
    participant Persona as Persona Utils
    participant MantecaEval as Manteca evaluation

    Client->>KYC: GET /kyc?scope=manteca
    KYC->>Persona: getPendingInquiryTemplate(referenceId, "manteca")
    Persona->>MantecaEval: evaluateAccount(referenceId)
    alt supported
        MantecaEval-->>Persona: template info
        Persona-->>KYC: template
        KYC-->>Client: 200 { status / inquiry }
    else not_supported
        MantecaEval-->>Persona: NOT_SUPPORTED error
        Persona-->>KYC: throws NOT_SUPPORTED
        KYC-->>Client: 400 { code: "not supported" }
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • cruzdanilo
  • nfmelendez
🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Out of Scope Changes check ❓ Inconclusive Some changes appear tangential to the core Manteca inquiry support, including removal of onramp.ts, refactoring of bridge.ts types, and significant restructuring of shared ramp utilities beyond what seems necessary for Manteca inquiry. Clarify whether the onramp.ts removal, bridge.ts type changes, and ramp utility refactoring are required dependencies for Manteca inquiry support or represent architectural changes beyond the issue scope.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title '✨ server: support manteca inquiry' clearly summarizes the main objective of implementing Manteca inquiry support in the server, which aligns with the primary change across multiple files.
Linked Issues check ✅ Passed The PR successfully implements Manteca integration with support for multiple countries (Argentina and Brazil) and currencies, aligning with issue #438 requirements for ramp manteca implementation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch manteca

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link

Summary of Changes

Hello @mainqueg, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the server's capability to handle Know Your Customer (KYC) and on-ramp processes by integrating Manteca. It involves a substantial refactoring of the on-ramp module, introducing new logic for Manteca-specific user onboarding, and updating API interactions and data structures to support this new provider. The changes aim to provide a more robust and flexible system for managing user verification and fund transfers.

Highlights

  • Manteca Inquiry Support: Introduced comprehensive support for Manteca inquiries within the server-side KYC and on-ramp processes, including new API endpoints, data validation, and error handling.
  • API Refactoring and Renaming: The onramp API route and its corresponding file server/api/onramp.ts have been renamed to ramp (server/api/ramp.ts) to streamline the on-ramp functionality.
  • KYC Scope Expansion: The /kyc API endpoints now support a 'manteca' scope, allowing for Manteca-specific KYC flows and handling NOT_SUPPORTED errors during inquiry template retrieval.
  • Manteca Onboarding Implementation: The mantecaOnboarding function has been fully implemented to handle the complete Manteca onboarding process, including initiating onboarding with personal data, uploading identity documents, and accepting terms and conditions.
  • Schema and Utility Updates: Modified various schemas (ProviderInfo, NewUserResponse) and utility functions (getPendingInquiryTemplate, getDocumentForManteca, getProvider in manteca.ts) to align with the new Manteca integration and simplified error codes.
  • Enhanced Test Coverage: Added extensive unit tests for the manteca scope in server/test/api/kyc.test.ts and for the new getDocumentForManteca utility in server/test/utils/persona.test.ts to ensure robust functionality.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View issue and 6 additional flags in Devin Review.

Open in Devin Review

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for Manteca inquiries, significantly refactoring the KYC and ramp provider integration. Key changes include renaming the 'onramp' module to 'ramp', extending the KYC scope to include 'manteca', and streamlining the logic for retrieving provider information and handling Manteca onboarding. The changes also include comprehensive new tests for the Manteca scope, ensuring the correctness of the new flows. The refactoring improves maintainability by centralizing Persona-related logic and simplifying provider interfaces.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@server/api/ramp.ts`:
- Around line 196-229: The onboarding handlers only return 400 for one specific
code each; update the error handling in the manteca and bridge cases (around
mantecaOnboarding and bridgeOnboarding) so that any error whose message is a
member of MantecaErrorCodes or BridgeErrorCodes returns c.json({ code:
error.message }, 400). Keep the existing captureException(error, { contexts: {
credential } }) and the instanceof Error check, replace the single-case switch
with a general check using
Object.values(MantecaErrorCodes).includes(error.message) and
Object.values(BridgeErrorCodes).includes(error.message) and return 400 for any
match instead of re-throwing.

In `@server/utils/ramps/manteca.ts`:
- Around line 250-321: In mantecaOnboarding the expression account.replace("0x",
"") is repeated multiple times; introduce a const userExternalId =
account.replace("0x", "") near the top of the function and replace all uses of
account.replace("0x", "") (calls to getUser, the externalId property passed to
initiateOnboarding, the first argument to uploadIdentityFile for FRONT/BACK, and
the argument to acceptTermsAndConditions, as well as any captureException extra
data that references the stripped account) with userExternalId to avoid repeated
string ops and improve readability.
- Around line 302-320: The current use of Promise.allSettled with only logging
can let critical operations silently fail; update the block around
Promise.allSettled (which runs uploadIdentityFile and acceptTermsAndConditions)
to treat failures as fatal: after awaiting results, inspect the results array
for any entry with status === "rejected", call captureException(result.reason, {
extra: { account } }) for each, and then throw a new Error (including a brief
context like "Manteca onboarding failed for account") or switch to Promise.all
so the function rejects immediately when any of uploadIdentityFile or
acceptTermsAndConditions fails; ensure you reference the uploadIdentityFile and
acceptTermsAndConditions calls and the results variable when making this change.

@sentry
Copy link

sentry bot commented Jan 23, 2026

Codecov Report

❌ Patch coverage is 57.74059% with 101 lines in your changes missing coverage. Please review.
✅ Project coverage is 62.26%. Comparing base (c198406) to head (af63981).

Files with missing lines Patch % Lines
server/utils/ramps/manteca.ts 5.97% 63 Missing ⚠️
server/api/ramp.ts 76.80% 15 Missing and 14 partials ⚠️
server/hooks/manteca.ts 85.71% 4 Missing and 1 partial ⚠️
server/api/kyc.ts 70.00% 3 Missing ⚠️
server/utils/ramps/bridge.ts 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #680      +/-   ##
==========================================
+ Coverage   61.07%   62.26%   +1.18%     
==========================================
  Files         169      169              
  Lines        5236     5446     +210     
  Branches     1461     1541      +80     
==========================================
+ Hits         3198     3391     +193     
+ Misses       1876     1875       -1     
- Partials      162      180      +18     
Flag Coverage Δ
e2e 61.03% <35.98%> (+17.92%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@server/utils/ramps/manteca.ts`:
- Around line 705-716: The two multi-line arrow helpers getExchange and
getNationality should be converted to function declarations: replace the const
getExchange = (countryCode: string): (typeof Exchange)[number] => { ... } and
const getNationality = (countryCode: string): string => { ... } with function
getExchange(countryCode: string): (typeof Exchange)[number] { ... } and function
getNationality(countryCode: string): string { ... } respectively, preserving the
same body, type annotations, error throw logic (throw new Error(`Invalid
country: ${countryCode}`)) and return values so behavior and types remain
unchanged.

Copy link

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View issue and 11 additional flags in Devin Review.

Open in Devin Review

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 13

🤖 Fix all issues with AI agents
In `@server/api/kyc.ts`:
- Around line 43-44: The picklist schema for the "scope" field is duplicated in
the validators (see the scope: optional(picklist(["basic","manteca"]))
occurrences); extract a shared constant (e.g., const scopePicklistSchema =
optional(picklist(["basic","manteca"]))) and replace both inline uses with that
constant so GET/POST validators reference the same schema symbol
(scopePicklistSchema) to prevent drift.
- Around line 26-27: Replace the direct c.json(...) error responses in the "not
supported" branches with thrown HTTPException instances so the global error
handler handles them uniformly; import HTTPException from 'hono' if not already,
and in the two branches that currently return c.json for unsupported operations
(the branches that build the scopeValidationErrors and the other "not supported"
response paths) throw new HTTPException with the appropriate status code and
include the same error payload/message used in the c.json call, preserving any
fields from scopeValidationErrors so handlers downstream receive the identical
payload.

In `@server/api/ramp.ts`:
- Around line 157-168: The try/catch around getMantecaDepositDetails currently
only maps MantecaErrorCodes.NOT_SUPPORTED_CURRENCY to a 400 response and
re-throws other known MantecaErrorCodes as 500; update the catch so that any
error whose message is one of Object.values(MantecaErrorCodes) results in
returning c.json({ code: error.message }, 400) (after captureException) instead
of re-throwing, preserving the existing captureException call and only
re-throwing unknown errors; locate this logic in the catch block that references
getMantecaDepositDetails, MantecaErrorCodes, captureException and c.json to make
the change.
- Around line 47-54: ErrorCodes currently spreads MantecaErrorCodes but omits
BridgeErrorCodes; update the ErrorCodes object (the constant named ErrorCodes in
ramp.ts) to include BridgeErrorCodes as well (e.g., add ...BridgeErrorCodes
alongside ...MantecaErrorCodes), ensuring the order and names remain consistent
and that BridgeErrorCodes is imported/available in the module before use.
- Around line 186-195: The catch block in the quote endpoint erroneously only
maps BridgeErrorCodes.NOT_AVAILABLE_CRYPTO_PAYMENT_RAIL to a 400 response; other
BridgeErrorCodes bubble up as 500s. Update the catch in server/api/ramp.ts
(where captureException, BridgeErrorCodes and c.json are used) to, after
verifying error instanceof Error and
Object.values(BridgeErrorCodes).includes(error.message), return c.json({ code:
error.message }, 400) for all BridgeErrorCodes (e.g., replace the switch with a
single return), otherwise rethrow the error.

In `@server/hooks/manteca.ts`:
- Around line 184-194: The code currently constructs account via const account =
`0x${payload.data.userExternalId}` and assumes payload.data.userExternalId is
valid hex; validate that userExternalId before using it (or parse/normalize it
via the project's Address schema) inside the hook where setUser and
database.query.credentials.findFirst are called. Specifically, add a validation
step for payload.data.userExternalId (e.g., regex or Address schema helper) and
if invalid, call captureException with details and return a clear error response
instead of proceeding to setUser or querying credentials; ensure the same
validated/normalized account string is used for setUser and in the
credentials.where eq(credentials.account, account) query.

In `@server/test/api/ramp.test.ts`:
- Around line 313-340: Add parallel tests for the "bridge" provider in
server/test/api/ramp.test.ts mirroring the existing "manteca" tests: spy on
bridge.bridgeOnboarding (using vi.spyOn) and add a success test that
mocksResolvedValue and asserts a 200 response and { code: "ok" } and that
bridge.bridgeOnboarding was called with account and "ramp-test"; add an error
test that mocksRejectedValue(new Error(bridge.ErrorCodes.ALREADY_ONBOARDED)) and
asserts the endpoint returns the correct HTTP status and JSON body for the
ALREADY_ONBOARDED case; also add one or two additional bridge-specific error
tests (mockRejectedValue with other bridge.ErrorCodes) to assert expected status
and error codes.
- Around line 38-41: In the afterEach block remove the redundant
vi.clearAllMocks() call since vi.restoreAllMocks() already clears mocks; update
the afterEach cleanup to only call vi.restoreAllMocks() (refer to the afterEach
callback and the vi.clearAllMocks / vi.restoreAllMocks calls to locate the lines
to change).
- Around line 266-268: The test currently uses a `as never` cast when mocking
bridge.getCustomer which hides type mismatches; replace the `as never` with a
properly typed mock object that matches the expected return type of
`getCustomer` (or use TypeScript's `satisfies` operator) so the compiler
validates the mock shape—locate the `vi.spyOn(bridge, "getCustomer")` call in
the "returns quote and deposit info for bridge fiat" test and provide a typed
mock (or partial mock typed as the function's return type) instead of the `as
never` assertion.

In `@server/test/utils/persona.test.ts`:
- Around line 304-352: Add a new test case in the "get document for manteca"
suite that verifies Brazil (BR) uses the updated id_class priority: call
persona.getDocumentForManteca with an array of documents including multiple
id_class values ordered to trigger the BR priority map and assert the function
returns the expected document; reuse the existing document fixture shape
(id_class.value, id_number.value, id_issuing_country.value, id_document_id) and
name the test something like "returns document by id class priority for BR" to
prevent regressions in persona.getDocumentForManteca.

In `@server/utils/ramps/manteca.ts`:
- Line 21: The import line mixes runtime imports with a type; split the
type-only symbol into a separate import type statement: keep the runtime imports
getAccount, getDocument, getDocumentForManteca in the existing import and move
MantecaCountryCode (aliased as CountryCode) into its own "import type {
MantecaCountryCode as CountryCode } from \"../persona\";" declaration so the
type-only import uses TypeScript's import type syntax.
- Around line 241-248: The predicate computing hasPendingTasks on
mantecaUser.onboarding must guard against undefined OnboardingTaskInfo entries
and treat IN_PROGRESS as onboarding: update the some(...) callback used for
hasPendingTasks to use optional chaining (e.g., task?.required) and check status
values (include "PENDING" or "IN_PROGRESS" or check status !== "COMPLETED") so
undefined tasks don't throw and IN_PROGRESS keeps the user in the "ONBOARDING"
branch.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 Fix all issues with AI agents
In `@server/api/ramp.ts`:
- Around line 18-19: The file currently imports "database" and "credentials"
directly; update server/api/ramp.ts to stop importing those and instead read
them from the request context (use c.var.db and c.var.credentials) inside every
route handler that interacts with the DB (replace direct references to
database.* and credentials with c.var.db and c.var.credentials). Remove the
top-level import line for database/credentials and update all handler functions
in this file (including the handlers around the previously noted block at lines
~77-80) to accept and use the context variable (c) and call c.var.db methods
rather than the imported client.
- Around line 61-107: The GET "/" route (created via new Hono().get(...)) and
the other Ramp routes (GET "/limits", GET "/quote", POST "/") are missing
OpenAPI specs; add .doc() calls chained onto each route to provide OpenAPI
metadata (summary, description, tags), request parameter schemas (reuse the
existing vValidator schemas for query/body where applicable), and response
schemas/types matching the handler outputs (e.g., provider list shape for the
GET "/" handler using ProviderInfo and ErrorCodes). Ensure you attach .doc()
immediately after the handler registration for each route, reference the same
validator schemas (e.g., the object(...) passed to vValidator) and the response
DTOs so the generated OpenAPI accurately reflects query params, request bodies,
and successful/error responses.
- Around line 115-116: Replace the bare TODO comment "TODO support multiple
providers" with a TODO that includes the project ticket reference (e.g. `#438`)
per guidelines; update the comment near the existing TODO so it reads something
like a TODO with the issue id or URL (attach the issue number you referenced) to
link this work to the tracker.
- Around line 84-88: Validate credential.account with the Address valibot schema
before passing it to getMantecaProvider: use parse(Address, credential.account)
(or equivalent validation helper) to convert/validate the plain string into the
branded Address type, assign the result to a variable (e.g., validatedAccount)
and pass that into getMantecaProvider(validatedAccount, countryCode); handle
validation errors by capturing the exception (captureException) and returning
the same fallback object used in the existing catch path so runtime typing and
safety are preserved for the getMantecaProvider call.

In `@server/hooks/manteca.ts`:
- Around line 194-200: The captureException call in manteca.ts is sending the
full webhook payload (variable payload) to Sentry and may leak PII; change the
call in the credential-not-found branch around the
credential/credentials.findFirst check so it logs only minimal identifiers
(e.g., account and any non-PII request id) instead of the entire
payload—sanitize or replace contexts payload with an object like { account } or
{ account, webhookId } and keep level:"error"; update the captureException
invocation (and any related error logging) to use the sanitized context.

In `@server/test/hooks/manteca.test.ts`:
- Around line 206-226: The test "returns credential not found when credential
does not exist" fails address validation because userExternalId is set to
"nonexistent"; change payload.data.userExternalId to a valid 40-hex character
string (an address-format hex not present in the DB) so the handler passes the
address validation and exercises the credential-not-found branch; keep
createSignature(payload) and the rest of the request unchanged.

@mainqueg mainqueg force-pushed the manteca branch 2 times, most recently from f08c05a to 6e6a96a Compare January 27, 2026 16:15
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/utils/ramps/bridge.ts (1)

122-124: Stub throws unhandled error.

The onboarding function rejects with a generic error. If callers invoke this, they'll receive an unhandled 5xx. Consider throwing an HTTPException with a clearer status or adding documentation that Bridge onboarding is not yet implemented.

♻️ Suggested improvement
 export async function onboarding(_data: Onboarding): Promise<void> {
-  await Promise.reject(new Error("not implemented"));
+  throw new Error("bridge onboarding not implemented");
 }
🤖 Fix all issues with AI agents
In `@server/api/ramp.ts`:
- Around line 217-218: The code uses credential.account directly when calling
setUser and mantecaOnboarding; validate and parse credential.account first (same
as GET "/" endpoint) into an account variable and check its shape/presence
before use, then call setUser({ id: account.output }) and pass account.output
into mantecaOnboarding; update references to use the parsed account variable
instead of credential.account to keep validation consistent.
- Around line 122-123: The code passes credential.account directly into setUser
in the POST handler; make it consistent with the GET "/" handler by validating
credential.account with safeParse(Address, credential.account) (as used before
calling getMantecaProvider) and only call setUser({ id: parsed.data }) when
validation succeeds, otherwise return the same ErrorCodes.NO_CREDENTIAL (or
appropriate 400) response; update any downstream use (e.g., getMantecaProvider)
to use the validated value rather than the raw credential.account.
- Around line 154-155: Validate credential.account the same way GET "/" does
before calling setUser and before passing the address to bridge deposit detail
calls: run the existing address validation utility used in the GET "/" handler
on credential.account, handle invalid addresses by returning the same error
response, then assign the validated result to a variable (e.g., account) and
call setUser({ id: account.output }) and use account.output for subsequent
bridge deposit detail calls instead of credential.account; ensure you update
both places where bridge deposit details are called.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@server/test/api/ramp.test.ts`:
- Around line 122-132: Extract a reusable base Manteca user fixture and replace
the duplicated inline objects used in vi.spyOn(manteca,
"getUser").mockResolvedValue calls; create a single const (e.g.,
baseMantecaUser) with common fields (id, numberId, type, exchange, onboarding,
creationTime, updatedAt) and then use object spread to override only status in
each test (e.g., { ...baseMantecaUser, status: "ONBOARDING" }) where
manteca.getUser is mocked in the failing and other related tests.
- Around line 288-294: The test currently leaves the depositInfo assertion
commented out; update the test to assert the mocked deposit details are returned
by uncommenting or adding an assertion for depositInfo (e.g.,
expect(json).toMatchObject({ quote: { buyRate: "1.00", sellRate: "1.00" },
depositInfo: expect.any(Array) }) or a stricter match against the specific
mocked payload), ensuring this corresponds to the mock for getDepositDetails
used in the test so the response validation verifies depositInfo is present and
correct.

Comment on lines +122 to +132
it("returns 400 if manteca user status is onboarding", async () => {
vi.spyOn(manteca, "getUser").mockResolvedValue({
id: "user123",
numberId: "456",
status: "ONBOARDING",
type: "INDIVIDUAL",
exchange: "ARGENTINA",
onboarding: {},
creationTime: "2024-01-01T00:00:00Z",
updatedAt: "2024-01-01T00:00:00Z",
});
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider extracting repeated mock user data.

The manteca user mock object with id, numberId, status, type, exchange, onboarding, creationTime, and updatedAt is duplicated 4 times. Extracting a base fixture would reduce duplication and simplify status variations.

♻️ Suggested fixture extraction
const baseMantecaUser = {
  id: "user123",
  numberId: "456",
  type: "INDIVIDUAL" as const,
  exchange: "ARGENTINA" as const,
  onboarding: {},
  creationTime: "2024-01-01T00:00:00Z",
  updatedAt: "2024-01-01T00:00:00Z",
};

// Usage in tests:
vi.spyOn(manteca, "getUser").mockResolvedValue({ ...baseMantecaUser, status: "ONBOARDING" });
vi.spyOn(manteca, "getUser").mockResolvedValue({ ...baseMantecaUser, status: "ACTIVE" });

Also applies to: 140-150, 185-195, 221-231

🤖 Prompt for AI Agents
In `@server/test/api/ramp.test.ts` around lines 122 - 132, Extract a reusable base
Manteca user fixture and replace the duplicated inline objects used in
vi.spyOn(manteca, "getUser").mockResolvedValue calls; create a single const
(e.g., baseMantecaUser) with common fields (id, numberId, type, exchange,
onboarding, creationTime, updatedAt) and then use object spread to override only
status in each test (e.g., { ...baseMantecaUser, status: "ONBOARDING" }) where
manteca.getUser is mocked in the failing and other related tests.

Comment on lines +288 to +294
expect(response.status).toBe(200);
const json = await response.json();
expect(json).toMatchObject({
quote: { buyRate: "1.00", sellRate: "1.00" },
// depositInfo: expect.any(Array),
});
});
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Incomplete test verification: commented-out depositInfo assertion.

The commented-out assertion // depositInfo: expect.any(Array) suggests either incomplete test coverage or a TODO. Since getDepositDetails is mocked with specific data, the test should verify that depositInfo is returned correctly.

♻️ Proposed fix to complete the assertion
         expect(response.status).toBe(200);
         const json = await response.json();
         expect(json).toMatchObject({
           quote: { buyRate: "1.00", sellRate: "1.00" },
-          // depositInfo: expect.any(Array),
+          depositInfo: expect.any(Array),
         });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
expect(response.status).toBe(200);
const json = await response.json();
expect(json).toMatchObject({
quote: { buyRate: "1.00", sellRate: "1.00" },
// depositInfo: expect.any(Array),
});
});
expect(response.status).toBe(200);
const json = await response.json();
expect(json).toMatchObject({
quote: { buyRate: "1.00", sellRate: "1.00" },
depositInfo: expect.any(Array),
});
🤖 Prompt for AI Agents
In `@server/test/api/ramp.test.ts` around lines 288 - 294, The test currently
leaves the depositInfo assertion commented out; update the test to assert the
mocked deposit details are returned by uncommenting or adding an assertion for
depositInfo (e.g., expect(json).toMatchObject({ quote: { buyRate: "1.00",
sellRate: "1.00" }, depositInfo: expect.any(Array) }) or a stricter match
against the specific mocked payload), ensuring this corresponds to the mock for
getDepositDetails used in the test so the response validation verifies
depositInfo is present and correct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

server: ramp manteca

2 participants