@usdctofiat/offramp 1.3.0 → 2.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 +252 -0
- package/README.md +82 -2
- package/dist/{chunk-JQBKGGI2.js → chunk-HBR3Z6HX.js} +118 -40
- package/dist/chunk-HBR3Z6HX.js.map +1 -0
- package/dist/errors-Deoi_xYZ.d.cts +236 -0
- package/dist/errors-Deoi_xYZ.d.ts +236 -0
- package/dist/index.cjs +128 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +30 -1
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +220 -40
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +86 -2
- package/dist/react.d.ts +86 -2
- package/dist/react.js +122 -3
- package/dist/react.js.map +1 -1
- package/package.json +3 -2
- package/dist/chunk-JQBKGGI2.js.map +0 -1
- package/dist/errors-CfZrDly0.d.cts +0 -145
- package/dist/errors-CfZrDly0.d.ts +0 -145
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { currencyInfo } from '@zkp2p/sdk';
|
|
2
|
+
|
|
3
|
+
type PlatformId = "venmo" | "cashapp" | "chime" | "revolut" | "wise" | "mercadopago" | "zelle" | "paypal" | "monzo" | "n26";
|
|
4
|
+
/**
|
|
5
|
+
* Describes the Peer browser-extension pre-registration requirement for a
|
|
6
|
+
* platform. When present, curator's `/v2/makers/create` will reject the maker
|
|
7
|
+
* until the user has registered their handle inside the Peer (PeerAuth)
|
|
8
|
+
* extension at `/verify/<providerId>`.
|
|
9
|
+
*
|
|
10
|
+
* Drives the {@link isPeerExtensionRegistrationError} check and the React
|
|
11
|
+
* `usePeerExtensionRegistration` hook in `@usdctofiat/offramp/react`.
|
|
12
|
+
*/
|
|
13
|
+
interface PeerExtensionRegistrationInfo {
|
|
14
|
+
/**
|
|
15
|
+
* Upstream provider id — matches the Peer extension verify handler. Used
|
|
16
|
+
* to build the sidebar route (`/verify/<providerId>`).
|
|
17
|
+
*/
|
|
18
|
+
readonly providerId: string;
|
|
19
|
+
/** Human-readable message surfaced when curator rejects the maker. */
|
|
20
|
+
readonly requiredPrompt: string;
|
|
21
|
+
/** Label for the install / connect / verify CTA. */
|
|
22
|
+
readonly ctaLabel: string;
|
|
23
|
+
/** Optional subtext (e.g. PayPal Business disclaimer). */
|
|
24
|
+
readonly ctaSubtext?: string;
|
|
25
|
+
/** Minimum Peer extension version expected for this provider. */
|
|
26
|
+
readonly minExtensionVersion: string;
|
|
27
|
+
}
|
|
28
|
+
interface PlatformEntry {
|
|
29
|
+
readonly id: PlatformId;
|
|
30
|
+
readonly name: string;
|
|
31
|
+
readonly currencies: readonly string[];
|
|
32
|
+
readonly identifier: {
|
|
33
|
+
readonly label: string;
|
|
34
|
+
readonly placeholder: string;
|
|
35
|
+
readonly help: string;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Present when curator requires the maker to first register this handle in
|
|
39
|
+
* the Peer extension before `/v2/makers/create` will succeed. Today this
|
|
40
|
+
* applies to PayPal and Wise. See `@usdctofiat/offramp/react` for the
|
|
41
|
+
* `usePeerExtensionRegistration` hook that drives the handshake.
|
|
42
|
+
*/
|
|
43
|
+
readonly extensionRegistration?: PeerExtensionRegistrationInfo;
|
|
44
|
+
validate(input: string): {
|
|
45
|
+
valid: boolean;
|
|
46
|
+
normalized: string;
|
|
47
|
+
error?: string;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Extracts the bare PayPal.me username from any accepted input shape
|
|
52
|
+
* (`paypal.me/user`, `https://paypal.me/user`, `@user`, `user`). Mirrors the
|
|
53
|
+
* upstream zkp2p-clients normalizer so our offchainId hashes identically.
|
|
54
|
+
*/
|
|
55
|
+
declare function normalizePaypalMeUsername(value: string): string;
|
|
56
|
+
/** All supported payment platforms. Access via `PLATFORMS.REVOLUT`, `PLATFORMS.WISE`, etc. */
|
|
57
|
+
declare const PLATFORMS: {
|
|
58
|
+
readonly VENMO: PlatformEntry;
|
|
59
|
+
readonly CASHAPP: PlatformEntry;
|
|
60
|
+
readonly CHIME: PlatformEntry;
|
|
61
|
+
readonly REVOLUT: PlatformEntry;
|
|
62
|
+
readonly WISE: PlatformEntry;
|
|
63
|
+
readonly MERCADO_PAGO: PlatformEntry;
|
|
64
|
+
readonly ZELLE: PlatformEntry;
|
|
65
|
+
readonly PAYPAL: PlatformEntry;
|
|
66
|
+
readonly MONZO: PlatformEntry;
|
|
67
|
+
readonly N26: PlatformEntry;
|
|
68
|
+
};
|
|
69
|
+
/** Platform key type for PLATFORMS constant. */
|
|
70
|
+
type PlatformKey = keyof typeof PLATFORMS;
|
|
71
|
+
/**
|
|
72
|
+
* Shape curator's `/v2/makers/create` expects since the flat-offchainId
|
|
73
|
+
* migration (upstream #580). The endpoint hashes `offchainId + processorName`
|
|
74
|
+
* directly — legacy platform-specific keys (`paypalEmail`, `venmoUsername`,
|
|
75
|
+
* `wisetag`, …) are no longer accepted.
|
|
76
|
+
*/
|
|
77
|
+
interface PayeeDepositData {
|
|
78
|
+
offchainId: string;
|
|
79
|
+
telegramUsername?: string;
|
|
80
|
+
metadata?: Record<string, string>;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Returns the extension-registration metadata for a platform, or `null` if
|
|
84
|
+
* the platform does not require Peer-extension pre-registration. Use this to
|
|
85
|
+
* decide whether to surface an "Install / Connect Peer Extension" CTA in
|
|
86
|
+
* your UI before calling `offramp()` for PayPal or Wise.
|
|
87
|
+
*/
|
|
88
|
+
declare function getPeerExtensionRegistrationInfo(platform: string): PeerExtensionRegistrationInfo | null;
|
|
89
|
+
/**
|
|
90
|
+
* True when a failed `/v2/makers/create` response should be interpreted as
|
|
91
|
+
* "maker needs to register in the Peer extension first". Platforms without
|
|
92
|
+
* an `extensionRegistration` config always return false.
|
|
93
|
+
*
|
|
94
|
+
* Mirrors upstream `isExtensionRegistrationRequiredPostError`: a 400 status
|
|
95
|
+
* on a registration-required platform is treated as registration required,
|
|
96
|
+
* and so is any response whose message contains the curator phrasing.
|
|
97
|
+
*/
|
|
98
|
+
declare function isPeerExtensionRegistrationError(platform: string, message?: string | null, statusCode?: number | null): boolean;
|
|
99
|
+
|
|
100
|
+
interface CurrencyEntry {
|
|
101
|
+
readonly code: string;
|
|
102
|
+
readonly name: string;
|
|
103
|
+
readonly symbol: string;
|
|
104
|
+
readonly countryCode: string;
|
|
105
|
+
}
|
|
106
|
+
type CurrencyMap = {
|
|
107
|
+
readonly [K in keyof typeof currencyInfo]: CurrencyEntry;
|
|
108
|
+
};
|
|
109
|
+
/** All supported currencies with metadata. Access via `CURRENCIES.EUR.symbol` etc. */
|
|
110
|
+
declare const CURRENCIES: CurrencyMap;
|
|
111
|
+
|
|
112
|
+
declare const OFFRAMP_ERROR_CODES: {
|
|
113
|
+
readonly VALIDATION: "VALIDATION";
|
|
114
|
+
readonly APPROVAL_FAILED: "APPROVAL_FAILED";
|
|
115
|
+
readonly REGISTRATION_FAILED: "REGISTRATION_FAILED";
|
|
116
|
+
/**
|
|
117
|
+
* Curator rejected the maker because the user has not registered this
|
|
118
|
+
* handle in the Peer extension yet. Thrown from `offramp()` for PayPal
|
|
119
|
+
* and Wise when `/v2/makers/create` returns 400 or a "creating the maker"
|
|
120
|
+
* message. Recover by prompting the user through the Peer extension via
|
|
121
|
+
* `usePeerExtensionRegistration(platform)` (React) or `peerExtensionSdk`
|
|
122
|
+
* directly, then call `offramp()` again.
|
|
123
|
+
*/
|
|
124
|
+
readonly EXTENSION_REGISTRATION_REQUIRED: "EXTENSION_REGISTRATION_REQUIRED";
|
|
125
|
+
readonly DEPOSIT_FAILED: "DEPOSIT_FAILED";
|
|
126
|
+
readonly CONFIRMATION_FAILED: "CONFIRMATION_FAILED";
|
|
127
|
+
readonly DELEGATION_FAILED: "DELEGATION_FAILED";
|
|
128
|
+
readonly USER_CANCELLED: "USER_CANCELLED";
|
|
129
|
+
readonly UNSUPPORTED: "UNSUPPORTED";
|
|
130
|
+
};
|
|
131
|
+
type OfframpErrorCode = (typeof OFFRAMP_ERROR_CODES)[keyof typeof OFFRAMP_ERROR_CODES];
|
|
132
|
+
interface OfframpParams {
|
|
133
|
+
/** USDC amount as decimal string, min 1. */
|
|
134
|
+
amount: string;
|
|
135
|
+
/** Payment platform — use `PLATFORMS.REVOLUT` etc. */
|
|
136
|
+
platform: PlatformEntry;
|
|
137
|
+
/** Fiat currency — use `CURRENCIES.EUR` etc. */
|
|
138
|
+
currency: CurrencyEntry;
|
|
139
|
+
/** Platform-specific identifier (username, email, IBAN). */
|
|
140
|
+
identifier: string;
|
|
141
|
+
/** Optional: restrict the deposit to this taker wallet (OTC private order). */
|
|
142
|
+
otcTaker?: string;
|
|
143
|
+
/** Optional SDK-only referral metadata for telemetry attribution. */
|
|
144
|
+
referralId?: string;
|
|
145
|
+
/** Optional SDK-only integrator metadata for telemetry attribution. */
|
|
146
|
+
integratorId?: string;
|
|
147
|
+
/** Optional per-wallet key to replay the first successful result for 10 minutes. */
|
|
148
|
+
idempotencyKey?: string;
|
|
149
|
+
}
|
|
150
|
+
interface OfframpResult {
|
|
151
|
+
depositId: string;
|
|
152
|
+
txHash: string;
|
|
153
|
+
/** Whether an existing undelegated deposit was resumed. */
|
|
154
|
+
resumed: boolean;
|
|
155
|
+
/** OTC link for the taker, present when `otcTaker` was provided. */
|
|
156
|
+
otcLink?: string;
|
|
157
|
+
}
|
|
158
|
+
type OfframpStep = "approving" | "registering" | "depositing" | "confirming" | "delegating" | "restricting" | "resuming" | "done";
|
|
159
|
+
type OfframpState = "idle" | "approving" | "registering" | "depositing" | "confirming" | "delegating" | "done" | "error";
|
|
160
|
+
interface OfframpProgress {
|
|
161
|
+
step: OfframpStep;
|
|
162
|
+
txHash?: string;
|
|
163
|
+
depositId?: string;
|
|
164
|
+
}
|
|
165
|
+
type OnProgress = (progress: OfframpProgress) => void;
|
|
166
|
+
type DepositStatus = "active" | "empty" | "closed";
|
|
167
|
+
interface OfframpQuoteInput {
|
|
168
|
+
amount: string;
|
|
169
|
+
currency: CurrencyEntry;
|
|
170
|
+
platform: PlatformEntry;
|
|
171
|
+
}
|
|
172
|
+
interface OfframpQuote {
|
|
173
|
+
amountUsdc: number;
|
|
174
|
+
expectedFiat: number;
|
|
175
|
+
effectiveRate: number;
|
|
176
|
+
vaultSpreadBps: number;
|
|
177
|
+
}
|
|
178
|
+
interface OfframpVaultStatus {
|
|
179
|
+
rateManagerId: string;
|
|
180
|
+
rateManagerAddress: string;
|
|
181
|
+
feeRateBps: number;
|
|
182
|
+
escrow: string;
|
|
183
|
+
isActive: boolean;
|
|
184
|
+
}
|
|
185
|
+
interface OfframpCreateOptions {
|
|
186
|
+
integratorId?: string;
|
|
187
|
+
referralId?: string;
|
|
188
|
+
telemetry?: boolean;
|
|
189
|
+
}
|
|
190
|
+
interface DepositInfo {
|
|
191
|
+
/** Numeric deposit ID. Pass this to `close()`. */
|
|
192
|
+
depositId: string;
|
|
193
|
+
/** Composite ID (escrowAddress_depositId). */
|
|
194
|
+
compositeId: string;
|
|
195
|
+
/** Creation transaction hash. */
|
|
196
|
+
txHash?: string;
|
|
197
|
+
status: DepositStatus;
|
|
198
|
+
remainingUsdc: number;
|
|
199
|
+
outstandingUsdc: number;
|
|
200
|
+
totalTakenUsdc: number;
|
|
201
|
+
fulfilledIntents: number;
|
|
202
|
+
paymentMethods: string[];
|
|
203
|
+
currencies: string[];
|
|
204
|
+
rateSource: string;
|
|
205
|
+
delegated: boolean;
|
|
206
|
+
escrowAddress: string;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Error thrown when curator's `/v2/makers/create` returns a non-success
|
|
211
|
+
* response. Preserves the HTTP status so callers can distinguish a
|
|
212
|
+
* "needs Peer-extension registration" 400 from a transient server error.
|
|
213
|
+
*
|
|
214
|
+
* `offramp()` re-raises this as an {@link OfframpError} with code
|
|
215
|
+
* `EXTENSION_REGISTRATION_REQUIRED` (for PayPal/Wise 400s) or
|
|
216
|
+
* `REGISTRATION_FAILED` (for any other curator error); `MakersCreateError`
|
|
217
|
+
* is attached as the `cause`.
|
|
218
|
+
*/
|
|
219
|
+
declare class MakersCreateError extends Error {
|
|
220
|
+
readonly status: number | null;
|
|
221
|
+
readonly body: string;
|
|
222
|
+
constructor(message: string, status: number | null, body: string);
|
|
223
|
+
}
|
|
224
|
+
declare class OfframpError extends Error {
|
|
225
|
+
readonly code: OfframpErrorCode;
|
|
226
|
+
readonly step?: OfframpStep;
|
|
227
|
+
readonly cause?: unknown;
|
|
228
|
+
readonly txHash?: string;
|
|
229
|
+
readonly depositId?: string;
|
|
230
|
+
constructor(message: string, code: OfframpErrorCode, step?: OfframpStep, cause?: unknown, details?: {
|
|
231
|
+
txHash?: string;
|
|
232
|
+
depositId?: string;
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export { type CurrencyEntry as C, type DepositInfo as D, MakersCreateError as M, type OfframpParams as O, type PlatformEntry as P, type OnProgress as a, type OfframpResult as b, type OfframpCreateOptions as c, type OfframpQuoteInput as d, type OfframpQuote as e, type OfframpVaultStatus as f, CURRENCIES as g, type DepositStatus as h, OFFRAMP_ERROR_CODES as i, OfframpError as j, type OfframpErrorCode as k, type OfframpProgress as l, type OfframpState as m, type OfframpStep as n, PLATFORMS as o, type PayeeDepositData as p, type PeerExtensionRegistrationInfo as q, type PlatformKey as r, getPeerExtensionRegistrationInfo as s, isPeerExtensionRegistrationError as t, normalizePaypalMeUsername as u };
|
package/dist/index.cjs
CHANGED
|
@@ -22,12 +22,15 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
CURRENCIES: () => CURRENCIES,
|
|
24
24
|
ESCROW_ADDRESS: () => ESCROW_ADDRESS,
|
|
25
|
+
MakersCreateError: () => MakersCreateError,
|
|
25
26
|
OFFRAMP_ERROR_CODES: () => OFFRAMP_ERROR_CODES,
|
|
26
27
|
Offramp: () => Offramp,
|
|
27
28
|
OfframpError: () => OfframpError,
|
|
29
|
+
PEER_EXTENSION_CHROME_URL: () => import_sdk7.PEER_EXTENSION_CHROME_URL,
|
|
28
30
|
PLATFORMS: () => PLATFORMS,
|
|
29
31
|
close: () => close,
|
|
30
32
|
createOfframp: () => createOfframp,
|
|
33
|
+
createPeerExtensionSdk: () => import_sdk7.createPeerExtensionSdk,
|
|
31
34
|
createTelemetryContext: () => createTelemetryContext,
|
|
32
35
|
delegate: () => delegate,
|
|
33
36
|
deposits: () => deposits,
|
|
@@ -35,7 +38,14 @@ __export(index_exports, {
|
|
|
35
38
|
emitEvent: () => emitEvent,
|
|
36
39
|
enableOtc: () => enableOtc,
|
|
37
40
|
getOtcLink: () => getOtcLink,
|
|
41
|
+
getPeerExtensionRegistrationInfo: () => getPeerExtensionRegistrationInfo,
|
|
42
|
+
getPeerExtensionState: () => import_sdk7.getPeerExtensionState,
|
|
43
|
+
isPeerExtensionAvailable: () => import_sdk7.isPeerExtensionAvailable,
|
|
44
|
+
isPeerExtensionRegistrationError: () => isPeerExtensionRegistrationError,
|
|
45
|
+
normalizePaypalMeUsername: () => normalizePaypalMeUsername,
|
|
38
46
|
offramp: () => offramp,
|
|
47
|
+
openPeerExtensionInstallPage: () => import_sdk7.openPeerExtensionInstallPage,
|
|
48
|
+
peerExtensionSdk: () => import_sdk7.peerExtensionSdk,
|
|
39
49
|
sanitizeAttributionId: () => sanitizeAttributionId,
|
|
40
50
|
sendTelemetryEvent: () => sendTelemetryEvent,
|
|
41
51
|
undelegate: () => undelegate
|
|
@@ -166,6 +176,17 @@ function resolveSupportedCurrencies(platform) {
|
|
|
166
176
|
}
|
|
167
177
|
return Array.from(codes).sort();
|
|
168
178
|
}
|
|
179
|
+
function normalizePaypalMeUsername(value) {
|
|
180
|
+
const trimmed = value.trim();
|
|
181
|
+
if (!trimmed) return "";
|
|
182
|
+
const withoutProtocol = trimmed.replace(/^https?:\/\//i, "").replace(/^www\./i, "");
|
|
183
|
+
if (/^paypal\.me(?:[?#].*)?$/i.test(withoutProtocol)) return "";
|
|
184
|
+
const withoutDomain = withoutProtocol.replace(/^paypal\.me\//i, "");
|
|
185
|
+
const [pathWithoutQuery] = withoutDomain.split(/[?#]/, 1);
|
|
186
|
+
const sanitizedPath = pathWithoutQuery.replace(/^\/+/, "");
|
|
187
|
+
const [username] = sanitizedPath.split("/", 1);
|
|
188
|
+
return username.replace(/^@+/, "").trim().toLowerCase();
|
|
189
|
+
}
|
|
169
190
|
var BLUEPRINTS = {
|
|
170
191
|
venmo: {
|
|
171
192
|
id: "venmo",
|
|
@@ -213,7 +234,13 @@ var BLUEPRINTS = {
|
|
|
213
234
|
placeholder: "wisetag (no @)",
|
|
214
235
|
helperText: "Your Wise @wisetag (no @)",
|
|
215
236
|
validation: import_zod.z.string().min(1).regex(/^[a-zA-Z0-9_-]+$/),
|
|
216
|
-
transform: (v) => v.replace(/^@+/, "").trim()
|
|
237
|
+
transform: (v) => v.replace(/^@+/, "").trim(),
|
|
238
|
+
extensionRegistration: {
|
|
239
|
+
providerId: "wise",
|
|
240
|
+
requiredPrompt: "This Wisetag is not registered yet. Verify it in the Peer extension, then refresh and retry with the same Wisetag.",
|
|
241
|
+
ctaLabel: "Install Peer Extension",
|
|
242
|
+
minExtensionVersion: "0.4.12"
|
|
243
|
+
}
|
|
217
244
|
},
|
|
218
245
|
mercadopago: {
|
|
219
246
|
id: "mercadopago",
|
|
@@ -234,10 +261,18 @@ var BLUEPRINTS = {
|
|
|
234
261
|
paypal: {
|
|
235
262
|
id: "paypal",
|
|
236
263
|
name: "PayPal",
|
|
237
|
-
identifierLabel: "
|
|
238
|
-
placeholder: "
|
|
239
|
-
helperText: "
|
|
240
|
-
validation: import_zod.z.string().
|
|
264
|
+
identifierLabel: "PayPal.me Username",
|
|
265
|
+
placeholder: "paypal.me/your-username",
|
|
266
|
+
helperText: "Your PayPal.me username, not your email",
|
|
267
|
+
validation: import_zod.z.string().min(1, "PayPal.me username is required").regex(/^[a-z0-9._-]+$/i, "Use your PayPal.me username (letters, numbers, . _ -)"),
|
|
268
|
+
transform: normalizePaypalMeUsername,
|
|
269
|
+
extensionRegistration: {
|
|
270
|
+
providerId: "paypal",
|
|
271
|
+
requiredPrompt: "This PayPal username is not registered yet. Verify it in the Peer extension, then refresh and retry with the same PayPal username.",
|
|
272
|
+
ctaLabel: "Install Peer Extension",
|
|
273
|
+
ctaSubtext: "PayPal Business accounts are not supported at this time.",
|
|
274
|
+
minExtensionVersion: "0.4.14"
|
|
275
|
+
}
|
|
241
276
|
},
|
|
242
277
|
monzo: {
|
|
243
278
|
id: "monzo",
|
|
@@ -268,6 +303,7 @@ function buildPlatformEntry(bp) {
|
|
|
268
303
|
placeholder: bp.placeholder,
|
|
269
304
|
help: bp.helperText
|
|
270
305
|
},
|
|
306
|
+
...bp.extensionRegistration ? { extensionRegistration: bp.extensionRegistration } : {},
|
|
271
307
|
validate(input) {
|
|
272
308
|
const transformed = bp.transform ? bp.transform(input) : input;
|
|
273
309
|
const result = bp.validation.safeParse(transformed);
|
|
@@ -294,6 +330,9 @@ var PLATFORMS = {
|
|
|
294
330
|
MONZO: buildPlatformEntry(BLUEPRINTS.monzo),
|
|
295
331
|
N26: buildPlatformEntry(BLUEPRINTS.n26)
|
|
296
332
|
};
|
|
333
|
+
function getPlatformById(id) {
|
|
334
|
+
return Object.values(PLATFORMS).find((p) => p.id === id) ?? null;
|
|
335
|
+
}
|
|
297
336
|
function normalizePaymentMethodLookupName(platform) {
|
|
298
337
|
const normalized = platform.trim().toLowerCase();
|
|
299
338
|
if (!normalized) return null;
|
|
@@ -337,34 +376,37 @@ function getPaymentMethodHashes(platform) {
|
|
|
337
376
|
}
|
|
338
377
|
return Array.from(hashes);
|
|
339
378
|
}
|
|
340
|
-
function buildDepositData(platform, identifier) {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
case "monzo":
|
|
359
|
-
return { monzoMeUsername: identifier, telegramUsername: "" };
|
|
360
|
-
case "n26":
|
|
361
|
-
return { iban: identifier, telegramUsername: "" };
|
|
362
|
-
default:
|
|
363
|
-
return { identifier, telegramUsername: "" };
|
|
364
|
-
}
|
|
379
|
+
function buildDepositData(platform, identifier, telegramUsername = "") {
|
|
380
|
+
const offchainId = platform === "chime" ? identifier.toLowerCase() : identifier;
|
|
381
|
+
return telegramUsername ? { offchainId, telegramUsername } : { offchainId };
|
|
382
|
+
}
|
|
383
|
+
function getPeerExtensionRegistrationInfo(platform) {
|
|
384
|
+
const entry = getPlatformById(platform);
|
|
385
|
+
return entry?.extensionRegistration ?? null;
|
|
386
|
+
}
|
|
387
|
+
var EXTENSION_REGISTRATION_ERROR_PATTERNS = ["creating the maker", "create the maker"];
|
|
388
|
+
function isPeerExtensionRegistrationError(platform, message, statusCode) {
|
|
389
|
+
const info = getPeerExtensionRegistrationInfo(platform);
|
|
390
|
+
if (!info) return false;
|
|
391
|
+
const normalized = (message ?? "").trim();
|
|
392
|
+
if (normalized === info.requiredPrompt) return true;
|
|
393
|
+
if (statusCode === 400) return true;
|
|
394
|
+
if (!normalized) return false;
|
|
395
|
+
const lower = normalized.toLowerCase();
|
|
396
|
+
return EXTENSION_REGISTRATION_ERROR_PATTERNS.some((p) => lower.includes(p));
|
|
365
397
|
}
|
|
366
398
|
|
|
367
399
|
// src/errors.ts
|
|
400
|
+
var MakersCreateError = class extends Error {
|
|
401
|
+
status;
|
|
402
|
+
body;
|
|
403
|
+
constructor(message, status, body) {
|
|
404
|
+
super(message);
|
|
405
|
+
this.name = "MakersCreateError";
|
|
406
|
+
this.status = status;
|
|
407
|
+
this.body = body;
|
|
408
|
+
}
|
|
409
|
+
};
|
|
368
410
|
var OfframpError = class extends Error {
|
|
369
411
|
code;
|
|
370
412
|
step;
|
|
@@ -1153,23 +1195,39 @@ function extractDepositIdFromLogs(logs) {
|
|
|
1153
1195
|
}
|
|
1154
1196
|
return null;
|
|
1155
1197
|
}
|
|
1156
|
-
async function registerPayeeDetails(processorName,
|
|
1198
|
+
async function registerPayeeDetails(processorName, payload) {
|
|
1157
1199
|
const controller = new AbortController();
|
|
1158
1200
|
const timeout = setTimeout(() => controller.abort(), PAYEE_REGISTRATION_TIMEOUT_MS);
|
|
1159
1201
|
try {
|
|
1160
|
-
const res = await fetch(`${API_BASE_URL}/
|
|
1202
|
+
const res = await fetch(`${API_BASE_URL}/v2/makers/create`, {
|
|
1161
1203
|
method: "POST",
|
|
1162
1204
|
headers: { "Content-Type": "application/json" },
|
|
1163
|
-
body: JSON.stringify({ processorName,
|
|
1205
|
+
body: JSON.stringify({ processorName, ...payload }),
|
|
1164
1206
|
signal: controller.signal
|
|
1165
1207
|
});
|
|
1166
1208
|
if (!res.ok) {
|
|
1167
1209
|
const txt = await res.text().catch(() => "");
|
|
1168
|
-
|
|
1210
|
+
let detail = txt || res.statusText;
|
|
1211
|
+
try {
|
|
1212
|
+
const parsed = JSON.parse(txt);
|
|
1213
|
+
if (typeof parsed.message === "string" && parsed.message.trim()) {
|
|
1214
|
+
detail = parsed.message;
|
|
1215
|
+
}
|
|
1216
|
+
} catch {
|
|
1217
|
+
}
|
|
1218
|
+
throw new MakersCreateError(
|
|
1219
|
+
`makers/create failed (${res.status}): ${detail}`,
|
|
1220
|
+
res.status,
|
|
1221
|
+
txt
|
|
1222
|
+
);
|
|
1169
1223
|
}
|
|
1170
1224
|
const json = await res.json();
|
|
1171
1225
|
if (!json.success || !json.responseObject?.hashedOnchainId) {
|
|
1172
|
-
throw new
|
|
1226
|
+
throw new MakersCreateError(
|
|
1227
|
+
json.message || "makers/create returned no hashedOnchainId",
|
|
1228
|
+
json.statusCode ?? null,
|
|
1229
|
+
""
|
|
1230
|
+
);
|
|
1173
1231
|
}
|
|
1174
1232
|
return json.responseObject.hashedOnchainId;
|
|
1175
1233
|
} finally {
|
|
@@ -1371,11 +1429,21 @@ async function offramp(walletClient, params, onProgress, telemetryContext) {
|
|
|
1371
1429
|
}
|
|
1372
1430
|
emitProgress({ step: "registering" });
|
|
1373
1431
|
let hashedOnchainId;
|
|
1432
|
+
const canonicalName = platformId.startsWith("zelle") ? "zelle" : platformId;
|
|
1374
1433
|
try {
|
|
1375
|
-
const
|
|
1376
|
-
|
|
1377
|
-
hashedOnchainId = await registerPayeeDetails(canonicalName, depositData);
|
|
1434
|
+
const payeePayload = buildDepositData(canonicalName, normalizedIdentifier);
|
|
1435
|
+
hashedOnchainId = await registerPayeeDetails(canonicalName, payeePayload);
|
|
1378
1436
|
} catch (err) {
|
|
1437
|
+
const status = err instanceof MakersCreateError ? err.status : null;
|
|
1438
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1439
|
+
if (isPeerExtensionRegistrationError(canonicalName, message, status)) {
|
|
1440
|
+
throw new OfframpError(
|
|
1441
|
+
`${platform.name} maker is not yet registered in the Peer extension. Verify this handle in the extension, then retry.`,
|
|
1442
|
+
"EXTENSION_REGISTRATION_REQUIRED",
|
|
1443
|
+
"registering",
|
|
1444
|
+
err
|
|
1445
|
+
);
|
|
1446
|
+
}
|
|
1379
1447
|
throw new OfframpError(
|
|
1380
1448
|
"Payee registration failed",
|
|
1381
1449
|
"REGISTRATION_FAILED",
|
|
@@ -1713,22 +1781,37 @@ var OFFRAMP_ERROR_CODES = {
|
|
|
1713
1781
|
VALIDATION: "VALIDATION",
|
|
1714
1782
|
APPROVAL_FAILED: "APPROVAL_FAILED",
|
|
1715
1783
|
REGISTRATION_FAILED: "REGISTRATION_FAILED",
|
|
1784
|
+
/**
|
|
1785
|
+
* Curator rejected the maker because the user has not registered this
|
|
1786
|
+
* handle in the Peer extension yet. Thrown from `offramp()` for PayPal
|
|
1787
|
+
* and Wise when `/v2/makers/create` returns 400 or a "creating the maker"
|
|
1788
|
+
* message. Recover by prompting the user through the Peer extension via
|
|
1789
|
+
* `usePeerExtensionRegistration(platform)` (React) or `peerExtensionSdk`
|
|
1790
|
+
* directly, then call `offramp()` again.
|
|
1791
|
+
*/
|
|
1792
|
+
EXTENSION_REGISTRATION_REQUIRED: "EXTENSION_REGISTRATION_REQUIRED",
|
|
1716
1793
|
DEPOSIT_FAILED: "DEPOSIT_FAILED",
|
|
1717
1794
|
CONFIRMATION_FAILED: "CONFIRMATION_FAILED",
|
|
1718
1795
|
DELEGATION_FAILED: "DELEGATION_FAILED",
|
|
1719
1796
|
USER_CANCELLED: "USER_CANCELLED",
|
|
1720
1797
|
UNSUPPORTED: "UNSUPPORTED"
|
|
1721
1798
|
};
|
|
1799
|
+
|
|
1800
|
+
// src/extension.ts
|
|
1801
|
+
var import_sdk7 = require("@zkp2p/sdk");
|
|
1722
1802
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1723
1803
|
0 && (module.exports = {
|
|
1724
1804
|
CURRENCIES,
|
|
1725
1805
|
ESCROW_ADDRESS,
|
|
1806
|
+
MakersCreateError,
|
|
1726
1807
|
OFFRAMP_ERROR_CODES,
|
|
1727
1808
|
Offramp,
|
|
1728
1809
|
OfframpError,
|
|
1810
|
+
PEER_EXTENSION_CHROME_URL,
|
|
1729
1811
|
PLATFORMS,
|
|
1730
1812
|
close,
|
|
1731
1813
|
createOfframp,
|
|
1814
|
+
createPeerExtensionSdk,
|
|
1732
1815
|
createTelemetryContext,
|
|
1733
1816
|
delegate,
|
|
1734
1817
|
deposits,
|
|
@@ -1736,7 +1819,14 @@ var OFFRAMP_ERROR_CODES = {
|
|
|
1736
1819
|
emitEvent,
|
|
1737
1820
|
enableOtc,
|
|
1738
1821
|
getOtcLink,
|
|
1822
|
+
getPeerExtensionRegistrationInfo,
|
|
1823
|
+
getPeerExtensionState,
|
|
1824
|
+
isPeerExtensionAvailable,
|
|
1825
|
+
isPeerExtensionRegistrationError,
|
|
1826
|
+
normalizePaypalMeUsername,
|
|
1739
1827
|
offramp,
|
|
1828
|
+
openPeerExtensionInstallPage,
|
|
1829
|
+
peerExtensionSdk,
|
|
1740
1830
|
sanitizeAttributionId,
|
|
1741
1831
|
sendTelemetryEvent,
|
|
1742
1832
|
undelegate
|