@oasisprotocol/privana-sdk 0.5.2 → 0.5.3
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/README.md +34 -0
- package/dist/{chunk-UHXVYWTF.cjs → chunk-7KEQHWZB.cjs} +902 -240
- package/dist/chunk-7KEQHWZB.cjs.map +1 -0
- package/dist/{chunk-ZVUMV4NR.js → chunk-DZURIIRE.js} +898 -242
- package/dist/chunk-DZURIIRE.js.map +1 -0
- package/dist/index.cjs +1356 -336
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +24 -11
- package/dist/index.d.ts +24 -11
- package/dist/index.js +1116 -104
- package/dist/index.js.map +1 -1
- package/dist/on-ramp.cjs +3 -3
- package/dist/on-ramp.d.cts +5 -4
- package/dist/on-ramp.d.ts +5 -4
- package/dist/on-ramp.js +1 -1
- package/dist/{pending-lock-BdkuMjmY.d.cts → pending-lock-f4bWWTyN.d.cts} +41 -7
- package/dist/{pending-lock-BdkuMjmY.d.ts → pending-lock-f4bWWTyN.d.ts} +41 -7
- package/package.json +1 -1
- package/dist/chunk-UHXVYWTF.cjs.map +0 -1
- package/dist/chunk-ZVUMV4NR.js.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { createSiweMessage } from 'viem/siwe';
|
|
3
|
+
import { createContext, useContext, useRef, useCallback, useSyncExternalStore, useMemo, useState, useEffect } from 'react';
|
|
3
4
|
import { WagmiContext, useConfig, useChainId, useSwitchChain, useAccount, useWalletClient } from 'wagmi';
|
|
4
5
|
import { watchAccount, getAccount, getWalletClient } from 'wagmi/actions';
|
|
5
|
-
import { createSiweMessage } from 'viem/siwe';
|
|
6
6
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
7
7
|
import { parseAbiItem, zeroAddress, walletActions, hexToString, parseUnits, decodeEventLog, formatUnits, createClient, custom } from 'viem';
|
|
8
8
|
import { useQueryClient } from '@tanstack/react-query';
|
|
@@ -95,8 +95,11 @@ function getExplorerAddressUrl(chainId, address) {
|
|
|
95
95
|
return `${chain.explorerUrl}/address/${address}#tokentxns`;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
// src/sdk/auth/auth-clock-skew.ts
|
|
99
|
+
var AUTH_CLOCK_SKEW_MS = 3e4;
|
|
100
|
+
|
|
98
101
|
// src/sdk/auth/hosted-auth.ts
|
|
99
|
-
var HOSTED_AUTH_CLOCK_SKEW_MS =
|
|
102
|
+
var HOSTED_AUTH_CLOCK_SKEW_MS = AUTH_CLOCK_SKEW_MS;
|
|
100
103
|
var PKCE_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
|
|
101
104
|
var DEFAULT_RANDOM_LENGTH = 64;
|
|
102
105
|
var HOSTED_AUTH_CALLBACK_QUERY_KEYS = ["code", "error", "error_description", "state"];
|
|
@@ -218,11 +221,32 @@ function isHostedAuthSessionActive(session, now = Date.now(), skewMs = HOSTED_AU
|
|
|
218
221
|
function isHostedAuthRefreshActive(session, now = Date.now(), skewMs = HOSTED_AUTH_CLOCK_SKEW_MS) {
|
|
219
222
|
return session.refreshExpiresAt > now + skewMs;
|
|
220
223
|
}
|
|
221
|
-
|
|
222
|
-
// src/sdk/auth/siwe.ts
|
|
224
|
+
var SIWE_MESSAGE_VALIDITY_MS = 24 * 60 * 60 * 1e3;
|
|
223
225
|
function buildSiweStatement(chainId) {
|
|
224
226
|
return `Sign in to Privana on chain ${chainId}`;
|
|
225
227
|
}
|
|
228
|
+
async function buildSiweLoginMessage(api, params) {
|
|
229
|
+
const { address, chainId, apiUrl } = params;
|
|
230
|
+
const [{ domain }, { nonce }] = await Promise.all([
|
|
231
|
+
api.getSiweDomain(),
|
|
232
|
+
api.getSiweNonce(address)
|
|
233
|
+
]);
|
|
234
|
+
const issuedAt = /* @__PURE__ */ new Date();
|
|
235
|
+
const expirationTime = new Date(issuedAt.getTime() + SIWE_MESSAGE_VALIDITY_MS);
|
|
236
|
+
const uri = typeof window !== "undefined" && window.location.origin ? window.location.origin : apiUrl;
|
|
237
|
+
const message = createSiweMessage({
|
|
238
|
+
address,
|
|
239
|
+
chainId,
|
|
240
|
+
domain,
|
|
241
|
+
expirationTime,
|
|
242
|
+
issuedAt,
|
|
243
|
+
nonce,
|
|
244
|
+
statement: buildSiweStatement(chainId),
|
|
245
|
+
uri,
|
|
246
|
+
version: "1"
|
|
247
|
+
});
|
|
248
|
+
return { message, expirationTime };
|
|
249
|
+
}
|
|
226
250
|
|
|
227
251
|
// src/sdk/client/errors.ts
|
|
228
252
|
var AccountingApiError = class _AccountingApiError extends Error {
|
|
@@ -347,9 +371,10 @@ var HttpClient = class {
|
|
|
347
371
|
var PRIVATE_READ_TOKEN_HEADER = "X-SIWE-Token";
|
|
348
372
|
var MAX_BATCH_BALANCE_TOKEN_IDS = 100;
|
|
349
373
|
var MAX_HISTORY_PAGE_SIZE = 100;
|
|
350
|
-
var PrivanaClient = class {
|
|
374
|
+
var PrivanaClient = class _PrivanaClient {
|
|
351
375
|
constructor(config) {
|
|
352
376
|
this.http = new HttpClient(config);
|
|
377
|
+
this.baseConfig = { ...config, headers: { ...config.headers } };
|
|
353
378
|
}
|
|
354
379
|
getBaseUrl() {
|
|
355
380
|
return this.http.getBaseUrl();
|
|
@@ -619,10 +644,23 @@ var PrivanaClient = class {
|
|
|
619
644
|
async getPendingOnRamps() {
|
|
620
645
|
return this.http.get("/v1/accounting/onramp/pending");
|
|
621
646
|
}
|
|
647
|
+
/**
|
|
648
|
+
* @deprecated This mutates the shared client's headers and displaces its Authorization
|
|
649
|
+
* (JWT bearer) header, which breaks concurrent JWT-authenticated requests. Use
|
|
650
|
+
* {@link PrivanaClient.withPrivateReadToken} instead, which returns a scoped client that
|
|
651
|
+
* authenticates the private read without touching the shared client's headers. Will be
|
|
652
|
+
* removed in a future release.
|
|
653
|
+
*/
|
|
622
654
|
setPrivateReadToken(token) {
|
|
623
655
|
this.http.removeHeader("Authorization");
|
|
624
656
|
this.http.setHeader(PRIVATE_READ_TOKEN_HEADER, token);
|
|
625
657
|
}
|
|
658
|
+
/**
|
|
659
|
+
* @deprecated The shared client no longer carries a private-read token between requests;
|
|
660
|
+
* private reads now run on a scoped client from {@link PrivanaClient.withPrivateReadToken}.
|
|
661
|
+
* Returns whatever X-SIWE-Token is currently set on the shared client's headers. Will be
|
|
662
|
+
* removed in a future release.
|
|
663
|
+
*/
|
|
626
664
|
getPrivateReadToken() {
|
|
627
665
|
return this.http.getHeader(PRIVATE_READ_TOKEN_HEADER);
|
|
628
666
|
}
|
|
@@ -636,6 +674,26 @@ var PrivanaClient = class {
|
|
|
636
674
|
clearBearerToken() {
|
|
637
675
|
this.http.removeHeader("Authorization");
|
|
638
676
|
}
|
|
677
|
+
/**
|
|
678
|
+
* Returns a scoped client whose requests authenticate with the given SIWE private-read
|
|
679
|
+
* token (X-SIWE-Token) instead of the client-wide JWT bearer. The scoped client shares
|
|
680
|
+
* baseUrl/timeout/base headers but owns a separate header set, so private reads issued
|
|
681
|
+
* through it never displace the real client's Authorization header: concurrent
|
|
682
|
+
* JWT-authenticated requests on the real client keep their bearer, and a bearer installed
|
|
683
|
+
* mid-flight (auto-login/hydration) is never erased by a private read.
|
|
684
|
+
*/
|
|
685
|
+
withPrivateReadToken(token) {
|
|
686
|
+
const headers = {};
|
|
687
|
+
for (const [name, value] of Object.entries(this.baseConfig.headers ?? {})) {
|
|
688
|
+
const lower = name.toLowerCase();
|
|
689
|
+
if (lower === "authorization" || lower === PRIVATE_READ_TOKEN_HEADER.toLowerCase()) {
|
|
690
|
+
continue;
|
|
691
|
+
}
|
|
692
|
+
headers[name] = value;
|
|
693
|
+
}
|
|
694
|
+
headers[PRIVATE_READ_TOKEN_HEADER] = token;
|
|
695
|
+
return new _PrivanaClient({ ...this.baseConfig, headers });
|
|
696
|
+
}
|
|
639
697
|
};
|
|
640
698
|
|
|
641
699
|
// src/sdk/signatures/eip712-types.ts
|
|
@@ -865,8 +923,421 @@ function useSafeAccount() {
|
|
|
865
923
|
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
866
924
|
}
|
|
867
925
|
|
|
926
|
+
// src/sdk/auth/siwe-persistence.ts
|
|
927
|
+
var PERSISTED_SIWE_AUTH_RECORD_VERSION = 2;
|
|
928
|
+
var warnedBlockedStorage = false;
|
|
929
|
+
function warnBlockedStorageOnce() {
|
|
930
|
+
if (warnedBlockedStorage) return;
|
|
931
|
+
warnedBlockedStorage = true;
|
|
932
|
+
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
933
|
+
console.warn(
|
|
934
|
+
"Privana SIWE auth: localStorage is unavailable or blocked; sessions will stay in memory only."
|
|
935
|
+
);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
function createSiweAuthStorageKey(apiUrl, chainId) {
|
|
939
|
+
const normalizedApiUrl = apiUrl.replace(/\/$/, "");
|
|
940
|
+
return ["privana", "siwe-auth", normalizedApiUrl, String(chainId)].join(":");
|
|
941
|
+
}
|
|
942
|
+
function buildPersistedSiweAuthRecordFromLogin(response, now, siweTokenExpiresAt) {
|
|
943
|
+
return {
|
|
944
|
+
version: PERSISTED_SIWE_AUTH_RECORD_VERSION,
|
|
945
|
+
tokens: {
|
|
946
|
+
siwe_token: response.siwe_token,
|
|
947
|
+
jwt_access_token: response.jwt_access_token,
|
|
948
|
+
jwt_refresh_token: response.jwt_refresh_token,
|
|
949
|
+
address: response.address
|
|
950
|
+
},
|
|
951
|
+
accessTokenExpiresAt: now + response.jwt_expires_in * 1e3,
|
|
952
|
+
refreshTokenExpiresAt: now + response.jwt_refresh_expires_in * 1e3,
|
|
953
|
+
siweTokenExpiresAt,
|
|
954
|
+
updatedAt: now
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
function applyRefreshToPersistedSiweAuthRecord(previous, response, now = Date.now()) {
|
|
958
|
+
return {
|
|
959
|
+
...previous,
|
|
960
|
+
tokens: {
|
|
961
|
+
...previous.tokens,
|
|
962
|
+
jwt_access_token: response.token,
|
|
963
|
+
jwt_refresh_token: response.refresh_token
|
|
964
|
+
},
|
|
965
|
+
accessTokenExpiresAt: now + response.expires_in * 1e3,
|
|
966
|
+
refreshTokenExpiresAt: now + response.refresh_expires_in * 1e3,
|
|
967
|
+
updatedAt: now
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
function isPersistedSiweAuthRecord(value) {
|
|
971
|
+
if (typeof value !== "object" || value === null) return false;
|
|
972
|
+
const record = value;
|
|
973
|
+
if (record.version !== PERSISTED_SIWE_AUTH_RECORD_VERSION) return false;
|
|
974
|
+
if (typeof record.accessTokenExpiresAt !== "number") return false;
|
|
975
|
+
if (typeof record.refreshTokenExpiresAt !== "number") return false;
|
|
976
|
+
if (typeof record.siweTokenExpiresAt !== "number") return false;
|
|
977
|
+
if (typeof record.updatedAt !== "number") return false;
|
|
978
|
+
const tokens = record.tokens;
|
|
979
|
+
if (typeof tokens !== "object" || tokens === null) return false;
|
|
980
|
+
const tokenFields = tokens;
|
|
981
|
+
return typeof tokenFields.siwe_token === "string" && typeof tokenFields.jwt_access_token === "string" && typeof tokenFields.jwt_refresh_token === "string" && typeof tokenFields.address === "string" && tokenFields.address.length > 0;
|
|
982
|
+
}
|
|
983
|
+
function isPersistedSiweAuthAccessActive(record, now = Date.now()) {
|
|
984
|
+
return record.accessTokenExpiresAt > now + AUTH_CLOCK_SKEW_MS;
|
|
985
|
+
}
|
|
986
|
+
function isPersistedSiweAuthRefreshActive(record, now = Date.now()) {
|
|
987
|
+
return record.refreshTokenExpiresAt > now + AUTH_CLOCK_SKEW_MS;
|
|
988
|
+
}
|
|
989
|
+
function parsePersistedSiweAuthRecord(raw, now = Date.now()) {
|
|
990
|
+
let parsed;
|
|
991
|
+
try {
|
|
992
|
+
parsed = JSON.parse(raw);
|
|
993
|
+
} catch {
|
|
994
|
+
return null;
|
|
995
|
+
}
|
|
996
|
+
if (!isPersistedSiweAuthRecord(parsed)) return null;
|
|
997
|
+
if (!isPersistedSiweAuthRefreshActive(parsed, now)) return null;
|
|
998
|
+
return parsed;
|
|
999
|
+
}
|
|
1000
|
+
function readPersistedSiweAuth(storage, key, now = Date.now()) {
|
|
1001
|
+
let raw;
|
|
1002
|
+
try {
|
|
1003
|
+
raw = storage.getItem(key);
|
|
1004
|
+
} catch {
|
|
1005
|
+
return null;
|
|
1006
|
+
}
|
|
1007
|
+
if (raw == null) return null;
|
|
1008
|
+
const record = parsePersistedSiweAuthRecord(raw, now);
|
|
1009
|
+
if (!record) removePersistedSiweAuth(storage, key);
|
|
1010
|
+
return record;
|
|
1011
|
+
}
|
|
1012
|
+
function writePersistedSiweAuth(storage, key, record) {
|
|
1013
|
+
try {
|
|
1014
|
+
storage.setItem(key, JSON.stringify(record));
|
|
1015
|
+
} catch {
|
|
1016
|
+
warnBlockedStorageOnce();
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
function removePersistedSiweAuth(storage, key) {
|
|
1020
|
+
try {
|
|
1021
|
+
storage.removeItem(key);
|
|
1022
|
+
} catch {
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
var localStorageProbe;
|
|
1026
|
+
function getSiweAuthLocalStorage() {
|
|
1027
|
+
if (localStorageProbe !== void 0) return localStorageProbe;
|
|
1028
|
+
if (typeof window === "undefined") return null;
|
|
1029
|
+
try {
|
|
1030
|
+
const storage = window.localStorage;
|
|
1031
|
+
storage.getItem("__privana_siwe_probe__");
|
|
1032
|
+
localStorageProbe = storage;
|
|
1033
|
+
} catch {
|
|
1034
|
+
warnBlockedStorageOnce();
|
|
1035
|
+
localStorageProbe = null;
|
|
1036
|
+
}
|
|
1037
|
+
return localStorageProbe;
|
|
1038
|
+
}
|
|
1039
|
+
function isAdoptableRecord(record, currentAddress, currentUpdatedAt) {
|
|
1040
|
+
if (!record || !currentAddress) return false;
|
|
1041
|
+
if (record.tokens.address.toLowerCase() !== currentAddress.toLowerCase()) return false;
|
|
1042
|
+
return record.updatedAt > (currentUpdatedAt ?? -1);
|
|
1043
|
+
}
|
|
1044
|
+
function resolveHydrationAction(record, connectedAddress, now = Date.now()) {
|
|
1045
|
+
if (!connectedAddress) return { type: "dormant" };
|
|
1046
|
+
if (!record) return { type: "dormant" };
|
|
1047
|
+
if (record.tokens.address.toLowerCase() !== connectedAddress.toLowerCase()) {
|
|
1048
|
+
return { type: "remove" };
|
|
1049
|
+
}
|
|
1050
|
+
if (isPersistedSiweAuthAccessActive(record, now)) return { type: "restore", record };
|
|
1051
|
+
if (isPersistedSiweAuthRefreshActive(record, now)) return { type: "refresh", record };
|
|
1052
|
+
return { type: "remove" };
|
|
1053
|
+
}
|
|
1054
|
+
function resolveStorageEvent(newValue, currentAddress, currentUpdatedAt, now = Date.now()) {
|
|
1055
|
+
if (!currentAddress) return { type: "ignore" };
|
|
1056
|
+
if (newValue == null) return { type: "logout" };
|
|
1057
|
+
const record = parsePersistedSiweAuthRecord(newValue, now);
|
|
1058
|
+
if (!record) return { type: "ignore" };
|
|
1059
|
+
if (!isAdoptableRecord(record, currentAddress, currentUpdatedAt)) return { type: "ignore" };
|
|
1060
|
+
return { type: "adopt", record };
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
// src/sdk/auth/siwe-auth-policy.ts
|
|
1064
|
+
function resolveActiveSessionAddress(...candidates) {
|
|
1065
|
+
return candidates.find((candidate) => !!candidate) ?? null;
|
|
1066
|
+
}
|
|
1067
|
+
function resolveAutoLoginEffectAction(input) {
|
|
1068
|
+
const {
|
|
1069
|
+
status,
|
|
1070
|
+
isConnected,
|
|
1071
|
+
address,
|
|
1072
|
+
sessionAddress,
|
|
1073
|
+
autoLogin,
|
|
1074
|
+
isLoading,
|
|
1075
|
+
isHydrating,
|
|
1076
|
+
autoAttemptedAddress,
|
|
1077
|
+
authenticatingAddress
|
|
1078
|
+
} = input;
|
|
1079
|
+
const activeAddress2 = resolveActiveSessionAddress(sessionAddress, authenticatingAddress);
|
|
1080
|
+
if (status === "connecting" || status === "reconnecting") return { type: "wait" };
|
|
1081
|
+
if (!isConnected && activeAddress2) return { type: "reset-on-disconnect" };
|
|
1082
|
+
if (isConnected && address && activeAddress2 && address.toLowerCase() !== activeAddress2.toLowerCase()) {
|
|
1083
|
+
return { type: "clear-on-mismatch" };
|
|
1084
|
+
}
|
|
1085
|
+
if (!autoLogin) return { type: "noop" };
|
|
1086
|
+
if (isHydrating) return { type: "wait" };
|
|
1087
|
+
if (isConnected && address && !sessionAddress && !isLoading && autoAttemptedAddress !== address) {
|
|
1088
|
+
return { type: "auto-login" };
|
|
1089
|
+
}
|
|
1090
|
+
return { type: "noop" };
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
// src/sdk/auth/auth-lifecycle.ts
|
|
1094
|
+
function initialAuthLifecycleState() {
|
|
1095
|
+
return {
|
|
1096
|
+
generation: 0,
|
|
1097
|
+
refreshData: null,
|
|
1098
|
+
currentRecord: null,
|
|
1099
|
+
autoAttemptedAddress: null,
|
|
1100
|
+
authenticatingAddress: null,
|
|
1101
|
+
hydratedAddress: null
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
function reduceAuthLifecycle(state, event) {
|
|
1105
|
+
switch (event.type) {
|
|
1106
|
+
case "reset":
|
|
1107
|
+
return {
|
|
1108
|
+
generation: state.generation + 1,
|
|
1109
|
+
refreshData: null,
|
|
1110
|
+
currentRecord: null,
|
|
1111
|
+
autoAttemptedAddress: null,
|
|
1112
|
+
authenticatingAddress: null,
|
|
1113
|
+
hydratedAddress: null
|
|
1114
|
+
};
|
|
1115
|
+
case "commit":
|
|
1116
|
+
return {
|
|
1117
|
+
...state,
|
|
1118
|
+
generation: state.generation + 1,
|
|
1119
|
+
refreshData: {
|
|
1120
|
+
refreshToken: event.record.tokens.jwt_refresh_token,
|
|
1121
|
+
refreshExpiresAt: event.record.refreshTokenExpiresAt
|
|
1122
|
+
},
|
|
1123
|
+
currentRecord: event.record
|
|
1124
|
+
};
|
|
1125
|
+
case "refresh":
|
|
1126
|
+
return {
|
|
1127
|
+
...state,
|
|
1128
|
+
refreshData: event.refreshData,
|
|
1129
|
+
currentRecord: event.record
|
|
1130
|
+
};
|
|
1131
|
+
case "setAutoAttemptedAddress":
|
|
1132
|
+
return { ...state, autoAttemptedAddress: event.address };
|
|
1133
|
+
case "setAuthenticatingAddress":
|
|
1134
|
+
return { ...state, authenticatingAddress: event.address };
|
|
1135
|
+
case "setHydratedAddress":
|
|
1136
|
+
return { ...state, hydratedAddress: event.address };
|
|
1137
|
+
case "clearCurrentRecord":
|
|
1138
|
+
return { ...state, currentRecord: null };
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// src/sdk/auth/auth-lifecycle-effects.ts
|
|
1143
|
+
function armPrivateRead(ports, input) {
|
|
1144
|
+
ports.cache.set(input.scopeKey, input.siweToken, input.siweExpiry);
|
|
1145
|
+
}
|
|
1146
|
+
function applyAccessRotation(ports, rotation) {
|
|
1147
|
+
ports.client.setBearerToken(rotation.accessToken);
|
|
1148
|
+
ports.react.setTokens(
|
|
1149
|
+
(prev) => prev ? {
|
|
1150
|
+
...prev,
|
|
1151
|
+
jwt_access_token: rotation.accessToken,
|
|
1152
|
+
jwt_refresh_token: rotation.refreshToken
|
|
1153
|
+
} : prev
|
|
1154
|
+
);
|
|
1155
|
+
ports.react.setAccessTokenExpiresAt(rotation.accessTokenExpiresAt);
|
|
1156
|
+
}
|
|
1157
|
+
function publishSession(ports, record) {
|
|
1158
|
+
ports.client.setBearerToken(record.tokens.jwt_access_token);
|
|
1159
|
+
ports.react.setSession({ address: record.tokens.address });
|
|
1160
|
+
ports.react.setTokens({
|
|
1161
|
+
siwe_token: record.tokens.siwe_token,
|
|
1162
|
+
jwt_access_token: record.tokens.jwt_access_token,
|
|
1163
|
+
jwt_refresh_token: record.tokens.jwt_refresh_token,
|
|
1164
|
+
address: record.tokens.address
|
|
1165
|
+
});
|
|
1166
|
+
ports.react.setAccessTokenExpiresAt(record.accessTokenExpiresAt);
|
|
1167
|
+
}
|
|
1168
|
+
function persistRecordIfEnabled(ports, record) {
|
|
1169
|
+
if (!ports.persistJwt) return;
|
|
1170
|
+
if (record) ports.storage.write(record);
|
|
1171
|
+
else ports.storage.remove();
|
|
1172
|
+
}
|
|
1173
|
+
function clearSessionEffects(ports) {
|
|
1174
|
+
ports.client.clearPrivateReadToken();
|
|
1175
|
+
ports.client.clearBearerToken();
|
|
1176
|
+
ports.react.setSession(null);
|
|
1177
|
+
ports.react.setTokens(null);
|
|
1178
|
+
ports.react.setAccessTokenExpiresAt(null);
|
|
1179
|
+
ports.react.setIsLoading(false);
|
|
1180
|
+
ports.react.setIsHydrating(false);
|
|
1181
|
+
ports.react.setError(null);
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// src/sdk/auth/siwe-auth-controller.ts
|
|
1185
|
+
function activeAddress(ctrl) {
|
|
1186
|
+
return resolveActiveSessionAddress(
|
|
1187
|
+
ctrl.getSessionAddress(),
|
|
1188
|
+
ctrl.getState().currentRecord?.tokens.address
|
|
1189
|
+
);
|
|
1190
|
+
}
|
|
1191
|
+
function ctrlReset(ctrl, removeStorage) {
|
|
1192
|
+
ctrl.loginInFlight = false;
|
|
1193
|
+
ctrl.loginOwnerGeneration = -1;
|
|
1194
|
+
ctrl.hydrateOwnerGeneration = -1;
|
|
1195
|
+
ctrl.refreshPromise = null;
|
|
1196
|
+
ctrl.dispatch({ type: "reset" });
|
|
1197
|
+
clearSessionEffects(ctrl.ports);
|
|
1198
|
+
if (removeStorage) persistRecordIfEnabled(ctrl.ports, null);
|
|
1199
|
+
}
|
|
1200
|
+
function ctrlRestoreSession(ctrl, record) {
|
|
1201
|
+
ctrl.dispatch({ type: "commit", record });
|
|
1202
|
+
armPrivateRead(ctrl.ports, {
|
|
1203
|
+
siweToken: record.tokens.siwe_token,
|
|
1204
|
+
siweExpiry: record.siweTokenExpiresAt,
|
|
1205
|
+
scopeKey: ctrl.ports.makeScopeKey(record.tokens.address)
|
|
1206
|
+
});
|
|
1207
|
+
publishSession(ctrl.ports, record);
|
|
1208
|
+
}
|
|
1209
|
+
function ctrlAdoptNewerRecordIfAvailable(ctrl) {
|
|
1210
|
+
if (!ctrl.config.persistJwt) return false;
|
|
1211
|
+
const record = ctrl.ports.storage.read();
|
|
1212
|
+
if (!record) return false;
|
|
1213
|
+
const current = activeAddress(ctrl);
|
|
1214
|
+
if (!isAdoptableRecord(record, current, ctrl.getState().currentRecord?.updatedAt ?? null)) {
|
|
1215
|
+
return false;
|
|
1216
|
+
}
|
|
1217
|
+
ctrlRestoreSession(ctrl, record);
|
|
1218
|
+
return true;
|
|
1219
|
+
}
|
|
1220
|
+
async function ctrlLogin(ctrl) {
|
|
1221
|
+
const address = ctrl.config.address;
|
|
1222
|
+
if (!address) throw new Error("No wallet connected");
|
|
1223
|
+
if (ctrl.loginInFlight) return;
|
|
1224
|
+
ctrl.loginInFlight = true;
|
|
1225
|
+
ctrl.dispatch({ type: "setAutoAttemptedAddress", address });
|
|
1226
|
+
ctrl.dispatch({ type: "setAuthenticatingAddress", address });
|
|
1227
|
+
ctrl.ports.react.setIsLoading(true);
|
|
1228
|
+
ctrl.ports.react.setError(null);
|
|
1229
|
+
const generation = ctrl.getState().generation;
|
|
1230
|
+
ctrl.loginOwnerGeneration = generation;
|
|
1231
|
+
const { chainId, apiUrl } = ctrl.config;
|
|
1232
|
+
const api = ctrl.api;
|
|
1233
|
+
try {
|
|
1234
|
+
const { message, expirationTime } = await buildSiweLoginMessage(api, {
|
|
1235
|
+
address,
|
|
1236
|
+
chainId,
|
|
1237
|
+
apiUrl
|
|
1238
|
+
});
|
|
1239
|
+
const signature = await ctrl.signer.signSiweMessage({ account: address, message });
|
|
1240
|
+
const res = await api.loginWithSiwe({ siwe_message: message, signature });
|
|
1241
|
+
if (ctrl.getState().generation !== generation) return;
|
|
1242
|
+
const record = buildPersistedSiweAuthRecordFromLogin(res, Date.now(), expirationTime.getTime());
|
|
1243
|
+
ctrlRestoreSession(ctrl, record);
|
|
1244
|
+
persistRecordIfEnabled(ctrl.ports, record);
|
|
1245
|
+
} catch (err) {
|
|
1246
|
+
if (ctrl.loginOwnerGeneration === generation) {
|
|
1247
|
+
ctrl.ports.react.setError(err instanceof Error ? err : new Error("Sign-in failed"));
|
|
1248
|
+
}
|
|
1249
|
+
throw err;
|
|
1250
|
+
} finally {
|
|
1251
|
+
if (ctrl.loginOwnerGeneration === generation) {
|
|
1252
|
+
ctrl.ports.react.setIsLoading(false);
|
|
1253
|
+
ctrl.loginInFlight = false;
|
|
1254
|
+
ctrl.loginOwnerGeneration = -1;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
async function ctrlLogout(ctrl) {
|
|
1259
|
+
const refreshToken = ctrl.getState().refreshData?.refreshToken;
|
|
1260
|
+
try {
|
|
1261
|
+
if (refreshToken) {
|
|
1262
|
+
try {
|
|
1263
|
+
await ctrl.api.logoutJwtSession({ refresh_token: refreshToken, revoke_all: true });
|
|
1264
|
+
} catch {
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
} finally {
|
|
1268
|
+
ctrlReset(ctrl, ctrl.config.persistJwt);
|
|
1269
|
+
ctrl.dispatch({ type: "setAutoAttemptedAddress", address: ctrl.config.address ?? null });
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
async function ctrlRefreshAccessToken(ctrl) {
|
|
1273
|
+
const data = ctrl.getState().refreshData;
|
|
1274
|
+
if (!data) return;
|
|
1275
|
+
if (Date.now() >= data.refreshExpiresAt - AUTH_CLOCK_SKEW_MS) {
|
|
1276
|
+
ctrlReset(ctrl, ctrl.config.persistJwt);
|
|
1277
|
+
return;
|
|
1278
|
+
}
|
|
1279
|
+
if (ctrl.refreshPromise) return ctrl.refreshPromise;
|
|
1280
|
+
const generation = ctrl.getState().generation;
|
|
1281
|
+
const promise = (async () => {
|
|
1282
|
+
try {
|
|
1283
|
+
if (ctrlAdoptNewerRecordIfAvailable(ctrl)) return;
|
|
1284
|
+
const res = await ctrl.api.refreshJwtSession({ refresh_token: data.refreshToken });
|
|
1285
|
+
if (ctrl.getState().generation !== generation) return;
|
|
1286
|
+
const refreshedAt = Date.now();
|
|
1287
|
+
const refreshData = {
|
|
1288
|
+
refreshToken: res.refresh_token,
|
|
1289
|
+
refreshExpiresAt: refreshedAt + res.refresh_expires_in * 1e3
|
|
1290
|
+
};
|
|
1291
|
+
const previous = ctrl.getState().currentRecord;
|
|
1292
|
+
if (previous && ctrl.config.persistJwt) {
|
|
1293
|
+
const nextRecord = applyRefreshToPersistedSiweAuthRecord(previous, res, refreshedAt);
|
|
1294
|
+
ctrl.dispatch({ type: "refresh", refreshData, record: nextRecord });
|
|
1295
|
+
ctrl.ports.storage.write(nextRecord);
|
|
1296
|
+
} else {
|
|
1297
|
+
ctrl.dispatch({ type: "refresh", refreshData, record: previous });
|
|
1298
|
+
}
|
|
1299
|
+
applyAccessRotation(ctrl.ports, {
|
|
1300
|
+
accessToken: res.token,
|
|
1301
|
+
refreshToken: res.refresh_token,
|
|
1302
|
+
accessTokenExpiresAt: refreshedAt + res.expires_in * 1e3
|
|
1303
|
+
});
|
|
1304
|
+
} catch {
|
|
1305
|
+
if (ctrl.getState().generation !== generation) return;
|
|
1306
|
+
if (!ctrlAdoptNewerRecordIfAvailable(ctrl)) ctrlReset(ctrl, ctrl.config.persistJwt);
|
|
1307
|
+
}
|
|
1308
|
+
})();
|
|
1309
|
+
ctrl.refreshPromise = promise;
|
|
1310
|
+
try {
|
|
1311
|
+
await promise;
|
|
1312
|
+
} finally {
|
|
1313
|
+
if (ctrl.refreshPromise === promise) ctrl.refreshPromise = null;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
async function ctrlHydrateViaRefresh(ctrl, record, address) {
|
|
1317
|
+
ctrl.dispatch({ type: "setAutoAttemptedAddress", address });
|
|
1318
|
+
ctrl.dispatch({ type: "setAuthenticatingAddress", address });
|
|
1319
|
+
ctrl.ports.react.setIsHydrating(true);
|
|
1320
|
+
ctrl.dispatch({ type: "commit", record });
|
|
1321
|
+
const hydrationGen = ctrl.getState().generation;
|
|
1322
|
+
ctrl.hydrateOwnerGeneration = hydrationGen;
|
|
1323
|
+
try {
|
|
1324
|
+
await ctrlRefreshAccessToken(ctrl).catch(() => {
|
|
1325
|
+
});
|
|
1326
|
+
const fresh = ctrl.getState().currentRecord;
|
|
1327
|
+
if (fresh && fresh.tokens.address.toLowerCase() === address.toLowerCase() && isPersistedSiweAuthAccessActive(fresh)) {
|
|
1328
|
+
ctrlRestoreSession(ctrl, fresh);
|
|
1329
|
+
} else if (ctrl.getState().generation === hydrationGen) {
|
|
1330
|
+
ctrl.dispatch({ type: "setAutoAttemptedAddress", address: null });
|
|
1331
|
+
}
|
|
1332
|
+
} finally {
|
|
1333
|
+
if (ctrl.hydrateOwnerGeneration === hydrationGen) {
|
|
1334
|
+
ctrl.ports.react.setIsHydrating(false);
|
|
1335
|
+
ctrl.hydrateOwnerGeneration = -1;
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
|
|
868
1340
|
// src/sdk/hooks/private-read-token-store.ts
|
|
869
|
-
var AUTH_CLOCK_SKEW_MS = 3e4;
|
|
870
1341
|
var cache = /* @__PURE__ */ new Map();
|
|
871
1342
|
function createScopeKey(apiUrl, chainId, address) {
|
|
872
1343
|
return `${apiUrl.replace(/\/$/, "")}:${chainId}:${address.toLowerCase()}`;
|
|
@@ -886,164 +1357,240 @@ function setCachedPrivateReadToken(scopeKey, token, expiresAt) {
|
|
|
886
1357
|
function deleteCachedPrivateReadToken(scopeKey) {
|
|
887
1358
|
cache.delete(scopeKey);
|
|
888
1359
|
}
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
children,
|
|
894
|
-
client,
|
|
895
|
-
networkConfig,
|
|
896
|
-
autoLogin = true
|
|
897
|
-
}) {
|
|
1360
|
+
|
|
1361
|
+
// src/sdk/hooks/use-siwe-auth-lifecycle.ts
|
|
1362
|
+
function useSiweAuthLifecycle(deps) {
|
|
1363
|
+
const { storageKey, apiUrl, chainId, persistJwt, autoLogin, client, api } = deps;
|
|
898
1364
|
const wagmiContext = useContext(WagmiContext);
|
|
899
1365
|
const { address, isConnected, status } = useSafeAccount();
|
|
900
1366
|
const [session, setSession] = useState(null);
|
|
901
1367
|
const [tokens, setTokens] = useState(null);
|
|
902
1368
|
const [isLoading, setIsLoading] = useState(false);
|
|
1369
|
+
const [isHydrating, setIsHydrating] = useState(false);
|
|
903
1370
|
const [error, setError] = useState(null);
|
|
904
1371
|
const [accessTokenExpiresAt, setAccessTokenExpiresAt] = useState(null);
|
|
905
|
-
const
|
|
906
|
-
const
|
|
907
|
-
const
|
|
908
|
-
const
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
const refreshToken = refreshDataRef.current?.refreshToken;
|
|
922
|
-
try {
|
|
923
|
-
if (refreshToken) {
|
|
924
|
-
await client.logoutJwtSession({ refresh_token: refreshToken });
|
|
1372
|
+
const sessionRef = useRef(null);
|
|
1373
|
+
const prevPersistJwtRef = useRef(void 0);
|
|
1374
|
+
const authRef = useRef(initialAuthLifecycleState());
|
|
1375
|
+
const storageAdapter = useMemo(
|
|
1376
|
+
() => ({
|
|
1377
|
+
read: () => {
|
|
1378
|
+
const ls = getSiweAuthLocalStorage();
|
|
1379
|
+
return ls ? readPersistedSiweAuth(ls, storageKey) : null;
|
|
1380
|
+
},
|
|
1381
|
+
write: (record) => {
|
|
1382
|
+
const ls = getSiweAuthLocalStorage();
|
|
1383
|
+
if (ls) writePersistedSiweAuth(ls, storageKey, record);
|
|
1384
|
+
},
|
|
1385
|
+
remove: () => {
|
|
1386
|
+
const ls = getSiweAuthLocalStorage();
|
|
1387
|
+
if (ls) removePersistedSiweAuth(ls, storageKey);
|
|
925
1388
|
}
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
const
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
const res = await client.refreshJwtSession({ refresh_token: data.refreshToken });
|
|
1002
|
-
const refreshedAt = Date.now();
|
|
1003
|
-
client.setBearerToken(res.token);
|
|
1004
|
-
refreshDataRef.current = {
|
|
1005
|
-
refreshToken: res.refresh_token,
|
|
1006
|
-
refreshExpiresAt: refreshedAt + res.refresh_expires_in * 1e3
|
|
1007
|
-
};
|
|
1008
|
-
setTokens(
|
|
1009
|
-
(prev) => prev ? { ...prev, jwt_access_token: res.token, jwt_refresh_token: res.refresh_token } : prev
|
|
1010
|
-
);
|
|
1011
|
-
setAccessTokenExpiresAt(refreshedAt + res.expires_in * 1e3);
|
|
1012
|
-
} catch {
|
|
1013
|
-
clearSession();
|
|
1014
|
-
} finally {
|
|
1015
|
-
refreshInFlight.current = false;
|
|
1016
|
-
}
|
|
1017
|
-
}, [client, clearSession]);
|
|
1389
|
+
}),
|
|
1390
|
+
[storageKey]
|
|
1391
|
+
);
|
|
1392
|
+
const scopeInputsRef = useRef({ apiUrl, chainId });
|
|
1393
|
+
scopeInputsRef.current.apiUrl = apiUrl;
|
|
1394
|
+
scopeInputsRef.current.chainId = chainId;
|
|
1395
|
+
const wagmiContextRef = useRef(wagmiContext);
|
|
1396
|
+
wagmiContextRef.current = wagmiContext;
|
|
1397
|
+
const portsRef = useRef(null);
|
|
1398
|
+
if (!portsRef.current) {
|
|
1399
|
+
portsRef.current = {
|
|
1400
|
+
persistJwt,
|
|
1401
|
+
client,
|
|
1402
|
+
storage: storageAdapter,
|
|
1403
|
+
cache: { set: setCachedPrivateReadToken },
|
|
1404
|
+
react: {
|
|
1405
|
+
setSession,
|
|
1406
|
+
setTokens,
|
|
1407
|
+
setAccessTokenExpiresAt,
|
|
1408
|
+
setIsLoading,
|
|
1409
|
+
setIsHydrating,
|
|
1410
|
+
setError
|
|
1411
|
+
},
|
|
1412
|
+
makeScopeKey: (addr) => createScopeKey(scopeInputsRef.current.apiUrl, scopeInputsRef.current.chainId, addr)
|
|
1413
|
+
};
|
|
1414
|
+
}
|
|
1415
|
+
const ports = portsRef.current;
|
|
1416
|
+
ports.persistJwt = persistJwt;
|
|
1417
|
+
ports.client = client;
|
|
1418
|
+
ports.storage = storageAdapter;
|
|
1419
|
+
const ctrlRef = useRef(null);
|
|
1420
|
+
if (!ctrlRef.current) {
|
|
1421
|
+
ctrlRef.current = {
|
|
1422
|
+
config: { address, chainId, apiUrl, persistJwt },
|
|
1423
|
+
ports,
|
|
1424
|
+
api,
|
|
1425
|
+
signer: {
|
|
1426
|
+
signSiweMessage: async ({ account, message }) => {
|
|
1427
|
+
const ctx = wagmiContextRef.current;
|
|
1428
|
+
if (!ctx) throw new Error("WagmiProvider is required for SIWE auth");
|
|
1429
|
+
const walletClient = await getWalletClient(ctx);
|
|
1430
|
+
if (!walletClient) throw new Error("No wallet client available");
|
|
1431
|
+
return walletClient.signMessage({
|
|
1432
|
+
account: walletClient.account ?? account,
|
|
1433
|
+
message
|
|
1434
|
+
});
|
|
1435
|
+
}
|
|
1436
|
+
},
|
|
1437
|
+
loginInFlight: false,
|
|
1438
|
+
loginOwnerGeneration: -1,
|
|
1439
|
+
hydrateOwnerGeneration: -1,
|
|
1440
|
+
refreshPromise: null,
|
|
1441
|
+
getState: () => authRef.current,
|
|
1442
|
+
getSessionAddress: () => sessionRef.current?.address ?? null,
|
|
1443
|
+
dispatch: (event) => {
|
|
1444
|
+
authRef.current = reduceAuthLifecycle(authRef.current, event);
|
|
1445
|
+
}
|
|
1446
|
+
};
|
|
1447
|
+
}
|
|
1448
|
+
const ctrl = ctrlRef.current;
|
|
1449
|
+
ctrl.config = { address, chainId, apiUrl, persistJwt };
|
|
1450
|
+
ctrl.api = api;
|
|
1451
|
+
const login = useCallback(() => ctrlLogin(ctrl), [ctrl]);
|
|
1452
|
+
const logout = useCallback(() => ctrlLogout(ctrl), [ctrl]);
|
|
1453
|
+
const refreshAccessToken = useCallback(() => ctrlRefreshAccessToken(ctrl), [ctrl]);
|
|
1454
|
+
const resetSession = useCallback(() => ctrlReset(ctrl, false), [ctrl]);
|
|
1455
|
+
const clearSession = useCallback(() => ctrlReset(ctrl, ctrl.config.persistJwt), [ctrl]);
|
|
1456
|
+
const restoreSession = useCallback(
|
|
1457
|
+
(record) => ctrlRestoreSession(ctrl, record),
|
|
1458
|
+
[ctrl]
|
|
1459
|
+
);
|
|
1460
|
+
const hydrateViaRefresh = useCallback(
|
|
1461
|
+
(record, addr) => ctrlHydrateViaRefresh(ctrl, record, addr),
|
|
1462
|
+
[ctrl]
|
|
1463
|
+
);
|
|
1018
1464
|
useEffect(() => {
|
|
1019
1465
|
if (accessTokenExpiresAt == null) return;
|
|
1020
|
-
const delay = Math.max(accessTokenExpiresAt -
|
|
1466
|
+
const delay = Math.max(accessTokenExpiresAt - AUTH_CLOCK_SKEW_MS - Date.now(), 0);
|
|
1021
1467
|
const timer = setTimeout(() => {
|
|
1022
1468
|
void refreshAccessToken();
|
|
1023
1469
|
}, delay);
|
|
1024
1470
|
return () => clearTimeout(timer);
|
|
1025
1471
|
}, [accessTokenExpiresAt, refreshAccessToken]);
|
|
1472
|
+
const scopeRef = useRef(void 0);
|
|
1026
1473
|
useEffect(() => {
|
|
1027
|
-
|
|
1474
|
+
const prev = scopeRef.current;
|
|
1475
|
+
scopeRef.current = { apiUrl, chainId, client };
|
|
1476
|
+
const scopeChanged = !!prev && !(prev.apiUrl === apiUrl && prev.chainId === chainId && prev.client === client);
|
|
1477
|
+
if (scopeChanged) {
|
|
1478
|
+
ctrlReset(ctrl, false);
|
|
1479
|
+
}
|
|
1480
|
+
if (!persistJwt) return;
|
|
1028
1481
|
if (status === "connecting" || status === "reconnecting") return;
|
|
1029
|
-
if (!isConnected
|
|
1030
|
-
|
|
1031
|
-
|
|
1482
|
+
if (!isConnected || !address) return;
|
|
1483
|
+
if (ctrl.getState().hydratedAddress === address) return;
|
|
1484
|
+
ctrl.dispatch({ type: "setHydratedAddress", address });
|
|
1485
|
+
const action = resolveHydrationAction(storageAdapter.read(), address);
|
|
1486
|
+
switch (action.type) {
|
|
1487
|
+
case "restore":
|
|
1488
|
+
restoreSession(action.record);
|
|
1489
|
+
ctrl.dispatch({ type: "setAutoAttemptedAddress", address });
|
|
1490
|
+
break;
|
|
1491
|
+
case "refresh":
|
|
1492
|
+
void hydrateViaRefresh(action.record, address);
|
|
1493
|
+
break;
|
|
1494
|
+
case "remove":
|
|
1495
|
+
storageAdapter.remove();
|
|
1496
|
+
break;
|
|
1032
1497
|
}
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1498
|
+
}, [
|
|
1499
|
+
apiUrl,
|
|
1500
|
+
chainId,
|
|
1501
|
+
client,
|
|
1502
|
+
persistJwt,
|
|
1503
|
+
status,
|
|
1504
|
+
isConnected,
|
|
1505
|
+
address,
|
|
1506
|
+
storageAdapter,
|
|
1507
|
+
ctrl,
|
|
1508
|
+
restoreSession,
|
|
1509
|
+
hydrateViaRefresh
|
|
1510
|
+
]);
|
|
1511
|
+
useEffect(() => {
|
|
1512
|
+
const action = resolveAutoLoginEffectAction({
|
|
1513
|
+
status,
|
|
1514
|
+
isConnected,
|
|
1515
|
+
address: address ?? null,
|
|
1516
|
+
sessionAddress: session?.address ?? null,
|
|
1517
|
+
autoLogin,
|
|
1518
|
+
isLoading,
|
|
1519
|
+
isHydrating,
|
|
1520
|
+
autoAttemptedAddress: ctrl.getState().autoAttemptedAddress,
|
|
1521
|
+
authenticatingAddress: ctrl.getState().authenticatingAddress
|
|
1522
|
+
});
|
|
1523
|
+
switch (action.type) {
|
|
1524
|
+
case "wait":
|
|
1525
|
+
case "noop":
|
|
1526
|
+
return;
|
|
1527
|
+
case "reset-on-disconnect":
|
|
1528
|
+
resetSession();
|
|
1529
|
+
return;
|
|
1530
|
+
case "clear-on-mismatch":
|
|
1531
|
+
clearSession();
|
|
1532
|
+
return;
|
|
1533
|
+
case "auto-login":
|
|
1534
|
+
void login().catch(() => {
|
|
1535
|
+
});
|
|
1536
|
+
return;
|
|
1036
1537
|
}
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1538
|
+
}, [
|
|
1539
|
+
autoLogin,
|
|
1540
|
+
status,
|
|
1541
|
+
isConnected,
|
|
1542
|
+
address,
|
|
1543
|
+
session,
|
|
1544
|
+
isLoading,
|
|
1545
|
+
isHydrating,
|
|
1546
|
+
ctrl,
|
|
1547
|
+
login,
|
|
1548
|
+
clearSession,
|
|
1549
|
+
resetSession
|
|
1550
|
+
]);
|
|
1551
|
+
useEffect(() => {
|
|
1552
|
+
if (!persistJwt || typeof window === "undefined") return;
|
|
1553
|
+
function onStorage(event) {
|
|
1554
|
+
if (event.key !== storageKey) return;
|
|
1555
|
+
const currentAddress = resolveActiveSessionAddress(
|
|
1556
|
+
sessionRef.current?.address,
|
|
1557
|
+
ctrl.getState().currentRecord?.tokens.address,
|
|
1558
|
+
ctrl.getState().authenticatingAddress
|
|
1559
|
+
);
|
|
1560
|
+
const action = resolveStorageEvent(
|
|
1561
|
+
event.newValue,
|
|
1562
|
+
currentAddress,
|
|
1563
|
+
ctrl.getState().currentRecord?.updatedAt ?? null
|
|
1564
|
+
);
|
|
1565
|
+
switch (action.type) {
|
|
1566
|
+
case "logout":
|
|
1567
|
+
resetSession();
|
|
1568
|
+
if (currentAddress)
|
|
1569
|
+
ctrl.dispatch({ type: "setAutoAttemptedAddress", address: currentAddress });
|
|
1570
|
+
break;
|
|
1571
|
+
case "adopt":
|
|
1572
|
+
restoreSession(action.record);
|
|
1573
|
+
break;
|
|
1574
|
+
}
|
|
1041
1575
|
}
|
|
1042
|
-
|
|
1043
|
-
|
|
1576
|
+
window.addEventListener("storage", onStorage);
|
|
1577
|
+
return () => window.removeEventListener("storage", onStorage);
|
|
1578
|
+
}, [persistJwt, storageKey, ctrl, restoreSession, resetSession]);
|
|
1579
|
+
useEffect(() => {
|
|
1580
|
+
const prev = prevPersistJwtRef.current;
|
|
1581
|
+
prevPersistJwtRef.current = persistJwt;
|
|
1582
|
+
if (!(prev === true && !persistJwt)) return;
|
|
1583
|
+
ctrl.dispatch({ type: "clearCurrentRecord" });
|
|
1584
|
+
storageAdapter.remove();
|
|
1585
|
+
}, [persistJwt, storageAdapter, ctrl]);
|
|
1586
|
+
useEffect(() => {
|
|
1587
|
+
sessionRef.current = session;
|
|
1588
|
+
}, [session]);
|
|
1589
|
+
return useMemo(
|
|
1044
1590
|
() => ({
|
|
1045
1591
|
isAuthenticated: !!session,
|
|
1046
|
-
isLoading,
|
|
1592
|
+
isLoading: isLoading || isHydrating,
|
|
1593
|
+
isHydrating,
|
|
1047
1594
|
error,
|
|
1048
1595
|
session,
|
|
1049
1596
|
accessToken: tokens?.jwt_access_token,
|
|
@@ -1051,8 +1598,38 @@ function SiweAuthProvider({
|
|
|
1051
1598
|
login,
|
|
1052
1599
|
logout
|
|
1053
1600
|
}),
|
|
1054
|
-
[session, isLoading, error, tokens, login, logout]
|
|
1601
|
+
[session, isLoading, isHydrating, error, tokens, login, logout]
|
|
1602
|
+
);
|
|
1603
|
+
}
|
|
1604
|
+
var SiweAuthContext = createContext(null);
|
|
1605
|
+
function SiweAuthProvider({
|
|
1606
|
+
children,
|
|
1607
|
+
client,
|
|
1608
|
+
networkConfig,
|
|
1609
|
+
autoLogin = true,
|
|
1610
|
+
persistJwt = false
|
|
1611
|
+
}) {
|
|
1612
|
+
const storageKey = useMemo(
|
|
1613
|
+
() => createSiweAuthStorageKey(networkConfig.apiUrl, networkConfig.chainId),
|
|
1614
|
+
[networkConfig.apiUrl, networkConfig.chainId]
|
|
1615
|
+
);
|
|
1616
|
+
const lifecycleClient = useMemo(
|
|
1617
|
+
() => ({
|
|
1618
|
+
setBearerToken: (t) => client.setBearerToken(t),
|
|
1619
|
+
clearBearerToken: () => client.clearBearerToken(),
|
|
1620
|
+
clearPrivateReadToken: () => client.clearPrivateReadToken()
|
|
1621
|
+
}),
|
|
1622
|
+
[client]
|
|
1055
1623
|
);
|
|
1624
|
+
const value = useSiweAuthLifecycle({
|
|
1625
|
+
storageKey,
|
|
1626
|
+
apiUrl: networkConfig.apiUrl,
|
|
1627
|
+
chainId: networkConfig.chainId,
|
|
1628
|
+
persistJwt,
|
|
1629
|
+
autoLogin,
|
|
1630
|
+
client: lifecycleClient,
|
|
1631
|
+
api: client
|
|
1632
|
+
});
|
|
1056
1633
|
return /* @__PURE__ */ jsx(SiweAuthContext.Provider, { value, children });
|
|
1057
1634
|
}
|
|
1058
1635
|
function useSiweAuth() {
|
|
@@ -1364,6 +1941,7 @@ function PrivanaProvider({
|
|
|
1364
1941
|
client,
|
|
1365
1942
|
networkConfig,
|
|
1366
1943
|
autoLogin: typeof siweAuth === "object" ? siweAuth.autoLogin : void 0,
|
|
1944
|
+
persistJwt: typeof siweAuth === "object" ? siweAuth.persistJwt : void 0,
|
|
1367
1945
|
children
|
|
1368
1946
|
}
|
|
1369
1947
|
) : children });
|
|
@@ -1434,6 +2012,47 @@ function removeBrowserStorageItem(key) {
|
|
|
1434
2012
|
}
|
|
1435
2013
|
}
|
|
1436
2014
|
}
|
|
2015
|
+
function canUseSharedBrowserStorage() {
|
|
2016
|
+
const storage = storageCandidate("localStorage");
|
|
2017
|
+
if (!storage) return false;
|
|
2018
|
+
const probeKey = "privana:shared-storage-probe";
|
|
2019
|
+
try {
|
|
2020
|
+
storage.setItem(probeKey, "1");
|
|
2021
|
+
storage.removeItem(probeKey);
|
|
2022
|
+
return true;
|
|
2023
|
+
} catch {
|
|
2024
|
+
return false;
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
function setSharedBrowserStorageItem(key, value) {
|
|
2028
|
+
const storage = storageCandidate("localStorage");
|
|
2029
|
+
if (!storage) return false;
|
|
2030
|
+
try {
|
|
2031
|
+
storage.setItem(key, value);
|
|
2032
|
+
} catch {
|
|
2033
|
+
return false;
|
|
2034
|
+
}
|
|
2035
|
+
try {
|
|
2036
|
+
storageCandidate("sessionStorage")?.removeItem(key);
|
|
2037
|
+
} catch {
|
|
2038
|
+
}
|
|
2039
|
+
return true;
|
|
2040
|
+
}
|
|
2041
|
+
function getSharedBrowserStorageItem(key) {
|
|
2042
|
+
try {
|
|
2043
|
+
return storageCandidate("localStorage")?.getItem(key) ?? null;
|
|
2044
|
+
} catch {
|
|
2045
|
+
return null;
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
function removeSharedBrowserStorageItem(key) {
|
|
2049
|
+
for (const storage of storageCandidates()) {
|
|
2050
|
+
try {
|
|
2051
|
+
storage.removeItem(key);
|
|
2052
|
+
} catch {
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
1437
2056
|
|
|
1438
2057
|
// src/sdk/hooks/pending-lock.ts
|
|
1439
2058
|
var DEFAULT_LOCK_DURATION_SECONDS = 259200;
|
|
@@ -1449,6 +2068,25 @@ function applyLockBuffer(amount, buffer = DEFAULT_ONRAMP_LOCK_BUFFER) {
|
|
|
1449
2068
|
function clampLockAmount(amount, maxAmount) {
|
|
1450
2069
|
return maxAmount !== void 0 && maxAmount < amount ? maxAmount : amount;
|
|
1451
2070
|
}
|
|
2071
|
+
function requireServiceAddress(serviceAddress) {
|
|
2072
|
+
if (!serviceAddress) {
|
|
2073
|
+
throw new Error("Service address not configured");
|
|
2074
|
+
}
|
|
2075
|
+
return serviceAddress;
|
|
2076
|
+
}
|
|
2077
|
+
function requireDepositLockOwner(walletAddress, beneficiary) {
|
|
2078
|
+
if (!walletAddress) throw new Error("No wallet connected");
|
|
2079
|
+
if (!beneficiary) throw new Error("No authenticated deposit account");
|
|
2080
|
+
if (walletAddress.toLowerCase() !== beneficiary.toLowerCase()) {
|
|
2081
|
+
throw new Error("Connected wallet does not match the authenticated deposit account");
|
|
2082
|
+
}
|
|
2083
|
+
return beneficiary;
|
|
2084
|
+
}
|
|
2085
|
+
function walletClientAccountAddress(walletClient) {
|
|
2086
|
+
const account = walletClient.account;
|
|
2087
|
+
if (!account) return void 0;
|
|
2088
|
+
return typeof account === "string" ? account : account.address;
|
|
2089
|
+
}
|
|
1452
2090
|
async function createSignedLockRequest({
|
|
1453
2091
|
client,
|
|
1454
2092
|
walletClient,
|
|
@@ -1462,6 +2100,10 @@ async function createSignedLockRequest({
|
|
|
1462
2100
|
if (amount <= 0n) {
|
|
1463
2101
|
throw new Error("Lock amount must be positive");
|
|
1464
2102
|
}
|
|
2103
|
+
const signerAddress = walletClientAccountAddress(walletClient);
|
|
2104
|
+
if (!signerAddress || signerAddress.toLowerCase() !== userAddress.toLowerCase()) {
|
|
2105
|
+
throw new Error("Connected wallet does not match the authenticated deposit account");
|
|
2106
|
+
}
|
|
1465
2107
|
const expiry = BigInt(Math.floor(Date.now() / 1e3) + lockDuration);
|
|
1466
2108
|
const { nonce } = await client.getLockNonce(userAddress);
|
|
1467
2109
|
const signature = await signLockMessage({
|
|
@@ -1498,13 +2140,15 @@ var PostDepositLockError = class _PostDepositLockError extends Error {
|
|
|
1498
2140
|
this.signedAmount = signedAmount;
|
|
1499
2141
|
this.creditedAmount = creditedAmount;
|
|
1500
2142
|
this.name = "PostDepositLockError";
|
|
2143
|
+
this.submissionMayHaveSucceeded = options?.submissionMayHaveSucceeded ?? false;
|
|
1501
2144
|
Object.setPrototypeOf(this, _PostDepositLockError.prototype);
|
|
1502
2145
|
}
|
|
1503
2146
|
};
|
|
1504
2147
|
async function submitPendingLock({
|
|
1505
2148
|
client,
|
|
1506
2149
|
payload,
|
|
1507
|
-
creditedAmount
|
|
2150
|
+
creditedAmount,
|
|
2151
|
+
beforeSubmit
|
|
1508
2152
|
}) {
|
|
1509
2153
|
let signedAmount;
|
|
1510
2154
|
try {
|
|
@@ -1528,13 +2172,14 @@ async function submitPendingLock({
|
|
|
1528
2172
|
}
|
|
1529
2173
|
if (creditedAmount !== void 0 && creditedAmount < signedAmount) {
|
|
1530
2174
|
throw new PostDepositLockError(
|
|
1531
|
-
|
|
2175
|
+
"Credited amount is below the signed lock amount",
|
|
1532
2176
|
"credited-below-signed",
|
|
1533
2177
|
signedAmount,
|
|
1534
2178
|
creditedAmount
|
|
1535
2179
|
);
|
|
1536
2180
|
}
|
|
1537
2181
|
try {
|
|
2182
|
+
beforeSubmit?.();
|
|
1538
2183
|
return await client.lockFunds(payload);
|
|
1539
2184
|
} catch (err) {
|
|
1540
2185
|
throw new PostDepositLockError(
|
|
@@ -1579,7 +2224,6 @@ function clearPendingLock(userAddress, correlationId) {
|
|
|
1579
2224
|
}
|
|
1580
2225
|
var INITIAL_AUTH_BACKOFF_MS = 5e3;
|
|
1581
2226
|
var MAX_AUTH_BACKOFF_MS = 6e4;
|
|
1582
|
-
var DEFAULT_SIWE_AUTH_VALIDITY_MS = 24 * 60 * 60 * 1e3;
|
|
1583
2227
|
var privateReadFailureCache = /* @__PURE__ */ new Map();
|
|
1584
2228
|
var privateReadInflight = /* @__PURE__ */ new Map();
|
|
1585
2229
|
async function executeHostedAuthPrivateReadRequest({
|
|
@@ -1604,13 +2248,13 @@ async function executeHostedAuthPrivateReadRequest({
|
|
|
1604
2248
|
};
|
|
1605
2249
|
await ensureHostedAuth(false);
|
|
1606
2250
|
try {
|
|
1607
|
-
return await request();
|
|
2251
|
+
return await request(client);
|
|
1608
2252
|
} catch (error) {
|
|
1609
2253
|
if (!(error instanceof AccountingApiError) || error.statusCode !== 401) {
|
|
1610
2254
|
throw error;
|
|
1611
2255
|
}
|
|
1612
2256
|
await ensureHostedAuth(true);
|
|
1613
|
-
return request();
|
|
2257
|
+
return request(client);
|
|
1614
2258
|
}
|
|
1615
2259
|
}
|
|
1616
2260
|
function clearPrivateReadScope(scopeKey, client) {
|
|
@@ -1618,6 +2262,24 @@ function clearPrivateReadScope(scopeKey, client) {
|
|
|
1618
2262
|
privateReadFailureCache.delete(scopeKey);
|
|
1619
2263
|
client.clearPrivateReadToken();
|
|
1620
2264
|
}
|
|
2265
|
+
async function executeSiwePrivateReadRequest({
|
|
2266
|
+
client,
|
|
2267
|
+
scopeKey,
|
|
2268
|
+
getToken,
|
|
2269
|
+
request
|
|
2270
|
+
}) {
|
|
2271
|
+
const run = (token2) => request(client.withPrivateReadToken(token2));
|
|
2272
|
+
const token = await getToken(false);
|
|
2273
|
+
try {
|
|
2274
|
+
return await run(token);
|
|
2275
|
+
} catch (error) {
|
|
2276
|
+
if (!(error instanceof AccountingApiError) || error.statusCode !== 401) {
|
|
2277
|
+
throw error;
|
|
2278
|
+
}
|
|
2279
|
+
clearPrivateReadScope(scopeKey, client);
|
|
2280
|
+
return run(await getToken(true));
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
1621
2283
|
function recordPrivateReadFailure(scopeKey) {
|
|
1622
2284
|
const previous = privateReadFailureCache.get(scopeKey);
|
|
1623
2285
|
const backoffMs = Math.min(
|
|
@@ -1664,46 +2326,26 @@ function usePrivateReadRequest() {
|
|
|
1664
2326
|
if (!walletAddress) {
|
|
1665
2327
|
throw new Error("No wallet connected");
|
|
1666
2328
|
}
|
|
1667
|
-
const walletClient = await getWalletClient(wagmiContext);
|
|
1668
|
-
if (!walletClient) {
|
|
1669
|
-
throw new Error("No wallet client available");
|
|
1670
|
-
}
|
|
1671
2329
|
const apiUrl = networkConfig.apiUrl;
|
|
1672
2330
|
const scopeKey = createScopeKey(apiUrl, networkConfig.chainId, walletAddress);
|
|
1673
2331
|
const getToken = async (forceRefresh) => {
|
|
1674
2332
|
const inflight = privateReadInflight.get(scopeKey);
|
|
1675
|
-
if (inflight)
|
|
1676
|
-
const token = await inflight;
|
|
1677
|
-
client.setPrivateReadToken(token);
|
|
1678
|
-
return token;
|
|
1679
|
-
}
|
|
2333
|
+
if (inflight) return inflight;
|
|
1680
2334
|
if (!forceRefresh) {
|
|
1681
2335
|
const cached = getCachedPrivateReadToken(scopeKey);
|
|
1682
|
-
if (cached)
|
|
1683
|
-
client.setPrivateReadToken(cached);
|
|
1684
|
-
return cached;
|
|
1685
|
-
}
|
|
2336
|
+
if (cached) return cached;
|
|
1686
2337
|
}
|
|
1687
2338
|
ensureFailureBackoff(scopeKey);
|
|
1688
2339
|
const authPromise = (async () => {
|
|
1689
2340
|
try {
|
|
1690
|
-
const
|
|
1691
|
-
|
|
1692
|
-
client
|
|
1693
|
-
|
|
1694
|
-
const
|
|
1695
|
-
const expirationTime = new Date(issuedAt.getTime() + DEFAULT_SIWE_AUTH_VALIDITY_MS);
|
|
1696
|
-
const uri = typeof window !== "undefined" && window.location.origin ? window.location.origin : apiUrl;
|
|
1697
|
-
const message = createSiweMessage({
|
|
2341
|
+
const walletClient = await getWalletClient(wagmiContext);
|
|
2342
|
+
if (!walletClient) {
|
|
2343
|
+
throw new Error("No wallet client available");
|
|
2344
|
+
}
|
|
2345
|
+
const { message, expirationTime } = await buildSiweLoginMessage(client, {
|
|
1698
2346
|
address: walletAddress,
|
|
1699
2347
|
chainId: networkConfig.chainId,
|
|
1700
|
-
|
|
1701
|
-
expirationTime,
|
|
1702
|
-
issuedAt,
|
|
1703
|
-
nonce: nonceResponse.nonce,
|
|
1704
|
-
statement: buildSiweStatement(networkConfig.chainId),
|
|
1705
|
-
uri,
|
|
1706
|
-
version: "1"
|
|
2348
|
+
apiUrl
|
|
1707
2349
|
});
|
|
1708
2350
|
const signature = await walletClient.signMessage({
|
|
1709
2351
|
account: walletClient.account ?? walletAddress,
|
|
@@ -1715,7 +2357,6 @@ function usePrivateReadRequest() {
|
|
|
1715
2357
|
});
|
|
1716
2358
|
setCachedPrivateReadToken(scopeKey, login.siwe_token, expirationTime.getTime());
|
|
1717
2359
|
privateReadFailureCache.delete(scopeKey);
|
|
1718
|
-
client.setPrivateReadToken(login.siwe_token);
|
|
1719
2360
|
return login.siwe_token;
|
|
1720
2361
|
} catch (error) {
|
|
1721
2362
|
const authError = error instanceof Error ? error : new Error("Failed to authenticate private reads");
|
|
@@ -1729,17 +2370,7 @@ function usePrivateReadRequest() {
|
|
|
1729
2370
|
privateReadInflight.set(scopeKey, authPromise);
|
|
1730
2371
|
return authPromise;
|
|
1731
2372
|
};
|
|
1732
|
-
|
|
1733
|
-
try {
|
|
1734
|
-
return await request();
|
|
1735
|
-
} catch (error) {
|
|
1736
|
-
if (!(error instanceof AccountingApiError) || error.statusCode !== 401) {
|
|
1737
|
-
throw error;
|
|
1738
|
-
}
|
|
1739
|
-
clearPrivateReadScope(scopeKey, client);
|
|
1740
|
-
await getToken(true);
|
|
1741
|
-
return request();
|
|
1742
|
-
}
|
|
2373
|
+
return executeSiwePrivateReadRequest({ client, scopeKey, getToken, request });
|
|
1743
2374
|
},
|
|
1744
2375
|
[
|
|
1745
2376
|
client,
|
|
@@ -1766,7 +2397,6 @@ function usePrivateReadRequest() {
|
|
|
1766
2397
|
|
|
1767
2398
|
// src/sdk/hooks/use-deposit-verification.ts
|
|
1768
2399
|
function useDepositVerification(options = {}) {
|
|
1769
|
-
const { client } = usePrivanaContext();
|
|
1770
2400
|
const queryClient = useQueryClient();
|
|
1771
2401
|
const { executePrivateRead } = usePrivateReadRequest();
|
|
1772
2402
|
const pollInterval = options.pollInterval ?? 5e3;
|
|
@@ -1775,6 +2405,7 @@ function useDepositVerification(options = {}) {
|
|
|
1775
2405
|
const [isVerifying, setIsVerifying] = useState(false);
|
|
1776
2406
|
const [didTimeout, setDidTimeout] = useState(false);
|
|
1777
2407
|
const [verificationFailed, setVerificationFailed] = useState(false);
|
|
2408
|
+
const [canCheckAnotherTransfer, setCanCheckAnotherTransfer] = useState(false);
|
|
1778
2409
|
const [error, setError] = useState(null);
|
|
1779
2410
|
const [txHash, setTxHash] = useState();
|
|
1780
2411
|
const generationRef = useRef(0);
|
|
@@ -1810,14 +2441,16 @@ function useDepositVerification(options = {}) {
|
|
|
1810
2441
|
const isStale = () => generation !== generationRef.current;
|
|
1811
2442
|
const { hash, chainId, amount, logIndex } = ctx;
|
|
1812
2443
|
setVerificationFailed(false);
|
|
2444
|
+
setCanCheckAnotherTransfer(false);
|
|
1813
2445
|
setError(null);
|
|
1814
2446
|
setDidTimeout(false);
|
|
1815
2447
|
setIsVerifying(true);
|
|
1816
2448
|
const pollStartTime = Date.now();
|
|
1817
|
-
const markVerificationFailed = (err) => {
|
|
2449
|
+
const markVerificationFailed = (err, canCheckAnother = false) => {
|
|
1818
2450
|
setIsVerifying(false);
|
|
1819
2451
|
setError(err);
|
|
1820
2452
|
setVerificationFailed(true);
|
|
2453
|
+
setCanCheckAnotherTransfer(canCheckAnother);
|
|
1821
2454
|
onErrorRef.current?.(err);
|
|
1822
2455
|
};
|
|
1823
2456
|
const markVerificationTimedOut = () => {
|
|
@@ -1833,7 +2466,7 @@ function useDepositVerification(options = {}) {
|
|
|
1833
2466
|
if (isStale()) return;
|
|
1834
2467
|
try {
|
|
1835
2468
|
const result = await executePrivateRead(
|
|
1836
|
-
() =>
|
|
2469
|
+
(readClient) => readClient.checkDeposit({
|
|
1837
2470
|
chain_id: chainId,
|
|
1838
2471
|
tx_hash: hash,
|
|
1839
2472
|
amount: amount.toString(),
|
|
@@ -1868,11 +2501,12 @@ function useDepositVerification(options = {}) {
|
|
|
1868
2501
|
}
|
|
1869
2502
|
if (isStale()) return;
|
|
1870
2503
|
if (triggerResult.status === "credited") {
|
|
2504
|
+
const creditedAmount = creditedAmountFromResponse(triggerResult, amount);
|
|
1871
2505
|
setIsVerifying(false);
|
|
1872
2506
|
verificationContextRef.current = null;
|
|
1873
2507
|
queryClient.invalidateQueries({ queryKey: ["accounting-balance"] });
|
|
1874
2508
|
queryClient.invalidateQueries({ queryKey: ["accounting-history"] });
|
|
1875
|
-
onCreditedRef.current?.(hash, triggerResult);
|
|
2509
|
+
onCreditedRef.current?.(hash, triggerResult, creditedAmount);
|
|
1876
2510
|
return;
|
|
1877
2511
|
}
|
|
1878
2512
|
if (triggerResult.status === "error") {
|
|
@@ -1892,16 +2526,29 @@ function useDepositVerification(options = {}) {
|
|
|
1892
2526
|
return true;
|
|
1893
2527
|
}
|
|
1894
2528
|
try {
|
|
1895
|
-
const result = await executePrivateRead(
|
|
2529
|
+
const result = await executePrivateRead(
|
|
2530
|
+
(readClient) => readClient.getDepositStatus(depositId)
|
|
2531
|
+
);
|
|
1896
2532
|
if (isStale()) return true;
|
|
1897
2533
|
consecutiveFailures = 0;
|
|
1898
2534
|
if (result.status === "credited") {
|
|
2535
|
+
let creditedAmount;
|
|
2536
|
+
try {
|
|
2537
|
+
creditedAmount = creditedAmountFromResponse(result, amount);
|
|
2538
|
+
} catch (err) {
|
|
2539
|
+
stopPolling();
|
|
2540
|
+
markVerificationFailed(
|
|
2541
|
+
err instanceof Error ? err : new Error("Deposit credited amount is invalid"),
|
|
2542
|
+
false
|
|
2543
|
+
);
|
|
2544
|
+
return true;
|
|
2545
|
+
}
|
|
1899
2546
|
stopPolling();
|
|
1900
2547
|
setIsVerifying(false);
|
|
1901
2548
|
verificationContextRef.current = null;
|
|
1902
2549
|
queryClient.invalidateQueries({ queryKey: ["accounting-balance"] });
|
|
1903
2550
|
queryClient.invalidateQueries({ queryKey: ["accounting-history"] });
|
|
1904
|
-
onCreditedRef.current?.(hash, result);
|
|
2551
|
+
onCreditedRef.current?.(hash, result, creditedAmount);
|
|
1905
2552
|
return true;
|
|
1906
2553
|
}
|
|
1907
2554
|
if (result.status === "error") {
|
|
@@ -1933,20 +2580,11 @@ function useDepositVerification(options = {}) {
|
|
|
1933
2580
|
} catch (err) {
|
|
1934
2581
|
if (isStale()) return;
|
|
1935
2582
|
stopPolling();
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
);
|
|
2583
|
+
const error2 = err instanceof Error ? err : new Error("Deposit verification failed");
|
|
2584
|
+
markVerificationFailed(error2, isDefinitiveCandidateFailure(error2));
|
|
1939
2585
|
}
|
|
1940
2586
|
},
|
|
1941
|
-
[
|
|
1942
|
-
client,
|
|
1943
|
-
executePrivateRead,
|
|
1944
|
-
finalityRetryInterval,
|
|
1945
|
-
pollInterval,
|
|
1946
|
-
pollTimeout,
|
|
1947
|
-
queryClient,
|
|
1948
|
-
stopPolling
|
|
1949
|
-
]
|
|
2587
|
+
[executePrivateRead, finalityRetryInterval, pollInterval, pollTimeout, queryClient, stopPolling]
|
|
1950
2588
|
);
|
|
1951
2589
|
const verify = useCallback(
|
|
1952
2590
|
async (ctx) => {
|
|
@@ -1977,12 +2615,14 @@ function useDepositVerification(options = {}) {
|
|
|
1977
2615
|
setIsVerifying(false);
|
|
1978
2616
|
setDidTimeout(false);
|
|
1979
2617
|
setVerificationFailed(false);
|
|
2618
|
+
setCanCheckAnotherTransfer(false);
|
|
1980
2619
|
setError(null);
|
|
1981
2620
|
}, [stopPolling]);
|
|
1982
2621
|
return {
|
|
1983
2622
|
isVerifying,
|
|
1984
2623
|
didTimeout,
|
|
1985
2624
|
verificationFailed,
|
|
2625
|
+
canCheckAnotherTransfer,
|
|
1986
2626
|
error,
|
|
1987
2627
|
txHash,
|
|
1988
2628
|
verify,
|
|
@@ -1990,6 +2630,19 @@ function useDepositVerification(options = {}) {
|
|
|
1990
2630
|
reset
|
|
1991
2631
|
};
|
|
1992
2632
|
}
|
|
2633
|
+
function creditedAmountFromResponse(response, requestedAmount) {
|
|
2634
|
+
if (response.amount == null) return requestedAmount;
|
|
2635
|
+
try {
|
|
2636
|
+
const amount = BigInt(response.amount);
|
|
2637
|
+
if (amount <= 0n) throw new Error("non-positive amount");
|
|
2638
|
+
return amount;
|
|
2639
|
+
} catch (err) {
|
|
2640
|
+
throw new Error("Deposit API returned an invalid credited amount", { cause: err });
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
function isDefinitiveCandidateFailure(error) {
|
|
2644
|
+
return error instanceof AccountingApiError && error.statusCode === 400;
|
|
2645
|
+
}
|
|
1993
2646
|
function sleep(ms) {
|
|
1994
2647
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1995
2648
|
}
|
|
@@ -2431,7 +3084,9 @@ function useFiatOnRamp(options) {
|
|
|
2431
3084
|
const { address } = useAccount();
|
|
2432
3085
|
const { data: walletClient } = useWalletClient();
|
|
2433
3086
|
const { client, enabledTokens, networkConfig, serviceAddress } = usePrivanaContext();
|
|
2434
|
-
const { executePrivateRead, privateReadReady } = usePrivateReadRequest();
|
|
3087
|
+
const { executePrivateRead, privateReadAddress, privateReadReady } = usePrivateReadRequest();
|
|
3088
|
+
const privateReadAddressRef = useRef(privateReadAddress);
|
|
3089
|
+
privateReadAddressRef.current = privateReadAddress;
|
|
2435
3090
|
const { ensureCorrectChain } = useEnsureCorrectChain();
|
|
2436
3091
|
const wagmiConfig = useConfig();
|
|
2437
3092
|
const queryClient = useQueryClient();
|
|
@@ -2453,7 +3108,6 @@ function useFiatOnRamp(options) {
|
|
|
2453
3108
|
const activeIntentIdRef = useRef(null);
|
|
2454
3109
|
const activeVerificationRecordRef = useRef(null);
|
|
2455
3110
|
const activeVerificationKeyRef = useRef(null);
|
|
2456
|
-
const activeVerificationAmountRef = useRef(null);
|
|
2457
3111
|
const lockOwnerRef = useRef(null);
|
|
2458
3112
|
const triggeredVerificationKeysRef = useRef(/* @__PURE__ */ new Set());
|
|
2459
3113
|
const activeVerificationDoneRef = useRef(null);
|
|
@@ -2502,7 +3156,7 @@ function useFiatOnRamp(options) {
|
|
|
2502
3156
|
void (async () => {
|
|
2503
3157
|
try {
|
|
2504
3158
|
emitDebug("deposit-address:request");
|
|
2505
|
-
const resp = await executePrivateRead(() =>
|
|
3159
|
+
const resp = await executePrivateRead((readClient) => readClient.getDepositAddress());
|
|
2506
3160
|
if (cancelled) return;
|
|
2507
3161
|
setDepositAddress(resp.deposit_address);
|
|
2508
3162
|
const token = enabledTokens.find((t) => t.id.toLowerCase() === tokenId.toLowerCase());
|
|
@@ -2532,7 +3186,9 @@ function useFiatOnRamp(options) {
|
|
|
2532
3186
|
}
|
|
2533
3187
|
try {
|
|
2534
3188
|
emitDebug("pending:request");
|
|
2535
|
-
const { pending: rows } = await executePrivateRead(
|
|
3189
|
+
const { pending: rows } = await executePrivateRead(
|
|
3190
|
+
(readClient) => readClient.getPendingOnRamps()
|
|
3191
|
+
);
|
|
2536
3192
|
setPending(rows);
|
|
2537
3193
|
emitDebug("pending:success", {
|
|
2538
3194
|
count: rows.length,
|
|
@@ -2542,7 +3198,7 @@ function useFiatOnRamp(options) {
|
|
|
2542
3198
|
emitDebug("pending:error", errorPayload(err));
|
|
2543
3199
|
console.warn("Failed to load pending on-ramps:", err);
|
|
2544
3200
|
}
|
|
2545
|
-
}, [
|
|
3201
|
+
}, [emitDebug, executePrivateRead, privateReadReady]);
|
|
2546
3202
|
useEffect(() => {
|
|
2547
3203
|
refreshPending();
|
|
2548
3204
|
}, [refreshPending]);
|
|
@@ -2552,13 +3208,12 @@ function useFiatOnRamp(options) {
|
|
|
2552
3208
|
if (key) triggeredVerificationKeysRef.current.delete(key);
|
|
2553
3209
|
activeVerificationKeyRef.current = null;
|
|
2554
3210
|
activeVerificationRecordRef.current = null;
|
|
2555
|
-
activeVerificationAmountRef.current = null;
|
|
2556
3211
|
setActiveVerificationId(null);
|
|
2557
3212
|
activeVerificationDoneRef.current?.();
|
|
2558
3213
|
activeVerificationDoneRef.current = null;
|
|
2559
3214
|
}, []);
|
|
2560
3215
|
const submitPendingLockAfterCredit = useCallback(
|
|
2561
|
-
async (transactionId, userAddress) => {
|
|
3216
|
+
async (transactionId, userAddress, creditedAmount) => {
|
|
2562
3217
|
const signedLock = loadPendingLock(userAddress, transactionId);
|
|
2563
3218
|
if (!signedLock) {
|
|
2564
3219
|
clearPendingLock(userAddress, transactionId);
|
|
@@ -2571,7 +3226,6 @@ function useFiatOnRamp(options) {
|
|
|
2571
3226
|
(onLockFailedRef.current ?? onErrorRef.current)?.(error2);
|
|
2572
3227
|
return;
|
|
2573
3228
|
}
|
|
2574
|
-
const creditedAmount = activeVerificationAmountRef.current ?? void 0;
|
|
2575
3229
|
try {
|
|
2576
3230
|
const result = await submitPendingLock({ client, payload: signedLock, creditedAmount });
|
|
2577
3231
|
queryClient.invalidateQueries({ queryKey: ["accounting-balance"] });
|
|
@@ -2617,7 +3271,7 @@ function useFiatOnRamp(options) {
|
|
|
2617
3271
|
});
|
|
2618
3272
|
setFinalityProgress((prev) => ({ ...prev, [record.transaction_id]: message }));
|
|
2619
3273
|
},
|
|
2620
|
-
onCredited: (depositTxHash) => {
|
|
3274
|
+
onCredited: (depositTxHash, _response, creditedAmount) => {
|
|
2621
3275
|
const record = activeVerificationRecordRef.current;
|
|
2622
3276
|
const verificationKey = record ? getOnRampVerificationKey(record) : null;
|
|
2623
3277
|
emitDebug("verification:credited", {
|
|
@@ -2634,9 +3288,9 @@ function useFiatOnRamp(options) {
|
|
|
2634
3288
|
delete next[record.transaction_id];
|
|
2635
3289
|
return next;
|
|
2636
3290
|
});
|
|
2637
|
-
const lockOwner = lockOwnerRef.current ??
|
|
3291
|
+
const lockOwner = lockOwnerRef.current ?? privateReadAddress;
|
|
2638
3292
|
if (lockOwner) {
|
|
2639
|
-
void submitPendingLockAfterCredit(record.transaction_id, lockOwner);
|
|
3293
|
+
void submitPendingLockAfterCredit(record.transaction_id, lockOwner, creditedAmount);
|
|
2640
3294
|
} else if (postDepositLock) {
|
|
2641
3295
|
emitDebug("lock:owner-unavailable", { transactionId: record.transaction_id });
|
|
2642
3296
|
(onLockFailedRef.current ?? onErrorRef.current)?.(
|
|
@@ -2655,7 +3309,7 @@ function useFiatOnRamp(options) {
|
|
|
2655
3309
|
depositTxHash
|
|
2656
3310
|
});
|
|
2657
3311
|
const updated = await executePrivateRead(
|
|
2658
|
-
() =>
|
|
3312
|
+
(readClient) => readClient.updateOnRamp(record.transaction_id, {
|
|
2659
3313
|
deposit_tx_hash: depositTxHash
|
|
2660
3314
|
})
|
|
2661
3315
|
);
|
|
@@ -2716,8 +3370,10 @@ function useFiatOnRamp(options) {
|
|
|
2716
3370
|
if (!token) throw new Error(`Unknown token: ${tokenId}`);
|
|
2717
3371
|
if (!depositAddress) throw new Error("Privana deposit address is not ready");
|
|
2718
3372
|
let lockAmount;
|
|
3373
|
+
let lockOwner;
|
|
2719
3374
|
if (postDepositLock) {
|
|
2720
3375
|
if (!address || !walletClient) throw new Error("Wallet not connected");
|
|
3376
|
+
lockOwner = requireDepositLockOwner(address, privateReadAddress);
|
|
2721
3377
|
if (!quoteCurrencyAmount) {
|
|
2722
3378
|
throw new Error(
|
|
2723
3379
|
"postDepositLock requires quoteCurrencyAmount to derive the lock amount"
|
|
@@ -2746,7 +3402,7 @@ function useFiatOnRamp(options) {
|
|
|
2746
3402
|
depositAddress
|
|
2747
3403
|
});
|
|
2748
3404
|
const record = await executePrivateRead(
|
|
2749
|
-
() =>
|
|
3405
|
+
(readClient) => readClient.createOnRampIntent({
|
|
2750
3406
|
wallet_address: depositAddress,
|
|
2751
3407
|
token_id: tokenId,
|
|
2752
3408
|
chain_id: token.chainId,
|
|
@@ -2755,22 +3411,25 @@ function useFiatOnRamp(options) {
|
|
|
2755
3411
|
base_currency_amount: baseCurrencyAmount
|
|
2756
3412
|
})
|
|
2757
3413
|
);
|
|
2758
|
-
if (postDepositLock &&
|
|
3414
|
+
if (postDepositLock && lockOwner && lockAmount !== void 0) {
|
|
2759
3415
|
const signingWalletClient = await getWalletClient3(wagmiConfig, {
|
|
2760
3416
|
chainId: networkConfig.chainId
|
|
2761
3417
|
});
|
|
2762
3418
|
const signedLock = await createSignedLockRequest({
|
|
2763
3419
|
client,
|
|
2764
3420
|
walletClient: signingWalletClient,
|
|
2765
|
-
userAddress:
|
|
3421
|
+
userAddress: lockOwner,
|
|
2766
3422
|
networkConfig,
|
|
2767
3423
|
serviceAddress: requireServiceAddress(postDepositLock.serviceAddress ?? serviceAddress),
|
|
2768
3424
|
tokenId,
|
|
2769
3425
|
amount: lockAmount,
|
|
2770
3426
|
lockDuration: postDepositLock.lockDuration
|
|
2771
3427
|
});
|
|
2772
|
-
|
|
2773
|
-
|
|
3428
|
+
if (privateReadAddressRef.current?.toLowerCase() !== lockOwner.toLowerCase()) {
|
|
3429
|
+
throw new Error("Authenticated deposit account changed while signing");
|
|
3430
|
+
}
|
|
3431
|
+
savePendingLock(lockOwner, record.transaction_id, signedLock);
|
|
3432
|
+
lockOwnerRef.current = lockOwner;
|
|
2774
3433
|
emitDebug("intent:lock-signed", {
|
|
2775
3434
|
transactionId: record.transaction_id,
|
|
2776
3435
|
amount: signedLock.amount,
|
|
@@ -2802,6 +3461,7 @@ function useFiatOnRamp(options) {
|
|
|
2802
3461
|
executePrivateRead,
|
|
2803
3462
|
networkConfig,
|
|
2804
3463
|
postDepositLock,
|
|
3464
|
+
privateReadAddress,
|
|
2805
3465
|
serviceAddress,
|
|
2806
3466
|
tokenId,
|
|
2807
3467
|
wagmiConfig,
|
|
@@ -2827,7 +3487,7 @@ function useFiatOnRamp(options) {
|
|
|
2827
3487
|
chainId: token.chainId
|
|
2828
3488
|
});
|
|
2829
3489
|
const record = await executePrivateRead(
|
|
2830
|
-
() =>
|
|
3490
|
+
(readClient) => readClient.updateOnRamp(transactionId, {
|
|
2831
3491
|
token_id: tokenId,
|
|
2832
3492
|
chain_id: token.chainId,
|
|
2833
3493
|
moonpay_transaction_id: transactionId === moonpayTransactionId ? void 0 : moonpayTransactionId
|
|
@@ -2847,7 +3507,7 @@ function useFiatOnRamp(options) {
|
|
|
2847
3507
|
console.warn("Failed to register on-ramp token mapping:", err);
|
|
2848
3508
|
}
|
|
2849
3509
|
},
|
|
2850
|
-
[
|
|
3510
|
+
[emitDebug, enabledTokens, executePrivateRead, tokenId]
|
|
2851
3511
|
);
|
|
2852
3512
|
const handleTransactionCreated = useCallback(
|
|
2853
3513
|
async (props) => {
|
|
@@ -2862,7 +3522,9 @@ function useFiatOnRamp(options) {
|
|
|
2862
3522
|
setError(null);
|
|
2863
3523
|
try {
|
|
2864
3524
|
emitDebug("moonpay:onUrlSignatureRequested", summariseMoonPayUrl(url));
|
|
2865
|
-
const { signature } = await executePrivateRead(
|
|
3525
|
+
const { signature } = await executePrivateRead(
|
|
3526
|
+
(readClient) => readClient.signOnRampUrl({ url })
|
|
3527
|
+
);
|
|
2866
3528
|
setStatus("awaiting-purchase");
|
|
2867
3529
|
emitDebug("sign-url:success", {
|
|
2868
3530
|
signatureLength: signature.length
|
|
@@ -2877,7 +3539,7 @@ function useFiatOnRamp(options) {
|
|
|
2877
3539
|
throw err;
|
|
2878
3540
|
}
|
|
2879
3541
|
},
|
|
2880
|
-
[
|
|
3542
|
+
[emitDebug, executePrivateRead]
|
|
2881
3543
|
);
|
|
2882
3544
|
const waitForOnChainHash = useCallback(
|
|
2883
3545
|
async (transactionId) => {
|
|
@@ -2889,7 +3551,9 @@ function useFiatOnRamp(options) {
|
|
|
2889
3551
|
});
|
|
2890
3552
|
while (Date.now() - startTime < deliveryTimeout) {
|
|
2891
3553
|
try {
|
|
2892
|
-
const { pending: rows } = await executePrivateRead(
|
|
3554
|
+
const { pending: rows } = await executePrivateRead(
|
|
3555
|
+
(readClient) => readClient.getPendingOnRamps()
|
|
3556
|
+
);
|
|
2893
3557
|
setPending(rows);
|
|
2894
3558
|
const record = rows.find((r) => matchesOnRampTransaction(r, transactionId));
|
|
2895
3559
|
emitDebug("delivery-poll:tick", {
|
|
@@ -2916,7 +3580,7 @@ function useFiatOnRamp(options) {
|
|
|
2916
3580
|
emitDebug("delivery-poll:timeout", { transactionId });
|
|
2917
3581
|
return null;
|
|
2918
3582
|
},
|
|
2919
|
-
[
|
|
3583
|
+
[deliveryPollInterval, deliveryTimeout, emitDebug, executePrivateRead]
|
|
2920
3584
|
);
|
|
2921
3585
|
const triggerVerification = useCallback(
|
|
2922
3586
|
async (record) => {
|
|
@@ -2984,7 +3648,6 @@ function useFiatOnRamp(options) {
|
|
|
2984
3648
|
`Delivered amount (${record.quote_currency_amount}) is below the minimum deposit.`
|
|
2985
3649
|
);
|
|
2986
3650
|
}
|
|
2987
|
-
activeVerificationAmountRef.current = amount;
|
|
2988
3651
|
if (activeIntentIdRef.current === record.transaction_id) {
|
|
2989
3652
|
setStatus("verifying");
|
|
2990
3653
|
}
|
|
@@ -3003,7 +3666,6 @@ function useFiatOnRamp(options) {
|
|
|
3003
3666
|
if (activeVerificationKeyRef.current === verificationKey) {
|
|
3004
3667
|
activeVerificationKeyRef.current = null;
|
|
3005
3668
|
activeVerificationRecordRef.current = null;
|
|
3006
|
-
activeVerificationAmountRef.current = null;
|
|
3007
3669
|
setActiveVerificationId(null);
|
|
3008
3670
|
}
|
|
3009
3671
|
throw err;
|
|
@@ -3249,12 +3911,6 @@ function matchesOnRampTransaction(record, transactionId) {
|
|
|
3249
3911
|
function getOnRampVerificationKey(record) {
|
|
3250
3912
|
return record.on_chain_tx_hash ?? record.transaction_id;
|
|
3251
3913
|
}
|
|
3252
|
-
function requireServiceAddress(serviceAddress) {
|
|
3253
|
-
if (!serviceAddress) {
|
|
3254
|
-
throw new Error("Service address not configured");
|
|
3255
|
-
}
|
|
3256
|
-
return serviceAddress;
|
|
3257
|
-
}
|
|
3258
3914
|
function summariseMoonPayEventProps(props) {
|
|
3259
3915
|
return {
|
|
3260
3916
|
id: props.id,
|
|
@@ -3688,7 +4344,7 @@ function FiatOnRampForm({
|
|
|
3688
4344
|
] }),
|
|
3689
4345
|
lockPending && /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground flex items-center gap-2 text-sm", children: [
|
|
3690
4346
|
/* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin", "aria-hidden": true }),
|
|
3691
|
-
"Purchase credited
|
|
4347
|
+
"Purchase credited. Locking your funds\u2026"
|
|
3692
4348
|
] }),
|
|
3693
4349
|
autoStart ? !visible && isPrePurchase && /* @__PURE__ */ jsx(Skeleton, { className: "h-[656px] w-full rounded-md" }) : isInitializing ? /* @__PURE__ */ jsx(Skeleton, { className: "h-9 w-full rounded-md" }) : /* @__PURE__ */ jsxs(Button, { type: "button", onClick: handleOpen, disabled: !canBuy, children: [
|
|
3694
4350
|
(isBusy || visible) && /* @__PURE__ */ jsx(Loader2, { className: "animate-spin", "aria-hidden": true }),
|
|
@@ -3717,6 +4373,6 @@ function parseFinalityProgress(message) {
|
|
|
3717
4373
|
return match ? `${match[1]} confirmations` : null;
|
|
3718
4374
|
}
|
|
3719
4375
|
|
|
3720
|
-
export { AccountingApiError, Button, DEFAULT_LOCK_DURATION_SECONDS, DEFAULT_ONRAMP_LOCK_BUFFER, FiatOnRampForm, HOSTED_AUTH_CLOCK_SKEW_MS, HostedAuthError, HostedAuthRequiredError, HostedAuthStateMismatchError, HttpClient, LOCK_TYPES, MODIFY_LOCK_TYPES, NETWORK_CONFIG, NetworkError, PostDepositLockError, PrivanaClient, PrivanaProvider, SUPPORTED_CHAINS, SiweAuthProvider, Skeleton, TRANSFER_LOCKED_TYPES, TRANSFER_TYPES, ValidationError, WITHDRAW_FROM_LOCK_TYPES, WITHDRAW_TYPES, applyLockBuffer, applyRefreshResponse, buildHostedAuthSession, buildSiweStatement, buttonVariants, canUseBrowserStorage, clampLockAmount, clearHostedAuthPendingTransaction, clearPendingLock, cn, createDomain, createHostedAuthPendingStorageKey, createHostedAuthState, createHostedAuthStorageKey, createLockExpiry, createPkceChallenge, createPkceVerifier, createSignedLockRequest, formatCountdown, formatTimeRemaining, formatTokenAmount, getAccountingContract, getApiUrl, getBlockNumber, getBrowserStorageItem, getChainById, getChainId, getExplorerAddressUrl, getExplorerLabel, getTransactionReceipt, getWalletClient3 as getWalletClient, isHostedAuthRefreshActive, isHostedAuthSessionActive, isSignedLockUsable, loadPendingLock, normalizeAddress, normalizeHex, parseHostedAuthCallback, parseTokenAmount, persistHostedAuthPendingTransaction, readHostedAuthPendingTransaction, readStoredHostedAuthSession, removeBrowserStorageItem, savePendingLock, setBrowserStorageItem, shortenAddress, signLockMessage, signModifyLockMessage, signTransferLockedMessage, signTransferMessage, signWithdrawFromLockMessage, signWithdrawMessage, stripHostedAuthCallbackParams, submitPendingLock, syncHostedAuthSessionToClient, useDepositVerification, useEnsureCorrectChain, useFiatOnRamp, usePrivanaContext, usePrivateReadRequest, useSafeAccount, useSafePrivanaContext, useSiweAuth, waitForTransactionReceipt };
|
|
3721
|
-
//# sourceMappingURL=chunk-
|
|
3722
|
-
//# sourceMappingURL=chunk-
|
|
4376
|
+
export { AccountingApiError, Button, DEFAULT_LOCK_DURATION_SECONDS, DEFAULT_ONRAMP_LOCK_BUFFER, FiatOnRampForm, HOSTED_AUTH_CLOCK_SKEW_MS, HostedAuthError, HostedAuthRequiredError, HostedAuthStateMismatchError, HttpClient, LOCK_TYPES, MODIFY_LOCK_TYPES, NETWORK_CONFIG, NetworkError, PostDepositLockError, PrivanaClient, PrivanaProvider, SUPPORTED_CHAINS, SiweAuthProvider, Skeleton, TRANSFER_LOCKED_TYPES, TRANSFER_TYPES, ValidationError, WITHDRAW_FROM_LOCK_TYPES, WITHDRAW_TYPES, applyLockBuffer, applyRefreshResponse, buildHostedAuthSession, buildSiweStatement, buttonVariants, canUseBrowserStorage, canUseSharedBrowserStorage, clampLockAmount, clearHostedAuthPendingTransaction, clearPendingLock, cn, createDomain, createHostedAuthPendingStorageKey, createHostedAuthState, createHostedAuthStorageKey, createLockExpiry, createPkceChallenge, createPkceVerifier, createSignedLockRequest, formatCountdown, formatTimeRemaining, formatTokenAmount, getAccountingContract, getApiUrl, getBlockNumber, getBrowserStorageItem, getChainById, getChainId, getExplorerAddressUrl, getExplorerLabel, getSharedBrowserStorageItem, getTransactionReceipt, getWalletClient3 as getWalletClient, isHostedAuthRefreshActive, isHostedAuthSessionActive, isSignedLockUsable, loadPendingLock, normalizeAddress, normalizeHex, parseHostedAuthCallback, parseTokenAmount, persistHostedAuthPendingTransaction, readHostedAuthPendingTransaction, readStoredHostedAuthSession, removeBrowserStorageItem, removeSharedBrowserStorageItem, requireDepositLockOwner, requireServiceAddress, savePendingLock, setBrowserStorageItem, setSharedBrowserStorageItem, shortenAddress, signLockMessage, signModifyLockMessage, signTransferLockedMessage, signTransferMessage, signWithdrawFromLockMessage, signWithdrawMessage, stripHostedAuthCallbackParams, submitPendingLock, syncHostedAuthSessionToClient, useDepositVerification, useEnsureCorrectChain, useFiatOnRamp, usePrivanaContext, usePrivateReadRequest, useSafeAccount, useSafePrivanaContext, useSiweAuth, waitForTransactionReceipt };
|
|
4377
|
+
//# sourceMappingURL=chunk-DZURIIRE.js.map
|
|
4378
|
+
//# sourceMappingURL=chunk-DZURIIRE.js.map
|