midnight-mcp 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/LICENSE +21 -0
- package/README.md +136 -0
- package/dist/db/index.d.ts +3 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +2 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/vectorStore.d.ts +66 -0
- package/dist/db/vectorStore.d.ts.map +1 -0
- package/dist/db/vectorStore.js +196 -0
- package/dist/db/vectorStore.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/pipeline/embeddings.d.ts +25 -0
- package/dist/pipeline/embeddings.d.ts.map +1 -0
- package/dist/pipeline/embeddings.js +103 -0
- package/dist/pipeline/embeddings.js.map +1 -0
- package/dist/pipeline/github.d.ts +67 -0
- package/dist/pipeline/github.d.ts.map +1 -0
- package/dist/pipeline/github.js +287 -0
- package/dist/pipeline/github.js.map +1 -0
- package/dist/pipeline/index.d.ts +11 -0
- package/dist/pipeline/index.d.ts.map +1 -0
- package/dist/pipeline/index.js +6 -0
- package/dist/pipeline/index.js.map +1 -0
- package/dist/pipeline/indexer.d.ts +38 -0
- package/dist/pipeline/indexer.d.ts.map +1 -0
- package/dist/pipeline/indexer.js +222 -0
- package/dist/pipeline/indexer.js.map +1 -0
- package/dist/pipeline/parser.d.ts +46 -0
- package/dist/pipeline/parser.d.ts.map +1 -0
- package/dist/pipeline/parser.js +436 -0
- package/dist/pipeline/parser.js.map +1 -0
- package/dist/pipeline/releases.d.ts +112 -0
- package/dist/pipeline/releases.d.ts.map +1 -0
- package/dist/pipeline/releases.js +298 -0
- package/dist/pipeline/releases.js.map +1 -0
- package/dist/pipeline/repository.d.ts +372 -0
- package/dist/pipeline/repository.d.ts.map +1 -0
- package/dist/pipeline/repository.js +517 -0
- package/dist/pipeline/repository.js.map +1 -0
- package/dist/prompts/index.d.ts +3 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +2 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/templates.d.ts +26 -0
- package/dist/prompts/templates.d.ts.map +1 -0
- package/dist/prompts/templates.js +353 -0
- package/dist/prompts/templates.js.map +1 -0
- package/dist/resources/code.d.ts +16 -0
- package/dist/resources/code.d.ts.map +1 -0
- package/dist/resources/code.js +630 -0
- package/dist/resources/code.js.map +1 -0
- package/dist/resources/docs.d.ts +16 -0
- package/dist/resources/docs.d.ts.map +1 -0
- package/dist/resources/docs.js +989 -0
- package/dist/resources/docs.js.map +1 -0
- package/dist/resources/index.d.ts +6 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +13 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/schemas.d.ts +16 -0
- package/dist/resources/schemas.d.ts.map +1 -0
- package/dist/resources/schemas.js +407 -0
- package/dist/resources/schemas.js.map +1 -0
- package/dist/scripts/index-repos.d.ts +12 -0
- package/dist/scripts/index-repos.d.ts.map +1 -0
- package/dist/scripts/index-repos.js +53 -0
- package/dist/scripts/index-repos.js.map +1 -0
- package/dist/server.d.ts +14 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +231 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/analyze.d.ts +140 -0
- package/dist/tools/analyze.d.ts.map +1 -0
- package/dist/tools/analyze.js +270 -0
- package/dist/tools/analyze.js.map +1 -0
- package/dist/tools/index.d.ts +392 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +9 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/repository.d.ts +537 -0
- package/dist/tools/repository.d.ts.map +1 -0
- package/dist/tools/repository.js +654 -0
- package/dist/tools/repository.js.map +1 -0
- package/dist/tools/search.d.ts +204 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +210 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/utils/config.d.ts +66 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +161 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +14 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +43 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
import { githubClient } from "../pipeline/index.js";
|
|
2
|
+
import { logger } from "../utils/index.js";
|
|
3
|
+
// Code example resources
|
|
4
|
+
export const codeResources = [
|
|
5
|
+
{
|
|
6
|
+
uri: "midnight://code/examples/counter",
|
|
7
|
+
name: "Counter Example",
|
|
8
|
+
description: "Simple counter contract demonstrating basic Compact concepts",
|
|
9
|
+
mimeType: "text/x-compact",
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
uri: "midnight://code/examples/bboard",
|
|
13
|
+
name: "Bulletin Board Example",
|
|
14
|
+
description: "Full DApp example with private messaging",
|
|
15
|
+
mimeType: "text/x-compact",
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
uri: "midnight://code/patterns/state-management",
|
|
19
|
+
name: "State Management Pattern",
|
|
20
|
+
description: "Best practices for managing public and private state",
|
|
21
|
+
mimeType: "text/x-compact",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
uri: "midnight://code/patterns/access-control",
|
|
25
|
+
name: "Access Control Pattern",
|
|
26
|
+
description: "Implementing access control in Compact contracts",
|
|
27
|
+
mimeType: "text/x-compact",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
uri: "midnight://code/patterns/privacy-preserving",
|
|
31
|
+
name: "Privacy-Preserving Pattern",
|
|
32
|
+
description: "Patterns for maintaining privacy in smart contracts",
|
|
33
|
+
mimeType: "text/x-compact",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
uri: "midnight://code/templates/token",
|
|
37
|
+
name: "Token Template",
|
|
38
|
+
description: "Starter template for privacy-preserving token contracts",
|
|
39
|
+
mimeType: "text/x-compact",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
uri: "midnight://code/templates/voting",
|
|
43
|
+
name: "Voting Template",
|
|
44
|
+
description: "Starter template for private voting contracts",
|
|
45
|
+
mimeType: "text/x-compact",
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
// Embedded code examples and templates
|
|
49
|
+
const EMBEDDED_CODE = {
|
|
50
|
+
"midnight://code/examples/counter": `// Counter Example Contract
|
|
51
|
+
// A simple contract demonstrating basic Compact concepts
|
|
52
|
+
|
|
53
|
+
include "std";
|
|
54
|
+
|
|
55
|
+
ledger {
|
|
56
|
+
// Public counter - visible to everyone
|
|
57
|
+
counter: Counter;
|
|
58
|
+
|
|
59
|
+
// Track last modifier (public)
|
|
60
|
+
lastModifier: Opaque<"address">;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Increment the counter
|
|
64
|
+
export circuit increment(amount: Field): Field {
|
|
65
|
+
// Validate input
|
|
66
|
+
assert(amount > 0, "Amount must be positive");
|
|
67
|
+
assert(amount <= 100, "Amount too large");
|
|
68
|
+
|
|
69
|
+
// Update counter
|
|
70
|
+
ledger.counter.increment(amount);
|
|
71
|
+
|
|
72
|
+
// Return new value
|
|
73
|
+
return ledger.counter.value();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Decrement the counter
|
|
77
|
+
export circuit decrement(amount: Field): Field {
|
|
78
|
+
// Validate input
|
|
79
|
+
assert(amount > 0, "Amount must be positive");
|
|
80
|
+
assert(ledger.counter.value() >= amount, "Counter would go negative");
|
|
81
|
+
|
|
82
|
+
// Update counter
|
|
83
|
+
ledger.counter.decrement(amount);
|
|
84
|
+
|
|
85
|
+
// Return new value
|
|
86
|
+
return ledger.counter.value();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Read current value (view function)
|
|
90
|
+
export circuit getValue(): Field {
|
|
91
|
+
return ledger.counter.value();
|
|
92
|
+
}
|
|
93
|
+
`,
|
|
94
|
+
"midnight://code/examples/bboard": `// Bulletin Board Example Contract
|
|
95
|
+
// Demonstrates private messaging with selective disclosure
|
|
96
|
+
|
|
97
|
+
include "std";
|
|
98
|
+
|
|
99
|
+
ledger {
|
|
100
|
+
// Public: message count and IDs
|
|
101
|
+
messageCount: Counter;
|
|
102
|
+
messageIds: Set<Field>;
|
|
103
|
+
|
|
104
|
+
// Private: actual message contents
|
|
105
|
+
@private
|
|
106
|
+
messages: Map<Field, Opaque<"string">>;
|
|
107
|
+
|
|
108
|
+
// Private: message authors
|
|
109
|
+
@private
|
|
110
|
+
authors: Map<Field, Opaque<"address">>;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Post a new message (content is private)
|
|
114
|
+
export circuit postMessage(content: Opaque<"string">, author: Opaque<"address">): Field {
|
|
115
|
+
// Generate unique message ID
|
|
116
|
+
const messageId = ledger.messageCount.value();
|
|
117
|
+
|
|
118
|
+
// Store message privately
|
|
119
|
+
ledger.messages.insert(messageId, content);
|
|
120
|
+
ledger.authors.insert(messageId, author);
|
|
121
|
+
|
|
122
|
+
// Update public counters
|
|
123
|
+
ledger.messageCount.increment(1);
|
|
124
|
+
ledger.messageIds.add(messageId);
|
|
125
|
+
|
|
126
|
+
return messageId;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Witness to fetch message content
|
|
130
|
+
witness getMessageContent(id: Field): Opaque<"string"> {
|
|
131
|
+
return ledger.messages.get(id);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Reveal a message publicly (owner's choice)
|
|
135
|
+
export circuit revealMessage(id: Field): Opaque<"string"> {
|
|
136
|
+
assert(ledger.messageIds.contains(id), "Message not found");
|
|
137
|
+
|
|
138
|
+
const content = getMessageContent(id);
|
|
139
|
+
return disclose(content);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Get total message count
|
|
143
|
+
export circuit getMessageCount(): Field {
|
|
144
|
+
return ledger.messageCount.value();
|
|
145
|
+
}
|
|
146
|
+
`,
|
|
147
|
+
"midnight://code/patterns/state-management": `// State Management Pattern
|
|
148
|
+
// Best practices for managing public and private state
|
|
149
|
+
|
|
150
|
+
include "std";
|
|
151
|
+
|
|
152
|
+
ledger {
|
|
153
|
+
// PUBLIC STATE
|
|
154
|
+
// - Use for data that should be transparent
|
|
155
|
+
// - Visible in blockchain explorers
|
|
156
|
+
// - Can be queried by anyone
|
|
157
|
+
|
|
158
|
+
totalSupply: Counter;
|
|
159
|
+
publicConfig: Field;
|
|
160
|
+
|
|
161
|
+
// PRIVATE STATE
|
|
162
|
+
// - Use for sensitive user data
|
|
163
|
+
// - Only owner can read
|
|
164
|
+
// - Requires witnesses to access in circuits
|
|
165
|
+
|
|
166
|
+
@private
|
|
167
|
+
userSecrets: Map<Opaque<"address">, Bytes<32>>;
|
|
168
|
+
|
|
169
|
+
@private
|
|
170
|
+
privateBalances: Map<Opaque<"address">, Field>;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Reading public state is straightforward
|
|
174
|
+
export circuit getTotalSupply(): Field {
|
|
175
|
+
return ledger.totalSupply.value();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Reading private state requires a witness
|
|
179
|
+
witness getUserSecret(user: Opaque<"address">): Bytes<32> {
|
|
180
|
+
return ledger.userSecrets.get(user);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Using private state in a circuit
|
|
184
|
+
export circuit proveSecretKnowledge(
|
|
185
|
+
user: Opaque<"address">,
|
|
186
|
+
secretHash: Bytes<32>
|
|
187
|
+
): Boolean {
|
|
188
|
+
const secret = getUserSecret(user);
|
|
189
|
+
|
|
190
|
+
// Prove knowledge without revealing secret
|
|
191
|
+
assert(hash(secret) == secretHash);
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Selective disclosure pattern
|
|
196
|
+
export circuit revealBalance(user: Opaque<"address">): Field {
|
|
197
|
+
const balance = getPrivateBalance(user);
|
|
198
|
+
// Explicitly reveal - user's choice
|
|
199
|
+
return disclose(balance);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
witness getPrivateBalance(user: Opaque<"address">): Field {
|
|
203
|
+
return ledger.privateBalances.get(user);
|
|
204
|
+
}
|
|
205
|
+
`,
|
|
206
|
+
"midnight://code/patterns/access-control": `// Access Control Pattern
|
|
207
|
+
// Implementing permissions and authorization
|
|
208
|
+
|
|
209
|
+
include "std";
|
|
210
|
+
|
|
211
|
+
ledger {
|
|
212
|
+
// Role definitions
|
|
213
|
+
owner: Opaque<"address">;
|
|
214
|
+
admins: Set<Opaque<"address">>;
|
|
215
|
+
|
|
216
|
+
// Access-controlled state
|
|
217
|
+
sensitiveData: Field;
|
|
218
|
+
|
|
219
|
+
@private
|
|
220
|
+
adminKeys: Map<Opaque<"address">, Bytes<32>>;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Witness to get caller identity
|
|
224
|
+
witness getCaller(): Opaque<"address"> {
|
|
225
|
+
return getCurrentCaller();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Only owner can call
|
|
229
|
+
export circuit onlyOwnerAction(newValue: Field): Void {
|
|
230
|
+
const caller = getCaller();
|
|
231
|
+
assert(caller == ledger.owner, "Not owner");
|
|
232
|
+
|
|
233
|
+
ledger.sensitiveData = newValue;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Only admins can call
|
|
237
|
+
export circuit onlyAdminAction(data: Field): Void {
|
|
238
|
+
const caller = getCaller();
|
|
239
|
+
assert(ledger.admins.contains(caller), "Not admin");
|
|
240
|
+
|
|
241
|
+
// Admin action here
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Multi-sig pattern (require multiple approvals)
|
|
245
|
+
witness getApprovalCount(action: Bytes<32>): Field {
|
|
246
|
+
return countApprovals(action);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export circuit requireMultisig(action: Bytes<32>, threshold: Field): Boolean {
|
|
250
|
+
const approvals = getApprovalCount(action);
|
|
251
|
+
assert(approvals >= threshold, "Insufficient approvals");
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Time-locked action
|
|
256
|
+
witness getCurrentTime(): Field {
|
|
257
|
+
return getBlockTimestamp();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export circuit timeLockedAction(unlockTime: Field): Void {
|
|
261
|
+
const currentTime = getCurrentTime();
|
|
262
|
+
assert(currentTime >= unlockTime, "Action is timelocked");
|
|
263
|
+
|
|
264
|
+
// Perform action
|
|
265
|
+
}
|
|
266
|
+
`,
|
|
267
|
+
"midnight://code/patterns/privacy-preserving": `// Privacy-Preserving Patterns
|
|
268
|
+
// Techniques for maintaining privacy in smart contracts
|
|
269
|
+
|
|
270
|
+
include "std";
|
|
271
|
+
|
|
272
|
+
ledger {
|
|
273
|
+
// Commitment-based private balance
|
|
274
|
+
balanceCommitments: Map<Opaque<"address">, Field>;
|
|
275
|
+
|
|
276
|
+
// Nullifier set (prevents double-spending)
|
|
277
|
+
nullifiers: Set<Field>;
|
|
278
|
+
|
|
279
|
+
@private
|
|
280
|
+
secretBalances: Map<Opaque<"address">, Field>;
|
|
281
|
+
|
|
282
|
+
@private
|
|
283
|
+
secretNonces: Map<Opaque<"address">, Field>;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// PATTERN 1: Commitment Scheme
|
|
287
|
+
// Store commitments instead of values
|
|
288
|
+
|
|
289
|
+
export circuit deposit(
|
|
290
|
+
user: Opaque<"address">,
|
|
291
|
+
amount: Field,
|
|
292
|
+
nonce: Field
|
|
293
|
+
): Field {
|
|
294
|
+
// Create commitment: hash(amount, nonce, user)
|
|
295
|
+
const commitment = hash(amount, nonce, user);
|
|
296
|
+
|
|
297
|
+
// Store commitment (hides amount)
|
|
298
|
+
ledger.balanceCommitments.insert(user, commitment);
|
|
299
|
+
|
|
300
|
+
return commitment;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export circuit proveBalance(
|
|
304
|
+
user: Opaque<"address">,
|
|
305
|
+
amount: Field,
|
|
306
|
+
nonce: Field,
|
|
307
|
+
minBalance: Field
|
|
308
|
+
): Boolean {
|
|
309
|
+
// Verify commitment
|
|
310
|
+
const expectedCommitment = hash(amount, nonce, user);
|
|
311
|
+
assert(ledger.balanceCommitments.get(user) == expectedCommitment);
|
|
312
|
+
|
|
313
|
+
// Prove property without revealing value
|
|
314
|
+
assert(amount >= minBalance);
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// PATTERN 2: Nullifiers (Prevent Double-Spending)
|
|
319
|
+
|
|
320
|
+
witness generateNullifier(secret: Bytes<32>, action: Field): Field {
|
|
321
|
+
return hash(secret, action);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export circuit spendOnce(
|
|
325
|
+
secret: Bytes<32>,
|
|
326
|
+
action: Field
|
|
327
|
+
): Void {
|
|
328
|
+
const nullifier = generateNullifier(secret, action);
|
|
329
|
+
|
|
330
|
+
// Check nullifier hasn't been used
|
|
331
|
+
assert(!ledger.nullifiers.contains(nullifier), "Already spent");
|
|
332
|
+
|
|
333
|
+
// Mark as used
|
|
334
|
+
ledger.nullifiers.add(nullifier);
|
|
335
|
+
|
|
336
|
+
// Perform action
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// PATTERN 3: Range Proofs
|
|
340
|
+
|
|
341
|
+
export circuit proveInRange(
|
|
342
|
+
@private value: Field,
|
|
343
|
+
min: Field,
|
|
344
|
+
max: Field
|
|
345
|
+
): Boolean {
|
|
346
|
+
// Prove value is in range without revealing it
|
|
347
|
+
assert(value >= min);
|
|
348
|
+
assert(value <= max);
|
|
349
|
+
return true;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// PATTERN 4: Private Set Membership
|
|
353
|
+
|
|
354
|
+
export circuit proveMembership(
|
|
355
|
+
@private element: Field,
|
|
356
|
+
setRoot: Field,
|
|
357
|
+
@private proof: Array<Field>
|
|
358
|
+
): Boolean {
|
|
359
|
+
// Prove element is in set without revealing which element
|
|
360
|
+
const computedRoot = computeMerkleRoot(element, proof);
|
|
361
|
+
assert(computedRoot == setRoot);
|
|
362
|
+
return true;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
witness computeMerkleRoot(element: Field, proof: Array<Field>): Field {
|
|
366
|
+
// Compute Merkle root from element and proof
|
|
367
|
+
return merkleCompute(element, proof);
|
|
368
|
+
}
|
|
369
|
+
`,
|
|
370
|
+
"midnight://code/templates/token": `// Privacy-Preserving Token Template
|
|
371
|
+
// Starter template for token contracts with privacy features
|
|
372
|
+
|
|
373
|
+
include "std";
|
|
374
|
+
|
|
375
|
+
ledger {
|
|
376
|
+
// Public token metadata
|
|
377
|
+
name: Opaque<"string">;
|
|
378
|
+
symbol: Opaque<"string">;
|
|
379
|
+
decimals: Field;
|
|
380
|
+
totalSupply: Counter;
|
|
381
|
+
|
|
382
|
+
// Private balances
|
|
383
|
+
@private
|
|
384
|
+
balances: Map<Opaque<"address">, Field>;
|
|
385
|
+
|
|
386
|
+
// Private allowances
|
|
387
|
+
@private
|
|
388
|
+
allowances: Map<Opaque<"address">, Map<Opaque<"address">, Field>>;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Witnesses for private state access
|
|
392
|
+
witness getBalance(account: Opaque<"address">): Field {
|
|
393
|
+
return ledger.balances.get(account) ?? 0;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
witness getAllowance(owner: Opaque<"address">, spender: Opaque<"address">): Field {
|
|
397
|
+
return ledger.allowances.get(owner)?.get(spender) ?? 0;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
witness getCaller(): Opaque<"address"> {
|
|
401
|
+
return getCurrentCaller();
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Transfer tokens privately
|
|
405
|
+
export circuit transfer(
|
|
406
|
+
to: Opaque<"address">,
|
|
407
|
+
amount: Field
|
|
408
|
+
): Boolean {
|
|
409
|
+
const from = getCaller();
|
|
410
|
+
const fromBalance = getBalance(from);
|
|
411
|
+
|
|
412
|
+
// Validate
|
|
413
|
+
assert(amount > 0, "Invalid amount");
|
|
414
|
+
assert(fromBalance >= amount, "Insufficient balance");
|
|
415
|
+
|
|
416
|
+
// Update balances privately
|
|
417
|
+
ledger.balances.insert(from, fromBalance - amount);
|
|
418
|
+
ledger.balances.insert(to, getBalance(to) + amount);
|
|
419
|
+
|
|
420
|
+
return true;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Approve spender
|
|
424
|
+
export circuit approve(
|
|
425
|
+
spender: Opaque<"address">,
|
|
426
|
+
amount: Field
|
|
427
|
+
): Boolean {
|
|
428
|
+
const owner = getCaller();
|
|
429
|
+
|
|
430
|
+
// Get or create allowance map for owner
|
|
431
|
+
// Note: Simplified - actual implementation needs nested map handling
|
|
432
|
+
ledger.allowances.get(owner).insert(spender, amount);
|
|
433
|
+
|
|
434
|
+
return true;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Transfer from approved account
|
|
438
|
+
export circuit transferFrom(
|
|
439
|
+
from: Opaque<"address">,
|
|
440
|
+
to: Opaque<"address">,
|
|
441
|
+
amount: Field
|
|
442
|
+
): Boolean {
|
|
443
|
+
const spender = getCaller();
|
|
444
|
+
const allowance = getAllowance(from, spender);
|
|
445
|
+
const fromBalance = getBalance(from);
|
|
446
|
+
|
|
447
|
+
// Validate
|
|
448
|
+
assert(amount > 0, "Invalid amount");
|
|
449
|
+
assert(allowance >= amount, "Insufficient allowance");
|
|
450
|
+
assert(fromBalance >= amount, "Insufficient balance");
|
|
451
|
+
|
|
452
|
+
// Update state
|
|
453
|
+
ledger.balances.insert(from, fromBalance - amount);
|
|
454
|
+
ledger.balances.insert(to, getBalance(to) + amount);
|
|
455
|
+
ledger.allowances.get(from).insert(spender, allowance - amount);
|
|
456
|
+
|
|
457
|
+
return true;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Reveal balance (user's choice)
|
|
461
|
+
export circuit revealMyBalance(): Field {
|
|
462
|
+
const caller = getCaller();
|
|
463
|
+
const balance = getBalance(caller);
|
|
464
|
+
return disclose(balance);
|
|
465
|
+
}
|
|
466
|
+
`,
|
|
467
|
+
"midnight://code/templates/voting": `// Private Voting Template
|
|
468
|
+
// Starter template for privacy-preserving voting contracts
|
|
469
|
+
|
|
470
|
+
include "std";
|
|
471
|
+
|
|
472
|
+
ledger {
|
|
473
|
+
// Public: proposal metadata
|
|
474
|
+
proposalCount: Counter;
|
|
475
|
+
proposals: Map<Field, Opaque<"string">>;
|
|
476
|
+
votingDeadlines: Map<Field, Field>;
|
|
477
|
+
|
|
478
|
+
// Public: vote tallies (revealed after voting ends)
|
|
479
|
+
finalTallies: Map<Field, Map<Field, Field>>; // proposalId -> optionId -> count
|
|
480
|
+
|
|
481
|
+
// Private: individual votes
|
|
482
|
+
@private
|
|
483
|
+
votes: Map<Field, Map<Opaque<"address">, Field>>; // proposalId -> voter -> option
|
|
484
|
+
|
|
485
|
+
// Nullifiers to prevent double voting
|
|
486
|
+
voteNullifiers: Set<Field>;
|
|
487
|
+
|
|
488
|
+
// Eligible voters
|
|
489
|
+
eligibleVoters: Set<Opaque<"address">>;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Witnesses
|
|
493
|
+
witness getCaller(): Opaque<"address"> {
|
|
494
|
+
return getCurrentCaller();
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
witness getCurrentTime(): Field {
|
|
498
|
+
return getBlockTimestamp();
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
witness getVote(proposalId: Field, voter: Opaque<"address">): Field {
|
|
502
|
+
return ledger.votes.get(proposalId)?.get(voter) ?? 0;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
witness computeNullifier(voter: Opaque<"address">, proposalId: Field): Field {
|
|
506
|
+
return hash(voter, proposalId);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// Create a new proposal
|
|
510
|
+
export circuit createProposal(
|
|
511
|
+
description: Opaque<"string">,
|
|
512
|
+
deadline: Field,
|
|
513
|
+
options: Field
|
|
514
|
+
): Field {
|
|
515
|
+
const proposalId = ledger.proposalCount.value();
|
|
516
|
+
|
|
517
|
+
// Store proposal
|
|
518
|
+
ledger.proposals.insert(proposalId, description);
|
|
519
|
+
ledger.votingDeadlines.insert(proposalId, deadline);
|
|
520
|
+
|
|
521
|
+
// Initialize tally for each option
|
|
522
|
+
// (Simplified - actual implementation needs loop)
|
|
523
|
+
|
|
524
|
+
ledger.proposalCount.increment(1);
|
|
525
|
+
return proposalId;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// Cast a private vote
|
|
529
|
+
export circuit vote(
|
|
530
|
+
proposalId: Field,
|
|
531
|
+
option: Field
|
|
532
|
+
): Boolean {
|
|
533
|
+
const voter = getCaller();
|
|
534
|
+
const currentTime = getCurrentTime();
|
|
535
|
+
|
|
536
|
+
// Check eligibility
|
|
537
|
+
assert(ledger.eligibleVoters.contains(voter), "Not eligible to vote");
|
|
538
|
+
|
|
539
|
+
// Check deadline
|
|
540
|
+
const deadline = ledger.votingDeadlines.get(proposalId);
|
|
541
|
+
assert(currentTime < deadline, "Voting ended");
|
|
542
|
+
|
|
543
|
+
// Check for double voting using nullifier
|
|
544
|
+
const nullifier = computeNullifier(voter, proposalId);
|
|
545
|
+
assert(!ledger.voteNullifiers.contains(nullifier), "Already voted");
|
|
546
|
+
|
|
547
|
+
// Record vote privately
|
|
548
|
+
ledger.votes.get(proposalId).insert(voter, option);
|
|
549
|
+
|
|
550
|
+
// Add nullifier to prevent double voting
|
|
551
|
+
ledger.voteNullifiers.add(nullifier);
|
|
552
|
+
|
|
553
|
+
return true;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// Reveal individual vote (voter's choice)
|
|
557
|
+
export circuit revealMyVote(proposalId: Field): Field {
|
|
558
|
+
const voter = getCaller();
|
|
559
|
+
const myVote = getVote(proposalId, voter);
|
|
560
|
+
return disclose(myVote);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// Tally votes (after deadline)
|
|
564
|
+
// Note: This is simplified - real implementation would need
|
|
565
|
+
// a mechanism to privately aggregate votes
|
|
566
|
+
export circuit tallyVotes(proposalId: Field): Boolean {
|
|
567
|
+
const currentTime = getCurrentTime();
|
|
568
|
+
const deadline = ledger.votingDeadlines.get(proposalId);
|
|
569
|
+
|
|
570
|
+
assert(currentTime >= deadline, "Voting still active");
|
|
571
|
+
|
|
572
|
+
// In a real implementation, votes would be aggregated
|
|
573
|
+
// using homomorphic encryption or MPC
|
|
574
|
+
|
|
575
|
+
return true;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// Add eligible voter (admin only)
|
|
579
|
+
export circuit addVoter(voter: Opaque<"address">): Void {
|
|
580
|
+
// Add access control in real implementation
|
|
581
|
+
ledger.eligibleVoters.add(voter);
|
|
582
|
+
}
|
|
583
|
+
`,
|
|
584
|
+
};
|
|
585
|
+
/**
|
|
586
|
+
* Get code content by URI
|
|
587
|
+
*/
|
|
588
|
+
export async function getCode(uri) {
|
|
589
|
+
// Check embedded code first
|
|
590
|
+
if (EMBEDDED_CODE[uri]) {
|
|
591
|
+
return EMBEDDED_CODE[uri];
|
|
592
|
+
}
|
|
593
|
+
// Try to fetch from GitHub for example paths
|
|
594
|
+
if (uri.startsWith("midnight://code/examples/")) {
|
|
595
|
+
const exampleName = uri.replace("midnight://code/examples/", "");
|
|
596
|
+
try {
|
|
597
|
+
// Map example names to repositories
|
|
598
|
+
const repoMap = {
|
|
599
|
+
counter: {
|
|
600
|
+
owner: "midnightntwrk",
|
|
601
|
+
repo: "example-counter",
|
|
602
|
+
path: "contract/src/counter.compact",
|
|
603
|
+
},
|
|
604
|
+
bboard: {
|
|
605
|
+
owner: "midnightntwrk",
|
|
606
|
+
repo: "example-bboard",
|
|
607
|
+
path: "contract/src/bboard.compact",
|
|
608
|
+
},
|
|
609
|
+
};
|
|
610
|
+
const mapping = repoMap[exampleName];
|
|
611
|
+
if (mapping) {
|
|
612
|
+
const file = await githubClient.getFileContent(mapping.owner, mapping.repo, mapping.path);
|
|
613
|
+
if (file) {
|
|
614
|
+
return file.content;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
catch (error) {
|
|
619
|
+
logger.warn(`Could not fetch code from GitHub: ${uri}`);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
return null;
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* List all available code resources
|
|
626
|
+
*/
|
|
627
|
+
export function listCodeResources() {
|
|
628
|
+
return codeResources;
|
|
629
|
+
}
|
|
630
|
+
//# sourceMappingURL=code.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code.js","sourceRoot":"","sources":["../../src/resources/code.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface ResourceDefinition {
|
|
2
|
+
uri: string;
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
mimeType: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const documentationResources: ResourceDefinition[];
|
|
8
|
+
/**
|
|
9
|
+
* Get documentation content by URI
|
|
10
|
+
*/
|
|
11
|
+
export declare function getDocumentation(uri: string): Promise<string | null>;
|
|
12
|
+
/**
|
|
13
|
+
* List all available documentation resources
|
|
14
|
+
*/
|
|
15
|
+
export declare function listDocumentationResources(): ResourceDefinition[];
|
|
16
|
+
//# sourceMappingURL=docs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/resources/docs.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAGD,eAAO,MAAM,sBAAsB,EAAE,kBAAkB,EAqEtD,CAAC;AAy4BF;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAyB1E;AAED;;GAEG;AACH,wBAAgB,0BAA0B,IAAI,kBAAkB,EAAE,CAEjE"}
|