@veridex/sdk 1.0.0-beta.1
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/CHANGELOG.md +73 -0
- package/LICENSE +21 -0
- package/README.md +212 -0
- package/dist/chains/aptos/index.d.mts +140 -0
- package/dist/chains/aptos/index.d.ts +140 -0
- package/dist/chains/aptos/index.js +563 -0
- package/dist/chains/aptos/index.js.map +1 -0
- package/dist/chains/aptos/index.mjs +536 -0
- package/dist/chains/aptos/index.mjs.map +1 -0
- package/dist/chains/evm/index.d.mts +5 -0
- package/dist/chains/evm/index.d.ts +5 -0
- package/dist/chains/evm/index.js +1233 -0
- package/dist/chains/evm/index.js.map +1 -0
- package/dist/chains/evm/index.mjs +1205 -0
- package/dist/chains/evm/index.mjs.map +1 -0
- package/dist/chains/solana/index.d.mts +116 -0
- package/dist/chains/solana/index.d.ts +116 -0
- package/dist/chains/solana/index.js +513 -0
- package/dist/chains/solana/index.js.map +1 -0
- package/dist/chains/solana/index.mjs +491 -0
- package/dist/chains/solana/index.mjs.map +1 -0
- package/dist/chains/starknet/index.d.mts +172 -0
- package/dist/chains/starknet/index.d.ts +172 -0
- package/dist/chains/starknet/index.js +534 -0
- package/dist/chains/starknet/index.js.map +1 -0
- package/dist/chains/starknet/index.mjs +507 -0
- package/dist/chains/starknet/index.mjs.map +1 -0
- package/dist/chains/sui/index.d.mts +182 -0
- package/dist/chains/sui/index.d.ts +182 -0
- package/dist/chains/sui/index.js +560 -0
- package/dist/chains/sui/index.js.map +1 -0
- package/dist/chains/sui/index.mjs +533 -0
- package/dist/chains/sui/index.mjs.map +1 -0
- package/dist/constants.d.mts +150 -0
- package/dist/constants.d.ts +150 -0
- package/dist/constants.js +430 -0
- package/dist/constants.js.map +1 -0
- package/dist/constants.mjs +392 -0
- package/dist/constants.mjs.map +1 -0
- package/dist/index-0NXfbk0z.d.ts +637 -0
- package/dist/index-D0dLVjTA.d.mts +637 -0
- package/dist/index.d.mts +3101 -0
- package/dist/index.d.ts +3101 -0
- package/dist/index.js +13186 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +13011 -0
- package/dist/index.mjs.map +1 -0
- package/dist/payload.d.mts +125 -0
- package/dist/payload.d.ts +125 -0
- package/dist/payload.js +315 -0
- package/dist/payload.js.map +1 -0
- package/dist/payload.mjs +269 -0
- package/dist/payload.mjs.map +1 -0
- package/dist/queries/index.d.mts +148 -0
- package/dist/queries/index.d.ts +148 -0
- package/dist/queries/index.js +1533 -0
- package/dist/queries/index.js.map +1 -0
- package/dist/queries/index.mjs +1508 -0
- package/dist/queries/index.mjs.map +1 -0
- package/dist/types-ChIsqCiw.d.mts +565 -0
- package/dist/types-ChIsqCiw.d.ts +565 -0
- package/dist/types-FJL7j6gQ.d.mts +172 -0
- package/dist/types-FJL7j6gQ.d.ts +172 -0
- package/dist/types.d.mts +407 -0
- package/dist/types.d.ts +407 -0
- package/dist/types.js +19 -0
- package/dist/types.js.map +1 -0
- package/dist/types.mjs +1 -0
- package/dist/types.mjs.map +1 -0
- package/dist/utils.d.mts +81 -0
- package/dist/utils.d.ts +81 -0
- package/dist/utils.js +430 -0
- package/dist/utils.js.map +1 -0
- package/dist/utils.mjs +390 -0
- package/dist/utils.mjs.map +1 -0
- package/dist/wormhole.d.mts +167 -0
- package/dist/wormhole.d.ts +167 -0
- package/dist/wormhole.js +468 -0
- package/dist/wormhole.js.map +1 -0
- package/dist/wormhole.mjs +422 -0
- package/dist/wormhole.mjs.map +1 -0
- package/package.json +151 -0
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/chains/starknet/index.ts
|
|
21
|
+
var starknet_exports = {};
|
|
22
|
+
__export(starknet_exports, {
|
|
23
|
+
StarknetClient: () => StarknetClient
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(starknet_exports);
|
|
26
|
+
|
|
27
|
+
// src/chains/starknet/StarknetClient.ts
|
|
28
|
+
var import_crypto = require("crypto");
|
|
29
|
+
var import_starknet = require("starknet");
|
|
30
|
+
|
|
31
|
+
// src/payload.ts
|
|
32
|
+
var import_ethers = require("ethers");
|
|
33
|
+
|
|
34
|
+
// src/constants.ts
|
|
35
|
+
var ACTION_TRANSFER = 1;
|
|
36
|
+
var ACTION_EXECUTE = 2;
|
|
37
|
+
var ACTION_BRIDGE = 4;
|
|
38
|
+
|
|
39
|
+
// src/payload.ts
|
|
40
|
+
function encodeTransferAction(token, recipient, amount) {
|
|
41
|
+
const tokenPadded = padTo32Bytes(token);
|
|
42
|
+
const recipientPadded = padTo32Bytes(recipient);
|
|
43
|
+
const amountBytes = import_ethers.ethers.zeroPadValue(import_ethers.ethers.toBeHex(amount), 32);
|
|
44
|
+
return import_ethers.ethers.concat([
|
|
45
|
+
import_ethers.ethers.toBeHex(ACTION_TRANSFER, 1),
|
|
46
|
+
tokenPadded,
|
|
47
|
+
recipientPadded,
|
|
48
|
+
amountBytes
|
|
49
|
+
]);
|
|
50
|
+
}
|
|
51
|
+
function encodeBridgeAction(token, amount, targetChain, recipient) {
|
|
52
|
+
const tokenPadded = padTo32Bytes(token);
|
|
53
|
+
const amountBytes = import_ethers.ethers.zeroPadValue(import_ethers.ethers.toBeHex(amount), 32);
|
|
54
|
+
const targetChainBytes = import_ethers.ethers.toBeHex(targetChain, 2);
|
|
55
|
+
const recipientPadded = padTo32Bytes(recipient);
|
|
56
|
+
return import_ethers.ethers.concat([
|
|
57
|
+
import_ethers.ethers.toBeHex(ACTION_BRIDGE, 1),
|
|
58
|
+
tokenPadded,
|
|
59
|
+
amountBytes,
|
|
60
|
+
targetChainBytes,
|
|
61
|
+
recipientPadded
|
|
62
|
+
]);
|
|
63
|
+
}
|
|
64
|
+
function encodeExecuteAction(target, value, data) {
|
|
65
|
+
const targetPadded = padTo32Bytes(target);
|
|
66
|
+
const valueBytes = import_ethers.ethers.zeroPadValue(import_ethers.ethers.toBeHex(value), 32);
|
|
67
|
+
const dataBytes = import_ethers.ethers.getBytes(data);
|
|
68
|
+
const dataLengthBytes = import_ethers.ethers.toBeHex(dataBytes.length, 2);
|
|
69
|
+
return import_ethers.ethers.concat([
|
|
70
|
+
import_ethers.ethers.toBeHex(ACTION_EXECUTE, 1),
|
|
71
|
+
targetPadded,
|
|
72
|
+
valueBytes,
|
|
73
|
+
dataLengthBytes,
|
|
74
|
+
data
|
|
75
|
+
]);
|
|
76
|
+
}
|
|
77
|
+
function padTo32Bytes(address) {
|
|
78
|
+
if (address.toLowerCase() === "native") {
|
|
79
|
+
return "0x" + "0".repeat(64);
|
|
80
|
+
}
|
|
81
|
+
if (address.startsWith("0x")) {
|
|
82
|
+
const hex2 = address.replace("0x", "");
|
|
83
|
+
if (!/^[0-9a-fA-F]*$/.test(hex2)) {
|
|
84
|
+
throw new Error(`Invalid address: ${address}. Expected hex string or 'native'.`);
|
|
85
|
+
}
|
|
86
|
+
return "0x" + hex2.padStart(64, "0");
|
|
87
|
+
}
|
|
88
|
+
const base58Chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
89
|
+
for (const char of address) {
|
|
90
|
+
if (!base58Chars.includes(char)) {
|
|
91
|
+
throw new Error(`Invalid address: ${address}. Contains invalid base58 character '${char}'.`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
let value = BigInt(0);
|
|
95
|
+
for (const char of address) {
|
|
96
|
+
value = value * 58n + BigInt(base58Chars.indexOf(char));
|
|
97
|
+
}
|
|
98
|
+
let hex = value.toString(16);
|
|
99
|
+
if (hex.length > 64) {
|
|
100
|
+
throw new Error(`Invalid address: ${address}. Decoded value too large for 32 bytes.`);
|
|
101
|
+
}
|
|
102
|
+
return "0x" + hex.padStart(64, "0");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// src/chains/starknet/StarknetClient.ts
|
|
106
|
+
var FELT252_MAX = BigInt("0x0800000000000000000000000000000000000000000000000000000000000000") - 1n;
|
|
107
|
+
var U128_MAX = BigInt("0x100000000000000000000000000000000");
|
|
108
|
+
function toStarknetU256(keyHash) {
|
|
109
|
+
const cleanHash = keyHash.replace("0x", "").padStart(64, "0");
|
|
110
|
+
const value = BigInt("0x" + cleanHash);
|
|
111
|
+
const low = value % U128_MAX;
|
|
112
|
+
const high = value / U128_MAX;
|
|
113
|
+
return [
|
|
114
|
+
"0x" + low.toString(16),
|
|
115
|
+
"0x" + high.toString(16)
|
|
116
|
+
];
|
|
117
|
+
}
|
|
118
|
+
var StarknetClient = class {
|
|
119
|
+
config;
|
|
120
|
+
provider;
|
|
121
|
+
hubRpcUrl;
|
|
122
|
+
hubContractAddress;
|
|
123
|
+
constructor(config) {
|
|
124
|
+
this.config = {
|
|
125
|
+
name: `Starknet ${config.network || "mainnet"}`,
|
|
126
|
+
chainId: 0,
|
|
127
|
+
wormholeChainId: config.wormholeChainId,
|
|
128
|
+
rpcUrl: config.rpcUrl,
|
|
129
|
+
explorerUrl: config.network === "sepolia" ? "https://sepolia.starkscan.co" : "https://starkscan.co",
|
|
130
|
+
isEvm: false,
|
|
131
|
+
contracts: {
|
|
132
|
+
hub: config.spokeContractAddress,
|
|
133
|
+
wormholeCoreBridge: config.bridgeContractAddress ?? ""
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
this.hubRpcUrl = config.hubRpcUrl;
|
|
137
|
+
this.hubContractAddress = config.hubContractAddress;
|
|
138
|
+
this.provider = new import_starknet.RpcProvider({ nodeUrl: config.rpcUrl });
|
|
139
|
+
}
|
|
140
|
+
getConfig() {
|
|
141
|
+
return this.config;
|
|
142
|
+
}
|
|
143
|
+
async getNonce(_userKeyHash) {
|
|
144
|
+
return 0n;
|
|
145
|
+
}
|
|
146
|
+
async getMessageFee() {
|
|
147
|
+
return 0n;
|
|
148
|
+
}
|
|
149
|
+
async buildTransferPayload(params) {
|
|
150
|
+
return encodeTransferAction(params.token, params.recipient, params.amount);
|
|
151
|
+
}
|
|
152
|
+
async buildExecutePayload(params) {
|
|
153
|
+
return encodeExecuteAction(params.target, params.value, params.data);
|
|
154
|
+
}
|
|
155
|
+
async buildBridgePayload(params) {
|
|
156
|
+
return encodeBridgeAction(params.token, params.amount, params.destinationChain, params.recipient);
|
|
157
|
+
}
|
|
158
|
+
async dispatch(signature, publicKeyX, publicKeyY, targetChain, actionPayload, nonce, signer) {
|
|
159
|
+
void signature;
|
|
160
|
+
void publicKeyX;
|
|
161
|
+
void publicKeyY;
|
|
162
|
+
void targetChain;
|
|
163
|
+
void actionPayload;
|
|
164
|
+
void nonce;
|
|
165
|
+
void signer;
|
|
166
|
+
throw new Error(
|
|
167
|
+
"Direct dispatch not supported on Starknet. Starknet actions are executed via the Veridex Hub (Base Sepolia) + custom bridge. Use dispatchGasless() to route through relayer, which will submit attestations to the bridge."
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
async dispatchGasless(signature, publicKeyX, publicKeyY, targetChain, actionPayload, nonce, relayerUrl) {
|
|
171
|
+
const keyHash = this.computeKeyHash(publicKeyX, publicKeyY);
|
|
172
|
+
const request = {
|
|
173
|
+
signature: {
|
|
174
|
+
r: "0x" + signature.r.toString(16).padStart(64, "0"),
|
|
175
|
+
s: "0x" + signature.s.toString(16).padStart(64, "0"),
|
|
176
|
+
authenticatorData: signature.authenticatorData,
|
|
177
|
+
clientDataJSON: signature.clientDataJSON,
|
|
178
|
+
challengeIndex: signature.challengeIndex,
|
|
179
|
+
typeIndex: signature.typeIndex
|
|
180
|
+
},
|
|
181
|
+
publicKeyX: "0x" + publicKeyX.toString(16).padStart(64, "0"),
|
|
182
|
+
publicKeyY: "0x" + publicKeyY.toString(16).padStart(64, "0"),
|
|
183
|
+
targetChain,
|
|
184
|
+
// 50001 for Starknet
|
|
185
|
+
actionPayload,
|
|
186
|
+
userNonce: Number(nonce)
|
|
187
|
+
};
|
|
188
|
+
const response = await fetch(`${relayerUrl}/api/v1/submit`, {
|
|
189
|
+
method: "POST",
|
|
190
|
+
headers: { "Content-Type": "application/json" },
|
|
191
|
+
body: JSON.stringify(request)
|
|
192
|
+
});
|
|
193
|
+
if (!response.ok) {
|
|
194
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
195
|
+
throw new Error(
|
|
196
|
+
`Relayer submission failed: ${response.status} ${response.statusText}. Error: ${errorText}`
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
const result = await response.json();
|
|
200
|
+
return {
|
|
201
|
+
transactionHash: result.transactionHash ?? result.txHash ?? result.hubTxHash,
|
|
202
|
+
sequence: BigInt(result.sequence || 0),
|
|
203
|
+
userKeyHash: keyHash,
|
|
204
|
+
targetChain
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
// Note: getVaultAddress is now defined in the Social Recovery section below
|
|
208
|
+
// with enhanced spoke contract querying support.
|
|
209
|
+
computeVaultAddress(userKeyHash) {
|
|
210
|
+
const clean = userKeyHash.replace(/^0x/, "");
|
|
211
|
+
return "0x" + clean;
|
|
212
|
+
}
|
|
213
|
+
async vaultExists(userKeyHash) {
|
|
214
|
+
if (!this.config.contracts.hub) {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
try {
|
|
218
|
+
const vaultAddress = await this.getVaultAddress(userKeyHash);
|
|
219
|
+
if (!vaultAddress) {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
const anyProvider = this.provider;
|
|
223
|
+
if (typeof anyProvider.getClassHashAt === "function") {
|
|
224
|
+
await anyProvider.getClassHashAt(vaultAddress);
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
} catch {
|
|
228
|
+
}
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
async createVault(userKeyHash, signer) {
|
|
232
|
+
void signer;
|
|
233
|
+
throw new Error(
|
|
234
|
+
`Vault creation on Starknet must be done via Hub dispatch + custom bridge attestation. Use Hub client (Base Sepolia) to dispatch a CREATE_VAULT action with targetChain=50001. KeyHash=${userKeyHash}`
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
async createVaultSponsored(userKeyHash, sponsorPrivateKey, rpcUrl) {
|
|
238
|
+
void userKeyHash;
|
|
239
|
+
void sponsorPrivateKey;
|
|
240
|
+
void rpcUrl;
|
|
241
|
+
throw new Error(
|
|
242
|
+
"Vault creation on Starknet must be done via Hub dispatch + custom bridge attestation. Use Hub client (Base Sepolia) with sponsor key to dispatch CREATE_VAULT action."
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Create a vault via the relayer (sponsored/gasless)
|
|
247
|
+
* This is the recommended way to create Starknet vaults
|
|
248
|
+
*
|
|
249
|
+
* The relayer will dispatch a vault creation action from Hub via custom bridge to Starknet spoke
|
|
250
|
+
*/
|
|
251
|
+
async createVaultViaRelayer(userKeyHash, relayerUrl) {
|
|
252
|
+
const response = await fetch(`${relayerUrl}/api/v1/starknet/vault`, {
|
|
253
|
+
method: "POST",
|
|
254
|
+
headers: {
|
|
255
|
+
"Content-Type": "application/json"
|
|
256
|
+
},
|
|
257
|
+
body: JSON.stringify({
|
|
258
|
+
userKeyHash,
|
|
259
|
+
chainId: this.config.wormholeChainId
|
|
260
|
+
})
|
|
261
|
+
});
|
|
262
|
+
const result = await response.json();
|
|
263
|
+
if (!response.ok || !result.success) {
|
|
264
|
+
throw new Error(result.error || "Failed to create vault via relayer");
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
address: result.vaultAddress,
|
|
268
|
+
transactionHash: result.transactionHash || "",
|
|
269
|
+
blockNumber: 0,
|
|
270
|
+
gasUsed: 0n,
|
|
271
|
+
alreadyExisted: result.alreadyExists || false,
|
|
272
|
+
sponsoredBy: "relayer"
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Get vault info via relayer (includes existence check)
|
|
277
|
+
*/
|
|
278
|
+
async getVaultViaRelayer(userKeyHash, relayerUrl) {
|
|
279
|
+
const response = await fetch(
|
|
280
|
+
`${relayerUrl}/api/v1/starknet/vault/${userKeyHash}?chainId=${this.config.wormholeChainId}`
|
|
281
|
+
);
|
|
282
|
+
if (!response.ok) {
|
|
283
|
+
throw new Error("Failed to get vault info from relayer");
|
|
284
|
+
}
|
|
285
|
+
const result = await response.json();
|
|
286
|
+
return {
|
|
287
|
+
vaultAddress: result.vaultAddress,
|
|
288
|
+
exists: result.exists
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
async estimateVaultCreationGas(_userKeyHash) {
|
|
292
|
+
return 0n;
|
|
293
|
+
}
|
|
294
|
+
getFactoryAddress() {
|
|
295
|
+
return void 0;
|
|
296
|
+
}
|
|
297
|
+
getImplementationAddress() {
|
|
298
|
+
return void 0;
|
|
299
|
+
}
|
|
300
|
+
// ========================================================================
|
|
301
|
+
// Balance utility (best-effort)
|
|
302
|
+
// ========================================================================
|
|
303
|
+
async getNativeBalance(address) {
|
|
304
|
+
try {
|
|
305
|
+
const anyProvider = this.provider;
|
|
306
|
+
if (typeof anyProvider.getBalance === "function") {
|
|
307
|
+
const res = await anyProvider.getBalance(address);
|
|
308
|
+
return BigInt(res);
|
|
309
|
+
}
|
|
310
|
+
} catch {
|
|
311
|
+
}
|
|
312
|
+
return 0n;
|
|
313
|
+
}
|
|
314
|
+
getProvider() {
|
|
315
|
+
return this.provider;
|
|
316
|
+
}
|
|
317
|
+
// ========================================================================
|
|
318
|
+
// Session Management (Issue #13)
|
|
319
|
+
// ========================================================================
|
|
320
|
+
/**
|
|
321
|
+
* Register a session key on the Hub (must be called via Hub client)
|
|
322
|
+
* Starknet spokes validate sessions via CCQ, but registration happens on Hub
|
|
323
|
+
*
|
|
324
|
+
* @throws Error - Session management must be done via Hub chain
|
|
325
|
+
*/
|
|
326
|
+
async registerSession(_params) {
|
|
327
|
+
throw new Error(
|
|
328
|
+
"Session registration must be performed on the Hub chain (Base). Use EVMClient connected to the Hub to call registerSession()."
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Revoke a session key on the Hub (must be called via Hub client)
|
|
333
|
+
*
|
|
334
|
+
* @throws Error - Session management must be done via Hub chain
|
|
335
|
+
*/
|
|
336
|
+
async revokeSession(_params) {
|
|
337
|
+
throw new Error(
|
|
338
|
+
"Session revocation must be performed on the Hub chain (Base). Use EVMClient connected to the Hub to call revokeSession()."
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Check if a session is active by querying the Hub
|
|
343
|
+
* This method queries the Hub contract directly for session validation
|
|
344
|
+
*
|
|
345
|
+
* @param userKeyHash - Hash of user's Passkey public key
|
|
346
|
+
* @param sessionKeyHash - Hash of session key to validate
|
|
347
|
+
* @returns Session validation result with expiry and limits
|
|
348
|
+
*/
|
|
349
|
+
async isSessionActive(userKeyHash, sessionKeyHash) {
|
|
350
|
+
if (!this.hubRpcUrl || !this.hubContractAddress) {
|
|
351
|
+
throw new Error(
|
|
352
|
+
"Hub configuration required for session validation. Provide hubRpcUrl and hubContractAddress in StarknetClientConfig."
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
throw new Error(
|
|
356
|
+
"isSessionActive requires Hub client integration. Use EVMClient.isSessionActive() on the Hub chain, then pass the result to session execution on Starknet."
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Get all sessions for a user from the Hub
|
|
361
|
+
*
|
|
362
|
+
* @param userKeyHash - Hash of user's Passkey public key
|
|
363
|
+
* @returns Array of all sessions (active and expired/revoked)
|
|
364
|
+
*/
|
|
365
|
+
async getUserSessions(userKeyHash) {
|
|
366
|
+
if (!this.hubRpcUrl || !this.hubContractAddress) {
|
|
367
|
+
throw new Error(
|
|
368
|
+
"Hub configuration required for session queries. Provide hubRpcUrl and hubContractAddress in StarknetClientConfig."
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
throw new Error(
|
|
372
|
+
`getUserSessions requires Hub client integration. Use EVMClient.getUserSessions() on the Hub chain. User: ${userKeyHash}`
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
// ========================================================================
|
|
376
|
+
// Query-Based Execution (Issue #9/#10)
|
|
377
|
+
// ========================================================================
|
|
378
|
+
/**
|
|
379
|
+
* Get user state from Hub (comprehensive state query)
|
|
380
|
+
* Returns key hash, nonce, and last action hash for CCQ validation
|
|
381
|
+
*
|
|
382
|
+
* @param userKeyHash - Hash of user's Passkey public key
|
|
383
|
+
* @returns User state with nonce and last action hash
|
|
384
|
+
*/
|
|
385
|
+
async getUserState(userKeyHash) {
|
|
386
|
+
if (!this.hubRpcUrl || !this.hubContractAddress) {
|
|
387
|
+
throw new Error(
|
|
388
|
+
"Hub configuration required for state queries. Provide hubRpcUrl and hubContractAddress in StarknetClientConfig."
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
throw new Error(
|
|
392
|
+
`getUserState requires Hub client integration. Use EVMClient.getUserState() on the Hub chain. User: ${userKeyHash}`
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Get user's last action hash from Hub
|
|
397
|
+
* Used for optimistic execution and nonce validation
|
|
398
|
+
*
|
|
399
|
+
* @param userKeyHash - Hash of user's Passkey public key
|
|
400
|
+
* @returns Last action hash (zero hash if no actions)
|
|
401
|
+
*/
|
|
402
|
+
async getUserLastActionHash(userKeyHash) {
|
|
403
|
+
if (!this.hubRpcUrl || !this.hubContractAddress) {
|
|
404
|
+
throw new Error(
|
|
405
|
+
"Hub configuration required for action hash queries. Provide hubRpcUrl and hubContractAddress in StarknetClientConfig."
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
throw new Error(
|
|
409
|
+
`getUserLastActionHash requires Hub client integration. Use EVMClient.getUserLastActionHash() on the Hub chain. User: ${userKeyHash}`
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Execute with query-based validation (faster than VAA, ~23s vs 60-90s)
|
|
414
|
+
* Uses Wormhole CCQ to validate Hub state, then executes on Starknet
|
|
415
|
+
*
|
|
416
|
+
* @param params Query execution parameters with CCQ response
|
|
417
|
+
* @returns Dispatch result with transaction hash
|
|
418
|
+
*
|
|
419
|
+
* @remarks
|
|
420
|
+
* Query-based execution flow:
|
|
421
|
+
* 1. Query Hub state via Wormhole CCQ
|
|
422
|
+
* 2. Validate Guardian signatures on query response
|
|
423
|
+
* 3. Execute on Starknet with validated state
|
|
424
|
+
* 4. Hub state must be < 60s stale (enforced by QueryVerifier)
|
|
425
|
+
*/
|
|
426
|
+
async executeWithQuery(_params) {
|
|
427
|
+
throw new Error(
|
|
428
|
+
"Query-based execution on Starknet requires relayer integration. Use relayer API to submit query-validated transactions. Relayer will call veridex_spoke::execute_with_query on Starknet."
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
// ========================================================================
|
|
432
|
+
// Internal helpers
|
|
433
|
+
// ========================================================================
|
|
434
|
+
computeKeyHash(publicKeyX, publicKeyY) {
|
|
435
|
+
const xHex = publicKeyX.toString(16).padStart(64, "0");
|
|
436
|
+
const yHex = publicKeyY.toString(16).padStart(64, "0");
|
|
437
|
+
const combined = Buffer.from(xHex + yHex, "hex");
|
|
438
|
+
const hash = (0, import_crypto.createHash)("sha256").update(combined).digest("hex");
|
|
439
|
+
return "0x" + hash;
|
|
440
|
+
}
|
|
441
|
+
buildMessageHash(keyHash, targetChain, actionPayload, nonce) {
|
|
442
|
+
const keyHashBuffer = Buffer.from(keyHash.replace(/^0x/, ""), "hex");
|
|
443
|
+
const targetChainBuffer = Buffer.alloc(2);
|
|
444
|
+
targetChainBuffer.writeUInt16BE(targetChain);
|
|
445
|
+
const payloadBuffer = Buffer.from(actionPayload.replace(/^0x/, ""), "hex");
|
|
446
|
+
const nonceHex = nonce.toString(16).padStart(64, "0");
|
|
447
|
+
const nonceBuffer = Buffer.from(nonceHex, "hex");
|
|
448
|
+
const combined = Buffer.concat([keyHashBuffer, targetChainBuffer, payloadBuffer, nonceBuffer]);
|
|
449
|
+
const hash = (0, import_crypto.createHash)("sha256").update(combined).digest("hex");
|
|
450
|
+
return "0x" + hash;
|
|
451
|
+
}
|
|
452
|
+
// ============================================================================
|
|
453
|
+
// Social Recovery Methods (Issue #23)
|
|
454
|
+
// ============================================================================
|
|
455
|
+
//
|
|
456
|
+
// Note: Social recovery is managed on the Hub chain (EVM).
|
|
457
|
+
// Starknet spokes receive and execute recovery VAAs broadcast from the Hub.
|
|
458
|
+
// The relayer service handles submitting recovery transactions to Starknet.
|
|
459
|
+
//
|
|
460
|
+
// SDK users should use EVMClient methods for guardian management and
|
|
461
|
+
// recovery initiation on the Hub chain.
|
|
462
|
+
// ============================================================================
|
|
463
|
+
/**
|
|
464
|
+
* Get vault address by owner key hash
|
|
465
|
+
*
|
|
466
|
+
* @param ownerKeyHash - Owner's passkey hash
|
|
467
|
+
* @returns Vault address on Starknet (felt252 as hex string)
|
|
468
|
+
*/
|
|
469
|
+
async getVaultAddress(ownerKeyHash) {
|
|
470
|
+
try {
|
|
471
|
+
const spokeAddress = this.config.contracts.hub;
|
|
472
|
+
if (!spokeAddress) {
|
|
473
|
+
throw new Error("Spoke contract address not configured");
|
|
474
|
+
}
|
|
475
|
+
const [low, high] = toStarknetU256(ownerKeyHash);
|
|
476
|
+
const result = await this.provider.callContract({
|
|
477
|
+
contractAddress: spokeAddress,
|
|
478
|
+
entrypoint: "get_vault",
|
|
479
|
+
calldata: [low, high]
|
|
480
|
+
});
|
|
481
|
+
const vaultAddress = result[0];
|
|
482
|
+
if (vaultAddress === "0x0" || vaultAddress === "0") {
|
|
483
|
+
return null;
|
|
484
|
+
}
|
|
485
|
+
return vaultAddress;
|
|
486
|
+
} catch (error) {
|
|
487
|
+
console.error("Error getting vault address:", error);
|
|
488
|
+
return null;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Check if vault exists and get basic info
|
|
493
|
+
*
|
|
494
|
+
* @param ownerKeyHash - Owner's passkey hash
|
|
495
|
+
* @returns Vault info or null if not found
|
|
496
|
+
*/
|
|
497
|
+
async getVaultInfo(ownerKeyHash) {
|
|
498
|
+
const vaultAddress = await this.getVaultAddress(ownerKeyHash);
|
|
499
|
+
if (!vaultAddress) {
|
|
500
|
+
return null;
|
|
501
|
+
}
|
|
502
|
+
return {
|
|
503
|
+
address: vaultAddress,
|
|
504
|
+
ownerKeyHash
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Check if spoke contract is paused
|
|
509
|
+
*
|
|
510
|
+
* @returns Whether the protocol is paused
|
|
511
|
+
*/
|
|
512
|
+
async isProtocolPaused() {
|
|
513
|
+
try {
|
|
514
|
+
const spokeAddress = this.config.contracts.hub;
|
|
515
|
+
if (!spokeAddress) {
|
|
516
|
+
throw new Error("Spoke contract address not configured");
|
|
517
|
+
}
|
|
518
|
+
const result = await this.provider.callContract({
|
|
519
|
+
contractAddress: spokeAddress,
|
|
520
|
+
entrypoint: "is_paused",
|
|
521
|
+
calldata: []
|
|
522
|
+
});
|
|
523
|
+
return result[0] === "0x1" || result[0] === "1";
|
|
524
|
+
} catch (error) {
|
|
525
|
+
console.error("Error checking pause status:", error);
|
|
526
|
+
return false;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
531
|
+
0 && (module.exports = {
|
|
532
|
+
StarknetClient
|
|
533
|
+
});
|
|
534
|
+
//# sourceMappingURL=index.js.map
|