@metamask/ramps-controller 24.0.0 → 25.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -1
- package/dist/RampsController-method-action-types.d.ts +5 -3
- package/dist/RampsController-method-action-types.d.ts.map +1 -1
- package/dist/RampsController-method-action-types.js.map +1 -1
- package/dist/RampsController.d.ts +38 -20
- package/dist/RampsController.d.ts.map +1 -1
- package/dist/RampsController.js +104 -67
- package/dist/RampsController.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/dist/RampsController.js
CHANGED
|
@@ -85,24 +85,56 @@ export const RAMPS_CONTROLLER_REQUIRED_CONTROLLER_ACTIONS = [
|
|
|
85
85
|
'KycController:refreshSessionStatus',
|
|
86
86
|
'KycController:hasCompletedVendorDisclaimers',
|
|
87
87
|
'KycController:hasCompletedSessionDisclaimers',
|
|
88
|
+
'KycController:clearState',
|
|
88
89
|
'RemoteFeatureFlagController:getState',
|
|
89
90
|
'UserStorageController:getState',
|
|
90
91
|
'UserStorageController:performGetStorageAllFeatureEntries',
|
|
91
92
|
'UserStorageController:performBatchSetStorage',
|
|
92
93
|
];
|
|
93
94
|
/**
|
|
94
|
-
*
|
|
95
|
+
* KYC vocabulary used on the VBA onboarding snapshot. `'none'` means no
|
|
96
|
+
* session exists yet (or the vendor returned an unrecognized status).
|
|
95
97
|
*/
|
|
96
|
-
export
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
98
|
+
export const VBA_KYC_STATUSES = [
|
|
99
|
+
'none',
|
|
100
|
+
'new',
|
|
101
|
+
'retry',
|
|
102
|
+
'pending',
|
|
103
|
+
'approved',
|
|
104
|
+
'rejected',
|
|
105
|
+
];
|
|
106
|
+
/**
|
|
107
|
+
* Autoramp setup progress after KYC has been approved.
|
|
108
|
+
* `'in_progress'` is reserved for hosts that observe an in-flight hydrate;
|
|
109
|
+
* {@link RampsController.hydrateVbaOnboarding} itself returns `'ready'` or
|
|
110
|
+
* `'retryable_failure'` once the coalesced run settles.
|
|
111
|
+
*/
|
|
112
|
+
export const VBA_AUTORAMP_STATUSES = [
|
|
113
|
+
'not_ready',
|
|
114
|
+
'in_progress',
|
|
115
|
+
'ready',
|
|
116
|
+
'retryable_failure',
|
|
117
|
+
];
|
|
118
|
+
const EMPTY_VBA_ONBOARDING_SNAPSHOT = {
|
|
119
|
+
sessionExists: false,
|
|
120
|
+
vendorDisclaimersComplete: false,
|
|
121
|
+
sessionDisclaimersComplete: false,
|
|
122
|
+
kycStatus: 'none',
|
|
123
|
+
autorampStatus: 'not_ready',
|
|
124
|
+
};
|
|
125
|
+
const VBA_KYC_STATUS_SET = new Set(VBA_KYC_STATUSES);
|
|
126
|
+
/**
|
|
127
|
+
* Maps a vendor status string onto the snapshot vocabulary.
|
|
128
|
+
*
|
|
129
|
+
* @param value - Raw KYC status from the session.
|
|
130
|
+
* @returns A known {@link VbaKycStatus}, or `'none'` when missing/unknown.
|
|
131
|
+
*/
|
|
132
|
+
function toVbaKycStatus(value) {
|
|
133
|
+
if (value && VBA_KYC_STATUS_SET.has(value)) {
|
|
134
|
+
return value;
|
|
135
|
+
}
|
|
136
|
+
return 'none';
|
|
137
|
+
}
|
|
106
138
|
/**
|
|
107
139
|
* Distinguishes an already-materialized {@link AutorampAccount} from the
|
|
108
140
|
* create-fields shape accepted by {@link RampsController.addAutoramp}.
|
|
@@ -237,12 +269,6 @@ const rampsControllerMetadata = {
|
|
|
237
269
|
includeInStateLogs: true,
|
|
238
270
|
usedInUi: true,
|
|
239
271
|
},
|
|
240
|
-
vbaOnboardingStage: {
|
|
241
|
-
persist: true,
|
|
242
|
-
includeInDebugSnapshot: true,
|
|
243
|
-
includeInStateLogs: true,
|
|
244
|
-
usedInUi: true,
|
|
245
|
-
},
|
|
246
272
|
};
|
|
247
273
|
/**
|
|
248
274
|
* Creates a default resource state object.
|
|
@@ -288,7 +314,6 @@ export function getDefaultRampsControllerState() {
|
|
|
288
314
|
orders: [],
|
|
289
315
|
autoramps: [],
|
|
290
316
|
providerAutoSelected: false,
|
|
291
|
-
vbaOnboardingStage: null,
|
|
292
317
|
};
|
|
293
318
|
}
|
|
294
319
|
const DEPENDENT_RESOURCE_KEYS = [
|
|
@@ -2500,15 +2525,17 @@ export class RampsController extends BaseController {
|
|
|
2500
2525
|
}
|
|
2501
2526
|
}
|
|
2502
2527
|
/**
|
|
2503
|
-
*
|
|
2504
|
-
*
|
|
2528
|
+
* Refreshes KYC session facts and, when Iron has approved KYC, activates the
|
|
2529
|
+
* Money Account (wallet registration + autoramp). Hosts map the returned
|
|
2530
|
+
* {@link VbaOnboardingSnapshot} onto their own funnel; this method does not
|
|
2531
|
+
* name screens.
|
|
2505
2532
|
*
|
|
2506
2533
|
* Overlapping calls share one run so polling cannot trigger duplicate wallet
|
|
2507
2534
|
* signatures or autoramp creation.
|
|
2508
2535
|
*
|
|
2509
2536
|
* @param params - VBA onboarding parameters.
|
|
2510
2537
|
* @param params.walletAddress - Monad Money Account wallet address.
|
|
2511
|
-
* @returns
|
|
2538
|
+
* @returns Independent KYC and autoramp facts for the current customer.
|
|
2512
2539
|
*/
|
|
2513
2540
|
async hydrateVbaOnboarding({ walletAddress, }) {
|
|
2514
2541
|
if (this.#vbaOnboardingHydrationPromise) {
|
|
@@ -2526,20 +2553,21 @@ export class RampsController extends BaseController {
|
|
|
2526
2553
|
}
|
|
2527
2554
|
}
|
|
2528
2555
|
async #hydrateVbaOnboarding(walletAddress) {
|
|
2529
|
-
// Fetch the customer's latest session from the vendor account so each stage
|
|
2530
|
-
// reflects backend truth (e.g. re-verification required after a new
|
|
2531
|
-
// document) rather than only device-local state. A `null` session means no
|
|
2532
|
-
// customer/session exists yet, so onboarding starts at the email step.
|
|
2533
2556
|
// Prefer the in-memory/persisted session status over the backend
|
|
2534
|
-
// latest-status endpoint: after SumSub the backend endpoint
|
|
2535
|
-
// reports kycStatus 'new' right after an 'approved' applicant result), while
|
|
2557
|
+
// latest-status endpoint: after SumSub the backend endpoint can lag, while
|
|
2536
2558
|
// the controller state reflects the journey/SDK outcome. Fall back to a
|
|
2537
2559
|
// backend fetch only when the controller has no session in state (e.g. a
|
|
2538
2560
|
// reinstall/cleared state resuming an existing customer, or a brand-new user
|
|
2539
2561
|
// with no session at all).
|
|
2540
2562
|
let session = null;
|
|
2563
|
+
// Whether `session` came from persisted controller state (as opposed to a
|
|
2564
|
+
// fresh backend fetch, which is always scoped to the current user). Only a
|
|
2565
|
+
// persisted session can belong to a previous identity, so only that path
|
|
2566
|
+
// needs the ownership check below.
|
|
2567
|
+
let sessionFromCache = false;
|
|
2541
2568
|
try {
|
|
2542
2569
|
session = this.messenger.call('KycController:refreshSessionStatus');
|
|
2570
|
+
sessionFromCache = true;
|
|
2543
2571
|
}
|
|
2544
2572
|
catch {
|
|
2545
2573
|
try {
|
|
@@ -2547,48 +2575,43 @@ export class RampsController extends BaseController {
|
|
|
2547
2575
|
}
|
|
2548
2576
|
catch {
|
|
2549
2577
|
// No session exists for this customer yet: the backend returns 404
|
|
2550
|
-
// ("KYC session not found"), which surfaces as a rejection here.
|
|
2551
|
-
// it as "start onboarding at the email step" rather than an error.
|
|
2578
|
+
// ("KYC session not found"), which surfaces as a rejection here.
|
|
2552
2579
|
session = null;
|
|
2553
2580
|
}
|
|
2554
2581
|
}
|
|
2555
2582
|
if (!session) {
|
|
2556
|
-
return
|
|
2557
|
-
}
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
}
|
|
2580
|
-
// Submitted; vendor is finalizing → "verification in progress".
|
|
2581
|
-
return this.#setVbaOnboardingStage(VbaOnboardingStage.KycPending);
|
|
2583
|
+
return { ...EMPTY_VBA_ONBOARDING_SNAPSHOT };
|
|
2584
|
+
}
|
|
2585
|
+
// A persisted session can outlive the identity that created it — e.g. a new
|
|
2586
|
+
// wallet created over an install that still holds a previous customer's
|
|
2587
|
+
// session. Reusing it makes the backend reject every session-scoped call
|
|
2588
|
+
// (owner mismatch), dead-ending the user. Verify ownership up front against
|
|
2589
|
+
// the signed-in profile and, on a mismatch, discard the stale session.
|
|
2590
|
+
if (sessionFromCache &&
|
|
2591
|
+
!(await this.#isVbaSessionOwnedByCurrentProfile(session))) {
|
|
2592
|
+
this.messenger.call('KycController:clearState');
|
|
2593
|
+
return { ...EMPTY_VBA_ONBOARDING_SNAPSHOT };
|
|
2594
|
+
}
|
|
2595
|
+
const vendorDisclaimersComplete = await this.messenger.call('KycController:hasCompletedVendorDisclaimers');
|
|
2596
|
+
const sessionDisclaimersComplete = await this.messenger.call('KycController:hasCompletedSessionDisclaimers');
|
|
2597
|
+
const snapshot = {
|
|
2598
|
+
sessionExists: true,
|
|
2599
|
+
vendorDisclaimersComplete,
|
|
2600
|
+
sessionDisclaimersComplete,
|
|
2601
|
+
kycStatus: toVbaKycStatus(session.finalStatus),
|
|
2602
|
+
autorampStatus: 'not_ready',
|
|
2603
|
+
};
|
|
2604
|
+
if (snapshot.kycStatus !== 'approved') {
|
|
2605
|
+
return snapshot;
|
|
2582
2606
|
}
|
|
2583
2607
|
if (!walletAddress.trim()) {
|
|
2584
2608
|
throw new Error('walletAddress is required after KYC acceptance.');
|
|
2585
2609
|
}
|
|
2586
2610
|
// KYC is approved; the remaining work activates the Money account (register
|
|
2587
2611
|
// the wallet + ensure an autoramp). Those calls hit the neobank backend and
|
|
2588
|
-
// can fail transiently (e.g. an address-list lookup timeout).
|
|
2589
|
-
// keep the user on
|
|
2590
|
-
//
|
|
2591
|
-
// error screen — the KYC decision itself already succeeded.
|
|
2612
|
+
// can fail transiently (e.g. an address-list lookup timeout). Surface
|
|
2613
|
+
// `retryable_failure` so the host can keep the user on a pending screen
|
|
2614
|
+
// rather than a fatal error — the KYC decision itself already succeeded.
|
|
2592
2615
|
try {
|
|
2593
2616
|
const registration = await this.registerMoneyAccountWallet({
|
|
2594
2617
|
address: walletAddress,
|
|
@@ -2613,17 +2636,31 @@ export class RampsController extends BaseController {
|
|
|
2613
2636
|
}
|
|
2614
2637
|
}
|
|
2615
2638
|
catch {
|
|
2616
|
-
return
|
|
2639
|
+
return { ...snapshot, autorampStatus: 'retryable_failure' };
|
|
2617
2640
|
}
|
|
2618
|
-
return
|
|
2641
|
+
return { ...snapshot, autorampStatus: 'ready' };
|
|
2619
2642
|
}
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2643
|
+
/**
|
|
2644
|
+
* Whether a persisted KYC session belongs to the currently signed-in profile.
|
|
2645
|
+
* A session's `externalUserId` is the canonical profile id captured when the
|
|
2646
|
+
* session was created, so it must match the current profile for the session
|
|
2647
|
+
* to be reused. When the current identity cannot be resolved, err on the side
|
|
2648
|
+
* of keeping the session (return `true`) so a transient profile-read failure
|
|
2649
|
+
* never discards a valid session.
|
|
2650
|
+
*
|
|
2651
|
+
* @param session - The persisted KYC session status to check.
|
|
2652
|
+
* @returns Whether the session is owned by the current profile.
|
|
2653
|
+
*/
|
|
2654
|
+
async #isVbaSessionOwnedByCurrentProfile(session) {
|
|
2655
|
+
const profile = await this.messenger.call('AuthenticationController:getSessionProfile');
|
|
2656
|
+
const canonicalId = typeof profile?.canonicalProfileId === 'string' &&
|
|
2657
|
+
profile.canonicalProfileId.length > 0
|
|
2658
|
+
? profile.canonicalProfileId
|
|
2659
|
+
: profile?.profileId;
|
|
2660
|
+
if (typeof canonicalId !== 'string' || canonicalId.length === 0) {
|
|
2661
|
+
return true;
|
|
2625
2662
|
}
|
|
2626
|
-
return
|
|
2663
|
+
return session.externalUserId === canonicalId;
|
|
2627
2664
|
}
|
|
2628
2665
|
/**
|
|
2629
2666
|
* Removes a local autoramp last-seen cursor by id.
|