@veridex/sdk 1.1.0 → 1.1.2

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.
Files changed (93) hide show
  1. package/dist/{EVMClient-DtqvdfUP.d.mts → EVMClient-Bmy9czkE.d.mts} +2 -0
  2. package/dist/auth/prepareAuth.js +107 -32
  3. package/dist/auth/prepareAuth.js.map +1 -1
  4. package/dist/auth/prepareAuth.mjs +6 -6
  5. package/dist/chains/aptos/index.js.map +1 -1
  6. package/dist/chains/aptos/index.mjs +3 -3
  7. package/dist/chains/avalanche/index.d.mts +1 -1
  8. package/dist/chains/avalanche/index.js +59 -11
  9. package/dist/chains/avalanche/index.js.map +1 -1
  10. package/dist/chains/avalanche/index.mjs +4 -4
  11. package/dist/chains/evm/index.d.mts +3 -3
  12. package/dist/chains/evm/index.js +59 -11
  13. package/dist/chains/evm/index.js.map +1 -1
  14. package/dist/chains/evm/index.mjs +3 -3
  15. package/dist/chains/solana/index.js.map +1 -1
  16. package/dist/chains/solana/index.mjs +3 -3
  17. package/dist/chains/stacks/index.d.mts +1 -1
  18. package/dist/chains/stacks/index.js.map +1 -1
  19. package/dist/chains/stacks/index.mjs +3 -3
  20. package/dist/chains/starknet/index.d.mts +1 -1
  21. package/dist/chains/starknet/index.js.map +1 -1
  22. package/dist/chains/starknet/index.mjs +3 -3
  23. package/dist/chains/stellar/index.d.mts +312 -0
  24. package/dist/chains/stellar/index.js +300 -0
  25. package/dist/chains/stellar/index.js.map +1 -0
  26. package/dist/chains/stellar/index.mjs +260 -0
  27. package/dist/chains/stellar/index.mjs.map +1 -0
  28. package/dist/chains/sui/index.d.mts +1 -1
  29. package/dist/chains/sui/index.js.map +1 -1
  30. package/dist/chains/sui/index.mjs +3 -3
  31. package/dist/{chunk-Q5O3M5LP.mjs → chunk-2TS375ET.mjs} +2 -2
  32. package/dist/{chunk-QT4ZZ4GM.mjs → chunk-5FDOTI5G.mjs} +2 -2
  33. package/dist/{chunk-N4A2RMUN.mjs → chunk-AFHWA4CZ.mjs} +2 -2
  34. package/dist/{chunk-5T6KPH7A.mjs → chunk-CSU4IV2F.mjs} +2 -2
  35. package/dist/{chunk-YCUJZ6Z7.mjs → chunk-CTYDGO6E.mjs} +63 -6
  36. package/dist/chunk-CTYDGO6E.mjs.map +1 -0
  37. package/dist/{chunk-USDA5JTN.mjs → chunk-DZUNCSI5.mjs} +61 -13
  38. package/dist/chunk-DZUNCSI5.mjs.map +1 -0
  39. package/dist/{chunk-SXXGTQIR.mjs → chunk-E3SU36C2.mjs} +2 -2
  40. package/dist/{chunk-NUWSMJFJ.mjs → chunk-EFIXFA6V.mjs} +2 -2
  41. package/dist/{chunk-MLXQHIH2.mjs → chunk-GM5DKEHD.mjs} +2 -2
  42. package/dist/{chunk-GWJRKDSA.mjs → chunk-GOWXQPTW.mjs} +3 -3
  43. package/dist/{chunk-OVMMTL6H.mjs → chunk-ICGB3AHI.mjs} +2 -2
  44. package/dist/{chunk-QDO6NQ7P.mjs → chunk-M3GUNREX.mjs} +20 -3
  45. package/dist/{chunk-QDO6NQ7P.mjs.map → chunk-M3GUNREX.mjs.map} +1 -1
  46. package/dist/{chunk-X7BZMSPQ.mjs → chunk-RD6ZYUVG.mjs} +52 -30
  47. package/dist/chunk-RD6ZYUVG.mjs.map +1 -0
  48. package/dist/{chunk-F3YAGZSW.mjs → chunk-TPEP6XUA.mjs} +2 -2
  49. package/dist/{chunk-M3MM4YMF.mjs → chunk-UPO55SBK.mjs} +2 -2
  50. package/dist/{chunk-PDHZ5X5O.mjs → chunk-YYT3V7CI.mjs} +2 -2
  51. package/dist/constants.d.mts +2 -2
  52. package/dist/constants.js +51 -29
  53. package/dist/constants.js.map +1 -1
  54. package/dist/constants.mjs +1 -1
  55. package/dist/{index-DDalBhAm.d.mts → index-CKKUV4J7.d.mts} +10 -7
  56. package/dist/index.d.mts +43 -14
  57. package/dist/index.js +512 -159
  58. package/dist/index.js.map +1 -1
  59. package/dist/index.mjs +335 -128
  60. package/dist/index.mjs.map +1 -1
  61. package/dist/passkey.js +57 -4
  62. package/dist/passkey.js.map +1 -1
  63. package/dist/passkey.mjs +3 -3
  64. package/dist/payload.js.map +1 -1
  65. package/dist/payload.mjs +2 -2
  66. package/dist/portfolio-JA4OTF7Y.mjs +13 -0
  67. package/dist/queries/index.js +49 -27
  68. package/dist/queries/index.js.map +1 -1
  69. package/dist/queries/index.mjs +5 -5
  70. package/dist/{types-B7V5VNbO.d.mts → types-C564CfsE.d.mts} +33 -4
  71. package/dist/utils.js +49 -27
  72. package/dist/utils.js.map +1 -1
  73. package/dist/utils.mjs +2 -2
  74. package/dist/wormhole.js.map +1 -1
  75. package/dist/wormhole.mjs +2 -2
  76. package/package.json +8 -1
  77. package/dist/chunk-USDA5JTN.mjs.map +0 -1
  78. package/dist/chunk-X7BZMSPQ.mjs.map +0 -1
  79. package/dist/chunk-YCUJZ6Z7.mjs.map +0 -1
  80. package/dist/portfolio-V347KZOL.mjs +0 -13
  81. /package/dist/{chunk-Q5O3M5LP.mjs.map → chunk-2TS375ET.mjs.map} +0 -0
  82. /package/dist/{chunk-QT4ZZ4GM.mjs.map → chunk-5FDOTI5G.mjs.map} +0 -0
  83. /package/dist/{chunk-N4A2RMUN.mjs.map → chunk-AFHWA4CZ.mjs.map} +0 -0
  84. /package/dist/{chunk-5T6KPH7A.mjs.map → chunk-CSU4IV2F.mjs.map} +0 -0
  85. /package/dist/{chunk-SXXGTQIR.mjs.map → chunk-E3SU36C2.mjs.map} +0 -0
  86. /package/dist/{chunk-NUWSMJFJ.mjs.map → chunk-EFIXFA6V.mjs.map} +0 -0
  87. /package/dist/{chunk-MLXQHIH2.mjs.map → chunk-GM5DKEHD.mjs.map} +0 -0
  88. /package/dist/{chunk-GWJRKDSA.mjs.map → chunk-GOWXQPTW.mjs.map} +0 -0
  89. /package/dist/{chunk-OVMMTL6H.mjs.map → chunk-ICGB3AHI.mjs.map} +0 -0
  90. /package/dist/{chunk-F3YAGZSW.mjs.map → chunk-TPEP6XUA.mjs.map} +0 -0
  91. /package/dist/{chunk-M3MM4YMF.mjs.map → chunk-UPO55SBK.mjs.map} +0 -0
  92. /package/dist/{chunk-PDHZ5X5O.mjs.map → chunk-YYT3V7CI.mjs.map} +0 -0
  93. /package/dist/{portfolio-V347KZOL.mjs.map → portfolio-JA4OTF7Y.mjs.map} +0 -0
package/dist/index.mjs CHANGED
@@ -1,34 +1,36 @@
1
1
  import {
2
2
  CHAIN_NAMES,
3
3
  CHAIN_PRESETS,
4
+ configureDefaultRpcUrls,
4
5
  getChainConfig,
5
6
  getChainPreset,
6
7
  getDefaultHub,
7
8
  getEffectivePrimaryHub,
8
9
  getFeatureFlags,
9
10
  getHubChains,
11
+ getRpcUrlOverride,
10
12
  getSupportedChains,
11
13
  isChainSupported,
12
14
  isHubChain,
13
15
  isMultiHubEnabled,
14
16
  resetFeatureFlags,
15
17
  setFeatureFlags
16
- } from "./chunk-QDO6NQ7P.mjs";
18
+ } from "./chunk-M3GUNREX.mjs";
17
19
  import {
18
20
  EVMHubClientAdapter
19
21
  } from "./chunk-V636MIV3.mjs";
20
22
  import {
21
23
  SolanaClient
22
- } from "./chunk-Q5O3M5LP.mjs";
24
+ } from "./chunk-2TS375ET.mjs";
23
25
  import {
24
26
  AptosClient
25
- } from "./chunk-QT4ZZ4GM.mjs";
27
+ } from "./chunk-5FDOTI5G.mjs";
26
28
  import {
27
29
  SuiClient
28
- } from "./chunk-SXXGTQIR.mjs";
30
+ } from "./chunk-E3SU36C2.mjs";
29
31
  import {
30
32
  StarknetClient
31
- } from "./chunk-MLXQHIH2.mjs";
33
+ } from "./chunk-GM5DKEHD.mjs";
32
34
  import {
33
35
  STACKS_ACTION_TYPES,
34
36
  StacksClient,
@@ -56,13 +58,13 @@ import {
56
58
  parseContractPrincipal,
57
59
  rsToCompactSignature,
58
60
  validatePostConditions
59
- } from "./chunk-5T6KPH7A.mjs";
61
+ } from "./chunk-CSU4IV2F.mjs";
60
62
  import {
61
63
  AvalancheClient
62
- } from "./chunk-N4A2RMUN.mjs";
64
+ } from "./chunk-AFHWA4CZ.mjs";
63
65
  import {
64
66
  EVMClient
65
- } from "./chunk-USDA5JTN.mjs";
67
+ } from "./chunk-DZUNCSI5.mjs";
66
68
  import {
67
69
  CONSISTENCY_LEVELS,
68
70
  GUARDIAN_CONFIG,
@@ -85,7 +87,7 @@ import {
85
87
  supportsRelayer,
86
88
  validateEmitter,
87
89
  waitForGuardianSignatures
88
- } from "./chunk-M3MM4YMF.mjs";
90
+ } from "./chunk-UPO55SBK.mjs";
89
91
  import {
90
92
  buildChallenge,
91
93
  buildGaslessChallenge,
@@ -109,7 +111,7 @@ import {
109
111
  parseAmount,
110
112
  solanaAddressToBytes32,
111
113
  trimTo20Bytes
112
- } from "./chunk-F3YAGZSW.mjs";
114
+ } from "./chunk-TPEP6XUA.mjs";
113
115
  import {
114
116
  ARBITRUM_SEPOLIA_TOKENS,
115
117
  BASE_SEPOLIA_TOKENS,
@@ -127,13 +129,15 @@ import {
127
129
  getTokenBySymbol,
128
130
  getTokenList,
129
131
  isNativeToken
130
- } from "./chunk-PDHZ5X5O.mjs";
132
+ } from "./chunk-YYT3V7CI.mjs";
131
133
  import {
132
134
  PasskeyManager,
133
135
  VERIDEX_RP_ID,
136
+ buildRelayerApiUrl,
134
137
  detectRpId,
138
+ normalizeRelayerOrigin,
135
139
  supportsRelatedOrigins
136
- } from "./chunk-YCUJZ6Z7.mjs";
140
+ } from "./chunk-CTYDGO6E.mjs";
137
141
  import {
138
142
  base64URLDecode,
139
143
  base64URLEncode,
@@ -149,7 +153,7 @@ import {
149
153
  isValidWormholeChainId,
150
154
  parseDERSignature,
151
155
  retryWithBackoff
152
- } from "./chunk-NUWSMJFJ.mjs";
156
+ } from "./chunk-EFIXFA6V.mjs";
153
157
  import {
154
158
  ACTION_BRIDGE,
155
159
  ACTION_CONFIG,
@@ -165,7 +169,7 @@ import {
165
169
  WORMHOLE_API,
166
170
  WORMHOLE_CHAIN_IDS,
167
171
  WORMHOLE_CHAIN_IDS_FLAT
168
- } from "./chunk-X7BZMSPQ.mjs";
172
+ } from "./chunk-RD6ZYUVG.mjs";
169
173
 
170
174
  // src/core/BalanceManager.ts
171
175
  import { ethers } from "ethers";
@@ -1014,7 +1018,7 @@ var RelayerClient = class _RelayerClient {
1014
1018
  baseUrl;
1015
1019
  config;
1016
1020
  constructor(config) {
1017
- this.baseUrl = config.baseUrl.replace(/\/+$/, "");
1021
+ this.baseUrl = normalizeRelayerOrigin(config.baseUrl);
1018
1022
  this.config = { ...DEFAULT_CONFIG2, ...config };
1019
1023
  }
1020
1024
  // ========================================================================
@@ -1281,6 +1285,7 @@ var RelayerClient = class _RelayerClient {
1281
1285
  * Make an HTTP request to the relayer
1282
1286
  */
1283
1287
  async fetch(path, options = {}) {
1288
+ const resolvedUrl = path.startsWith("/api/v1/") ? buildRelayerApiUrl(this.baseUrl, path.replace(/^\/api\/v1/, "")) : `${this.baseUrl}${path}`;
1284
1289
  const headers = {
1285
1290
  "Content-Type": "application/json",
1286
1291
  "User-Agent": `@veridex/sdk/${_RelayerClient.SDK_VERSION}`,
@@ -1294,7 +1299,7 @@ var RelayerClient = class _RelayerClient {
1294
1299
  let lastError = null;
1295
1300
  for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
1296
1301
  try {
1297
- const response = await fetch(`${this.baseUrl}${path}`, {
1302
+ const response = await fetch(resolvedUrl, {
1298
1303
  ...options,
1299
1304
  headers,
1300
1305
  signal: controller.signal
@@ -5300,7 +5305,7 @@ var VeridexSDK = class {
5300
5305
  const wormholeChainId = chainConfig.wormholeChainId;
5301
5306
  const tokenList = getAllTokens(wormholeChainId);
5302
5307
  const erc20Tokens = tokenList.filter((t) => !isNativeToken(t.address)).map((t) => t.address);
5303
- const { queryPortfolio } = await import("./portfolio-V347KZOL.mjs");
5308
+ const { queryPortfolio } = await import("./portfolio-JA4OTF7Y.mjs");
5304
5309
  const result = await queryPortfolio(credential.keyHash, this.queryApiKey, {
5305
5310
  network: this.testnet ? "testnet" : "mainnet",
5306
5311
  vaultAddresses: { [wormholeChainId]: vaultAddress },
@@ -5663,7 +5668,7 @@ var VeridexSDK = class {
5663
5668
  const tokenList = getAllTokens(wormholeChainId);
5664
5669
  const erc20Tokens = tokenList.filter((t) => !isNativeToken(t.address)).map((t) => t.address);
5665
5670
  const rpcUrl = this.chainRpcUrls?.[wormholeChainId] ?? chainConfig.rpcUrl;
5666
- const { queryPortfolio } = await import("./portfolio-V347KZOL.mjs");
5671
+ const { queryPortfolio } = await import("./portfolio-JA4OTF7Y.mjs");
5667
5672
  const result = await queryPortfolio(credential.keyHash, this.queryApiKey, {
5668
5673
  network: this.testnet ? "testnet" : "mainnet",
5669
5674
  vaultAddresses: { [wormholeChainId]: vaultAddress },
@@ -6657,7 +6662,7 @@ var CredentialManager = class {
6657
6662
  constructor(config = {}) {
6658
6663
  this.config = {
6659
6664
  storageKey: config.storageKey ?? DEFAULT_STORAGE_KEY,
6660
- relayerUrl: config.relayerUrl ?? ""
6665
+ relayerUrl: normalizeRelayerOrigin(config.relayerUrl ?? "")
6661
6666
  };
6662
6667
  }
6663
6668
  // ========================================================================
@@ -6805,7 +6810,7 @@ var CredentialManager = class {
6805
6810
  const managed = this.getCredential(credentialId);
6806
6811
  if (!managed) return false;
6807
6812
  try {
6808
- const response = await fetch(`${this.config.relayerUrl}/api/v1/credential/metadata`, {
6813
+ const response = await fetch(buildRelayerApiUrl(this.config.relayerUrl, "/credential/metadata"), {
6809
6814
  method: "PUT",
6810
6815
  headers: { "Content-Type": "application/json" },
6811
6816
  body: JSON.stringify({
@@ -6831,7 +6836,10 @@ var CredentialManager = class {
6831
6836
  if (!this.config.relayerUrl) return null;
6832
6837
  try {
6833
6838
  const response = await fetch(
6834
- `${this.config.relayerUrl}/api/v1/credential/metadata?keyHash=${encodeURIComponent(keyHash)}`
6839
+ buildRelayerApiUrl(
6840
+ this.config.relayerUrl,
6841
+ `/credential/metadata?keyHash=${encodeURIComponent(keyHash)}`
6842
+ )
6835
6843
  );
6836
6844
  if (!response.ok) return null;
6837
6845
  const data = await response.json();
@@ -6953,7 +6961,7 @@ var CredentialManager = class {
6953
6961
 
6954
6962
  // src/core/CrossOriginAuth.ts
6955
6963
  var DEFAULT_AUTH_PORTAL_URL = "https://auth.veridex.network";
6956
- var DEFAULT_RELAYER_URL = "https://amused-kameko-veridex-demo-37453117.koyeb.app/api/v1";
6964
+ var DEFAULT_RELAYER_URL = "https://relayer.veridex.network";
6957
6965
  var AUTH_MESSAGE_TYPES = {
6958
6966
  AUTH_REQUEST: "VERIDEX_AUTH_REQUEST",
6959
6967
  AUTH_RESPONSE: "VERIDEX_AUTH_RESPONSE",
@@ -6965,7 +6973,7 @@ var CrossOriginAuth = class {
6965
6973
  this.config = {
6966
6974
  rpId: config.rpId ?? VERIDEX_RP_ID,
6967
6975
  authPortalUrl: config.authPortalUrl ?? DEFAULT_AUTH_PORTAL_URL,
6968
- relayerUrl: config.relayerUrl ?? DEFAULT_RELAYER_URL,
6976
+ relayerUrl: normalizeRelayerOrigin(config.relayerUrl ?? DEFAULT_RELAYER_URL),
6969
6977
  mode: config.mode ?? "popup",
6970
6978
  popupFeatures: config.popupFeatures ?? "width=500,height=600,left=100,top=100",
6971
6979
  timeout: config.timeout ?? 12e4,
@@ -7182,7 +7190,8 @@ var CrossOriginAuth = class {
7182
7190
  return bytes;
7183
7191
  }
7184
7192
  async requestServerSessionChallenge(options) {
7185
- const response = await fetch(`${this.config.relayerUrl}/session/challenge`, {
7193
+ const challengeUrl = buildRelayerApiUrl(this.config.relayerUrl, "/session/challenge");
7194
+ const response = await fetch(challengeUrl, {
7186
7195
  method: "POST",
7187
7196
  headers: { "Content-Type": "application/json" },
7188
7197
  body: JSON.stringify({
@@ -7228,7 +7237,7 @@ var CrossOriginAuth = class {
7228
7237
  if (!session.serverChallengeId) {
7229
7238
  throw new Error("Session must include a relayer-issued serverChallengeId");
7230
7239
  }
7231
- const response = await fetch(`${this.config.relayerUrl}/session/create`, {
7240
+ const response = await fetch(buildRelayerApiUrl(this.config.relayerUrl, "/session/create"), {
7232
7241
  method: "POST",
7233
7242
  headers: { "Content-Type": "application/json" },
7234
7243
  body: JSON.stringify({
@@ -7251,7 +7260,9 @@ var CrossOriginAuth = class {
7251
7260
  * Returns the session details if valid, null if expired/revoked.
7252
7261
  */
7253
7262
  async validateServerSession(sessionId) {
7254
- const response = await fetch(`${this.config.relayerUrl}/session/${encodeURIComponent(sessionId)}`);
7263
+ const response = await fetch(
7264
+ buildRelayerApiUrl(this.config.relayerUrl, `/session/${encodeURIComponent(sessionId)}`)
7265
+ );
7255
7266
  if (!response.ok) {
7256
7267
  return null;
7257
7268
  }
@@ -7265,9 +7276,12 @@ var CrossOriginAuth = class {
7265
7276
  * Revoke a server session token.
7266
7277
  */
7267
7278
  async revokeServerSession(sessionId) {
7268
- const response = await fetch(`${this.config.relayerUrl}/session/${encodeURIComponent(sessionId)}`, {
7269
- method: "DELETE"
7270
- });
7279
+ const response = await fetch(
7280
+ buildRelayerApiUrl(this.config.relayerUrl, `/session/${encodeURIComponent(sessionId)}`),
7281
+ {
7282
+ method: "DELETE"
7283
+ }
7284
+ );
7271
7285
  return response.ok;
7272
7286
  }
7273
7287
  /**
@@ -7716,6 +7730,12 @@ function validateSessionConfig(config) {
7716
7730
  "INVALID_CONFIG" /* INVALID_CONFIG */
7717
7731
  );
7718
7732
  }
7733
+ if (config.maxValue === 0n && config.allowUnboundedMaxValue !== true) {
7734
+ throw new SessionError(
7735
+ 'Session maxValue=0 means "no per-tx limit" \u2014 the vault daily cap is then the only bound. This is a foot-gun: a compromised session key can drain the vault up to that cap. Pass a non-zero maxValue, or set allowUnboundedMaxValue:true if you have verified the vault daily cap and accept the residual risk.',
7736
+ "INVALID_CONFIG" /* INVALID_CONFIG */
7737
+ );
7738
+ }
7719
7739
  }
7720
7740
 
7721
7741
  // src/sessions/storage.ts
@@ -7824,39 +7844,44 @@ var IndexedDBSessionStorage = class {
7824
7844
  );
7825
7845
  }
7826
7846
  }
7847
+ async decryptSession(stored) {
7848
+ const key = await this.getEncryptionKey();
7849
+ const encryptedPrivateKey = new Uint8Array(stored.encryptedPrivateKey);
7850
+ const privateKey = await decrypt(encryptedPrivateKey, key);
7851
+ return {
7852
+ keyHash: stored.keyHash,
7853
+ publicKey: new Uint8Array(stored.publicKey),
7854
+ privateKey,
7855
+ expiry: stored.expiry,
7856
+ maxValue: BigInt(stored.maxValue),
7857
+ chainScopes: stored.chainScopes ?? [],
7858
+ userKeyHash: stored.userKeyHash
7859
+ };
7860
+ }
7861
+ async pruneExpiredSessions(records) {
7862
+ const now = Date.now();
7863
+ const validRecords = records.filter((record) => record.expiry > now);
7864
+ const expiredRecords = records.filter((record) => record.expiry <= now);
7865
+ if (expiredRecords.length > 0) {
7866
+ await Promise.all(expiredRecords.map((record) => this.remove(record.keyHash)));
7867
+ }
7868
+ return validRecords.sort((left, right) => right.savedAt - left.savedAt);
7869
+ }
7827
7870
  /**
7828
- * Load the active session (decrypts private key)
7871
+ * Load a session (decrypts private key)
7829
7872
  */
7830
- async load() {
7873
+ async load(keyHash) {
7831
7874
  try {
7832
7875
  await this.initialize();
7833
7876
  if (!this.db) {
7834
7877
  throw new Error("Database not initialized");
7835
7878
  }
7836
- const allSessions = await this.getAllSessions();
7837
- if (allSessions.length === 0) {
7838
- return null;
7839
- }
7840
- const now = Date.now();
7841
- const validSessions = allSessions.filter((s) => s.expiry > now).sort((a, b) => b.savedAt - a.savedAt);
7879
+ const sessions = keyHash ? await this.getSessionByKeyHash(keyHash) : await this.getAllSessions();
7880
+ const validSessions = await this.pruneExpiredSessions(sessions);
7842
7881
  if (validSessions.length === 0) {
7843
- await this.clear();
7844
7882
  return null;
7845
7883
  }
7846
- const stored = validSessions[0];
7847
- const key = await this.getEncryptionKey();
7848
- const encryptedPrivateKey = new Uint8Array(stored.encryptedPrivateKey);
7849
- const privateKey = await decrypt(encryptedPrivateKey, key);
7850
- const session = {
7851
- keyHash: stored.keyHash,
7852
- publicKey: new Uint8Array(stored.publicKey),
7853
- privateKey,
7854
- expiry: stored.expiry,
7855
- maxValue: BigInt(stored.maxValue),
7856
- chainScopes: stored.chainScopes,
7857
- userKeyHash: stored.userKeyHash
7858
- };
7859
- return session;
7884
+ return this.decryptSession(validSessions[0]);
7860
7885
  } catch (error) {
7861
7886
  if (error instanceof SessionError) {
7862
7887
  throw error;
@@ -7889,6 +7914,75 @@ var IndexedDBSessionStorage = class {
7889
7914
  };
7890
7915
  });
7891
7916
  }
7917
+ async getSessionByKeyHash(keyHash) {
7918
+ if (!this.db) {
7919
+ return [];
7920
+ }
7921
+ return new Promise((resolve, reject) => {
7922
+ const transaction = this.db.transaction([STORE_NAME], "readonly");
7923
+ const store = transaction.objectStore(STORE_NAME);
7924
+ const request = store.get(keyHash);
7925
+ request.onsuccess = () => {
7926
+ resolve(request.result ? [request.result] : []);
7927
+ };
7928
+ request.onerror = () => {
7929
+ reject(new SessionError(
7930
+ "Failed to get session",
7931
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
7932
+ request.error
7933
+ ));
7934
+ };
7935
+ });
7936
+ }
7937
+ async loadAll() {
7938
+ try {
7939
+ await this.initialize();
7940
+ if (!this.db) {
7941
+ return [];
7942
+ }
7943
+ const records = await this.pruneExpiredSessions(await this.getAllSessions());
7944
+ return Promise.all(records.map((record) => this.decryptSession(record)));
7945
+ } catch (error) {
7946
+ if (error instanceof SessionError) {
7947
+ throw error;
7948
+ }
7949
+ throw new SessionError(
7950
+ "Failed to load sessions",
7951
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
7952
+ error
7953
+ );
7954
+ }
7955
+ }
7956
+ async remove(keyHash) {
7957
+ try {
7958
+ await this.initialize();
7959
+ if (!this.db) {
7960
+ return;
7961
+ }
7962
+ return new Promise((resolve, reject) => {
7963
+ const transaction = this.db.transaction([STORE_NAME], "readwrite");
7964
+ const store = transaction.objectStore(STORE_NAME);
7965
+ const request = store.delete(keyHash);
7966
+ request.onsuccess = () => resolve();
7967
+ request.onerror = () => {
7968
+ reject(new SessionError(
7969
+ "Failed to remove session",
7970
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
7971
+ request.error
7972
+ ));
7973
+ };
7974
+ });
7975
+ } catch (error) {
7976
+ if (error instanceof SessionError) {
7977
+ throw error;
7978
+ }
7979
+ throw new SessionError(
7980
+ "Failed to remove session",
7981
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
7982
+ error
7983
+ );
7984
+ }
7985
+ }
7892
7986
  /**
7893
7987
  * Clear all sessions
7894
7988
  */
@@ -7925,14 +8019,9 @@ var IndexedDBSessionStorage = class {
7925
8019
  /**
7926
8020
  * Check if any session exists
7927
8021
  */
7928
- async exists() {
8022
+ async exists(keyHash) {
7929
8023
  try {
7930
- await this.initialize();
7931
- if (!this.db) {
7932
- return false;
7933
- }
7934
- const sessions = await this.getAllSessions();
7935
- return sessions.length > 0;
8024
+ return await this.load(keyHash) !== null;
7936
8025
  } catch {
7937
8026
  return false;
7938
8027
  }
@@ -7951,7 +8040,8 @@ var STORAGE_KEY_PREFIX = "veridex-session-";
7951
8040
  var LocalStorageSessionStorage = class {
7952
8041
  encryptionKey = null;
7953
8042
  credentialId;
7954
- storageKey;
8043
+ credentialHash;
8044
+ legacyStorageKey;
7955
8045
  /**
7956
8046
  * @param credentialId User's Passkey credential ID (for key derivation)
7957
8047
  */
@@ -7963,7 +8053,60 @@ var LocalStorageSessionStorage = class {
7963
8053
  );
7964
8054
  }
7965
8055
  this.credentialId = credentialId;
7966
- this.storageKey = STORAGE_KEY_PREFIX + ethers10.keccak256(ethers10.toUtf8Bytes(credentialId));
8056
+ this.credentialHash = ethers10.keccak256(ethers10.toUtf8Bytes(credentialId));
8057
+ this.legacyStorageKey = STORAGE_KEY_PREFIX + this.credentialHash;
8058
+ }
8059
+ getSessionStorageKey(keyHash) {
8060
+ return `${STORAGE_KEY_PREFIX}${this.credentialHash}:${keyHash}`;
8061
+ }
8062
+ getSessionStoragePrefix() {
8063
+ return `${STORAGE_KEY_PREFIX}${this.credentialHash}:`;
8064
+ }
8065
+ async deserializeSession(stored) {
8066
+ const key = await this.getEncryptionKey();
8067
+ const encryptedPrivateKey = typeof stored.encryptedPrivateKey === "string" ? ethers10.getBytes(stored.encryptedPrivateKey) : new Uint8Array(stored.encryptedPrivateKey);
8068
+ const privateKey = await decrypt(encryptedPrivateKey, key);
8069
+ return {
8070
+ keyHash: stored.keyHash,
8071
+ publicKey: typeof stored.publicKey === "string" ? ethers10.getBytes(stored.publicKey) : new Uint8Array(stored.publicKey),
8072
+ privateKey,
8073
+ expiry: stored.expiry,
8074
+ maxValue: BigInt(stored.maxValue),
8075
+ chainScopes: stored.chainScopes ?? [],
8076
+ userKeyHash: stored.userKeyHash
8077
+ };
8078
+ }
8079
+ getRawRecords() {
8080
+ const records = [];
8081
+ const prefix = this.getSessionStoragePrefix();
8082
+ for (let index = 0; index < localStorage.length; index++) {
8083
+ const key = localStorage.key(index);
8084
+ if (!key || !key.startsWith(prefix)) {
8085
+ continue;
8086
+ }
8087
+ const value = localStorage.getItem(key);
8088
+ if (!value) {
8089
+ continue;
8090
+ }
8091
+ records.push(JSON.parse(value));
8092
+ }
8093
+ const legacyValue = localStorage.getItem(this.legacyStorageKey);
8094
+ if (legacyValue) {
8095
+ records.push(JSON.parse(legacyValue));
8096
+ }
8097
+ return records;
8098
+ }
8099
+ async getValidRecords() {
8100
+ const now = Date.now();
8101
+ const validRecords = [];
8102
+ for (const record of this.getRawRecords()) {
8103
+ if (record.expiry <= now) {
8104
+ await this.remove(record.keyHash);
8105
+ continue;
8106
+ }
8107
+ validRecords.push(record);
8108
+ }
8109
+ return validRecords.sort((left, right) => right.savedAt - left.savedAt);
7967
8110
  }
7968
8111
  /**
7969
8112
  * Get or derive encryption key
@@ -7992,7 +8135,7 @@ var LocalStorageSessionStorage = class {
7992
8135
  userKeyHash: session.userKeyHash,
7993
8136
  savedAt: Date.now()
7994
8137
  };
7995
- localStorage.setItem(this.storageKey, JSON.stringify(storageObject));
8138
+ localStorage.setItem(this.getSessionStorageKey(session.keyHash), JSON.stringify(storageObject));
7996
8139
  } catch (error) {
7997
8140
  if (error instanceof SessionError) {
7998
8141
  throw error;
@@ -8005,32 +8148,15 @@ var LocalStorageSessionStorage = class {
8005
8148
  }
8006
8149
  }
8007
8150
  /**
8008
- * Load the active session (decrypts private key)
8151
+ * Load a session (decrypts private key)
8009
8152
  */
8010
- async load() {
8153
+ async load(keyHash) {
8011
8154
  try {
8012
- const data = localStorage.getItem(this.storageKey);
8013
- if (!data) {
8014
- return null;
8015
- }
8016
- const stored = JSON.parse(data);
8017
- if (stored.expiry <= Date.now()) {
8018
- await this.clear();
8155
+ const records = keyHash ? (await this.getValidRecords()).filter((record) => record.keyHash === keyHash) : await this.getValidRecords();
8156
+ if (records.length === 0) {
8019
8157
  return null;
8020
8158
  }
8021
- const key = await this.getEncryptionKey();
8022
- const encryptedPrivateKey = ethers10.getBytes(stored.encryptedPrivateKey);
8023
- const privateKey = await decrypt(encryptedPrivateKey, key);
8024
- const session = {
8025
- keyHash: stored.keyHash,
8026
- publicKey: ethers10.getBytes(stored.publicKey),
8027
- privateKey,
8028
- expiry: stored.expiry,
8029
- maxValue: BigInt(stored.maxValue),
8030
- chainScopes: stored.chainScopes,
8031
- userKeyHash: stored.userKeyHash
8032
- };
8033
- return session;
8159
+ return this.deserializeSession(records[0]);
8034
8160
  } catch (error) {
8035
8161
  await this.clear();
8036
8162
  if (error instanceof SessionError) {
@@ -8043,12 +8169,55 @@ var LocalStorageSessionStorage = class {
8043
8169
  );
8044
8170
  }
8045
8171
  }
8172
+ async loadAll() {
8173
+ try {
8174
+ const records = await this.getValidRecords();
8175
+ return Promise.all(records.map((record) => this.deserializeSession(record)));
8176
+ } catch (error) {
8177
+ await this.clear();
8178
+ if (error instanceof SessionError) {
8179
+ throw error;
8180
+ }
8181
+ throw new SessionError(
8182
+ "Failed to load sessions",
8183
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
8184
+ error
8185
+ );
8186
+ }
8187
+ }
8188
+ async remove(keyHash) {
8189
+ try {
8190
+ localStorage.removeItem(this.getSessionStorageKey(keyHash));
8191
+ const legacyValue = localStorage.getItem(this.legacyStorageKey);
8192
+ if (legacyValue) {
8193
+ const legacyRecord = JSON.parse(legacyValue);
8194
+ if (legacyRecord.keyHash === keyHash) {
8195
+ localStorage.removeItem(this.legacyStorageKey);
8196
+ }
8197
+ }
8198
+ } catch (error) {
8199
+ throw new SessionError(
8200
+ "Failed to remove session",
8201
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
8202
+ error
8203
+ );
8204
+ }
8205
+ }
8046
8206
  /**
8047
8207
  * Clear all sessions
8048
8208
  */
8049
8209
  async clear() {
8050
8210
  try {
8051
- localStorage.removeItem(this.storageKey);
8211
+ const keysToRemove = [];
8212
+ const prefix = this.getSessionStoragePrefix();
8213
+ for (let index = 0; index < localStorage.length; index++) {
8214
+ const key = localStorage.key(index);
8215
+ if (key && key.startsWith(prefix)) {
8216
+ keysToRemove.push(key);
8217
+ }
8218
+ }
8219
+ keysToRemove.forEach((key) => localStorage.removeItem(key));
8220
+ localStorage.removeItem(this.legacyStorageKey);
8052
8221
  } catch (error) {
8053
8222
  throw new SessionError(
8054
8223
  "Failed to clear sessions",
@@ -8060,9 +8229,9 @@ var LocalStorageSessionStorage = class {
8060
8229
  /**
8061
8230
  * Check if any session exists
8062
8231
  */
8063
- async exists() {
8232
+ async exists(keyHash) {
8064
8233
  try {
8065
- return localStorage.getItem(this.storageKey) !== null;
8234
+ return await this.load(keyHash) !== null;
8066
8235
  } catch {
8067
8236
  return false;
8068
8237
  }
@@ -8112,7 +8281,8 @@ var SessionManager = class {
8112
8281
  maxValue: config.maxValue ?? 0n,
8113
8282
  autoRefresh: config.autoRefresh ?? true,
8114
8283
  refreshBuffer: config.refreshBuffer ?? DEFAULT_REFRESH_BUFFER,
8115
- chainScopes: config.chainScopes ?? []
8284
+ chainScopes: config.chainScopes ?? [],
8285
+ allowUnboundedMaxValue: config.allowUnboundedMaxValue ?? false
8116
8286
  };
8117
8287
  validateSessionConfig(this.config);
8118
8288
  this.debug = managerConfig?.debug ?? false;
@@ -8127,6 +8297,14 @@ var SessionManager = class {
8127
8297
  refreshTimer = null;
8128
8298
  eventCallbacks = [];
8129
8299
  debug;
8300
+ resolveConfig(configOverride) {
8301
+ const resolvedConfig = {
8302
+ ...this.config,
8303
+ ...configOverride
8304
+ };
8305
+ validateSessionConfig(resolvedConfig);
8306
+ return resolvedConfig;
8307
+ }
8130
8308
  // ========================================================================
8131
8309
  // Session Lifecycle
8132
8310
  // ========================================================================
@@ -8143,15 +8321,16 @@ var SessionManager = class {
8143
8321
  * @returns Created session key
8144
8322
  * @throws SessionError if registration fails
8145
8323
  */
8146
- async createSession() {
8324
+ async createSession(configOverride) {
8147
8325
  try {
8148
8326
  this.log("Creating new session...");
8327
+ const sessionConfig = this.resolveConfig(configOverride);
8149
8328
  const keyPair = generateSecp256k1KeyPair();
8150
8329
  const keyHash = computeSessionKeyHash(keyPair.publicKey);
8151
8330
  this.log("Generated session key:", keyHash);
8152
8331
  const challenge = ethers11.solidityPacked(
8153
8332
  ["string", "bytes32", "uint256", "uint256"],
8154
- ["registerSession", keyHash, this.config.duration, this.config.maxValue]
8333
+ ["registerSession", keyHash, sessionConfig.duration, sessionConfig.maxValue]
8155
8334
  );
8156
8335
  this.log("Challenge prepared, requesting Passkey signature...");
8157
8336
  const signature = await this.passkeySign(ethers11.getBytes(challenge));
@@ -8161,20 +8340,20 @@ var SessionManager = class {
8161
8340
  publicKeyX: this.credential.publicKeyX,
8162
8341
  publicKeyY: this.credential.publicKeyY,
8163
8342
  sessionKeyHash: keyHash,
8164
- duration: this.config.duration,
8165
- maxValue: this.config.maxValue,
8343
+ duration: sessionConfig.duration,
8344
+ maxValue: sessionConfig.maxValue,
8166
8345
  requireUV: true
8167
8346
  };
8168
8347
  await this.hubClient.registerSession(registerParams);
8169
8348
  this.log("Session registered on Hub");
8170
- const expiry = Date.now() + this.config.duration * 1e3;
8349
+ const expiry = Date.now() + sessionConfig.duration * 1e3;
8171
8350
  this.currentSession = {
8172
8351
  publicKey: keyPair.publicKey,
8173
8352
  privateKey: keyPair.privateKey,
8174
8353
  keyHash,
8175
8354
  expiry,
8176
- maxValue: this.config.maxValue,
8177
- chainScopes: this.config.chainScopes,
8355
+ maxValue: sessionConfig.maxValue,
8356
+ chainScopes: sessionConfig.chainScopes,
8178
8357
  userKeyHash: this.credential.keyHash
8179
8358
  };
8180
8359
  await this.storage.save(this.currentSession);
@@ -8199,12 +8378,15 @@ var SessionManager = class {
8199
8378
  *
8200
8379
  * @returns Loaded session or null if no valid session exists
8201
8380
  */
8202
- async loadSession() {
8381
+ async loadSession(keyHash) {
8203
8382
  try {
8204
- this.log("Loading session from storage...");
8205
- const session = await this.storage.load();
8383
+ this.log("Loading session from storage...", keyHash ?? "latest");
8384
+ const session = await this.storage.load(keyHash);
8206
8385
  if (!session) {
8207
8386
  this.log("No session found in storage");
8387
+ if (!keyHash) {
8388
+ this.currentSession = null;
8389
+ }
8208
8390
  return null;
8209
8391
  }
8210
8392
  if (session.expiry <= Date.now()) {
@@ -8221,27 +8403,43 @@ var SessionManager = class {
8221
8403
  return session;
8222
8404
  } catch (error) {
8223
8405
  this.log("Failed to load session:", error);
8224
- await this.storage.clear();
8406
+ if (!keyHash) {
8407
+ await this.storage.clear();
8408
+ }
8225
8409
  return null;
8226
8410
  }
8227
8411
  }
8412
+ async listSessions() {
8413
+ return this.storage.loadAll();
8414
+ }
8415
+ async selectSession(keyHash) {
8416
+ const session = await this.loadSession(keyHash);
8417
+ if (!session) {
8418
+ throw new SessionError(
8419
+ `Session ${keyHash} not found`,
8420
+ "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */
8421
+ );
8422
+ }
8423
+ return session;
8424
+ }
8228
8425
  /**
8229
8426
  * Revoke the current session (requires biometric authentication)
8230
8427
  *
8231
8428
  * @throws SessionError if no active session or revocation fails
8232
8429
  */
8233
- async revokeSession() {
8234
- if (!this.currentSession) {
8430
+ async revokeSession(keyHash) {
8431
+ const targetSession = keyHash ? await this.storage.load(keyHash) : this.currentSession;
8432
+ if (!targetSession) {
8235
8433
  throw new SessionError(
8236
- "No active session to revoke",
8237
- "NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
8434
+ keyHash ? `Session ${keyHash} not found` : "No active session to revoke",
8435
+ keyHash ? "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ : "NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
8238
8436
  );
8239
8437
  }
8240
8438
  try {
8241
- this.log("Revoking session:", this.currentSession.keyHash);
8439
+ this.log("Revoking session:", targetSession.keyHash);
8242
8440
  const challenge = ethers11.solidityPacked(
8243
8441
  ["string", "bytes32"],
8244
- ["revokeSession", this.currentSession.keyHash]
8442
+ ["revokeSession", targetSession.keyHash]
8245
8443
  );
8246
8444
  const signature = await this.passkeySign(ethers11.getBytes(challenge));
8247
8445
  this.log("Passkey signature obtained, revoking on Hub...");
@@ -8249,18 +8447,24 @@ var SessionManager = class {
8249
8447
  signature,
8250
8448
  publicKeyX: this.credential.publicKeyX,
8251
8449
  publicKeyY: this.credential.publicKeyY,
8252
- sessionKeyHash: this.currentSession.keyHash,
8450
+ sessionKeyHash: targetSession.keyHash,
8253
8451
  requireUV: true
8254
8452
  };
8255
8453
  await this.hubClient.revokeSession(revokeParams);
8256
8454
  this.log("Session revoked on Hub");
8257
- await this.storage.clear();
8258
- if (this.refreshTimer) {
8259
- clearTimeout(this.refreshTimer);
8260
- this.refreshTimer = null;
8455
+ await this.storage.remove(targetSession.keyHash);
8456
+ const revokedKeyHash = targetSession.keyHash;
8457
+ const revokedCurrentSession = this.currentSession?.keyHash === revokedKeyHash;
8458
+ if (revokedCurrentSession) {
8459
+ if (this.refreshTimer) {
8460
+ clearTimeout(this.refreshTimer);
8461
+ this.refreshTimer = null;
8462
+ }
8463
+ this.currentSession = await this.storage.load();
8464
+ if (this.currentSession && this.config.autoRefresh) {
8465
+ this.scheduleRefresh();
8466
+ }
8261
8467
  }
8262
- const revokedKeyHash = this.currentSession.keyHash;
8263
- this.currentSession = null;
8264
8468
  this.emit({ type: "session-revoked", keyHash: revokedKeyHash });
8265
8469
  this.log("Session revoked successfully");
8266
8470
  } catch (error) {
@@ -8338,45 +8542,46 @@ var SessionManager = class {
8338
8542
  * @returns Session signature
8339
8543
  * @throws SessionError if no active session, expired, or value exceeds limit
8340
8544
  */
8341
- async signWithSession(action) {
8342
- if (!this.currentSession) {
8545
+ async signWithSession(action, keyHash) {
8546
+ const session = keyHash ? await this.storage.load(keyHash) : this.currentSession;
8547
+ if (!session) {
8343
8548
  throw new SessionError(
8344
- "No active session available",
8345
- "NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
8549
+ keyHash ? `Session ${keyHash} not found` : "No active session available",
8550
+ keyHash ? "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ : "NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
8346
8551
  );
8347
8552
  }
8348
8553
  const now = Date.now();
8349
- if (now >= this.currentSession.expiry) {
8350
- this.emit({ type: "session-expired", keyHash: this.currentSession.keyHash });
8554
+ if (now >= session.expiry) {
8555
+ this.emit({ type: "session-expired", keyHash: session.keyHash });
8351
8556
  throw new SessionError(
8352
8557
  "Session has expired",
8353
8558
  "SESSION_EXPIRED" /* SESSION_EXPIRED */
8354
8559
  );
8355
8560
  }
8356
- if (this.currentSession.maxValue > 0n && action.value > this.currentSession.maxValue) {
8561
+ if (session.maxValue > 0n && action.value > session.maxValue) {
8357
8562
  throw new SessionError(
8358
- `Transaction value (${action.value}) exceeds session limit (${this.currentSession.maxValue})`,
8563
+ `Transaction value (${action.value}) exceeds session limit (${session.maxValue})`,
8359
8564
  "VALUE_EXCEEDS_LIMIT" /* VALUE_EXCEEDS_LIMIT */,
8360
- { value: action.value, limit: this.currentSession.maxValue }
8565
+ { value: action.value, limit: session.maxValue }
8361
8566
  );
8362
8567
  }
8363
- if (this.currentSession.chainScopes.length > 0 && !this.currentSession.chainScopes.includes(action.targetChain)) {
8568
+ if (session.chainScopes.length > 0 && !session.chainScopes.includes(action.targetChain)) {
8364
8569
  throw new SessionError(
8365
8570
  `Chain ${action.targetChain} not in session scope`,
8366
8571
  "CHAIN_NOT_ALLOWED" /* CHAIN_NOT_ALLOWED */,
8367
- { chain: action.targetChain, allowedChains: this.currentSession.chainScopes }
8572
+ { chain: action.targetChain, allowedChains: session.chainScopes }
8368
8573
  );
8369
8574
  }
8370
8575
  this.log("Signing action with session key...");
8371
8576
  const messageHash = hashAction(action);
8372
8577
  const { signature } = signWithSessionKey(
8373
- this.currentSession.privateKey,
8578
+ session.privateKey,
8374
8579
  messageHash
8375
8580
  );
8376
8581
  const sessionSignature = {
8377
8582
  signature,
8378
- sessionKeyHash: this.currentSession.keyHash,
8379
- userKeyHash: this.currentSession.userKeyHash,
8583
+ sessionKeyHash: session.keyHash,
8584
+ userKeyHash: session.userKeyHash,
8380
8585
  timestamp: now,
8381
8586
  nonce: action.nonce
8382
8587
  };
@@ -8389,8 +8594,8 @@ var SessionManager = class {
8389
8594
  * @param action Action parameters
8390
8595
  * @returns Session-signed action ready for submission
8391
8596
  */
8392
- async signAction(action) {
8393
- const signature = await this.signWithSession(action);
8597
+ async signAction(action, keyHash) {
8598
+ const signature = await this.signWithSession(action, keyHash);
8394
8599
  return {
8395
8600
  action,
8396
8601
  signature,
@@ -9253,6 +9458,7 @@ export {
9253
9458
  calculatePercentage,
9254
9459
  computeKeyHash,
9255
9460
  computeSessionKeyHash,
9461
+ configureDefaultRpcUrls,
9256
9462
  createAuditEntry,
9257
9463
  createChainClient,
9258
9464
  createChainDetector,
@@ -9323,6 +9529,7 @@ export {
9323
9529
  getExplorerUrl,
9324
9530
  getFeatureFlags,
9325
9531
  getHubChains,
9532
+ getRpcUrlOverride,
9326
9533
  getSequenceFromTxReceipt,
9327
9534
  getContractPrincipal as getStacksContractPrincipal,
9328
9535
  getStacksExplorerAddressUrl,