@usdctofiat/offramp 3.0.2 → 3.1.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/dist/react.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { WalletClient } from 'viem';
2
- import { m as OfframpState, n as OfframpStep, j as OfframpError, O as OfframpParams, b as OfframpResult, D as DepositInfo, c as OfframpCreateOptions, q as PeerExtensionRegistrationInfo, P as PlatformEntry } from './errors-DKQ2N_ih.cjs';
2
+ import { m as OfframpState, n as OfframpStep, f as OfframpError, h as OfframpParams, l as OfframpResult, D as DepositInfo, e as OfframpCreateOptions, x as PeerExtensionRegistrationInfo, F as PeerMetadataMessage, p as OnProgress, L as PlatformEntry } from './errors-DzTiflBh.cjs';
3
3
  import '@zkp2p/sdk';
4
4
 
5
5
  interface UseOfframpReturn {
@@ -27,8 +27,8 @@ declare function useOfframp(defaultOptions?: OfframpCreateOptions): UseOfframpRe
27
27
  * yet approved; call `connectExtension()` to trigger the Peer approval
28
28
  * prompt
29
29
  * - `ready` — extension installed and origin approved; call
30
- * `openVerifySidebar()` to send the user into the `/verify/<providerId>`
31
- * handler, or just retry the `offramp(...)` call
30
+ * `startRegistrationCapture()` to launch headless metadata capture, or just
31
+ * retry the `offramp(...)` call
32
32
  * - `unsupported` — the provided platform does not require extension
33
33
  * registration; the hook is a no-op for it
34
34
  */
@@ -44,9 +44,11 @@ interface UsePeerExtensionRegistrationReturn {
44
44
  info: PeerExtensionRegistrationInfo | null;
45
45
  /** True while a `requestConnection()` or initial state check is in flight. */
46
46
  busy: boolean;
47
- /** Last error from `requestConnection()` / `openSidebar()`, if any. */
47
+ /** Last error from `requestConnection()` / `authenticate()`, if any. */
48
48
  error: string | null;
49
- /** Re-poll `peerExtensionSdk.getState()`. Call after the user confirms they've finished the verify flow. */
49
+ /** Last metadata payload captured for this platform. */
50
+ capturedMetadata: PeerMetadataMessage | null;
51
+ /** Re-poll `peerExtensionSdk.getState()`. Call after the user finishes metadata capture. */
50
52
  refresh: () => Promise<void>;
51
53
  /**
52
54
  * Open the Chrome Web Store listing for the Peer extension. Falls back to
@@ -56,20 +58,28 @@ interface UsePeerExtensionRegistrationReturn {
56
58
  installExtension: () => void;
57
59
  /**
58
60
  * Request an origin connection. Triggers the Peer extension's approval
59
- * prompt. Returns `true` if the user approved, `false` otherwise. On
60
- * approval the hook auto-advances to `ready` and opens the verify sidebar.
61
+ * prompt. Returns `true` if the user approved, `false` otherwise.
61
62
  */
62
63
  connectExtension: () => Promise<boolean>;
63
64
  /**
64
- * Open `/verify/<providerId>` in the Peer extension sidebar so the user
65
- * can finish registering their handle. Safe to call from any phase the
66
- * hook will fall back to install/connect if those steps aren't done yet.
65
+ * Launch headless Peer metadata capture for this provider. Safe to call from
66
+ * any phase the hook will fall back to install/connect if those steps
67
+ * aren't done yet.
68
+ */
69
+ startRegistrationCapture: () => Promise<void>;
70
+ /**
71
+ * Deprecated compatibility alias for `startRegistrationCapture()`.
67
72
  */
68
73
  openVerifySidebar: () => Promise<void>;
74
+ completeRegistration: (walletClient: WalletClient, params: OfframpParams, options?: {
75
+ capturedMetadata?: PeerMetadataMessage;
76
+ onProgress?: OnProgress;
77
+ attestationServiceUrl?: string | null;
78
+ }) => Promise<OfframpResult>;
69
79
  }
70
80
  /**
71
81
  * React hook that drives the Peer extension handshake required for PayPal
72
- * and Wise makers. Mirrors the CTA state machine used in usdctofiat.xyz.
82
+ * and Wise makers.
73
83
  *
74
84
  * ```tsx
75
85
  * import { PLATFORMS } from "@usdctofiat/offramp";
@@ -93,7 +103,7 @@ interface UsePeerExtensionRegistrationReturn {
93
103
  * </button>
94
104
  * )}
95
105
  * {needsExtension && peer.phase === "ready" && (
96
- * <button onClick={peer.openVerifySidebar}>Verify in Peer</button>
106
+ * <button onClick={peer.startRegistrationCapture}>Register with Peer</button>
97
107
  * )}
98
108
  * </>
99
109
  * );
@@ -102,4 +112,4 @@ interface UsePeerExtensionRegistrationReturn {
102
112
  */
103
113
  declare function usePeerExtensionRegistration(platform: PlatformEntry | null | undefined): UsePeerExtensionRegistrationReturn;
104
114
 
105
- export { type PeerExtensionRegistrationPhase, type UseOfframpReturn, type UsePeerExtensionRegistrationReturn, useOfframp, usePeerExtensionRegistration };
115
+ export { type PeerExtensionRegistrationPhase, PeerMetadataMessage, type UseOfframpReturn, type UsePeerExtensionRegistrationReturn, useOfframp, usePeerExtensionRegistration };
package/dist/react.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { WalletClient } from 'viem';
2
- import { m as OfframpState, n as OfframpStep, j as OfframpError, O as OfframpParams, b as OfframpResult, D as DepositInfo, c as OfframpCreateOptions, q as PeerExtensionRegistrationInfo, P as PlatformEntry } from './errors-DKQ2N_ih.js';
2
+ import { m as OfframpState, n as OfframpStep, f as OfframpError, h as OfframpParams, l as OfframpResult, D as DepositInfo, e as OfframpCreateOptions, x as PeerExtensionRegistrationInfo, F as PeerMetadataMessage, p as OnProgress, L as PlatformEntry } from './errors-DzTiflBh.js';
3
3
  import '@zkp2p/sdk';
4
4
 
5
5
  interface UseOfframpReturn {
@@ -27,8 +27,8 @@ declare function useOfframp(defaultOptions?: OfframpCreateOptions): UseOfframpRe
27
27
  * yet approved; call `connectExtension()` to trigger the Peer approval
28
28
  * prompt
29
29
  * - `ready` — extension installed and origin approved; call
30
- * `openVerifySidebar()` to send the user into the `/verify/<providerId>`
31
- * handler, or just retry the `offramp(...)` call
30
+ * `startRegistrationCapture()` to launch headless metadata capture, or just
31
+ * retry the `offramp(...)` call
32
32
  * - `unsupported` — the provided platform does not require extension
33
33
  * registration; the hook is a no-op for it
34
34
  */
@@ -44,9 +44,11 @@ interface UsePeerExtensionRegistrationReturn {
44
44
  info: PeerExtensionRegistrationInfo | null;
45
45
  /** True while a `requestConnection()` or initial state check is in flight. */
46
46
  busy: boolean;
47
- /** Last error from `requestConnection()` / `openSidebar()`, if any. */
47
+ /** Last error from `requestConnection()` / `authenticate()`, if any. */
48
48
  error: string | null;
49
- /** Re-poll `peerExtensionSdk.getState()`. Call after the user confirms they've finished the verify flow. */
49
+ /** Last metadata payload captured for this platform. */
50
+ capturedMetadata: PeerMetadataMessage | null;
51
+ /** Re-poll `peerExtensionSdk.getState()`. Call after the user finishes metadata capture. */
50
52
  refresh: () => Promise<void>;
51
53
  /**
52
54
  * Open the Chrome Web Store listing for the Peer extension. Falls back to
@@ -56,20 +58,28 @@ interface UsePeerExtensionRegistrationReturn {
56
58
  installExtension: () => void;
57
59
  /**
58
60
  * Request an origin connection. Triggers the Peer extension's approval
59
- * prompt. Returns `true` if the user approved, `false` otherwise. On
60
- * approval the hook auto-advances to `ready` and opens the verify sidebar.
61
+ * prompt. Returns `true` if the user approved, `false` otherwise.
61
62
  */
62
63
  connectExtension: () => Promise<boolean>;
63
64
  /**
64
- * Open `/verify/<providerId>` in the Peer extension sidebar so the user
65
- * can finish registering their handle. Safe to call from any phase the
66
- * hook will fall back to install/connect if those steps aren't done yet.
65
+ * Launch headless Peer metadata capture for this provider. Safe to call from
66
+ * any phase the hook will fall back to install/connect if those steps
67
+ * aren't done yet.
68
+ */
69
+ startRegistrationCapture: () => Promise<void>;
70
+ /**
71
+ * Deprecated compatibility alias for `startRegistrationCapture()`.
67
72
  */
68
73
  openVerifySidebar: () => Promise<void>;
74
+ completeRegistration: (walletClient: WalletClient, params: OfframpParams, options?: {
75
+ capturedMetadata?: PeerMetadataMessage;
76
+ onProgress?: OnProgress;
77
+ attestationServiceUrl?: string | null;
78
+ }) => Promise<OfframpResult>;
69
79
  }
70
80
  /**
71
81
  * React hook that drives the Peer extension handshake required for PayPal
72
- * and Wise makers. Mirrors the CTA state machine used in usdctofiat.xyz.
82
+ * and Wise makers.
73
83
  *
74
84
  * ```tsx
75
85
  * import { PLATFORMS } from "@usdctofiat/offramp";
@@ -93,7 +103,7 @@ interface UsePeerExtensionRegistrationReturn {
93
103
  * </button>
94
104
  * )}
95
105
  * {needsExtension && peer.phase === "ready" && (
96
- * <button onClick={peer.openVerifySidebar}>Verify in Peer</button>
106
+ * <button onClick={peer.startRegistrationCapture}>Register with Peer</button>
97
107
  * )}
98
108
  * </>
99
109
  * );
@@ -102,4 +112,4 @@ interface UsePeerExtensionRegistrationReturn {
102
112
  */
103
113
  declare function usePeerExtensionRegistration(platform: PlatformEntry | null | undefined): UsePeerExtensionRegistrationReturn;
104
114
 
105
- export { type PeerExtensionRegistrationPhase, type UseOfframpReturn, type UsePeerExtensionRegistrationReturn, useOfframp, usePeerExtensionRegistration };
115
+ export { type PeerExtensionRegistrationPhase, PeerMetadataMessage, type UseOfframpReturn, type UsePeerExtensionRegistrationReturn, useOfframp, usePeerExtensionRegistration };
package/dist/react.js CHANGED
@@ -2,11 +2,15 @@ import {
2
2
  OfframpError,
3
3
  PEER_EXTENSION_CHROME_URL,
4
4
  close,
5
+ completePeerExtensionRegistration,
5
6
  createOfframp,
6
7
  deposits,
8
+ getPeerExtensionRegistrationAuthParams,
7
9
  getPeerExtensionRegistrationInfo,
10
+ isPeerExtensionMetadataBridgeAvailable,
11
+ offramp,
8
12
  peerExtensionSdk
9
- } from "./chunk-F7DVUBMT.js";
13
+ } from "./chunk-XQ7HOLLB.js";
10
14
 
11
15
  // src/hooks/useOfframp.ts
12
16
  import { useCallback, useRef, useState } from "react";
@@ -32,7 +36,7 @@ function useOfframp(defaultOptions = {}) {
32
36
  setIsLoading(false);
33
37
  lockRef.current = false;
34
38
  }, []);
35
- const offramp = useCallback(
39
+ const offramp2 = useCallback(
36
40
  async (walletClient, params) => {
37
41
  if (lockRef.current) throw new OfframpError("Deposit already in progress", "VALIDATION");
38
42
  lockRef.current = true;
@@ -82,7 +86,7 @@ function useOfframp(defaultOptions = {}) {
82
86
  lastError,
83
87
  error: lastError,
84
88
  isLoading,
85
- offramp,
89
+ offramp: offramp2,
86
90
  deposits,
87
91
  close,
88
92
  reset
@@ -90,16 +94,23 @@ function useOfframp(defaultOptions = {}) {
90
94
  }
91
95
 
92
96
  // src/hooks/usePeerExtensionRegistration.ts
93
- import { useCallback as useCallback2, useEffect, useRef as useRef2, useState as useState2 } from "react";
97
+ import { useCallback as useCallback2, useEffect, useMemo, useRef as useRef2, useState as useState2 } from "react";
94
98
  function usePeerExtensionRegistration(platform) {
95
- const info = platform ? getPeerExtensionRegistrationInfo(platform.id) : null;
99
+ const platformId = platform?.id ?? null;
100
+ const info = platformId ? getPeerExtensionRegistrationInfo(platformId) : null;
101
+ const authParams = useMemo(
102
+ () => platformId ? getPeerExtensionRegistrationAuthParams(platformId) : null,
103
+ [platformId]
104
+ );
96
105
  const [phase, setPhase] = useState2(
97
106
  info ? "checking" : "unsupported"
98
107
  );
99
108
  const [busy, setBusy] = useState2(false);
100
109
  const [error, setError] = useState2(null);
110
+ const [capturedMetadata, setCapturedMetadata] = useState2(null);
101
111
  const mountedRef = useRef2(true);
102
112
  const providerId = info?.providerId ?? null;
113
+ const metadataPlatform = authParams?.platform ?? null;
103
114
  const refresh = useCallback2(async () => {
104
115
  if (!providerId) {
105
116
  setPhase("unsupported");
@@ -108,6 +119,10 @@ function usePeerExtensionRegistration(platform) {
108
119
  try {
109
120
  const state = await peerExtensionSdk.getState();
110
121
  if (!mountedRef.current) return;
122
+ if (state === "ready" && !isPeerExtensionMetadataBridgeAvailable()) {
123
+ setPhase("needs_install");
124
+ return;
125
+ }
111
126
  setPhase(mapSdkState(state));
112
127
  } catch {
113
128
  if (!mountedRef.current) return;
@@ -118,6 +133,7 @@ function usePeerExtensionRegistration(platform) {
118
133
  mountedRef.current = true;
119
134
  setError(null);
120
135
  setBusy(false);
136
+ setCapturedMetadata(null);
121
137
  if (!providerId) {
122
138
  setPhase("unsupported");
123
139
  } else {
@@ -128,6 +144,21 @@ function usePeerExtensionRegistration(platform) {
128
144
  mountedRef.current = false;
129
145
  };
130
146
  }, [providerId, refresh]);
147
+ useEffect(() => {
148
+ setCapturedMetadata(null);
149
+ if (!metadataPlatform) return;
150
+ try {
151
+ return peerExtensionSdk.onMetadataMessage((message) => {
152
+ if (!mountedRef.current || message.platform !== metadataPlatform) return;
153
+ setCapturedMetadata(message);
154
+ if (message.errorMessage) {
155
+ setError(message.errorMessage);
156
+ }
157
+ });
158
+ } catch {
159
+ return;
160
+ }
161
+ }, [metadataPlatform, phase]);
131
162
  const installExtension = useCallback2(() => {
132
163
  setError(null);
133
164
  try {
@@ -139,15 +170,14 @@ function usePeerExtensionRegistration(platform) {
139
170
  }
140
171
  }, []);
141
172
  const connectExtension = useCallback2(async () => {
142
- if (!providerId) return false;
173
+ if (!authParams) return false;
143
174
  setError(null);
144
175
  setBusy(true);
145
176
  try {
146
177
  const approved = await peerExtensionSdk.requestConnection();
147
178
  if (!mountedRef.current) return approved;
148
179
  if (approved) {
149
- setPhase("ready");
150
- peerExtensionSdk.openSidebar(`/verify/${providerId}`);
180
+ setPhase(isPeerExtensionMetadataBridgeAvailable() ? "ready" : "needs_install");
151
181
  } else {
152
182
  setError("Connection was not approved. Try again once you've approved Peer.");
153
183
  }
@@ -162,40 +192,89 @@ function usePeerExtensionRegistration(platform) {
162
192
  } finally {
163
193
  if (mountedRef.current) setBusy(false);
164
194
  }
165
- }, [providerId, refresh]);
166
- const openVerifySidebar = useCallback2(async () => {
167
- if (!providerId) return;
195
+ }, [authParams, refresh]);
196
+ const startRegistrationCapture = useCallback2(async () => {
197
+ if (!authParams) return;
168
198
  setError(null);
169
- const state = await peerExtensionSdk.getState().catch(() => "needs_install");
170
- if (!mountedRef.current) return;
171
- const nextPhase = mapSdkState(state);
172
- setPhase(nextPhase);
173
- if (nextPhase === "needs_install") {
174
- installExtension();
175
- return;
176
- }
177
- if (nextPhase === "needs_connection") {
178
- await connectExtension();
179
- return;
180
- }
199
+ setBusy(true);
181
200
  try {
182
- peerExtensionSdk.openSidebar(`/verify/${providerId}`);
201
+ const state = await peerExtensionSdk.getState().catch(() => "needs_install");
202
+ if (!mountedRef.current) return;
203
+ const nextPhase = state === "ready" && !isPeerExtensionMetadataBridgeAvailable() ? "needs_install" : mapSdkState(state);
204
+ setPhase(nextPhase);
205
+ if (nextPhase === "needs_install") {
206
+ installExtension();
207
+ return;
208
+ }
209
+ if (nextPhase === "needs_connection") {
210
+ const approved = await peerExtensionSdk.requestConnection();
211
+ if (!mountedRef.current) return;
212
+ if (!approved) {
213
+ setError("Connection was not approved. Try again once you've approved Peer.");
214
+ return;
215
+ }
216
+ if (!isPeerExtensionMetadataBridgeAvailable()) {
217
+ setPhase("needs_install");
218
+ installExtension();
219
+ return;
220
+ }
221
+ setPhase("ready");
222
+ }
223
+ setCapturedMetadata(null);
224
+ peerExtensionSdk.authenticate(authParams);
183
225
  } catch (err) {
184
226
  setError(
185
- err instanceof Error ? err.message : "Couldn't open the Peer extension. Make sure it's enabled."
227
+ err instanceof Error ? err.message : "Couldn't start Peer extension registration. Make sure Peer is enabled."
186
228
  );
187
229
  refresh();
230
+ } finally {
231
+ if (mountedRef.current) setBusy(false);
188
232
  }
189
- }, [connectExtension, installExtension, providerId, refresh]);
233
+ }, [authParams, installExtension, refresh]);
234
+ const openVerifySidebar = useCallback2(
235
+ async () => startRegistrationCapture(),
236
+ [startRegistrationCapture]
237
+ );
238
+ const completeRegistration = useCallback2(
239
+ async (walletClient, params, options = {}) => {
240
+ const metadata = options.capturedMetadata ?? capturedMetadata;
241
+ if (!metadata) {
242
+ const message = "No Peer metadata captured yet. Start registration first.";
243
+ setError(message);
244
+ throw new Error(message);
245
+ }
246
+ setError(null);
247
+ setBusy(true);
248
+ try {
249
+ await completePeerExtensionRegistration({
250
+ platform: params.platform,
251
+ identifier: params.identifier,
252
+ capturedMetadata: metadata
253
+ });
254
+ return await offramp(walletClient, params, options.onProgress);
255
+ } catch (err) {
256
+ setError(
257
+ err instanceof Error ? err.message : "Couldn't complete Peer extension registration. Try capturing metadata again."
258
+ );
259
+ throw err;
260
+ } finally {
261
+ if (mountedRef.current) setBusy(false);
262
+ }
263
+ },
264
+ [capturedMetadata]
265
+ );
190
266
  return {
191
267
  phase,
192
268
  info,
193
269
  busy,
194
270
  error,
271
+ capturedMetadata,
195
272
  refresh,
196
273
  installExtension,
197
274
  connectExtension,
198
- openVerifySidebar
275
+ startRegistrationCapture,
276
+ openVerifySidebar,
277
+ completeRegistration
199
278
  };
200
279
  }
201
280
  function mapSdkState(state) {
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks/useOfframp.ts","../src/hooks/usePeerExtensionRegistration.ts"],"sourcesContent":["import { useCallback, useRef, useState } from \"react\";\nimport type { WalletClient } from \"viem\";\nimport type {\n OfframpCreateOptions,\n OfframpParams,\n OfframpResult,\n OfframpState,\n OfframpStep,\n DepositInfo,\n} from \"../types\";\nimport { createOfframp } from \"../offramp\";\nimport { deposits as depositsFn, close as closeFn } from \"../queries\";\nimport { OfframpError } from \"../errors\";\n\nexport interface UseOfframpReturn {\n state: OfframpState;\n step: OfframpStep | null;\n txHash: string | null;\n depositId: string | null;\n lastError: OfframpError | null;\n /** @deprecated Use `lastError` instead. */\n error: OfframpError | null;\n isLoading: boolean;\n offramp: (walletClient: WalletClient, params: OfframpParams) => Promise<OfframpResult>;\n deposits: (walletAddress: string) => Promise<DepositInfo[]>;\n close: (walletClient: WalletClient, depositId: string, escrowAddress?: string) => Promise<string>;\n reset: () => void;\n}\n\nfunction mapStepToState(step: OfframpStep): OfframpState {\n if (step === \"resuming\" || step === \"restricting\") return \"delegating\";\n if (step === \"done\") return \"done\";\n return step;\n}\n\nexport function useOfframp(defaultOptions: OfframpCreateOptions = {}): UseOfframpReturn {\n const [state, setState] = useState<OfframpState>(\"idle\");\n const [step, setStep] = useState<OfframpStep | null>(null);\n const [txHash, setTxHash] = useState<string | null>(null);\n const [depositId, setDepositId] = useState<string | null>(null);\n const [lastError, setLastError] = useState<OfframpError | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const lockRef = useRef(false);\n\n const reset = useCallback(() => {\n setState(\"idle\");\n setStep(null);\n setTxHash(null);\n setDepositId(null);\n setLastError(null);\n setIsLoading(false);\n lockRef.current = false;\n }, []);\n\n const offramp = useCallback(\n async (walletClient: WalletClient, params: OfframpParams): Promise<OfframpResult> => {\n if (lockRef.current) throw new OfframpError(\"Deposit already in progress\", \"VALIDATION\");\n lockRef.current = true;\n setIsLoading(true);\n setState(\"idle\");\n setLastError(null);\n setStep(null);\n setTxHash(null);\n setDepositId(null);\n\n try {\n const sdk = createOfframp({\n walletClient,\n integratorId: params.integratorId ?? defaultOptions.integratorId,\n referralId: params.referralId ?? defaultOptions.referralId,\n telemetry: defaultOptions.telemetry,\n });\n const result = await sdk.createDeposit(params, (progress) => {\n setStep(progress.step);\n setState(mapStepToState(progress.step));\n if (progress.txHash) setTxHash(progress.txHash);\n if (progress.depositId) setDepositId(progress.depositId);\n });\n setState(\"done\");\n setDepositId(result.depositId);\n setTxHash(result.txHash);\n return result;\n } catch (err) {\n const offrampError =\n err instanceof OfframpError\n ? err\n : new OfframpError(\n err instanceof Error ? err.message : \"Offramp failed\",\n \"DEPOSIT_FAILED\",\n );\n setLastError(offrampError);\n setState(\"error\");\n throw offrampError;\n } finally {\n setIsLoading(false);\n lockRef.current = false;\n }\n },\n [defaultOptions.integratorId, defaultOptions.referralId, defaultOptions.telemetry],\n );\n\n return {\n state,\n step,\n txHash,\n depositId,\n lastError,\n error: lastError,\n isLoading,\n offramp,\n deposits: depositsFn,\n close: closeFn,\n reset,\n };\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { peerExtensionSdk, type PeerExtensionState, PEER_EXTENSION_CHROME_URL } from \"../extension\";\nimport {\n getPeerExtensionRegistrationInfo,\n type PeerExtensionRegistrationInfo,\n type PlatformEntry,\n} from \"../platforms\";\n\n/**\n * Phase surfaced to callers:\n * - `checking` — polling the extension state on mount\n * - `needs_install` — the Peer extension is not installed; call\n * `installExtension()` or surface the install URL\n * - `needs_connection` — the extension is installed but this origin is not\n * yet approved; call `connectExtension()` to trigger the Peer approval\n * prompt\n * - `ready` — extension installed and origin approved; call\n * `openVerifySidebar()` to send the user into the `/verify/<providerId>`\n * handler, or just retry the `offramp(...)` call\n * - `unsupported` — the provided platform does not require extension\n * registration; the hook is a no-op for it\n */\nexport type PeerExtensionRegistrationPhase =\n | \"checking\"\n | \"needs_install\"\n | \"needs_connection\"\n | \"ready\"\n | \"unsupported\";\n\nexport interface UsePeerExtensionRegistrationReturn {\n /** Current handshake phase. */\n phase: PeerExtensionRegistrationPhase;\n /**\n * Registration metadata for this platform (prompt copy, CTA label, min\n * extension version). `null` for platforms that don't require extension\n * registration, in which case `phase === \"unsupported\"`.\n */\n info: PeerExtensionRegistrationInfo | null;\n /** True while a `requestConnection()` or initial state check is in flight. */\n busy: boolean;\n /** Last error from `requestConnection()` / `openSidebar()`, if any. */\n error: string | null;\n /** Re-poll `peerExtensionSdk.getState()`. Call after the user confirms they've finished the verify flow. */\n refresh: () => Promise<void>;\n /**\n * Open the Chrome Web Store listing for the Peer extension. Falls back to\n * `window.open(PEER_EXTENSION_CHROME_URL)` outside of browsers where\n * `openInstallPage()` would throw.\n */\n installExtension: () => void;\n /**\n * Request an origin connection. Triggers the Peer extension's approval\n * prompt. Returns `true` if the user approved, `false` otherwise. On\n * approval the hook auto-advances to `ready` and opens the verify sidebar.\n */\n connectExtension: () => Promise<boolean>;\n /**\n * Open `/verify/<providerId>` in the Peer extension sidebar so the user\n * can finish registering their handle. Safe to call from any phase — the\n * hook will fall back to install/connect if those steps aren't done yet.\n */\n openVerifySidebar: () => Promise<void>;\n}\n\n/**\n * React hook that drives the Peer extension handshake required for PayPal\n * and Wise makers. Mirrors the CTA state machine used in usdctofiat.xyz.\n *\n * ```tsx\n * import { PLATFORMS } from \"@usdctofiat/offramp\";\n * import { useOfframp, usePeerExtensionRegistration } from \"@usdctofiat/offramp/react\";\n *\n * function PayPalSellButton() {\n * const { offramp, lastError } = useOfframp();\n * const peer = usePeerExtensionRegistration(PLATFORMS.PAYPAL);\n *\n * const needsExtension = lastError?.code === \"EXTENSION_REGISTRATION_REQUIRED\";\n *\n * return (\n * <>\n * <button onClick={() => offramp(walletClient, params)}>Sell USDC</button>\n * {needsExtension && peer.phase === \"needs_install\" && (\n * <button onClick={peer.installExtension}>Install Peer Extension</button>\n * )}\n * {needsExtension && peer.phase === \"needs_connection\" && (\n * <button onClick={peer.connectExtension} disabled={peer.busy}>\n * Connect Peer Extension\n * </button>\n * )}\n * {needsExtension && peer.phase === \"ready\" && (\n * <button onClick={peer.openVerifySidebar}>Verify in Peer</button>\n * )}\n * </>\n * );\n * }\n * ```\n */\nexport function usePeerExtensionRegistration(\n platform: PlatformEntry | null | undefined,\n): UsePeerExtensionRegistrationReturn {\n const info = platform ? getPeerExtensionRegistrationInfo(platform.id) : null;\n const [phase, setPhase] = useState<PeerExtensionRegistrationPhase>(\n info ? \"checking\" : \"unsupported\",\n );\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const mountedRef = useRef(true);\n // Close over the current provider id so state refreshes triggered after\n // `platform` swaps don't race with the previous one.\n const providerId = info?.providerId ?? null;\n\n const refresh = useCallback(async () => {\n if (!providerId) {\n setPhase(\"unsupported\");\n return;\n }\n try {\n const state = await peerExtensionSdk.getState();\n if (!mountedRef.current) return;\n setPhase(mapSdkState(state));\n } catch {\n if (!mountedRef.current) return;\n setPhase(\"needs_install\");\n }\n }, [providerId]);\n\n useEffect(() => {\n mountedRef.current = true;\n setError(null);\n setBusy(false);\n if (!providerId) {\n setPhase(\"unsupported\");\n } else {\n setPhase(\"checking\");\n refresh();\n }\n return () => {\n mountedRef.current = false;\n };\n }, [providerId, refresh]);\n\n const installExtension = useCallback(() => {\n setError(null);\n try {\n peerExtensionSdk.openInstallPage();\n } catch {\n if (typeof window !== \"undefined\") {\n window.open(PEER_EXTENSION_CHROME_URL, \"_blank\", \"noopener,noreferrer\");\n }\n }\n }, []);\n\n const connectExtension = useCallback(async (): Promise<boolean> => {\n if (!providerId) return false;\n setError(null);\n setBusy(true);\n try {\n const approved = await peerExtensionSdk.requestConnection();\n if (!mountedRef.current) return approved;\n if (approved) {\n setPhase(\"ready\");\n peerExtensionSdk.openSidebar(`/verify/${providerId}`);\n } else {\n setError(\"Connection was not approved. Try again once you've approved Peer.\");\n }\n return approved;\n } catch (err) {\n if (!mountedRef.current) return false;\n setError(\n err instanceof Error\n ? err.message\n : \"Couldn't request a Peer extension connection. Make sure Peer is installed and enabled.\",\n );\n // Re-check state in case the user installed or disabled something.\n refresh();\n return false;\n } finally {\n if (mountedRef.current) setBusy(false);\n }\n }, [providerId, refresh]);\n\n const openVerifySidebar = useCallback(async () => {\n if (!providerId) return;\n setError(null);\n // Resync state before opening — the user may have installed or\n // disconnected while the hook was idle.\n const state = await peerExtensionSdk.getState().catch(() => \"needs_install\" as const);\n if (!mountedRef.current) return;\n const nextPhase = mapSdkState(state);\n setPhase(nextPhase);\n if (nextPhase === \"needs_install\") {\n installExtension();\n return;\n }\n if (nextPhase === \"needs_connection\") {\n await connectExtension();\n return;\n }\n try {\n peerExtensionSdk.openSidebar(`/verify/${providerId}`);\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : \"Couldn't open the Peer extension. Make sure it's enabled.\",\n );\n refresh();\n }\n }, [connectExtension, installExtension, providerId, refresh]);\n\n return {\n phase,\n info,\n busy,\n error,\n refresh,\n installExtension,\n connectExtension,\n openVerifySidebar,\n };\n}\n\nfunction mapSdkState(state: PeerExtensionState): PeerExtensionRegistrationPhase {\n if (state === \"needs_install\") return \"needs_install\";\n if (state === \"needs_connection\") return \"needs_connection\";\n return \"ready\";\n}\n"],"mappings":"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","names":["useCallback","useRef","useState","useState","useRef","useCallback"]}
1
+ {"version":3,"sources":["../src/hooks/useOfframp.ts","../src/hooks/usePeerExtensionRegistration.ts"],"sourcesContent":["import { useCallback, useRef, useState } from \"react\";\nimport type { WalletClient } from \"viem\";\nimport type {\n OfframpCreateOptions,\n OfframpParams,\n OfframpResult,\n OfframpState,\n OfframpStep,\n DepositInfo,\n} from \"../types\";\nimport { createOfframp } from \"../offramp\";\nimport { deposits as depositsFn, close as closeFn } from \"../queries\";\nimport { OfframpError } from \"../errors\";\n\nexport interface UseOfframpReturn {\n state: OfframpState;\n step: OfframpStep | null;\n txHash: string | null;\n depositId: string | null;\n lastError: OfframpError | null;\n /** @deprecated Use `lastError` instead. */\n error: OfframpError | null;\n isLoading: boolean;\n offramp: (walletClient: WalletClient, params: OfframpParams) => Promise<OfframpResult>;\n deposits: (walletAddress: string) => Promise<DepositInfo[]>;\n close: (walletClient: WalletClient, depositId: string, escrowAddress?: string) => Promise<string>;\n reset: () => void;\n}\n\nfunction mapStepToState(step: OfframpStep): OfframpState {\n if (step === \"resuming\" || step === \"restricting\") return \"delegating\";\n if (step === \"done\") return \"done\";\n return step;\n}\n\nexport function useOfframp(defaultOptions: OfframpCreateOptions = {}): UseOfframpReturn {\n const [state, setState] = useState<OfframpState>(\"idle\");\n const [step, setStep] = useState<OfframpStep | null>(null);\n const [txHash, setTxHash] = useState<string | null>(null);\n const [depositId, setDepositId] = useState<string | null>(null);\n const [lastError, setLastError] = useState<OfframpError | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const lockRef = useRef(false);\n\n const reset = useCallback(() => {\n setState(\"idle\");\n setStep(null);\n setTxHash(null);\n setDepositId(null);\n setLastError(null);\n setIsLoading(false);\n lockRef.current = false;\n }, []);\n\n const offramp = useCallback(\n async (walletClient: WalletClient, params: OfframpParams): Promise<OfframpResult> => {\n if (lockRef.current) throw new OfframpError(\"Deposit already in progress\", \"VALIDATION\");\n lockRef.current = true;\n setIsLoading(true);\n setState(\"idle\");\n setLastError(null);\n setStep(null);\n setTxHash(null);\n setDepositId(null);\n\n try {\n const sdk = createOfframp({\n walletClient,\n integratorId: params.integratorId ?? defaultOptions.integratorId,\n referralId: params.referralId ?? defaultOptions.referralId,\n telemetry: defaultOptions.telemetry,\n });\n const result = await sdk.createDeposit(params, (progress) => {\n setStep(progress.step);\n setState(mapStepToState(progress.step));\n if (progress.txHash) setTxHash(progress.txHash);\n if (progress.depositId) setDepositId(progress.depositId);\n });\n setState(\"done\");\n setDepositId(result.depositId);\n setTxHash(result.txHash);\n return result;\n } catch (err) {\n const offrampError =\n err instanceof OfframpError\n ? err\n : new OfframpError(\n err instanceof Error ? err.message : \"Offramp failed\",\n \"DEPOSIT_FAILED\",\n );\n setLastError(offrampError);\n setState(\"error\");\n throw offrampError;\n } finally {\n setIsLoading(false);\n lockRef.current = false;\n }\n },\n [defaultOptions.integratorId, defaultOptions.referralId, defaultOptions.telemetry],\n );\n\n return {\n state,\n step,\n txHash,\n depositId,\n lastError,\n error: lastError,\n isLoading,\n offramp,\n deposits: depositsFn,\n close: closeFn,\n reset,\n };\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { WalletClient } from \"viem\";\nimport { offramp as createDeposit } from \"../deposit\";\nimport {\n peerExtensionSdk,\n isPeerExtensionMetadataBridgeAvailable,\n type PeerExtensionState,\n PEER_EXTENSION_CHROME_URL,\n type PeerMetadataMessage,\n} from \"../extension\";\nimport {\n completePeerExtensionRegistration,\n getPeerExtensionRegistrationAuthParams,\n getPeerExtensionRegistrationInfo,\n type PeerExtensionRegistrationInfo,\n type PlatformEntry,\n} from \"../platforms\";\nimport type { OfframpParams, OfframpResult, OnProgress } from \"../types\";\n\n/**\n * Phase surfaced to callers:\n * - `checking` — polling the extension state on mount\n * - `needs_install` — the Peer extension is not installed; call\n * `installExtension()` or surface the install URL\n * - `needs_connection` — the extension is installed but this origin is not\n * yet approved; call `connectExtension()` to trigger the Peer approval\n * prompt\n * - `ready` — extension installed and origin approved; call\n * `startRegistrationCapture()` to launch headless metadata capture, or just\n * retry the `offramp(...)` call\n * - `unsupported` — the provided platform does not require extension\n * registration; the hook is a no-op for it\n */\nexport type PeerExtensionRegistrationPhase =\n | \"checking\"\n | \"needs_install\"\n | \"needs_connection\"\n | \"ready\"\n | \"unsupported\";\n\nexport interface UsePeerExtensionRegistrationReturn {\n /** Current handshake phase. */\n phase: PeerExtensionRegistrationPhase;\n /**\n * Registration metadata for this platform (prompt copy, CTA label, min\n * extension version). `null` for platforms that don't require extension\n * registration, in which case `phase === \"unsupported\"`.\n */\n info: PeerExtensionRegistrationInfo | null;\n /** True while a `requestConnection()` or initial state check is in flight. */\n busy: boolean;\n /** Last error from `requestConnection()` / `authenticate()`, if any. */\n error: string | null;\n /** Last metadata payload captured for this platform. */\n capturedMetadata: PeerMetadataMessage | null;\n /** Re-poll `peerExtensionSdk.getState()`. Call after the user finishes metadata capture. */\n refresh: () => Promise<void>;\n /**\n * Open the Chrome Web Store listing for the Peer extension. Falls back to\n * `window.open(PEER_EXTENSION_CHROME_URL)` outside of browsers where\n * `openInstallPage()` would throw.\n */\n installExtension: () => void;\n /**\n * Request an origin connection. Triggers the Peer extension's approval\n * prompt. Returns `true` if the user approved, `false` otherwise.\n */\n connectExtension: () => Promise<boolean>;\n /**\n * Launch headless Peer metadata capture for this provider. Safe to call from\n * any phase — the hook will fall back to install/connect if those steps\n * aren't done yet.\n */\n startRegistrationCapture: () => Promise<void>;\n /**\n * Deprecated compatibility alias for `startRegistrationCapture()`.\n */\n openVerifySidebar: () => Promise<void>;\n completeRegistration: (\n walletClient: WalletClient,\n params: OfframpParams,\n options?: {\n capturedMetadata?: PeerMetadataMessage;\n onProgress?: OnProgress;\n attestationServiceUrl?: string | null;\n },\n ) => Promise<OfframpResult>;\n}\n\n/**\n * React hook that drives the Peer extension handshake required for PayPal\n * and Wise makers.\n *\n * ```tsx\n * import { PLATFORMS } from \"@usdctofiat/offramp\";\n * import { useOfframp, usePeerExtensionRegistration } from \"@usdctofiat/offramp/react\";\n *\n * function PayPalSellButton() {\n * const { offramp, lastError } = useOfframp();\n * const peer = usePeerExtensionRegistration(PLATFORMS.PAYPAL);\n *\n * const needsExtension = lastError?.code === \"EXTENSION_REGISTRATION_REQUIRED\";\n *\n * return (\n * <>\n * <button onClick={() => offramp(walletClient, params)}>Sell USDC</button>\n * {needsExtension && peer.phase === \"needs_install\" && (\n * <button onClick={peer.installExtension}>Install Peer Extension</button>\n * )}\n * {needsExtension && peer.phase === \"needs_connection\" && (\n * <button onClick={peer.connectExtension} disabled={peer.busy}>\n * Connect Peer Extension\n * </button>\n * )}\n * {needsExtension && peer.phase === \"ready\" && (\n * <button onClick={peer.startRegistrationCapture}>Register with Peer</button>\n * )}\n * </>\n * );\n * }\n * ```\n */\nexport function usePeerExtensionRegistration(\n platform: PlatformEntry | null | undefined,\n): UsePeerExtensionRegistrationReturn {\n const platformId = platform?.id ?? null;\n const info = platformId ? getPeerExtensionRegistrationInfo(platformId) : null;\n const authParams = useMemo(\n () => (platformId ? getPeerExtensionRegistrationAuthParams(platformId) : null),\n [platformId],\n );\n const [phase, setPhase] = useState<PeerExtensionRegistrationPhase>(\n info ? \"checking\" : \"unsupported\",\n );\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [capturedMetadata, setCapturedMetadata] = useState<PeerMetadataMessage | null>(null);\n const mountedRef = useRef(true);\n const providerId = info?.providerId ?? null;\n const metadataPlatform = authParams?.platform ?? null;\n\n const refresh = useCallback(async () => {\n if (!providerId) {\n setPhase(\"unsupported\");\n return;\n }\n try {\n const state = await peerExtensionSdk.getState();\n if (!mountedRef.current) return;\n if (state === \"ready\" && !isPeerExtensionMetadataBridgeAvailable()) {\n setPhase(\"needs_install\");\n return;\n }\n setPhase(mapSdkState(state));\n } catch {\n if (!mountedRef.current) return;\n setPhase(\"needs_install\");\n }\n }, [providerId]);\n\n useEffect(() => {\n mountedRef.current = true;\n setError(null);\n setBusy(false);\n setCapturedMetadata(null);\n if (!providerId) {\n setPhase(\"unsupported\");\n } else {\n setPhase(\"checking\");\n refresh();\n }\n return () => {\n mountedRef.current = false;\n };\n }, [providerId, refresh]);\n\n useEffect(() => {\n setCapturedMetadata(null);\n if (!metadataPlatform) return;\n\n try {\n return peerExtensionSdk.onMetadataMessage((message) => {\n if (!mountedRef.current || message.platform !== metadataPlatform) return;\n setCapturedMetadata(message);\n if (message.errorMessage) {\n setError(message.errorMessage);\n }\n });\n } catch {\n return;\n }\n }, [metadataPlatform, phase]);\n\n const installExtension = useCallback(() => {\n setError(null);\n try {\n peerExtensionSdk.openInstallPage();\n } catch {\n if (typeof window !== \"undefined\") {\n window.open(PEER_EXTENSION_CHROME_URL, \"_blank\", \"noopener,noreferrer\");\n }\n }\n }, []);\n\n const connectExtension = useCallback(async (): Promise<boolean> => {\n if (!authParams) return false;\n setError(null);\n setBusy(true);\n try {\n const approved = await peerExtensionSdk.requestConnection();\n if (!mountedRef.current) return approved;\n if (approved) {\n setPhase(isPeerExtensionMetadataBridgeAvailable() ? \"ready\" : \"needs_install\");\n } else {\n setError(\"Connection was not approved. Try again once you've approved Peer.\");\n }\n return approved;\n } catch (err) {\n if (!mountedRef.current) return false;\n setError(\n err instanceof Error\n ? err.message\n : \"Couldn't request a Peer extension connection. Make sure Peer is installed and enabled.\",\n );\n refresh();\n return false;\n } finally {\n if (mountedRef.current) setBusy(false);\n }\n }, [authParams, refresh]);\n\n const startRegistrationCapture = useCallback(async () => {\n if (!authParams) return;\n setError(null);\n setBusy(true);\n try {\n const state = await peerExtensionSdk.getState().catch(() => \"needs_install\" as const);\n if (!mountedRef.current) return;\n const nextPhase =\n state === \"ready\" && !isPeerExtensionMetadataBridgeAvailable()\n ? \"needs_install\"\n : mapSdkState(state);\n setPhase(nextPhase);\n if (nextPhase === \"needs_install\") {\n installExtension();\n return;\n }\n if (nextPhase === \"needs_connection\") {\n const approved = await peerExtensionSdk.requestConnection();\n if (!mountedRef.current) return;\n if (!approved) {\n setError(\"Connection was not approved. Try again once you've approved Peer.\");\n return;\n }\n if (!isPeerExtensionMetadataBridgeAvailable()) {\n setPhase(\"needs_install\");\n installExtension();\n return;\n }\n setPhase(\"ready\");\n }\n setCapturedMetadata(null);\n peerExtensionSdk.authenticate(authParams);\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : \"Couldn't start Peer extension registration. Make sure Peer is enabled.\",\n );\n refresh();\n } finally {\n if (mountedRef.current) setBusy(false);\n }\n }, [authParams, installExtension, refresh]);\n\n const openVerifySidebar = useCallback(\n async () => startRegistrationCapture(),\n [startRegistrationCapture],\n );\n\n const completeRegistration = useCallback(\n async (\n walletClient: WalletClient,\n params: OfframpParams,\n options: {\n capturedMetadata?: PeerMetadataMessage;\n onProgress?: OnProgress;\n attestationServiceUrl?: string | null;\n } = {},\n ): Promise<OfframpResult> => {\n const metadata = options.capturedMetadata ?? capturedMetadata;\n if (!metadata) {\n const message = \"No Peer metadata captured yet. Start registration first.\";\n setError(message);\n throw new Error(message);\n }\n\n setError(null);\n setBusy(true);\n try {\n await completePeerExtensionRegistration({\n platform: params.platform,\n identifier: params.identifier,\n capturedMetadata: metadata,\n });\n return await createDeposit(walletClient, params, options.onProgress);\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : \"Couldn't complete Peer extension registration. Try capturing metadata again.\",\n );\n throw err;\n } finally {\n if (mountedRef.current) setBusy(false);\n }\n },\n [capturedMetadata],\n );\n\n return {\n phase,\n info,\n busy,\n error,\n capturedMetadata,\n refresh,\n installExtension,\n connectExtension,\n startRegistrationCapture,\n openVerifySidebar,\n completeRegistration,\n };\n}\n\nfunction mapSdkState(state: PeerExtensionState): PeerExtensionRegistrationPhase {\n if (state === \"needs_install\") return \"needs_install\";\n if (state === \"needs_connection\") return \"needs_connection\";\n return \"ready\";\n}\n"],"mappings":"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","names":["offramp","useCallback","useRef","useState","useState","useRef","useCallback"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usdctofiat/offramp",
3
- "version": "3.0.2",
3
+ "version": "3.1.0",
4
4
  "description": "USDC-to-fiat offramp SDK — create delegated deposits in one function call",
5
5
  "license": "MIT",
6
6
  "author": "Galleon Labs",
@@ -51,14 +51,16 @@
51
51
  "test": "vitest run"
52
52
  },
53
53
  "dependencies": {
54
- "@zkp2p/sdk": "0.4.0-rc.4",
54
+ "@zkp2p/contracts-v2": "0.2.2",
55
+ "@zkp2p/sdk": "0.4.3",
55
56
  "zod": "^4.3.6"
56
57
  },
57
58
  "devDependencies": {
59
+ "@types/react": "^19.2.9",
58
60
  "tsup": "^8.5.0",
59
61
  "typescript": "^6.0.3",
60
62
  "viem": "^2.48.8",
61
- "vitest": "^4.1.2"
63
+ "vitest": "^4.1.7"
62
64
  },
63
65
  "peerDependencies": {
64
66
  "react": ">=18.0.0",