@veridex/sdk 1.1.6 → 1.1.7

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 (95) hide show
  1. package/dist/{EVMClient-CTOtNY8I.d.mts → EVMClient-DqDiFak8.d.mts} +1 -1
  2. package/dist/auth/prepareAuth.d.mts +5 -4
  3. package/dist/auth/prepareAuth.js +57 -1415
  4. package/dist/auth/prepareAuth.js.map +1 -1
  5. package/dist/auth/prepareAuth.mjs +17 -96
  6. package/dist/auth/prepareAuth.mjs.map +1 -1
  7. package/dist/chains/aptos/index.d.mts +1 -1
  8. package/dist/chains/aptos/index.js +11 -33
  9. package/dist/chains/aptos/index.js.map +1 -1
  10. package/dist/chains/aptos/index.mjs +2 -2
  11. package/dist/chains/avalanche/index.d.mts +2 -2
  12. package/dist/chains/avalanche/index.js +19 -115
  13. package/dist/chains/avalanche/index.js.map +1 -1
  14. package/dist/chains/avalanche/index.mjs +3 -3
  15. package/dist/chains/evm/index.d.mts +3 -3
  16. package/dist/chains/evm/index.js +19 -115
  17. package/dist/chains/evm/index.js.map +1 -1
  18. package/dist/chains/evm/index.mjs +2 -2
  19. package/dist/chains/solana/index.d.mts +1 -1
  20. package/dist/chains/solana/index.js +11 -33
  21. package/dist/chains/solana/index.js.map +1 -1
  22. package/dist/chains/solana/index.mjs +2 -2
  23. package/dist/chains/stacks/index.d.mts +1 -1
  24. package/dist/chains/stacks/index.js +11 -38
  25. package/dist/chains/stacks/index.js.map +1 -1
  26. package/dist/chains/stacks/index.mjs +2 -2
  27. package/dist/chains/starknet/index.d.mts +36 -2
  28. package/dist/chains/starknet/index.js +208 -37
  29. package/dist/chains/starknet/index.js.map +1 -1
  30. package/dist/chains/starknet/index.mjs +9 -4
  31. package/dist/chains/sui/index.d.mts +1 -1
  32. package/dist/chains/sui/index.js +11 -27
  33. package/dist/chains/sui/index.js.map +1 -1
  34. package/dist/chains/sui/index.mjs +2 -2
  35. package/dist/{chunk-ZNIVNPGF.mjs → chunk-3PCAVZUZ.mjs} +173 -37
  36. package/dist/chunk-3PCAVZUZ.mjs.map +1 -0
  37. package/dist/{chunk-DQOW3G7M.mjs → chunk-6BINP4RT.mjs} +48 -9
  38. package/dist/{chunk-DQOW3G7M.mjs.map → chunk-6BINP4RT.mjs.map} +1 -1
  39. package/dist/{chunk-7KN6Y4GX.mjs → chunk-AK5HWYX4.mjs} +12 -40
  40. package/dist/chunk-AK5HWYX4.mjs.map +1 -0
  41. package/dist/{chunk-QVTADARB.mjs → chunk-FPSCAGYS.mjs} +12 -35
  42. package/dist/chunk-FPSCAGYS.mjs.map +1 -0
  43. package/dist/{chunk-USVZH4QC.mjs → chunk-H3WRT6Y4.mjs} +20 -117
  44. package/dist/chunk-H3WRT6Y4.mjs.map +1 -0
  45. package/dist/{chunk-GXJUY2SC.mjs → chunk-MNH22BM2.mjs} +12 -35
  46. package/dist/chunk-MNH22BM2.mjs.map +1 -0
  47. package/dist/chunk-N42LPFPJ.mjs +177 -0
  48. package/dist/chunk-N42LPFPJ.mjs.map +1 -0
  49. package/dist/{chunk-D57UJ4L5.mjs → chunk-NKSRF45N.mjs} +12 -29
  50. package/dist/chunk-NKSRF45N.mjs.map +1 -0
  51. package/dist/{chunk-2CALEUER.mjs → chunk-SKZLZFE2.mjs} +5 -58
  52. package/dist/chunk-SKZLZFE2.mjs.map +1 -0
  53. package/dist/{chunk-NVRAQPSF.mjs → chunk-UF5NWMSQ.mjs} +20 -4
  54. package/dist/chunk-UF5NWMSQ.mjs.map +1 -0
  55. package/dist/chunk-WC4X3MAO.mjs +58 -0
  56. package/dist/chunk-WC4X3MAO.mjs.map +1 -0
  57. package/dist/{chunk-5FH67KLG.mjs → chunk-XHDOSV2F.mjs} +2 -2
  58. package/dist/{index-9ercn1sa.d.mts → index-D1nb2JV9.d.mts} +1 -1
  59. package/dist/index-qyOqd8tx.d.mts +517 -0
  60. package/dist/index.d.mts +27 -364
  61. package/dist/index.js +2316 -2473
  62. package/dist/index.js.map +1 -1
  63. package/dist/index.mjs +978 -51
  64. package/dist/index.mjs.map +1 -1
  65. package/dist/passkey.mjs +2 -1
  66. package/dist/payload.d.mts +22 -28
  67. package/dist/payload.js +50 -9
  68. package/dist/payload.js.map +1 -1
  69. package/dist/payload.mjs +7 -3
  70. package/dist/platform/index.d.mts +3 -0
  71. package/dist/platform/index.js +216 -0
  72. package/dist/platform/index.js.map +1 -0
  73. package/dist/platform/index.mjs +21 -0
  74. package/dist/platform/index.mjs.map +1 -0
  75. package/dist/{portfolio-W2FQ2G3O.mjs → portfolio-MLP2JIFK.mjs} +2 -3
  76. package/dist/queries/index.mjs +324 -10
  77. package/dist/queries/index.mjs.map +1 -1
  78. package/dist/{types-DQ5dtU9x.d.mts → types-CdlEbixV.d.mts} +11 -1
  79. package/package.json +7 -1
  80. package/dist/chunk-2CALEUER.mjs.map +0 -1
  81. package/dist/chunk-72ZA3OYQ.mjs +0 -20
  82. package/dist/chunk-72ZA3OYQ.mjs.map +0 -1
  83. package/dist/chunk-7KN6Y4GX.mjs.map +0 -1
  84. package/dist/chunk-D57UJ4L5.mjs.map +0 -1
  85. package/dist/chunk-GXJUY2SC.mjs.map +0 -1
  86. package/dist/chunk-NVRAQPSF.mjs.map +0 -1
  87. package/dist/chunk-QVTADARB.mjs.map +0 -1
  88. package/dist/chunk-USVZH4QC.mjs.map +0 -1
  89. package/dist/chunk-XDIIFIW6.mjs +0 -330
  90. package/dist/chunk-XDIIFIW6.mjs.map +0 -1
  91. package/dist/chunk-ZNIVNPGF.mjs.map +0 -1
  92. package/dist/chunk-ZXMTPBSP.mjs +0 -857
  93. package/dist/chunk-ZXMTPBSP.mjs.map +0 -1
  94. /package/dist/{chunk-5FH67KLG.mjs.map → chunk-XHDOSV2F.mjs.map} +0 -0
  95. /package/dist/{portfolio-W2FQ2G3O.mjs.map → portfolio-MLP2JIFK.mjs.map} +0 -0
@@ -1,330 +0,0 @@
1
- import {
2
- WORMHOLE_QUERY_PROXY_URLS
3
- } from "./chunk-72ZA3OYQ.mjs";
4
- import {
5
- MAINNET_CHAINS,
6
- TESTNET_CHAINS
7
- } from "./chunk-KYOOTSRA.mjs";
8
-
9
- // src/queries/hubState.ts
10
- import axios from "axios";
11
- import { Buffer } from "buffer";
12
- import { ethers } from "ethers";
13
- import {
14
- EthCallQueryRequest,
15
- EthCallQueryResponse,
16
- PerChainQueryRequest,
17
- QueryRequest,
18
- QueryResponse,
19
- hexToUint8Array,
20
- isValidHexString
21
- } from "@wormhole-foundation/wormhole-query-sdk";
22
- var QueryHubStateError = class extends Error {
23
- code;
24
- cause;
25
- constructor(code, message, cause) {
26
- super(message);
27
- this.name = "QueryHubStateError";
28
- this.code = code;
29
- this.cause = cause;
30
- }
31
- };
32
- function resolveNetwork(options) {
33
- if (options?.network) return options.network;
34
- const envCandidates = [
35
- globalThis?.process?.env?.NEXT_PUBLIC_VERIDEX_NETWORK,
36
- globalThis?.process?.env?.VERIDEX_NETWORK,
37
- globalThis?.process?.env?.NEXT_PUBLIC_WORMHOLE_NETWORK,
38
- globalThis?.process?.env?.WORMHOLE_NETWORK
39
- ].filter(Boolean);
40
- const env = envCandidates[0]?.toLowerCase();
41
- if (env === "mainnet" || env === "testnet") return env;
42
- return "testnet";
43
- }
44
- function concatBytes(parts) {
45
- const total = parts.reduce((sum, p) => sum + p.length, 0);
46
- const out = new Uint8Array(total);
47
- let offset = 0;
48
- for (const p of parts) {
49
- out.set(p, offset);
50
- offset += p.length;
51
- }
52
- return out;
53
- }
54
- function signaturesToProofBytes(signatures) {
55
- const chunks = [];
56
- for (const sig of signatures) {
57
- if (typeof sig !== "string" || sig.length !== 132 || !/^[0-9a-fA-F]+$/.test(sig)) {
58
- throw new QueryHubStateError(
59
- "PROXY_RESPONSE_INVALID",
60
- `Invalid guardian signature format (expected 132 hex chars): ${String(sig)}`
61
- );
62
- }
63
- chunks.push(hexToUint8Array(`0x${sig}`));
64
- }
65
- return concatBytes(chunks);
66
- }
67
- function decodeQueryBytes(bytes) {
68
- if (typeof bytes !== "string" || bytes.length === 0) {
69
- throw new QueryHubStateError("PROXY_RESPONSE_INVALID", "Missing query response bytes");
70
- }
71
- if (isValidHexString(bytes)) {
72
- return hexToUint8Array(bytes);
73
- }
74
- try {
75
- if (typeof atob === "function") {
76
- const raw = atob(bytes);
77
- const arr = new Uint8Array(raw.length);
78
- for (let i = 0; i < raw.length; i++) arr[i] = raw.charCodeAt(i);
79
- return arr;
80
- }
81
- } catch {
82
- }
83
- try {
84
- return new Uint8Array(Buffer.from(bytes, "base64"));
85
- } catch (cause) {
86
- throw new QueryHubStateError("PROXY_RESPONSE_INVALID", "Unrecognized query response bytes encoding", cause);
87
- }
88
- }
89
- function sleep(ms) {
90
- return new Promise((resolve) => setTimeout(resolve, ms));
91
- }
92
- async function withExponentialBackoff(fn, maxAttempts) {
93
- let attempt = 0;
94
- let lastError;
95
- while (attempt < maxAttempts) {
96
- try {
97
- return await fn();
98
- } catch (err) {
99
- lastError = err;
100
- attempt += 1;
101
- if (attempt >= maxAttempts) break;
102
- const baseMs = 250;
103
- const backoffMs = Math.min(5e3, baseMs * 2 ** (attempt - 1));
104
- const jitterMs = Math.floor(Math.random() * 100);
105
- await sleep(backoffMs + jitterMs);
106
- }
107
- }
108
- throw lastError;
109
- }
110
- function getHubConfig(network) {
111
- if (network === "testnet") {
112
- const baseSepolia = TESTNET_CHAINS.baseSepolia;
113
- if (!baseSepolia?.contracts?.hub) {
114
- throw new QueryHubStateError("MISSING_HUB_ADDRESS", "Missing Base Sepolia hub address in SDK constants");
115
- }
116
- return {
117
- wormholeChainId: baseSepolia.wormholeChainId,
118
- hubAddress: baseSepolia.contracts.hub,
119
- endpoint: WORMHOLE_QUERY_PROXY_URLS.testnet,
120
- rpcUrl: baseSepolia.rpcUrl
121
- };
122
- }
123
- if (network === "mainnet") {
124
- const base = MAINNET_CHAINS.base;
125
- const hubAddress = base?.contracts?.hub;
126
- if (!hubAddress) {
127
- throw new QueryHubStateError(
128
- "MISSING_HUB_ADDRESS",
129
- "Missing mainnet hub address in SDK constants (MAINNET_CHAINS.base.contracts.hub)"
130
- );
131
- }
132
- return {
133
- wormholeChainId: base.wormholeChainId,
134
- hubAddress,
135
- endpoint: WORMHOLE_QUERY_PROXY_URLS.mainnet,
136
- rpcUrl: base.rpcUrl
137
- };
138
- }
139
- throw new QueryHubStateError("UNSUPPORTED_NETWORK", `Unsupported network: ${network}`);
140
- }
141
- function encodeHubCalls(hubAddress, userKeyHash) {
142
- const nonceAbiCandidates = [
143
- "function getUserNonce(bytes32 userKeyHash) view returns (uint256)",
144
- "function userNonces(bytes32 userKeyHash) view returns (uint256)",
145
- "function getNonceByHash(bytes32 userKeyHash) view returns (uint256)"
146
- ];
147
- const registeredAbiCandidates = [
148
- "function registeredKeys(bytes32 userKeyHash) view returns (bool)",
149
- "function isKeyRegisteredByHash(bytes32 userKeyHash) view returns (bool)"
150
- ];
151
- const actionHashAbiCandidates = [
152
- "function getUserLastActionHash(bytes32 userKeyHash) view returns (bytes32)",
153
- "function userLastActionHash(bytes32 userKeyHash) view returns (bytes32)"
154
- ];
155
- const iface = new ethers.Interface([
156
- ...nonceAbiCandidates,
157
- ...registeredAbiCandidates,
158
- ...actionHashAbiCandidates
159
- ]);
160
- const nonceFnNames = ["getUserNonce", "userNonces", "getNonceByHash"];
161
- const regFnNames = ["registeredKeys", "isKeyRegisteredByHash"];
162
- const actionHashFnNames = ["getUserLastActionHash", "userLastActionHash"];
163
- return [
164
- ...nonceFnNames.map((fn) => ({
165
- to: hubAddress,
166
- data: iface.encodeFunctionData(fn, [userKeyHash])
167
- })),
168
- ...regFnNames.map((fn) => ({
169
- to: hubAddress,
170
- data: iface.encodeFunctionData(fn, [userKeyHash])
171
- })),
172
- ...actionHashFnNames.map((fn) => ({
173
- to: hubAddress,
174
- data: iface.encodeFunctionData(fn, [userKeyHash])
175
- }))
176
- ];
177
- }
178
- function decodeFirstNonce(results) {
179
- const candidates = [
180
- "function getUserNonce(bytes32 userKeyHash) view returns (uint256)",
181
- "function userNonces(bytes32 userKeyHash) view returns (uint256)",
182
- "function getNonceByHash(bytes32 userKeyHash) view returns (uint256)"
183
- ];
184
- const iface = new ethers.Interface(candidates);
185
- const fnNames = ["getUserNonce", "userNonces", "getNonceByHash"];
186
- for (let idx = 0; idx < fnNames.length; idx++) {
187
- const fnName = fnNames[idx];
188
- try {
189
- const data = results[idx];
190
- if (!data || data === "0x") continue;
191
- const decoded = iface.decodeFunctionResult(fnName, data);
192
- return decoded[0];
193
- } catch {
194
- }
195
- }
196
- throw new QueryHubStateError("QUERY_RESPONSE_INVALID", "Unable to decode user nonce from query response");
197
- }
198
- function decodeFirstIsRegistered(results) {
199
- const nonceCandidateCount = 3;
200
- const candidates = [
201
- "function registeredKeys(bytes32 userKeyHash) view returns (bool)",
202
- "function isKeyRegisteredByHash(bytes32 userKeyHash) view returns (bool)"
203
- ];
204
- const iface = new ethers.Interface(candidates);
205
- const fnNames = ["registeredKeys", "isKeyRegisteredByHash"];
206
- for (let i = 0; i < fnNames.length; i++) {
207
- const fnName = fnNames[i];
208
- try {
209
- const data = results[nonceCandidateCount + i];
210
- if (!data || data === "0x") continue;
211
- const decoded = iface.decodeFunctionResult(fnName, data);
212
- return Boolean(decoded[0]);
213
- } catch {
214
- }
215
- }
216
- return false;
217
- }
218
- function decodeLastActionHash(results) {
219
- const nonceCandidateCount = 3;
220
- const registeredCandidateCount = 2;
221
- const actionHashOffset = nonceCandidateCount + registeredCandidateCount;
222
- const candidates = [
223
- "function getUserLastActionHash(bytes32 userKeyHash) view returns (bytes32)",
224
- "function userLastActionHash(bytes32 userKeyHash) view returns (bytes32)"
225
- ];
226
- const iface = new ethers.Interface(candidates);
227
- const fnNames = ["getUserLastActionHash", "userLastActionHash"];
228
- for (let i = 0; i < fnNames.length; i++) {
229
- const fnName = fnNames[i];
230
- try {
231
- const data = results[actionHashOffset + i];
232
- if (!data || data === "0x") continue;
233
- const decoded = iface.decodeFunctionResult(fnName, data);
234
- return decoded[0];
235
- } catch {
236
- }
237
- }
238
- return ethers.ZeroHash;
239
- }
240
- async function queryHubState(userKeyHash, apiKey, options) {
241
- if (typeof userKeyHash !== "string" || userKeyHash.length === 0) {
242
- throw new QueryHubStateError("INVALID_ARGUMENT", "userKeyHash is required");
243
- }
244
- if (!isValidHexString(userKeyHash) || hexToUint8Array(userKeyHash).length !== 32) {
245
- throw new QueryHubStateError("INVALID_ARGUMENT", "userKeyHash must be a 32-byte hex string");
246
- }
247
- if (typeof apiKey !== "string" || apiKey.length === 0) {
248
- throw new QueryHubStateError("INVALID_ARGUMENT", "apiKey is required");
249
- }
250
- const network = resolveNetwork(options);
251
- const maxAgeSeconds = options?.maxAge ?? 60;
252
- const maxAttempts = options?.maxAttempts ?? 4;
253
- const { wormholeChainId, hubAddress, endpoint, rpcUrl } = getHubConfig(network);
254
- const provider = new ethers.JsonRpcProvider(rpcUrl);
255
- const callData = encodeHubCalls(hubAddress, userKeyHash);
256
- const doFetch = async () => {
257
- try {
258
- const latestBlock = await provider.getBlockNumber();
259
- const blockTag = Math.max(0, latestBlock - 2);
260
- const request = new QueryRequest(Date.now() & 4294967295, [
261
- new PerChainQueryRequest(wormholeChainId, new EthCallQueryRequest(blockTag, callData))
262
- ]);
263
- const requestHex = Buffer.from(request.serialize()).toString("hex");
264
- const response = await axios.post(
265
- endpoint,
266
- { bytes: requestHex },
267
- {
268
- headers: {
269
- "X-API-Key": apiKey,
270
- "Content-Type": "application/json"
271
- },
272
- timeout: 1e4
273
- }
274
- );
275
- const data = response.data;
276
- const signatures = data?.signatures;
277
- const bytes = data?.bytes;
278
- if (!Array.isArray(signatures) || typeof bytes !== "string") {
279
- throw new QueryHubStateError("PROXY_RESPONSE_INVALID", "Query Proxy response missing signatures/bytes");
280
- }
281
- const proof = signaturesToProofBytes(signatures);
282
- const queryBytes = decodeQueryBytes(bytes);
283
- const parsed = QueryResponse.from(queryBytes);
284
- const perChain = parsed.responses.find((r) => r.chainId === wormholeChainId);
285
- if (!perChain) {
286
- throw new QueryHubStateError("QUERY_RESPONSE_INVALID", "Missing per-chain response for hub chain");
287
- }
288
- const chainResp = EthCallQueryResponse.from(perChain.response.serialize());
289
- const blockTime = Number(chainResp.blockTime);
290
- const nowSeconds = Math.floor(Date.now() / 1e3);
291
- if (nowSeconds - blockTime > maxAgeSeconds) {
292
- throw new QueryHubStateError(
293
- "ATTESTATION_STALE",
294
- `Guardian attestation is stale (blockTime=${blockTime}, now=${nowSeconds}, maxAge=${maxAgeSeconds}s)`
295
- );
296
- }
297
- const nonce = decodeFirstNonce(chainResp.results);
298
- const isRegistered = decodeFirstIsRegistered(chainResp.results);
299
- const lastActionHash = decodeLastActionHash(chainResp.results);
300
- return {
301
- nonce,
302
- isRegistered,
303
- blockTime,
304
- proof,
305
- lastActionHash
306
- };
307
- } catch (err) {
308
- if (err instanceof QueryHubStateError) throw err;
309
- if (axios.isAxiosError(err)) {
310
- const ax = err;
311
- const status = ax.response?.status;
312
- const statusText = ax.response?.statusText;
313
- const details = typeof ax.response?.data === "string" ? ax.response?.data : void 0;
314
- throw new QueryHubStateError(
315
- "PROXY_HTTP_ERROR",
316
- `Query Proxy request failed${status ? ` (${status} ${statusText ?? ""})` : ""}${details ? `: ${details}` : ""}`,
317
- err
318
- );
319
- }
320
- throw new QueryHubStateError("PROXY_HTTP_ERROR", "Query Proxy request failed", err);
321
- }
322
- };
323
- return await withExponentialBackoff(doFetch, maxAttempts);
324
- }
325
-
326
- export {
327
- QueryHubStateError,
328
- queryHubState
329
- };
330
- //# sourceMappingURL=chunk-XDIIFIW6.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/queries/hubState.ts"],"sourcesContent":["import axios, { AxiosError } from 'axios';\nimport { Buffer } from 'buffer';\nimport { ethers } from 'ethers';\nimport {\n EthCallQueryRequest,\n EthCallQueryResponse,\n PerChainQueryRequest,\n QueryRequest,\n QueryResponse,\n hexToUint8Array,\n isValidHexString,\n} from '@wormhole-foundation/wormhole-query-sdk';\n\nimport { MAINNET_CHAINS, TESTNET_CHAINS } from '../constants.js';\nimport { WORMHOLE_QUERY_PROXY_URLS } from './constants.js';\n\nexport type QueryHubStateNetwork = 'testnet' | 'mainnet';\n\nexport type QueryHubStateOptions = {\n /** Max response age in seconds (default: 60). */\n maxAge?: number;\n network?: QueryHubStateNetwork;\n /** Maximum attempts including the first try (default: 4). */\n maxAttempts?: number;\n};\n\nexport type HubStateResult = {\n nonce: bigint;\n isRegistered: boolean;\n blockTime: number;\n proof: Uint8Array;\n /** Last action hash (Issue #9/#10 - for action-hash binding) */\n lastActionHash?: string;\n};\n\nexport type QueryHubStateErrorCode =\n | 'INVALID_ARGUMENT'\n | 'UNSUPPORTED_NETWORK'\n | 'MISSING_HUB_ADDRESS'\n | 'PROXY_HTTP_ERROR'\n | 'PROXY_RESPONSE_INVALID'\n | 'ATTESTATION_STALE'\n | 'QUERY_RESPONSE_INVALID';\n\nexport class QueryHubStateError extends Error {\n code: QueryHubStateErrorCode;\n cause?: unknown;\n\n constructor(code: QueryHubStateErrorCode, message: string, cause?: unknown) {\n super(message);\n this.name = 'QueryHubStateError';\n this.code = code;\n this.cause = cause;\n }\n}\n\nfunction resolveNetwork(options?: QueryHubStateOptions): QueryHubStateNetwork {\n if (options?.network) return options.network;\n\n const envCandidates = [\n (globalThis as any)?.process?.env?.NEXT_PUBLIC_VERIDEX_NETWORK,\n (globalThis as any)?.process?.env?.VERIDEX_NETWORK,\n (globalThis as any)?.process?.env?.NEXT_PUBLIC_WORMHOLE_NETWORK,\n (globalThis as any)?.process?.env?.WORMHOLE_NETWORK,\n ].filter(Boolean);\n\n const env = (envCandidates[0] as string | undefined)?.toLowerCase();\n if (env === 'mainnet' || env === 'testnet') return env;\n\n // Default to testnet to support Base Sepolia out-of-the-box.\n return 'testnet';\n}\n\nfunction concatBytes(parts: Uint8Array[]): Uint8Array {\n const total = parts.reduce((sum, p) => sum + p.length, 0);\n const out = new Uint8Array(total);\n let offset = 0;\n for (const p of parts) {\n out.set(p, offset);\n offset += p.length;\n }\n return out;\n}\n\nfunction signaturesToProofBytes(signatures: string[]): Uint8Array {\n const chunks: Uint8Array[] = [];\n\n for (const sig of signatures) {\n if (typeof sig !== 'string' || sig.length !== 132 || !/^[0-9a-fA-F]+$/.test(sig)) {\n throw new QueryHubStateError(\n 'PROXY_RESPONSE_INVALID',\n `Invalid guardian signature format (expected 132 hex chars): ${String(sig)}`\n );\n }\n // Avoid Node Buffer-backed Uint8Array (can surface as SharedArrayBuffer in DTS types).\n chunks.push(hexToUint8Array(`0x${sig}`));\n }\n\n return concatBytes(chunks);\n}\n\nfunction decodeQueryBytes(bytes: string): Uint8Array {\n if (typeof bytes !== 'string' || bytes.length === 0) {\n throw new QueryHubStateError('PROXY_RESPONSE_INVALID', 'Missing query response bytes');\n }\n\n // Query Proxy commonly returns a 0x-prefixed hex string.\n if (isValidHexString(bytes)) {\n return hexToUint8Array(bytes);\n }\n\n // Fallback: attempt base64 decoding.\n try {\n if (typeof atob === 'function') {\n const raw = atob(bytes);\n const arr = new Uint8Array(raw.length);\n for (let i = 0; i < raw.length; i++) arr[i] = raw.charCodeAt(i);\n return arr;\n }\n } catch {\n // ignore\n }\n\n try {\n return new Uint8Array(Buffer.from(bytes, 'base64'));\n } catch (cause) {\n throw new QueryHubStateError('PROXY_RESPONSE_INVALID', 'Unrecognized query response bytes encoding', cause);\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function withExponentialBackoff<T>(\n fn: () => Promise<T>,\n maxAttempts: number\n): Promise<T> {\n let attempt = 0;\n let lastError: unknown;\n\n while (attempt < maxAttempts) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n attempt += 1;\n if (attempt >= maxAttempts) break;\n\n const baseMs = 250;\n const backoffMs = Math.min(5_000, baseMs * 2 ** (attempt - 1));\n const jitterMs = Math.floor(Math.random() * 100);\n await sleep(backoffMs + jitterMs);\n }\n }\n\n throw lastError;\n}\n\nfunction getHubConfig(network: QueryHubStateNetwork): {\n wormholeChainId: number;\n hubAddress: string;\n endpoint: string;\n rpcUrl: string;\n} {\n if (network === 'testnet') {\n const baseSepolia = TESTNET_CHAINS.baseSepolia;\n if (!baseSepolia?.contracts?.hub) {\n throw new QueryHubStateError('MISSING_HUB_ADDRESS', 'Missing Base Sepolia hub address in SDK constants');\n }\n\n return {\n wormholeChainId: baseSepolia.wormholeChainId,\n hubAddress: baseSepolia.contracts.hub,\n endpoint: WORMHOLE_QUERY_PROXY_URLS.testnet,\n rpcUrl: baseSepolia.rpcUrl,\n };\n }\n\n if (network === 'mainnet') {\n const base = MAINNET_CHAINS.base;\n const hubAddress = (base?.contracts as any)?.hub as string | undefined;\n\n if (!hubAddress) {\n throw new QueryHubStateError(\n 'MISSING_HUB_ADDRESS',\n 'Missing mainnet hub address in SDK constants (MAINNET_CHAINS.base.contracts.hub)'\n );\n }\n\n return {\n wormholeChainId: base.wormholeChainId,\n hubAddress,\n endpoint: WORMHOLE_QUERY_PROXY_URLS.mainnet,\n rpcUrl: base.rpcUrl,\n };\n }\n\n throw new QueryHubStateError('UNSUPPORTED_NETWORK', `Unsupported network: ${network}`);\n}\n\nfunction encodeHubCalls(hubAddress: string, userKeyHash: string): { to: string; data: string }[] {\n // Support both the spec name and known on-chain variants.\n const nonceAbiCandidates = [\n 'function getUserNonce(bytes32 userKeyHash) view returns (uint256)',\n 'function userNonces(bytes32 userKeyHash) view returns (uint256)',\n 'function getNonceByHash(bytes32 userKeyHash) view returns (uint256)',\n ];\n\n const registeredAbiCandidates = [\n 'function registeredKeys(bytes32 userKeyHash) view returns (bool)',\n 'function isKeyRegisteredByHash(bytes32 userKeyHash) view returns (bool)',\n ];\n\n // Issue #9/#10: Add getUserLastActionHash for action-hash binding\n const actionHashAbiCandidates = [\n 'function getUserLastActionHash(bytes32 userKeyHash) view returns (bytes32)',\n 'function userLastActionHash(bytes32 userKeyHash) view returns (bytes32)',\n ];\n\n // We encode *all* candidates; the proxy will execute each call, and we decode the first successful one.\n // This makes the client resilient to Hub ABI differences across deployments.\n const iface = new ethers.Interface([\n ...nonceAbiCandidates,\n ...registeredAbiCandidates,\n ...actionHashAbiCandidates,\n ]);\n\n const nonceFnNames = ['getUserNonce', 'userNonces', 'getNonceByHash'] as const;\n const regFnNames = ['registeredKeys', 'isKeyRegisteredByHash'] as const;\n const actionHashFnNames = ['getUserLastActionHash', 'userLastActionHash'] as const;\n\n return [\n ...nonceFnNames.map((fn) => ({\n to: hubAddress,\n data: iface.encodeFunctionData(fn, [userKeyHash]),\n })),\n ...regFnNames.map((fn) => ({\n to: hubAddress,\n data: iface.encodeFunctionData(fn, [userKeyHash]),\n })),\n ...actionHashFnNames.map((fn) => ({\n to: hubAddress,\n data: iface.encodeFunctionData(fn, [userKeyHash]),\n })),\n ];\n}\n\nfunction decodeFirstNonce(results: string[]): bigint {\n const candidates = [\n 'function getUserNonce(bytes32 userKeyHash) view returns (uint256)',\n 'function userNonces(bytes32 userKeyHash) view returns (uint256)',\n 'function getNonceByHash(bytes32 userKeyHash) view returns (uint256)',\n ];\n const iface = new ethers.Interface(candidates);\n const fnNames = ['getUserNonce', 'userNonces', 'getNonceByHash'] as const;\n\n for (let idx = 0; idx < fnNames.length; idx++) {\n const fnName = fnNames[idx];\n try {\n const data = results[idx];\n if (!data || data === '0x') continue;\n const decoded = iface.decodeFunctionResult(fnName, data);\n return decoded[0] as bigint;\n } catch {\n // keep trying\n }\n }\n\n throw new QueryHubStateError('QUERY_RESPONSE_INVALID', 'Unable to decode user nonce from query response');\n}\n\nfunction decodeFirstIsRegistered(results: string[]): boolean {\n const nonceCandidateCount = 3;\n const candidates = [\n 'function registeredKeys(bytes32 userKeyHash) view returns (bool)',\n 'function isKeyRegisteredByHash(bytes32 userKeyHash) view returns (bool)',\n ];\n const iface = new ethers.Interface(candidates);\n const fnNames = ['registeredKeys', 'isKeyRegisteredByHash'] as const;\n\n for (let i = 0; i < fnNames.length; i++) {\n const fnName = fnNames[i];\n try {\n const data = results[nonceCandidateCount + i];\n if (!data || data === '0x') continue;\n const decoded = iface.decodeFunctionResult(fnName, data);\n return Boolean(decoded[0]);\n } catch {\n // keep trying\n }\n }\n\n // If the hub deployment doesn’t support registration, treat as false.\n return false;\n}\n\n/** * Decode last action hash from query results (Issue #9/#10)\n * Returns zero hash if not available (backwards compatibility)\n */\nfunction decodeLastActionHash(results: string[]): string {\n const nonceCandidateCount = 3;\n const registeredCandidateCount = 2;\n const actionHashOffset = nonceCandidateCount + registeredCandidateCount;\n\n const candidates = [\n 'function getUserLastActionHash(bytes32 userKeyHash) view returns (bytes32)',\n 'function userLastActionHash(bytes32 userKeyHash) view returns (bytes32)',\n ];\n const iface = new ethers.Interface(candidates);\n const fnNames = ['getUserLastActionHash', 'userLastActionHash'] as const;\n\n for (let i = 0; i < fnNames.length; i++) {\n const fnName = fnNames[i];\n try {\n const data = results[actionHashOffset + i];\n if (!data || data === '0x') continue;\n const decoded = iface.decodeFunctionResult(fnName, data);\n return decoded[0] as string;\n } catch {\n // keep trying\n }\n }\n\n // Backwards compatibility: return zero hash if not available\n return ethers.ZeroHash;\n}\n\n/** * Fetch Guardian-attested Hub state directly from the Wormhole Query Proxy.\n *\n * Client-side only: this avoids relayer API costs and produces a Guardian-signed proof\n * that can be forwarded to the relayer for on-chain verification/submission.\n */\nexport async function queryHubState(\n userKeyHash: string,\n apiKey: string,\n options?: QueryHubStateOptions\n): Promise<HubStateResult> {\n if (typeof userKeyHash !== 'string' || userKeyHash.length === 0) {\n throw new QueryHubStateError('INVALID_ARGUMENT', 'userKeyHash is required');\n }\n if (!isValidHexString(userKeyHash) || hexToUint8Array(userKeyHash).length !== 32) {\n throw new QueryHubStateError('INVALID_ARGUMENT', 'userKeyHash must be a 32-byte hex string');\n }\n if (typeof apiKey !== 'string' || apiKey.length === 0) {\n throw new QueryHubStateError('INVALID_ARGUMENT', 'apiKey is required');\n }\n\n const network = resolveNetwork(options);\n const maxAgeSeconds = options?.maxAge ?? 60;\n const maxAttempts = options?.maxAttempts ?? 4;\n\n const { wormholeChainId, hubAddress, endpoint, rpcUrl } = getHubConfig(network);\n\n const provider = new ethers.JsonRpcProvider(rpcUrl);\n\n const callData = encodeHubCalls(hubAddress, userKeyHash);\n\n const doFetch = async () => {\n try {\n const latestBlock = await provider.getBlockNumber();\n const blockTag = Math.max(0, latestBlock - 2);\n\n const request = new QueryRequest(Date.now() & 0xffffffff, [\n new PerChainQueryRequest(wormholeChainId, new EthCallQueryRequest(blockTag, callData)),\n ]);\n\n // Wormhole Query Proxy expects raw hex WITHOUT 0x prefix\n const requestHex = Buffer.from(request.serialize()).toString('hex');\n\n const response = await axios.post(\n endpoint,\n { bytes: requestHex },\n {\n headers: {\n 'X-API-Key': apiKey,\n 'Content-Type': 'application/json',\n },\n timeout: 10_000,\n }\n );\n\n const data = response.data as any;\n const signatures = data?.signatures as string[] | undefined;\n const bytes = data?.bytes as string | undefined;\n\n if (!Array.isArray(signatures) || typeof bytes !== 'string') {\n throw new QueryHubStateError('PROXY_RESPONSE_INVALID', 'Query Proxy response missing signatures/bytes');\n }\n\n const proof = signaturesToProofBytes(signatures);\n const queryBytes = decodeQueryBytes(bytes);\n const parsed = QueryResponse.from(queryBytes);\n\n const perChain = parsed.responses.find((r) => r.chainId === wormholeChainId);\n if (!perChain) {\n throw new QueryHubStateError('QUERY_RESPONSE_INVALID', 'Missing per-chain response for hub chain');\n }\n\n // The SDK provides a parser for the chain-specific response.\n const chainResp = EthCallQueryResponse.from(perChain.response.serialize());\n const blockTime = Number(chainResp.blockTime);\n\n const nowSeconds = Math.floor(Date.now() / 1000);\n if (nowSeconds - blockTime > maxAgeSeconds) {\n throw new QueryHubStateError(\n 'ATTESTATION_STALE',\n `Guardian attestation is stale (blockTime=${blockTime}, now=${nowSeconds}, maxAge=${maxAgeSeconds}s)`\n );\n }\n\n const nonce = decodeFirstNonce(chainResp.results);\n const isRegistered = decodeFirstIsRegistered(chainResp.results);\n const lastActionHash = decodeLastActionHash(chainResp.results);\n\n return {\n nonce,\n isRegistered,\n blockTime,\n proof,\n lastActionHash,\n } satisfies HubStateResult;\n } catch (err) {\n if (err instanceof QueryHubStateError) throw err;\n if (axios.isAxiosError(err)) {\n const ax = err as AxiosError;\n const status = ax.response?.status;\n const statusText = ax.response?.statusText;\n const details = typeof ax.response?.data === 'string' ? ax.response?.data : undefined;\n\n throw new QueryHubStateError(\n 'PROXY_HTTP_ERROR',\n `Query Proxy request failed${status ? ` (${status} ${statusText ?? ''})` : ''}${details ? `: ${details}` : ''}`,\n err\n );\n }\n\n throw new QueryHubStateError('PROXY_HTTP_ERROR', 'Query Proxy request failed', err);\n }\n };\n\n return await withExponentialBackoff(doFetch, maxAttempts);\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/chains/starknet/StarknetClient.ts"],"sourcesContent":["/**\n * Veridex Protocol SDK - Starknet Chain Client\n *\n * Production-grade implementation of ChainClient interface for Starknet.\n * Supports custom bridge attestation, gasless execution via Hub dispatch.\n *\n * Security:\n * - Native starknet::eth_signature::verify_eth_signature for validation\n * - Custom bridge with multi-relayer threshold attestations\n * - Replay protection via nonce verification on Hub\n * - Bridge validates source_chain == hub_chain_id (10004 = Base Sepolia)\n *\n * Architecture:\n * - Starknet actions MUST be dispatched via Hub (Base Sepolia)\n * - Hub publishes Wormhole message → relayer monitors → relayer submits attestation\n * - Bridge accumulates attestations → threshold reached → spoke executes\n * - Spoke validates source_chain == hubChainId (NOT targetChain)\n * \n * Custom Bridge:\n * - Bridge address: 0x30d2e7f26dc75819cfddcd7caa26a76b681d5918f219c99060c42ce1e3f69e4\n * - Chain ID: 50001 (custom range 50000+, reserved for non-Wormhole chains)\n * - Hub Chain ID: 10004 (Base Sepolia - what bridge validates as source)\n */\n\nimport type { SessionKey } from '../../sessions/types.js';\nimport type {\n ChainClient,\n ChainConfig,\n TransferParams,\n ExecuteParams,\n BridgeParams,\n DispatchResult,\n WebAuthnSignature,\n VaultCreationResult,\n RegisterSessionParams,\n RevokeSessionParams,\n SessionValidationResult,\n} from '../../core/types.js';\nimport { createHash } from 'crypto';\nimport { RpcProvider } from 'starknet';\nimport { encodeTransferAction, encodeExecuteAction, encodeBridgeAction } from '../../payload.js';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n// 2^128 for splitting u256 into low/high\nconst U128_MAX = BigInt('0x100000000000000000000000000000000');\n\n/**\n * Convert a 256-bit keyHash to Starknet u256 format (low, high felt252 pair).\n * Starknet u256 is represented as two felt252 values: (low_128_bits, high_128_bits)\n * \n * @param keyHash - 256-bit hex string (with or without 0x prefix)\n * @returns Array of two hex strings [low, high] for Starknet calldata\n */\nfunction toStarknetU256(keyHash: string): [string, string] {\n const cleanHash = keyHash.replace('0x', '').padStart(64, '0');\n const value = BigInt('0x' + cleanHash);\n \n // Split into low 128 bits and high 128 bits\n const low = value % U128_MAX;\n const high = value / U128_MAX;\n \n return [\n '0x' + low.toString(16),\n '0x' + high.toString(16)\n ];\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface StarknetClientConfig {\n wormholeChainId: number;\n rpcUrl: string;\n spokeContractAddress?: string;\n bridgeContractAddress?: string;\n network?: 'mainnet' | 'sepolia' | 'testnet';\n hubRpcUrl?: string; // Hub chain RPC for session management\n hubContractAddress?: string; // Hub contract for session management\n}\n\n// ============================================================================\n// StarknetClient\n// ============================================================================\n\nexport class StarknetClient implements ChainClient {\n private config: ChainConfig;\n private provider: RpcProvider;\n private hubRpcUrl?: string;\n private hubContractAddress?: string;\n\n constructor(config: StarknetClientConfig) {\n this.config = {\n name: `Starknet ${config.network || 'mainnet'}`,\n chainId: 0,\n wormholeChainId: config.wormholeChainId,\n rpcUrl: config.rpcUrl,\n explorerUrl: config.network === 'sepolia'\n ? 'https://sepolia.starkscan.co'\n : 'https://starkscan.co',\n isEvm: false,\n contracts: {\n hub: config.spokeContractAddress,\n wormholeCoreBridge: config.bridgeContractAddress ?? '',\n },\n };\n\n this.hubRpcUrl = config.hubRpcUrl;\n this.hubContractAddress = config.hubContractAddress;\n\n this.provider = new RpcProvider({ nodeUrl: config.rpcUrl });\n }\n\n getConfig(): ChainConfig {\n return this.config;\n }\n\n async getNonce(_userKeyHash: string): Promise<bigint> {\n return 0n;\n }\n\n async getMessageFee(): Promise<bigint> {\n return 0n;\n }\n\n async buildTransferPayload(params: TransferParams): Promise<string> {\n return encodeTransferAction(params.token, params.recipient, params.amount);\n }\n\n async buildExecutePayload(params: ExecuteParams): Promise<string> {\n return encodeExecuteAction(params.target, params.value, params.data);\n }\n\n async buildBridgePayload(params: BridgeParams): Promise<string> {\n return encodeBridgeAction(params.token, params.amount, params.destinationChain, params.recipient);\n }\n\n async dispatch(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n targetChain: number,\n actionPayload: string,\n nonce: bigint,\n signer: any\n ): Promise<DispatchResult> {\n void signature;\n void publicKeyX;\n void publicKeyY;\n void targetChain;\n void actionPayload;\n void nonce;\n void signer;\n throw new Error(\n 'Direct dispatch not supported on Starknet. ' +\n 'Starknet actions are executed via the Veridex Hub (Base Sepolia) + custom bridge. ' +\n 'Use dispatchGasless() to route through relayer, which will submit attestations to the bridge.'\n );\n }\n\n async dispatchGasless(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n targetChain: number,\n actionPayload: string,\n nonce: bigint,\n relayerUrl: string\n ): Promise<DispatchResult> {\n /**\n * Starknet gasless execution flow:\n * 1. User signs action with passkey (on client)\n * 2. SDK submits to relayer with targetChain=50001 (Starknet)\n * 3. Relayer dispatches to Hub (Base Sepolia) with targetChain=50001\n * 4. Hub publishes Wormhole message\n * 5. Relayer monitors Hub Dispatch event\n * 6. Relayer submits attestation to Starknet Bridge\n * 7. Bridge accumulates attestations from multiple relayers\n * 8. When threshold reached, Bridge calls spoke.execute()\n * 9. Spoke validates source_chain == hubChainId (10004)\n * 10. Spoke executes action on user's vault\n * \n * Result: Completely gasless for user - relayer pays all fees\n */\n const keyHash = this.computeKeyHash(publicKeyX, publicKeyY);\n\n // Submit to relayer for Hub dispatch + bridge attestation\n const request = {\n signature: {\n r: '0x' + signature.r.toString(16).padStart(64, '0'),\n s: '0x' + signature.s.toString(16).padStart(64, '0'),\n authenticatorData: signature.authenticatorData,\n clientDataJSON: signature.clientDataJSON,\n challengeIndex: signature.challengeIndex,\n typeIndex: signature.typeIndex,\n },\n publicKeyX: '0x' + publicKeyX.toString(16).padStart(64, '0'),\n publicKeyY: '0x' + publicKeyY.toString(16).padStart(64, '0'),\n targetChain, // 50001 for Starknet\n actionPayload,\n userNonce: Number(nonce),\n };\n\n const response = await fetch(`${relayerUrl}/api/v1/submit`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new Error(\n `Relayer submission failed: ${response.status} ${response.statusText}. ` +\n `Error: ${errorText}`\n );\n }\n\n const result = await response.json();\n\n return {\n transactionHash: result.transactionHash ?? result.txHash ?? result.hubTxHash,\n sequence: BigInt(result.sequence || 0),\n userKeyHash: keyHash,\n targetChain,\n };\n }\n\n // Note: getVaultAddress is now defined in the Social Recovery section below\n // with enhanced spoke contract querying support.\n\n computeVaultAddress(userKeyHash: string): string {\n /**\n * Starknet vault derivation:\n * - Vaults are created via spoke contract\n * - Address is deterministic from userKeyHash\n * - Uses keyHash directly as vault identifier (felt252)\n * \n * Note: Actual vault address on Starknet may differ based on\n * spoke implementation. This is a best-effort derivation.\n */\n const clean = userKeyHash.replace(/^0x/, '');\n return '0x' + clean;\n }\n\n async vaultExists(userKeyHash: string): Promise<boolean> {\n /**\n * Check if vault exists on Starknet spoke\n * Best-effort: queries spoke contract if available\n */\n if (!this.config.contracts.hub) {\n return false;\n }\n\n try {\n const vaultAddress = await this.getVaultAddress(userKeyHash);\n if (!vaultAddress) {\n return false;\n }\n\n // Query Starknet RPC for contract code at vault address\n const anyProvider = this.provider as any;\n if (typeof anyProvider.getClassHashAt === 'function') {\n await anyProvider.getClassHashAt(vaultAddress);\n return true;\n }\n } catch {\n // Vault doesn't exist or RPC doesn't support query\n }\n\n return false;\n }\n\n async createVault(userKeyHash: string, signer: any): Promise<VaultCreationResult> {\n void signer;\n throw new Error(\n 'Vault creation on Starknet must be done via Hub dispatch + custom bridge attestation. ' +\n 'Use Hub client (Base Sepolia) to dispatch a CREATE_VAULT action with targetChain=50001. ' +\n `KeyHash=${userKeyHash}`\n );\n }\n\n async createVaultSponsored?(userKeyHash: string, sponsorPrivateKey: string, rpcUrl?: string): Promise<VaultCreationResult> {\n void userKeyHash;\n void sponsorPrivateKey;\n void rpcUrl;\n throw new Error(\n 'Vault creation on Starknet must be done via Hub dispatch + custom bridge attestation. ' +\n 'Use Hub client (Base Sepolia) with sponsor key to dispatch CREATE_VAULT action.'\n );\n }\n\n /**\n * Create a vault via the relayer (sponsored/gasless)\n * This is the recommended way to create Starknet vaults\n * \n * The relayer will dispatch a vault creation action from Hub via custom bridge to Starknet spoke\n */\n async createVaultViaRelayer(\n userKeyHash: string,\n relayerUrl: string\n ): Promise<VaultCreationResult> {\n const response = await fetch(`${relayerUrl}/api/v1/starknet/vault`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n userKeyHash,\n chainId: this.config.wormholeChainId,\n }),\n });\n\n const result = await response.json();\n\n if (!response.ok || !result.success) {\n throw new Error(result.error || 'Failed to create vault via relayer');\n }\n\n return {\n address: result.vaultAddress,\n transactionHash: result.transactionHash || '',\n blockNumber: 0,\n gasUsed: 0n,\n alreadyExisted: result.alreadyExists || false,\n sponsoredBy: 'relayer',\n };\n }\n\n /**\n * Get vault info via relayer (includes existence check)\n */\n async getVaultViaRelayer(\n userKeyHash: string,\n relayerUrl: string\n ): Promise<{ vaultAddress: string; exists: boolean }> {\n const response = await fetch(\n `${relayerUrl}/api/v1/starknet/vault/${userKeyHash}?chainId=${this.config.wormholeChainId}`\n );\n\n if (!response.ok) {\n throw new Error('Failed to get vault info from relayer');\n }\n\n const result = await response.json();\n return {\n vaultAddress: result.vaultAddress,\n exists: result.exists,\n };\n }\n\n async estimateVaultCreationGas(_userKeyHash: string): Promise<bigint> {\n return 0n;\n }\n\n getFactoryAddress(): string | undefined {\n return undefined;\n }\n\n getImplementationAddress(): string | undefined {\n return undefined;\n }\n\n // ========================================================================\n // Balance utility (best-effort)\n // ========================================================================\n\n async getNativeBalance(address: string): Promise<bigint> {\n // Best-effort: some Starknet RPCs support getBalance, but it is not universal.\n try {\n const anyProvider = this.provider as any;\n if (typeof anyProvider.getBalance === 'function') {\n const res = await anyProvider.getBalance(address);\n return BigInt(res);\n }\n } catch {\n // ignore\n }\n return 0n;\n }\n\n getProvider(): RpcProvider {\n return this.provider;\n }\n\n // ========================================================================\n // Session Management (Issue #13)\n // ========================================================================\n\n /**\n * Register a session key on the Hub (must be called via Hub client)\n * Starknet spokes validate sessions via CCQ, but registration happens on Hub\n * \n * @throws Error - Session management must be done via Hub chain\n */\n async registerSession(_params: RegisterSessionParams): Promise<void> {\n throw new Error(\n 'Session registration must be performed on the Hub chain (Base). ' +\n 'Use EVMClient connected to the Hub to call registerSession().'\n );\n }\n\n /**\n * Revoke a session key on the Hub (must be called via Hub client)\n * \n * @throws Error - Session management must be done via Hub chain\n */\n async revokeSession(_params: RevokeSessionParams): Promise<void> {\n throw new Error(\n 'Session revocation must be performed on the Hub chain (Base). ' +\n 'Use EVMClient connected to the Hub to call revokeSession().'\n );\n }\n\n /**\n * Check if a session is active by querying the Hub\n * This method queries the Hub contract directly for session validation\n * \n * @param userKeyHash - Hash of user's Passkey public key\n * @param sessionKeyHash - Hash of session key to validate\n * @returns Session validation result with expiry and limits\n */\n async isSessionActive(\n _userKeyHash: string,\n _sessionKeyHash: string\n ): Promise<SessionValidationResult> {\n if (!this.hubRpcUrl || !this.hubContractAddress) {\n throw new Error(\n 'Hub configuration required for session validation. ' +\n 'Provide hubRpcUrl and hubContractAddress in StarknetClientConfig.'\n );\n }\n\n // Query Hub contract for session status\n throw new Error(\n 'isSessionActive requires Hub client integration. ' +\n 'Use EVMClient.isSessionActive() on the Hub chain, ' +\n 'then pass the result to session execution on Starknet.'\n );\n }\n\n /**\n * Get all sessions for a user from the Hub\n * \n * @param userKeyHash - Hash of user's Passkey public key\n * @returns Array of all sessions (active and expired/revoked)\n */\n async getUserSessions(userKeyHash: string): Promise<SessionKey[]> {\n if (!this.hubRpcUrl || !this.hubContractAddress) {\n throw new Error(\n 'Hub configuration required for session queries. ' +\n 'Provide hubRpcUrl and hubContractAddress in StarknetClientConfig.'\n );\n }\n\n // Query Hub contract for user sessions\n throw new Error(\n 'getUserSessions requires Hub client integration. ' +\n 'Use EVMClient.getUserSessions() on the Hub chain. ' +\n `User: ${userKeyHash}`\n );\n }\n\n // ========================================================================\n // Query-Based Execution (Issue #9/#10)\n // ========================================================================\n\n /**\n * Get user state from Hub (comprehensive state query)\n * Returns key hash, nonce, and last action hash for CCQ validation\n * \n * @param userKeyHash - Hash of user's Passkey public key\n * @returns User state with nonce and last action hash\n */\n async getUserState(userKeyHash: string): Promise<{\n keyHash: string;\n nonce: bigint;\n lastActionHash: string;\n }> {\n if (!this.hubRpcUrl || !this.hubContractAddress) {\n throw new Error(\n 'Hub configuration required for state queries. ' +\n 'Provide hubRpcUrl and hubContractAddress in StarknetClientConfig.'\n );\n }\n\n // Query Hub contract for user state\n throw new Error(\n 'getUserState requires Hub client integration. ' +\n 'Use EVMClient.getUserState() on the Hub chain. ' +\n `User: ${userKeyHash}`\n );\n }\n\n /**\n * Get user's last action hash from Hub\n * Used for optimistic execution and nonce validation\n * \n * @param userKeyHash - Hash of user's Passkey public key\n * @returns Last action hash (zero hash if no actions)\n */\n async getUserLastActionHash(userKeyHash: string): Promise<string> {\n if (!this.hubRpcUrl || !this.hubContractAddress) {\n throw new Error(\n 'Hub configuration required for action hash queries. ' +\n 'Provide hubRpcUrl and hubContractAddress in StarknetClientConfig.'\n );\n }\n\n // Query Hub contract for last action hash\n throw new Error(\n 'getUserLastActionHash requires Hub client integration. ' +\n 'Use EVMClient.getUserLastActionHash() on the Hub chain. ' +\n `User: ${userKeyHash}`\n );\n }\n\n /**\n * Execute with query-based validation (faster than VAA, ~23s vs 60-90s)\n * Uses Wormhole CCQ to validate Hub state, then executes on Starknet\n * \n * @param params Query execution parameters with CCQ response\n * @returns Dispatch result with transaction hash\n * \n * @remarks\n * Query-based execution flow:\n * 1. Query Hub state via Wormhole CCQ\n * 2. Validate Guardian signatures on query response\n * 3. Execute on Starknet with validated state\n * 4. Hub state must be < 60s stale (enforced by QueryVerifier)\n */\n async executeWithQuery(\n _params: {\n userKeyHash: string;\n queryResponse: Uint8Array; // CCQ Guardian response\n actionType: number;\n actionPayload: Uint8Array;\n relayerUrl?: string;\n }\n ): Promise<DispatchResult> {\n throw new Error(\n 'Query-based execution on Starknet requires relayer integration. ' +\n 'Use relayer API to submit query-validated transactions. ' +\n 'Relayer will call veridex_spoke::execute_with_query on Starknet.'\n );\n }\n\n // ========================================================================\n // Internal helpers\n // ========================================================================\n\n private computeKeyHash(publicKeyX: bigint, publicKeyY: bigint): string {\n const xHex = publicKeyX.toString(16).padStart(64, '0');\n const yHex = publicKeyY.toString(16).padStart(64, '0');\n const combined = Buffer.from(xHex + yHex, 'hex');\n const hash = createHash('sha256').update(combined).digest('hex');\n return '0x' + hash;\n }\n\n // ============================================================================\n // Social Recovery Methods (Issue #23)\n // ============================================================================\n // \n // Note: Social recovery is managed on the Hub chain (EVM).\n // Starknet spokes receive and execute recovery VAAs broadcast from the Hub.\n // The relayer service handles submitting recovery transactions to Starknet.\n //\n // SDK users should use EVMClient methods for guardian management and\n // recovery initiation on the Hub chain.\n // ============================================================================\n\n /**\n * Get vault address by owner key hash\n * \n * @param ownerKeyHash - Owner's passkey hash\n * @returns Vault address on Starknet (felt252 as hex string)\n */\n async getVaultAddress(ownerKeyHash: string): Promise<string | null> {\n try {\n const spokeAddress = this.config.contracts.hub;\n if (!spokeAddress) {\n throw new Error('Spoke contract address not configured');\n }\n\n // Starknet spoke expects u256 (low, high) format for keyHash\n const [low, high] = toStarknetU256(ownerKeyHash);\n\n // Call get_vault on spoke contract with u256 split into [low, high]\n const result = await this.provider.callContract({\n contractAddress: spokeAddress,\n entrypoint: 'get_vault',\n calldata: [low, high],\n });\n\n // result[0] is the vault address (0 if not found)\n const vaultAddress = result[0];\n if (vaultAddress === '0x0' || vaultAddress === '0') {\n return null;\n }\n\n return vaultAddress;\n } catch (error) {\n console.error('Error getting vault address:', error);\n return null;\n }\n }\n\n /**\n * Check if vault exists and get basic info\n * \n * @param ownerKeyHash - Owner's passkey hash \n * @returns Vault info or null if not found\n */\n async getVaultInfo(ownerKeyHash: string): Promise<{\n address: string;\n ownerKeyHash: string;\n } | null> {\n const vaultAddress = await this.getVaultAddress(ownerKeyHash);\n if (!vaultAddress) {\n return null;\n }\n\n return {\n address: vaultAddress,\n ownerKeyHash,\n };\n }\n\n /**\n * Check if spoke contract is paused\n * \n * @returns Whether the protocol is paused\n */\n async isProtocolPaused(): Promise<boolean> {\n try {\n const spokeAddress = this.config.contracts.hub;\n if (!spokeAddress) {\n throw new Error('Spoke contract address not configured');\n }\n\n const result = await this.provider.callContract({\n contractAddress: spokeAddress,\n entrypoint: 'is_paused',\n calldata: [],\n });\n\n return result[0] === '0x1' || result[0] === '1';\n } catch (error) {\n console.error('Error checking pause status:', error);\n return false;\n }\n }\n}\n"],"mappings":"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","names":[]}