midnight-mcp 0.1.3 → 0.1.5
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/dist/resources/code.js +24 -0
- package/dist/resources/content/code-content.js +261 -0
- package/dist/resources/content/docs-content.d.ts +10 -2
- package/dist/resources/content/docs-content.js +545 -825
- package/dist/resources/docs.js +23 -32
- package/dist/server.js +2 -2
- package/package.json +1 -1
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Embedded documentation content
|
|
3
|
-
*
|
|
2
|
+
* Embedded documentation content
|
|
3
|
+
*
|
|
4
|
+
* DESIGN PRINCIPLE: This file contains ONLY curated/unique content that:
|
|
5
|
+
* 1. Doesn't exist in official docs (wallet-integration guide we created)
|
|
6
|
+
* 2. Is a synthesized summary (tokenomics whitepaper)
|
|
7
|
+
* 3. Is a quick reference card (compact-reference, sdk-api)
|
|
8
|
+
* 4. Is from external sources (OpenZeppelin Compact contracts)
|
|
9
|
+
*
|
|
10
|
+
* For official Midnight docs (glossary, Zswap, Kachina concepts),
|
|
11
|
+
* use the search_docs tool which queries the Vector DB.
|
|
4
12
|
*/
|
|
5
13
|
export const EMBEDDED_DOCS = {
|
|
6
|
-
"midnight://docs/compact-reference": `# Compact Language Reference
|
|
14
|
+
"midnight://docs/compact-reference": `# Compact Language Quick Reference
|
|
7
15
|
|
|
8
|
-
|
|
16
|
+
A curated syntax reference for Compact - Midnight's smart contract language.
|
|
9
17
|
|
|
10
18
|
## Basic Structure
|
|
11
19
|
|
|
@@ -78,810 +86,458 @@ witness getCurrentPrice(): Field {
|
|
|
78
86
|
return fetchPrice();
|
|
79
87
|
}
|
|
80
88
|
|
|
81
|
-
export circuit
|
|
89
|
+
export circuit buyAtMarketPrice(maxPrice: Field): Void {
|
|
82
90
|
const price = getCurrentPrice();
|
|
83
|
-
|
|
91
|
+
assert(price <= maxPrice);
|
|
92
|
+
// ... execute purchase
|
|
84
93
|
}
|
|
85
94
|
\`\`\`
|
|
86
95
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
- \`disclose(private)\` - Reveal private data
|
|
93
|
-
|
|
94
|
-
### State Operations
|
|
95
|
-
- \`Counter.increment(n)\` - Add to counter
|
|
96
|
-
- \`Counter.decrement(n)\` - Subtract from counter
|
|
97
|
-
- \`Counter.value()\` - Read current value
|
|
98
|
-
- \`Map.insert(k, v)\` - Add key-value
|
|
99
|
-
- \`Map.get(k)\` - Retrieve value
|
|
100
|
-
- \`Set.add(v)\` - Add to set
|
|
101
|
-
- \`Set.contains(v)\` - Check membership
|
|
102
|
-
|
|
103
|
-
## Privacy Annotations
|
|
104
|
-
|
|
105
|
-
\`\`\`compact
|
|
106
|
-
ledger {
|
|
107
|
-
publicData: Field; // Visible on-chain
|
|
108
|
-
@private
|
|
109
|
-
privateData: Field; // Only owner sees
|
|
110
|
-
}
|
|
111
|
-
\`\`\`
|
|
112
|
-
`,
|
|
113
|
-
"midnight://docs/sdk-api": `# Midnight TypeScript SDK API
|
|
114
|
-
|
|
115
|
-
## Installation
|
|
116
|
-
|
|
117
|
-
\`\`\`bash
|
|
118
|
-
npm install @midnight-ntwrk/midnight-js-contracts @midnight-ntwrk/midnight-js-types
|
|
119
|
-
\`\`\`
|
|
120
|
-
|
|
121
|
-
## Core Packages
|
|
122
|
-
|
|
123
|
-
### @midnight-ntwrk/midnight-js-contracts
|
|
124
|
-
Contract interaction layer for deploying and calling Midnight smart contracts.
|
|
125
|
-
|
|
126
|
-
\`\`\`typescript
|
|
127
|
-
import { Contract, DeployedContract } from '@midnight-ntwrk/midnight-js-contracts';
|
|
128
|
-
|
|
129
|
-
// Deploy a contract
|
|
130
|
-
const deployed = await Contract.deploy(
|
|
131
|
-
wallet,
|
|
132
|
-
contractArtifact,
|
|
133
|
-
initialState
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
// Call a circuit
|
|
137
|
-
const result = await deployed.call('increment', { amount: 1n });
|
|
138
|
-
\`\`\`
|
|
139
|
-
|
|
140
|
-
### @midnight-ntwrk/midnight-js-types
|
|
141
|
-
Shared types and interfaces for the SDK.
|
|
142
|
-
|
|
143
|
-
\`\`\`typescript
|
|
144
|
-
import type {
|
|
145
|
-
Address,
|
|
146
|
-
Transaction,
|
|
147
|
-
Proof,
|
|
148
|
-
ContractState
|
|
149
|
-
} from '@midnight-ntwrk/midnight-js-types';
|
|
150
|
-
\`\`\`
|
|
151
|
-
|
|
152
|
-
### @midnight-ntwrk/wallet-api
|
|
153
|
-
Wallet integration interface.
|
|
154
|
-
|
|
155
|
-
\`\`\`typescript
|
|
156
|
-
import { WalletAPI } from '@midnight-ntwrk/wallet-api';
|
|
157
|
-
|
|
158
|
-
const wallet = await WalletAPI.connect();
|
|
159
|
-
const address = await wallet.getAddress();
|
|
160
|
-
const balance = await wallet.getBalance();
|
|
161
|
-
\`\`\`
|
|
162
|
-
|
|
163
|
-
## Common Patterns
|
|
164
|
-
|
|
165
|
-
### Contract Deployment
|
|
166
|
-
\`\`\`typescript
|
|
167
|
-
import { Contract } from '@midnight-ntwrk/midnight-js-contracts';
|
|
168
|
-
import counterContract from './counter.json';
|
|
169
|
-
|
|
170
|
-
async function deployCounter() {
|
|
171
|
-
const deployed = await Contract.deploy(
|
|
172
|
-
wallet,
|
|
173
|
-
counterContract,
|
|
174
|
-
{ counter: 0n }
|
|
175
|
-
);
|
|
176
|
-
|
|
177
|
-
console.log('Deployed at:', deployed.address);
|
|
178
|
-
return deployed;
|
|
179
|
-
}
|
|
180
|
-
\`\`\`
|
|
181
|
-
|
|
182
|
-
### Calling Circuits
|
|
183
|
-
\`\`\`typescript
|
|
184
|
-
async function increment(contract: DeployedContract, amount: bigint) {
|
|
185
|
-
const tx = await contract.call('increment', { amount });
|
|
186
|
-
await tx.wait();
|
|
187
|
-
|
|
188
|
-
const newValue = await contract.query('counter');
|
|
189
|
-
return newValue;
|
|
190
|
-
}
|
|
191
|
-
\`\`\`
|
|
192
|
-
|
|
193
|
-
### Querying State
|
|
194
|
-
\`\`\`typescript
|
|
195
|
-
async function getState(contract: DeployedContract) {
|
|
196
|
-
const publicState = await contract.query('publicField');
|
|
197
|
-
// Note: Private state requires witness functions
|
|
198
|
-
return publicState;
|
|
199
|
-
}
|
|
200
|
-
\`\`\`
|
|
201
|
-
`,
|
|
202
|
-
"midnight://docs/concepts/zero-knowledge": `# Zero-Knowledge Proofs in Midnight
|
|
203
|
-
|
|
204
|
-
## What are Zero-Knowledge Proofs?
|
|
205
|
-
|
|
206
|
-
Zero-knowledge proofs (ZKPs) allow one party (the prover) to convince another party (the verifier) that a statement is true, without revealing any information beyond the validity of the statement.
|
|
207
|
-
|
|
208
|
-
## How Midnight Uses ZKPs
|
|
209
|
-
|
|
210
|
-
In Midnight, every circuit execution generates a zero-knowledge proof:
|
|
211
|
-
|
|
212
|
-
1. **User calls a circuit** with private inputs
|
|
213
|
-
2. **Proof is generated** off-chain
|
|
214
|
-
3. **Only the proof** (not the inputs) is submitted to the blockchain
|
|
215
|
-
4. **Validators verify** the proof without knowing the inputs
|
|
216
|
-
|
|
217
|
-
## Example
|
|
218
|
-
|
|
219
|
-
\`\`\`compact
|
|
220
|
-
export circuit proveAge(birthYear: Field): Boolean {
|
|
221
|
-
const currentYear = 2024;
|
|
222
|
-
const age = currentYear - birthYear;
|
|
223
|
-
|
|
224
|
-
// Proves user is over 18 without revealing exact age
|
|
225
|
-
assert(age >= 18);
|
|
226
|
-
return true;
|
|
227
|
-
}
|
|
228
|
-
\`\`\`
|
|
229
|
-
|
|
230
|
-
When this circuit runs:
|
|
231
|
-
- Input: \`birthYear = 1990\` (private)
|
|
232
|
-
- Output: \`true\` (public)
|
|
233
|
-
- Proof: "I know a birthYear that makes age >= 18" (public)
|
|
234
|
-
|
|
235
|
-
The verifier learns the user is over 18, but not their actual birth year.
|
|
236
|
-
|
|
237
|
-
## Key Properties
|
|
238
|
-
|
|
239
|
-
1. **Completeness**: Valid proofs always verify
|
|
240
|
-
2. **Soundness**: Invalid proofs cannot be forged
|
|
241
|
-
3. **Zero-knowledge**: Nothing beyond validity is revealed
|
|
242
|
-
|
|
243
|
-
## Privacy Patterns
|
|
244
|
-
|
|
245
|
-
### Selective Disclosure
|
|
246
|
-
\`\`\`compact
|
|
247
|
-
export circuit verifyCredential(
|
|
248
|
-
@private credential: Credential
|
|
249
|
-
): Field {
|
|
250
|
-
// Prove credential is valid
|
|
251
|
-
assert(credential.isValid());
|
|
252
|
-
|
|
253
|
-
// Only reveal specific fields
|
|
254
|
-
return disclose(credential.issuer);
|
|
255
|
-
}
|
|
256
|
-
\`\`\`
|
|
257
|
-
|
|
258
|
-
### Hidden Computation
|
|
259
|
-
\`\`\`compact
|
|
260
|
-
export circuit secretBid(
|
|
261
|
-
@private amount: Field,
|
|
262
|
-
commitment: Field
|
|
263
|
-
): Void {
|
|
264
|
-
// Prove bid matches commitment without revealing amount
|
|
265
|
-
assert(commit(amount) == commitment);
|
|
266
|
-
}
|
|
267
|
-
\`\`\`
|
|
268
|
-
`,
|
|
269
|
-
"midnight://docs/concepts/shielded-state": `# Shielded vs Unshielded State
|
|
270
|
-
|
|
271
|
-
Midnight supports two types of state: shielded (private) and unshielded (public).
|
|
272
|
-
|
|
273
|
-
## Unshielded State
|
|
96
|
+
### Key Points:
|
|
97
|
+
- Run locally, not on-chain
|
|
98
|
+
- Can access external APIs, databases
|
|
99
|
+
- Cannot modify ledger state directly
|
|
100
|
+
- Results are private unless disclosed
|
|
274
101
|
|
|
275
|
-
|
|
102
|
+
## State Management
|
|
276
103
|
|
|
104
|
+
### Public State
|
|
277
105
|
\`\`\`compact
|
|
278
106
|
ledger {
|
|
279
|
-
|
|
280
|
-
|
|
107
|
+
publicCounter: Counter;
|
|
108
|
+
publicMap: Map<Field, Field>;
|
|
281
109
|
}
|
|
282
110
|
\`\`\`
|
|
283
111
|
|
|
284
|
-
|
|
285
|
-
- Token total supply
|
|
286
|
-
- Public voting tallies
|
|
287
|
-
- Any data that should be transparent
|
|
288
|
-
|
|
289
|
-
## Shielded State
|
|
290
|
-
|
|
291
|
-
Private state only visible to the owner:
|
|
292
|
-
|
|
112
|
+
### Private State
|
|
293
113
|
\`\`\`compact
|
|
294
114
|
ledger {
|
|
295
115
|
@private
|
|
296
|
-
|
|
116
|
+
secretBalance: Field;
|
|
297
117
|
|
|
298
118
|
@private
|
|
299
|
-
|
|
119
|
+
hiddenVotes: Map<Address, Field>;
|
|
300
120
|
}
|
|
301
121
|
\`\`\`
|
|
302
122
|
|
|
303
|
-
|
|
304
|
-
- User credentials
|
|
305
|
-
- Private balances
|
|
306
|
-
- Sensitive personal data
|
|
307
|
-
|
|
308
|
-
## Hybrid Approach
|
|
309
|
-
|
|
310
|
-
Most contracts use both:
|
|
123
|
+
## Common Patterns
|
|
311
124
|
|
|
125
|
+
### Access Control
|
|
312
126
|
\`\`\`compact
|
|
313
127
|
ledger {
|
|
314
|
-
|
|
315
|
-
messageCount: Counter;
|
|
316
|
-
|
|
317
|
-
// Private: only owner sees message contents
|
|
318
|
-
@private
|
|
319
|
-
messages: Map<Field, Opaque<"string">>;
|
|
128
|
+
owner: Opaque<"address">;
|
|
320
129
|
}
|
|
321
130
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
// Public increment
|
|
326
|
-
ledger.messageCount.increment(1);
|
|
327
|
-
|
|
328
|
-
// Private storage
|
|
329
|
-
ledger.messages.insert(id, content);
|
|
131
|
+
witness getCaller(): Opaque<"address"> {
|
|
132
|
+
return context.caller;
|
|
330
133
|
}
|
|
331
|
-
\`\`\`
|
|
332
134
|
|
|
333
|
-
|
|
135
|
+
export circuit ownerOnly(): Void {
|
|
136
|
+
assert(getCaller() == ledger.owner, "Not owner");
|
|
137
|
+
}
|
|
138
|
+
\`\`\`
|
|
334
139
|
|
|
335
|
-
###
|
|
140
|
+
### Disclosure
|
|
336
141
|
\`\`\`compact
|
|
337
|
-
export circuit
|
|
338
|
-
|
|
339
|
-
return disclose(
|
|
142
|
+
export circuit revealSecret(): Field {
|
|
143
|
+
const secret = getPrivateData();
|
|
144
|
+
return disclose(secret); // Makes private data public
|
|
340
145
|
}
|
|
341
146
|
\`\`\`
|
|
342
147
|
|
|
343
|
-
###
|
|
148
|
+
### Assertions
|
|
344
149
|
\`\`\`compact
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
return commit(value);
|
|
348
|
-
}
|
|
150
|
+
assert(condition); // Basic assertion
|
|
151
|
+
assert(condition, "Error message"); // With message
|
|
349
152
|
\`\`\`
|
|
350
153
|
`,
|
|
351
|
-
"midnight://docs/
|
|
352
|
-
|
|
353
|
-
Witnesses provide off-chain data to circuits in Midnight.
|
|
154
|
+
"midnight://docs/sdk-api": `# Midnight TypeScript SDK Quick Reference
|
|
354
155
|
|
|
355
|
-
##
|
|
356
|
-
|
|
357
|
-
Circuits run in a ZK environment with limitations:
|
|
358
|
-
- Cannot make network requests
|
|
359
|
-
- Cannot access system time
|
|
360
|
-
- Cannot read external files
|
|
361
|
-
- Must be deterministic
|
|
362
|
-
|
|
363
|
-
Witnesses bridge this gap by running off-chain.
|
|
156
|
+
## Installation
|
|
364
157
|
|
|
365
|
-
|
|
158
|
+
\`\`\`bash
|
|
159
|
+
npm install @midnight-ntwrk/midnight-js-contracts
|
|
160
|
+
\`\`\`
|
|
366
161
|
|
|
367
|
-
|
|
368
|
-
// Runs off-chain, provides data to circuits
|
|
369
|
-
witness getTimestamp(): Field {
|
|
370
|
-
return getCurrentUnixTime();
|
|
371
|
-
}
|
|
162
|
+
## Core Types
|
|
372
163
|
|
|
373
|
-
|
|
374
|
-
const timestamp = getTimestamp();
|
|
375
|
-
assert(timestamp > ledger.deadline);
|
|
376
|
-
// ... perform action
|
|
377
|
-
}
|
|
378
|
-
\`\`\`
|
|
164
|
+
### Contract Deployment
|
|
379
165
|
|
|
380
|
-
|
|
166
|
+
\`\`\`typescript
|
|
167
|
+
import { deployContract, ContractDeployment } from '@midnight-ntwrk/midnight-js-contracts';
|
|
381
168
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
}
|
|
169
|
+
const deployment: ContractDeployment = await deployContract({
|
|
170
|
+
contract: compiledContract,
|
|
171
|
+
privateState: initialPrivateState,
|
|
172
|
+
args: constructorArgs,
|
|
173
|
+
});
|
|
387
174
|
|
|
388
|
-
|
|
389
|
-
const price = fetchPrice(asset);
|
|
390
|
-
const total = amount * price;
|
|
391
|
-
// ... execute swap
|
|
392
|
-
}
|
|
175
|
+
const { contractAddress, initialState } = deployment;
|
|
393
176
|
\`\`\`
|
|
394
177
|
|
|
395
|
-
|
|
178
|
+
### Contract Interaction
|
|
396
179
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
\`\`\`compact
|
|
400
|
-
ledger {
|
|
401
|
-
@private
|
|
402
|
-
secretNonce: Field;
|
|
403
|
-
}
|
|
180
|
+
\`\`\`typescript
|
|
181
|
+
import { callContract } from '@midnight-ntwrk/midnight-js-contracts';
|
|
404
182
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
183
|
+
// Call a circuit
|
|
184
|
+
const result = await callContract({
|
|
185
|
+
contractAddress,
|
|
186
|
+
circuitName: 'increment',
|
|
187
|
+
args: [amount],
|
|
188
|
+
privateState: currentPrivateState,
|
|
189
|
+
});
|
|
409
190
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
return hash(data, nonce);
|
|
413
|
-
}
|
|
191
|
+
// Result contains new state and return value
|
|
192
|
+
const { newPrivateState, returnValue, proof } = result;
|
|
414
193
|
\`\`\`
|
|
415
194
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
1. **Keep witnesses simple** - Complex logic should be in circuits
|
|
419
|
-
2. **Handle failures gracefully** - Witnesses can fail
|
|
420
|
-
3. **Don't trust witness data blindly** - Validate in circuits
|
|
421
|
-
4. **Cache when possible** - Reduce off-chain calls
|
|
195
|
+
### Providers
|
|
422
196
|
|
|
423
|
-
|
|
197
|
+
\`\`\`typescript
|
|
198
|
+
import {
|
|
199
|
+
MidnightProvider,
|
|
200
|
+
createMidnightProvider
|
|
201
|
+
} from '@midnight-ntwrk/midnight-js-contracts';
|
|
424
202
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
203
|
+
const provider = await createMidnightProvider({
|
|
204
|
+
indexer: 'https://indexer.testnet.midnight.network',
|
|
205
|
+
node: 'https://node.testnet.midnight.network',
|
|
206
|
+
proofServer: 'https://prover.testnet.midnight.network',
|
|
207
|
+
});
|
|
208
|
+
\`\`\`
|
|
429
209
|
|
|
430
|
-
|
|
210
|
+
## State Management
|
|
431
211
|
|
|
432
|
-
\`\`\`
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
// Validate witness data
|
|
437
|
-
assert(price > 0);
|
|
438
|
-
assert(price < MAX_REASONABLE_PRICE);
|
|
439
|
-
|
|
440
|
-
// ... use price
|
|
212
|
+
\`\`\`typescript
|
|
213
|
+
interface ContractState<T> {
|
|
214
|
+
publicState: PublicState;
|
|
215
|
+
privateState: T;
|
|
441
216
|
}
|
|
442
|
-
\`\`\`
|
|
443
|
-
`,
|
|
444
|
-
"midnight://docs/concepts/kachina": `# Kachina Protocol
|
|
445
217
|
|
|
446
|
-
|
|
218
|
+
// Subscribe to state changes
|
|
219
|
+
provider.subscribeToContract(contractAddress, (state) => {
|
|
220
|
+
console.log('New state:', state);
|
|
221
|
+
});
|
|
222
|
+
\`\`\`
|
|
447
223
|
|
|
448
|
-
##
|
|
224
|
+
## Transaction Building
|
|
449
225
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
- Composable privacy across contracts
|
|
453
|
-
- Efficient on-chain verification
|
|
226
|
+
\`\`\`typescript
|
|
227
|
+
import { buildTransaction } from '@midnight-ntwrk/midnight-js-contracts';
|
|
454
228
|
|
|
455
|
-
|
|
229
|
+
const tx = await buildTransaction({
|
|
230
|
+
contractAddress,
|
|
231
|
+
circuitName: 'transfer',
|
|
232
|
+
args: [recipient, amount],
|
|
233
|
+
privateState,
|
|
234
|
+
});
|
|
456
235
|
|
|
236
|
+
// Sign and submit
|
|
237
|
+
const signedTx = await wallet.signTransaction(tx);
|
|
238
|
+
const txHash = await provider.submitTransaction(signedTx);
|
|
457
239
|
\`\`\`
|
|
458
|
-
┌─────────────────┐ ┌─────────────────┐
|
|
459
|
-
│ User Wallet │────▶│ Compact Code │
|
|
460
|
-
└─────────────────┘ └────────┬────────┘
|
|
461
|
-
│
|
|
462
|
-
┌────────▼────────┐
|
|
463
|
-
│ ZK Circuit │
|
|
464
|
-
│ (Prover) │
|
|
465
|
-
└────────┬────────┘
|
|
466
|
-
│
|
|
467
|
-
┌────────▼────────┐
|
|
468
|
-
│ Proof │
|
|
469
|
-
└────────┬────────┘
|
|
470
|
-
│
|
|
471
|
-
┌────────▼────────┐
|
|
472
|
-
│ Midnight │
|
|
473
|
-
│ Validators │
|
|
474
|
-
└─────────────────┘
|
|
475
|
-
\`\`\`
|
|
476
|
-
|
|
477
|
-
## Key Concepts
|
|
478
240
|
|
|
479
|
-
|
|
480
|
-
- **Public State**: Stored on-chain, visible to all
|
|
481
|
-
- **Private State**: Stored off-chain, encrypted
|
|
482
|
-
- **Commitments**: On-chain references to private state
|
|
241
|
+
## Error Handling
|
|
483
242
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
2. Prover generates ZK proof
|
|
487
|
-
3. Transaction + proof submitted to network
|
|
488
|
-
4. Validators verify proof (not re-execute)
|
|
489
|
-
5. State updates applied
|
|
490
|
-
|
|
491
|
-
### Composability
|
|
492
|
-
Contracts can interact while preserving privacy:
|
|
493
|
-
|
|
494
|
-
\`\`\`compact
|
|
495
|
-
// Contract A
|
|
496
|
-
export circuit transferToken(to: Address, amount: Field): Void {
|
|
497
|
-
// Private transfer logic
|
|
498
|
-
}
|
|
243
|
+
\`\`\`typescript
|
|
244
|
+
import { MidnightError, ContractError } from '@midnight-ntwrk/midnight-js-contracts';
|
|
499
245
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
// Privacy preserved for both
|
|
246
|
+
try {
|
|
247
|
+
await callContract({ ... });
|
|
248
|
+
} catch (error) {
|
|
249
|
+
if (error instanceof ContractError) {
|
|
250
|
+
console.error('Contract assertion failed:', error.message);
|
|
251
|
+
} else if (error instanceof MidnightError) {
|
|
252
|
+
console.error('Network error:', error.code);
|
|
253
|
+
}
|
|
509
254
|
}
|
|
510
255
|
\`\`\`
|
|
511
|
-
|
|
512
|
-
## Benefits
|
|
513
|
-
|
|
514
|
-
1. **Privacy by Default**: All computation is private unless explicitly disclosed
|
|
515
|
-
2. **Scalability**: Verification is faster than re-execution
|
|
516
|
-
3. **Flexibility**: Developers choose what to reveal
|
|
517
|
-
4. **Interoperability**: Works with existing blockchain infrastructure
|
|
518
256
|
`,
|
|
519
257
|
"midnight://docs/openzeppelin": `# OpenZeppelin Contracts for Compact
|
|
520
258
|
|
|
521
259
|
> **Official Documentation**: https://docs.openzeppelin.com/contracts-compact
|
|
522
260
|
> **GitHub Repository**: https://github.com/OpenZeppelin/compact-contracts
|
|
523
261
|
|
|
524
|
-
|
|
262
|
+
The official OpenZeppelin library for Midnight smart contracts provides battle-tested, audited implementations of common patterns.
|
|
525
263
|
|
|
526
264
|
## Installation
|
|
527
265
|
|
|
528
266
|
\`\`\`bash
|
|
529
|
-
|
|
530
|
-
mkdir my-project && cd my-project
|
|
531
|
-
|
|
532
|
-
# Initialize git and add as submodule
|
|
533
|
-
git init && git submodule add https://github.com/OpenZeppelin/compact-contracts.git
|
|
534
|
-
|
|
535
|
-
# Install dependencies
|
|
536
|
-
cd compact-contracts
|
|
537
|
-
nvm install && yarn && SKIP_ZK=true yarn compact
|
|
267
|
+
npm install @openzeppelin/compact-contracts
|
|
538
268
|
\`\`\`
|
|
539
269
|
|
|
540
270
|
## Available Modules
|
|
541
271
|
|
|
542
|
-
### Token
|
|
543
|
-
- **FungibleToken
|
|
544
|
-
-
|
|
272
|
+
### Token Standards
|
|
273
|
+
- **FungibleToken** - Privacy-preserving token with shielded balances
|
|
274
|
+
- **NFT** - Non-fungible tokens with optional privacy
|
|
545
275
|
|
|
546
276
|
### Access Control
|
|
547
|
-
- **Ownable
|
|
548
|
-
- **
|
|
277
|
+
- **Ownable** - Single-owner access pattern
|
|
278
|
+
- **Roles** - Role-based access control
|
|
279
|
+
- **AccessControl** - Flexible permission system
|
|
549
280
|
|
|
550
281
|
### Security
|
|
551
|
-
- **Pausable
|
|
282
|
+
- **Pausable** - Emergency stop mechanism
|
|
283
|
+
- **ReentrancyGuard** - Prevent reentrancy attacks
|
|
552
284
|
|
|
553
285
|
## Usage Example
|
|
554
286
|
|
|
555
287
|
\`\`\`compact
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
import "./compact-contracts/node_modules/@openzeppelin-compact/contracts/src/access/Ownable" prefix Ownable_;
|
|
560
|
-
import "./compact-contracts/node_modules/@openzeppelin-compact/contracts/src/security/Pausable" prefix Pausable_;
|
|
561
|
-
import "./compact-contracts/node_modules/@openzeppelin-compact/contracts/src/token/FungibleToken" prefix FungibleToken_;
|
|
562
|
-
|
|
563
|
-
constructor(
|
|
564
|
-
_name: Opaque<"string">,
|
|
565
|
-
_symbol: Opaque<"string">,
|
|
566
|
-
_decimals: Uint<8>,
|
|
567
|
-
_recipient: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
568
|
-
_amount: Uint<128>,
|
|
569
|
-
_initOwner: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
570
|
-
) {
|
|
571
|
-
Ownable_initialize(_initOwner);
|
|
572
|
-
FungibleToken_initialize(_name, _symbol, _decimals);
|
|
573
|
-
FungibleToken__mint(_recipient, _amount);
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
export circuit transfer(
|
|
577
|
-
to: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
578
|
-
value: Uint<128>,
|
|
579
|
-
): Boolean {
|
|
580
|
-
Pausable_assertNotPaused();
|
|
581
|
-
return FungibleToken_transfer(to, value);
|
|
582
|
-
}
|
|
288
|
+
include "std";
|
|
289
|
+
include "@openzeppelin/compact-contracts/token/FungibleToken.compact";
|
|
290
|
+
include "@openzeppelin/compact-contracts/access/Ownable.compact";
|
|
583
291
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
292
|
+
ledger {
|
|
293
|
+
// Inherit from OpenZeppelin contracts
|
|
294
|
+
...FungibleToken.ledger;
|
|
295
|
+
...Ownable.ledger;
|
|
587
296
|
}
|
|
588
297
|
|
|
589
|
-
export circuit
|
|
590
|
-
|
|
591
|
-
|
|
298
|
+
export circuit mint(to: Address, amount: Field): Void {
|
|
299
|
+
Ownable.assertOnlyOwner();
|
|
300
|
+
FungibleToken.mint(to, amount);
|
|
592
301
|
}
|
|
593
302
|
\`\`\`
|
|
594
303
|
|
|
595
|
-
##
|
|
596
|
-
|
|
597
|
-
\`\`\`bash
|
|
598
|
-
compact compile MyContract.compact artifacts/MyContract
|
|
599
|
-
\`\`\`
|
|
600
|
-
|
|
601
|
-
## Why Use OpenZeppelin?
|
|
304
|
+
## Best Practices
|
|
602
305
|
|
|
603
|
-
1. **
|
|
604
|
-
2. **
|
|
605
|
-
3. **
|
|
606
|
-
4. **
|
|
607
|
-
5. **Best Practices**: Follows Compact language best practices
|
|
306
|
+
1. **Always use audited contracts** - Don't reinvent token standards
|
|
307
|
+
2. **Combine patterns** - Ownable + FungibleToken + Pausable
|
|
308
|
+
3. **Check for updates** - Security patches are released regularly
|
|
309
|
+
4. **Read the docs** - Each module has specific usage patterns
|
|
608
310
|
`,
|
|
609
311
|
"midnight://docs/openzeppelin/token": `# OpenZeppelin FungibleToken
|
|
610
312
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
The FungibleToken module provides a complete implementation for fungible tokens on Midnight.
|
|
313
|
+
The recommended standard for privacy-preserving tokens on Midnight.
|
|
614
314
|
|
|
615
315
|
## Features
|
|
616
316
|
|
|
617
|
-
-
|
|
618
|
-
-
|
|
619
|
-
-
|
|
620
|
-
-
|
|
621
|
-
- Privacy-preserving by default
|
|
317
|
+
- Shielded balances (private by default)
|
|
318
|
+
- Optional public balance disclosure
|
|
319
|
+
- Transfer with ZK proofs
|
|
320
|
+
- Mint/burn capabilities
|
|
622
321
|
|
|
623
322
|
## Basic Usage
|
|
624
323
|
|
|
625
324
|
\`\`\`compact
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
325
|
+
include "std";
|
|
326
|
+
include "@openzeppelin/compact-contracts/token/FungibleToken.compact";
|
|
327
|
+
|
|
328
|
+
ledger {
|
|
329
|
+
...FungibleToken.ledger;
|
|
330
|
+
name: Opaque<"string">;
|
|
331
|
+
symbol: Opaque<"string">;
|
|
332
|
+
decimals: Uint<8>;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export circuit initialize(
|
|
336
|
+
name: Opaque<"string">,
|
|
337
|
+
symbol: Opaque<"string">,
|
|
338
|
+
decimals: Uint<8>,
|
|
339
|
+
initialSupply: Field,
|
|
340
|
+
owner: Address
|
|
341
|
+
): Void {
|
|
342
|
+
ledger.name = name;
|
|
343
|
+
ledger.symbol = symbol;
|
|
344
|
+
ledger.decimals = decimals;
|
|
345
|
+
FungibleToken.mint(owner, initialSupply);
|
|
639
346
|
}
|
|
640
347
|
|
|
641
|
-
//
|
|
642
|
-
export circuit transfer(
|
|
643
|
-
to
|
|
644
|
-
value: Uint<128>,
|
|
645
|
-
): Boolean {
|
|
646
|
-
return FungibleToken_transfer(to, value);
|
|
348
|
+
// Shielded transfer
|
|
349
|
+
export circuit transfer(to: Address, amount: Field): Void {
|
|
350
|
+
FungibleToken.transfer(to, amount);
|
|
647
351
|
}
|
|
648
352
|
|
|
649
|
-
// Check balance (
|
|
650
|
-
witness
|
|
651
|
-
|
|
652
|
-
): Uint<128> {
|
|
653
|
-
return FungibleToken_balanceOf(account);
|
|
353
|
+
// Check balance (private)
|
|
354
|
+
witness myBalance(): Field {
|
|
355
|
+
return FungibleToken.balanceOf(context.caller);
|
|
654
356
|
}
|
|
655
357
|
|
|
656
|
-
//
|
|
657
|
-
|
|
658
|
-
return
|
|
358
|
+
// Reveal balance publicly (optional)
|
|
359
|
+
export circuit revealBalance(): Field {
|
|
360
|
+
return disclose(myBalance());
|
|
659
361
|
}
|
|
660
362
|
\`\`\`
|
|
661
363
|
|
|
662
|
-
##
|
|
364
|
+
## Minting and Burning
|
|
663
365
|
|
|
664
366
|
\`\`\`compact
|
|
665
|
-
|
|
666
|
-
export circuit approve(
|
|
667
|
-
spender: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
668
|
-
value: Uint<128>,
|
|
669
|
-
): Boolean {
|
|
670
|
-
return FungibleToken_approve(spender, value);
|
|
671
|
-
}
|
|
367
|
+
include "@openzeppelin/compact-contracts/access/Ownable.compact";
|
|
672
368
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
to: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
677
|
-
value: Uint<128>,
|
|
678
|
-
): Boolean {
|
|
679
|
-
return FungibleToken_transferFrom(from, to, value);
|
|
369
|
+
ledger {
|
|
370
|
+
...FungibleToken.ledger;
|
|
371
|
+
...Ownable.ledger;
|
|
680
372
|
}
|
|
681
|
-
\`\`\`
|
|
682
373
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
import "./compact-contracts/node_modules/@openzeppelin-compact/contracts/src/access/Ownable" prefix Ownable_;
|
|
687
|
-
|
|
688
|
-
export circuit mint(
|
|
689
|
-
to: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
690
|
-
amount: Uint<128>,
|
|
691
|
-
): [] {
|
|
692
|
-
Ownable_assertOnlyOwner();
|
|
693
|
-
FungibleToken__mint(to, amount);
|
|
374
|
+
export circuit mint(to: Address, amount: Field): Void {
|
|
375
|
+
Ownable.assertOnlyOwner();
|
|
376
|
+
FungibleToken.mint(to, amount);
|
|
694
377
|
}
|
|
695
378
|
|
|
696
|
-
export circuit burn(
|
|
697
|
-
|
|
698
|
-
amount: Uint<128>,
|
|
699
|
-
): [] {
|
|
700
|
-
Ownable_assertOnlyOwner();
|
|
701
|
-
FungibleToken__burn(from, amount);
|
|
379
|
+
export circuit burn(amount: Field): Void {
|
|
380
|
+
FungibleToken.burn(context.caller, amount);
|
|
702
381
|
}
|
|
703
382
|
\`\`\`
|
|
383
|
+
|
|
384
|
+
## Privacy Model
|
|
385
|
+
|
|
386
|
+
| Operation | Privacy |
|
|
387
|
+
|-----------|---------|
|
|
388
|
+
| Balance | Shielded (private) |
|
|
389
|
+
| Transfer amount | Shielded |
|
|
390
|
+
| Sender | Shielded |
|
|
391
|
+
| Recipient | Shielded |
|
|
392
|
+
| Transaction occurred | Public (proof exists) |
|
|
393
|
+
|
|
394
|
+
## Important Notes
|
|
395
|
+
|
|
396
|
+
1. **No approval mechanism** - Unlike ERC20, transfers are direct
|
|
397
|
+
2. **Balances are commitments** - Not stored as plain values
|
|
398
|
+
3. **Privacy by default** - Explicit disclosure required to reveal
|
|
704
399
|
`,
|
|
705
400
|
"midnight://docs/openzeppelin/access": `# OpenZeppelin Access Control
|
|
706
401
|
|
|
707
|
-
|
|
402
|
+
Patterns for controlling who can call contract functions.
|
|
708
403
|
|
|
709
404
|
## Ownable
|
|
710
405
|
|
|
711
406
|
Simple single-owner access control.
|
|
712
407
|
|
|
713
408
|
\`\`\`compact
|
|
714
|
-
|
|
409
|
+
include "@openzeppelin/compact-contracts/access/Ownable.compact";
|
|
715
410
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
constructor(
|
|
719
|
-
_owner: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
720
|
-
) {
|
|
721
|
-
Ownable_initialize(_owner);
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
// Only owner can call this
|
|
725
|
-
export circuit adminFunction(): [] {
|
|
726
|
-
Ownable_assertOnlyOwner();
|
|
727
|
-
// ... admin logic
|
|
411
|
+
ledger {
|
|
412
|
+
...Ownable.ledger;
|
|
728
413
|
}
|
|
729
414
|
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
newOwner: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
733
|
-
): [] {
|
|
734
|
-
Ownable_assertOnlyOwner();
|
|
735
|
-
Ownable_transferOwnership(newOwner);
|
|
415
|
+
export circuit initialize(owner: Address): Void {
|
|
416
|
+
Ownable.initialize(owner);
|
|
736
417
|
}
|
|
737
418
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
Ownable_renounceOwnership();
|
|
419
|
+
export circuit adminFunction(): Void {
|
|
420
|
+
Ownable.assertOnlyOwner();
|
|
421
|
+
// Only owner can execute this
|
|
742
422
|
}
|
|
743
423
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
424
|
+
export circuit transferOwnership(newOwner: Address): Void {
|
|
425
|
+
Ownable.assertOnlyOwner();
|
|
426
|
+
Ownable.transferOwnership(newOwner);
|
|
747
427
|
}
|
|
748
428
|
\`\`\`
|
|
749
429
|
|
|
750
|
-
##
|
|
430
|
+
## Role-Based Access Control
|
|
751
431
|
|
|
752
|
-
For
|
|
432
|
+
For more complex permission systems.
|
|
753
433
|
|
|
754
434
|
\`\`\`compact
|
|
755
|
-
|
|
435
|
+
include "@openzeppelin/compact-contracts/access/AccessControl.compact";
|
|
756
436
|
|
|
757
|
-
|
|
437
|
+
ledger {
|
|
438
|
+
...AccessControl.ledger;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const ADMIN_ROLE: Bytes<32> = keccak256("ADMIN_ROLE");
|
|
758
442
|
const MINTER_ROLE: Bytes<32> = keccak256("MINTER_ROLE");
|
|
759
|
-
const PAUSER_ROLE: Bytes<32> = keccak256("PAUSER_ROLE");
|
|
760
443
|
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
444
|
+
export circuit initialize(admin: Address): Void {
|
|
445
|
+
AccessControl.grantRole(ADMIN_ROLE, admin);
|
|
446
|
+
AccessControl.setRoleAdmin(MINTER_ROLE, ADMIN_ROLE);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
export circuit mint(to: Address, amount: Field): Void {
|
|
450
|
+
AccessControl.assertHasRole(MINTER_ROLE);
|
|
451
|
+
// Mint tokens
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
export circuit grantMinterRole(account: Address): Void {
|
|
455
|
+
AccessControl.assertHasRole(ADMIN_ROLE);
|
|
456
|
+
AccessControl.grantRole(MINTER_ROLE, account);
|
|
765
457
|
}
|
|
458
|
+
\`\`\`
|
|
766
459
|
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
460
|
+
## Combining Patterns
|
|
461
|
+
|
|
462
|
+
\`\`\`compact
|
|
463
|
+
include "@openzeppelin/compact-contracts/access/Ownable.compact";
|
|
464
|
+
include "@openzeppelin/compact-contracts/security/Pausable.compact";
|
|
465
|
+
|
|
466
|
+
ledger {
|
|
467
|
+
...Ownable.ledger;
|
|
468
|
+
...Pausable.ledger;
|
|
771
469
|
}
|
|
772
470
|
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
//
|
|
471
|
+
export circuit criticalFunction(): Void {
|
|
472
|
+
Ownable.assertOnlyOwner();
|
|
473
|
+
Pausable.assertNotPaused();
|
|
474
|
+
// Execute critical logic
|
|
777
475
|
}
|
|
778
476
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
account: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
783
|
-
): [] {
|
|
784
|
-
AC_assertOnlyRole(AC_DEFAULT_ADMIN_ROLE());
|
|
785
|
-
AC__grantRole(role, account);
|
|
477
|
+
export circuit pause(): Void {
|
|
478
|
+
Ownable.assertOnlyOwner();
|
|
479
|
+
Pausable.pause();
|
|
786
480
|
}
|
|
787
481
|
\`\`\`
|
|
788
482
|
`,
|
|
789
483
|
"midnight://docs/openzeppelin/security": `# OpenZeppelin Security Patterns
|
|
790
484
|
|
|
791
|
-
Security
|
|
485
|
+
Security utilities for Compact contracts.
|
|
792
486
|
|
|
793
487
|
## Pausable
|
|
794
488
|
|
|
795
|
-
Emergency stop mechanism for
|
|
489
|
+
Emergency stop mechanism for contracts.
|
|
796
490
|
|
|
797
491
|
\`\`\`compact
|
|
798
|
-
|
|
492
|
+
include "@openzeppelin/compact-contracts/security/Pausable.compact";
|
|
493
|
+
include "@openzeppelin/compact-contracts/access/Ownable.compact";
|
|
799
494
|
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
constructor(_owner: Either<ZswapCoinPublicKey, ContractAddress>) {
|
|
804
|
-
Ownable_initialize(_owner);
|
|
805
|
-
// Contract starts unpaused
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
// Protected function - won't work when paused
|
|
809
|
-
export circuit transfer(
|
|
810
|
-
to: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
811
|
-
amount: Uint<128>,
|
|
812
|
-
): Boolean {
|
|
813
|
-
Pausable_assertNotPaused();
|
|
814
|
-
// ... transfer logic
|
|
495
|
+
ledger {
|
|
496
|
+
...Pausable.ledger;
|
|
497
|
+
...Ownable.ledger;
|
|
815
498
|
}
|
|
816
499
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
Pausable__pause();
|
|
500
|
+
export circuit transfer(to: Address, amount: Field): Void {
|
|
501
|
+
Pausable.assertNotPaused();
|
|
502
|
+
// Transfer logic
|
|
821
503
|
}
|
|
822
504
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
Pausable__unpause();
|
|
505
|
+
export circuit pause(): Void {
|
|
506
|
+
Ownable.assertOnlyOwner();
|
|
507
|
+
Pausable.pause();
|
|
827
508
|
}
|
|
828
509
|
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
510
|
+
export circuit unpause(): Void {
|
|
511
|
+
Ownable.assertOnlyOwner();
|
|
512
|
+
Pausable.unpause();
|
|
832
513
|
}
|
|
833
514
|
\`\`\`
|
|
834
515
|
|
|
835
|
-
##
|
|
516
|
+
## When to Use Pausable
|
|
836
517
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
import "./compact-contracts/node_modules/@openzeppelin-compact/contracts/src/token/FungibleToken" prefix FungibleToken_;
|
|
844
|
-
|
|
845
|
-
constructor(
|
|
846
|
-
_name: Opaque<"string">,
|
|
847
|
-
_symbol: Opaque<"string">,
|
|
848
|
-
_decimals: Uint<8>,
|
|
849
|
-
_initialSupply: Uint<128>,
|
|
850
|
-
_owner: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
851
|
-
) {
|
|
852
|
-
Ownable_initialize(_owner);
|
|
853
|
-
FungibleToken_initialize(_name, _symbol, _decimals);
|
|
854
|
-
FungibleToken__mint(_owner, _initialSupply);
|
|
855
|
-
}
|
|
518
|
+
- Token contracts handling real value
|
|
519
|
+
- DeFi protocols with liquidity
|
|
520
|
+
- Contracts with upgrade mechanisms
|
|
521
|
+
- Any contract where bugs could cause fund loss
|
|
522
|
+
|
|
523
|
+
## Implementation Details
|
|
856
524
|
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
): Boolean {
|
|
862
|
-
Pausable_assertNotPaused();
|
|
863
|
-
return FungibleToken_transfer(to, value);
|
|
525
|
+
\`\`\`compact
|
|
526
|
+
// Pausable module internals (simplified)
|
|
527
|
+
ledger {
|
|
528
|
+
paused: Boolean;
|
|
864
529
|
}
|
|
865
530
|
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
to: Either<ZswapCoinPublicKey, ContractAddress>,
|
|
869
|
-
amount: Uint<128>,
|
|
870
|
-
): [] {
|
|
871
|
-
Ownable_assertOnlyOwner();
|
|
872
|
-
Pausable_assertNotPaused();
|
|
873
|
-
FungibleToken__mint(to, amount);
|
|
531
|
+
circuit Pausable_assertNotPaused(): Void {
|
|
532
|
+
assert(!ledger.paused, "Contract is paused");
|
|
874
533
|
}
|
|
875
534
|
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
Ownable_assertOnlyOwner();
|
|
879
|
-
Pausable__pause();
|
|
535
|
+
circuit Pausable_pause(): Void {
|
|
536
|
+
ledger.paused = true;
|
|
880
537
|
}
|
|
881
538
|
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
Pausable__unpause();
|
|
539
|
+
circuit Pausable_unpause(): Void {
|
|
540
|
+
ledger.paused = false;
|
|
885
541
|
}
|
|
886
542
|
\`\`\`
|
|
887
543
|
|
|
@@ -893,281 +549,345 @@ export circuit unpause(): [] {
|
|
|
893
549
|
4. **Document pause conditions** for users
|
|
894
550
|
5. **Consider timelock** for unpause in high-value contracts
|
|
895
551
|
`,
|
|
896
|
-
"midnight://docs/tokenomics": `# Midnight Tokenomics
|
|
897
|
-
|
|
898
|
-
## Overview
|
|
899
|
-
|
|
900
|
-
Midnight introduces a novel dual-component tokenomics system with NIGHT (utility token) and DUST (transaction resource), designed for operational predictability, privacy, and cross-chain cooperation.
|
|
901
|
-
|
|
902
|
-
## Core Pillars
|
|
903
|
-
|
|
904
|
-
1. **Operational Predictability**: NIGHT generates DUST continuously, enabling transactions without direct token expenditure
|
|
905
|
-
2. **Rational Privacy**: DUST is shielded - transactions don't leave metadata trails
|
|
906
|
-
3. **Cooperative Tokenomics**: Multi-chain architecture enables cross-chain value creation
|
|
907
|
-
4. **Fair Distribution**: Free, multi-phase token distribution (Glacier Drop)
|
|
908
|
-
|
|
909
|
-
---
|
|
910
|
-
|
|
911
|
-
## The NIGHT Token
|
|
552
|
+
"midnight://docs/tokenomics": `# Midnight Tokenomics Summary
|
|
912
553
|
|
|
913
|
-
|
|
554
|
+
A curated summary of the Midnight Tokenomics Whitepaper (June 2025).
|
|
914
555
|
|
|
915
|
-
|
|
556
|
+
## Dual-Token Model
|
|
916
557
|
|
|
917
|
-
|
|
918
|
-
- **Transferable**: Can be freely transferred, listed on exchanges, bridged across networks
|
|
919
|
-
- **Total Supply**: 24 billion NIGHT tokens
|
|
920
|
-
- **Non-expendable**: Not consumed to execute transactions
|
|
921
|
-
- **Disinflationary**: Circulating supply expansion slows over time
|
|
922
|
-
- **Multi-chain Native**: Exists natively on both Cardano (as Native Asset) and Midnight
|
|
558
|
+
Midnight uses two components: **NIGHT** (token) and **DUST** (resource).
|
|
923
559
|
|
|
924
|
-
###
|
|
560
|
+
### NIGHT Token
|
|
561
|
+
- **Supply**: 24 billion (fixed)
|
|
562
|
+
- **Subunit**: 1 NIGHT = 1,000,000 STARs
|
|
563
|
+
- **Visibility**: Unshielded (public)
|
|
564
|
+
- **Function**: Generates DUST, governance, block rewards
|
|
565
|
+
- **Multi-chain**: Native on both Cardano and Midnight
|
|
925
566
|
|
|
926
|
-
|
|
927
|
-
- **
|
|
928
|
-
- **
|
|
929
|
-
- **
|
|
930
|
-
- **
|
|
567
|
+
### DUST Resource
|
|
568
|
+
- **Type**: Shielded, non-transferable
|
|
569
|
+
- **Function**: Pay transaction fees
|
|
570
|
+
- **Generation**: Continuously from NIGHT holdings
|
|
571
|
+
- **Decay**: When disassociated from NIGHT
|
|
572
|
+
- **Privacy**: Transactions don't leak metadata
|
|
931
573
|
|
|
932
|
-
|
|
574
|
+
## Key Insight: NIGHT Generates DUST
|
|
933
575
|
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
576
|
+
\`\`\`
|
|
577
|
+
Hold NIGHT → Generates DUST → Pay for transactions
|
|
578
|
+
(continuous) (consumed on use)
|
|
579
|
+
\`\`\`
|
|
937
580
|
|
|
938
|
-
|
|
581
|
+
This means: **Hold NIGHT, transact "for free"** (no recurring token spend)
|
|
939
582
|
|
|
940
|
-
|
|
583
|
+
## Block Rewards
|
|
941
584
|
|
|
585
|
+
**Formula**:
|
|
942
586
|
\`\`\`
|
|
943
|
-
|
|
587
|
+
Actual Reward = Base Reward × [S + (1-S) × U]
|
|
944
588
|
|
|
945
589
|
Where:
|
|
946
|
-
-
|
|
947
|
-
-
|
|
948
|
-
- S = Total Supply
|
|
590
|
+
- S = Subsidy rate (95% at launch)
|
|
591
|
+
- U = Block utilization (target: 50%)
|
|
949
592
|
\`\`\`
|
|
950
593
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
594
|
+
- Full blocks: Producer gets 100% of base reward
|
|
595
|
+
- Empty blocks: Producer gets only subsidy (95%)
|
|
596
|
+
- Remainder goes to Treasury
|
|
954
597
|
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
### Key Properties
|
|
598
|
+
## Token Distribution
|
|
958
599
|
|
|
959
|
-
|
|
960
|
-
-
|
|
961
|
-
-
|
|
962
|
-
-
|
|
963
|
-
- **Non-transferable**: Cannot be bought, sold, or transferred between addresses
|
|
964
|
-
- **MEV-resistant**: Shielding prevents attackers from identifying victims
|
|
600
|
+
### Phase 1: Glacier Drop (60 days)
|
|
601
|
+
- Free allocation to crypto holders
|
|
602
|
+
- 50% to Cardano, 20% to Bitcoin, 30% to others
|
|
603
|
+
- Minimum $100 USD equivalent required
|
|
965
604
|
|
|
966
|
-
###
|
|
605
|
+
### Phase 2: Scavenger Mine (30 days)
|
|
606
|
+
- Computational puzzles (accessible to public)
|
|
607
|
+
- Claims unclaimed Glacier Drop tokens
|
|
608
|
+
- Seeds network constituents
|
|
967
609
|
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
3. Cap is proportional to associated NIGHT balance
|
|
610
|
+
### Phase 3: Lost-and-Found (4 years)
|
|
611
|
+
- Second chance for Glacier Drop eligible
|
|
612
|
+
- Fractional allocation
|
|
972
613
|
|
|
973
|
-
|
|
614
|
+
## Key Differentiators
|
|
974
615
|
|
|
975
|
-
**
|
|
976
|
-
|
|
977
|
-
-
|
|
978
|
-
|
|
616
|
+
1. **No token spend for transactions** - DUST is renewable
|
|
617
|
+
2. **MEV resistant** - Shielded transactions
|
|
618
|
+
3. **Cross-chain native** - Same token on Cardano + Midnight
|
|
619
|
+
4. **Fair distribution** - Free, multi-phase, broad eligibility
|
|
620
|
+
`,
|
|
621
|
+
"midnight://docs/wallet-integration": `# Midnight Wallet Integration Guide
|
|
979
622
|
|
|
980
|
-
|
|
981
|
-
- Severing NIGHT association causes linear decay
|
|
982
|
-
- Prevents double-spending through cap enforcement
|
|
623
|
+
A guide for integrating Midnight Lace wallet into your DApp.
|
|
983
624
|
|
|
984
|
-
|
|
625
|
+
## Browser Detection
|
|
985
626
|
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
627
|
+
\`\`\`typescript
|
|
628
|
+
declare global {
|
|
629
|
+
interface Window {
|
|
630
|
+
midnight?: {
|
|
631
|
+
mnLace?: MidnightProvider;
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
}
|
|
989
635
|
|
|
990
|
-
|
|
636
|
+
function isWalletAvailable(): boolean {
|
|
637
|
+
return typeof window !== 'undefined'
|
|
638
|
+
&& window.midnight?.mnLace !== undefined;
|
|
639
|
+
}
|
|
640
|
+
\`\`\`
|
|
991
641
|
|
|
992
|
-
##
|
|
642
|
+
## DApp Connector API
|
|
993
643
|
|
|
994
|
-
|
|
644
|
+
\`\`\`typescript
|
|
645
|
+
interface DAppConnectorAPI {
|
|
646
|
+
enable(): Promise<MidnightAPI>;
|
|
647
|
+
isEnabled(): Promise<boolean>;
|
|
648
|
+
apiVersion(): string;
|
|
649
|
+
name(): string;
|
|
650
|
+
icon(): string;
|
|
651
|
+
}
|
|
995
652
|
|
|
996
|
-
|
|
997
|
-
|
|
653
|
+
async function connectWallet(): Promise<MidnightAPI> {
|
|
654
|
+
if (!window.midnight?.mnLace) {
|
|
655
|
+
throw new Error('Midnight Lace wallet not found');
|
|
656
|
+
}
|
|
657
|
+
return await window.midnight.mnLace.enable();
|
|
658
|
+
}
|
|
998
659
|
\`\`\`
|
|
999
660
|
|
|
1000
|
-
|
|
1001
|
-
- **Congestion Rate**: Dynamic multiplier based on network demand
|
|
1002
|
-
- **Transaction Weight**: Based on computational resources (initially storage in KB)
|
|
661
|
+
## MidnightAPI Interface
|
|
1003
662
|
|
|
1004
|
-
|
|
663
|
+
\`\`\`typescript
|
|
664
|
+
interface MidnightAPI {
|
|
665
|
+
getUsedAddresses(): Promise<string[]>;
|
|
666
|
+
getBalance(): Promise<Balance>;
|
|
667
|
+
signTx(tx: Transaction): Promise<SignedTransaction>;
|
|
668
|
+
submitTx(signedTx: SignedTransaction): Promise<TxHash>;
|
|
669
|
+
signData(address: string, payload: string): Promise<Signature>;
|
|
670
|
+
}
|
|
671
|
+
\`\`\`
|
|
1005
672
|
|
|
1006
|
-
|
|
1007
|
-
- Above 50%: Fees increase to manage congestion
|
|
1008
|
-
- Acts as automatic stabilizer for network efficiency
|
|
673
|
+
## React Hook
|
|
1009
674
|
|
|
1010
|
-
|
|
675
|
+
\`\`\`typescript
|
|
676
|
+
export function useWallet() {
|
|
677
|
+
const [state, setState] = useState({
|
|
678
|
+
isConnected: false,
|
|
679
|
+
address: null as string | null,
|
|
680
|
+
isLoading: false,
|
|
681
|
+
error: null as string | null,
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
const connect = useCallback(async () => {
|
|
685
|
+
setState(prev => ({ ...prev, isLoading: true, error: null }));
|
|
686
|
+
try {
|
|
687
|
+
if (!window.midnight?.mnLace) {
|
|
688
|
+
throw new Error('Please install Midnight Lace wallet');
|
|
689
|
+
}
|
|
690
|
+
const api = await window.midnight.mnLace.enable();
|
|
691
|
+
const addresses = await api.getUsedAddresses();
|
|
692
|
+
setState({
|
|
693
|
+
isConnected: true,
|
|
694
|
+
address: addresses[0] || null,
|
|
695
|
+
isLoading: false,
|
|
696
|
+
error: null,
|
|
697
|
+
});
|
|
698
|
+
return api;
|
|
699
|
+
} catch (error) {
|
|
700
|
+
setState(prev => ({
|
|
701
|
+
...prev,
|
|
702
|
+
isLoading: false,
|
|
703
|
+
error: error instanceof Error ? error.message : 'Failed',
|
|
704
|
+
}));
|
|
705
|
+
throw error;
|
|
706
|
+
}
|
|
707
|
+
}, []);
|
|
708
|
+
|
|
709
|
+
return { ...state, connect };
|
|
710
|
+
}
|
|
711
|
+
\`\`\`
|
|
712
|
+
|
|
713
|
+
## Connection Flow
|
|
714
|
+
|
|
715
|
+
\`\`\`
|
|
716
|
+
1. User clicks "Connect Wallet"
|
|
717
|
+
2. DApp calls window.midnight.mnLace.enable()
|
|
718
|
+
3. Wallet popup asks user to approve
|
|
719
|
+
4. User approves → DApp receives MidnightAPI
|
|
720
|
+
5. DApp can now interact with wallet
|
|
721
|
+
\`\`\`
|
|
1011
722
|
|
|
1012
|
-
##
|
|
723
|
+
## Best Practices
|
|
1013
724
|
|
|
1014
|
-
|
|
725
|
+
1. Always check wallet availability first
|
|
726
|
+
2. Handle user rejection gracefully
|
|
727
|
+
3. Store connection state in context
|
|
728
|
+
4. Provide clear loading/error feedback
|
|
729
|
+
5. Test with Midnight Lace extension
|
|
730
|
+
`,
|
|
731
|
+
// Common Errors Reference - VERIFIED from official Midnight documentation
|
|
732
|
+
"midnight://docs/common-errors": `# Common Midnight Errors & Solutions
|
|
1015
733
|
|
|
1016
|
-
|
|
1017
|
-
- Initial producers don't receive rewards
|
|
1018
|
-
- Progressive decentralization planned
|
|
734
|
+
Verified error messages from official Midnight documentation.
|
|
1019
735
|
|
|
1020
|
-
|
|
736
|
+
## Version Mismatch Errors
|
|
1021
737
|
|
|
1022
|
-
|
|
1023
|
-
- Selection proportional to delegated ADA stake
|
|
1024
|
-
- Dual-network participation doesn't affect Cardano rewards
|
|
738
|
+
**Source:** [Fix version mismatch errors guide](https://docs.midnight.network/how-to/fix-version-mismatches)
|
|
1025
739
|
|
|
1026
|
-
|
|
740
|
+
Version mismatches occur when Midnight components are out of sync:
|
|
741
|
+
- Compact compiler
|
|
742
|
+
- Runtime libraries (@midnight-ntwrk/compact-runtime, @midnight-ntwrk/ledger)
|
|
743
|
+
- Proof server
|
|
744
|
+
- Indexer
|
|
1027
745
|
|
|
1028
|
-
|
|
746
|
+
### "Version mismatch" / CompactError
|
|
747
|
+
\`\`\`javascript
|
|
748
|
+
// The runtime checks version compatibility on startup
|
|
749
|
+
throw new __compactRuntime.CompactError(\`Version mismatch...\`);
|
|
1029
750
|
\`\`\`
|
|
1030
|
-
R = π(1 - B - T) / (B × γ)
|
|
1031
751
|
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
752
|
+
**Fix:** Check versions and update all components together:
|
|
753
|
+
\`\`\`bash
|
|
754
|
+
# Check your versions
|
|
755
|
+
compact --version
|
|
756
|
+
npm list @midnight-ntwrk/compact-runtime
|
|
757
|
+
npm list @midnight-ntwrk/ledger
|
|
1038
758
|
|
|
1039
|
-
|
|
759
|
+
# Consult the compatibility matrix
|
|
760
|
+
# https://docs.midnight.network/relnotes/support-matrix
|
|
1040
761
|
\`\`\`
|
|
1041
|
-
Nb = Bo × R
|
|
1042
762
|
|
|
1043
|
-
|
|
1044
|
-
\`\`\`
|
|
763
|
+
## Compact Compiler Errors
|
|
1045
764
|
|
|
1046
|
-
###
|
|
765
|
+
### "invalid context for a ledger ADT type"
|
|
766
|
+
**Source:** Compact 0.15/0.23 release notes
|
|
1047
767
|
|
|
1048
|
-
|
|
768
|
+
Ledger ADT types (Counter, Map, etc.) cannot be used as Compact types in casts.
|
|
1049
769
|
|
|
1050
|
-
\`\`\`
|
|
1051
|
-
|
|
1052
|
-
|
|
770
|
+
\`\`\`compact
|
|
771
|
+
// ❌ Wrong - casting to ledger ADT type
|
|
772
|
+
const x = value as Counter; // Error!
|
|
1053
773
|
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
- U = Block utilization ratio
|
|
774
|
+
// ✅ Correct - use the ledger field directly
|
|
775
|
+
ledger.counter.increment(1);
|
|
1057
776
|
\`\`\`
|
|
1058
777
|
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
- **Partially full**: Linear interpolation between them
|
|
1062
|
-
|
|
1063
|
-
---
|
|
1064
|
-
|
|
1065
|
-
## Token Distribution
|
|
1066
|
-
|
|
1067
|
-
### Design Principles
|
|
1068
|
-
|
|
1069
|
-
- **Broad**: No single party dominates
|
|
1070
|
-
- **Inclusive**: Open to participants beyond crypto
|
|
1071
|
-
- **Free**: Allocated at no cost
|
|
1072
|
-
- **Transparent**: Open-source audited smart contracts
|
|
1073
|
-
|
|
1074
|
-
### Phase 1: Glacier Drop (60 days)
|
|
1075
|
-
|
|
1076
|
-
**Eligible Networks**:
|
|
1077
|
-
- Cardano (50% allocation)
|
|
1078
|
-
- Bitcoin (20% allocation)
|
|
1079
|
-
- Ethereum, Solana, XRPL, BNB Chain, Avalanche, Brave (remaining 30%, proportional)
|
|
778
|
+
### "static type error" - argument count/type mismatch
|
|
779
|
+
**Source:** Compact runtime type checks
|
|
1080
780
|
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
781
|
+
\`\`\`javascript
|
|
782
|
+
// Runtime validates argument counts
|
|
783
|
+
if (args_1.length !== 2)
|
|
784
|
+
throw new __compactRuntime.CompactError(
|
|
785
|
+
\`post: expected 2 arguments, received \${args_1.length}\`
|
|
786
|
+
);
|
|
787
|
+
\`\`\`
|
|
1085
788
|
|
|
1086
|
-
**
|
|
1087
|
-
1. Sign message proving address ownership
|
|
1088
|
-
2. Provide unused Cardano address for redemption
|
|
1089
|
-
3. Tokens initially frozen, thaw during redemption period
|
|
789
|
+
**Fix:** Ensure TypeScript calls match circuit signatures exactly.
|
|
1090
790
|
|
|
1091
|
-
###
|
|
791
|
+
### assert() failures
|
|
792
|
+
**Source:** [Compact language reference](https://docs.midnight.network/develop/reference/compact/lang-ref)
|
|
1092
793
|
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
794
|
+
\`\`\`compact
|
|
795
|
+
// Assert syntax (Compact 0.16+)
|
|
796
|
+
assert(condition, "error message");
|
|
1096
797
|
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
- ~10% → Midnight TGE (partnerships/liquidity)
|
|
1101
|
-
- ~5% → On-chain Treasury
|
|
1102
|
-
- Rest → Scavenger Mine participants + Lost-and-Found
|
|
798
|
+
// Example from bboard tutorial
|
|
799
|
+
assert(ledger.state == State.VACANT, "Attempted to post to an occupied board");
|
|
800
|
+
\`\`\`
|
|
1103
801
|
|
|
1104
|
-
|
|
802
|
+
**Note:** If assertion fails, the transaction fails without reaching the chain.
|
|
1105
803
|
|
|
1106
|
-
|
|
1107
|
-
- Fractional allocation of original entitlement
|
|
1108
|
-
- After 4 years, unclaimed tokens go to Treasury
|
|
804
|
+
## TypeScript SDK Errors
|
|
1109
805
|
|
|
1110
|
-
###
|
|
806
|
+
### ContractTypeError
|
|
807
|
+
**Source:** @midnight-ntwrk/midnight-js-contracts
|
|
1111
808
|
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
- 25% unlock at start, then every 90 days
|
|
1115
|
-
- Total: 4 unlocks over 360 days
|
|
809
|
+
Thrown when there's a contract type mismatch between the given contract type
|
|
810
|
+
and the initial state deployed at a contract address.
|
|
1116
811
|
|
|
1117
|
-
|
|
812
|
+
\`\`\`typescript
|
|
813
|
+
// Typically thrown by findDeployedContract()
|
|
814
|
+
try {
|
|
815
|
+
const contract = await findDeployedContract(provider, address, MyContract);
|
|
816
|
+
} catch (e) {
|
|
817
|
+
if (e instanceof ContractTypeError) {
|
|
818
|
+
// The contract at this address is a different type
|
|
819
|
+
console.error('Contract type mismatch:', e.circuitIds);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
\`\`\`
|
|
1118
823
|
|
|
1119
|
-
|
|
824
|
+
### type_error() - Runtime type errors
|
|
825
|
+
**Source:** @midnight-ntwrk/compact-runtime
|
|
1120
826
|
|
|
1121
|
-
|
|
827
|
+
Internal function for type errors with parameters: who, what, where, type, value.
|
|
1122
828
|
|
|
1123
|
-
|
|
829
|
+
## DApp Connector Errors
|
|
1124
830
|
|
|
1125
|
-
**
|
|
1126
|
-
- DUST generation leasing
|
|
1127
|
-
- Broker-managed leasing
|
|
1128
|
-
- Babel Station (DUST filling station using ZSwap)
|
|
831
|
+
**Source:** @midnight-ntwrk/dapp-connector-api ErrorCodes
|
|
1129
832
|
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
- On-chain capacity exchange
|
|
833
|
+
\`\`\`typescript
|
|
834
|
+
import { ErrorCodes } from '@midnight-ntwrk/dapp-connector-api';
|
|
1133
835
|
|
|
1134
|
-
|
|
836
|
+
// ErrorCodes.Rejected - User rejected the request
|
|
837
|
+
// ErrorCodes.InvalidRequest - Malformed transaction or request
|
|
838
|
+
// ErrorCodes.InternalError - DApp connector couldn't process request
|
|
1135
839
|
|
|
1136
|
-
|
|
840
|
+
try {
|
|
841
|
+
const api = await window.midnight.mnLace.enable();
|
|
842
|
+
} catch (error) {
|
|
843
|
+
if (error.code === ErrorCodes.Rejected) {
|
|
844
|
+
console.log('User rejected wallet connection');
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
\`\`\`
|
|
1137
848
|
|
|
1138
|
-
|
|
849
|
+
## Node.js Environment Errors
|
|
1139
850
|
|
|
1140
|
-
|
|
851
|
+
### ERR_UNSUPPORTED_DIR_IMPORT
|
|
852
|
+
**Source:** [BBoard tutorial troubleshooting](https://docs.midnight.network/develop/tutorial/3-creating/bboard-dapp)
|
|
1141
853
|
|
|
1142
|
-
|
|
854
|
+
Occurs due to environment caching after modifying shell config or changing Node versions.
|
|
1143
855
|
|
|
1144
|
-
|
|
856
|
+
**Fix:**
|
|
857
|
+
\`\`\`bash
|
|
858
|
+
# 1. Open a NEW terminal window (don't just source ~/.zshrc)
|
|
859
|
+
# 2. Verify Node version
|
|
860
|
+
nvm use 18
|
|
1145
861
|
|
|
1146
|
-
|
|
1147
|
-
-
|
|
1148
|
-
|
|
862
|
+
# 3. Clear cached modules
|
|
863
|
+
rm -rf node_modules/.cache
|
|
864
|
+
\`\`\`
|
|
1149
865
|
|
|
1150
|
-
|
|
866
|
+
## Transaction Errors
|
|
1151
867
|
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
- Treasury access for approved proposals
|
|
1155
|
-
- Automated protocol updates
|
|
868
|
+
### INSUFFICIENT_FUNDS / Not enough tDUST
|
|
869
|
+
**Source:** Midnight documentation examples
|
|
1156
870
|
|
|
1157
|
-
|
|
871
|
+
\`\`\`typescript
|
|
872
|
+
try {
|
|
873
|
+
const result = await sdk.sendTransaction(options);
|
|
874
|
+
} catch (error) {
|
|
875
|
+
if (error.code === 'INSUFFICIENT_FUNDS') {
|
|
876
|
+
console.error('Not enough tDUST in wallet');
|
|
877
|
+
// Direct user to testnet faucet
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
\`\`\`
|
|
1158
881
|
|
|
1159
|
-
##
|
|
882
|
+
## Debugging Resources
|
|
1160
883
|
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
- **Scavenger Mine**: Computational task-based distribution
|
|
1169
|
-
- **ZSwap**: Atomic asset swap mechanism for privacy
|
|
1170
|
-
- **Babel Station**: Service enabling tokenless transactions
|
|
884
|
+
1. **Compatibility Matrix:** [/relnotes/support-matrix](https://docs.midnight.network/relnotes/support-matrix)
|
|
885
|
+
2. **Discord:** #developer-support channel
|
|
886
|
+
3. **Recompile after updates:**
|
|
887
|
+
\`\`\`bash
|
|
888
|
+
rm -rf contract/*.cjs contract/*.prover contract/*.verifier
|
|
889
|
+
compact compile src/contract.compact contract/
|
|
890
|
+
\`\`\`
|
|
1171
891
|
`,
|
|
1172
892
|
};
|
|
1173
893
|
//# sourceMappingURL=docs-content.js.map
|