@kairoguard/sdk 0.0.7 → 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 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";
@@ -64,6 +64,8 @@ const PRESIGN_POLL_INTERVAL_MS = 2_000;
64
64
  const PRESIGN_POLL_TIMEOUT_MS = 120_000;
65
65
  const SIGN_POLL_INTERVAL_MS = 2_000;
66
66
  const SIGN_POLL_TIMEOUT_MS = 180_000;
67
+ const ACTIVATION_POLL_INTERVAL_MS = 3_000;
68
+ const ACTIVATION_POLL_TIMEOUT_MS = 90_000;
67
69
  function curveToNumber(curve) {
68
70
  return curve === "ed25519" ? 2 : 0;
69
71
  }
@@ -149,21 +151,7 @@ export class KairoClient {
149
151
  const walletId = dkgResult.dWalletObjectId;
150
152
  const address = (curve === "ed25519" ? dkgResult.solanaAddress : dkgResult.ethereumAddress) ?? "";
151
153
  const encryptedShareId = dkgResult.encryptedUserSecretKeyShareId ?? "";
152
- // 8. Activate the dWallet (sign to accept encrypted key share)
153
- if (encryptedShareId) {
154
- await this.activateWallet(walletId, encryptedShareId, encryptionKeys, dkgOutputs.userPublicOutput);
155
- }
156
- // 9. Provision into vault (binding + registration) if policy is provided
157
- let bindingObjectId;
158
- if (opts?.policyObjectId) {
159
- const provisionResult = await this.backend.provision({
160
- dwalletObjectId: walletId,
161
- policyObjectId: opts.policyObjectId,
162
- stableId: opts.stableId ?? `agent-wallet-${walletId.slice(0, 8)}`,
163
- });
164
- bindingObjectId = provisionResult.bindingObjectId ?? undefined;
165
- }
166
- // 10. Save secret share locally
154
+ // 8. Save secret share locally BEFORE activation so it is never lost
167
155
  const record = {
168
156
  walletId,
169
157
  dWalletCapId: dkgResult.dWalletCapObjectId,
@@ -173,11 +161,26 @@ export class KairoClient {
173
161
  userSecretKeyShare: dkgOutputs.userSecretKeyShare,
174
162
  userPublicOutput: dkgOutputs.userPublicOutput,
175
163
  encryptedUserSecretKeyShareId: encryptedShareId,
176
- bindingObjectId,
164
+ bindingObjectId: undefined,
177
165
  policyObjectId: opts?.policyObjectId,
178
166
  createdAt: Date.now(),
179
167
  };
180
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
+ }
181
184
  return {
182
185
  walletId,
183
186
  address,
@@ -534,38 +537,26 @@ export class KairoClient {
534
537
  return BigInt(balanceHex);
535
538
  }
536
539
  async activateWallet(walletId, encryptedShareId, encryptionKeys, userPublicOutput) {
537
- // Wait a moment for the dWallet state to propagate
538
- await new Promise((r) => setTimeout(r, 2000));
539
- const rpcUrlForActivation = await this.resolveSuiRpcUrl();
540
- const dWallet = await withRetry(() => fetchDWallet(rpcUrlForActivation, this.network, walletId), { label: "fetchDWallet(activate)" });
541
- // Check dWallet state - skip activation if already active
542
- const state = dWallet?.state;
543
- const isActive = Boolean(state?.Active) || state?.$kind === "Active";
544
- if (isActive) {
545
- // Already activated, nothing to do
546
- return;
547
- }
548
- const isAwaitingSignature = Boolean(state?.AwaitingKeyHolderSignature) ||
549
- state?.$kind === "AwaitingKeyHolderSignature";
550
- if (!isAwaitingSignature) {
551
- // Unknown state - wait and retry once
552
- await new Promise((r) => setTimeout(r, 3000));
553
- const dWallet2 = await withRetry(() => fetchDWallet(rpcUrlForActivation, this.network, walletId), { label: "fetchDWallet(activate-recheck)" });
554
- const state2 = dWallet2?.state;
555
- const isActive2 = Boolean(state2?.Active) || state2?.$kind === "Active";
556
- 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")
557
553
  return;
558
- const isAwaiting2 = Boolean(state2?.AwaitingKeyHolderSignature) ||
559
- state2?.$kind === "AwaitingKeyHolderSignature";
560
- if (!isAwaiting2) {
561
- const stateKind = state2?.$kind ?? Object.keys(state2 ?? {})[0] ?? "Unknown";
562
- throw new Error(`dWallet is not ready for activation (state=${stateKind}). ` +
563
- `This can happen if the DKG is still processing. Wait a few seconds and retry.`);
564
- }
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.`);
565
556
  }
566
557
  const signature = await computeUserOutputSignature({
567
558
  encryptionKeys,
568
- dWallet,
559
+ dWallet: dWallet,
569
560
  userPublicOutput: new Uint8Array(userPublicOutput),
570
561
  });
571
562
  await this.backend.activateDWallet({
@@ -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;
@@ -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
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kairoguard/sdk",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",