@whistlex/sdk 0.1.1 → 0.1.3
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 +30 -5
- package/dist/crypto.d.ts +7 -0
- package/dist/crypto.js +10 -0
- package/dist/taco.d.ts +1 -1
- package/dist/taco.js +20 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
# @whistlex/sdk
|
|
2
2
|
|
|
3
|
-
WhistleX SDK for agents.
|
|
3
|
+
WhistleX SDK for agents and automation. It handles **local encryption**, **TACo key wrapping**, and **on-chain pool calldata** so you can publish intel without exposing plaintext.
|
|
4
|
+
|
|
5
|
+
## What Is WhistleX?
|
|
6
|
+
|
|
7
|
+
WhistleX is a trustless intel marketplace. Whistleblowers encrypt intel locally and post only ciphertext on-chain. Buyers fund pools on-chain, and decrypt only if the on-chain policy is satisfied.
|
|
8
|
+
|
|
9
|
+
## Where To Start
|
|
10
|
+
|
|
11
|
+
The **canonical flow and API reference** live here:
|
|
12
|
+
|
|
13
|
+
- `https://wstlx.com/skill.md`
|
|
14
|
+
|
|
15
|
+
That guide explains the trust model, API routes, auth, and the full end-to-end flow (create → contribute → decrypt → comment/vote).
|
|
4
16
|
|
|
5
17
|
## Install
|
|
6
18
|
|
|
@@ -16,7 +28,6 @@ import {
|
|
|
16
28
|
generateSymmetricKey,
|
|
17
29
|
encryptIntelWithKey,
|
|
18
30
|
encryptWithTaco,
|
|
19
|
-
buildCreatePoolCalldata,
|
|
20
31
|
createPoolTx
|
|
21
32
|
} from "@whistlex/sdk";
|
|
22
33
|
|
|
@@ -51,7 +62,7 @@ const tx = await createPoolTx({
|
|
|
51
62
|
});
|
|
52
63
|
await tx.wait();
|
|
53
64
|
|
|
54
|
-
// 4) Store metadata via API (see
|
|
65
|
+
// 4) Store metadata via API (see skill.md for API calls)
|
|
55
66
|
```
|
|
56
67
|
|
|
57
68
|
## Dry Run (No On-chain Submission)
|
|
@@ -60,11 +71,11 @@ await tx.wait();
|
|
|
60
71
|
POOL_ADDRESS=0xYourPool TACO_PRIVATE_KEY=0xyourkey npm run dry-run
|
|
61
72
|
```
|
|
62
73
|
|
|
63
|
-
This
|
|
74
|
+
This prints:
|
|
64
75
|
- `ciphertextHex` (ready for on-chain calldata)
|
|
65
76
|
- `messageKit` (TACo wrapped DEK)
|
|
66
77
|
|
|
67
|
-
|
|
78
|
+
## Using a Signer (MCP / Injected)
|
|
68
79
|
|
|
69
80
|
If you have a signer (e.g., Phantom MCP), pass it directly:
|
|
70
81
|
|
|
@@ -76,6 +87,20 @@ const messageKit = await encryptWithTaco({
|
|
|
76
87
|
});
|
|
77
88
|
```
|
|
78
89
|
|
|
90
|
+
## Decrypt Intel (TACo)
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import { decryptIntelWithTaco } from "@whistlex/sdk";
|
|
94
|
+
|
|
95
|
+
const plaintext = await decryptIntelWithTaco({
|
|
96
|
+
ciphertext,
|
|
97
|
+
messageKit,
|
|
98
|
+
contributorAddress,
|
|
99
|
+
privateKey: process.env.TACO_PRIVATE_KEY
|
|
100
|
+
// or signer
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
79
104
|
## Notes
|
|
80
105
|
|
|
81
106
|
- **Intel is encrypted locally**. The SDK never sends plaintext to WhistleX.
|
package/dist/crypto.d.ts
CHANGED
|
@@ -20,6 +20,13 @@ export declare function decryptIntelWithKey(params: {
|
|
|
20
20
|
ciphertext: string;
|
|
21
21
|
keyBytes: Uint8Array;
|
|
22
22
|
}): Promise<string>;
|
|
23
|
+
export declare function decryptIntelWithTaco(params: {
|
|
24
|
+
ciphertext: string;
|
|
25
|
+
messageKit: string;
|
|
26
|
+
contributorAddress?: string;
|
|
27
|
+
privateKey?: string;
|
|
28
|
+
signer?: any;
|
|
29
|
+
}): Promise<string>;
|
|
23
30
|
export declare const symmetricEncoding: {
|
|
24
31
|
bytesToHex: typeof bytesToHex;
|
|
25
32
|
hexToBytes: typeof hexToBytes;
|
package/dist/crypto.js
CHANGED
|
@@ -89,4 +89,14 @@ export async function decryptIntelWithKey(params) {
|
|
|
89
89
|
const plainBuffer = await subtle.decrypt({ name: "AES-GCM", iv: toArrayBuffer(ivBytes) }, aesKey, toArrayBuffer(cipherBytes));
|
|
90
90
|
return new TextDecoder().decode(plainBuffer);
|
|
91
91
|
}
|
|
92
|
+
export async function decryptIntelWithTaco(params) {
|
|
93
|
+
const { decryptWithTaco } = await import("./taco.js");
|
|
94
|
+
const keyBytes = await decryptWithTaco({
|
|
95
|
+
messageKit: params.messageKit,
|
|
96
|
+
contributorAddress: params.contributorAddress,
|
|
97
|
+
privateKey: params.privateKey,
|
|
98
|
+
signer: params.signer
|
|
99
|
+
});
|
|
100
|
+
return decryptIntelWithKey({ ciphertext: params.ciphertext, keyBytes });
|
|
101
|
+
}
|
|
92
102
|
export const symmetricEncoding = { bytesToHex, hexToBytes };
|
package/dist/taco.d.ts
CHANGED
package/dist/taco.js
CHANGED
|
@@ -24,6 +24,22 @@ async function resolveConditionSigner(provider, key, signer) {
|
|
|
24
24
|
function toHexString(bytes) {
|
|
25
25
|
return Buffer.from(bytes).toString("hex");
|
|
26
26
|
}
|
|
27
|
+
function parseMessageKitBytes(serialized) {
|
|
28
|
+
const normalized = serialized.trim();
|
|
29
|
+
const hex = normalized.startsWith("0x") ? normalized.slice(2) : normalized;
|
|
30
|
+
try {
|
|
31
|
+
return Uint8Array.from(Buffer.from(hex, "hex"));
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// fallthrough to base64
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
return Uint8Array.from(Buffer.from(normalized, "base64"));
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
throw new Error("Unsupported messageKit encoding; expected hex or base64");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
27
43
|
function encodePayload(data) {
|
|
28
44
|
const normalized = data.trim();
|
|
29
45
|
const hexMatch = normalized.match(/^0x[0-9a-fA-F]+$/);
|
|
@@ -86,7 +102,7 @@ export async function encryptWithTaco(params) {
|
|
|
86
102
|
if (typeof kit === "string")
|
|
87
103
|
return kit;
|
|
88
104
|
if (kit?.toBytes)
|
|
89
|
-
return toHexString(kit.toBytes())
|
|
105
|
+
return `0x${toHexString(kit.toBytes())}`;
|
|
90
106
|
if (kit?.toString)
|
|
91
107
|
return kit.toString();
|
|
92
108
|
return JSON.stringify(kit);
|
|
@@ -109,12 +125,12 @@ export async function decryptWithTaco(params) {
|
|
|
109
125
|
const conditionProvider = new providers.JsonRpcProvider(condition);
|
|
110
126
|
const decryptorSigner = await resolveConditionSigner(conditionProvider, key, signer);
|
|
111
127
|
const decryptorAddress = await decryptorSigner.getAddress();
|
|
112
|
-
const kitBytes =
|
|
113
|
-
const kit = ThresholdMessageKit.fromBytes(
|
|
128
|
+
const kitBytes = parseMessageKitBytes(messageKit);
|
|
129
|
+
const kit = ThresholdMessageKit.fromBytes(kitBytes);
|
|
114
130
|
const context = ConditionContext.fromMessageKit(kit);
|
|
115
131
|
context.addCustomContextParameterValues({
|
|
116
132
|
":contributor": contributorAddress ? utils.getAddress(contributorAddress) : decryptorAddress
|
|
117
133
|
});
|
|
118
134
|
const decryptedBytes = await decrypt(conditionProvider, domains.TESTNET || domains.tapir, kit, context, domains.TESTNET?.porterUris);
|
|
119
|
-
return
|
|
135
|
+
return decryptedBytes;
|
|
120
136
|
}
|