midnight-mcp 0.1.34 → 0.1.36
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.
|
@@ -65,4 +65,107 @@ export declare function getVersionInfo(): string;
|
|
|
65
65
|
* Check if a version is within supported range
|
|
66
66
|
*/
|
|
67
67
|
export declare function isVersionSupported(version: string): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Built-in functions vs patterns you must implement yourself
|
|
70
|
+
* CRITICAL: These are the actual stdlib functions available in Compact
|
|
71
|
+
*/
|
|
72
|
+
export declare const BUILTIN_FUNCTIONS: {
|
|
73
|
+
/** Actually built into the language/stdlib */
|
|
74
|
+
stdlib: {
|
|
75
|
+
name: string;
|
|
76
|
+
signature: string;
|
|
77
|
+
description: string;
|
|
78
|
+
}[];
|
|
79
|
+
/** NOT built-in - you must implement these patterns yourself */
|
|
80
|
+
notBuiltIn: {
|
|
81
|
+
name: string;
|
|
82
|
+
wrongUsage: string;
|
|
83
|
+
correctPattern: string;
|
|
84
|
+
description: string;
|
|
85
|
+
}[];
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Type compatibility rules - what types can be compared/operated together
|
|
89
|
+
*/
|
|
90
|
+
export declare const TYPE_COMPATIBILITY: {
|
|
91
|
+
comparisons: ({
|
|
92
|
+
types: string;
|
|
93
|
+
works: boolean;
|
|
94
|
+
note: string;
|
|
95
|
+
fix?: undefined;
|
|
96
|
+
} | {
|
|
97
|
+
types: string;
|
|
98
|
+
works: boolean;
|
|
99
|
+
fix: string;
|
|
100
|
+
note?: undefined;
|
|
101
|
+
})[];
|
|
102
|
+
arithmetic: ({
|
|
103
|
+
types: string;
|
|
104
|
+
works: boolean;
|
|
105
|
+
note: string;
|
|
106
|
+
fix?: undefined;
|
|
107
|
+
} | {
|
|
108
|
+
types: string;
|
|
109
|
+
works: boolean;
|
|
110
|
+
fix: string;
|
|
111
|
+
note?: undefined;
|
|
112
|
+
})[];
|
|
113
|
+
assignments: {
|
|
114
|
+
types: string;
|
|
115
|
+
works: boolean;
|
|
116
|
+
fix: string;
|
|
117
|
+
}[];
|
|
118
|
+
tips: string[];
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Ledger type limitations - what works in circuits vs TypeScript
|
|
122
|
+
*/
|
|
123
|
+
export declare const LEDGER_TYPE_LIMITS: {
|
|
124
|
+
Counter: {
|
|
125
|
+
circuitOperations: {
|
|
126
|
+
method: string;
|
|
127
|
+
works: boolean;
|
|
128
|
+
note: string;
|
|
129
|
+
}[];
|
|
130
|
+
typescriptAccess: string;
|
|
131
|
+
reason: string;
|
|
132
|
+
};
|
|
133
|
+
Map: {
|
|
134
|
+
circuitOperations: {
|
|
135
|
+
method: string;
|
|
136
|
+
works: boolean;
|
|
137
|
+
note: string;
|
|
138
|
+
}[];
|
|
139
|
+
typescriptAccess: string;
|
|
140
|
+
reason: string;
|
|
141
|
+
pattern: string;
|
|
142
|
+
};
|
|
143
|
+
Set: {
|
|
144
|
+
circuitOperations: {
|
|
145
|
+
method: string;
|
|
146
|
+
works: boolean;
|
|
147
|
+
note: string;
|
|
148
|
+
}[];
|
|
149
|
+
typescriptAccess: string;
|
|
150
|
+
reason: string;
|
|
151
|
+
};
|
|
152
|
+
MerkleTree: {
|
|
153
|
+
circuitOperations: {
|
|
154
|
+
method: string;
|
|
155
|
+
works: boolean;
|
|
156
|
+
note: string;
|
|
157
|
+
}[];
|
|
158
|
+
typescriptAccess: string;
|
|
159
|
+
pattern: string;
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Common compilation errors with their fixes
|
|
164
|
+
* Maps actual compiler error messages to solutions
|
|
165
|
+
*/
|
|
166
|
+
export declare const COMMON_ERRORS: {
|
|
167
|
+
error: string;
|
|
168
|
+
cause: string;
|
|
169
|
+
fix: string;
|
|
170
|
+
}[];
|
|
68
171
|
//# sourceMappingURL=compact-version.d.ts.map
|
|
@@ -92,4 +92,271 @@ export function isVersionSupported(version) {
|
|
|
92
92
|
const maxNum = maxMajor * 100 + maxMinor;
|
|
93
93
|
return versionNum >= minNum && versionNum <= maxNum;
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Built-in functions vs patterns you must implement yourself
|
|
97
|
+
* CRITICAL: These are the actual stdlib functions available in Compact
|
|
98
|
+
*/
|
|
99
|
+
export const BUILTIN_FUNCTIONS = {
|
|
100
|
+
/** Actually built into the language/stdlib */
|
|
101
|
+
stdlib: [
|
|
102
|
+
{
|
|
103
|
+
name: "persistentHash",
|
|
104
|
+
signature: "persistentHash<T>(value: T): Bytes<32>",
|
|
105
|
+
description: "Poseidon hash that produces consistent results across calls",
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: "persistentCommit",
|
|
109
|
+
signature: "persistentCommit<T>(value: T): Bytes<32>",
|
|
110
|
+
description: "Creates a hiding commitment to a value",
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: "pad",
|
|
114
|
+
signature: "pad(length: number, value: string): Bytes<N>",
|
|
115
|
+
description: "Pads a string to fixed-length bytes",
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: "disclose",
|
|
119
|
+
signature: "disclose(value: T): T",
|
|
120
|
+
description: "Explicitly reveals a witness value (required in conditionals)",
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: "assert",
|
|
124
|
+
signature: "assert(condition: Boolean, message?: string): []",
|
|
125
|
+
description: "Fails circuit if condition is false",
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: "default",
|
|
129
|
+
signature: "default<T>(): T",
|
|
130
|
+
description: "Returns default value for a type (0 for numbers, empty for collections)",
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
/** NOT built-in - you must implement these patterns yourself */
|
|
134
|
+
notBuiltIn: [
|
|
135
|
+
{
|
|
136
|
+
name: "public_key",
|
|
137
|
+
wrongUsage: "public_key(sk) // ERROR: unbound identifier",
|
|
138
|
+
correctPattern: `// Derive public key using persistentHash
|
|
139
|
+
const pk = persistentHash<Vector<2, Bytes<32>>>([
|
|
140
|
+
pad(32, "midnight:pk:"),
|
|
141
|
+
sk
|
|
142
|
+
]);`,
|
|
143
|
+
description: "Public key derivation is NOT a builtin - use persistentHash pattern",
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
name: "verify_signature",
|
|
147
|
+
wrongUsage: "verify_signature(msg, sig, pk) // Does not exist",
|
|
148
|
+
correctPattern: `// Signature verification must be done via witnesses
|
|
149
|
+
// The prover verifies off-chain, then provides the boolean result
|
|
150
|
+
witness signature_valid(): Boolean;`,
|
|
151
|
+
description: "Signature verification is done off-chain in the prover",
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: "random",
|
|
155
|
+
wrongUsage: "random() // Does not exist in ZK circuits",
|
|
156
|
+
correctPattern: `// Randomness must come from witnesses (prover-provided)
|
|
157
|
+
witness get_random_value(): Field;`,
|
|
158
|
+
description: "ZK circuits are deterministic - randomness must come from witnesses",
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Type compatibility rules - what types can be compared/operated together
|
|
164
|
+
*/
|
|
165
|
+
export const TYPE_COMPATIBILITY = {
|
|
166
|
+
comparisons: [
|
|
167
|
+
{ types: "Field == Field", works: true, note: "Direct comparison" },
|
|
168
|
+
{
|
|
169
|
+
types: "Field == Uint<N>",
|
|
170
|
+
works: false,
|
|
171
|
+
fix: "Cast with `value as Field`",
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
types: "Field >= 0",
|
|
175
|
+
works: false,
|
|
176
|
+
fix: "Use bounded Uint<0..N> parameter instead",
|
|
177
|
+
},
|
|
178
|
+
{ types: "Uint<N> == Uint<N>", works: true, note: "Same-width comparison" },
|
|
179
|
+
{
|
|
180
|
+
types: "Uint<0..2> == Uint<0..2>",
|
|
181
|
+
works: true,
|
|
182
|
+
note: "Bounded integers",
|
|
183
|
+
},
|
|
184
|
+
{ types: "Bytes<32> == Bytes<32>", works: true, note: "Direct comparison" },
|
|
185
|
+
{ types: "Boolean == Boolean", works: true, note: "Direct comparison" },
|
|
186
|
+
],
|
|
187
|
+
arithmetic: [
|
|
188
|
+
{ types: "Field + Field", works: true, note: "Field arithmetic" },
|
|
189
|
+
{ types: "Field + Uint<N>", works: false, fix: "Cast Uint to Field first" },
|
|
190
|
+
{
|
|
191
|
+
types: "Uint<N> + Uint<N>",
|
|
192
|
+
works: true,
|
|
193
|
+
note: "Must fit in result width",
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
assignments: [
|
|
197
|
+
{
|
|
198
|
+
types: "Field = Uint<N>",
|
|
199
|
+
works: false,
|
|
200
|
+
fix: "Cast with `value as Field`",
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
types: "Uint<N> = Field",
|
|
204
|
+
works: false,
|
|
205
|
+
fix: "Use bounded param or explicit cast",
|
|
206
|
+
},
|
|
207
|
+
],
|
|
208
|
+
tips: [
|
|
209
|
+
"Use Uint<0..N> for circuit parameters that need range validation",
|
|
210
|
+
"Field is unbounded - use for hashes, commitments, general computation",
|
|
211
|
+
"Uint<N> is bounded - use when you need range checks",
|
|
212
|
+
"Casting with `as Field` is safe but loses range information",
|
|
213
|
+
],
|
|
214
|
+
};
|
|
215
|
+
/**
|
|
216
|
+
* Ledger type limitations - what works in circuits vs TypeScript
|
|
217
|
+
*/
|
|
218
|
+
export const LEDGER_TYPE_LIMITS = {
|
|
219
|
+
Counter: {
|
|
220
|
+
circuitOperations: [
|
|
221
|
+
{ method: ".increment(n)", works: true, note: "Adds n to counter" },
|
|
222
|
+
{
|
|
223
|
+
method: ".decrement(n)",
|
|
224
|
+
works: true,
|
|
225
|
+
note: "Subtracts n from counter",
|
|
226
|
+
},
|
|
227
|
+
{ method: ".resetToDefault()", works: true, note: "Resets to 0" },
|
|
228
|
+
{ method: ".value()", works: false, note: "NOT available in circuits" },
|
|
229
|
+
],
|
|
230
|
+
typescriptAccess: "Access counter value via `ledgerState.counter` in TypeScript SDK",
|
|
231
|
+
reason: "ZK circuits cannot read current ledger state - only modify it",
|
|
232
|
+
},
|
|
233
|
+
Map: {
|
|
234
|
+
circuitOperations: [
|
|
235
|
+
{
|
|
236
|
+
method: ".insert(key, value)",
|
|
237
|
+
works: true,
|
|
238
|
+
note: "Adds/updates entry",
|
|
239
|
+
},
|
|
240
|
+
{ method: ".remove(key)", works: true, note: "Removes entry" },
|
|
241
|
+
{
|
|
242
|
+
method: ".lookup(key)",
|
|
243
|
+
works: false,
|
|
244
|
+
note: "NOT available in circuits",
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
method: ".member(key)",
|
|
248
|
+
works: false,
|
|
249
|
+
note: "NOT available in circuits",
|
|
250
|
+
},
|
|
251
|
+
],
|
|
252
|
+
typescriptAccess: "Query map via `contractState.data.get(key)` in TypeScript SDK",
|
|
253
|
+
reason: "ZK circuits prove transitions, not current state. Use witnesses for reads.",
|
|
254
|
+
pattern: `// To read a map value in a circuit, use a witness:
|
|
255
|
+
witness get_stored_value(key: Bytes<32>): Field;
|
|
256
|
+
|
|
257
|
+
export circuit update_if_exists(key: Bytes<32>, new_value: Field): [] {
|
|
258
|
+
const current = get_stored_value(key); // Prover fetches from ledger
|
|
259
|
+
// ... use current value
|
|
260
|
+
data.insert(key, new_value); // Update is allowed
|
|
261
|
+
}`,
|
|
262
|
+
},
|
|
263
|
+
Set: {
|
|
264
|
+
circuitOperations: [
|
|
265
|
+
{ method: ".insert(value)", works: true, note: "Adds to set" },
|
|
266
|
+
{ method: ".remove(value)", works: true, note: "Removes from set" },
|
|
267
|
+
{
|
|
268
|
+
method: ".member(value)",
|
|
269
|
+
works: false,
|
|
270
|
+
note: "NOT available in circuits",
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
typescriptAccess: "Check membership via `contractState.set.has(value)` in TypeScript SDK",
|
|
274
|
+
reason: "Same as Map - use witnesses for membership checks",
|
|
275
|
+
},
|
|
276
|
+
MerkleTree: {
|
|
277
|
+
circuitOperations: [
|
|
278
|
+
{ method: ".insert(leaf)", works: true, note: "Adds leaf to tree" },
|
|
279
|
+
{ method: ".root()", works: false, note: "NOT available in circuits" },
|
|
280
|
+
],
|
|
281
|
+
typescriptAccess: "Get root via `contractState.tree.root` in TypeScript SDK",
|
|
282
|
+
pattern: `// To verify a merkle proof in circuit:
|
|
283
|
+
witness get_merkle_root(): Bytes<32>;
|
|
284
|
+
witness get_merkle_proof(leaf: Bytes<32>): Vector<32, Bytes<32>>;
|
|
285
|
+
|
|
286
|
+
// Verify proof using persistentHash to compute expected root`,
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
/**
|
|
290
|
+
* Common compilation errors with their fixes
|
|
291
|
+
* Maps actual compiler error messages to solutions
|
|
292
|
+
*/
|
|
293
|
+
export const COMMON_ERRORS = [
|
|
294
|
+
{
|
|
295
|
+
error: 'unbound identifier "public_key"',
|
|
296
|
+
cause: "Trying to use public_key() as if it's a builtin function",
|
|
297
|
+
fix: `Use persistentHash pattern instead:
|
|
298
|
+
const pk = persistentHash<Vector<2, Bytes<32>>>([pad(32, "midnight:pk:"), sk]);`,
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
error: "incompatible combination of types Field and Uint",
|
|
302
|
+
cause: "Comparing or operating on Field with Uint without casting",
|
|
303
|
+
fix: `Cast Uint to Field: (myUint as Field)
|
|
304
|
+
Or use bounded Uint<0..N> for parameters that need constraints`,
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
error: 'operation "value" undefined for ledger field type Counter',
|
|
308
|
+
cause: "Trying to read Counter.value() inside a circuit",
|
|
309
|
+
fix: `Counter values cannot be read in circuits. Options:
|
|
310
|
+
1. Use a witness: witness get_counter_value(): Uint<64>;
|
|
311
|
+
2. Read from TypeScript SDK: ledgerState.counter
|
|
312
|
+
3. Track the value in a separate Field ledger variable`,
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
error: "implicit disclosure of witness value",
|
|
316
|
+
cause: "Using witness value in conditional without disclose()",
|
|
317
|
+
fix: `Wrap witness comparisons in disclose():
|
|
318
|
+
if (disclose(witness_value == expected)) { ... }`,
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
error: 'parse error: found "{" looking for an identifier',
|
|
322
|
+
cause: "Using old ledger { } block syntax",
|
|
323
|
+
fix: `Use individual exports instead:
|
|
324
|
+
export ledger field1: Type1;
|
|
325
|
+
export ledger field2: Type2;`,
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
error: 'parse error: found "{" looking for ";"',
|
|
329
|
+
cause: "Using Void as return type (doesn't exist)",
|
|
330
|
+
fix: `Use empty tuple [] for no return value:
|
|
331
|
+
export circuit myCircuit(): [] { ... }`,
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
error: 'unbound identifier "Cell"',
|
|
335
|
+
cause: "Using deprecated Cell<T> wrapper (removed in 0.15)",
|
|
336
|
+
fix: `Remove Cell wrapper, just use the type directly:
|
|
337
|
+
export ledger myField: Field; // Not Cell<Field>`,
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
error: "member access requires struct type",
|
|
341
|
+
cause: "Trying to use .member() or .lookup() on Map/Set in circuit",
|
|
342
|
+
fix: `Map/Set queries are not available in circuits.
|
|
343
|
+
Use a witness to fetch the value from the prover:
|
|
344
|
+
witness lookup_value(key: Bytes<32>): Field;`,
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
error: "cannot prove assertion",
|
|
348
|
+
cause: "Assert condition cannot be proven true",
|
|
349
|
+
fix: `Check your logic. Common causes:
|
|
350
|
+
1. Witness returns unexpected value
|
|
351
|
+
2. Range check fails (use bounded Uint)
|
|
352
|
+
3. Logic error in circuit`,
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
error: 'parse error: found ":" looking for ")"',
|
|
356
|
+
cause: "Using Rust-style :: for enum variant access",
|
|
357
|
+
fix: `Use dot notation for enum variants:
|
|
358
|
+
WRONG: Choice::rock, GameState::waiting
|
|
359
|
+
CORRECT: Choice.rock, GameState.waiting`,
|
|
360
|
+
},
|
|
361
|
+
];
|
|
95
362
|
//# sourceMappingURL=compact-version.js.map
|
|
@@ -133,6 +133,16 @@ export enum GameState { waiting, playing, finished }
|
|
|
133
133
|
export enum Choice { rock, paper, scissors }
|
|
134
134
|
\`\`\`
|
|
135
135
|
|
|
136
|
+
**Enum Access Syntax** - use DOT notation (not Rust-style ::):
|
|
137
|
+
\`\`\`compact
|
|
138
|
+
// CORRECT - dot notation
|
|
139
|
+
if (choice == Choice.rock) { ... }
|
|
140
|
+
game_state = GameState.waiting;
|
|
141
|
+
|
|
142
|
+
// WRONG - Rust-style double colon
|
|
143
|
+
if (choice == Choice::rock) { ... } // ❌ Parse error: found ":" looking for ")"
|
|
144
|
+
\`\`\`
|
|
145
|
+
|
|
136
146
|
**Structs**:
|
|
137
147
|
\`\`\`compact
|
|
138
148
|
export struct PlayerConfig {
|
|
@@ -225,6 +235,7 @@ constructor(initNonce: Bytes<32>) {
|
|
|
225
235
|
\`\`\`compact
|
|
226
236
|
witness local_secret_key(): Bytes<32>;
|
|
227
237
|
|
|
238
|
+
// IMPORTANT: public_key() is NOT a builtin - use this pattern
|
|
228
239
|
circuit get_public_key(sk: Bytes<32>): Bytes<32> {
|
|
229
240
|
return persistentHash<Vector<2, Bytes<32>>>([pad(32, "myapp:pk:"), sk]);
|
|
230
241
|
}
|
|
@@ -237,32 +248,47 @@ export circuit authenticated_action(): [] {
|
|
|
237
248
|
}
|
|
238
249
|
\`\`\`
|
|
239
250
|
|
|
240
|
-
### Commit-Reveal Pattern
|
|
251
|
+
### Commit-Reveal Pattern (COMPLETE, VALIDATED)
|
|
241
252
|
\`\`\`compact
|
|
253
|
+
pragma language_version >= 0.16 && <= 0.18;
|
|
254
|
+
|
|
255
|
+
import CompactStandardLibrary;
|
|
256
|
+
|
|
257
|
+
// Ledger state
|
|
242
258
|
export ledger commitment: Bytes<32>;
|
|
243
|
-
export ledger
|
|
259
|
+
export ledger revealed_value: Field;
|
|
260
|
+
export ledger is_revealed: Boolean;
|
|
244
261
|
|
|
245
|
-
|
|
246
|
-
witness
|
|
262
|
+
// Witnesses for off-chain storage
|
|
263
|
+
witness local_secret_key(): Bytes<32>;
|
|
264
|
+
witness store_secret_value(v: Field): [];
|
|
265
|
+
witness get_secret_value(): Field;
|
|
266
|
+
|
|
267
|
+
// Helper: compute commitment hash
|
|
268
|
+
circuit compute_commitment(value: Field, salt: Bytes<32>): Bytes<32> {
|
|
269
|
+
// Convert Field to Bytes for hashing
|
|
270
|
+
const value_bytes = value as Bytes<32>;
|
|
271
|
+
return persistentHash<Vector<2, Bytes<32>>>([value_bytes, salt]);
|
|
272
|
+
}
|
|
247
273
|
|
|
274
|
+
// Commit phase: store hash on-chain, value off-chain
|
|
248
275
|
export circuit commit(value: Field): [] {
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
commitment = disclose(
|
|
252
|
-
|
|
253
|
-
sk
|
|
254
|
-
]));
|
|
276
|
+
const salt = local_secret_key();
|
|
277
|
+
store_secret_value(value);
|
|
278
|
+
commitment = disclose(compute_commitment(value, salt));
|
|
279
|
+
is_revealed = false;
|
|
255
280
|
}
|
|
256
281
|
|
|
282
|
+
// Reveal phase: verify stored value matches commitment
|
|
257
283
|
export circuit reveal(): Field {
|
|
258
|
-
const
|
|
259
|
-
const value =
|
|
260
|
-
const expected =
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
284
|
+
const salt = local_secret_key();
|
|
285
|
+
const value = get_secret_value();
|
|
286
|
+
const expected = compute_commitment(value, salt);
|
|
287
|
+
assert(disclose(expected == commitment), "Value doesn't match commitment");
|
|
288
|
+
assert(disclose(!is_revealed), "Already revealed");
|
|
289
|
+
|
|
290
|
+
revealed_value = disclose(value);
|
|
291
|
+
is_revealed = true;
|
|
266
292
|
return disclose(value);
|
|
267
293
|
}
|
|
268
294
|
\`\`\`
|
|
@@ -296,22 +322,39 @@ export circuit check_broken(guess: Field): Boolean {
|
|
|
296
322
|
|
|
297
323
|
### Counter Operations
|
|
298
324
|
\`\`\`compact
|
|
325
|
+
// These work in circuits:
|
|
299
326
|
counter.increment(1);
|
|
300
327
|
counter.decrement(1);
|
|
301
|
-
|
|
328
|
+
counter.resetToDefault();
|
|
329
|
+
|
|
330
|
+
// ⚠️ DOES NOT WORK IN CIRCUITS:
|
|
331
|
+
// const val = counter.value(); // ERROR: operation undefined
|
|
332
|
+
// Instead, read counter value in TypeScript SDK: ledgerState.counter
|
|
302
333
|
\`\`\`
|
|
303
334
|
|
|
304
335
|
### Map Operations
|
|
305
336
|
\`\`\`compact
|
|
337
|
+
// These work in circuits:
|
|
306
338
|
balances.insert(address, 100);
|
|
307
|
-
|
|
308
|
-
|
|
339
|
+
balances.remove(address);
|
|
340
|
+
|
|
341
|
+
// ⚠️ DOES NOT WORK IN CIRCUITS:
|
|
342
|
+
// const balance = balances.lookup(address); // ERROR
|
|
343
|
+
// const exists = balances.member(address); // ERROR
|
|
344
|
+
// Instead, use witnesses to read values:
|
|
345
|
+
witness get_balance(addr: Bytes<32>): Uint<64>;
|
|
309
346
|
\`\`\`
|
|
310
347
|
|
|
311
348
|
### Set Operations
|
|
312
349
|
\`\`\`compact
|
|
350
|
+
// These work in circuits:
|
|
313
351
|
members.insert(address);
|
|
314
|
-
|
|
352
|
+
members.remove(address);
|
|
353
|
+
|
|
354
|
+
// ⚠️ DOES NOT WORK IN CIRCUITS:
|
|
355
|
+
// const isMember = members.member(address); // ERROR
|
|
356
|
+
// Use witness instead:
|
|
357
|
+
witness is_member(addr: Bytes<32>): Boolean;
|
|
315
358
|
\`\`\`
|
|
316
359
|
|
|
317
360
|
### Maybe Operations
|
|
@@ -326,9 +369,9 @@ if (opt.is_some) {
|
|
|
326
369
|
|
|
327
370
|
### Type Casting
|
|
328
371
|
\`\`\`compact
|
|
329
|
-
const
|
|
330
|
-
const
|
|
331
|
-
const
|
|
372
|
+
const bytes: Bytes<32> = myField as Bytes<32>; // Field to Bytes
|
|
373
|
+
const num: Uint<64> = myField as Uint<64>; // Field to Uint (bounds not checked!)
|
|
374
|
+
const field: Field = myUint as Field; // Uint to Field (safe)
|
|
332
375
|
\`\`\`
|
|
333
376
|
|
|
334
377
|
### Hashing
|
|
@@ -336,8 +379,8 @@ const num: Uint<64> = f as Uint<64>; // Field to Uint
|
|
|
336
379
|
// Persistent hash (same input = same output across calls)
|
|
337
380
|
const hash = persistentHash<Vector<2, Bytes<32>>>([data1, data2]);
|
|
338
381
|
|
|
339
|
-
//
|
|
340
|
-
const commit =
|
|
382
|
+
// Persistent commit (hiding commitment)
|
|
383
|
+
const commit = persistentCommit<Field>(value);
|
|
341
384
|
\`\`\`
|
|
342
385
|
|
|
343
386
|
---
|
|
@@ -159,6 +159,93 @@ export declare function compareSyntax(input: CompareSyntaxInput): Promise<{
|
|
|
159
159
|
*/
|
|
160
160
|
export declare function getLatestSyntax(input: GetLatestSyntaxInput): Promise<{
|
|
161
161
|
quickStartTemplate: string;
|
|
162
|
+
builtinFunctions: {
|
|
163
|
+
stdlib: {
|
|
164
|
+
name: string;
|
|
165
|
+
signature: string;
|
|
166
|
+
description: string;
|
|
167
|
+
}[];
|
|
168
|
+
notBuiltIn: {
|
|
169
|
+
name: string;
|
|
170
|
+
wrongUsage: string;
|
|
171
|
+
correctPattern: string;
|
|
172
|
+
description: string;
|
|
173
|
+
}[];
|
|
174
|
+
};
|
|
175
|
+
typeCompatibility: {
|
|
176
|
+
comparisons: ({
|
|
177
|
+
types: string;
|
|
178
|
+
works: boolean;
|
|
179
|
+
note: string;
|
|
180
|
+
fix?: undefined;
|
|
181
|
+
} | {
|
|
182
|
+
types: string;
|
|
183
|
+
works: boolean;
|
|
184
|
+
fix: string;
|
|
185
|
+
note?: undefined;
|
|
186
|
+
})[];
|
|
187
|
+
arithmetic: ({
|
|
188
|
+
types: string;
|
|
189
|
+
works: boolean;
|
|
190
|
+
note: string;
|
|
191
|
+
fix?: undefined;
|
|
192
|
+
} | {
|
|
193
|
+
types: string;
|
|
194
|
+
works: boolean;
|
|
195
|
+
fix: string;
|
|
196
|
+
note?: undefined;
|
|
197
|
+
})[];
|
|
198
|
+
assignments: {
|
|
199
|
+
types: string;
|
|
200
|
+
works: boolean;
|
|
201
|
+
fix: string;
|
|
202
|
+
}[];
|
|
203
|
+
tips: string[];
|
|
204
|
+
};
|
|
205
|
+
ledgerTypeLimits: {
|
|
206
|
+
Counter: {
|
|
207
|
+
circuitOperations: {
|
|
208
|
+
method: string;
|
|
209
|
+
works: boolean;
|
|
210
|
+
note: string;
|
|
211
|
+
}[];
|
|
212
|
+
typescriptAccess: string;
|
|
213
|
+
reason: string;
|
|
214
|
+
};
|
|
215
|
+
Map: {
|
|
216
|
+
circuitOperations: {
|
|
217
|
+
method: string;
|
|
218
|
+
works: boolean;
|
|
219
|
+
note: string;
|
|
220
|
+
}[];
|
|
221
|
+
typescriptAccess: string;
|
|
222
|
+
reason: string;
|
|
223
|
+
pattern: string;
|
|
224
|
+
};
|
|
225
|
+
Set: {
|
|
226
|
+
circuitOperations: {
|
|
227
|
+
method: string;
|
|
228
|
+
works: boolean;
|
|
229
|
+
note: string;
|
|
230
|
+
}[];
|
|
231
|
+
typescriptAccess: string;
|
|
232
|
+
reason: string;
|
|
233
|
+
};
|
|
234
|
+
MerkleTree: {
|
|
235
|
+
circuitOperations: {
|
|
236
|
+
method: string;
|
|
237
|
+
works: boolean;
|
|
238
|
+
note: string;
|
|
239
|
+
}[];
|
|
240
|
+
typescriptAccess: string;
|
|
241
|
+
pattern: string;
|
|
242
|
+
};
|
|
243
|
+
};
|
|
244
|
+
commonErrors: {
|
|
245
|
+
error: string;
|
|
246
|
+
cause: string;
|
|
247
|
+
fix: string;
|
|
248
|
+
}[];
|
|
162
249
|
commonMistakes: {
|
|
163
250
|
wrong: string;
|
|
164
251
|
correct: string;
|
|
@@ -8,7 +8,7 @@ import { logger, DEFAULT_REPOSITORIES, SelfCorrectionHints, } from "../../utils/
|
|
|
8
8
|
import { sendProgressNotification } from "../../server.js";
|
|
9
9
|
import { REPO_ALIASES, EXAMPLES } from "./constants.js";
|
|
10
10
|
import { EMBEDDED_DOCS } from "../../resources/content/docs-content.js";
|
|
11
|
-
import { COMPACT_VERSION, RECOMMENDED_PRAGMA, REFERENCE_CONTRACTS, } from "../../config/compact-version.js";
|
|
11
|
+
import { COMPACT_VERSION, RECOMMENDED_PRAGMA, REFERENCE_CONTRACTS, BUILTIN_FUNCTIONS, TYPE_COMPATIBILITY, LEDGER_TYPE_LIMITS, COMMON_ERRORS, } from "../../config/compact-version.js";
|
|
12
12
|
// Re-export validation handlers from validation.ts
|
|
13
13
|
export { extractContractStructure } from "./validation.js";
|
|
14
14
|
/**
|
|
@@ -356,6 +356,14 @@ witness local_secret_key(): Bytes<32>;
|
|
|
356
356
|
export circuit increment(): [] {
|
|
357
357
|
counter.increment(1);
|
|
358
358
|
}`,
|
|
359
|
+
// Built-in functions vs patterns (CRITICAL knowledge)
|
|
360
|
+
builtinFunctions: BUILTIN_FUNCTIONS,
|
|
361
|
+
// Type compatibility rules
|
|
362
|
+
typeCompatibility: TYPE_COMPATIBILITY,
|
|
363
|
+
// Ledger type limitations in circuits
|
|
364
|
+
ledgerTypeLimits: LEDGER_TYPE_LIMITS,
|
|
365
|
+
// Common compilation errors with fixes
|
|
366
|
+
commonErrors: COMMON_ERRORS,
|
|
359
367
|
// Common mistakes that cause compilation failures
|
|
360
368
|
commonMistakes: [
|
|
361
369
|
{
|
|
@@ -388,6 +396,26 @@ export circuit increment(): [] {
|
|
|
388
396
|
correct: "Field",
|
|
389
397
|
error: "unbound identifier Cell (deprecated)",
|
|
390
398
|
},
|
|
399
|
+
{
|
|
400
|
+
wrong: "public_key(sk)",
|
|
401
|
+
correct: 'persistentHash<Vector<2, Bytes<32>>>([pad(32, "midnight:pk:"), sk])',
|
|
402
|
+
error: 'unbound identifier "public_key"',
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
wrong: "counter.value()",
|
|
406
|
+
correct: "// Read via witness or TypeScript SDK",
|
|
407
|
+
error: 'operation "value" undefined for Counter',
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
wrong: "data.lookup(key)",
|
|
411
|
+
correct: "// Use witness: witness get_value(key): Type;",
|
|
412
|
+
error: "member access requires struct type",
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
wrong: "Choice::rock (Rust-style)",
|
|
416
|
+
correct: "Choice.rock (dot notation)",
|
|
417
|
+
error: 'parse error: found ":" looking for ")"',
|
|
418
|
+
},
|
|
391
419
|
],
|
|
392
420
|
syntaxReference: compactReference,
|
|
393
421
|
sections: [
|
|
@@ -396,6 +424,9 @@ export circuit increment(): [] {
|
|
|
396
424
|
"Imports",
|
|
397
425
|
"Ledger Declarations",
|
|
398
426
|
"Data Types",
|
|
427
|
+
"Built-in Functions",
|
|
428
|
+
"Type Compatibility",
|
|
429
|
+
"Ledger Type Limits",
|
|
399
430
|
"Circuits",
|
|
400
431
|
"Witnesses",
|
|
401
432
|
"Constructor",
|
|
@@ -403,6 +434,7 @@ export circuit increment(): [] {
|
|
|
403
434
|
"Common Operations",
|
|
404
435
|
"Assertions",
|
|
405
436
|
"Common Mistakes to Avoid",
|
|
437
|
+
"Common Errors & Fixes",
|
|
406
438
|
"Exports for TypeScript",
|
|
407
439
|
"Reference Contracts",
|
|
408
440
|
],
|
|
@@ -411,7 +443,13 @@ export circuit increment(): [] {
|
|
|
411
443
|
repo: rc.repo,
|
|
412
444
|
description: rc.description,
|
|
413
445
|
})),
|
|
414
|
-
note: `CRITICAL: Use quickStartTemplate as your base. Check commonMistakes before submitting code.
|
|
446
|
+
note: `CRITICAL: Use quickStartTemplate as your base. Check commonMistakes and commonErrors before submitting code.
|
|
447
|
+
KEY GOTCHAS:
|
|
448
|
+
1. public_key() is NOT a builtin - use persistentHash pattern
|
|
449
|
+
2. Counter.value() NOT available in circuits - use witnesses
|
|
450
|
+
3. Map.lookup()/Set.member() NOT available in circuits - use witnesses
|
|
451
|
+
4. Field vs Uint comparison requires casting
|
|
452
|
+
This reference is for Compact ${COMPACT_VERSION.min}-${COMPACT_VERSION.max} (last updated: ${COMPACT_VERSION.lastUpdated}).`,
|
|
415
453
|
};
|
|
416
454
|
}
|
|
417
455
|
}
|