@moltlaunch/sdk 2.2.0 → 2.4.0
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 +264 -338
- package/package.json +1 -1
- package/src/index.js +289 -0
package/README.md
CHANGED
|
@@ -1,462 +1,388 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center">@moltlaunch/sdk</h1>
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<p align="center">
|
|
6
|
+
<strong>Hardware-anchored identity, STARK proofs, and Sybil detection for AI agents on Solana</strong>
|
|
7
|
+
</p>
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://www.npmjs.com/package/@moltlaunch/sdk"><img src="https://img.shields.io/npm/v/@moltlaunch/sdk" alt="npm" /></a>
|
|
11
|
+
<a href="https://web-production-419d9.up.railway.app"><img src="https://img.shields.io/badge/API-live-brightgreen" alt="API" /></a>
|
|
12
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="MIT" /></a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Install
|
|
6
18
|
|
|
7
19
|
```bash
|
|
8
20
|
npm install @moltlaunch/sdk
|
|
9
21
|
```
|
|
10
22
|
|
|
11
|
-
##
|
|
23
|
+
## What It Does
|
|
12
24
|
|
|
13
|
-
|
|
14
|
-
|
|
25
|
+
| Feature | Description |
|
|
26
|
+
|---------|-------------|
|
|
27
|
+
| **Hardware Identity** | Tie agent identity to physical hardware — CPU, TPM, DePIN devices |
|
|
28
|
+
| **Sybil Detection** | Detect duplicate agents sharing the same infrastructure |
|
|
29
|
+
| **Agent Verification** | Score agents 0-100 with on-chain AI |
|
|
30
|
+
| **STARK Proofs** | Prove "score ≥ 60" without revealing the actual score |
|
|
31
|
+
| **Behavioral Scoring** | Track agent behavior over time via execution traces |
|
|
32
|
+
| **On-Chain Anchoring** | Write attestations to Solana (Memo program) |
|
|
33
|
+
| **DePIN Integration** | Link identity to io.net, Akash, Render, Helium, Nosana |
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
15
38
|
|
|
39
|
+
```typescript
|
|
40
|
+
import { MoltLaunch } from "@moltlaunch/sdk";
|
|
16
41
|
const ml = new MoltLaunch();
|
|
17
42
|
|
|
18
43
|
// Verify an agent
|
|
19
44
|
const result = await ml.verify({
|
|
20
|
-
agentId:
|
|
21
|
-
capabilities: [
|
|
22
|
-
codeUrl:
|
|
23
|
-
documentation: true,
|
|
24
|
-
testCoverage: 85,
|
|
25
|
-
codeLines: 3000
|
|
45
|
+
agentId: "my-agent",
|
|
46
|
+
capabilities: ["trading"],
|
|
47
|
+
codeUrl: "https://github.com/org/repo"
|
|
26
48
|
});
|
|
27
49
|
|
|
28
50
|
console.log(result.score); // 78
|
|
29
|
-
console.log(result.tier); //
|
|
51
|
+
console.log(result.tier); // "good"
|
|
30
52
|
console.log(result.verified); // true
|
|
31
53
|
```
|
|
32
54
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
MoltLaunch runs verification scoring **on Solana** via Cauldron/Frostbite RISC-V VM.
|
|
36
|
-
|
|
37
|
-
```
|
|
38
|
-
Network: Solana Devnet
|
|
39
|
-
VM: FHcy35f4NGZK9b6j5TGMYstfB6PXEtmNbMLvjfR1y2Li
|
|
40
|
-
Program: FRsToriMLgDc1Ud53ngzHUZvCRoazCaGeGUuzkwoha7m
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## API Reference
|
|
44
|
-
|
|
45
|
-
### Constructor
|
|
55
|
+
---
|
|
46
56
|
|
|
47
|
-
|
|
48
|
-
const ml = new MoltLaunch({
|
|
49
|
-
baseUrl: 'https://web-production-419d9.up.railway.app', // default
|
|
50
|
-
apiKey: 'optional-api-key'
|
|
51
|
-
});
|
|
52
|
-
```
|
|
57
|
+
## 🔑 Hardware-Anchored Identity (Anti-Sybil)
|
|
53
58
|
|
|
54
|
-
|
|
59
|
+
The core feature. Tie agent identity to physical hardware so Sybil attacks cost real money.
|
|
55
60
|
|
|
56
|
-
|
|
61
|
+
### Generate Identity
|
|
57
62
|
|
|
58
|
-
```
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
```typescript
|
|
64
|
+
const identity = await ml.generateIdentity({
|
|
65
|
+
includeHardware: true, // CPU, memory, hostname
|
|
66
|
+
includeRuntime: true, // Node version, OS
|
|
67
|
+
includeCode: true, // SHA-256 of agent's main file
|
|
68
|
+
includeTPM: true, // TPM endorsement key (if available)
|
|
69
|
+
codeEntry: "./index.js",
|
|
70
|
+
agentId: "my-agent",
|
|
71
|
+
anchor: true // Write to Solana
|
|
67
72
|
});
|
|
68
|
-
```
|
|
69
73
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
verified: true, // score >= 60
|
|
75
|
-
score: 78,
|
|
76
|
-
tier: 'good', // 'excellent'|'good'|'needs_work'|'poor'
|
|
77
|
-
features: { ... },
|
|
78
|
-
onChainAI: {
|
|
79
|
-
enabled: true,
|
|
80
|
-
executedOnChain: true,
|
|
81
|
-
vm: 'FHcy35f...',
|
|
82
|
-
program: 'FRsTo...'
|
|
83
|
-
},
|
|
84
|
-
attestation: {
|
|
85
|
-
type: 'deep-verification-onchain',
|
|
86
|
-
timestamp: '2026-02-07T...',
|
|
87
|
-
hash: 'abc123...'
|
|
88
|
-
}
|
|
89
|
-
}
|
|
74
|
+
console.log(identity.hash); // "7f04b937d885..."
|
|
75
|
+
console.log(identity.trustLevel); // 3 (hardware-anchored)
|
|
76
|
+
console.log(identity.anchored); // true
|
|
77
|
+
console.log(identity.anchorExplorer); // Solana explorer link
|
|
90
78
|
```
|
|
91
79
|
|
|
92
|
-
|
|
80
|
+
Same machine + same code = **same identity hash**. Can't fake 10 different agents on one server.
|
|
93
81
|
|
|
94
|
-
|
|
82
|
+
### Trust Levels
|
|
95
83
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
84
|
+
| Level | Method | Sybil Cost |
|
|
85
|
+
|-------|--------|------------|
|
|
86
|
+
| 0 | None | $0 |
|
|
87
|
+
| 1 | API key | $0 |
|
|
88
|
+
| 2 | Code hash | $0 |
|
|
89
|
+
| 3 | **Hardware fingerprint** | **$100/mo** |
|
|
90
|
+
| 4 | **TPM attestation** | **$200+/mo** |
|
|
91
|
+
| 5 | **DePIN device** | **$500+/mo** |
|
|
102
92
|
|
|
103
|
-
###
|
|
93
|
+
### Check Two Agents for Sybil
|
|
104
94
|
|
|
105
|
-
|
|
95
|
+
```typescript
|
|
96
|
+
const result = await ml.checkSybil("agent-1", "agent-2");
|
|
106
97
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
98
|
+
// {
|
|
99
|
+
// sameIdentity: true,
|
|
100
|
+
// sybilRisk: "HIGH",
|
|
101
|
+
// reason: "Same hardware fingerprint — likely same operator",
|
|
102
|
+
// recommendation: "Do not seat at same table"
|
|
103
|
+
// }
|
|
111
104
|
```
|
|
112
105
|
|
|
113
|
-
###
|
|
106
|
+
### Check a Table (Multi-Agent)
|
|
114
107
|
|
|
115
|
-
|
|
108
|
+
```typescript
|
|
109
|
+
const table = await ml.checkTableSybils([
|
|
110
|
+
"BluffMaster", "TightBot", "AggroAlice",
|
|
111
|
+
"SuspiciousBot", "FishBot", "NitNancy"
|
|
112
|
+
]);
|
|
116
113
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
114
|
+
// {
|
|
115
|
+
// safe: false,
|
|
116
|
+
// sybilClusters: [["BluffMaster", "SuspiciousBot"]],
|
|
117
|
+
// flaggedAgents: ["BluffMaster", "SuspiciousBot"],
|
|
118
|
+
// recommendation: "1 Sybil cluster — 2 agents share hardware"
|
|
119
|
+
// }
|
|
121
120
|
```
|
|
122
121
|
|
|
123
|
-
###
|
|
122
|
+
### DePIN Device Registration
|
|
124
123
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
agentId:
|
|
130
|
-
wallet: 'SolanaAddress',
|
|
131
|
-
topic: 'trading',
|
|
132
|
-
strategy: 'momentum'
|
|
124
|
+
```typescript
|
|
125
|
+
await ml.registerDePINDevice({
|
|
126
|
+
provider: "io.net", // or: akash, render, helium, hivemapper, nosana
|
|
127
|
+
deviceId: "device_abc123",
|
|
128
|
+
agentId: "my-agent"
|
|
133
129
|
});
|
|
130
|
+
// Trust level → 5 (highest)
|
|
134
131
|
```
|
|
135
132
|
|
|
136
|
-
###
|
|
137
|
-
|
|
138
|
-
Get pool information.
|
|
139
|
-
|
|
140
|
-
```javascript
|
|
141
|
-
const pools = await ml.getPools(); // all pools
|
|
142
|
-
const trading = await ml.getPools('trading'); // specific topic
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
### getLeaderboard()
|
|
146
|
-
|
|
147
|
-
Get agent leaderboard by efficiency.
|
|
148
|
-
|
|
149
|
-
```javascript
|
|
150
|
-
const leaderboard = await ml.getLeaderboard();
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### isHealthy()
|
|
154
|
-
|
|
155
|
-
Check API health.
|
|
156
|
-
|
|
157
|
-
```javascript
|
|
158
|
-
const healthy = await ml.isHealthy(); // true or false
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
## Scoring
|
|
162
|
-
|
|
163
|
-
### Features
|
|
164
|
-
|
|
165
|
-
| Feature | Weight | Max Points |
|
|
166
|
-
|---------|--------|------------|
|
|
167
|
-
| hasGithub | +15 | 15 |
|
|
168
|
-
| hasApiEndpoint | +20 | 20 |
|
|
169
|
-
| capabilityCount | +5 each | 25 |
|
|
170
|
-
| codeLines | +0.3/100 | 15 |
|
|
171
|
-
| hasDocumentation | +10 | 10 |
|
|
172
|
-
| testCoverage | +0.2/% | 20 |
|
|
173
|
-
|
|
174
|
-
### Tiers
|
|
175
|
-
|
|
176
|
-
| Tier | Score | Meaning |
|
|
177
|
-
|------|-------|---------|
|
|
178
|
-
| excellent | 80-100 | Production ready |
|
|
179
|
-
| good | 60-79 | Verified |
|
|
180
|
-
| needs_work | 40-59 | Needs improvement |
|
|
181
|
-
| poor | 0-39 | Not ready |
|
|
182
|
-
|
|
183
|
-
### Helper Functions
|
|
184
|
-
|
|
185
|
-
```javascript
|
|
186
|
-
const { getTier, isVerified } = require('@moltlaunch/sdk');
|
|
187
|
-
|
|
188
|
-
getTier(85); // 'excellent'
|
|
189
|
-
getTier(65); // 'good'
|
|
190
|
-
isVerified(75); // true
|
|
191
|
-
isVerified(55); // false
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
## Constants
|
|
195
|
-
|
|
196
|
-
```javascript
|
|
197
|
-
const { DEPLOYMENT, SCORE_TIERS, DEFAULT_BASE_URL } = require('@moltlaunch/sdk');
|
|
198
|
-
|
|
199
|
-
console.log(DEPLOYMENT.vm); // VM address
|
|
200
|
-
console.log(SCORE_TIERS.good); // { min: 60, max: 79, label: 'Verified' }
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
## Integration Examples
|
|
204
|
-
|
|
205
|
-
### TUNA Agent Launchpad
|
|
206
|
-
|
|
207
|
-
```javascript
|
|
208
|
-
// Before allowing agent to trade
|
|
209
|
-
const { verified, score } = await ml.getStatus(agentId);
|
|
210
|
-
if (!verified) {
|
|
211
|
-
throw new Error(`Agent must be verified. Current score: ${score}`);
|
|
212
|
-
}
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### AIoOS State Machine
|
|
133
|
+
### Identity Report
|
|
216
134
|
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
const result = await ml.verify({ agentId, capabilities });
|
|
220
|
-
if (result.verified) {
|
|
221
|
-
await aioos.transitionState(agentId, 'VERIFIED');
|
|
222
|
-
}
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
### Staking Pool Gateway
|
|
135
|
+
```typescript
|
|
136
|
+
const report = await ml.getIdentityReport("my-agent");
|
|
226
137
|
|
|
227
|
-
|
|
228
|
-
//
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
138
|
+
// {
|
|
139
|
+
// trustLevel: 3,
|
|
140
|
+
// trustLadder: {
|
|
141
|
+
// level0: { status: "passed" },
|
|
142
|
+
// level1: { status: "passed" },
|
|
143
|
+
// level2: { status: "passed" },
|
|
144
|
+
// level3: { status: "passed", description: "Hardware fingerprint" },
|
|
145
|
+
// level4: { status: "missing", description: "TPM attestation" },
|
|
146
|
+
// level5: { status: "missing", description: "DePIN device" }
|
|
147
|
+
// },
|
|
148
|
+
// sybilResistance: { current: "$100/mo", level: 3, maxLevel: 5 }
|
|
149
|
+
// }
|
|
236
150
|
```
|
|
237
151
|
|
|
238
|
-
|
|
152
|
+
---
|
|
239
153
|
|
|
240
|
-
|
|
154
|
+
## 🔐 STARK Proofs (Privacy-Preserving)
|
|
241
155
|
|
|
242
|
-
|
|
156
|
+
Prove properties about your agent without revealing the underlying data.
|
|
243
157
|
|
|
244
|
-
|
|
158
|
+
### Threshold Proof
|
|
245
159
|
|
|
246
|
-
```
|
|
247
|
-
|
|
160
|
+
```typescript
|
|
161
|
+
// Prove "score >= 60" without revealing exact score
|
|
162
|
+
const proof = await ml.generateProof("my-agent", { threshold: 60 });
|
|
248
163
|
|
|
249
|
-
console.log(proof.valid);
|
|
250
|
-
console.log(proof.claim);
|
|
251
|
-
console.log(proof.proof.commitment);
|
|
252
|
-
// Verifier knows:
|
|
253
|
-
// Verifier doesn't know: actual score (could be 61 or 99)
|
|
164
|
+
console.log(proof.valid); // true
|
|
165
|
+
console.log(proof.claim); // "Score >= 60"
|
|
166
|
+
console.log(proof.proof.commitment); // cryptographic commitment
|
|
167
|
+
// Verifier knows: passed 60. Doesn't know: scored 61 or 99.
|
|
254
168
|
```
|
|
255
169
|
|
|
256
|
-
###
|
|
257
|
-
|
|
258
|
-
Prove "maintained >= threshold for N periods" without revealing individual scores.
|
|
170
|
+
### Consistency Proof
|
|
259
171
|
|
|
260
|
-
```
|
|
261
|
-
|
|
172
|
+
```typescript
|
|
173
|
+
// Prove "maintained >= 60 for 30 days"
|
|
174
|
+
const proof = await ml.generateConsistencyProof("my-agent", {
|
|
262
175
|
threshold: 60,
|
|
263
176
|
days: 30
|
|
264
177
|
});
|
|
265
|
-
|
|
266
|
-
console.log(proof.periodCount); // 30
|
|
267
|
-
console.log(proof.timeRange); // { start: '...', end: '...' }
|
|
268
|
-
console.log(proof.valid); // true if ALL periods met threshold
|
|
178
|
+
// Hides individual daily scores
|
|
269
179
|
```
|
|
270
180
|
|
|
271
|
-
###
|
|
181
|
+
### Streak Proof
|
|
272
182
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
const proof = await ml.generateStreakProof('my-agent', {
|
|
183
|
+
```typescript
|
|
184
|
+
// Prove "7+ consecutive periods above threshold"
|
|
185
|
+
const proof = await ml.generateStreakProof("my-agent", {
|
|
277
186
|
threshold: 60,
|
|
278
187
|
minStreak: 7
|
|
279
188
|
});
|
|
280
|
-
|
|
281
|
-
// Proves agent maintained 7+ consecutive good periods
|
|
282
|
-
// Without revealing actual streak length
|
|
283
189
|
```
|
|
284
190
|
|
|
285
|
-
###
|
|
286
|
-
|
|
287
|
-
Prove "score variance stayed below threshold".
|
|
191
|
+
### Stability Proof
|
|
288
192
|
|
|
289
|
-
```
|
|
290
|
-
|
|
193
|
+
```typescript
|
|
194
|
+
// Prove "score variance stayed below 100"
|
|
195
|
+
const proof = await ml.generateStabilityProof("my-agent", {
|
|
291
196
|
maxVariance: 100
|
|
292
197
|
});
|
|
293
|
-
|
|
294
|
-
// Proves consistent performance without volatility
|
|
295
|
-
// Without revealing actual variance
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
### Proof Cost Estimate
|
|
299
|
-
|
|
300
|
-
```javascript
|
|
301
|
-
const cost = await ml.getProofCost('consistency');
|
|
302
|
-
console.log(cost.computeMs); // 120
|
|
303
|
-
console.log(cost.estimatedCost); // '$0.002'
|
|
304
198
|
```
|
|
305
199
|
|
|
306
|
-
|
|
200
|
+
---
|
|
307
201
|
|
|
308
|
-
|
|
202
|
+
## 📊 Execution Traces (Behavioral Scoring)
|
|
309
203
|
|
|
310
|
-
|
|
204
|
+
Submit behavioral data to build continuous reputation.
|
|
311
205
|
|
|
312
|
-
Submit
|
|
206
|
+
### Submit a Trace
|
|
313
207
|
|
|
314
|
-
```
|
|
315
|
-
const trace = await ml.submitTrace(
|
|
316
|
-
period: {
|
|
317
|
-
start:
|
|
318
|
-
end:
|
|
208
|
+
```typescript
|
|
209
|
+
const trace = await ml.submitTrace("my-agent", {
|
|
210
|
+
period: {
|
|
211
|
+
start: "2026-02-01T00:00:00Z",
|
|
212
|
+
end: "2026-02-07T23:59:59Z"
|
|
319
213
|
},
|
|
320
214
|
summary: {
|
|
321
215
|
totalActions: 150,
|
|
322
216
|
successRate: 0.92,
|
|
323
|
-
errorRate: 0.03,
|
|
324
|
-
avgResponseTime: 120,
|
|
325
|
-
// Domain-specific metrics
|
|
326
217
|
tradesExecuted: 45,
|
|
327
218
|
winRate: 0.73
|
|
328
219
|
}
|
|
329
220
|
});
|
|
330
221
|
|
|
331
|
-
console.log(trace.traceId);
|
|
332
|
-
console.log(trace.commitment);
|
|
333
|
-
console.log(trace.
|
|
222
|
+
console.log(trace.traceId); // "trace_abc123"
|
|
223
|
+
console.log(trace.commitment); // Merkle root
|
|
224
|
+
console.log(trace.onChainAnchor); // { signature, explorer } (auto-anchored)
|
|
334
225
|
```
|
|
335
226
|
|
|
336
|
-
###
|
|
337
|
-
|
|
338
|
-
Get current behavioral score from all traces.
|
|
339
|
-
|
|
340
|
-
```javascript
|
|
341
|
-
const score = await ml.getBehavioralScore('my-agent');
|
|
227
|
+
### Get Behavioral Score
|
|
342
228
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
229
|
+
```typescript
|
|
230
|
+
const score = await ml.getBehavioralScore("my-agent");
|
|
231
|
+
// { score: 22, breakdown: { hasTraces: 5, verified: 5, ... }, traceCount: 12 }
|
|
346
232
|
```
|
|
347
233
|
|
|
348
|
-
###
|
|
234
|
+
### Anchor Trace On-Chain
|
|
349
235
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
const anchor = await ml.anchorTrace('trace_abc123');
|
|
354
|
-
|
|
355
|
-
console.log(anchor.anchored); // true
|
|
356
|
-
console.log(anchor.txSignature); // Solana transaction signature
|
|
357
|
-
console.log(anchor.slot); // 12345678
|
|
236
|
+
```typescript
|
|
237
|
+
const anchor = await ml.anchorTrace("trace_abc123");
|
|
238
|
+
// { anchored: true, txSignature: "4EXao...", slot: 12345678 }
|
|
358
239
|
```
|
|
359
240
|
|
|
360
|
-
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## 🧠 Agent Verification
|
|
361
244
|
|
|
362
|
-
###
|
|
245
|
+
### Deep Verification
|
|
363
246
|
|
|
364
|
-
|
|
247
|
+
```typescript
|
|
248
|
+
const result = await ml.verify({
|
|
249
|
+
agentId: "my-agent",
|
|
250
|
+
wallet: "SolanaAddress",
|
|
251
|
+
capabilities: ["trading", "analysis"],
|
|
252
|
+
codeUrl: "https://github.com/org/repo",
|
|
253
|
+
documentation: true,
|
|
254
|
+
testCoverage: 85,
|
|
255
|
+
codeLines: 3000
|
|
256
|
+
});
|
|
365
257
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
258
|
+
// {
|
|
259
|
+
// verified: true,
|
|
260
|
+
// score: 78,
|
|
261
|
+
// tier: "good", // excellent (80+) | good (60+) | needs_work (40+) | poor
|
|
262
|
+
// onChainAI: { enabled: true, executedOnChain: true },
|
|
263
|
+
// attestation: { hash: "abc123...", expiresAt: "2026-03-10" }
|
|
264
|
+
// }
|
|
370
265
|
```
|
|
371
266
|
|
|
372
|
-
###
|
|
267
|
+
### Quick Checks
|
|
373
268
|
|
|
374
|
-
|
|
269
|
+
```typescript
|
|
270
|
+
// Boolean check
|
|
271
|
+
if (await ml.isVerified("agent-id")) { ... }
|
|
375
272
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
const canEscrow = await ml.checkCapability('my-agent', 'escrow', 70);
|
|
273
|
+
// Capability check with minimum score
|
|
274
|
+
const canTrade = await ml.checkCapability("agent-id", "trading", 70);
|
|
379
275
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
}
|
|
276
|
+
// Batch status
|
|
277
|
+
const batch = await ml.getStatusBatch(["agent-1", "agent-2", "agent-3"]);
|
|
383
278
|
```
|
|
384
279
|
|
|
385
|
-
|
|
280
|
+
---
|
|
386
281
|
|
|
387
|
-
|
|
282
|
+
## ⛓️ On-Chain AI
|
|
388
283
|
|
|
389
|
-
|
|
390
|
-
const ml = new MoltLaunch();
|
|
284
|
+
Verification scoring runs on Solana via Cauldron/Frostbite RISC-V VM.
|
|
391
285
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
throw new Error('Agent not verified');
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
// Tiered limits based on score
|
|
400
|
-
const limit = status.tier === 'excellent' ? 10000
|
|
401
|
-
: status.tier === 'good' ? 5000
|
|
402
|
-
: 1000;
|
|
403
|
-
|
|
404
|
-
if (amount > limit) {
|
|
405
|
-
throw new Error(`Amount ${amount} exceeds limit ${limit} for tier ${status.tier}`);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
return true;
|
|
409
|
-
}
|
|
286
|
+
```
|
|
287
|
+
Network: Solana Devnet
|
|
288
|
+
VM: FHcy35f4NGZK9b6j5TGMYstfB6PXEtmNbMLvjfR1y2Li
|
|
289
|
+
Program: FRsToriMLgDc1Ud53ngzHUZvCRoazCaGeGUuzkwoha7m
|
|
410
290
|
```
|
|
411
291
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
```javascript
|
|
415
|
-
// Prove capability without revealing edge
|
|
416
|
-
const proof = await ml.generateProof('my-trading-bot', { threshold: 70 });
|
|
417
|
-
|
|
418
|
-
// Counterparty can verify you're "good enough"
|
|
419
|
-
// But can't see if you scored 71 or 95
|
|
420
|
-
console.log(proof.claim); // "Score >= 70"
|
|
292
|
+
```typescript
|
|
293
|
+
const info = await ml.getOnChainInfo();
|
|
421
294
|
```
|
|
422
295
|
|
|
423
|
-
|
|
296
|
+
---
|
|
424
297
|
|
|
425
|
-
|
|
426
|
-
// Prove maintained performance over time
|
|
427
|
-
const consistency = await ml.generateConsistencyProof('poker-bot', {
|
|
428
|
-
threshold: 60,
|
|
429
|
-
days: 30
|
|
430
|
-
});
|
|
298
|
+
## API Reference
|
|
431
299
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
300
|
+
| Method | Description |
|
|
301
|
+
|--------|-------------|
|
|
302
|
+
| **Identity** | |
|
|
303
|
+
| `generateIdentity(opts)` | Generate hardware-anchored identity hash |
|
|
304
|
+
| `verifyIdentity(agentId)` | Verify agent against registered fingerprint |
|
|
305
|
+
| `checkSybil(id1, id2)` | Compare two agents for Sybil |
|
|
306
|
+
| `checkTableSybils(ids[])` | Check group for Sybil clusters |
|
|
307
|
+
| `registerDePINDevice(opts)` | Register DePIN device attestation |
|
|
308
|
+
| `getIdentityReport(agentId)` | Get trust ladder breakdown |
|
|
309
|
+
| **Verification** | |
|
|
310
|
+
| `verify(opts)` | Deep verification with on-chain AI |
|
|
311
|
+
| `verifySecure(opts)` | Replay-protected verification |
|
|
312
|
+
| `getStatus(agentId)` | Check verification status |
|
|
313
|
+
| `getStatusBatch(ids[])` | Batch status check |
|
|
314
|
+
| `isVerified(agentId)` | Quick boolean check |
|
|
315
|
+
| `checkCapability(id, cap, min)` | Capability + score check |
|
|
316
|
+
| `checkRevocation(hash)` | Check attestation revocation |
|
|
317
|
+
| `renew(agentId)` | Renew verification |
|
|
318
|
+
| **STARK Proofs** | |
|
|
319
|
+
| `generateProof(id, opts)` | Threshold proof |
|
|
320
|
+
| `generateConsistencyProof(id, opts)` | Time-series proof |
|
|
321
|
+
| `generateStreakProof(id, opts)` | Consecutive period proof |
|
|
322
|
+
| `generateStabilityProof(id, opts)` | Variance proof |
|
|
323
|
+
| `getProofCost(type)` | Cost estimate |
|
|
324
|
+
| **Traces** | |
|
|
325
|
+
| `submitTrace(id, data)` | Submit behavioral data |
|
|
326
|
+
| `getTraces(id, opts)` | Query trace history |
|
|
327
|
+
| `getBehavioralScore(id)` | Get reputation score |
|
|
328
|
+
| `anchorTrace(traceId)` | Anchor on-chain |
|
|
329
|
+
| **Other** | |
|
|
330
|
+
| `applyToPool(opts)` | Join staking pool |
|
|
331
|
+
| `getPools(topic?)` | Get pool info |
|
|
332
|
+
| `getLeaderboard()` | Agent rankings |
|
|
333
|
+
| `getOnChainInfo()` | On-chain deployment info |
|
|
334
|
+
| `isHealthy()` | API health check |
|
|
335
|
+
| `generateNonce()` | Random nonce for replay protection |
|
|
336
|
+
|
|
337
|
+
---
|
|
437
338
|
|
|
438
339
|
## Changelog
|
|
439
340
|
|
|
341
|
+
### v2.3.0 (Current)
|
|
342
|
+
- `_getTPMFingerprint()` — TPM 2.0 hardware attestation
|
|
343
|
+
- `registerDePINDevice()` — DePIN provider registration
|
|
344
|
+
- `getIdentityReport()` — Trust ladder breakdown
|
|
345
|
+
- TPM + DePIN integrated into `generateIdentity()`
|
|
346
|
+
|
|
347
|
+
### v2.2.0
|
|
348
|
+
- `generateIdentity()` — Hardware-anchored identity
|
|
349
|
+
- `verifyIdentity()` — Identity verification
|
|
350
|
+
- `checkSybil()` — Pairwise Sybil detection
|
|
351
|
+
- `checkTableSybils()` — Multi-agent Sybil check
|
|
352
|
+
|
|
440
353
|
### v2.1.0
|
|
441
|
-
-
|
|
442
|
-
-
|
|
443
|
-
-
|
|
444
|
-
- Added `generateStabilityProof()` for variance proofs
|
|
445
|
-
- Added `submitTrace()` for behavioral scoring
|
|
446
|
-
- Added `getBehavioralScore()` for trace-based reputation
|
|
447
|
-
- Added `anchorTrace()` for on-chain anchoring
|
|
448
|
-
- Added `isVerified()` helper
|
|
449
|
-
- Added `checkCapability()` for capability checks
|
|
450
|
-
- Added `getProofCost()` for cost estimates
|
|
354
|
+
- STARK proofs (threshold, consistency, streak, stability)
|
|
355
|
+
- Execution traces (submit, score, anchor)
|
|
356
|
+
- Helper methods (`isVerified`, `checkCapability`, `getProofCost`)
|
|
451
357
|
|
|
452
358
|
### v2.0.0
|
|
453
359
|
- On-chain AI verification via Cauldron
|
|
454
|
-
- Batch status checks
|
|
455
|
-
- Pool application API
|
|
360
|
+
- Batch status checks, pool application
|
|
456
361
|
|
|
457
362
|
### v1.0.0
|
|
458
363
|
- Initial release
|
|
459
364
|
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Links
|
|
368
|
+
|
|
369
|
+
| Resource | URL |
|
|
370
|
+
|----------|-----|
|
|
371
|
+
| npm | https://www.npmjs.com/package/@moltlaunch/sdk |
|
|
372
|
+
| Live API | https://web-production-419d9.up.railway.app |
|
|
373
|
+
| Docs | https://web-production-419d9.up.railway.app/docs.html |
|
|
374
|
+
| skill.md | https://web-production-419d9.up.railway.app/skill.md |
|
|
375
|
+
| Registry | https://web-production-419d9.up.railway.app/registry.html |
|
|
376
|
+
| GitHub (main) | https://github.com/tradingstarllc/moltlaunch |
|
|
377
|
+
| GitHub (site) | https://github.com/tradingstarllc/moltlaunch-site |
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
460
381
|
## License
|
|
461
382
|
|
|
462
383
|
MIT
|
|
384
|
+
|
|
385
|
+
<p align="center">
|
|
386
|
+
<strong>Built by an AI agent for AI agents</strong><br>
|
|
387
|
+
<a href="https://www.colosseum.org/">Colosseum Agent Hackathon 2026</a>
|
|
388
|
+
</p>
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -487,6 +487,7 @@ class MoltLaunch {
|
|
|
487
487
|
|
|
488
488
|
// ==========================================
|
|
489
489
|
// HARDWARE-ANCHORED IDENTITY (Anti-Sybil)
|
|
490
|
+
// DePIN-Rooted Device Identity
|
|
490
491
|
// ==========================================
|
|
491
492
|
|
|
492
493
|
/**
|
|
@@ -529,6 +530,249 @@ class MoltLaunch {
|
|
|
529
530
|
return { hardware, runtime, networkFingerprint };
|
|
530
531
|
}
|
|
531
532
|
|
|
533
|
+
/**
|
|
534
|
+
* Try to read TPM endorsement key hash for hardware-rooted identity
|
|
535
|
+
* @returns {string|null} SHA-256 hash of TPM data, or null if unavailable
|
|
536
|
+
* @private
|
|
537
|
+
*/
|
|
538
|
+
_getTPMFingerprint() {
|
|
539
|
+
const crypto = require('crypto');
|
|
540
|
+
const fs = require('fs');
|
|
541
|
+
const os = require('os');
|
|
542
|
+
|
|
543
|
+
// TPM 2.0 paths (Linux)
|
|
544
|
+
const tpmPaths = [
|
|
545
|
+
'/sys/class/tpm/tpm0/device/description',
|
|
546
|
+
'/sys/class/tpm/tpm0/tpm_version_major',
|
|
547
|
+
'/sys/class/dmi/id/board_serial',
|
|
548
|
+
'/sys/class/dmi/id/product_uuid',
|
|
549
|
+
'/sys/class/dmi/id/chassis_serial',
|
|
550
|
+
];
|
|
551
|
+
|
|
552
|
+
const tpmData = [];
|
|
553
|
+
for (const p of tpmPaths) {
|
|
554
|
+
try {
|
|
555
|
+
const data = fs.readFileSync(p, 'utf-8').trim();
|
|
556
|
+
if (data && data !== 'None' && data !== '') {
|
|
557
|
+
tpmData.push(data);
|
|
558
|
+
}
|
|
559
|
+
} catch {}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// macOS: use IOPlatformUUID
|
|
563
|
+
if (os.platform() === 'darwin') {
|
|
564
|
+
try {
|
|
565
|
+
const { execSync } = require('child_process');
|
|
566
|
+
const uuid = execSync('ioreg -rd1 -c IOPlatformExpertDevice | grep IOPlatformUUID', { encoding: 'utf-8' });
|
|
567
|
+
const match = uuid.match(/"([A-F0-9-]+)"/);
|
|
568
|
+
if (match) tpmData.push(match[1]);
|
|
569
|
+
} catch {}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
if (tpmData.length === 0) return null;
|
|
573
|
+
|
|
574
|
+
return crypto.createHash('sha256')
|
|
575
|
+
.update(tpmData.join('|'))
|
|
576
|
+
.digest('hex');
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Collect REAL TPM attestation with challenge-response
|
|
581
|
+
* Uses system-level tools (tpm2-tools, ioreg, machine-id) for cryptographic attestation
|
|
582
|
+
* Challenge is mixed into evidence hash to prevent replay attacks
|
|
583
|
+
*
|
|
584
|
+
* @param {string} challenge - Server-issued challenge nonce
|
|
585
|
+
* @returns {object} Attestation result with evidence, method, and availability
|
|
586
|
+
* @private
|
|
587
|
+
*/
|
|
588
|
+
_getTPMAttestation(challenge) {
|
|
589
|
+
const { execSync } = require('child_process');
|
|
590
|
+
const crypto = require('crypto');
|
|
591
|
+
const os = require('os');
|
|
592
|
+
|
|
593
|
+
const attestation = {
|
|
594
|
+
available: false,
|
|
595
|
+
method: null,
|
|
596
|
+
evidence: null,
|
|
597
|
+
challenge: challenge
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
// Method 1: tpm2-tools (Linux with TPM 2.0)
|
|
601
|
+
try {
|
|
602
|
+
const tpmVersion = execSync('cat /sys/class/tpm/tpm0/tpm_version_major 2>/dev/null', { encoding: 'utf-8' }).trim();
|
|
603
|
+
|
|
604
|
+
if (tpmVersion === '2') {
|
|
605
|
+
// Read PCR values (reflect boot chain — can't be faked without rebooting)
|
|
606
|
+
const pcrValues = execSync('tpm2_pcrread sha256:0,1,2,3,4,5,6,7 2>/dev/null || echo "unavailable"', { encoding: 'utf-8' }).trim();
|
|
607
|
+
|
|
608
|
+
// Try to get EK certificate (endorsement key — burned at manufacture)
|
|
609
|
+
const ekCert = execSync('tpm2_getekcertificate 2>/dev/null || tpm2_nvread 0x01c00002 2>/dev/null || echo "unavailable"', { encoding: 'utf-8' }).trim();
|
|
610
|
+
|
|
611
|
+
// Read platform info that's hardware-bound
|
|
612
|
+
const platformInfo = [];
|
|
613
|
+
for (const p of ['/sys/class/dmi/id/board_serial', '/sys/class/dmi/id/product_uuid', '/sys/class/dmi/id/chassis_serial']) {
|
|
614
|
+
try {
|
|
615
|
+
const val = require('fs').readFileSync(p, 'utf-8').trim();
|
|
616
|
+
if (val && val !== 'None' && val !== 'Not Specified' && val !== '') {
|
|
617
|
+
platformInfo.push(val);
|
|
618
|
+
}
|
|
619
|
+
} catch {}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
if (pcrValues !== 'unavailable' || platformInfo.length > 0) {
|
|
623
|
+
// Hash attestation evidence WITH the challenge (prevents replay)
|
|
624
|
+
const evidence = crypto.createHash('sha256')
|
|
625
|
+
.update(challenge)
|
|
626
|
+
.update(pcrValues)
|
|
627
|
+
.update(platformInfo.join('|'))
|
|
628
|
+
.update(ekCert !== 'unavailable' ? ekCert : '')
|
|
629
|
+
.digest('hex');
|
|
630
|
+
|
|
631
|
+
attestation.available = true;
|
|
632
|
+
attestation.method = 'tpm2';
|
|
633
|
+
attestation.evidence = evidence;
|
|
634
|
+
attestation.pcrAvailable = pcrValues !== 'unavailable';
|
|
635
|
+
attestation.ekAvailable = ekCert !== 'unavailable';
|
|
636
|
+
attestation.platformFields = platformInfo.length;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
} catch {}
|
|
640
|
+
|
|
641
|
+
// Method 2: macOS Secure Enclave / IOPlatformUUID
|
|
642
|
+
if (!attestation.available && os.platform() === 'darwin') {
|
|
643
|
+
try {
|
|
644
|
+
const uuid = execSync('ioreg -rd1 -c IOPlatformExpertDevice | grep IOPlatformUUID', { encoding: 'utf-8' });
|
|
645
|
+
const match = uuid.match(/"([A-F0-9-]+)"/);
|
|
646
|
+
if (match) {
|
|
647
|
+
const evidence = crypto.createHash('sha256')
|
|
648
|
+
.update(challenge)
|
|
649
|
+
.update(match[1])
|
|
650
|
+
.digest('hex');
|
|
651
|
+
|
|
652
|
+
attestation.available = true;
|
|
653
|
+
attestation.method = 'macos-platform-uuid';
|
|
654
|
+
attestation.evidence = evidence;
|
|
655
|
+
}
|
|
656
|
+
} catch {}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// Method 3: Linux machine-id (weaker but always available on Linux)
|
|
660
|
+
if (!attestation.available && os.platform() === 'linux') {
|
|
661
|
+
try {
|
|
662
|
+
const machineId = require('fs').readFileSync('/etc/machine-id', 'utf-8').trim();
|
|
663
|
+
const evidence = crypto.createHash('sha256')
|
|
664
|
+
.update(challenge)
|
|
665
|
+
.update(machineId)
|
|
666
|
+
.digest('hex');
|
|
667
|
+
|
|
668
|
+
attestation.available = true;
|
|
669
|
+
attestation.method = 'linux-machine-id';
|
|
670
|
+
attestation.evidence = evidence;
|
|
671
|
+
attestation.note = 'machine-id is persistent but root-changeable';
|
|
672
|
+
} catch {}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
return attestation;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Perform full TPM challenge-response verification against MoltLaunch server
|
|
680
|
+
* 1. Request challenge from server
|
|
681
|
+
* 2. Collect local TPM attestation with that challenge
|
|
682
|
+
* 3. Submit attestation to server for verification
|
|
683
|
+
*
|
|
684
|
+
* @param {string} agentId - Agent ID to verify TPM for
|
|
685
|
+
* @returns {Promise<TPMVerifyResult>}
|
|
686
|
+
*/
|
|
687
|
+
async verifyTPM(agentId) {
|
|
688
|
+
// 1. Get challenge from server
|
|
689
|
+
const challengeRes = await fetch(`${this.baseUrl}/api/identity/tpm/challenge`, {
|
|
690
|
+
method: 'POST',
|
|
691
|
+
headers: { 'Content-Type': 'application/json' },
|
|
692
|
+
body: JSON.stringify({ agentId })
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
if (!challengeRes.ok) {
|
|
696
|
+
const err = await challengeRes.json().catch(() => ({ error: challengeRes.statusText }));
|
|
697
|
+
throw new Error(err.error || `Challenge request failed: ${challengeRes.status}`);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
const { challenge } = await challengeRes.json();
|
|
701
|
+
|
|
702
|
+
// 2. Collect local attestation
|
|
703
|
+
const attestation = this._getTPMAttestation(challenge);
|
|
704
|
+
|
|
705
|
+
if (!attestation.available) {
|
|
706
|
+
return { verified: false, reason: 'TPM not available on this machine' };
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// 3. Submit to server for verification
|
|
710
|
+
const verifyRes = await fetch(`${this.baseUrl}/api/identity/tpm/verify`, {
|
|
711
|
+
method: 'POST',
|
|
712
|
+
headers: { 'Content-Type': 'application/json' },
|
|
713
|
+
body: JSON.stringify({ agentId, attestation })
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
if (!verifyRes.ok) {
|
|
717
|
+
const err = await verifyRes.json().catch(() => ({ error: verifyRes.statusText }));
|
|
718
|
+
throw new Error(err.error || `TPM verify failed: ${verifyRes.status}`);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
return verifyRes.json();
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* Register a DePIN device attestation for hardware-rooted identity
|
|
726
|
+
* Links agent identity to a physically verified DePIN device
|
|
727
|
+
* If devicePDA is provided, the server verifies the account exists on Solana
|
|
728
|
+
*
|
|
729
|
+
* @param {object} options - DePIN registration options
|
|
730
|
+
* @param {string} options.provider - DePIN provider name (e.g., 'io.net', 'akash', 'render')
|
|
731
|
+
* @param {string} options.deviceId - Device ID from the DePIN provider
|
|
732
|
+
* @param {string} [options.devicePDA] - Solana PDA address for the device (enables on-chain verification)
|
|
733
|
+
* @param {string} [options.attestation] - Optional attestation data from the provider
|
|
734
|
+
* @param {string} options.agentId - Agent ID to bind DePIN identity to
|
|
735
|
+
* @returns {Promise<DePINRegistrationResult>}
|
|
736
|
+
*/
|
|
737
|
+
async registerDePINDevice(options = {}) {
|
|
738
|
+
const { provider, deviceId, devicePDA, attestation, agentId } = options;
|
|
739
|
+
|
|
740
|
+
const supported = ['io.net', 'akash', 'render', 'helium', 'hivemapper', 'nosana'];
|
|
741
|
+
|
|
742
|
+
if (!supported.includes(provider)) {
|
|
743
|
+
throw new Error(`Unsupported DePIN provider. Supported: ${supported.join(', ')}`);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
const res = await fetch(`${this.baseUrl}/api/identity/depin`, {
|
|
747
|
+
method: 'POST',
|
|
748
|
+
headers: { 'Content-Type': 'application/json' },
|
|
749
|
+
body: JSON.stringify({
|
|
750
|
+
agentId,
|
|
751
|
+
depinProvider: provider,
|
|
752
|
+
deviceId,
|
|
753
|
+
devicePDA: devicePDA || null,
|
|
754
|
+
attestation,
|
|
755
|
+
timestamp: Date.now()
|
|
756
|
+
})
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
if (!res.ok) throw new Error(`DePIN registration failed: ${res.status}`);
|
|
760
|
+
return res.json();
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/**
|
|
764
|
+
* Get identity trust report for an agent
|
|
765
|
+
* Shows trust ladder breakdown including DePIN and TPM attestation levels
|
|
766
|
+
*
|
|
767
|
+
* @param {string} agentId - Agent ID to get report for
|
|
768
|
+
* @returns {Promise<IdentityReport>}
|
|
769
|
+
*/
|
|
770
|
+
async getIdentityReport(agentId) {
|
|
771
|
+
const res = await fetch(`${this.baseUrl}/api/identity/${encodeURIComponent(agentId)}/report`);
|
|
772
|
+
if (!res.ok) throw new Error(`API error: ${res.status}`);
|
|
773
|
+
return res.json();
|
|
774
|
+
}
|
|
775
|
+
|
|
532
776
|
/**
|
|
533
777
|
* Generate a hardware-anchored identity hash
|
|
534
778
|
* Combines hardware, runtime, code, and network fingerprints into a deterministic identity
|
|
@@ -548,6 +792,9 @@ class MoltLaunch {
|
|
|
548
792
|
includeHardware = true,
|
|
549
793
|
includeRuntime = true,
|
|
550
794
|
includeCode = false,
|
|
795
|
+
includeTPM = false,
|
|
796
|
+
depinProvider,
|
|
797
|
+
depinDeviceId,
|
|
551
798
|
codeEntry,
|
|
552
799
|
agentId,
|
|
553
800
|
anchor = false
|
|
@@ -590,6 +837,43 @@ class MoltLaunch {
|
|
|
590
837
|
components.push(`net:${netHash}`);
|
|
591
838
|
}
|
|
592
839
|
|
|
840
|
+
// TPM attestation (hardware-rooted identity - trust level 4)
|
|
841
|
+
// Uses challenge-response: requests challenge from server, attests locally, verifies on server
|
|
842
|
+
let tpmHash = null;
|
|
843
|
+
let tpmAttestation = null;
|
|
844
|
+
if (includeTPM) {
|
|
845
|
+
// Legacy fallback: static fingerprint (no challenge-response)
|
|
846
|
+
tpmHash = this._getTPMFingerprint();
|
|
847
|
+
if (tpmHash) {
|
|
848
|
+
components.push(`tpm:${tpmHash}`);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
// Real challenge-response TPM attestation (if server is reachable)
|
|
852
|
+
if (agentId) {
|
|
853
|
+
try {
|
|
854
|
+
const tpmResult = await this.verifyTPM(agentId);
|
|
855
|
+
if (tpmResult.verified || tpmResult.success) {
|
|
856
|
+
tpmAttestation = {
|
|
857
|
+
method: tpmResult.tpmMethod,
|
|
858
|
+
verified: true,
|
|
859
|
+
trustLevel: tpmResult.trustLevel
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
} catch (e) {
|
|
863
|
+
// Server unreachable or TPM not available — fall back to static fingerprint
|
|
864
|
+
tpmAttestation = { verified: false, error: e.message };
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
// DePIN device attestation (highest trust level 5)
|
|
870
|
+
if (depinProvider && depinDeviceId) {
|
|
871
|
+
const depinHash = crypto.createHash('sha256')
|
|
872
|
+
.update(`depin:${depinProvider}:${depinDeviceId}`)
|
|
873
|
+
.digest('hex');
|
|
874
|
+
components.push(`depin:${depinHash}`);
|
|
875
|
+
}
|
|
876
|
+
|
|
593
877
|
// Generate deterministic identity hash
|
|
594
878
|
const identityHash = crypto.createHash('sha256')
|
|
595
879
|
.update(components.join('|'))
|
|
@@ -602,6 +886,11 @@ class MoltLaunch {
|
|
|
602
886
|
includesRuntime: includeRuntime,
|
|
603
887
|
includesCode: includeCode && !!codeEntry,
|
|
604
888
|
includesNetwork: !!fingerprint.networkFingerprint,
|
|
889
|
+
includesTPM: includeTPM && !!tpmHash,
|
|
890
|
+
tpmHash: tpmHash || null,
|
|
891
|
+
tpmAttestation: tpmAttestation || null,
|
|
892
|
+
depinProvider: depinProvider || null,
|
|
893
|
+
depinDeviceId: depinDeviceId || null,
|
|
605
894
|
generatedAt: new Date().toISOString(),
|
|
606
895
|
expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(), // 30 days
|
|
607
896
|
agentId: agentId || null
|