@oasisprotocol/privana-sdk 0.2.1 → 0.4.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/index.js CHANGED
@@ -1,579 +1,15 @@
1
1
  "use client";
2
- import { createContext, useMemo, useState, useEffect, useRef, useCallback, useContext, useSyncExternalStore, useId } from 'react';
3
- import { zeroAddress, erc20Abi, hexToString } from 'viem';
4
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { usePrivanaContext, createHostedAuthPendingStorageKey, clearHostedAuthPendingTransaction, HostedAuthRequiredError, HostedAuthError, createPkceVerifier, createPkceChallenge, createHostedAuthState, persistHostedAuthPendingTransaction, parseHostedAuthCallback, readHostedAuthPendingTransaction, HostedAuthStateMismatchError, buildHostedAuthSession, useSafePrivanaContext, usePrivateReadRequest, formatTokenAmount, useDepositVerification, getTransactionReceipt, waitForTransactionReceipt, cn, Button, stripHostedAuthCallbackParams, AccountingApiError, getChainId2, shortenAddress, formatTimeRemaining, parseTokenAmount, getExplorerAddressUrl } from './chunk-ZVNC4FTJ.js';
3
+ export { AccountingApiError, Button, HOSTED_AUTH_CLOCK_SKEW_MS, HostedAuthError, HostedAuthRequiredError, HostedAuthStateMismatchError, HttpClient, NETWORK_CONFIG, NetworkError, PrivanaClient, PrivanaProvider, SUPPORTED_CHAINS, SiweAuthProvider, ValidationError, applyRefreshResponse, buildHostedAuthSession, buttonVariants, clearHostedAuthPendingTransaction, createHostedAuthPendingStorageKey, createHostedAuthState, createHostedAuthStorageKey, createPkceChallenge, createPkceVerifier, getAccountingContract, getApiUrl, getChainById, getChainId, getExplorerAddressUrl, isHostedAuthRefreshActive, isHostedAuthSessionActive, normalizeAddress, normalizeHex, parseHostedAuthCallback, persistHostedAuthPendingTransaction, readHostedAuthPendingTransaction, readStoredHostedAuthSession, stripHostedAuthCallbackParams, syncHostedAuthSessionToClient, useDepositVerification, usePrivanaContext, useSafeAccount, useSafePrivanaContext, useSiweAuth } from './chunk-ZVNC4FTJ.js';
4
+ import { useState, useRef, useMemo, useCallback, useContext, useEffect, useId } from 'react';
5
5
  import { QueryClientContext, useQuery, useQueryClient, useMutation, keepPreviousData } from '@tanstack/react-query';
6
- import { clsx } from 'clsx';
7
- import { twMerge } from 'tailwind-merge';
8
- import { createSiweMessage } from 'viem/siwe';
9
- import { WagmiContext, useAccount, useWalletClient, useConfig, useWriteContract, useSendTransaction, useChainId, useSwitchChain, useBalance as useBalance$1, useReadContract } from 'wagmi';
10
- import { watchAccount, getAccount, getWalletClient } from 'wagmi/actions';
11
- import { getTransactionReceipt as getTransactionReceipt$1, waitForTransactionReceipt as waitForTransactionReceipt$1, getTransaction, call } from 'viem/actions';
12
- import { Slot } from '@radix-ui/react-slot';
13
- import { cva } from 'class-variance-authority';
6
+ import { useAccount, useWalletClient, useConfig, useWriteContract, useSendTransaction, useChainId, useSwitchChain, useBalance as useBalance$1, useReadContract } from 'wagmi';
7
+ import { zeroAddress, erc20Abi } from 'viem';
14
8
  import * as DialogPrimitive from '@radix-ui/react-dialog';
15
9
  import { XIcon } from 'lucide-react';
10
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
16
11
  import { toast } from 'sonner';
17
12
 
18
- // ../../shared/config.json
19
- var config_default = {
20
- chains: [
21
- {
22
- id: 84532,
23
- name: "Base Sepolia",
24
- explorerUrl: "https://sepolia.basescan.org"
25
- }
26
- ],
27
- networks: {
28
- testnet: {
29
- chainId: 23295,
30
- name: "Sapphire Testnet",
31
- accountingContract: "0xaF8e5de153A584528B57DD4B9B0195956BBDF571",
32
- apiUrl: "https://testnet.privana.finance"
33
- },
34
- mainnet: {
35
- chainId: 23294,
36
- name: "Sapphire Mainnet",
37
- accountingContract: "0x0000000000000000000000000000000000000000",
38
- apiUrl: ""
39
- }
40
- }
41
- };
42
-
43
- // src/sdk/types/common.ts
44
- var NETWORK_CONFIG = {
45
- testnet: {
46
- ...config_default.networks.testnet,
47
- accountingContract: config_default.networks.testnet.accountingContract
48
- },
49
- mainnet: {
50
- ...config_default.networks.mainnet,
51
- accountingContract: config_default.networks.mainnet.accountingContract
52
- }
53
- };
54
- function getChainId(network) {
55
- return NETWORK_CONFIG[network].chainId;
56
- }
57
- function getAccountingContract(network) {
58
- return NETWORK_CONFIG[network].accountingContract;
59
- }
60
- function getApiUrl(network) {
61
- return NETWORK_CONFIG[network].apiUrl;
62
- }
63
- function normalizeHex(value) {
64
- const normalized = value.trim().toLowerCase();
65
- return normalized.startsWith("0x") ? normalized : `0x${normalized}`;
66
- }
67
- function normalizeAddress(value) {
68
- return normalizeHex(value);
69
- }
70
-
71
- // src/sdk/types/chains.ts
72
- var SUPPORTED_CHAINS = config_default.chains.map((chain) => ({
73
- id: chain.id,
74
- name: chain.name,
75
- explorerUrl: chain.explorerUrl
76
- }));
77
- function getChainById(chainId) {
78
- return SUPPORTED_CHAINS.find((c) => c.id === chainId);
79
- }
80
- function getExplorerAddressUrl(chainId, address) {
81
- const chain = getChainById(chainId);
82
- if (!chain) return void 0;
83
- return `${chain.explorerUrl}/address/${address}#tokentxns`;
84
- }
85
-
86
- // src/sdk/auth/hosted-auth.ts
87
- var HOSTED_AUTH_CLOCK_SKEW_MS = 3e4;
88
- var PKCE_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
89
- var DEFAULT_RANDOM_LENGTH = 64;
90
- var HOSTED_AUTH_CALLBACK_QUERY_KEYS = ["code", "error", "error_description", "state"];
91
- function randomString(length) {
92
- const values = new Uint8Array(length);
93
- crypto.getRandomValues(values);
94
- let output = "";
95
- for (const value of values) {
96
- output += PKCE_CHARSET[value % PKCE_CHARSET.length];
97
- }
98
- return output;
99
- }
100
- function toBase64Url(bytes) {
101
- let binary = "";
102
- bytes.forEach((byte) => {
103
- binary += String.fromCharCode(byte);
104
- });
105
- return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
106
- }
107
- function createPkceVerifier(length = DEFAULT_RANDOM_LENGTH) {
108
- return randomString(length);
109
- }
110
- async function createPkceChallenge(verifier) {
111
- const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier));
112
- return toBase64Url(new Uint8Array(digest));
113
- }
114
- function createHostedAuthState(length = DEFAULT_RANDOM_LENGTH) {
115
- return randomString(length);
116
- }
117
- function createHostedAuthStorageKey(apiUrl, config) {
118
- const normalizedApiUrl = apiUrl.replace(/\/$/, "");
119
- return [
120
- "privana",
121
- "hosted-auth",
122
- normalizedApiUrl,
123
- config.clientId.trim(),
124
- config.redirectUri.trim()
125
- ].join(":");
126
- }
127
- function createHostedAuthPendingStorageKey(apiUrl, config) {
128
- return `${createHostedAuthStorageKey(apiUrl, config)}:pending`;
129
- }
130
- function persistHostedAuthPendingTransaction(storage, key, transaction) {
131
- storage.setItem(key, JSON.stringify(transaction));
132
- }
133
- function readHostedAuthPendingTransaction(storage, key) {
134
- const raw = storage.getItem(key);
135
- if (!raw) return null;
136
- try {
137
- const parsed = JSON.parse(raw);
138
- if (typeof parsed.codeVerifier !== "string" || typeof parsed.state !== "string") {
139
- return null;
140
- }
141
- return {
142
- codeVerifier: parsed.codeVerifier,
143
- state: parsed.state
144
- };
145
- } catch {
146
- return null;
147
- }
148
- }
149
- function clearHostedAuthPendingTransaction(storage, key) {
150
- storage.removeItem(key);
151
- }
152
- function parseHostedAuthCallback(url, redirectUri) {
153
- const expectedUrl = new URL(redirectUri);
154
- if (url.origin !== expectedUrl.origin || url.pathname !== expectedUrl.pathname) {
155
- return null;
156
- }
157
- const code = url.searchParams.get("code");
158
- if (code) {
159
- return {
160
- code,
161
- state: url.searchParams.get("state")
162
- };
163
- }
164
- const error = url.searchParams.get("error");
165
- if (error) {
166
- return {
167
- error,
168
- errorDescription: url.searchParams.get("error_description") ?? void 0,
169
- state: url.searchParams.get("state")
170
- };
171
- }
172
- return null;
173
- }
174
- function stripHostedAuthCallbackParams(url) {
175
- const nextUrl = new URL(url.toString());
176
- HOSTED_AUTH_CALLBACK_QUERY_KEYS.forEach((key) => {
177
- nextUrl.searchParams.delete(key);
178
- });
179
- return `${nextUrl.pathname}${nextUrl.search}${nextUrl.hash}`;
180
- }
181
- function buildHostedAuthSession(response, config, now = Date.now()) {
182
- return {
183
- accessToken: response.access_token,
184
- refreshToken: response.refresh_token,
185
- idToken: response.id_token,
186
- tokenType: response.token_type,
187
- address: response.address,
188
- clientId: config.clientId,
189
- redirectUri: config.redirectUri,
190
- expiresAt: now + response.expires_in * 1e3,
191
- refreshExpiresAt: now + response.refresh_expires_in * 1e3
192
- };
193
- }
194
- function applyRefreshResponse(session, response, now = Date.now()) {
195
- return {
196
- ...session,
197
- accessToken: response.token,
198
- refreshToken: response.refresh_token,
199
- expiresAt: now + response.expires_in * 1e3,
200
- refreshExpiresAt: now + response.refresh_expires_in * 1e3
201
- };
202
- }
203
- function isHostedAuthSessionActive(session, now = Date.now(), skewMs = HOSTED_AUTH_CLOCK_SKEW_MS) {
204
- return session.expiresAt > now + skewMs;
205
- }
206
- function isHostedAuthRefreshActive(session, now = Date.now(), skewMs = HOSTED_AUTH_CLOCK_SKEW_MS) {
207
- return session.refreshExpiresAt > now + skewMs;
208
- }
209
-
210
- // src/sdk/client/errors.ts
211
- var AccountingApiError = class _AccountingApiError extends Error {
212
- constructor(message, statusCode, detail) {
213
- super(message);
214
- this.statusCode = statusCode;
215
- this.detail = detail;
216
- this.name = "AccountingApiError";
217
- Object.setPrototypeOf(this, _AccountingApiError.prototype);
218
- }
219
- };
220
- var NetworkError = class _NetworkError extends Error {
221
- constructor(message, cause) {
222
- super(message);
223
- this.cause = cause;
224
- this.name = "NetworkError";
225
- Object.setPrototypeOf(this, _NetworkError.prototype);
226
- }
227
- };
228
- var ValidationError = class _ValidationError extends Error {
229
- constructor(message, field) {
230
- super(message);
231
- this.field = field;
232
- this.name = "ValidationError";
233
- Object.setPrototypeOf(this, _ValidationError.prototype);
234
- }
235
- };
236
- var HostedAuthError = class _HostedAuthError extends Error {
237
- constructor(message) {
238
- super(message);
239
- this.name = "HostedAuthError";
240
- Object.setPrototypeOf(this, _HostedAuthError.prototype);
241
- }
242
- };
243
- var HostedAuthRequiredError = class _HostedAuthRequiredError extends HostedAuthError {
244
- constructor(message = "Hosted redirect authentication is required. Start login with useHostedRedirectAuth().") {
245
- super(message);
246
- this.name = "HostedAuthRequiredError";
247
- Object.setPrototypeOf(this, _HostedAuthRequiredError.prototype);
248
- }
249
- };
250
- var HostedAuthStateMismatchError = class _HostedAuthStateMismatchError extends HostedAuthError {
251
- constructor(message = "Hosted authentication returned an invalid state value.") {
252
- super(message);
253
- this.name = "HostedAuthStateMismatchError";
254
- Object.setPrototypeOf(this, _HostedAuthStateMismatchError.prototype);
255
- }
256
- };
257
-
258
- // src/sdk/client/http-client.ts
259
- var HttpClient = class {
260
- constructor(config) {
261
- this.baseUrl = config.baseUrl.replace(/\/$/, "");
262
- this.timeout = config.timeout ?? 3e4;
263
- this.headers = {
264
- "Content-Type": "application/json",
265
- ...config.headers
266
- };
267
- }
268
- async get(path) {
269
- return this.request("GET", path);
270
- }
271
- async post(path, body) {
272
- return this.request("POST", path, body);
273
- }
274
- getBaseUrl() {
275
- return this.baseUrl;
276
- }
277
- setHeader(name, value) {
278
- this.headers[name] = value;
279
- }
280
- removeHeader(name) {
281
- delete this.headers[name];
282
- }
283
- getHeader(name) {
284
- return this.headers[name];
285
- }
286
- async request(method, path, body) {
287
- const url = `${this.baseUrl}${path}`;
288
- const controller = new AbortController();
289
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
290
- try {
291
- const response = await fetch(url, {
292
- method,
293
- headers: this.headers,
294
- body: body ? JSON.stringify(body) : void 0,
295
- signal: controller.signal
296
- });
297
- clearTimeout(timeoutId);
298
- if (!response.ok) {
299
- let detail;
300
- try {
301
- const errorBody = await response.json();
302
- detail = errorBody.detail || errorBody.error_description || errorBody.message;
303
- } catch {
304
- detail = await response.text().catch(() => void 0);
305
- }
306
- throw new AccountingApiError(
307
- `API request failed: ${response.status} ${response.statusText}`,
308
- response.status,
309
- detail
310
- );
311
- }
312
- return response.json();
313
- } catch (error) {
314
- clearTimeout(timeoutId);
315
- if (error instanceof AccountingApiError) {
316
- throw error;
317
- }
318
- if (error instanceof Error) {
319
- if (error.name === "AbortError") {
320
- throw new NetworkError(`Request timeout after ${this.timeout}ms`);
321
- }
322
- throw new NetworkError(`Network request failed: ${error.message}`, error);
323
- }
324
- throw new NetworkError("Unknown network error occurred");
325
- }
326
- }
327
- };
328
-
329
- // src/sdk/client/privana-client.ts
330
- var PRIVATE_READ_TOKEN_HEADER = "X-SIWE-Token";
331
- var MAX_BATCH_BALANCE_TOKEN_IDS = 100;
332
- var MAX_HISTORY_PAGE_SIZE = 100;
333
- var PrivanaClient = class {
334
- constructor(config) {
335
- this.http = new HttpClient(config);
336
- }
337
- getBaseUrl() {
338
- return this.http.getBaseUrl();
339
- }
340
- async getDepositAddress(request = {}) {
341
- return this.http.post("/v1/accounting/deposits/address", {
342
- chain_type: request.chain_type ?? "evm",
343
- version: request.version ?? 0
344
- });
345
- }
346
- async checkDeposit(request) {
347
- return this.http.post("/v1/accounting/deposits/check", {
348
- chain_type: request.chain_type ?? "evm",
349
- chain_id: request.chain_id,
350
- tx_hash: normalizeHex(request.tx_hash),
351
- amount: String(request.amount),
352
- log_index: request.log_index ?? 0,
353
- version: request.version ?? 0
354
- });
355
- }
356
- async getDepositStatus(depositId) {
357
- return this.http.get(`/v1/accounting/deposits/status/${depositId}`);
358
- }
359
- async getBalance(tokenId) {
360
- const token = normalizeHex(tokenId);
361
- return this.http.get(`/v1/accounting/balances/${token}`);
362
- }
363
- async getBatchBalances(request) {
364
- if (request.token_ids.length > MAX_BATCH_BALANCE_TOKEN_IDS) {
365
- throw new Error(
366
- `Batch balance requests support at most ${MAX_BATCH_BALANCE_TOKEN_IDS} token IDs`
367
- );
368
- }
369
- return this.http.post("/v1/accounting/balances/batch", {
370
- token_ids: request.token_ids.map((id) => normalizeHex(id))
371
- });
372
- }
373
- async getHistory(request = {}) {
374
- const offset = request.offset ?? -1;
375
- const limit = request.limit ?? 50;
376
- if (!Number.isSafeInteger(offset)) {
377
- throw new Error("History offset must be an integer");
378
- }
379
- if (!Number.isSafeInteger(limit)) {
380
- throw new Error("History limit must be an integer");
381
- }
382
- if (limit < 0 || limit > MAX_HISTORY_PAGE_SIZE) {
383
- throw new Error(`History requests support between 0 and ${MAX_HISTORY_PAGE_SIZE} entries`);
384
- }
385
- const params = new URLSearchParams({
386
- offset: String(offset),
387
- limit: String(limit)
388
- });
389
- return this.http.get(`/v1/accounting/history?${params.toString()}`);
390
- }
391
- async listTokens() {
392
- return this.http.get("/v1/accounting/tokens");
393
- }
394
- async getTokenInfo(tokenId) {
395
- const token = normalizeHex(tokenId);
396
- return this.http.get(`/v1/accounting/tokens/${token}`);
397
- }
398
- async lockFunds(request) {
399
- return this.http.post("/v1/accounting/funds/lock", {
400
- service_address: normalizeAddress(request.service_address),
401
- token_id: normalizeHex(request.token_id),
402
- amount: String(request.amount),
403
- expiry: String(request.expiry),
404
- nonce: String(request.nonce),
405
- signature: normalizeHex(request.signature)
406
- });
407
- }
408
- async modifyLock(request) {
409
- return this.http.post("/v1/accounting/funds/modify-lock", {
410
- lock_id: request.lock_id,
411
- amount: String(request.amount),
412
- new_expiry: String(request.new_expiry),
413
- nonce: String(request.nonce),
414
- signature: normalizeHex(request.signature)
415
- });
416
- }
417
- async unlockFunds(request) {
418
- return this.http.post("/v1/accounting/funds/unlock", {
419
- user_address: normalizeAddress(request.user_address),
420
- lock_id: request.lock_id
421
- });
422
- }
423
- async unlockAllExpired(request) {
424
- return this.http.post(
425
- "/v1/accounting/funds/unlock-all-expired",
426
- {
427
- user_address: normalizeAddress(request.user_address)
428
- }
429
- );
430
- }
431
- async getLockedFunds(serviceAddress) {
432
- const queryParams = serviceAddress ? `?service_address=${normalizeAddress(serviceAddress)}` : "";
433
- return this.http.get(`/v1/accounting/funds/locked${queryParams}`);
434
- }
435
- async getTotalLockedBalance(tokenId) {
436
- const token = normalizeHex(tokenId);
437
- return this.http.get(`/v1/accounting/funds/locked/total/${token}`);
438
- }
439
- async getExpiredLocks() {
440
- return this.http.get("/v1/accounting/funds/expired");
441
- }
442
- async transferFunds(request) {
443
- return this.http.post("/v1/accounting/funds/transfer", {
444
- to_address: normalizeAddress(request.to_address),
445
- token_id: normalizeHex(request.token_id),
446
- amount: String(request.amount),
447
- nonce: String(request.nonce),
448
- signature: normalizeHex(request.signature)
449
- });
450
- }
451
- async getTransferNonce(userAddress) {
452
- const user = normalizeAddress(userAddress);
453
- return this.http.get(`/v1/accounting/funds/transfer/nonce/${user}`);
454
- }
455
- async getLockNonce(userAddress) {
456
- const user = normalizeAddress(userAddress);
457
- return this.http.get(`/v1/accounting/funds/lock/nonce/${user}`);
458
- }
459
- async getModifyLockNonce(userAddress) {
460
- const user = normalizeAddress(userAddress);
461
- return this.http.get(`/v1/accounting/funds/modify-lock/nonce/${user}`);
462
- }
463
- async transferLockedFunds(request) {
464
- return this.http.post("/v1/accounting/funds/transfer-locked", {
465
- user_address: normalizeAddress(request.user_address),
466
- lock_id: request.lock_id,
467
- to_address: normalizeAddress(request.to_address),
468
- amount: String(request.amount),
469
- service_address: normalizeAddress(request.service_address),
470
- nonce: String(request.nonce),
471
- signature: normalizeHex(request.signature)
472
- });
473
- }
474
- async withdrawFromLock(request) {
475
- return this.http.post(
476
- "/v1/accounting/funds/withdraw-from-lock",
477
- {
478
- to_address: normalizeAddress(request.to_address),
479
- lock_id: request.lock_id,
480
- amount: String(request.amount),
481
- nonce: String(request.nonce),
482
- signature: normalizeHex(request.signature)
483
- }
484
- );
485
- }
486
- async requestWithdrawal(request) {
487
- return this.http.post("/v1/accounting/withdraw", {
488
- token_id: normalizeHex(request.token_id),
489
- amount: String(request.amount),
490
- nonce: String(request.nonce),
491
- signature: normalizeHex(request.signature)
492
- });
493
- }
494
- async getWithdrawalNonce(userAddress) {
495
- const user = normalizeAddress(userAddress);
496
- return this.http.get(`/v1/accounting/withdraw/nonce/${user}`);
497
- }
498
- async getTransferLockedNonce(serviceAddress) {
499
- const service = normalizeAddress(serviceAddress);
500
- return this.http.get(
501
- `/v1/accounting/funds/transfer-locked/nonce/${service}`
502
- );
503
- }
504
- async getPendingWithdrawals(userAddress) {
505
- const user = normalizeAddress(userAddress);
506
- return this.http.get(`/v1/accounting/withdraw/pending/${user}`);
507
- }
508
- async getWithdrawalInfo(index) {
509
- return this.http.get(`/v1/accounting/withdraw/${index}`);
510
- }
511
- async getSiweDomain() {
512
- return this.http.get("/v1/accounting/auth/domain");
513
- }
514
- async getSiweNonce(userAddress) {
515
- const user = normalizeAddress(userAddress);
516
- return this.http.get(`/v1/accounting/auth/nonce?address=${user}`);
517
- }
518
- async loginWithSiwe(request) {
519
- return this.http.post("/v1/accounting/auth/login", {
520
- siwe_message: request.siwe_message,
521
- signature: normalizeHex(request.signature)
522
- });
523
- }
524
- getHostedAuthAuthorizeUrl(request) {
525
- const url = new URL(
526
- "v1/accounting/auth/authorize",
527
- `${this.http.getBaseUrl().replace(/\/$/, "")}/`
528
- );
529
- url.searchParams.set("client_id", request.client_id);
530
- url.searchParams.set("redirect_uri", request.redirect_uri);
531
- url.searchParams.set("code_challenge", request.code_challenge);
532
- url.searchParams.set("state", request.state);
533
- url.searchParams.set("chain_id", String(request.chain_id));
534
- url.searchParams.set("response_mode", request.response_mode ?? "redirect");
535
- url.searchParams.set("code_challenge_method", request.code_challenge_method ?? "S256");
536
- return url.toString();
537
- }
538
- async exchangeHostedAuthCode(request) {
539
- return this.http.post("/v1/accounting/auth/token", {
540
- grant_type: request.grant_type ?? "authorization_code",
541
- code: request.code,
542
- code_verifier: request.code_verifier,
543
- client_id: request.client_id,
544
- redirect_uri: request.redirect_uri
545
- });
546
- }
547
- async refreshJwtSession(request) {
548
- return this.http.post("/v1/accounting/auth/jwt/refresh", {
549
- refresh_token: request.refresh_token
550
- });
551
- }
552
- async logoutJwtSession(request = {}) {
553
- return this.http.post("/v1/accounting/auth/jwt/logout", {
554
- refresh_token: request.refresh_token,
555
- revoke_all: request.revoke_all ?? false
556
- });
557
- }
558
- setPrivateReadToken(token) {
559
- this.http.removeHeader("Authorization");
560
- this.http.setHeader(PRIVATE_READ_TOKEN_HEADER, token);
561
- }
562
- getPrivateReadToken() {
563
- return this.http.getHeader(PRIVATE_READ_TOKEN_HEADER);
564
- }
565
- clearPrivateReadToken() {
566
- this.http.removeHeader(PRIVATE_READ_TOKEN_HEADER);
567
- }
568
- setBearerToken(token) {
569
- this.http.removeHeader(PRIVATE_READ_TOKEN_HEADER);
570
- this.http.setHeader("Authorization", `Bearer ${token}`);
571
- }
572
- clearBearerToken() {
573
- this.http.removeHeader("Authorization");
574
- }
575
- };
576
-
577
13
  // src/sdk/signatures/eip712-types.ts
578
14
  function createDomain(chainId, verifyingContract) {
579
15
  return {
@@ -769,294 +205,6 @@ async function signWithdrawFromLockMessage({
769
205
  });
770
206
  return signature;
771
207
  }
772
- var PrivanaContext = createContext(null);
773
- function readStoredHostedAuthSession(storage, hostedAuthStorageKey, now = Date.now()) {
774
- const raw = storage.getItem(hostedAuthStorageKey);
775
- if (!raw) {
776
- return null;
777
- }
778
- try {
779
- const parsed = JSON.parse(raw);
780
- if (!isHostedAuthRefreshActive(parsed, now, 0)) {
781
- storage.removeItem(hostedAuthStorageKey);
782
- return null;
783
- }
784
- return parsed;
785
- } catch {
786
- storage.removeItem(hostedAuthStorageKey);
787
- return null;
788
- }
789
- }
790
- function syncHostedAuthSessionToClient(client, hostedAuthConfig, hostedAuthSession) {
791
- if (!hostedAuthConfig) {
792
- client.clearBearerToken();
793
- client.clearPrivateReadToken();
794
- return;
795
- }
796
- if (hostedAuthSession && isHostedAuthSessionActive(hostedAuthSession)) {
797
- client.setBearerToken(hostedAuthSession.accessToken);
798
- client.clearPrivateReadToken();
799
- return;
800
- }
801
- client.clearBearerToken();
802
- client.clearPrivateReadToken();
803
- }
804
- var DEFAULT_NETWORK_CONFIG = NETWORK_CONFIG.testnet;
805
- function PrivanaProvider({
806
- children,
807
- networkConfig: networkConfigOverride,
808
- tokens,
809
- chains,
810
- pollingInterval = 1e4,
811
- serviceAddress,
812
- hostedAuth
813
- }) {
814
- const networkConfig = useMemo(() => {
815
- const config = {
816
- ...DEFAULT_NETWORK_CONFIG,
817
- ...networkConfigOverride
818
- };
819
- if (!config.chainId || config.chainId <= 0) {
820
- throw new Error("PrivanaProvider: networkConfig.chainId must be a positive number");
821
- }
822
- if (!config.accountingContract || !config.accountingContract.startsWith("0x")) {
823
- throw new Error("PrivanaProvider: networkConfig.accountingContract must be a valid address");
824
- }
825
- if (!config.apiUrl) {
826
- throw new Error("PrivanaProvider: networkConfig.apiUrl must be provided");
827
- }
828
- return config;
829
- }, [
830
- networkConfigOverride?.chainId,
831
- networkConfigOverride?.name,
832
- networkConfigOverride?.accountingContract,
833
- networkConfigOverride?.apiUrl
834
- ]);
835
- const resolvedChains = useMemo(() => {
836
- if (chains && chains.length > 0) return chains;
837
- return SUPPORTED_CHAINS;
838
- }, [chains]);
839
- const client = useMemo(
840
- () => new PrivanaClient({ baseUrl: networkConfig.apiUrl }),
841
- [networkConfig.apiUrl]
842
- );
843
- const [allTokens, setAllTokens] = useState([]);
844
- const [tokensStatus, setTokensStatus] = useState("loading");
845
- const [tokensError, setTokensError] = useState();
846
- useEffect(() => {
847
- setTokensStatus("loading");
848
- setTokensError(void 0);
849
- client.listTokens().then(({ tokens: list }) => {
850
- setAllTokens(
851
- list.map((t) => ({
852
- id: t.token_id,
853
- symbol: t.symbol,
854
- decimals: t.decimals,
855
- contract: t.token_address ?? zeroAddress,
856
- name: t.name,
857
- chainId: t.chain_id
858
- }))
859
- );
860
- setTokensStatus("ready");
861
- }).catch((err) => {
862
- setTokensError(err instanceof Error ? err : new Error(String(err)));
863
- setTokensStatus("error");
864
- });
865
- }, [client]);
866
- const enabledTokens = useMemo(() => {
867
- if (tokens && tokens.length > 0) {
868
- const allowed = new Set(tokens.map((id) => id.toLowerCase()));
869
- return allTokens.filter((t) => allowed.has(t.id.toLowerCase()));
870
- }
871
- return allTokens;
872
- }, [allTokens, tokens]);
873
- const tokenById = useMemo(
874
- () => Object.fromEntries(enabledTokens.map((t) => [t.id.toLowerCase(), t])),
875
- [enabledTokens]
876
- );
877
- const getTokenById = useMemo(() => (id) => tokenById[id.toLowerCase()], [tokenById]);
878
- const chainById = useMemo(
879
- () => Object.fromEntries(resolvedChains.map((c) => [c.id, c])),
880
- [resolvedChains]
881
- );
882
- const getChainById2 = useMemo(() => (id) => chainById[id], [chainById]);
883
- const hostedAuthConfig = useMemo(() => {
884
- if (!hostedAuth) return null;
885
- const clientId = hostedAuth.clientId.trim();
886
- const redirectUri = hostedAuth.redirectUri.trim();
887
- if (!clientId) {
888
- throw new Error(
889
- "PrivanaProvider: hostedAuth.clientId must be provided when hostedAuth is enabled"
890
- );
891
- }
892
- if (!redirectUri) {
893
- throw new Error(
894
- "PrivanaProvider: hostedAuth.redirectUri must be provided when hostedAuth is enabled"
895
- );
896
- }
897
- return {
898
- clientId,
899
- redirectUri
900
- };
901
- }, [hostedAuth]);
902
- const hostedAuthStorageKey = useMemo(
903
- () => hostedAuthConfig ? createHostedAuthStorageKey(networkConfig.apiUrl, hostedAuthConfig) : null,
904
- [hostedAuthConfig, networkConfig.apiUrl]
905
- );
906
- const [hostedAuthSession, setHostedAuthSessionState] = useState(null);
907
- const hostedAuthSessionRef = useRef(null);
908
- const hostedAuthStateVersionRef = useRef(0);
909
- const hostedAuthRefreshInflight = useRef(null);
910
- const clearHostedAuthSession = useCallback(() => {
911
- hostedAuthStateVersionRef.current += 1;
912
- hostedAuthSessionRef.current = null;
913
- hostedAuthRefreshInflight.current = null;
914
- setHostedAuthSessionState(null);
915
- client.clearBearerToken();
916
- client.clearPrivateReadToken();
917
- if (hostedAuthStorageKey && typeof window !== "undefined") {
918
- window.sessionStorage.removeItem(hostedAuthStorageKey);
919
- }
920
- }, [client, hostedAuthStorageKey]);
921
- const setHostedAuthSession = useCallback(
922
- (session) => {
923
- if (!session) {
924
- clearHostedAuthSession();
925
- return;
926
- }
927
- hostedAuthStateVersionRef.current += 1;
928
- hostedAuthSessionRef.current = session;
929
- setHostedAuthSessionState(session);
930
- if (isHostedAuthSessionActive(session)) {
931
- client.setBearerToken(session.accessToken);
932
- } else {
933
- client.clearBearerToken();
934
- }
935
- client.clearPrivateReadToken();
936
- if (hostedAuthStorageKey && typeof window !== "undefined") {
937
- window.sessionStorage.setItem(hostedAuthStorageKey, JSON.stringify(session));
938
- }
939
- },
940
- [clearHostedAuthSession, client, hostedAuthStorageKey]
941
- );
942
- const refreshHostedAuthSession = useCallback(async () => {
943
- if (!hostedAuthConfig) {
944
- throw new HostedAuthRequiredError(
945
- "Hosted redirect authentication is not configured for this provider."
946
- );
947
- }
948
- const currentSession = hostedAuthSessionRef.current;
949
- if (!currentSession) {
950
- throw new HostedAuthRequiredError();
951
- }
952
- if (!isHostedAuthRefreshActive(currentSession)) {
953
- clearHostedAuthSession();
954
- throw new HostedAuthRequiredError(
955
- "Hosted redirect authentication has expired. Start login again."
956
- );
957
- }
958
- if (hostedAuthRefreshInflight.current) {
959
- return hostedAuthRefreshInflight.current;
960
- }
961
- const refreshPromise = (async () => {
962
- const refreshVersion = hostedAuthStateVersionRef.current;
963
- try {
964
- const response = await client.refreshJwtSession({
965
- refresh_token: currentSession.refreshToken
966
- });
967
- if (refreshVersion !== hostedAuthStateVersionRef.current) {
968
- const latestSession = hostedAuthSessionRef.current;
969
- if (latestSession) {
970
- return latestSession;
971
- }
972
- throw new HostedAuthRequiredError(
973
- "Hosted redirect authentication has changed. Start login again."
974
- );
975
- }
976
- const nextSession = applyRefreshResponse(currentSession, response);
977
- setHostedAuthSession(nextSession);
978
- return nextSession;
979
- } catch (error) {
980
- if (refreshVersion === hostedAuthStateVersionRef.current) {
981
- clearHostedAuthSession();
982
- }
983
- throw error;
984
- } finally {
985
- hostedAuthRefreshInflight.current = null;
986
- }
987
- })();
988
- hostedAuthRefreshInflight.current = refreshPromise;
989
- return refreshPromise;
990
- }, [clearHostedAuthSession, client, hostedAuthConfig, setHostedAuthSession]);
991
- useEffect(() => {
992
- hostedAuthSessionRef.current = hostedAuthSession;
993
- }, [hostedAuthSession]);
994
- useEffect(() => {
995
- if (!hostedAuthStorageKey || typeof window === "undefined") {
996
- hostedAuthStateVersionRef.current += 1;
997
- hostedAuthSessionRef.current = null;
998
- hostedAuthRefreshInflight.current = null;
999
- setHostedAuthSessionState(null);
1000
- return;
1001
- }
1002
- const restoredSession = readStoredHostedAuthSession(window.sessionStorage, hostedAuthStorageKey);
1003
- hostedAuthStateVersionRef.current += 1;
1004
- hostedAuthSessionRef.current = restoredSession;
1005
- hostedAuthRefreshInflight.current = null;
1006
- setHostedAuthSessionState(restoredSession);
1007
- }, [hostedAuthStorageKey]);
1008
- useEffect(() => {
1009
- syncHostedAuthSessionToClient(client, hostedAuthConfig, hostedAuthSession);
1010
- }, [client, hostedAuthConfig, hostedAuthSession]);
1011
- const value = useMemo(
1012
- () => ({
1013
- client,
1014
- networkConfig,
1015
- enabledTokens,
1016
- defaultToken: enabledTokens[0],
1017
- getTokenById,
1018
- getChainById: getChainById2,
1019
- chains: resolvedChains,
1020
- tokensStatus,
1021
- tokensError,
1022
- pollingInterval,
1023
- serviceAddress,
1024
- hostedAuthConfig,
1025
- hostedAuthSession,
1026
- setHostedAuthSession,
1027
- clearHostedAuthSession,
1028
- refreshHostedAuthSession
1029
- }),
1030
- [
1031
- client,
1032
- networkConfig,
1033
- enabledTokens,
1034
- getTokenById,
1035
- getChainById2,
1036
- resolvedChains,
1037
- tokensStatus,
1038
- tokensError,
1039
- pollingInterval,
1040
- serviceAddress,
1041
- hostedAuthConfig,
1042
- hostedAuthSession,
1043
- setHostedAuthSession,
1044
- clearHostedAuthSession,
1045
- refreshHostedAuthSession
1046
- ]
1047
- );
1048
- return /* @__PURE__ */ jsx(PrivanaContext.Provider, { value, children });
1049
- }
1050
- function usePrivanaContext() {
1051
- const context = useContext(PrivanaContext);
1052
- if (!context) {
1053
- throw new Error("usePrivanaContext must be used within a PrivanaProvider");
1054
- }
1055
- return context;
1056
- }
1057
- function useSafePrivanaContext() {
1058
- return useContext(PrivanaContext);
1059
- }
1060
208
 
1061
209
  // src/sdk/hooks/use-privana-client.ts
1062
210
  function usePrivanaClient() {
@@ -1265,280 +413,6 @@ function useHostedRedirectAuth() {
1265
413
  refresh
1266
414
  };
1267
415
  }
1268
- function cn(...inputs) {
1269
- return twMerge(clsx(inputs));
1270
- }
1271
- function formatTokenAmount(amount, decimals = 18) {
1272
- const value = typeof amount === "string" ? BigInt(amount) : amount;
1273
- const divisor = BigInt(10 ** decimals);
1274
- const integerPart = value / divisor;
1275
- const fractionalPart = value % divisor;
1276
- const fractionalStr = fractionalPart.toString().padStart(decimals, "0");
1277
- const twoDecimals = fractionalStr.slice(0, 2).padEnd(2, "0");
1278
- const integerWithSpaces = integerPart.toString().replace(/\B(?=(\d{3})+(?!\d))/g, "\u2009");
1279
- return `${integerWithSpaces}.${twoDecimals}`;
1280
- }
1281
- function parseTokenAmount(amount, decimals = 18) {
1282
- const sanitized = amount.replace(/[\s\u2009]/g, "").replace(/,/g, ".");
1283
- const lastDot = sanitized.lastIndexOf(".");
1284
- const integerPart = lastDot === -1 ? sanitized : sanitized.slice(0, lastDot).replace(/\./g, "");
1285
- const fractionalPart = lastDot === -1 ? "" : sanitized.slice(lastDot + 1);
1286
- const paddedFractional = fractionalPart.padEnd(decimals, "0").slice(0, decimals);
1287
- return BigInt(integerPart + paddedFractional);
1288
- }
1289
- function shortenAddress(address, chars = 4) {
1290
- if (!address || address.length < chars * 2 + 2) return address;
1291
- return `${address.slice(0, chars + 2)}...${address.slice(-chars)}`;
1292
- }
1293
- function formatTimeRemaining(expiryTimestamp) {
1294
- const now = Math.floor(Date.now() / 1e3);
1295
- const diff = expiryTimestamp - now;
1296
- if (diff <= 0) return "Expired";
1297
- const days = Math.floor(diff / 86400);
1298
- const hours = Math.floor(diff % 86400 / 3600);
1299
- const minutes = Math.floor(diff % 3600 / 60);
1300
- if (days > 0) {
1301
- return hours > 0 ? `${days}d ${hours}h left` : `${days}d left`;
1302
- }
1303
- if (hours > 0) {
1304
- return minutes > 0 ? `${hours}h ${minutes}m left` : `${hours}h left`;
1305
- }
1306
- return `${minutes}m left`;
1307
- }
1308
- var defaultResult = {
1309
- address: void 0,
1310
- isConnected: false
1311
- };
1312
- function useSafeAccount() {
1313
- const context = useContext(WagmiContext);
1314
- const cacheRef = useRef(defaultResult);
1315
- const subscribe = useCallback(
1316
- (onChange) => {
1317
- if (!context) return () => {
1318
- };
1319
- return watchAccount(context, { onChange });
1320
- },
1321
- [context]
1322
- );
1323
- const getSnapshot = useCallback(() => {
1324
- if (!context) return defaultResult;
1325
- const account = getAccount(context);
1326
- if (cacheRef.current.address !== account.address || cacheRef.current.isConnected !== account.isConnected) {
1327
- cacheRef.current = { address: account.address, isConnected: account.isConnected };
1328
- }
1329
- return cacheRef.current;
1330
- }, [context]);
1331
- const getServerSnapshot = useCallback(() => defaultResult, []);
1332
- return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
1333
- }
1334
-
1335
- // src/sdk/hooks/use-private-read-request.ts
1336
- var AUTH_CLOCK_SKEW_MS = 3e4;
1337
- var INITIAL_AUTH_BACKOFF_MS = 5e3;
1338
- var MAX_AUTH_BACKOFF_MS = 6e4;
1339
- var DEFAULT_SIWE_AUTH_VALIDITY_MS = 24 * 60 * 60 * 1e3;
1340
- var PRIVATE_READ_STATEMENT = "Sign in to Privana to access private account data.";
1341
- var privateReadTokenCache = /* @__PURE__ */ new Map();
1342
- var privateReadFailureCache = /* @__PURE__ */ new Map();
1343
- var privateReadInflight = /* @__PURE__ */ new Map();
1344
- async function executeHostedAuthPrivateReadRequest({
1345
- client,
1346
- hostedAuthSession,
1347
- refreshHostedAuthSession,
1348
- request
1349
- }) {
1350
- const ensureHostedAuth = async (forceRefresh) => {
1351
- if (!hostedAuthSession) {
1352
- throw new HostedAuthRequiredError();
1353
- }
1354
- if (!forceRefresh && isHostedAuthSessionActive(hostedAuthSession)) {
1355
- client.clearPrivateReadToken();
1356
- client.setBearerToken(hostedAuthSession.accessToken);
1357
- return hostedAuthSession.accessToken;
1358
- }
1359
- const refreshed = await refreshHostedAuthSession();
1360
- client.clearPrivateReadToken();
1361
- client.setBearerToken(refreshed.accessToken);
1362
- return refreshed.accessToken;
1363
- };
1364
- await ensureHostedAuth(false);
1365
- try {
1366
- return await request();
1367
- } catch (error) {
1368
- if (!(error instanceof AccountingApiError) || error.statusCode !== 401) {
1369
- throw error;
1370
- }
1371
- await ensureHostedAuth(true);
1372
- return request();
1373
- }
1374
- }
1375
- function createScopeKey(apiUrl, deploymentChainId, address) {
1376
- return `${apiUrl.replace(/\/$/, "")}:${deploymentChainId}:${address.toLowerCase()}`;
1377
- }
1378
- function getCachedPrivateReadToken(scopeKey) {
1379
- const cached = privateReadTokenCache.get(scopeKey);
1380
- if (!cached) return null;
1381
- if (cached.expiresAt <= Date.now() + AUTH_CLOCK_SKEW_MS) {
1382
- privateReadTokenCache.delete(scopeKey);
1383
- return null;
1384
- }
1385
- return cached.token;
1386
- }
1387
- function clearPrivateReadScope(scopeKey, client) {
1388
- privateReadTokenCache.delete(scopeKey);
1389
- privateReadFailureCache.delete(scopeKey);
1390
- client.clearPrivateReadToken();
1391
- }
1392
- function recordPrivateReadFailure(scopeKey) {
1393
- const previous = privateReadFailureCache.get(scopeKey);
1394
- const backoffMs = Math.min(
1395
- previous ? previous.backoffMs * 2 : INITIAL_AUTH_BACKOFF_MS,
1396
- MAX_AUTH_BACKOFF_MS
1397
- );
1398
- privateReadFailureCache.set(scopeKey, {
1399
- backoffMs,
1400
- retryAt: Date.now() + backoffMs
1401
- });
1402
- }
1403
- function ensureFailureBackoff(scopeKey) {
1404
- const failure = privateReadFailureCache.get(scopeKey);
1405
- if (!failure) return;
1406
- if (failure.retryAt <= Date.now()) {
1407
- privateReadFailureCache.delete(scopeKey);
1408
- return;
1409
- }
1410
- throw new Error(
1411
- `Private-read authentication is temporarily paused after a recent failure. Retry in ${Math.ceil(
1412
- (failure.retryAt - Date.now()) / 1e3
1413
- )}s.`
1414
- );
1415
- }
1416
- function usePrivateReadRequest() {
1417
- const wagmiContext = useContext(WagmiContext);
1418
- const { client, networkConfig, hostedAuthConfig, hostedAuthSession, refreshHostedAuthSession } = usePrivanaContext();
1419
- const { address: walletAddress } = useSafeAccount();
1420
- const privateReadAddress = hostedAuthConfig ? hostedAuthSession?.address ?? null : walletAddress ?? null;
1421
- const privateReadReady = hostedAuthConfig ? !!hostedAuthSession : !!walletAddress;
1422
- const executePrivateRead = useCallback(
1423
- async (request) => {
1424
- if (hostedAuthConfig) {
1425
- return executeHostedAuthPrivateReadRequest({
1426
- client,
1427
- hostedAuthSession,
1428
- refreshHostedAuthSession,
1429
- request
1430
- });
1431
- }
1432
- if (!wagmiContext) {
1433
- throw new Error("WagmiProvider is required for authenticated private reads");
1434
- }
1435
- if (!walletAddress) {
1436
- throw new Error("No wallet connected");
1437
- }
1438
- const walletClient = await getWalletClient(wagmiContext);
1439
- if (!walletClient) {
1440
- throw new Error("No wallet client available");
1441
- }
1442
- const apiUrl = networkConfig.apiUrl;
1443
- const scopeKey = createScopeKey(apiUrl, networkConfig.chainId, walletAddress);
1444
- const getToken = async (forceRefresh) => {
1445
- const inflight = privateReadInflight.get(scopeKey);
1446
- if (inflight) {
1447
- const token = await inflight;
1448
- client.setPrivateReadToken(token);
1449
- return token;
1450
- }
1451
- if (!forceRefresh) {
1452
- const cached = getCachedPrivateReadToken(scopeKey);
1453
- if (cached) {
1454
- client.setPrivateReadToken(cached);
1455
- return cached;
1456
- }
1457
- }
1458
- ensureFailureBackoff(scopeKey);
1459
- const authPromise = (async () => {
1460
- try {
1461
- const [{ domain }, nonceResponse] = await Promise.all([
1462
- client.getSiweDomain(),
1463
- client.getSiweNonce(walletAddress)
1464
- ]);
1465
- const issuedAt = /* @__PURE__ */ new Date();
1466
- const expirationTime = new Date(issuedAt.getTime() + DEFAULT_SIWE_AUTH_VALIDITY_MS);
1467
- const uri = typeof window !== "undefined" && window.location.origin ? window.location.origin : apiUrl;
1468
- const message = createSiweMessage({
1469
- address: walletAddress,
1470
- chainId: walletClient.chain?.id ?? networkConfig.chainId,
1471
- domain,
1472
- expirationTime,
1473
- issuedAt,
1474
- nonce: nonceResponse.nonce,
1475
- statement: PRIVATE_READ_STATEMENT,
1476
- uri,
1477
- version: "1"
1478
- });
1479
- const signature = await walletClient.signMessage({
1480
- account: walletClient.account ?? walletAddress,
1481
- message
1482
- });
1483
- const login = await client.loginWithSiwe({
1484
- siwe_message: message,
1485
- signature
1486
- });
1487
- privateReadTokenCache.set(scopeKey, {
1488
- token: login.siwe_token,
1489
- expiresAt: expirationTime.getTime()
1490
- });
1491
- privateReadFailureCache.delete(scopeKey);
1492
- client.setPrivateReadToken(login.siwe_token);
1493
- return login.siwe_token;
1494
- } catch (error) {
1495
- const authError = error instanceof Error ? error : new Error("Failed to authenticate private reads");
1496
- clearPrivateReadScope(scopeKey, client);
1497
- recordPrivateReadFailure(scopeKey);
1498
- throw authError;
1499
- } finally {
1500
- privateReadInflight.delete(scopeKey);
1501
- }
1502
- })();
1503
- privateReadInflight.set(scopeKey, authPromise);
1504
- return authPromise;
1505
- };
1506
- await getToken(false);
1507
- try {
1508
- return await request();
1509
- } catch (error) {
1510
- if (!(error instanceof AccountingApiError) || error.statusCode !== 401) {
1511
- throw error;
1512
- }
1513
- clearPrivateReadScope(scopeKey, client);
1514
- await getToken(true);
1515
- return request();
1516
- }
1517
- },
1518
- [
1519
- client,
1520
- hostedAuthConfig,
1521
- hostedAuthSession,
1522
- networkConfig.apiUrl,
1523
- networkConfig.chainId,
1524
- refreshHostedAuthSession,
1525
- walletAddress,
1526
- wagmiContext
1527
- ]
1528
- );
1529
- const privateReadQueryScope = useMemo(
1530
- () => [networkConfig.apiUrl, networkConfig.chainId, privateReadAddress],
1531
- [networkConfig.apiUrl, networkConfig.chainId, privateReadAddress]
1532
- );
1533
- return {
1534
- executePrivateRead,
1535
- privateReadAddress,
1536
- privateReadReady,
1537
- privateReadQueryScope
1538
- };
1539
- }
1540
-
1541
- // src/sdk/hooks/use-balance.ts
1542
416
  function useBalance(options = {}) {
1543
417
  const queryClient = useContext(QueryClientContext);
1544
418
  const accountingContext = useSafePrivanaContext();
@@ -1592,55 +466,6 @@ function useBatchBalances(options) {
1592
466
  refetch: query.refetch
1593
467
  };
1594
468
  }
1595
-
1596
- // ../../node_modules/@wagmi/core/dist/esm/utils/getAction.js
1597
- function getAction(client, actionFn, name) {
1598
- const action_implicit = client[actionFn.name];
1599
- if (typeof action_implicit === "function")
1600
- return action_implicit;
1601
- const action_explicit = client[name];
1602
- if (typeof action_explicit === "function")
1603
- return action_explicit;
1604
- return (params) => actionFn(client, params);
1605
- }
1606
-
1607
- // ../../node_modules/@wagmi/core/dist/esm/actions/getChainId.js
1608
- function getChainId2(config) {
1609
- return config.state.chainId;
1610
- }
1611
- async function getTransactionReceipt(config, parameters) {
1612
- const { chainId, ...rest } = parameters;
1613
- const client = config.getClient({ chainId });
1614
- const action = getAction(client, getTransactionReceipt$1, "getTransactionReceipt");
1615
- return action(rest);
1616
- }
1617
- async function waitForTransactionReceipt(config, parameters) {
1618
- const { chainId, timeout = 0, ...rest } = parameters;
1619
- const client = config.getClient({ chainId });
1620
- const action = getAction(client, waitForTransactionReceipt$1, "waitForTransactionReceipt");
1621
- const receipt = await action({ ...rest, timeout });
1622
- if (receipt.status === "reverted") {
1623
- const action_getTransaction = getAction(client, getTransaction, "getTransaction");
1624
- const { from: account, ...txn } = await action_getTransaction({
1625
- hash: receipt.transactionHash
1626
- });
1627
- const action_call = getAction(client, call, "call");
1628
- const code = await action_call({
1629
- ...txn,
1630
- account,
1631
- data: txn.input,
1632
- gasPrice: txn.type !== "eip1559" ? txn.gasPrice : void 0,
1633
- maxFeePerGas: txn.type === "eip1559" ? txn.maxFeePerGas : void 0,
1634
- maxPriorityFeePerGas: txn.type === "eip1559" ? txn.maxPriorityFeePerGas : void 0
1635
- });
1636
- const reason = code?.data ? hexToString(`0x${code.data.substring(138)}`) : "unknown reason";
1637
- throw new Error(reason);
1638
- }
1639
- return {
1640
- ...receipt,
1641
- chainId: client.chain.id
1642
- };
1643
- }
1644
469
  function useEnsureCorrectChain() {
1645
470
  const config = useConfig();
1646
471
  const chainId = useChainId();
@@ -1731,19 +556,14 @@ function useDeposit(options = {}) {
1731
556
  const queryClient = useQueryClient();
1732
557
  const config = useConfig();
1733
558
  const { executePrivateRead } = usePrivateReadRequest();
1734
- const pollInterval = options.pollInterval ?? 5e3;
1735
- const pollTimeout = options.pollTimeout ?? 18e4;
1736
559
  const confirmations = options.confirmations ?? 15;
1737
560
  const [depositAddress, setDepositAddress] = useState(null);
1738
561
  const [txHash, setTxHash] = useState();
1739
562
  const [isSwitchingChain, setIsSwitchingChain] = useState(false);
1740
563
  const [isWaitingForConfirmation, setIsWaitingForConfirmation] = useState(false);
1741
- const [isWaitingForProcessing, setIsWaitingForProcessing] = useState(false);
1742
- const [didTimeout, setDidTimeout] = useState(false);
1743
- const [verificationFailed, setVerificationFailed] = useState(false);
564
+ const [receiptFailed, setReceiptFailed] = useState(false);
1744
565
  const [depositError, setDepositError] = useState(null);
1745
566
  const generationRef = useRef(0);
1746
- const pollIntervalRef = useRef(null);
1747
567
  const verificationContextRef = useRef(null);
1748
568
  const onDepositAddressReceivedRef = useRef(options.onDepositAddressReceived);
1749
569
  const onDepositSuccessRef = useRef(options.onDepositSuccess);
@@ -1763,6 +583,28 @@ function useDeposit(options = {}) {
1763
583
  options.onCheckTimeout,
1764
584
  options.onError
1765
585
  ]);
586
+ const {
587
+ isVerifying,
588
+ didTimeout,
589
+ verificationFailed: innerVerificationFailed,
590
+ error: verificationError,
591
+ verify,
592
+ reset: resetVerification
593
+ } = useDepositVerification({
594
+ pollInterval: options.pollInterval,
595
+ pollTimeout: options.pollTimeout,
596
+ onCredited: (hash, response) => {
597
+ verificationContextRef.current = null;
598
+ if (address) clearPendingDeposit(address);
599
+ onCreditedRef.current?.(hash, response);
600
+ },
601
+ onCheckTimeout: (hash) => {
602
+ onCheckTimeoutRef.current?.(hash);
603
+ },
604
+ onError: (err) => {
605
+ onErrorRef.current?.(err);
606
+ }
607
+ });
1766
608
  const addressMutation = useMutation({
1767
609
  mutationFn: async () => {
1768
610
  if (!address) throw new Error("No wallet connected");
@@ -1797,149 +639,24 @@ function useDeposit(options = {}) {
1797
639
  useEffect(() => {
1798
640
  return () => {
1799
641
  invalidateGeneration();
1800
- if (pollIntervalRef.current) {
1801
- clearTimeout(pollIntervalRef.current);
1802
- pollIntervalRef.current = null;
1803
- }
1804
642
  };
1805
643
  }, [invalidateGeneration]);
1806
644
  const resumedAddressRef = useRef(void 0);
1807
- const stopPolling = useCallback(() => {
1808
- if (pollIntervalRef.current) {
1809
- clearTimeout(pollIntervalRef.current);
1810
- pollIntervalRef.current = null;
1811
- }
1812
- }, []);
1813
645
  const reset = useCallback(() => {
1814
646
  generationRef.current++;
1815
- stopPolling();
647
+ resetVerification();
1816
648
  if (address) clearPendingDeposit(address);
1817
649
  verificationContextRef.current = null;
1818
650
  setDepositAddress(null);
1819
651
  setTxHash(void 0);
1820
652
  setIsSwitchingChain(false);
1821
653
  setIsWaitingForConfirmation(false);
1822
- setIsWaitingForProcessing(false);
1823
- setDidTimeout(false);
1824
- setVerificationFailed(false);
654
+ setReceiptFailed(false);
1825
655
  setDepositError(null);
1826
656
  addressMutation.reset();
1827
657
  resetWriteContract();
1828
658
  resetSendTransaction();
1829
- }, [address, addressMutation, resetWriteContract, resetSendTransaction, stopPolling]);
1830
- const runVerification = useCallback(
1831
- async (ctx, generation) => {
1832
- const isStale = () => generation !== generationRef.current;
1833
- const { hash, chainId, amount } = ctx;
1834
- setVerificationFailed(false);
1835
- setDepositError(null);
1836
- setDidTimeout(false);
1837
- setIsWaitingForProcessing(true);
1838
- const pollStartTime = Date.now();
1839
- const markVerificationFailed = (err) => {
1840
- setIsWaitingForProcessing(false);
1841
- setDepositError(err);
1842
- setVerificationFailed(true);
1843
- onErrorRef.current?.(err);
1844
- };
1845
- try {
1846
- const triggerResult = await executePrivateRead(
1847
- () => client.checkDeposit({
1848
- chain_id: chainId,
1849
- tx_hash: hash,
1850
- amount: amount.toString()
1851
- })
1852
- );
1853
- if (isStale()) return;
1854
- if (triggerResult.status === "credited") {
1855
- setIsWaitingForProcessing(false);
1856
- verificationContextRef.current = null;
1857
- if (address) clearPendingDeposit(address);
1858
- queryClient.invalidateQueries({ queryKey: ["accounting-balance"] });
1859
- queryClient.invalidateQueries({ queryKey: ["accounting-history"] });
1860
- onCreditedRef.current?.(hash, triggerResult);
1861
- return;
1862
- }
1863
- if (triggerResult.status === "error") {
1864
- markVerificationFailed(new Error(triggerResult.detail ?? "Deposit verification failed"));
1865
- return;
1866
- }
1867
- const depositId = triggerResult.deposit_id;
1868
- if (!depositId) {
1869
- markVerificationFailed(new Error("Deposit check did not return a deposit id"));
1870
- return;
1871
- }
1872
- let consecutiveFailures = 0;
1873
- const checkStatus = async () => {
1874
- if (isStale()) return true;
1875
- if (Date.now() - pollStartTime > pollTimeout) {
1876
- stopPolling();
1877
- setIsWaitingForProcessing(false);
1878
- setDidTimeout(true);
1879
- onCheckTimeoutRef.current?.(hash);
1880
- queryClient.invalidateQueries({ queryKey: ["accounting-balance"] });
1881
- return true;
1882
- }
1883
- try {
1884
- const result = await executePrivateRead(() => client.getDepositStatus(depositId));
1885
- if (isStale()) return true;
1886
- consecutiveFailures = 0;
1887
- if (result.status === "credited") {
1888
- stopPolling();
1889
- setIsWaitingForProcessing(false);
1890
- verificationContextRef.current = null;
1891
- if (address) clearPendingDeposit(address);
1892
- queryClient.invalidateQueries({ queryKey: ["accounting-balance"] });
1893
- queryClient.invalidateQueries({ queryKey: ["accounting-history"] });
1894
- onCreditedRef.current?.(hash, result);
1895
- return true;
1896
- }
1897
- if (result.status === "error") {
1898
- stopPolling();
1899
- markVerificationFailed(new Error(result.detail ?? "Deposit verification failed"));
1900
- return true;
1901
- }
1902
- } catch (err) {
1903
- if (isStale()) return true;
1904
- consecutiveFailures++;
1905
- console.warn("Error polling deposit status:", err);
1906
- if (consecutiveFailures >= 3) {
1907
- stopPolling();
1908
- markVerificationFailed(
1909
- err instanceof Error ? err : new Error("Deposit status polling failed")
1910
- );
1911
- return true;
1912
- }
1913
- }
1914
- return false;
1915
- };
1916
- const pollLoop = async () => {
1917
- const done = await checkStatus();
1918
- if (!done && !isStale() && pollIntervalRef.current !== null) {
1919
- pollIntervalRef.current = setTimeout(pollLoop, pollInterval);
1920
- }
1921
- };
1922
- pollIntervalRef.current = setTimeout(pollLoop, pollInterval);
1923
- } catch (err) {
1924
- if (isStale()) return;
1925
- stopPolling();
1926
- markVerificationFailed(
1927
- err instanceof Error ? err : new Error("Deposit verification failed")
1928
- );
1929
- }
1930
- },
1931
- [address, client, executePrivateRead, pollInterval, pollTimeout, queryClient, stopPolling]
1932
- );
1933
- const retryVerification = useCallback(async () => {
1934
- const ctx = verificationContextRef.current;
1935
- if (!ctx) {
1936
- throw new Error("No pending deposit to verify");
1937
- }
1938
- generationRef.current++;
1939
- stopPolling();
1940
- const generation = generationRef.current;
1941
- await runVerification(ctx, generation);
1942
- }, [runVerification, stopPolling]);
659
+ }, [address, addressMutation, resetWriteContract, resetSendTransaction, resetVerification]);
1943
660
  useEffect(() => {
1944
661
  if (!address || resumedAddressRef.current === address) return;
1945
662
  const persisted = loadPendingDeposit(address);
@@ -1976,19 +693,17 @@ function useDeposit(options = {}) {
1976
693
  setIsWaitingForConfirmation(false);
1977
694
  onDepositSuccessRef.current?.(hash);
1978
695
  queryClient.invalidateQueries({ queryKey: ["readContract"] });
1979
- await runVerification(ctx, generation);
696
+ await verify(ctx);
1980
697
  } catch (err) {
1981
698
  if (isStale()) return;
1982
699
  setIsWaitingForConfirmation(false);
1983
- stopPolling();
1984
700
  const error2 = err instanceof Error ? err : new Error("Deposit verification failed");
1985
- setIsWaitingForProcessing(false);
1986
701
  setDepositError(error2);
1987
- setVerificationFailed(true);
702
+ setReceiptFailed(true);
1988
703
  onErrorRef.current?.(error2);
1989
704
  }
1990
705
  })();
1991
- }, [address, config, confirmations, queryClient, runVerification, stopPolling]);
706
+ }, [address, config, confirmations, queryClient, verify]);
1992
707
  const deposit = useCallback(
1993
708
  async (params) => {
1994
709
  if (verificationContextRef.current) {
@@ -2066,15 +781,13 @@ function useDeposit(options = {}) {
2066
781
  if (isStale()) return;
2067
782
  onDepositSuccessRef.current?.(hash);
2068
783
  queryClient.invalidateQueries({ queryKey: ["readContract"] });
2069
- await runVerification(ctx, generation);
784
+ await verify(ctx);
2070
785
  } catch (err) {
2071
786
  if (isStale()) return;
2072
787
  setIsWaitingForConfirmation(false);
2073
- stopPolling();
2074
788
  const error2 = err instanceof Error ? err : new Error("Deposit verification failed");
2075
- setIsWaitingForProcessing(false);
2076
789
  setDepositError(error2);
2077
- setVerificationFailed(true);
790
+ setReceiptFailed(true);
2078
791
  onErrorRef.current?.(error2);
2079
792
  }
2080
793
  } catch (err) {
@@ -2096,13 +809,21 @@ function useDeposit(options = {}) {
2096
809
  queryClient,
2097
810
  writeContractAsync,
2098
811
  sendTransactionAsync,
2099
- stopPolling,
2100
812
  reset,
2101
- runVerification
813
+ verify
2102
814
  ]
2103
815
  );
2104
- const isPending = addressMutation.isPending || isSwitchingChain || isSendingTx || isWaitingForConfirmation || isWaitingForProcessing;
2105
- const error = addressMutation.error || sendError || depositError;
816
+ const retryVerification = useCallback(async () => {
817
+ const ctx = verificationContextRef.current;
818
+ if (!ctx) {
819
+ throw new Error("No pending deposit to verify");
820
+ }
821
+ setReceiptFailed(false);
822
+ setDepositError(null);
823
+ await verify(ctx);
824
+ }, [verify]);
825
+ const isPending = addressMutation.isPending || isSwitchingChain || isSendingTx || isWaitingForConfirmation || isVerifying;
826
+ const error = addressMutation.error || sendError || depositError || verificationError;
2106
827
  return {
2107
828
  depositAddress,
2108
829
  txHash,
@@ -2110,9 +831,9 @@ function useDeposit(options = {}) {
2110
831
  isSwitchingChain,
2111
832
  isSendingTransaction: isSendingTx,
2112
833
  isWaitingForConfirmation,
2113
- isWaitingForProcessing,
834
+ isWaitingForProcessing: isVerifying,
2114
835
  didTimeout,
2115
- verificationFailed,
836
+ verificationFailed: innerVerificationFailed || receiptFailed,
2116
837
  isPending,
2117
838
  error,
2118
839
  deposit,
@@ -2772,52 +1493,6 @@ function useModifyLock(options = {}) {
2772
1493
  reset: mutation.reset
2773
1494
  };
2774
1495
  }
2775
- var buttonVariants = cva(
2776
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
2777
- {
2778
- variants: {
2779
- variant: {
2780
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
2781
- destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
2782
- outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
2783
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
2784
- ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
2785
- link: "text-primary underline-offset-4 hover:underline"
2786
- },
2787
- size: {
2788
- default: "h-9 px-4 py-2 has-[>svg]:px-3",
2789
- sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
2790
- lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
2791
- icon: "size-9",
2792
- "icon-sm": "size-8",
2793
- "icon-lg": "size-10"
2794
- }
2795
- },
2796
- defaultVariants: {
2797
- variant: "default",
2798
- size: "default"
2799
- }
2800
- }
2801
- );
2802
- function Button({
2803
- className,
2804
- variant = "default",
2805
- size = "default",
2806
- asChild = false,
2807
- ...props
2808
- }) {
2809
- const Comp = asChild ? Slot : "button";
2810
- return /* @__PURE__ */ jsx(
2811
- Comp,
2812
- {
2813
- "data-slot": "button",
2814
- "data-variant": variant,
2815
- "data-size": size,
2816
- className: cn(buttonVariants({ variant, size, className })),
2817
- ...props
2818
- }
2819
- );
2820
- }
2821
1496
  function Dialog({ ...props }) {
2822
1497
  return /* @__PURE__ */ jsx(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
2823
1498
  }
@@ -4437,6 +3112,6 @@ function Skeleton({ className, ...props }) {
4437
3112
  );
4438
3113
  }
4439
3114
 
4440
- export { AccountingApiError, Button, HOSTED_AUTH_CLOCK_SKEW_MS, HostedAuthError, HostedAuthRequiredError, HostedAuthStateMismatchError, HttpClient, LOCK_TYPES, MODIFY_LOCK_TYPES, NETWORK_CONFIG, NetworkError, PrivanaButton, PrivanaClient, PrivanaInlineModal, PrivanaModal, PrivanaProvider, SUPPORTED_CHAINS, Skeleton, TRANSFER_LOCKED_TYPES, TRANSFER_TYPES, ValidationError, WITHDRAW_FROM_LOCK_TYPES, WITHDRAW_TYPES, applyRefreshResponse, buildHostedAuthSession, buttonVariants, clearHostedAuthPendingTransaction, createDomain, createHostedAuthPendingStorageKey, createHostedAuthState, createHostedAuthStorageKey, createLockExpiry, createPkceChallenge, createPkceVerifier, getAccountingContract, getApiUrl, getChainById, getChainIcon, getChainId, getExplorerAddressUrl, getTokenIcon, isHostedAuthRefreshActive, isHostedAuthSessionActive, normalizeAddress, normalizeHex, parseHostedAuthCallback, persistHostedAuthPendingTransaction, readHostedAuthPendingTransaction, readStoredHostedAuthSession, signLockMessage, signModifyLockMessage, signTransferLockedMessage, signTransferMessage, signWithdrawFromLockMessage, signWithdrawMessage, stripHostedAuthCallbackParams, syncHostedAuthSessionToClient, useBalance, useBatchBalances, useDeposit, useExpiredLocks, useHistory, useHostedRedirectAuth, useLockFunds, useLockedFunds, useModifyLock, usePendingWithdrawals, usePrivanaClient, usePrivanaContext, useSafeAccount, useSafePrivanaContext, useTokenInfo, useTokenList, useTotalLockedBalance, useTransfer, useUnlockFunds, useWithdraw };
3115
+ export { LOCK_TYPES, MODIFY_LOCK_TYPES, PrivanaButton, PrivanaInlineModal, PrivanaModal, Skeleton, TRANSFER_LOCKED_TYPES, TRANSFER_TYPES, WITHDRAW_FROM_LOCK_TYPES, WITHDRAW_TYPES, createDomain, createLockExpiry, getChainIcon, getTokenIcon, signLockMessage, signModifyLockMessage, signTransferLockedMessage, signTransferMessage, signWithdrawFromLockMessage, signWithdrawMessage, useBalance, useBatchBalances, useDeposit, useExpiredLocks, useHistory, useHostedRedirectAuth, useLockFunds, useLockedFunds, useModifyLock, usePendingWithdrawals, usePrivanaClient, useTokenInfo, useTokenList, useTotalLockedBalance, useTransfer, useUnlockFunds, useWithdraw };
4441
3116
  //# sourceMappingURL=index.js.map
4442
3117
  //# sourceMappingURL=index.js.map