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