@kairoguard/sdk 0.0.14 → 0.0.16
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/backend.d.ts +11 -1
- package/dist/client.d.ts +5 -0
- package/dist/client.js +25 -26
- package/dist/denialReasons.d.ts +5 -0
- package/dist/denialReasons.js +28 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/package.json +1 -1
- package/dist/price.d.ts +0 -2
- package/dist/price.js +0 -65
package/dist/backend.d.ts
CHANGED
|
@@ -56,6 +56,16 @@ export interface ProvisionResponse {
|
|
|
56
56
|
dwalletObjectId: string;
|
|
57
57
|
walletState: string;
|
|
58
58
|
}
|
|
59
|
+
export interface MintReceiptResponse {
|
|
60
|
+
success: boolean;
|
|
61
|
+
receiptId?: string;
|
|
62
|
+
receiptObjectId?: string;
|
|
63
|
+
allowed?: boolean;
|
|
64
|
+
denialReason?: number;
|
|
65
|
+
denialReasonName?: string;
|
|
66
|
+
digest?: string;
|
|
67
|
+
error?: string;
|
|
68
|
+
}
|
|
59
69
|
export interface RegisterKeyRequest {
|
|
60
70
|
label: string;
|
|
61
71
|
email?: string;
|
|
@@ -307,7 +317,7 @@ export declare class BackendClient {
|
|
|
307
317
|
submitDKG(data: DKGSubmitRequest): Promise<DKGSubmitResponse>;
|
|
308
318
|
getDKGStatus(requestId: string): Promise<DKGStatusResponse>;
|
|
309
319
|
provision(params: ProvisionRequest): Promise<ProvisionResponse>;
|
|
310
|
-
mintReceipt(params: Record<string, unknown>): Promise<
|
|
320
|
+
mintReceipt(params: Record<string, unknown>): Promise<MintReceiptResponse>;
|
|
311
321
|
requestPresign(params: PresignRequestParams): Promise<PresignRequestResponse>;
|
|
312
322
|
getPresignStatus(requestId: string): Promise<PresignStatusResponse>;
|
|
313
323
|
requestSign(params: SignRequestParams): Promise<SignRequestResponse>;
|
package/dist/client.d.ts
CHANGED
|
@@ -50,6 +50,11 @@ export interface SignResult {
|
|
|
50
50
|
presignId: string;
|
|
51
51
|
signatureHex: Hex;
|
|
52
52
|
}
|
|
53
|
+
export declare class PolicyDeniedError extends Error {
|
|
54
|
+
readonly denialReason: number;
|
|
55
|
+
readonly denialReasonName: string;
|
|
56
|
+
constructor(denialReason: number, denialReasonName?: string);
|
|
57
|
+
}
|
|
53
58
|
export interface SignEvmParams {
|
|
54
59
|
walletId: string;
|
|
55
60
|
to: Hex;
|
package/dist/client.js
CHANGED
|
@@ -9,12 +9,23 @@
|
|
|
9
9
|
* // { walletId: "0xabc...", address: "0x742d...", curve: "secp256k1" }
|
|
10
10
|
*/
|
|
11
11
|
import { BackendClient, } from "./backend.js";
|
|
12
|
+
import { getDenialReasonName } from "./denialReasons.js";
|
|
12
13
|
import { KeyStore } from "./keystore.js";
|
|
13
14
|
import { Curve, fetchProtocolParams, deriveEncryptionKeys, generateSeed, generateSessionIdentifier, runDKG, computeUserOutputSignature, fetchDWallet, waitForDWalletState, } from "./ika-protocol.js";
|
|
14
15
|
import { Hash, SignatureAlgorithm, createUserSignMessageWithPublicOutput } from "@ika.xyz/sdk";
|
|
15
16
|
import { computeEvmIntentFromUnsignedTxBytes } from "./evmIntent.js";
|
|
16
17
|
import { keccak256, recoverTransactionAddress, serializeTransaction, } from "viem";
|
|
17
|
-
|
|
18
|
+
export class PolicyDeniedError extends Error {
|
|
19
|
+
denialReason;
|
|
20
|
+
denialReasonName;
|
|
21
|
+
constructor(denialReason, denialReasonName) {
|
|
22
|
+
const resolvedName = denialReasonName?.trim() || getDenialReasonName(denialReason);
|
|
23
|
+
super(`Policy denied: ${resolvedName}`);
|
|
24
|
+
this.name = "PolicyDeniedError";
|
|
25
|
+
this.denialReason = denialReason;
|
|
26
|
+
this.denialReasonName = resolvedName;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
18
29
|
const FALLBACK_SUI_RPC = "https://fullnode.testnet.sui.io:443";
|
|
19
30
|
async function testRpcEndpoint(url) {
|
|
20
31
|
try {
|
|
@@ -753,30 +764,17 @@ export class KairoClient {
|
|
|
753
764
|
if (!wallet.policyObjectId || !wallet.bindingObjectId) {
|
|
754
765
|
throw new Error("Wallet is missing policy binding metadata. Provision the wallet via dashboard or SDK before signing.");
|
|
755
766
|
}
|
|
756
|
-
const mintOnce = async () => {
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
}
|
|
768
|
-
return this.backend.mintReceipt({
|
|
769
|
-
policyObjectId: wallet.policyObjectId ?? undefined,
|
|
770
|
-
bindingObjectId: wallet.bindingObjectId,
|
|
771
|
-
namespace: ctx.namespace,
|
|
772
|
-
// chainId is encoded as u64 bytes (16 hex chars)
|
|
773
|
-
chainId: ctx.chainId.toString(16).padStart(16, "0"),
|
|
774
|
-
intentHashHex: stripHexPrefix(ctx.intentHashHex),
|
|
775
|
-
destinationHex: stripHexPrefix(ctx.destinationHex),
|
|
776
|
-
nativeValueHex: normalizedNativeValue.toString(16).padStart(64, "0"),
|
|
777
|
-
contextDataHex: ctx.contextDataHex ? stripHexPrefix(ctx.contextDataHex) : undefined,
|
|
778
|
-
});
|
|
779
|
-
};
|
|
767
|
+
const mintOnce = async () => this.backend.mintReceipt({
|
|
768
|
+
policyObjectId: wallet.policyObjectId ?? undefined,
|
|
769
|
+
bindingObjectId: wallet.bindingObjectId,
|
|
770
|
+
namespace: ctx.namespace,
|
|
771
|
+
// chainId is encoded as u64 bytes (16 hex chars)
|
|
772
|
+
chainId: ctx.chainId.toString(16).padStart(16, "0"),
|
|
773
|
+
intentHashHex: stripHexPrefix(ctx.intentHashHex),
|
|
774
|
+
destinationHex: stripHexPrefix(ctx.destinationHex),
|
|
775
|
+
nativeValueHex: ctx.nativeValue.toString(16).padStart(64, "0"),
|
|
776
|
+
contextDataHex: ctx.contextDataHex ? stripHexPrefix(ctx.contextDataHex) : undefined,
|
|
777
|
+
});
|
|
780
778
|
let response = await mintOnce();
|
|
781
779
|
const initialError = String(response?.error ?? "");
|
|
782
780
|
if (response.success === false && this.isReaffirmRequiredError(initialError)) {
|
|
@@ -787,7 +785,8 @@ export class KairoClient {
|
|
|
787
785
|
throw new Error(String(response.error ?? "Failed to mint policy receipt"));
|
|
788
786
|
}
|
|
789
787
|
if (response.allowed === false) {
|
|
790
|
-
|
|
788
|
+
const denialReason = Number(response.denialReason ?? 0);
|
|
789
|
+
throw new PolicyDeniedError(denialReason, response.denialReasonName);
|
|
791
790
|
}
|
|
792
791
|
const receiptId = String(response.receiptId ?? response.receiptObjectId ?? "");
|
|
793
792
|
if (!receiptId.startsWith("0x")) {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const DENIAL_REASONS = {
|
|
2
|
+
0: { code: "NONE", message: "No denial (allowed)" },
|
|
3
|
+
1: { code: "EXPIRED", message: "Policy has expired" },
|
|
4
|
+
2: { code: "DENYLIST", message: "Destination address is on the denylist" },
|
|
5
|
+
3: { code: "NOT_IN_ALLOWLIST", message: "Destination address is not in the allowlist" },
|
|
6
|
+
4: { code: "BAD_FORMAT", message: "Invalid intent format" },
|
|
7
|
+
10: { code: "CHAIN_NOT_ALLOWED", message: "This chain/network is not allowed by policy" },
|
|
8
|
+
11: { code: "BAD_SELECTOR_FORMAT", message: "Invalid EVM function selector format" },
|
|
9
|
+
12: { code: "SELECTOR_DENYLIST", message: "This contract function is on the denylist" },
|
|
10
|
+
13: { code: "SELECTOR_NOT_ALLOWED", message: "This contract function is not in the allowlist" },
|
|
11
|
+
14: { code: "BAD_AMOUNT_FORMAT", message: "Invalid ERC20 amount format" },
|
|
12
|
+
15: { code: "ERC20_AMOUNT_EXCEEDS_MAX", message: "ERC20 transfer amount exceeds policy limit" },
|
|
13
|
+
16: { code: "NO_POLICY_VERSION", message: "No active policy version found" },
|
|
14
|
+
20: { code: "NAMESPACE_NOT_ALLOWED", message: "This blockchain type (EVM/Bitcoin/Solana) is not allowed" },
|
|
15
|
+
21: { code: "BTC_SCRIPT_TYPE_NOT_ALLOWED", message: "Bitcoin address type not allowed by policy" },
|
|
16
|
+
22: { code: "BTC_FEE_RATE_EXCEEDED", message: "Bitcoin fee rate exceeds policy limit" },
|
|
17
|
+
23: { code: "SOL_PROGRAM_DENYLISTED", message: "Solana program is on the denylist" },
|
|
18
|
+
24: { code: "SOL_PROGRAM_NOT_ALLOWED", message: "Solana program is not in the allowlist" },
|
|
19
|
+
30: { code: "NATIVE_VALUE_EXCEEDED", message: "Native value exceeds policy limit" },
|
|
20
|
+
31: { code: "TIME_WINDOW_BLOCKED", message: "Transaction blocked by time window rule" },
|
|
21
|
+
32: { code: "PERIOD_LIMIT_EXCEEDED", message: "Period spending limit exceeded" },
|
|
22
|
+
33: { code: "RATE_LIMIT_EXCEEDED", message: "Rate limit exceeded" },
|
|
23
|
+
};
|
|
24
|
+
export function getDenialReasonName(code) {
|
|
25
|
+
if (code === undefined || code === null)
|
|
26
|
+
return "Unknown denial reason";
|
|
27
|
+
return DENIAL_REASONS[code]?.message ?? `Unknown denial reason (${code})`;
|
|
28
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export * from "./suiResult.js";
|
|
|
8
8
|
export * from "./suiTxBuilders.js";
|
|
9
9
|
export * from "./auditBundle.js";
|
|
10
10
|
export * from "./suiCustody.js";
|
|
11
|
-
export
|
|
11
|
+
export * from "./denialReasons.js";
|
|
12
|
+
export { KairoClient, PolicyDeniedError, type KairoClientOpts, type CreateWalletOpts, type WalletInfo, type ProposePolicyUpdateParams, type PolicyUpdateProposalResult, type ApprovePolicyUpdateParams, type ExecutePolicyUpdateParams, type PolicyUpdateStatus, } from "./client.js";
|
|
12
13
|
export { KeyStore, type WalletRecord } from "./keystore.js";
|
|
13
14
|
export { BackendClient, DEFAULT_BACKEND_URL, type BackendClientOpts } from "./backend.js";
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ export * from "./suiResult.js";
|
|
|
8
8
|
export * from "./suiTxBuilders.js";
|
|
9
9
|
export * from "./auditBundle.js";
|
|
10
10
|
export * from "./suiCustody.js";
|
|
11
|
-
export
|
|
11
|
+
export * from "./denialReasons.js";
|
|
12
|
+
export { KairoClient, PolicyDeniedError, } from "./client.js";
|
|
12
13
|
export { KeyStore } from "./keystore.js";
|
|
13
14
|
export { BackendClient, DEFAULT_BACKEND_URL } from "./backend.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kairoguard/sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"description": "Kairo SDK for multi-chain policy-based transaction signing with dWallet support (EVM, Bitcoin, Solana, Sui)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Kairo <mehraab@thewidercollective.com>",
|
package/dist/price.d.ts
DELETED
package/dist/price.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
const WEI_PER_ETH = 1000000000000000000n;
|
|
2
|
-
const USD_MICROS_SCALE = 1000000n;
|
|
3
|
-
const CACHE_MS = 60_000;
|
|
4
|
-
let cachedEthUsdMicros = null;
|
|
5
|
-
function parseUsdToMicros(input) {
|
|
6
|
-
const s = input.trim();
|
|
7
|
-
if (!s)
|
|
8
|
-
throw new Error("ETH/USD response is empty");
|
|
9
|
-
if (!/^\d+(\.\d+)?$/.test(s)) {
|
|
10
|
-
throw new Error(`Invalid ETH/USD amount: ${s}`);
|
|
11
|
-
}
|
|
12
|
-
const [wholeRaw, fracRaw = ""] = s.split(".");
|
|
13
|
-
const whole = BigInt(wholeRaw);
|
|
14
|
-
const frac = BigInt((fracRaw + "000000").slice(0, 6));
|
|
15
|
-
return whole * USD_MICROS_SCALE + frac;
|
|
16
|
-
}
|
|
17
|
-
async function fetchJsonWithTimeout(url, timeoutMs) {
|
|
18
|
-
const ctrl = new AbortController();
|
|
19
|
-
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
20
|
-
try {
|
|
21
|
-
const resp = await fetch(url, { signal: ctrl.signal });
|
|
22
|
-
if (!resp.ok) {
|
|
23
|
-
throw new Error(`HTTP ${resp.status} from ${url}`);
|
|
24
|
-
}
|
|
25
|
-
return await resp.json();
|
|
26
|
-
}
|
|
27
|
-
finally {
|
|
28
|
-
clearTimeout(timer);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
export async function fetchEthUsdMicros() {
|
|
32
|
-
const now = Date.now();
|
|
33
|
-
if (cachedEthUsdMicros && now - cachedEthUsdMicros.atMs < CACHE_MS) {
|
|
34
|
-
return cachedEthUsdMicros.value;
|
|
35
|
-
}
|
|
36
|
-
const providers = [
|
|
37
|
-
async () => {
|
|
38
|
-
const j = await fetchJsonWithTimeout("https://api.coinbase.com/v2/prices/ETH-USD/spot", 7000);
|
|
39
|
-
const amount = String(j?.data?.amount ?? "").trim();
|
|
40
|
-
return parseUsdToMicros(amount);
|
|
41
|
-
},
|
|
42
|
-
async () => {
|
|
43
|
-
const j = await fetchJsonWithTimeout("https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd", 7000);
|
|
44
|
-
const amount = String(j?.ethereum?.usd ?? "").trim();
|
|
45
|
-
return parseUsdToMicros(amount);
|
|
46
|
-
},
|
|
47
|
-
];
|
|
48
|
-
let lastErr = null;
|
|
49
|
-
for (const getPrice of providers) {
|
|
50
|
-
try {
|
|
51
|
-
const value = await getPrice();
|
|
52
|
-
if (value > 0n) {
|
|
53
|
-
cachedEthUsdMicros = { value, atMs: now };
|
|
54
|
-
return value;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
catch (error) {
|
|
58
|
-
lastErr = error;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
throw new Error(`Could not fetch ETH/USD price${lastErr ? `: ${lastErr instanceof Error ? lastErr.message : String(lastErr)}` : ""}`);
|
|
62
|
-
}
|
|
63
|
-
export function convertWeiToUsdMicros(weiValue, ethUsdMicros) {
|
|
64
|
-
return (weiValue * ethUsdMicros) / WEI_PER_ETH;
|
|
65
|
-
}
|