midnight-mcp 0.1.2 → 0.1.4

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.
@@ -1,11 +1,19 @@
1
1
  /**
2
- * Embedded documentation content for offline access
3
- * Separated from docs.ts for better maintainability
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
- Compact is a TypeScript-inspired language for writing privacy-preserving smart contracts on Midnight.
16
+ A curated syntax reference for Compact - Midnight's smart contract language.
9
17
 
10
18
  ## Basic Structure
11
19
 
@@ -78,820 +86,647 @@ witness getCurrentPrice(): Field {
78
86
  return fetchPrice();
79
87
  }
80
88
 
81
- export circuit swap(amount: Field): Void {
89
+ export circuit buyAtMarketPrice(maxPrice: Field): Void {
82
90
  const price = getCurrentPrice();
83
- // Use price in circuit logic
91
+ assert(price <= maxPrice);
92
+ // ... execute purchase
84
93
  }
85
94
  \`\`\`
86
95
 
87
- ## Built-in Functions
88
-
89
- ### Cryptographic
90
- - \`hash(data)\` - Compute cryptographic hash
91
- - \`commit(value)\` - Create hiding commitment
92
- - \`disclose(private)\` - Reveal private data
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
93
101
 
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
+ ## State Management
102
103
 
103
- ## Privacy Annotations
104
+ ### Public State
105
+ \`\`\`compact
106
+ ledger {
107
+ publicCounter: Counter;
108
+ publicMap: Map<Field, Field>;
109
+ }
110
+ \`\`\`
104
111
 
112
+ ### Private State
105
113
  \`\`\`compact
106
114
  ledger {
107
- publicData: Field; // Visible on-chain
108
115
  @private
109
- privateData: Field; // Only owner sees
116
+ secretBalance: Field;
117
+
118
+ @private
119
+ hiddenVotes: Map<Address, Field>;
120
+ }
121
+ \`\`\`
122
+
123
+ ## Common Patterns
124
+
125
+ ### Access Control
126
+ \`\`\`compact
127
+ ledger {
128
+ owner: Opaque<"address">;
129
+ }
130
+
131
+ witness getCaller(): Opaque<"address"> {
132
+ return context.caller;
133
+ }
134
+
135
+ export circuit ownerOnly(): Void {
136
+ assert(getCaller() == ledger.owner, "Not owner");
110
137
  }
111
138
  \`\`\`
139
+
140
+ ### Disclosure
141
+ \`\`\`compact
142
+ export circuit revealSecret(): Field {
143
+ const secret = getPrivateData();
144
+ return disclose(secret); // Makes private data public
145
+ }
146
+ \`\`\`
147
+
148
+ ### Assertions
149
+ \`\`\`compact
150
+ assert(condition); // Basic assertion
151
+ assert(condition, "Error message"); // With message
152
+ \`\`\`
112
153
  `,
113
- "midnight://docs/sdk-api": `# Midnight TypeScript SDK API
154
+ "midnight://docs/sdk-api": `# Midnight TypeScript SDK Quick Reference
114
155
 
115
156
  ## Installation
116
157
 
117
158
  \`\`\`bash
118
- npm install @midnight-ntwrk/midnight-js-contracts @midnight-ntwrk/midnight-js-types
159
+ npm install @midnight-ntwrk/midnight-js-contracts
119
160
  \`\`\`
120
161
 
121
- ## Core Packages
162
+ ## Core Types
122
163
 
123
- ### @midnight-ntwrk/midnight-js-contracts
124
- Contract interaction layer for deploying and calling Midnight smart contracts.
164
+ ### Contract Deployment
125
165
 
126
166
  \`\`\`typescript
127
- import { Contract, DeployedContract } from '@midnight-ntwrk/midnight-js-contracts';
167
+ import { deployContract, ContractDeployment } from '@midnight-ntwrk/midnight-js-contracts';
128
168
 
129
- // Deploy a contract
130
- const deployed = await Contract.deploy(
131
- wallet,
132
- contractArtifact,
133
- initialState
134
- );
169
+ const deployment: ContractDeployment = await deployContract({
170
+ contract: compiledContract,
171
+ privateState: initialPrivateState,
172
+ args: constructorArgs,
173
+ });
135
174
 
136
- // Call a circuit
137
- const result = await deployed.call('increment', { amount: 1n });
175
+ const { contractAddress, initialState } = deployment;
138
176
  \`\`\`
139
177
 
140
- ### @midnight-ntwrk/midnight-js-types
141
- Shared types and interfaces for the SDK.
178
+ ### Contract Interaction
142
179
 
143
180
  \`\`\`typescript
144
- import type {
145
- Address,
146
- Transaction,
147
- Proof,
148
- ContractState
149
- } from '@midnight-ntwrk/midnight-js-types';
150
- \`\`\`
181
+ import { callContract } from '@midnight-ntwrk/midnight-js-contracts';
151
182
 
152
- ### @midnight-ntwrk/wallet-api
153
- Wallet integration interface.
154
-
155
- \`\`\`typescript
156
- import { WalletAPI } from '@midnight-ntwrk/wallet-api';
183
+ // Call a circuit
184
+ const result = await callContract({
185
+ contractAddress,
186
+ circuitName: 'increment',
187
+ args: [amount],
188
+ privateState: currentPrivateState,
189
+ });
157
190
 
158
- const wallet = await WalletAPI.connect();
159
- const address = await wallet.getAddress();
160
- const balance = await wallet.getBalance();
191
+ // Result contains new state and return value
192
+ const { newPrivateState, returnValue, proof } = result;
161
193
  \`\`\`
162
194
 
163
- ## Common Patterns
195
+ ### Providers
164
196
 
165
- ### Contract Deployment
166
197
  \`\`\`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
- \`\`\`
198
+ import {
199
+ MidnightProvider,
200
+ createMidnightProvider
201
+ } from '@midnight-ntwrk/midnight-js-contracts';
181
202
 
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
- }
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
+ });
191
208
  \`\`\`
192
209
 
193
- ### Querying State
210
+ ## State Management
211
+
194
212
  \`\`\`typescript
195
- async function getState(contract: DeployedContract) {
196
- const publicState = await contract.query('publicField');
197
- // Note: Private state requires witness functions
198
- return publicState;
213
+ interface ContractState<T> {
214
+ publicState: PublicState;
215
+ privateState: T;
199
216
  }
200
- \`\`\`
201
- `,
202
- "midnight://docs/concepts/zero-knowledge": `# Zero-Knowledge Proofs in Midnight
203
-
204
- ## What are Zero-Knowledge Proofs?
205
217
 
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
218
+ // Subscribe to state changes
219
+ provider.subscribeToContract(contractAddress, (state) => {
220
+ console.log('New state:', state);
221
+ });
222
+ \`\`\`
209
223
 
210
- In Midnight, every circuit execution generates a zero-knowledge proof:
224
+ ## Transaction Building
211
225
 
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
226
+ \`\`\`typescript
227
+ import { buildTransaction } from '@midnight-ntwrk/midnight-js-contracts';
216
228
 
217
- ## Example
229
+ const tx = await buildTransaction({
230
+ contractAddress,
231
+ circuitName: 'transfer',
232
+ args: [recipient, amount],
233
+ privateState,
234
+ });
218
235
 
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
- }
236
+ // Sign and submit
237
+ const signedTx = await wallet.signTransaction(tx);
238
+ const txHash = await provider.submitTransaction(signedTx);
228
239
  \`\`\`
229
240
 
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
241
+ ## Error Handling
238
242
 
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
243
+ \`\`\`typescript
244
+ import { MidnightError, ContractError } from '@midnight-ntwrk/midnight-js-contracts';
244
245
 
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);
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
+ }
266
254
  }
267
255
  \`\`\`
268
256
  `,
269
- "midnight://docs/concepts/shielded-state": `# Shielded vs Unshielded State
257
+ "midnight://docs/openzeppelin": `# OpenZeppelin Contracts for Compact
270
258
 
271
- Midnight supports two types of state: shielded (private) and unshielded (public).
259
+ > **Official Documentation**: https://docs.openzeppelin.com/contracts-compact
260
+ > **GitHub Repository**: https://github.com/OpenZeppelin/compact-contracts
272
261
 
273
- ## Unshielded State
262
+ The official OpenZeppelin library for Midnight smart contracts provides battle-tested, audited implementations of common patterns.
274
263
 
275
- Public state visible to everyone on the blockchain:
264
+ ## Installation
276
265
 
277
- \`\`\`compact
278
- ledger {
279
- totalSupply: Counter; // Public counter
280
- balances: Map<Address, Field>; // Public mapping
281
- }
266
+ \`\`\`bash
267
+ npm install @openzeppelin/compact-contracts
282
268
  \`\`\`
283
269
 
284
- **Use for:**
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:
270
+ ## Available Modules
292
271
 
293
- \`\`\`compact
294
- ledger {
295
- @private
296
- secretKey: Bytes<32>;
297
-
298
- @private
299
- privateBalance: Field;
300
- }
301
- \`\`\`
272
+ ### Token Standards
273
+ - **FungibleToken** - Privacy-preserving token with shielded balances
274
+ - **NFT** - Non-fungible tokens with optional privacy
302
275
 
303
- **Use for:**
304
- - User credentials
305
- - Private balances
306
- - Sensitive personal data
276
+ ### Access Control
277
+ - **Ownable** - Single-owner access pattern
278
+ - **Roles** - Role-based access control
279
+ - **AccessControl** - Flexible permission system
307
280
 
308
- ## Hybrid Approach
281
+ ### Security
282
+ - **Pausable** - Emergency stop mechanism
283
+ - **ReentrancyGuard** - Prevent reentrancy attacks
309
284
 
310
- Most contracts use both:
285
+ ## Usage Example
311
286
 
312
287
  \`\`\`compact
288
+ include "std";
289
+ include "@openzeppelin/compact-contracts/token/FungibleToken.compact";
290
+ include "@openzeppelin/compact-contracts/access/Ownable.compact";
291
+
313
292
  ledger {
314
- // Public: anyone can see total messages
315
- messageCount: Counter;
316
-
317
- // Private: only owner sees message contents
318
- @private
319
- messages: Map<Field, Opaque<"string">>;
293
+ // Inherit from OpenZeppelin contracts
294
+ ...FungibleToken.ledger;
295
+ ...Ownable.ledger;
320
296
  }
321
297
 
322
- export circuit postMessage(content: Opaque<"string">): Void {
323
- const id = ledger.messageCount.value();
324
-
325
- // Public increment
326
- ledger.messageCount.increment(1);
327
-
328
- // Private storage
329
- ledger.messages.insert(id, content);
298
+ export circuit mint(to: Address, amount: Field): Void {
299
+ Ownable.assertOnlyOwner();
300
+ FungibleToken.mint(to, amount);
330
301
  }
331
302
  \`\`\`
332
303
 
333
- ## Transitioning Between States
334
-
335
- ### Disclose: Private → Public
336
- \`\`\`compact
337
- export circuit revealBalance(): Field {
338
- // Reveal private balance publicly
339
- return disclose(ledger.privateBalance);
340
- }
341
- \`\`\`
304
+ ## Best Practices
342
305
 
343
- ### Commit: Public Hidden
344
- \`\`\`compact
345
- export circuit hideValue(value: Field): Field {
346
- // Create commitment (hides value but proves existence)
347
- return commit(value);
348
- }
349
- \`\`\`
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
350
310
  `,
351
- "midnight://docs/concepts/witnesses": `# Witness Functions
352
-
353
- Witnesses provide off-chain data to circuits in Midnight.
311
+ "midnight://docs/openzeppelin/token": `# OpenZeppelin FungibleToken
354
312
 
355
- ## Why Witnesses?
313
+ The recommended standard for privacy-preserving tokens on Midnight.
356
314
 
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
315
+ ## Features
362
316
 
363
- Witnesses bridge this gap by running off-chain.
317
+ - Shielded balances (private by default)
318
+ - Optional public balance disclosure
319
+ - Transfer with ZK proofs
320
+ - Mint/burn capabilities
364
321
 
365
- ## Basic Witness
322
+ ## Basic Usage
366
323
 
367
324
  \`\`\`compact
368
- // Runs off-chain, provides data to circuits
369
- witness getTimestamp(): Field {
370
- return getCurrentUnixTime();
371
- }
325
+ include "std";
326
+ include "@openzeppelin/compact-contracts/token/FungibleToken.compact";
372
327
 
373
- export circuit timedAction(): Void {
374
- const timestamp = getTimestamp();
375
- assert(timestamp > ledger.deadline);
376
- // ... perform action
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);
377
346
  }
378
- \`\`\`
379
347
 
380
- ## Witness with Parameters
348
+ // Shielded transfer
349
+ export circuit transfer(to: Address, amount: Field): Void {
350
+ FungibleToken.transfer(to, amount);
351
+ }
381
352
 
382
- \`\`\`compact
383
- witness fetchPrice(asset: Opaque<"string">): Field {
384
- // Off-chain: call price oracle
385
- return callPriceOracle(asset);
353
+ // Check balance (private)
354
+ witness myBalance(): Field {
355
+ return FungibleToken.balanceOf(context.caller);
386
356
  }
387
357
 
388
- export circuit swap(asset: Opaque<"string">, amount: Field): Void {
389
- const price = fetchPrice(asset);
390
- const total = amount * price;
391
- // ... execute swap
358
+ // Reveal balance publicly (optional)
359
+ export circuit revealBalance(): Field {
360
+ return disclose(myBalance());
392
361
  }
393
362
  \`\`\`
394
363
 
395
- ## Private Data Access
396
-
397
- Witnesses can access private ledger state:
364
+ ## Minting and Burning
398
365
 
399
366
  \`\`\`compact
367
+ include "@openzeppelin/compact-contracts/access/Ownable.compact";
368
+
400
369
  ledger {
401
- @private
402
- secretNonce: Field;
370
+ ...FungibleToken.ledger;
371
+ ...Ownable.ledger;
403
372
  }
404
373
 
405
- witness getNextNonce(): Field {
406
- const current = ledger.secretNonce;
407
- return current + 1;
374
+ export circuit mint(to: Address, amount: Field): Void {
375
+ Ownable.assertOnlyOwner();
376
+ FungibleToken.mint(to, amount);
408
377
  }
409
378
 
410
- export circuit signedOperation(data: Field): Field {
411
- const nonce = getNextNonce();
412
- return hash(data, nonce);
379
+ export circuit burn(amount: Field): Void {
380
+ FungibleToken.burn(context.caller, amount);
413
381
  }
414
382
  \`\`\`
415
383
 
416
- ## Best Practices
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
384
+ ## Privacy Model
422
385
 
423
- ## Security Considerations
386
+ | Operation | Privacy |
387
+ |-----------|---------|
388
+ | Balance | Shielded (private) |
389
+ | Transfer amount | Shielded |
390
+ | Sender | Shielded |
391
+ | Recipient | Shielded |
392
+ | Transaction occurred | Public (proof exists) |
424
393
 
425
- ⚠️ Witnesses are NOT proven in ZK:
426
- - Circuit verifies witness output is used correctly
427
- - But doesn't verify HOW witness computed the value
428
- - Malicious witnesses can provide false data
394
+ ## Important Notes
429
395
 
430
- Always add assertions to validate witness data:
431
-
432
- \`\`\`compact
433
- export circuit usePrice(asset: Opaque<"string">): Void {
434
- const price = fetchPrice(asset);
435
-
436
- // Validate witness data
437
- assert(price > 0);
438
- assert(price < MAX_REASONABLE_PRICE);
439
-
440
- // ... use price
441
- }
442
- \`\`\`
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
443
399
  `,
444
- "midnight://docs/concepts/kachina": `# Kachina Protocol
445
-
446
- Kachina is the cryptographic protocol underlying Midnight's privacy features.
447
-
448
- ## Overview
449
-
450
- Kachina enables:
451
- - Private smart contracts with public verifiability
452
- - Composable privacy across contracts
453
- - Efficient on-chain verification
400
+ "midnight://docs/openzeppelin/access": `# OpenZeppelin Access Control
454
401
 
455
- ## Architecture
402
+ Patterns for controlling who can call contract functions.
456
403
 
457
- \`\`\`
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
- \`\`\`
404
+ ## Ownable
476
405
 
477
- ## Key Concepts
406
+ Simple single-owner access control.
478
407
 
479
- ### State Model
480
- - **Public State**: Stored on-chain, visible to all
481
- - **Private State**: Stored off-chain, encrypted
482
- - **Commitments**: On-chain references to private state
408
+ \`\`\`compact
409
+ include "@openzeppelin/compact-contracts/access/Ownable.compact";
483
410
 
484
- ### Transaction Flow
485
- 1. User prepares transaction locally
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
411
+ ledger {
412
+ ...Ownable.ledger;
413
+ }
490
414
 
491
- ### Composability
492
- Contracts can interact while preserving privacy:
415
+ export circuit initialize(owner: Address): Void {
416
+ Ownable.initialize(owner);
417
+ }
493
418
 
494
- \`\`\`compact
495
- // Contract A
496
- export circuit transferToken(to: Address, amount: Field): Void {
497
- // Private transfer logic
419
+ export circuit adminFunction(): Void {
420
+ Ownable.assertOnlyOwner();
421
+ // Only owner can execute this
498
422
  }
499
423
 
500
- // Contract B can call Contract A
501
- export circuit atomicSwap(
502
- tokenA: Address,
503
- tokenB: Address,
504
- amountA: Field,
505
- amountB: Field
506
- ): Void {
507
- // Both transfers happen atomically
508
- // Privacy preserved for both
424
+ export circuit transferOwnership(newOwner: Address): Void {
425
+ Ownable.assertOnlyOwner();
426
+ Ownable.transferOwnership(newOwner);
509
427
  }
510
428
  \`\`\`
511
429
 
512
- ## Benefits
430
+ ## Role-Based Access Control
513
431
 
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
- `,
519
- "midnight://docs/openzeppelin": `# OpenZeppelin Contracts for Compact
432
+ For more complex permission systems.
520
433
 
521
- > **Official Documentation**: https://docs.openzeppelin.com/contracts-compact
522
- > **GitHub Repository**: https://github.com/OpenZeppelin/compact-contracts
434
+ \`\`\`compact
435
+ include "@openzeppelin/compact-contracts/access/AccessControl.compact";
523
436
 
524
- OpenZeppelin Contracts for Compact is the **official and recommended** library for building secure smart contracts on Midnight. This library provides audited, battle-tested modules for common patterns.
437
+ ledger {
438
+ ...AccessControl.ledger;
439
+ }
525
440
 
526
- ## Installation
441
+ const ADMIN_ROLE: Bytes<32> = keccak256("ADMIN_ROLE");
442
+ const MINTER_ROLE: Bytes<32> = keccak256("MINTER_ROLE");
527
443
 
528
- \`\`\`bash
529
- # Create project directory
530
- mkdir my-project && cd my-project
444
+ export circuit initialize(admin: Address): Void {
445
+ AccessControl.grantRole(ADMIN_ROLE, admin);
446
+ AccessControl.setRoleAdmin(MINTER_ROLE, ADMIN_ROLE);
447
+ }
531
448
 
532
- # Initialize git and add as submodule
533
- git init && git submodule add https://github.com/OpenZeppelin/compact-contracts.git
449
+ export circuit mint(to: Address, amount: Field): Void {
450
+ AccessControl.assertHasRole(MINTER_ROLE);
451
+ // Mint tokens
452
+ }
534
453
 
535
- # Install dependencies
536
- cd compact-contracts
537
- nvm install && yarn && SKIP_ZK=true yarn compact
454
+ export circuit grantMinterRole(account: Address): Void {
455
+ AccessControl.assertHasRole(ADMIN_ROLE);
456
+ AccessControl.grantRole(MINTER_ROLE, account);
457
+ }
538
458
  \`\`\`
539
459
 
540
- ## Available Modules
541
-
542
- ### Token
543
- - **FungibleToken**: Standard token implementation with transfer, mint, burn
544
- - Recommended for all token contracts on Midnight
545
-
546
- ### Access Control
547
- - **Ownable**: Single owner access control
548
- - **AccessControl**: Role-based access control
549
-
550
- ### Security
551
- - **Pausable**: Emergency stop mechanism
552
-
553
- ## Usage Example
460
+ ## Combining Patterns
554
461
 
555
462
  \`\`\`compact
556
- pragma language_version >= 0.16.0;
463
+ include "@openzeppelin/compact-contracts/access/Ownable.compact";
464
+ include "@openzeppelin/compact-contracts/security/Pausable.compact";
557
465
 
558
- import CompactStandardLibrary;
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);
466
+ ledger {
467
+ ...Ownable.ledger;
468
+ ...Pausable.ledger;
582
469
  }
583
470
 
584
- export circuit pause(): [] {
585
- Ownable_assertOnlyOwner();
586
- Pausable__pause();
471
+ export circuit criticalFunction(): Void {
472
+ Ownable.assertOnlyOwner();
473
+ Pausable.assertNotPaused();
474
+ // Execute critical logic
587
475
  }
588
476
 
589
- export circuit unpause(): [] {
590
- Ownable_assertOnlyOwner();
591
- Pausable__unpause();
477
+ export circuit pause(): Void {
478
+ Ownable.assertOnlyOwner();
479
+ Pausable.pause();
592
480
  }
593
481
  \`\`\`
594
-
595
- ## Compilation
596
-
597
- \`\`\`bash
598
- compact compile MyContract.compact artifacts/MyContract
599
- \`\`\`
600
-
601
- ## Why Use OpenZeppelin?
602
-
603
- 1. **Security Audited**: Contracts are professionally audited
604
- 2. **Battle-Tested**: Used in production across the ecosystem
605
- 3. **Official Recommendation**: Midnight's recommended library for tokens
606
- 4. **Modularity**: Use only what you need
607
- 5. **Best Practices**: Follows Compact language best practices
608
482
  `,
609
- "midnight://docs/openzeppelin/token": `# OpenZeppelin FungibleToken
610
-
611
- > **This is the official and recommended token standard for Midnight.**
612
-
613
- The FungibleToken module provides a complete implementation for fungible tokens on Midnight.
483
+ "midnight://docs/openzeppelin/security": `# OpenZeppelin Security Patterns
614
484
 
615
- ## Features
485
+ Security utilities for Compact contracts.
616
486
 
617
- - ERC20-compatible interface
618
- - Transfer with balance tracking
619
- - Mint and burn operations
620
- - Approval and transferFrom patterns
621
- - Privacy-preserving by default
487
+ ## Pausable
622
488
 
623
- ## Basic Usage
489
+ Emergency stop mechanism for contracts.
624
490
 
625
491
  \`\`\`compact
626
- pragma language_version >= 0.16.0;
492
+ include "@openzeppelin/compact-contracts/security/Pausable.compact";
493
+ include "@openzeppelin/compact-contracts/access/Ownable.compact";
627
494
 
628
- import "./compact-contracts/node_modules/@openzeppelin-compact/contracts/src/token/FungibleToken" prefix FungibleToken_;
629
-
630
- constructor(
631
- _name: Opaque<"string">,
632
- _symbol: Opaque<"string">,
633
- _decimals: Uint<8>,
634
- _recipient: Either<ZswapCoinPublicKey, ContractAddress>,
635
- _initialSupply: Uint<128>,
636
- ) {
637
- FungibleToken_initialize(_name, _symbol, _decimals);
638
- FungibleToken__mint(_recipient, _initialSupply);
495
+ ledger {
496
+ ...Pausable.ledger;
497
+ ...Ownable.ledger;
639
498
  }
640
499
 
641
- // Transfer tokens
642
- export circuit transfer(
643
- to: Either<ZswapCoinPublicKey, ContractAddress>,
644
- value: Uint<128>,
645
- ): Boolean {
646
- return FungibleToken_transfer(to, value);
500
+ export circuit transfer(to: Address, amount: Field): Void {
501
+ Pausable.assertNotPaused();
502
+ // Transfer logic
647
503
  }
648
504
 
649
- // Check balance (witness function for privacy)
650
- witness balanceOf(
651
- account: Either<ZswapCoinPublicKey, ContractAddress>
652
- ): Uint<128> {
653
- return FungibleToken_balanceOf(account);
505
+ export circuit pause(): Void {
506
+ Ownable.assertOnlyOwner();
507
+ Pausable.pause();
654
508
  }
655
509
 
656
- // Get total supply
657
- witness totalSupply(): Uint<128> {
658
- return FungibleToken_totalSupply();
510
+ export circuit unpause(): Void {
511
+ Ownable.assertOnlyOwner();
512
+ Pausable.unpause();
659
513
  }
660
514
  \`\`\`
661
515
 
662
- ## Advanced: With Approval Pattern
516
+ ## When to Use Pausable
517
+
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
663
524
 
664
525
  \`\`\`compact
665
- // Approve spender
666
- export circuit approve(
667
- spender: Either<ZswapCoinPublicKey, ContractAddress>,
668
- value: Uint<128>,
669
- ): Boolean {
670
- return FungibleToken_approve(spender, value);
526
+ // Pausable module internals (simplified)
527
+ ledger {
528
+ paused: Boolean;
671
529
  }
672
530
 
673
- // Transfer from approved account
674
- export circuit transferFrom(
675
- from: Either<ZswapCoinPublicKey, ContractAddress>,
676
- to: Either<ZswapCoinPublicKey, ContractAddress>,
677
- value: Uint<128>,
678
- ): Boolean {
679
- return FungibleToken_transferFrom(from, to, value);
531
+ circuit Pausable_assertNotPaused(): Void {
532
+ assert(!ledger.paused, "Contract is paused");
680
533
  }
681
- \`\`\`
682
-
683
- ## Mint and Burn (Owner-Only)
684
-
685
- \`\`\`compact
686
- import "./compact-contracts/node_modules/@openzeppelin-compact/contracts/src/access/Ownable" prefix Ownable_;
687
534
 
688
- export circuit mint(
689
- to: Either<ZswapCoinPublicKey, ContractAddress>,
690
- amount: Uint<128>,
691
- ): [] {
692
- Ownable_assertOnlyOwner();
693
- FungibleToken__mint(to, amount);
535
+ circuit Pausable_pause(): Void {
536
+ ledger.paused = true;
694
537
  }
695
538
 
696
- export circuit burn(
697
- from: Either<ZswapCoinPublicKey, ContractAddress>,
698
- amount: Uint<128>,
699
- ): [] {
700
- Ownable_assertOnlyOwner();
701
- FungibleToken__burn(from, amount);
539
+ circuit Pausable_unpause(): Void {
540
+ ledger.paused = false;
702
541
  }
703
542
  \`\`\`
704
- `,
705
- "midnight://docs/openzeppelin/access": `# OpenZeppelin Access Control
706
-
707
- Access control modules for managing permissions in your contracts.
708
543
 
709
- ## Ownable
544
+ ## Best Practices
710
545
 
711
- Simple single-owner access control.
546
+ 1. **Always use Pausable** for contracts handling value
547
+ 2. **Combine with Ownable** for admin-only pause control
548
+ 3. **Test pause scenarios** thoroughly
549
+ 4. **Document pause conditions** for users
550
+ 5. **Consider timelock** for unpause in high-value contracts
551
+ `,
552
+ "midnight://docs/tokenomics": `# Midnight Tokenomics Summary
712
553
 
713
- \`\`\`compact
714
- pragma language_version >= 0.16.0;
554
+ A curated summary of the Midnight Tokenomics Whitepaper (June 2025).
715
555
 
716
- import "./compact-contracts/node_modules/@openzeppelin-compact/contracts/src/access/Ownable" prefix Ownable_;
556
+ ## Dual-Token Model
717
557
 
718
- constructor(
719
- _owner: Either<ZswapCoinPublicKey, ContractAddress>,
720
- ) {
721
- Ownable_initialize(_owner);
722
- }
558
+ Midnight uses two components: **NIGHT** (token) and **DUST** (resource).
723
559
 
724
- // Only owner can call this
725
- export circuit adminFunction(): [] {
726
- Ownable_assertOnlyOwner();
727
- // ... admin logic
728
- }
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
729
566
 
730
- // Transfer ownership
731
- export circuit transferOwnership(
732
- newOwner: Either<ZswapCoinPublicKey, ContractAddress>,
733
- ): [] {
734
- Ownable_assertOnlyOwner();
735
- Ownable_transferOwnership(newOwner);
736
- }
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
737
573
 
738
- // Renounce ownership (irreversible!)
739
- export circuit renounceOwnership(): [] {
740
- Ownable_assertOnlyOwner();
741
- Ownable_renounceOwnership();
742
- }
574
+ ## Key Insight: NIGHT Generates DUST
743
575
 
744
- // Check current owner
745
- witness owner(): Either<ZswapCoinPublicKey, ContractAddress> {
746
- return Ownable_owner();
747
- }
576
+ \`\`\`
577
+ Hold NIGHT Generates DUST → Pay for transactions
578
+ (continuous) (consumed on use)
748
579
  \`\`\`
749
580
 
750
- ## AccessControl (Role-Based)
581
+ This means: **Hold NIGHT, transact "for free"** (no recurring token spend)
751
582
 
752
- For contracts needing multiple roles with different permissions.
583
+ ## Block Rewards
753
584
 
754
- \`\`\`compact
755
- import "./compact-contracts/node_modules/@openzeppelin-compact/contracts/src/access/AccessControl" prefix AC_;
585
+ **Formula**:
586
+ \`\`\`
587
+ Actual Reward = Base Reward × [S + (1-S) × U]
756
588
 
757
- // Define role identifiers
758
- const MINTER_ROLE: Bytes<32> = keccak256("MINTER_ROLE");
759
- const PAUSER_ROLE: Bytes<32> = keccak256("PAUSER_ROLE");
589
+ Where:
590
+ - S = Subsidy rate (95% at launch)
591
+ - U = Block utilization (target: 50%)
592
+ \`\`\`
760
593
 
761
- constructor(_admin: Either<ZswapCoinPublicKey, ContractAddress>) {
762
- AC_initialize(_admin);
763
- AC__grantRole(MINTER_ROLE, _admin);
764
- AC__grantRole(PAUSER_ROLE, _admin);
765
- }
594
+ - Full blocks: Producer gets 100% of base reward
595
+ - Empty blocks: Producer gets only subsidy (95%)
596
+ - Remainder goes to Treasury
766
597
 
767
- // Only minters can call
768
- export circuit mint(to: Address, amount: Uint<128>): [] {
769
- AC_assertOnlyRole(MINTER_ROLE);
770
- // ... mint logic
771
- }
598
+ ## Token Distribution
772
599
 
773
- // Only pausers can call
774
- export circuit pause(): [] {
775
- AC_assertOnlyRole(PAUSER_ROLE);
776
- // ... pause logic
777
- }
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
778
604
 
779
- // Grant role (admin only)
780
- export circuit grantRole(
781
- role: Bytes<32>,
782
- account: Either<ZswapCoinPublicKey, ContractAddress>,
783
- ): [] {
784
- AC_assertOnlyRole(AC_DEFAULT_ADMIN_ROLE());
785
- AC__grantRole(role, account);
786
- }
787
- \`\`\`
788
- `,
789
- "midnight://docs/openzeppelin/security": `# OpenZeppelin Security Patterns
605
+ ### Phase 2: Scavenger Mine (30 days)
606
+ - Computational puzzles (accessible to public)
607
+ - Claims unclaimed Glacier Drop tokens
608
+ - Seeds network constituents
790
609
 
791
- Security modules for protecting your contracts.
610
+ ### Phase 3: Lost-and-Found (4 years)
611
+ - Second chance for Glacier Drop eligible
612
+ - Fractional allocation
792
613
 
793
- ## Pausable
614
+ ## Key Differentiators
794
615
 
795
- Emergency stop mechanism for your contract.
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
796
622
 
797
- \`\`\`compact
798
- pragma language_version >= 0.16.0;
623
+ A guide for integrating Midnight Lace wallet into your DApp.
799
624
 
800
- import "./compact-contracts/node_modules/@openzeppelin-compact/contracts/src/security/Pausable" prefix Pausable_;
801
- import "./compact-contracts/node_modules/@openzeppelin-compact/contracts/src/access/Ownable" prefix Ownable_;
625
+ ## Browser Detection
802
626
 
803
- constructor(_owner: Either<ZswapCoinPublicKey, ContractAddress>) {
804
- Ownable_initialize(_owner);
805
- // Contract starts unpaused
627
+ \`\`\`typescript
628
+ declare global {
629
+ interface Window {
630
+ midnight?: {
631
+ mnLace?: MidnightProvider;
632
+ };
633
+ }
806
634
  }
807
635
 
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
636
+ function isWalletAvailable(): boolean {
637
+ return typeof window !== 'undefined'
638
+ && window.midnight?.mnLace !== undefined;
815
639
  }
640
+ \`\`\`
816
641
 
817
- // Owner can pause
818
- export circuit pause(): [] {
819
- Ownable_assertOnlyOwner();
820
- Pausable__pause();
821
- }
642
+ ## DApp Connector API
822
643
 
823
- // Owner can unpause
824
- export circuit unpause(): [] {
825
- Ownable_assertOnlyOwner();
826
- Pausable__unpause();
644
+ \`\`\`typescript
645
+ interface DAppConnectorAPI {
646
+ enable(): Promise<MidnightAPI>;
647
+ isEnabled(): Promise<boolean>;
648
+ apiVersion(): string;
649
+ name(): string;
650
+ icon(): string;
827
651
  }
828
652
 
829
- // Check if paused
830
- witness isPaused(): Boolean {
831
- return Pausable_paused();
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();
832
658
  }
833
659
  \`\`\`
834
660
 
835
- ## Combined Example: Secure Token
836
-
837
- \`\`\`compact
838
- pragma language_version >= 0.16.0;
839
-
840
- import CompactStandardLibrary;
841
- import "./compact-contracts/node_modules/@openzeppelin-compact/contracts/src/access/Ownable" prefix Ownable_;
842
- import "./compact-contracts/node_modules/@openzeppelin-compact/contracts/src/security/Pausable" prefix Pausable_;
843
- import "./compact-contracts/node_modules/@openzeppelin-compact/contracts/src/token/FungibleToken" prefix FungibleToken_;
661
+ ## MidnightAPI Interface
844
662
 
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
- }
856
-
857
- // Pausable transfer
858
- export circuit transfer(
859
- to: Either<ZswapCoinPublicKey, ContractAddress>,
860
- value: Uint<128>,
861
- ): Boolean {
862
- Pausable_assertNotPaused();
863
- return FungibleToken_transfer(to, value);
864
- }
865
-
866
- // Owner-only mint
867
- export circuit mint(
868
- to: Either<ZswapCoinPublicKey, ContractAddress>,
869
- amount: Uint<128>,
870
- ): [] {
871
- Ownable_assertOnlyOwner();
872
- Pausable_assertNotPaused();
873
- FungibleToken__mint(to, amount);
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>;
874
670
  }
671
+ \`\`\`
875
672
 
876
- // Emergency pause
877
- export circuit pause(): [] {
878
- Ownable_assertOnlyOwner();
879
- Pausable__pause();
880
- }
673
+ ## React Hook
881
674
 
882
- export circuit unpause(): [] {
883
- Ownable_assertOnlyOwner();
884
- Pausable__unpause();
885
- }
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
886
721
  \`\`\`
887
722
 
888
723
  ## Best Practices
889
724
 
890
- 1. **Always use Pausable** for contracts handling value
891
- 2. **Combine with Ownable** for admin-only pause control
892
- 3. **Test pause scenarios** thoroughly
893
- 4. **Document pause conditions** for users
894
- 5. **Consider timelock** for unpause in high-value contracts
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
895
730
  `,
896
731
  };
897
732
  //# sourceMappingURL=docs-content.js.map