@usdctofiat/offramp 3.0.3 → 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/CHANGELOG.md +5 -0
- package/README.md +128 -23
- package/dist/{chunk-4KKKDDES.js → chunk-XQ7HOLLB.js} +292 -96
- package/dist/chunk-XQ7HOLLB.js.map +1 -0
- package/dist/{errors-D9bV_DWE.d.cts → errors-DzTiflBh.d.cts} +161 -6
- package/dist/{errors-D9bV_DWE.d.ts → errors-DzTiflBh.d.ts} +161 -6
- package/dist/index.cjs +297 -92
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -5
- package/dist/index.d.ts +9 -5
- package/dist/index.js +9 -3
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +385 -111
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +23 -13
- package/dist/react.d.ts +23 -13
- package/dist/react.js +106 -27
- package/dist/react.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-4KKKDDES.js.map +0 -1
package/dist/react.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WalletClient } from 'viem';
|
|
2
|
-
import {
|
|
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
|
-
* `
|
|
31
|
-
*
|
|
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()` / `
|
|
47
|
+
/** Last error from `requestConnection()` / `authenticate()`, if any. */
|
|
48
48
|
error: string | null;
|
|
49
|
-
/**
|
|
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.
|
|
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
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
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.
|
|
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.
|
|
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 {
|
|
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
|
-
* `
|
|
31
|
-
*
|
|
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()` / `
|
|
47
|
+
/** Last error from `requestConnection()` / `authenticate()`, if any. */
|
|
48
48
|
error: string | null;
|
|
49
|
-
/**
|
|
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.
|
|
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
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
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.
|
|
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.
|
|
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-
|
|
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
|
|
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
|
|
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 (!
|
|
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
|
-
}, [
|
|
166
|
-
const
|
|
167
|
-
if (!
|
|
195
|
+
}, [authParams, refresh]);
|
|
196
|
+
const startRegistrationCapture = useCallback2(async () => {
|
|
197
|
+
if (!authParams) return;
|
|
168
198
|
setError(null);
|
|
169
|
-
|
|
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.
|
|
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
|
|
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
|
-
}, [
|
|
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
|
-
|
|
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":";;;;;;;;;;;;;;;AAAA,SAAS,aAAa,QAAQ,gBAAgB;AA6B9C,SAAS,eAAe,MAAiC;AACvD,MAAI,SAAS,cAAc,SAAS,cAAe,QAAO;AAC1D,MAAI,SAAS,OAAQ,QAAO;AAC5B,SAAO;AACT;AAEO,SAAS,WAAW,iBAAuC,CAAC,GAAqB;AACtF,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAuB,MAAM;AACvD,QAAM,CAAC,MAAM,OAAO,IAAI,SAA6B,IAAI;AACzD,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAwB,IAAI;AACxD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAwB,IAAI;AAC9D,QAAM,CAAC,WAAW,YAAY,IAAI,SAA8B,IAAI;AACpE,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,UAAU,OAAO,KAAK;AAE5B,QAAM,QAAQ,YAAY,MAAM;AAC9B,aAAS,MAAM;AACf,YAAQ,IAAI;AACZ,cAAU,IAAI;AACd,iBAAa,IAAI;AACjB,iBAAa,IAAI;AACjB,iBAAa,KAAK;AAClB,YAAQ,UAAU;AAAA,EACpB,GAAG,CAAC,CAAC;AAEL,QAAMA,WAAU;AAAA,IACd,OAAO,cAA4B,WAAkD;AACnF,UAAI,QAAQ,QAAS,OAAM,IAAI,aAAa,+BAA+B,YAAY;AACvF,cAAQ,UAAU;AAClB,mBAAa,IAAI;AACjB,eAAS,MAAM;AACf,mBAAa,IAAI;AACjB,cAAQ,IAAI;AACZ,gBAAU,IAAI;AACd,mBAAa,IAAI;AAEjB,UAAI;AACF,cAAM,MAAM,cAAc;AAAA,UACxB;AAAA,UACA,cAAc,OAAO,gBAAgB,eAAe;AAAA,UACpD,YAAY,OAAO,cAAc,eAAe;AAAA,UAChD,WAAW,eAAe;AAAA,QAC5B,CAAC;AACD,cAAM,SAAS,MAAM,IAAI,cAAc,QAAQ,CAAC,aAAa;AAC3D,kBAAQ,SAAS,IAAI;AACrB,mBAAS,eAAe,SAAS,IAAI,CAAC;AACtC,cAAI,SAAS,OAAQ,WAAU,SAAS,MAAM;AAC9C,cAAI,SAAS,UAAW,cAAa,SAAS,SAAS;AAAA,QACzD,CAAC;AACD,iBAAS,MAAM;AACf,qBAAa,OAAO,SAAS;AAC7B,kBAAU,OAAO,MAAM;AACvB,eAAO;AAAA,MACT,SAAS,KAAK;AACZ,cAAM,eACJ,eAAe,eACX,MACA,IAAI;AAAA,UACF,eAAe,QAAQ,IAAI,UAAU;AAAA,UACrC;AAAA,QACF;AACN,qBAAa,YAAY;AACzB,iBAAS,OAAO;AAChB,cAAM;AAAA,MACR,UAAE;AACA,qBAAa,KAAK;AAClB,gBAAQ,UAAU;AAAA,MACpB;AAAA,IACF;AAAA,IACA,CAAC,eAAe,cAAc,eAAe,YAAY,eAAe,SAAS;AAAA,EACnF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,IACP;AAAA,IACA,SAAAA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AClHA,SAAS,eAAAC,cAAa,WAAW,SAAS,UAAAC,SAAQ,YAAAC,iBAAgB;AA0H3D,SAAS,6BACd,UACoC;AACpC,QAAM,aAAa,UAAU,MAAM;AACnC,QAAM,OAAO,aAAa,iCAAiC,UAAU,IAAI;AACzE,QAAM,aAAa;AAAA,IACjB,MAAO,aAAa,uCAAuC,UAAU,IAAI;AAAA,IACzE,CAAC,UAAU;AAAA,EACb;AACA,QAAM,CAAC,OAAO,QAAQ,IAAIC;AAAA,IACxB,OAAO,aAAa;AAAA,EACtB;AACA,QAAM,CAAC,MAAM,OAAO,IAAIA,UAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAwB,IAAI;AACtD,QAAM,CAAC,kBAAkB,mBAAmB,IAAIA,UAAqC,IAAI;AACzF,QAAM,aAAaC,QAAO,IAAI;AAC9B,QAAM,aAAa,MAAM,cAAc;AACvC,QAAM,mBAAmB,YAAY,YAAY;AAEjD,QAAM,UAAUC,aAAY,YAAY;AACtC,QAAI,CAAC,YAAY;AACf,eAAS,aAAa;AACtB;AAAA,IACF;AACA,QAAI;AACF,YAAM,QAAQ,MAAM,iBAAiB,SAAS;AAC9C,UAAI,CAAC,WAAW,QAAS;AACzB,UAAI,UAAU,WAAW,CAAC,uCAAuC,GAAG;AAClE,iBAAS,eAAe;AACxB;AAAA,MACF;AACA,eAAS,YAAY,KAAK,CAAC;AAAA,IAC7B,QAAQ;AACN,UAAI,CAAC,WAAW,QAAS;AACzB,eAAS,eAAe;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,UAAU,CAAC;AAEf,YAAU,MAAM;AACd,eAAW,UAAU;AACrB,aAAS,IAAI;AACb,YAAQ,KAAK;AACb,wBAAoB,IAAI;AACxB,QAAI,CAAC,YAAY;AACf,eAAS,aAAa;AAAA,IACxB,OAAO;AACL,eAAS,UAAU;AACnB,cAAQ;AAAA,IACV;AACA,WAAO,MAAM;AACX,iBAAW,UAAU;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,YAAY,OAAO,CAAC;AAExB,YAAU,MAAM;AACd,wBAAoB,IAAI;AACxB,QAAI,CAAC,iBAAkB;AAEvB,QAAI;AACF,aAAO,iBAAiB,kBAAkB,CAAC,YAAY;AACrD,YAAI,CAAC,WAAW,WAAW,QAAQ,aAAa,iBAAkB;AAClE,4BAAoB,OAAO;AAC3B,YAAI,QAAQ,cAAc;AACxB,mBAAS,QAAQ,YAAY;AAAA,QAC/B;AAAA,MACF,CAAC;AAAA,IACH,QAAQ;AACN;AAAA,IACF;AAAA,EACF,GAAG,CAAC,kBAAkB,KAAK,CAAC;AAE5B,QAAM,mBAAmBA,aAAY,MAAM;AACzC,aAAS,IAAI;AACb,QAAI;AACF,uBAAiB,gBAAgB;AAAA,IACnC,QAAQ;AACN,UAAI,OAAO,WAAW,aAAa;AACjC,eAAO,KAAK,2BAA2B,UAAU,qBAAqB;AAAA,MACxE;AAAA,IACF;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,mBAAmBA,aAAY,YAA8B;AACjE,QAAI,CAAC,WAAY,QAAO;AACxB,aAAS,IAAI;AACb,YAAQ,IAAI;AACZ,QAAI;AACF,YAAM,WAAW,MAAM,iBAAiB,kBAAkB;AAC1D,UAAI,CAAC,WAAW,QAAS,QAAO;AAChC,UAAI,UAAU;AACZ,iBAAS,uCAAuC,IAAI,UAAU,eAAe;AAAA,MAC/E,OAAO;AACL,iBAAS,mEAAmE;AAAA,MAC9E;AACA,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,UAAI,CAAC,WAAW,QAAS,QAAO;AAChC;AAAA,QACE,eAAe,QACX,IAAI,UACJ;AAAA,MACN;AACA,cAAQ;AACR,aAAO;AAAA,IACT,UAAE;AACA,UAAI,WAAW,QAAS,SAAQ,KAAK;AAAA,IACvC;AAAA,EACF,GAAG,CAAC,YAAY,OAAO,CAAC;AAExB,QAAM,2BAA2BA,aAAY,YAAY;AACvD,QAAI,CAAC,WAAY;AACjB,aAAS,IAAI;AACb,YAAQ,IAAI;AACZ,QAAI;AACF,YAAM,QAAQ,MAAM,iBAAiB,SAAS,EAAE,MAAM,MAAM,eAAwB;AACpF,UAAI,CAAC,WAAW,QAAS;AACzB,YAAM,YACJ,UAAU,WAAW,CAAC,uCAAuC,IACzD,kBACA,YAAY,KAAK;AACvB,eAAS,SAAS;AAClB,UAAI,cAAc,iBAAiB;AACjC,yBAAiB;AACjB;AAAA,MACF;AACA,UAAI,cAAc,oBAAoB;AACpC,cAAM,WAAW,MAAM,iBAAiB,kBAAkB;AAC1D,YAAI,CAAC,WAAW,QAAS;AACzB,YAAI,CAAC,UAAU;AACb,mBAAS,mEAAmE;AAC5E;AAAA,QACF;AACA,YAAI,CAAC,uCAAuC,GAAG;AAC7C,mBAAS,eAAe;AACxB,2BAAiB;AACjB;AAAA,QACF;AACA,iBAAS,OAAO;AAAA,MAClB;AACA,0BAAoB,IAAI;AACxB,uBAAiB,aAAa,UAAU;AAAA,IAC1C,SAAS,KAAK;AACZ;AAAA,QACE,eAAe,QACX,IAAI,UACJ;AAAA,MACN;AACA,cAAQ;AAAA,IACV,UAAE;AACA,UAAI,WAAW,QAAS,SAAQ,KAAK;AAAA,IACvC;AAAA,EACF,GAAG,CAAC,YAAY,kBAAkB,OAAO,CAAC;AAE1C,QAAM,oBAAoBA;AAAA,IACxB,YAAY,yBAAyB;AAAA,IACrC,CAAC,wBAAwB;AAAA,EAC3B;AAEA,QAAM,uBAAuBA;AAAA,IAC3B,OACE,cACA,QACA,UAII,CAAC,MACsB;AAC3B,YAAM,WAAW,QAAQ,oBAAoB;AAC7C,UAAI,CAAC,UAAU;AACb,cAAM,UAAU;AAChB,iBAAS,OAAO;AAChB,cAAM,IAAI,MAAM,OAAO;AAAA,MACzB;AAEA,eAAS,IAAI;AACb,cAAQ,IAAI;AACZ,UAAI;AACF,cAAM,kCAAkC;AAAA,UACtC,UAAU,OAAO;AAAA,UACjB,YAAY,OAAO;AAAA,UACnB,kBAAkB;AAAA,QACpB,CAAC;AACD,eAAO,MAAM,QAAc,cAAc,QAAQ,QAAQ,UAAU;AAAA,MACrE,SAAS,KAAK;AACZ;AAAA,UACE,eAAe,QACX,IAAI,UACJ;AAAA,QACN;AACA,cAAM;AAAA,MACR,UAAE;AACA,YAAI,WAAW,QAAS,SAAQ,KAAK;AAAA,MACvC;AAAA,IACF;AAAA,IACA,CAAC,gBAAgB;AAAA,EACnB;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,YAAY,OAA2D;AAC9E,MAAI,UAAU,gBAAiB,QAAO;AACtC,MAAI,UAAU,mBAAoB,QAAO;AACzC,SAAO;AACT;","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
|
|
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",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@zkp2p/contracts-v2": "0.2.2",
|
|
55
|
-
"@zkp2p/sdk": "0.4.
|
|
55
|
+
"@zkp2p/sdk": "0.4.3",
|
|
56
56
|
"zod": "^4.3.6"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|