@kairoguard/sdk 0.0.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/README.md +92 -0
- package/dist/auditBundle.d.ts +28 -0
- package/dist/auditBundle.js +20 -0
- package/dist/backend.d.ts +288 -0
- package/dist/backend.js +107 -0
- package/dist/bitcoinIntent.d.ts +104 -0
- package/dist/bitcoinIntent.js +126 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +237 -0
- package/dist/client.d.ts +186 -0
- package/dist/client.js +767 -0
- package/dist/evm.d.ts +19 -0
- package/dist/evm.js +53 -0
- package/dist/evmIntent.d.ts +11 -0
- package/dist/evmIntent.js +12 -0
- package/dist/ika-protocol.d.ts +85 -0
- package/dist/ika-protocol.js +156 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +13 -0
- package/dist/keystore.d.ts +29 -0
- package/dist/keystore.js +53 -0
- package/dist/skill-templates.d.ts +9 -0
- package/dist/skill-templates.js +252 -0
- package/dist/solanaIntent.d.ts +128 -0
- package/dist/solanaIntent.js +214 -0
- package/dist/suiCustody.d.ts +14 -0
- package/dist/suiCustody.js +183 -0
- package/dist/suiReceipts.d.ts +27 -0
- package/dist/suiReceipts.js +203 -0
- package/dist/suiResult.d.ts +8 -0
- package/dist/suiResult.js +12 -0
- package/dist/suiTxBuilders.d.ts +15 -0
- package/dist/suiTxBuilders.js +38 -0
- package/dist/types.d.ts +38 -0
- package/dist/types.js +1 -0
- package/package.json +29 -0
package/dist/evm.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal EVM JSON-RPC helpers using raw fetch (no ethers/viem runtime dependency).
|
|
3
|
+
*/
|
|
4
|
+
export interface EstimateGasParams {
|
|
5
|
+
from?: string;
|
|
6
|
+
to?: string;
|
|
7
|
+
value?: string;
|
|
8
|
+
data?: string;
|
|
9
|
+
gas?: string;
|
|
10
|
+
gasPrice?: string;
|
|
11
|
+
maxFeePerGas?: string;
|
|
12
|
+
maxPriorityFeePerGas?: string;
|
|
13
|
+
nonce?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function broadcastEvm(signedTx: string, rpcUrl: string): Promise<string>;
|
|
16
|
+
export declare function getBalance(address: string, rpcUrl: string): Promise<bigint>;
|
|
17
|
+
export declare function estimateGas(txParams: EstimateGasParams, rpcUrl: string): Promise<bigint>;
|
|
18
|
+
export declare function getTransactionCount(address: string, rpcUrl: string): Promise<bigint>;
|
|
19
|
+
export declare function getGasPrice(rpcUrl: string): Promise<bigint>;
|
package/dist/evm.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal EVM JSON-RPC helpers using raw fetch (no ethers/viem runtime dependency).
|
|
3
|
+
*/
|
|
4
|
+
let rpcRequestId = 0;
|
|
5
|
+
function parseHexQuantity(value, field) {
|
|
6
|
+
if (typeof value !== "string" || !/^0x[0-9a-fA-F]+$/.test(value)) {
|
|
7
|
+
throw new Error(`Invalid ${field} response: expected hex quantity`);
|
|
8
|
+
}
|
|
9
|
+
return BigInt(value);
|
|
10
|
+
}
|
|
11
|
+
async function rpcCall(rpcUrl, method, params) {
|
|
12
|
+
const id = ++rpcRequestId;
|
|
13
|
+
const response = await fetch(rpcUrl, {
|
|
14
|
+
method: "POST",
|
|
15
|
+
headers: { "Content-Type": "application/json" },
|
|
16
|
+
body: JSON.stringify({
|
|
17
|
+
jsonrpc: "2.0",
|
|
18
|
+
id,
|
|
19
|
+
method,
|
|
20
|
+
params,
|
|
21
|
+
}),
|
|
22
|
+
});
|
|
23
|
+
const payload = await response.json();
|
|
24
|
+
if (!response.ok) {
|
|
25
|
+
const errorMessage = "error" in payload
|
|
26
|
+
? payload.error.message
|
|
27
|
+
: `HTTP ${response.status}`;
|
|
28
|
+
throw new Error(`EVM RPC error (${method}): ${errorMessage}`);
|
|
29
|
+
}
|
|
30
|
+
if ("error" in payload) {
|
|
31
|
+
throw new Error(`EVM RPC error (${method}): ${payload.error.message}`);
|
|
32
|
+
}
|
|
33
|
+
return payload.result;
|
|
34
|
+
}
|
|
35
|
+
export async function broadcastEvm(signedTx, rpcUrl) {
|
|
36
|
+
return rpcCall(rpcUrl, "eth_sendRawTransaction", [signedTx]);
|
|
37
|
+
}
|
|
38
|
+
export async function getBalance(address, rpcUrl) {
|
|
39
|
+
const result = await rpcCall(rpcUrl, "eth_getBalance", [address, "latest"]);
|
|
40
|
+
return parseHexQuantity(result, "eth_getBalance");
|
|
41
|
+
}
|
|
42
|
+
export async function estimateGas(txParams, rpcUrl) {
|
|
43
|
+
const result = await rpcCall(rpcUrl, "eth_estimateGas", [txParams]);
|
|
44
|
+
return parseHexQuantity(result, "eth_estimateGas");
|
|
45
|
+
}
|
|
46
|
+
export async function getTransactionCount(address, rpcUrl) {
|
|
47
|
+
const result = await rpcCall(rpcUrl, "eth_getTransactionCount", [address, "pending"]);
|
|
48
|
+
return parseHexQuantity(result, "eth_getTransactionCount");
|
|
49
|
+
}
|
|
50
|
+
export async function getGasPrice(rpcUrl) {
|
|
51
|
+
const result = await rpcCall(rpcUrl, "eth_gasPrice", []);
|
|
52
|
+
return parseHexQuantity(result, "eth_gasPrice");
|
|
53
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { EvmChainId, EvmIntent, Hex } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Compute the EVM intent hash from the serialized unsigned tx bytes.
|
|
4
|
+
*
|
|
5
|
+
* In the reference ETH demo, the MPC signs over the raw serialized unsigned tx bytes,
|
|
6
|
+
* and the hash scheme used for ECDSA is KECCAK256.
|
|
7
|
+
*/
|
|
8
|
+
export declare function computeEvmIntentFromUnsignedTxBytes(params: {
|
|
9
|
+
chainId: EvmChainId;
|
|
10
|
+
unsignedTxBytesHex: Hex;
|
|
11
|
+
}): EvmIntent;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { keccak256, toBytes } from "viem";
|
|
2
|
+
/**
|
|
3
|
+
* Compute the EVM intent hash from the serialized unsigned tx bytes.
|
|
4
|
+
*
|
|
5
|
+
* In the reference ETH demo, the MPC signs over the raw serialized unsigned tx bytes,
|
|
6
|
+
* and the hash scheme used for ECDSA is KECCAK256.
|
|
7
|
+
*/
|
|
8
|
+
export function computeEvmIntentFromUnsignedTxBytes(params) {
|
|
9
|
+
const bytes = toBytes(params.unsignedTxBytesHex);
|
|
10
|
+
const intentHash = keccak256(bytes);
|
|
11
|
+
return { chainId: params.chainId, intentHash };
|
|
12
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ika Protocol helpers -- wraps @ika.xyz/sdk internals into clean functions.
|
|
3
|
+
*
|
|
4
|
+
* All Ika-specific crypto runs on the caller's machine (agent/client).
|
|
5
|
+
* The agent's secret share never leaves this process.
|
|
6
|
+
*/
|
|
7
|
+
import { UserShareEncryptionKeys, Curve, Hash, SignatureAlgorithm } from "@ika.xyz/sdk";
|
|
8
|
+
export type SupportedCurve = "secp256k1" | "ed25519";
|
|
9
|
+
declare function resolveCurve(curve: SupportedCurve): Curve;
|
|
10
|
+
/**
|
|
11
|
+
* Fetch Ika protocol public parameters for a given curve.
|
|
12
|
+
* Uses the IkaClient which reads from the Ika coordinator on Sui.
|
|
13
|
+
*/
|
|
14
|
+
export declare function fetchProtocolParams(curve: SupportedCurve, suiRpcUrl: string, network?: "testnet" | "mainnet"): Promise<Uint8Array>;
|
|
15
|
+
/**
|
|
16
|
+
* Derive encryption keys from a random seed (replaces browser wallet signature).
|
|
17
|
+
*/
|
|
18
|
+
export declare function deriveEncryptionKeys(seed: Uint8Array, curve: SupportedCurve): Promise<UserShareEncryptionKeys>;
|
|
19
|
+
/**
|
|
20
|
+
* Generate a random 32-byte seed for encryption key derivation.
|
|
21
|
+
*/
|
|
22
|
+
export declare function generateSeed(): Uint8Array;
|
|
23
|
+
export interface DKGOutputs {
|
|
24
|
+
userPublicOutput: number[];
|
|
25
|
+
userSecretKeyShare: number[];
|
|
26
|
+
userDKGMessage: number[];
|
|
27
|
+
encryptedUserShareAndProof: number[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Run the client-side DKG computation.
|
|
31
|
+
* This generates the user's share of the dWallet key pair.
|
|
32
|
+
*/
|
|
33
|
+
export declare function runDKG(params: {
|
|
34
|
+
protocolPublicParameters: Uint8Array;
|
|
35
|
+
curve: SupportedCurve;
|
|
36
|
+
encryptionKey: Uint8Array;
|
|
37
|
+
sessionIdentifier: Uint8Array;
|
|
38
|
+
adminAddress: string;
|
|
39
|
+
}): Promise<DKGOutputs>;
|
|
40
|
+
/**
|
|
41
|
+
* Generate a fresh random session identifier (32 bytes).
|
|
42
|
+
*/
|
|
43
|
+
export declare function generateSessionIdentifier(): Uint8Array;
|
|
44
|
+
/**
|
|
45
|
+
* Compute the user output signature needed to activate a dWallet.
|
|
46
|
+
* Requires the dWallet object (fetched from chain) and the user's public output.
|
|
47
|
+
*/
|
|
48
|
+
export declare function computeUserOutputSignature(params: {
|
|
49
|
+
encryptionKeys: UserShareEncryptionKeys;
|
|
50
|
+
dWallet: any;
|
|
51
|
+
userPublicOutput: Uint8Array;
|
|
52
|
+
}): Promise<Uint8Array>;
|
|
53
|
+
/**
|
|
54
|
+
* Fetch the dWallet object from Ika network for activation.
|
|
55
|
+
*/
|
|
56
|
+
export declare function fetchDWallet(suiRpcUrl: string, network: "testnet" | "mainnet", dwalletId: string): Promise<any>;
|
|
57
|
+
export interface ComputeUserSignMessageParams {
|
|
58
|
+
protocolPublicParameters: Uint8Array;
|
|
59
|
+
userPublicOutput: Uint8Array;
|
|
60
|
+
userSecretKeyShare: Uint8Array;
|
|
61
|
+
presignBytes: Uint8Array;
|
|
62
|
+
message: Uint8Array;
|
|
63
|
+
hash?: Hash;
|
|
64
|
+
signatureAlgorithm?: SignatureAlgorithm;
|
|
65
|
+
curve?: Curve;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Build the user-side sign message used by IKA MPC signing.
|
|
69
|
+
*/
|
|
70
|
+
export declare function computeUserSignMessage(params: ComputeUserSignMessageParams): Promise<Uint8Array>;
|
|
71
|
+
/**
|
|
72
|
+
* Decode presign bytes from common backend/network payload formats.
|
|
73
|
+
*/
|
|
74
|
+
export declare function decodePresignBytes(value: unknown): Uint8Array;
|
|
75
|
+
/**
|
|
76
|
+
* Decode and validate presign result objects returned by polling APIs.
|
|
77
|
+
*/
|
|
78
|
+
export declare function decodePresignResult(value: {
|
|
79
|
+
presignId?: string;
|
|
80
|
+
presignBytes?: unknown;
|
|
81
|
+
}): {
|
|
82
|
+
presignId: string;
|
|
83
|
+
presignBytes: Uint8Array;
|
|
84
|
+
};
|
|
85
|
+
export { Curve, resolveCurve };
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ika Protocol helpers -- wraps @ika.xyz/sdk internals into clean functions.
|
|
3
|
+
*
|
|
4
|
+
* All Ika-specific crypto runs on the caller's machine (agent/client).
|
|
5
|
+
* The agent's secret share never leaves this process.
|
|
6
|
+
*/
|
|
7
|
+
import { prepareDKG, UserShareEncryptionKeys, createRandomSessionIdentifier, createUserSignMessageWithPublicOutput, Curve, Hash, IkaClient, getNetworkConfig, SignatureAlgorithm, } from "@ika.xyz/sdk";
|
|
8
|
+
import { SuiClient } from "@mysten/sui/client";
|
|
9
|
+
import { randomBytes } from "node:crypto";
|
|
10
|
+
function resolveCurve(curve) {
|
|
11
|
+
return curve === "ed25519" ? Curve.ED25519 : Curve.SECP256K1;
|
|
12
|
+
}
|
|
13
|
+
// Protocol params are large (~MB). Cache per curve to avoid refetching.
|
|
14
|
+
const paramsCache = new Map();
|
|
15
|
+
/**
|
|
16
|
+
* Fetch Ika protocol public parameters for a given curve.
|
|
17
|
+
* Uses the IkaClient which reads from the Ika coordinator on Sui.
|
|
18
|
+
*/
|
|
19
|
+
export async function fetchProtocolParams(curve, suiRpcUrl, network = "testnet") {
|
|
20
|
+
const ikaCurve = resolveCurve(curve);
|
|
21
|
+
const cached = paramsCache.get(ikaCurve);
|
|
22
|
+
if (cached)
|
|
23
|
+
return cached;
|
|
24
|
+
const suiClient = new SuiClient({ url: suiRpcUrl });
|
|
25
|
+
const ikaConfig = getNetworkConfig(network);
|
|
26
|
+
const ikaClient = new IkaClient({ suiClient, config: ikaConfig });
|
|
27
|
+
await ikaClient.initialize();
|
|
28
|
+
// First arg is dWallet (undefined for new wallets), second is curve
|
|
29
|
+
const params = await ikaClient.getProtocolPublicParameters(undefined, ikaCurve);
|
|
30
|
+
paramsCache.set(ikaCurve, params);
|
|
31
|
+
return params;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Derive encryption keys from a random seed (replaces browser wallet signature).
|
|
35
|
+
*/
|
|
36
|
+
export async function deriveEncryptionKeys(seed, curve) {
|
|
37
|
+
return UserShareEncryptionKeys.fromRootSeedKey(seed, resolveCurve(curve));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Generate a random 32-byte seed for encryption key derivation.
|
|
41
|
+
*/
|
|
42
|
+
export function generateSeed() {
|
|
43
|
+
return new Uint8Array(randomBytes(32));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Run the client-side DKG computation.
|
|
47
|
+
* This generates the user's share of the dWallet key pair.
|
|
48
|
+
*/
|
|
49
|
+
export async function runDKG(params) {
|
|
50
|
+
const ikaCurve = resolveCurve(params.curve);
|
|
51
|
+
const result = await prepareDKG(params.protocolPublicParameters, ikaCurve, params.encryptionKey, params.sessionIdentifier, params.adminAddress);
|
|
52
|
+
return {
|
|
53
|
+
userPublicOutput: Array.from(result.userPublicOutput),
|
|
54
|
+
userSecretKeyShare: Array.from(result.userSecretKeyShare),
|
|
55
|
+
userDKGMessage: Array.from(result.userDKGMessage),
|
|
56
|
+
encryptedUserShareAndProof: Array.from(result.encryptedUserShareAndProof),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Generate a fresh random session identifier (32 bytes).
|
|
61
|
+
*/
|
|
62
|
+
export function generateSessionIdentifier() {
|
|
63
|
+
return createRandomSessionIdentifier();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Compute the user output signature needed to activate a dWallet.
|
|
67
|
+
* Requires the dWallet object (fetched from chain) and the user's public output.
|
|
68
|
+
*/
|
|
69
|
+
export async function computeUserOutputSignature(params) {
|
|
70
|
+
return params.encryptionKeys.getUserOutputSignature(params.dWallet, params.userPublicOutput);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Fetch the dWallet object from Ika network for activation.
|
|
74
|
+
*/
|
|
75
|
+
export async function fetchDWallet(suiRpcUrl, network, dwalletId) {
|
|
76
|
+
const suiClient = new SuiClient({ url: suiRpcUrl });
|
|
77
|
+
const ikaConfig = getNetworkConfig(network);
|
|
78
|
+
const ikaClient = new IkaClient({ suiClient, config: ikaConfig });
|
|
79
|
+
await ikaClient.initialize();
|
|
80
|
+
return ikaClient.getDWallet(dwalletId);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Build the user-side sign message used by IKA MPC signing.
|
|
84
|
+
*/
|
|
85
|
+
export async function computeUserSignMessage(params) {
|
|
86
|
+
return createUserSignMessageWithPublicOutput(params.protocolPublicParameters, params.userPublicOutput, params.userSecretKeyShare, params.presignBytes, params.message, params.hash ?? Hash.KECCAK256, params.signatureAlgorithm ?? SignatureAlgorithm.ECDSASecp256k1, params.curve ?? Curve.SECP256K1);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Decode presign bytes from common backend/network payload formats.
|
|
90
|
+
*/
|
|
91
|
+
export function decodePresignBytes(value) {
|
|
92
|
+
const decoded = coerceBytes(value);
|
|
93
|
+
if (!decoded) {
|
|
94
|
+
throw new Error("Invalid presign bytes format");
|
|
95
|
+
}
|
|
96
|
+
return decoded;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Decode and validate presign result objects returned by polling APIs.
|
|
100
|
+
*/
|
|
101
|
+
export function decodePresignResult(value) {
|
|
102
|
+
if (!value.presignId) {
|
|
103
|
+
throw new Error("Missing presignId");
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
presignId: value.presignId,
|
|
107
|
+
presignBytes: decodePresignBytes(value.presignBytes),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function coerceBytes(v) {
|
|
111
|
+
if (v instanceof Uint8Array)
|
|
112
|
+
return v;
|
|
113
|
+
if (Array.isArray(v) && v.every((x) => Number.isInteger(x) && x >= 0 && x <= 255)) {
|
|
114
|
+
return Uint8Array.from(v);
|
|
115
|
+
}
|
|
116
|
+
if (typeof v === "string") {
|
|
117
|
+
if (/^0x[0-9a-fA-F]*$/.test(v)) {
|
|
118
|
+
const raw = v.slice(2);
|
|
119
|
+
if (raw.length % 2 !== 0)
|
|
120
|
+
return null;
|
|
121
|
+
const out = new Uint8Array(raw.length / 2);
|
|
122
|
+
for (let i = 0; i < out.length; i++)
|
|
123
|
+
out[i] = parseInt(raw.slice(i * 2, i * 2 + 2), 16);
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
126
|
+
return base64ToBytes(v);
|
|
127
|
+
}
|
|
128
|
+
if (v && typeof v === "object") {
|
|
129
|
+
const obj = v;
|
|
130
|
+
if (typeof obj.bytes === "string")
|
|
131
|
+
return coerceBytes(obj.bytes);
|
|
132
|
+
if (typeof obj.data === "string")
|
|
133
|
+
return coerceBytes(obj.data);
|
|
134
|
+
if (typeof obj.value === "string")
|
|
135
|
+
return coerceBytes(obj.value);
|
|
136
|
+
if (Array.isArray(obj.bytes))
|
|
137
|
+
return coerceBytes(obj.bytes);
|
|
138
|
+
if (Array.isArray(obj.data))
|
|
139
|
+
return coerceBytes(obj.data);
|
|
140
|
+
if (Array.isArray(obj.value))
|
|
141
|
+
return coerceBytes(obj.value);
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
function base64ToBytes(s) {
|
|
146
|
+
try {
|
|
147
|
+
const buf = Buffer.from(s, "base64");
|
|
148
|
+
if (buf.length === 0 && s.length > 0)
|
|
149
|
+
return null;
|
|
150
|
+
return Uint8Array.from(buf);
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
export { Curve, resolveCurve };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from "./types";
|
|
2
|
+
export * from "./evmIntent";
|
|
3
|
+
export * from "./evm";
|
|
4
|
+
export * from "./bitcoinIntent";
|
|
5
|
+
export { type SolanaCluster, LAMPORTS_PER_SOL, type ParsedInstruction, type ParsedSolanaTransaction, type SolanaIntent, PROGRAM_IDS, SystemInstructionType, base58Decode, base58Encode, validateSolanaAddress, computeSolanaIntentHash, isKnownSafeProgram, isTokenProgram, getProgramName, lamportsToSOL, solToLamports, extractSystemTransfers, } from "./solanaIntent";
|
|
6
|
+
export * from "./suiReceipts";
|
|
7
|
+
export * from "./suiResult";
|
|
8
|
+
export * from "./suiTxBuilders";
|
|
9
|
+
export * from "./auditBundle";
|
|
10
|
+
export * from "./suiCustody";
|
|
11
|
+
export { KairoClient, type KairoClientOpts, type CreateWalletOpts, type WalletInfo, type ProposePolicyUpdateParams, type PolicyUpdateProposalResult, type ApprovePolicyUpdateParams, type ExecutePolicyUpdateParams, type PolicyUpdateStatus, } from "./client";
|
|
12
|
+
export { KeyStore, type WalletRecord } from "./keystore";
|
|
13
|
+
export { BackendClient, DEFAULT_BACKEND_URL, type BackendClientOpts } from "./backend";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from "./types";
|
|
2
|
+
export * from "./evmIntent";
|
|
3
|
+
export * from "./evm";
|
|
4
|
+
export * from "./bitcoinIntent";
|
|
5
|
+
export { LAMPORTS_PER_SOL, PROGRAM_IDS, SystemInstructionType, base58Decode, base58Encode, validateSolanaAddress, computeSolanaIntentHash, isKnownSafeProgram, isTokenProgram, getProgramName, lamportsToSOL, solToLamports, extractSystemTransfers, } from "./solanaIntent";
|
|
6
|
+
export * from "./suiReceipts";
|
|
7
|
+
export * from "./suiResult";
|
|
8
|
+
export * from "./suiTxBuilders";
|
|
9
|
+
export * from "./auditBundle";
|
|
10
|
+
export * from "./suiCustody";
|
|
11
|
+
export { KairoClient, } from "./client";
|
|
12
|
+
export { KeyStore } from "./keystore";
|
|
13
|
+
export { BackendClient, DEFAULT_BACKEND_URL } from "./backend";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local file-based key store for agent secret shares.
|
|
3
|
+
*
|
|
4
|
+
* Stores one JSON file per wallet in `storePath`.
|
|
5
|
+
* The agent's secret key share NEVER leaves this directory.
|
|
6
|
+
*/
|
|
7
|
+
export interface WalletRecord {
|
|
8
|
+
walletId: string;
|
|
9
|
+
dWalletCapId?: string;
|
|
10
|
+
address: string;
|
|
11
|
+
curve: string;
|
|
12
|
+
seed: number[];
|
|
13
|
+
userSecretKeyShare: number[];
|
|
14
|
+
userPublicOutput: number[];
|
|
15
|
+
encryptedUserSecretKeyShareId: string;
|
|
16
|
+
bindingObjectId?: string;
|
|
17
|
+
policyObjectId?: string;
|
|
18
|
+
createdAt: number;
|
|
19
|
+
}
|
|
20
|
+
export declare class KeyStore {
|
|
21
|
+
private dir;
|
|
22
|
+
constructor(storePath?: string);
|
|
23
|
+
private filePath;
|
|
24
|
+
save(record: WalletRecord): void;
|
|
25
|
+
load(walletId: string): WalletRecord | null;
|
|
26
|
+
list(): WalletRecord[];
|
|
27
|
+
delete(walletId: string): boolean;
|
|
28
|
+
has(walletId: string): boolean;
|
|
29
|
+
}
|
package/dist/keystore.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local file-based key store for agent secret shares.
|
|
3
|
+
*
|
|
4
|
+
* Stores one JSON file per wallet in `storePath`.
|
|
5
|
+
* The agent's secret key share NEVER leaves this directory.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, unlinkSync } from "node:fs";
|
|
8
|
+
import { join, resolve } from "node:path";
|
|
9
|
+
import { homedir } from "node:os";
|
|
10
|
+
function defaultStorePath() {
|
|
11
|
+
return join(homedir(), ".kairo", "keys");
|
|
12
|
+
}
|
|
13
|
+
function sanitizeId(walletId) {
|
|
14
|
+
return walletId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
15
|
+
}
|
|
16
|
+
export class KeyStore {
|
|
17
|
+
dir;
|
|
18
|
+
constructor(storePath) {
|
|
19
|
+
this.dir = resolve(storePath ?? defaultStorePath());
|
|
20
|
+
if (!existsSync(this.dir)) {
|
|
21
|
+
mkdirSync(this.dir, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
filePath(walletId) {
|
|
25
|
+
return join(this.dir, `${sanitizeId(walletId)}.json`);
|
|
26
|
+
}
|
|
27
|
+
save(record) {
|
|
28
|
+
writeFileSync(this.filePath(record.walletId), JSON.stringify(record, null, 2), "utf-8");
|
|
29
|
+
}
|
|
30
|
+
load(walletId) {
|
|
31
|
+
const fp = this.filePath(walletId);
|
|
32
|
+
if (!existsSync(fp))
|
|
33
|
+
return null;
|
|
34
|
+
return JSON.parse(readFileSync(fp, "utf-8"));
|
|
35
|
+
}
|
|
36
|
+
list() {
|
|
37
|
+
const files = readdirSync(this.dir).filter((f) => f.endsWith(".json"));
|
|
38
|
+
return files.map((f) => {
|
|
39
|
+
const raw = readFileSync(join(this.dir, f), "utf-8");
|
|
40
|
+
return JSON.parse(raw);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
delete(walletId) {
|
|
44
|
+
const fp = this.filePath(walletId);
|
|
45
|
+
if (!existsSync(fp))
|
|
46
|
+
return false;
|
|
47
|
+
unlinkSync(fp);
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
has(walletId) {
|
|
51
|
+
return existsSync(this.filePath(walletId));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedded skill file templates shipped with the SDK.
|
|
3
|
+
* Generated by `kairo init` into .cursor/skills/kairo/.
|
|
4
|
+
* All backend URLs are intentionally omitted -- the SDK and CLI
|
|
5
|
+
* resolve the endpoint internally.
|
|
6
|
+
*/
|
|
7
|
+
export declare const SKILL_MD = "---\nname: kairo\ndescription: Manage Kairo policy-enforced agent wallets. Use when creating wallets, setting transaction policies, checking vault status, minting policy receipts, or signing transactions through the Kairo SDK/CLI. Supports full wallet lifecycle: register API key -> create wallet (DKG) -> create policy -> bind -> vault provision -> mint receipt -> sign. Uses @kairo/sdk for non-custodial wallet creation (agent keeps secret share locally).\n---\n\n# Kairo \u2014 Agent Wallet Management\n\n## Quick Reference\n\nCLI: `npx kairo <command>`\nSDK reference: `.cursor/skills/kairo/references/sdk.md`\nAPI reference: `.cursor/skills/kairo/references/api.md`\n\n## Setup\n\nRun the one-line installer (already done if you see this file):\n```bash\nnpx @kairo/sdk init <YOUR_API_KEY>\n```\n\nThe API key is stored in `~/.kairo/config.json`. All CLI commands read it automatically.\n\n## Common Workflows\n\n### Check API Health\n```bash\nnpx kairo health\n```\n\n### Create a Policy\n```bash\nnpx kairo policy-create --stable-id \"my-policy\" --allow \"0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18\"\n```\nThen register the version:\n```bash\nnpx kairo policy-register --policy-id \"0x...\"\n```\n\n### Create Wallet (via SDK)\nFor wallet creation, use the Node.js SDK (handles DKG client-side):\n```typescript\nimport { KairoClient } from \"@kairo/sdk\";\nconst kairo = new KairoClient({ apiKey: process.env.KAIRO_API_KEY! });\nconst wallet = await kairo.createWallet({ curve: \"secp256k1\" });\n```\nSee `.cursor/skills/kairo/references/sdk.md` for full SDK docs.\n\n### Provision Wallet into Vault\nRequires: policy version registered first.\n```bash\nnpx kairo vault-provision --wallet-id \"0x...\" --policy-id \"0x...\" --stable-id \"my-policy\"\n```\n\n### Mint Policy Receipt\n```bash\nnpx kairo receipt-mint --policy-id \"0x...\" --binding-id \"0x...\" --destination \"0x742d35Cc...\" --intent-hash \"0xabab...\"\n```\n\n### Check Vault Status\n```bash\nnpx kairo vault-status --wallet-id \"0x...\"\n```\n\n### View Audit Events\n```bash\nnpx kairo audit --limit 20\n```\n\n## Full Agent Flow (End to End)\n\n1. `npx @kairo/sdk init <key>` \u2014 store API key, install skill\n2. `npx kairo policy-create` \u2014 create transaction policy with allowed addresses\n3. `npx kairo policy-register` \u2014 register version in on-chain registry\n4. Create wallet via SDK `createWallet()` \u2014 runs DKG locally, secret share stays on agent\n5. `npx kairo vault-provision` \u2014 bind policy + register wallet in vault (atomic)\n6. `npx kairo receipt-mint` \u2014 request policy check for a transaction\n7. Sign via SDK \u2014 both shares combine, only if policy allows\n\n## Trust Model\n\n- Agent's key share stays local (`~/.kairo/keys/`)\n- Server's key share stays on Kairo backend\n- Neither party can sign alone\n- Policy engine gates every transaction before server releases its share\n- All policy decisions are on-chain (Sui) and verifiable\n\n## Troubleshooting\n\n- **401 Unauthorized**: API key missing/invalid or not registered in backend key store. Re-run `npx @kairo/sdk init <key>` with a valid key.\n- **403 Forbidden: key does not own wallet**: Wallet wasn't created/provisioned with this API key (ownership mismatch).\n- **429 Rate limit**: Public Sui RPC throttled \u2014 use Shinami or own RPC provider.\n- **MoveAbort code 102**: Policy version not registered \u2014 call `npx kairo policy-register` before `vault-provision`.\n- **`nonce too low` / `already known`**: Rapid reruns or duplicate raw tx; wait for pending tx, then re-sign and rebroadcast.\n- **AwaitingKeyHolderSignature**: Wallet needs activation after DKG \u2014 SDK activation flow required.\n";
|
|
8
|
+
export declare const API_REFERENCE_MD = "# Kairo API Reference\n\n## Authentication\nAll write endpoints require `X-Kairo-Api-Key` header.\nThe CLI reads the key from `~/.kairo/config.json` automatically.\nOpen endpoints: `/health`, `/api/vault/info`, `/api/vault/status/:id`, `/api/audit/events`\n\n## Key Registration\n```bash\nnpx kairo register --label \"my-agent\"\n```\n\n## Wallet Creation (via SDK)\nThe SDK handles DKG client-side. Agent keeps their secret share locally.\n```typescript\nimport { KairoClient } from \"@kairo/sdk\";\nconst kairo = new KairoClient({ apiKey: process.env.KAIRO_API_KEY! });\nconst wallet = await kairo.createWallet({ curve: \"secp256k1\" });\n// wallet.walletId, wallet.address\n```\n\n## Policy Management\n\n### Create Policy\n```bash\nnpx kairo policy-create --stable-id \"my-policy\" --version \"1.0.0\" --allow \"0x<address>\"\n```\n\nRule types:\n- `1` = MaxNativeValue (max single transaction value)\n- `10` = PeriodLimit (cumulative spend limit per time window)\n\n### Register Policy Version\n```bash\nnpx kairo policy-register --policy-id \"0x...\"\n```\n\n### Get Policy Details\n```bash\nnpx kairo policy-details --policy-id \"0x...\"\n```\n\n## Vault\n\n### Provision (atomic binding + vault registration)\n```bash\nnpx kairo vault-provision --wallet-id \"0x...\" --policy-id \"0x...\" --stable-id \"my-policy\"\n```\nNote: Register policy version BEFORE calling provision.\n\n### Check Status\n```bash\nnpx kairo vault-status --wallet-id \"0x...\"\n```\n\n## Receipt Minting\n```bash\nnpx kairo receipt-mint --policy-id \"0x...\" --binding-id \"0x...\" --destination \"0x...\" --intent-hash \"0x...\"\n```\nNamespace: 1=EVM, 2=Bitcoin, 3=Solana\n\n## Utility\n```bash\nnpx kairo health # Server health\nnpx kairo audit --limit 20 # Recent audit events\n```\n";
|
|
9
|
+
export declare const SDK_REFERENCE_MD = "# Kairo SDK Reference\n\n## Installation\n```bash\nnpm install @kairo/sdk\n```\n\nRequires: `@ika.xyz/sdk`, `@mysten/sui`\n\n## KairoClient\n\n```typescript\nimport { KairoClient } from \"@kairo/sdk\";\n\nconst kairo = new KairoClient({\n apiKey: process.env.KAIRO_API_KEY!,\n storePath: \"~/.kairo/keys\", // local secret share storage (default)\n network: \"testnet\", // or \"mainnet\"\n suiRpcUrl: \"https://...\", // optional, defaults to public testnet\n});\n```\n\n### createWallet(opts?)\nCreates a dWallet via client-side DKG. Secret share stays local.\n\n```typescript\nconst wallet = await kairo.createWallet({\n curve: \"secp256k1\", // or \"ed25519\" for Solana\n policyObjectId: \"0x...\", // optional: auto-provision into vault\n stableId: \"my-policy\", // optional: binding label\n});\n// Returns: { walletId, address, curve, bindingObjectId?, createdAt }\n```\n\n**Important:** If providing `policyObjectId`, register the policy version first.\n\n### listWallets()\nLists all wallets in local key store.\n```typescript\nconst wallets = kairo.listWallets();\n```\n\n### getWallet(walletId)\nGets a specific wallet from local store.\n```typescript\nconst w = kairo.getWallet(\"0x...\");\n```\n\n## BackendClient (HTTP wrapper)\nLower-level HTTP client for direct API calls.\n\n```typescript\nimport { BackendClient } from \"@kairo/sdk\";\n\nconst client = new BackendClient({ apiKey: \"your-key\" });\n\nawait client.register(\"my-agent\");\nawait client.getHealth();\nawait client.submitDKG({...});\nawait client.getDKGStatus(requestId);\nawait client.provision({...});\nawait client.mintReceipt({...});\n```\n\n## KeyStore (local storage)\nFile-based secret share storage at `~/.kairo/keys/`.\n\n```typescript\nimport { KeyStore } from \"@kairo/sdk\";\n\nconst store = new KeyStore(\"~/.kairo/keys\");\nstore.save(record);\nstore.load(\"0x...\");\nstore.list();\nstore.delete(\"0x...\");\n```\n\n## Trust Model\n- Agent's secret share -> stored locally (KeyStore), never sent to server\n- Server's share -> held by Kairo backend\n- Full signing -> requires BOTH shares + policy approval\n- Kairo alone cannot sign (missing agent share)\n- Agent alone cannot sign (missing server share)\n";
|