@helm-protocol/ttt-mcp 0.2.1 → 0.2.2
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 +110 -1
- package/dist/auth.js +49 -11
- package/dist/index.js +61 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -144,6 +144,110 @@ Config file locations:
|
|
|
144
144
|
- Node.js >= 18
|
|
145
145
|
- Network access for time synthesis (HTTPS to time.nist.gov, time.google.com, time.cloudflare.com)
|
|
146
146
|
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Use Cases
|
|
150
|
+
|
|
151
|
+
### 1. MEV Bot — Transaction Ordering Proof
|
|
152
|
+
|
|
153
|
+
**Problem**: You got front-run. You know it happened. You can't prove it — mempool timestamps are per-node, unsigned, and non-authoritative. No evidence, no recourse.
|
|
154
|
+
|
|
155
|
+
**Solution**: Call `pot_generate` before submitting every transaction. The PoT receipt is cryptographically signed by three independent time sources (NIST, Google, Cloudflare), hashed on-chain to Base Sepolia TTT ERC-1155. If front-running occurs, you have a timestamped, on-chain-anchored record of your original submission that predates the attacker's block inclusion.
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
// Before tx submission
|
|
159
|
+
const pot = await client.callTool({ name: "pot_generate", arguments: { txHash: pendingTxHash, chainId: 8453 } });
|
|
160
|
+
// Store pot.potHash alongside your trade log
|
|
161
|
+
// If front-run: pot.potHash is your evidence, timestamped by NIST+Google+Cloudflare
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**V2 path**: When builder staking goes live, `S(V) ≥ V − c₀` makes reordering economically irrational for any V. Not just evidence — prevention.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
### 2. DEX Protocol — AdaptiveSwitch Sandwich Deterrence
|
|
169
|
+
|
|
170
|
+
**Problem**: Small-to-mid value sandwich attacks (V < ~$87) are constant background noise on any AMM. Each one is individually too small to litigate, collectively significant. No governance mechanism moves fast enough to respond.
|
|
171
|
+
|
|
172
|
+
**Solution**: Integrate `TTTHookSimple` (Uniswap V4 hook, Base Sepolia: `0x8C633b05b833a476925F7d9818da6E215760F2c7`). Honest builders who preserve PoT-verified ordering get `turbo` mode (~50ms path). Builders who tamper are flagged to `full` mode (~127ms + exponential backoff up to 320 blocks). The 77ms throughput differential makes reordering cost exceed opportunity value for the V* range. No vote. No committee. Economics.
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
// Query current switch state for a pool
|
|
176
|
+
const status = await client.callTool({ name: "pot_stats", arguments: { poolAddress: "0x..." } });
|
|
177
|
+
// status.adaptiveMode: "turbo" | "full"
|
|
178
|
+
// status.currentV_star: estimated MEV threshold being deterred
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Outcome**: ~80% reduction in sub-threshold sandwich attacks. Provable per-block audit trail.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
### 3. Hedge Fund / Prop Desk — MiFIR Art.22c Compliance
|
|
186
|
+
|
|
187
|
+
**Problem**: MiFIR Article 22c / RTS 25 requires microsecond-precision UTC-synchronized timestamps for every trade on regulated venues. The standard hardware solution (PTP/IEEE 1588 appliances) costs $50K–$500K and requires dedicated ops. Most DeFi-adjacent funds run manual reconciliation between two separate timestamp systems.
|
|
188
|
+
|
|
189
|
+
**Solution**: `pot_generate` produces an Ed25519-signed timestamp with uncertainty bound, confidence score, and multi-source attestation. The output is structurally compatible with RTS 25 audit record requirements. No hardware appliance. No dedicated ops. One API call per trade.
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
const audit = await client.callTool({
|
|
193
|
+
name: "pot_generate",
|
|
194
|
+
arguments: { txHash: tradeHash, chainId: 8453, metadata: { desk: "MACRO-1", trader: "algo-07" } }
|
|
195
|
+
});
|
|
196
|
+
// audit.timestamp: nanosecond precision
|
|
197
|
+
// audit.uncertainty: +/- ms bound (required field in RTS 25 record)
|
|
198
|
+
// audit.confidence: fraction of sources that agreed
|
|
199
|
+
// audit.ed25519_sig: non-repudiation signature
|
|
200
|
+
// Export to your compliance system — same format, every trade
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Outcome**: MiFIR-grade audit trail at ~$0.04/1K calls (DEX tier). Replaces $50K+ hardware setup. IETF standardized via `draft-helmprotocol-tttps-00`.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
### 4. Liquidity Provider — Position Timeline for Dispute Resolution
|
|
208
|
+
|
|
209
|
+
**Problem**: LP enters and exits positions based on market conditions. When impermanent loss occurs due to a suspected protocol exploit or ordering manipulation, proving the sequence of events (position entry → exploit event → position exit) requires timestamped evidence that the current stack doesn't provide.
|
|
210
|
+
|
|
211
|
+
**Solution**: Stamp every LP action (add liquidity, remove liquidity, fee harvest) with a PoT receipt. The receipt chain creates an unforgeable causal timeline: each action's potHash references the previous, anchored on Base Sepolia. Legally defensible for tax documentation, insurance claims, and protocol dispute resolution.
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
// On liquidity add
|
|
215
|
+
const entryPot = await client.callTool({ name: "pot_generate", arguments: { txHash: addLiqTx, chainId: 8453 } });
|
|
216
|
+
|
|
217
|
+
// On liquidity remove
|
|
218
|
+
const exitPot = await client.callTool({ name: "pot_generate", arguments: { txHash: removeLiqTx, chainId: 8453 } });
|
|
219
|
+
|
|
220
|
+
// Verify the causal chain
|
|
221
|
+
const chain = await client.callTool({ name: "pot_verify", arguments: { potHash: exitPot.potHash, precedingHash: entryPot.potHash } });
|
|
222
|
+
// chain.valid: true means exit cryptographically followed entry
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
### 5. AI Agent Coordination — Multi-Agent Causal Ordering
|
|
228
|
+
|
|
229
|
+
**Problem**: When multiple AI agents interact in a pipeline (Agent A signals → Agent B acts → Agent C settles), the causal order matters for debugging, auditing, and liability. Agent logs are unverifiable—any agent can claim any timestamp.
|
|
230
|
+
|
|
231
|
+
**Solution**: Each agent calls `pot_generate` before acting. The resulting potHash chain is independently verifiable: "Agent A's signal at T₁ preceded Agent B's action at T₂" can be proven without trusting either agent's self-reported logs. The on-chain anchor makes the ordering dispute-proof.
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
// Agent A (signal generator)
|
|
235
|
+
const signalPot = await client.callTool({ name: "pot_generate", arguments: { txHash: signalId } });
|
|
236
|
+
|
|
237
|
+
// Agent B (executor) — references Agent A's pot
|
|
238
|
+
const execPot = await client.callTool({
|
|
239
|
+
name: "pot_generate",
|
|
240
|
+
arguments: { txHash: execId, precedingPotHash: signalPot.potHash }
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// Any third party can verify the causal chain
|
|
244
|
+
const verified = await client.callTool({ name: "pot_verify", arguments: { potHash: execPot.potHash, precedingHash: signalPot.potHash } });
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**Outcome**: Unforgeable causal chain across autonomous agents. Useful for multi-agent DeFi strategies, audit compliance, and cross-agent dispute resolution.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
147
251
|
## TypeScript: MEV Bot Integration
|
|
148
252
|
|
|
149
253
|
```typescript
|
|
@@ -193,4 +297,9 @@ Commercial: peter@kenosian.com (hedge funds, DEX protocols, OTC desks)
|
|
|
193
297
|
|
|
194
298
|
## License
|
|
195
299
|
|
|
196
|
-
BSL-1.1
|
|
300
|
+
BSL-1.1 — free for non-commercial use.
|
|
301
|
+
|
|
302
|
+
**Commercial use** (production bots, hedge funds, prop desks) requires a license.
|
|
303
|
+
→ [kenosian.com/pricing](https://kenosian.com/pricing)
|
|
304
|
+
|
|
305
|
+
Change Date: 2029-05-28 → Apache 2.0
|
package/dist/auth.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,14 +17,28 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
var auth_exports = {};
|
|
20
30
|
__export(auth_exports, {
|
|
31
|
+
FREE_TIER_LIMIT: () => FREE_TIER_LIMIT,
|
|
21
32
|
checkRateLimit: () => checkRateLimit,
|
|
22
33
|
resolveApiKey: () => resolveApiKey
|
|
23
34
|
});
|
|
24
35
|
module.exports = __toCommonJS(auth_exports);
|
|
36
|
+
var fs = __toESM(require("fs"));
|
|
37
|
+
var path = __toESM(require("path"));
|
|
38
|
+
var os = __toESM(require("os"));
|
|
25
39
|
const FREE_TIER_LIMIT = parseInt(process.env.FREE_TIER_LIMIT ?? "100", 10);
|
|
40
|
+
const USAGE_DIR = path.join(os.homedir(), ".ttt-mcp");
|
|
41
|
+
const USAGE_FILE = path.join(USAGE_DIR, "usage.json");
|
|
26
42
|
const buckets = /* @__PURE__ */ new Map();
|
|
27
43
|
function nextMidnightUtc() {
|
|
28
44
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -31,36 +47,58 @@ function nextMidnightUtc() {
|
|
|
31
47
|
);
|
|
32
48
|
return midnight.getTime();
|
|
33
49
|
}
|
|
50
|
+
function readUsageFile() {
|
|
51
|
+
try {
|
|
52
|
+
if (!fs.existsSync(USAGE_DIR)) fs.mkdirSync(USAGE_DIR, { recursive: true });
|
|
53
|
+
if (fs.existsSync(USAGE_FILE)) {
|
|
54
|
+
return JSON.parse(fs.readFileSync(USAGE_FILE, "utf8"));
|
|
55
|
+
}
|
|
56
|
+
} catch {
|
|
57
|
+
}
|
|
58
|
+
return { count: 0, resetAt: nextMidnightUtc() };
|
|
59
|
+
}
|
|
60
|
+
function writeUsageFile(entry) {
|
|
61
|
+
try {
|
|
62
|
+
if (!fs.existsSync(USAGE_DIR)) fs.mkdirSync(USAGE_DIR, { recursive: true });
|
|
63
|
+
fs.writeFileSync(USAGE_FILE, JSON.stringify(entry), "utf8");
|
|
64
|
+
} catch {
|
|
65
|
+
}
|
|
66
|
+
}
|
|
34
67
|
function checkRateLimit(apiKey, clientIp) {
|
|
35
68
|
if (apiKey && apiKey.trim().length > 0) {
|
|
36
69
|
return { allowed: true, remaining: -1, tier: "paid" };
|
|
37
70
|
}
|
|
38
|
-
const bucketKey = `ip:${clientIp}`;
|
|
39
71
|
const now = Date.now();
|
|
72
|
+
if (clientIp === "stdio") {
|
|
73
|
+
let entry2 = readUsageFile();
|
|
74
|
+
if (now >= entry2.resetAt) {
|
|
75
|
+
entry2 = { count: 0, resetAt: nextMidnightUtc() };
|
|
76
|
+
}
|
|
77
|
+
if (entry2.count >= FREE_TIER_LIMIT) {
|
|
78
|
+
return { allowed: false, remaining: 0, tier: "free" };
|
|
79
|
+
}
|
|
80
|
+
entry2.count += 1;
|
|
81
|
+
writeUsageFile(entry2);
|
|
82
|
+
return { allowed: true, remaining: FREE_TIER_LIMIT - entry2.count, tier: "free" };
|
|
83
|
+
}
|
|
84
|
+
const bucketKey = `ip:${clientIp}`;
|
|
40
85
|
let entry = buckets.get(bucketKey);
|
|
41
86
|
if (!entry || now >= entry.resetAt) {
|
|
42
87
|
entry = { count: 0, resetAt: nextMidnightUtc() };
|
|
43
88
|
buckets.set(bucketKey, entry);
|
|
44
89
|
}
|
|
45
90
|
if (entry.count >= FREE_TIER_LIMIT) {
|
|
46
|
-
return {
|
|
47
|
-
allowed: false,
|
|
48
|
-
remaining: 0,
|
|
49
|
-
tier: "free"
|
|
50
|
-
};
|
|
91
|
+
return { allowed: false, remaining: 0, tier: "free" };
|
|
51
92
|
}
|
|
52
93
|
entry.count += 1;
|
|
53
|
-
return {
|
|
54
|
-
allowed: true,
|
|
55
|
-
remaining: FREE_TIER_LIMIT - entry.count,
|
|
56
|
-
tier: "free"
|
|
57
|
-
};
|
|
94
|
+
return { allowed: true, remaining: FREE_TIER_LIMIT - entry.count, tier: "free" };
|
|
58
95
|
}
|
|
59
96
|
function resolveApiKey(headerValue) {
|
|
60
97
|
return headerValue?.trim() || process.env.TTT_API_KEY?.trim() || void 0;
|
|
61
98
|
}
|
|
62
99
|
// Annotate the CommonJS export names for ESM import in node:
|
|
63
100
|
0 && (module.exports = {
|
|
101
|
+
FREE_TIER_LIMIT,
|
|
64
102
|
checkRateLimit,
|
|
65
103
|
resolveApiKey
|
|
66
104
|
});
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ var import_http = require("http");
|
|
|
7
7
|
var import_zod = require("zod");
|
|
8
8
|
var import_tools = require("./tools");
|
|
9
9
|
var import_auth = require("./auth");
|
|
10
|
+
const IS_STDIO = !process.env.PORT;
|
|
10
11
|
const server = new import_mcp.McpServer({
|
|
11
12
|
name: "ttt-mcp",
|
|
12
13
|
version: "0.1.0"
|
|
@@ -20,6 +21,21 @@ server.tool(
|
|
|
20
21
|
poolAddress: import_zod.z.string().describe("DEX pool contract address")
|
|
21
22
|
},
|
|
22
23
|
async (args) => {
|
|
24
|
+
if (IS_STDIO) {
|
|
25
|
+
const apiKey = (0, import_auth.resolveApiKey)();
|
|
26
|
+
const rl = (0, import_auth.checkRateLimit)(apiKey, "stdio");
|
|
27
|
+
if (!rl.allowed) {
|
|
28
|
+
return {
|
|
29
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
30
|
+
error: "rate_limit_exceeded",
|
|
31
|
+
message: `Free tier: ${import_auth.FREE_TIER_LIMIT} calls/day. Set TTT_API_KEY env var for unlimited access. \u2192 kenosian.com/pricing`,
|
|
32
|
+
remaining: 0,
|
|
33
|
+
tier: "free"
|
|
34
|
+
}) }],
|
|
35
|
+
isError: true
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
23
39
|
try {
|
|
24
40
|
const result = await (0, import_tools.potGenerate)(args);
|
|
25
41
|
return {
|
|
@@ -44,6 +60,21 @@ server.tool(
|
|
|
44
60
|
poolAddress: import_zod.z.string().describe("Uniswap V4 pool address (0x-prefixed)")
|
|
45
61
|
},
|
|
46
62
|
async (args) => {
|
|
63
|
+
if (IS_STDIO) {
|
|
64
|
+
const apiKey = (0, import_auth.resolveApiKey)();
|
|
65
|
+
const rl = (0, import_auth.checkRateLimit)(apiKey, "stdio");
|
|
66
|
+
if (!rl.allowed) {
|
|
67
|
+
return {
|
|
68
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
69
|
+
error: "rate_limit_exceeded",
|
|
70
|
+
message: `Free tier: ${import_auth.FREE_TIER_LIMIT} calls/day. Set TTT_API_KEY env var for unlimited access. \u2192 kenosian.com/pricing`,
|
|
71
|
+
remaining: 0,
|
|
72
|
+
tier: "free"
|
|
73
|
+
}) }],
|
|
74
|
+
isError: true
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
47
78
|
try {
|
|
48
79
|
const result = await (0, import_tools.potVerify)(args);
|
|
49
80
|
return {
|
|
@@ -67,6 +98,21 @@ server.tool(
|
|
|
67
98
|
limit: import_zod.z.number().optional().describe("Max entries to return. Default: 100, max: 1000")
|
|
68
99
|
},
|
|
69
100
|
async (args) => {
|
|
101
|
+
if (IS_STDIO) {
|
|
102
|
+
const apiKey = (0, import_auth.resolveApiKey)();
|
|
103
|
+
const rl = (0, import_auth.checkRateLimit)(apiKey, "stdio");
|
|
104
|
+
if (!rl.allowed) {
|
|
105
|
+
return {
|
|
106
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
107
|
+
error: "rate_limit_exceeded",
|
|
108
|
+
message: `Free tier: ${import_auth.FREE_TIER_LIMIT} calls/day. Set TTT_API_KEY env var for unlimited access. \u2192 kenosian.com/pricing`,
|
|
109
|
+
remaining: 0,
|
|
110
|
+
tier: "free"
|
|
111
|
+
}) }],
|
|
112
|
+
isError: true
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
70
116
|
try {
|
|
71
117
|
const result = await (0, import_tools.potQuery)(args);
|
|
72
118
|
return {
|
|
@@ -88,6 +134,21 @@ server.tool(
|
|
|
88
134
|
period: import_zod.z.enum(["day", "week", "month"]).describe("Time period for statistics")
|
|
89
135
|
},
|
|
90
136
|
async (args) => {
|
|
137
|
+
if (IS_STDIO) {
|
|
138
|
+
const apiKey = (0, import_auth.resolveApiKey)();
|
|
139
|
+
const rl = (0, import_auth.checkRateLimit)(apiKey, "stdio");
|
|
140
|
+
if (!rl.allowed) {
|
|
141
|
+
return {
|
|
142
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
143
|
+
error: "rate_limit_exceeded",
|
|
144
|
+
message: `Free tier: ${import_auth.FREE_TIER_LIMIT} calls/day. Set TTT_API_KEY env var for unlimited access. \u2192 kenosian.com/pricing`,
|
|
145
|
+
remaining: 0,
|
|
146
|
+
tier: "free"
|
|
147
|
+
}) }],
|
|
148
|
+
isError: true
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
91
152
|
try {
|
|
92
153
|
const result = await (0, import_tools.potStats)(args);
|
|
93
154
|
return {
|