@kairoguard/sdk 0.0.6 → 0.0.8
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/dist/client.js +40 -46
- package/dist/ika-protocol.d.ts +8 -0
- package/dist/ika-protocol.js +12 -0
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { BackendClient, } from "./backend.js";
|
|
12
12
|
import { KeyStore } from "./keystore.js";
|
|
13
|
-
import { Curve, fetchProtocolParams, deriveEncryptionKeys, generateSeed, generateSessionIdentifier, runDKG, computeUserOutputSignature, fetchDWallet, } from "./ika-protocol.js";
|
|
13
|
+
import { Curve, fetchProtocolParams, deriveEncryptionKeys, generateSeed, generateSessionIdentifier, runDKG, computeUserOutputSignature, fetchDWallet, waitForDWalletState, } from "./ika-protocol.js";
|
|
14
14
|
import { Hash, SignatureAlgorithm, createUserSignMessageWithPublicOutput } from "@ika.xyz/sdk";
|
|
15
15
|
import { computeEvmIntentFromUnsignedTxBytes } from "./evmIntent.js";
|
|
16
16
|
import { keccak256, recoverTransactionAddress, serializeTransaction, } from "viem";
|
|
@@ -22,7 +22,10 @@ async function testRpcEndpoint(url) {
|
|
|
22
22
|
headers: { "Content-Type": "application/json" },
|
|
23
23
|
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "suix_getLatestSuiSystemState", params: [] }),
|
|
24
24
|
});
|
|
25
|
-
|
|
25
|
+
if (!res.ok)
|
|
26
|
+
return false;
|
|
27
|
+
const json = await res.json();
|
|
28
|
+
return json.jsonrpc === "2.0" && "result" in json;
|
|
26
29
|
}
|
|
27
30
|
catch {
|
|
28
31
|
return false;
|
|
@@ -61,6 +64,8 @@ const PRESIGN_POLL_INTERVAL_MS = 2_000;
|
|
|
61
64
|
const PRESIGN_POLL_TIMEOUT_MS = 120_000;
|
|
62
65
|
const SIGN_POLL_INTERVAL_MS = 2_000;
|
|
63
66
|
const SIGN_POLL_TIMEOUT_MS = 180_000;
|
|
67
|
+
const ACTIVATION_POLL_INTERVAL_MS = 3_000;
|
|
68
|
+
const ACTIVATION_POLL_TIMEOUT_MS = 90_000;
|
|
64
69
|
function curveToNumber(curve) {
|
|
65
70
|
return curve === "ed25519" ? 2 : 0;
|
|
66
71
|
}
|
|
@@ -146,21 +151,7 @@ export class KairoClient {
|
|
|
146
151
|
const walletId = dkgResult.dWalletObjectId;
|
|
147
152
|
const address = (curve === "ed25519" ? dkgResult.solanaAddress : dkgResult.ethereumAddress) ?? "";
|
|
148
153
|
const encryptedShareId = dkgResult.encryptedUserSecretKeyShareId ?? "";
|
|
149
|
-
// 8.
|
|
150
|
-
if (encryptedShareId) {
|
|
151
|
-
await this.activateWallet(walletId, encryptedShareId, encryptionKeys, dkgOutputs.userPublicOutput);
|
|
152
|
-
}
|
|
153
|
-
// 9. Provision into vault (binding + registration) if policy is provided
|
|
154
|
-
let bindingObjectId;
|
|
155
|
-
if (opts?.policyObjectId) {
|
|
156
|
-
const provisionResult = await this.backend.provision({
|
|
157
|
-
dwalletObjectId: walletId,
|
|
158
|
-
policyObjectId: opts.policyObjectId,
|
|
159
|
-
stableId: opts.stableId ?? `agent-wallet-${walletId.slice(0, 8)}`,
|
|
160
|
-
});
|
|
161
|
-
bindingObjectId = provisionResult.bindingObjectId ?? undefined;
|
|
162
|
-
}
|
|
163
|
-
// 10. Save secret share locally
|
|
154
|
+
// 8. Save secret share locally BEFORE activation so it is never lost
|
|
164
155
|
const record = {
|
|
165
156
|
walletId,
|
|
166
157
|
dWalletCapId: dkgResult.dWalletCapObjectId,
|
|
@@ -170,11 +161,26 @@ export class KairoClient {
|
|
|
170
161
|
userSecretKeyShare: dkgOutputs.userSecretKeyShare,
|
|
171
162
|
userPublicOutput: dkgOutputs.userPublicOutput,
|
|
172
163
|
encryptedUserSecretKeyShareId: encryptedShareId,
|
|
173
|
-
bindingObjectId,
|
|
164
|
+
bindingObjectId: undefined,
|
|
174
165
|
policyObjectId: opts?.policyObjectId,
|
|
175
166
|
createdAt: Date.now(),
|
|
176
167
|
};
|
|
177
168
|
this.store.save(record);
|
|
169
|
+
// 9. Activate the dWallet (sign to accept encrypted key share)
|
|
170
|
+
if (encryptedShareId) {
|
|
171
|
+
await this.activateWallet(walletId, encryptedShareId, encryptionKeys, dkgOutputs.userPublicOutput);
|
|
172
|
+
}
|
|
173
|
+
// 10. Provision into vault (binding + registration) if policy is provided
|
|
174
|
+
let bindingObjectId;
|
|
175
|
+
if (opts?.policyObjectId) {
|
|
176
|
+
const provisionResult = await this.backend.provision({
|
|
177
|
+
dwalletObjectId: walletId,
|
|
178
|
+
policyObjectId: opts.policyObjectId,
|
|
179
|
+
stableId: opts.stableId ?? `agent-wallet-${walletId.slice(0, 8)}`,
|
|
180
|
+
});
|
|
181
|
+
bindingObjectId = provisionResult.bindingObjectId ?? undefined;
|
|
182
|
+
this.store.save({ ...record, bindingObjectId });
|
|
183
|
+
}
|
|
178
184
|
return {
|
|
179
185
|
walletId,
|
|
180
186
|
address,
|
|
@@ -531,38 +537,26 @@ export class KairoClient {
|
|
|
531
537
|
return BigInt(balanceHex);
|
|
532
538
|
}
|
|
533
539
|
async activateWallet(walletId, encryptedShareId, encryptionKeys, userPublicOutput) {
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
if (!isAwaitingSignature) {
|
|
548
|
-
// Unknown state - wait and retry once
|
|
549
|
-
await new Promise((r) => setTimeout(r, 3000));
|
|
550
|
-
const dWallet2 = await withRetry(() => fetchDWallet(rpcUrlForActivation, this.network, walletId), { label: "fetchDWallet(activate-recheck)" });
|
|
551
|
-
const state2 = dWallet2?.state;
|
|
552
|
-
const isActive2 = Boolean(state2?.Active) || state2?.$kind === "Active";
|
|
553
|
-
if (isActive2)
|
|
540
|
+
const rpcUrl = await this.resolveSuiRpcUrl();
|
|
541
|
+
// After DKG the on-chain dWallet goes through AwaitingNetworkDKGVerification
|
|
542
|
+
// (30-60s+ on testnet). Use the Ika SDK's native polling to wait for the
|
|
543
|
+
// correct state before attempting activation.
|
|
544
|
+
let dWallet;
|
|
545
|
+
try {
|
|
546
|
+
dWallet = await waitForDWalletState(rpcUrl, this.network, walletId, "AwaitingKeyHolderSignature", { timeout: ACTIVATION_POLL_TIMEOUT_MS, interval: ACTIVATION_POLL_INTERVAL_MS });
|
|
547
|
+
}
|
|
548
|
+
catch {
|
|
549
|
+
// May already be Active (idempotent retry after earlier partial success)
|
|
550
|
+
const current = await withRetry(() => fetchDWallet(rpcUrl, this.network, walletId), { label: "fetchDWallet(activate-fallback)" });
|
|
551
|
+
const kind = String(current?.state?.$kind ?? "");
|
|
552
|
+
if (kind === "Active")
|
|
554
553
|
return;
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
if (!isAwaiting2) {
|
|
558
|
-
const stateKind = state2?.$kind ?? Object.keys(state2 ?? {})[0] ?? "Unknown";
|
|
559
|
-
throw new Error(`dWallet is not ready for activation (state=${stateKind}). ` +
|
|
560
|
-
`This can happen if the DKG is still processing. Wait a few seconds and retry.`);
|
|
561
|
-
}
|
|
554
|
+
throw new Error(`dWallet activation timed out after ${ACTIVATION_POLL_TIMEOUT_MS / 1000}s ` +
|
|
555
|
+
`(state=${kind || "Unknown"}). The wallet record is saved locally — retry later.`);
|
|
562
556
|
}
|
|
563
557
|
const signature = await computeUserOutputSignature({
|
|
564
558
|
encryptionKeys,
|
|
565
|
-
dWallet,
|
|
559
|
+
dWallet: dWallet,
|
|
566
560
|
userPublicOutput: new Uint8Array(userPublicOutput),
|
|
567
561
|
});
|
|
568
562
|
await this.backend.activateDWallet({
|
package/dist/ika-protocol.d.ts
CHANGED
|
@@ -54,6 +54,14 @@ export declare function computeUserOutputSignature(params: {
|
|
|
54
54
|
* Fetch the dWallet object from Ika network for activation.
|
|
55
55
|
*/
|
|
56
56
|
export declare function fetchDWallet(suiRpcUrl: string, network: "testnet" | "mainnet", dwalletId: string): Promise<any>;
|
|
57
|
+
/**
|
|
58
|
+
* Poll until the dWallet reaches `targetState` using the Ika SDK's native
|
|
59
|
+
* getDWalletInParticularState, which handles reindexing/lag gracefully.
|
|
60
|
+
*/
|
|
61
|
+
export declare function waitForDWalletState(suiRpcUrl: string, network: "testnet" | "mainnet", dwalletId: string, targetState: "AwaitingKeyHolderSignature" | "Active", opts?: {
|
|
62
|
+
timeout?: number;
|
|
63
|
+
interval?: number;
|
|
64
|
+
}): Promise<any>;
|
|
57
65
|
export interface ComputeUserSignMessageParams {
|
|
58
66
|
protocolPublicParameters: Uint8Array;
|
|
59
67
|
userPublicOutput: Uint8Array;
|
package/dist/ika-protocol.js
CHANGED
|
@@ -98,6 +98,18 @@ export async function fetchDWallet(suiRpcUrl, network, dwalletId) {
|
|
|
98
98
|
await ready;
|
|
99
99
|
return ikaClient.getDWallet(dwalletId);
|
|
100
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Poll until the dWallet reaches `targetState` using the Ika SDK's native
|
|
103
|
+
* getDWalletInParticularState, which handles reindexing/lag gracefully.
|
|
104
|
+
*/
|
|
105
|
+
export async function waitForDWalletState(suiRpcUrl, network, dwalletId, targetState, opts) {
|
|
106
|
+
const { ikaClient, ready } = getOrCreateIkaClient(network, suiRpcUrl);
|
|
107
|
+
await ready;
|
|
108
|
+
return ikaClient.getDWalletInParticularState(dwalletId, targetState, {
|
|
109
|
+
timeout: opts?.timeout ?? 90_000,
|
|
110
|
+
interval: opts?.interval ?? 3_000,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
101
113
|
/**
|
|
102
114
|
* Build the user-side sign message used by IKA MPC signing.
|
|
103
115
|
*/
|