Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions packages/ramps-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Add `NeoBankService:getAutoramps` to load all autoramp accounts for the authenticated customer from `GET /neobank/autoramps` ([#10278](https://github.com/MetaMask/core/pull/10278))
- Add `RampsController:hydrateVbaOnboarding`, the persisted `vbaOnboardingStage` state, and the `VbaOnboardingStage` enum for Mobile routing ([#10278](https://github.com/MetaMask/core/pull/10278))
- Resolve the current onboarding stage (email OTP, vendor terms, provider terms, SumSub, pending KYC, rejected KYC, or completed) from the customer's KYC session status.
- After KYC acceptance, register the Money Account wallet, load the customer's authoritative autoramps, and create one only when needed; keep the user on the pending stage if account activation is momentarily unavailable.
- Coalesce overlapping hydration calls to prevent duplicate wallet signatures or autoramp creation during polling.

### Changed

- **BREAKING:** `RampsControllerMessenger` now requires the `KycController:getSessionStatusForVendor`, `KycController:refreshSessionStatus`, `KycController:hasCompletedVendorDisclaimers`, and `KycController:hasCompletedSessionDisclaimers` actions to hydrate VBA onboarding ([#10278](https://github.com/MetaMask/core/pull/10278))
- The action types are declared structurally in the ramps package, so no dependency on `@metamask/kyc-controller` is added.

## [23.0.0]

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ export type NeoBankServiceGetAutorampAction = {
handler: NeoBankService['getAutoramp'];
};

/**
* Fetches all autoramp accounts belonging to the authenticated customer.
*
* @returns Remote snapshots for all customer autoramps.
*/
export type NeoBankServiceGetAutorampsAction = {
type: `NeoBankService:getAutoramps`;
handler: NeoBankService['getAutoramps'];
};

/**
* Registers a Pix address via neobank-proxy `POST /neobank/addresses/pix`.
* Body is forwarded as opaque JSON (MoonPay address schema).
Expand Down Expand Up @@ -136,6 +146,7 @@ export type NeoBankServiceRegisterSelfHostedWalletAction = {
*/
export type NeoBankServiceMethodActions =
| NeoBankServiceGetAutorampAction
| NeoBankServiceGetAutorampsAction
| NeoBankServiceRegisterPixAddressAction
| NeoBankServiceGetAutorampQuoteAction
| NeoBankServiceCreateAutorampAction
Expand Down
60 changes: 60 additions & 0 deletions packages/ramps-controller/src/NeoBankService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,66 @@ describe('NeoBankService', () => {
});
});

describe('getAutoramps', () => {
it('gets and maps all autoramps for the authenticated customer', async () => {
const scope = nock(STAGING_BASE)
.get('/neobank/autoramps')
.query(true)
.matchHeader('Authorization', 'Bearer test-token')
.reply(200, [
{
id: 'ar-1',
customer_id: 'cust-1',
status: 'Approved',
wallet_address: '0xabc',
},
{
id: 'ar-2',
customer_id: 'cust-1',
status: 'Authorized',
recipient_account: { address: '0xdef' },
},
]);

const service = createService();

expect(await service.getAutoramps()).toMatchInlineSnapshot(`
[
{
"customerId": "cust-1",
"depositRailsSummary": {
"ready": false,
},
"id": "ar-1",
"status": "Approved",
"walletAddress": "0xabc",
},
{
"customerId": "cust-1",
"depositRailsSummary": undefined,
"id": "ar-2",
"status": "Authorized",
"walletAddress": "0xdef",
},
]
`);
expect(scope.isDone()).toBe(true);
});

it('rejects a malformed list response', async () => {
nock(STAGING_BASE)
.get('/neobank/autoramps')
.query(true)
.reply(200, { autoramps: [] });

const service = createService();

await expect(service.getAutoramps()).rejects.toThrow(
'Malformed response received from neo-bank autoramps API',
);
});
});

describe('registerPixAddress', () => {
it('posts /neobank/addresses/pix with JSON body and bearer auth', async () => {
const body = {
Expand Down
18 changes: 18 additions & 0 deletions packages/ramps-controller/src/NeoBankService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export type RegisterSelfHostedWalletParams = {

const MESSENGER_EXPOSED_METHODS = [
'getAutoramp',
'getAutoramps',
'registerPixAddress',
'getAutorampQuote',
'createAutoramp',
Expand Down Expand Up @@ -420,6 +421,23 @@ export class NeoBankService {
return this.#mapAutorampResponse(response);
}

/**
* Fetches all autoramp accounts belonging to the authenticated customer.
*
* @returns Remote snapshots for all customer autoramps.
*/
async getAutoramps(): Promise<AutorampRemoteSnapshot[]> {
const response = await this.#getJson<unknown>('autoramps');
if (!Array.isArray(response)) {
throw new Error(
'Malformed response received from neo-bank autoramps API',
);
}
return response.map((autoramp) =>
this.#mapAutorampResponse(autoramp as NeoBankAutorampResponse),
);
}

/**
* Registers a Pix address via neobank-proxy `POST /neobank/addresses/pix`.
* Body is forwarded as opaque JSON (MoonPay address schema).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,22 @@ export type RampsControllerRegisterMoneyAccountWalletAction = {
handler: RampsController['registerMoneyAccountWallet'];
};

/**
* Hydrates the Mobile-routable VBA onboarding stage from KYC state and
* completes wallet and autoramp setup after KYC acceptance.
*
* Overlapping calls share one run so polling cannot trigger duplicate wallet
* signatures or autoramp creation.
*
* @param params - VBA onboarding parameters.
* @param params.walletAddress - Monad Money Account wallet address.
* @returns The hydrated onboarding stage.
*/
export type RampsControllerHydrateVbaOnboardingAction = {
type: `RampsController:hydrateVbaOnboarding`;
handler: RampsController['hydrateVbaOnboarding'];
};

/**
* Removes a local autoramp last-seen cursor by id.
*
Expand Down Expand Up @@ -900,6 +916,7 @@ export type RampsControllerMethodActions =
| RampsControllerAddAutorampAction
| RampsControllerCreateAutorampAction
| RampsControllerRegisterMoneyAccountWalletAction
| RampsControllerHydrateVbaOnboardingAction
| RampsControllerRemoveAutorampAction
| RampsControllerMarkAutorampAsNotifiedAction
| RampsControllerApplyAutorampStatusFromPushAction
Expand Down
Loading
Loading