Receber por email
← Voltar para o catálogo

midnight-compact

Escreva, teste e implemente contratos inteligentes Compact para Midnight, incluindo contratos que preservam a privacidade, circuitos ZK e tokens blindados. Esta skill abrange a sintaxe da linguagem Compact, modelos de privacidade, padrões de circuito, testes e segurança.

10estrelas
Atualizado há 7 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add ADAvault/midnight-skill

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/midnight-compact/svg)](https://www.skillteca.com.br/skills/midnight-compact)

Skills relacionadas

Ver todas de DevOps e Infra →

Alerta por categoria

Receba novas skills de DevOps e Infra toda segunda

1 email curto, só com as skills novas de DevOps e Infra. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Midnight Compact Smart Contract Development

You are an expert Midnight smart contract developer. Compact is a TypeScript-like domain-specific language that compiles to zero-knowledge circuits, enabling privacy-preserving computation on the Midnight blockchain.

Core Principles

  1. Privacy by default — all computation is private unless explicitly disclosed with disclose().
  2. Dual-state model — contracts have public ledger state (on-chain) and private state (off-chain, per-user).
  3. Circuits, not functions — exported circuit declarations compile to ZK proofs. There are no function keywords.
  4. Witnesses bridge private data — witness declarations in Compact are implemented in TypeScript, providing off-chain private inputs.
  5. Correctness is enforced — all circuit computation is verified by ZK proofs. Only witness code runs unverified.
  6. Test everything — use the Compact simulator first, then standalone network, then testnet.

Decision Tree

When asked to write a smart contract:

  1. Specify the contract — before writing code, define:
  2. What state is public vs private?
  3. What operations (circuits) does it expose?
  4. What invariants must hold? (e.g., "total supply is conserved", "only owner can withdraw")
  5. What are the trust boundaries? (what can witnesses lie about?)
  6. What are the failure modes?
  7. Identify the privacy requirements: what must be shielded vs public?
  8. Design ledger state — export ledger for public, plain ledger for contract-private
  9. Design witnesses — what private data do users provide off-chain?
  10. Write circuits — exported for external calls, plain for internal
  11. Add disclose() calls — required for any witness-derived value written to ledger or used in conditionals
  12. Write TypeScript witnesses — implement witness bodies returning [newPrivateState, returnValue]
  13. Write tests — progressive approach:
  14. Unit test witnesses in isolation (correct types, immutable state, edge cases)
  15. Simulator tests for every circuit (happy path + error conditions)
  16. Invariant tests with fast-check (conservation laws, state machine validity)
  17. Privacy leak tests (verify secrets don't appear in public state)
  18. Adversarial tests (replay attacks, privilege escalation, malicious witnesses)
  19. Review for privacy leaks — check the security patterns in [security.md](reference/security.md)
  20. Check circuit complexity — verify k-values are acceptable (k <= 14 fast, k >= 17 needs optimization)
  21. Compile and deploy — compact compile, test with proof server, deploy to preprod before mainnet

When asked to audit or review a contract:

  1. Follow the auditing methodology in [auditing.md](reference/auditing.md)
  2. Phase 1: Map ledger state, circuits, witnesses, and trust boundaries
  3. Phase 2: Privacy leak scan — check all disclose() calls, witness interactions, and indirect leakage
  4. Phase 3: Circuit complexity analysis — check k values, ledger operation costs
  5. Phase 4: SDK integration review — version alignment, provider configuration
  6. Phase 5: Test coverage assessment
  7. Report findings with severity, privacy impact, and fix

Compact Language — Essential Syntax

Pragma (REQUIRED at top of every file)

pragma language_version >= 0.20;

Imports

import CompactStandardLibrary;                              // ALWAYS required
import "./path/to/Module" prefix Module_;                   // OZ composition pattern

Ledger Declarations

CRITICAL: Use individual statements. Block syntax ledger { } is DEPRECATED and causes parse errors.

export ledger counter: Counter;                             // public, readable by anyone
export ledger owner: Bytes<32>;                             // public
export sealed ledger name: Opaque<"string">;                // set once in constructor, immutable
ledger privateData: Field;                                  // NOT exported = private to contract

Types

Primitives:

| Type | Description | |------|-------------| | Field | Finite field element (basic numeric type for ZK circuits) | | Boolean | true/false | | Bytes<N> | Fixed-size byte array (N=32 most common) | | Uint<N> | Unsigned integer (N = 8, 16, 32, 64, 128). NOTE: Uint<256> NOT supported | | Uint<MIN..MAX> | Bounded unsigned integer | | Opaque<"string"> | External type bridged from TypeScript |

Collections:

| Type | Description | |------|-------------| | Counter | Incrementable/decrementable counter (ledger-backed) | | Map<K, V> | Key-value mapping (ledger-backed, expensive) | | Set<T> | Unique value collection (ledger-backed, expensive) | | Vector<N, T> | Fixed-size array (circuit-friendly) | | Maybe<T> | Optional value — some<T>(val) / none<T>() | | Either<L, R> | Union type — left<L, R>(val) / right<L, R>(val) |

Midnight-specific:

| Type | Description | |------|-------------| | ZswapCoinPublicKey | Wallet public key for coin operations | | ContractAddress | On-chain contract address | | CoinInfo | Coin descriptor for shielded tokens |

Custom types:

export enum GameState { waiting, playing, finished }
export struct PlayerConfig { name: Opaque<"string">, score: Uint<32> }

NOTE: Enum access uses dot notation: GameState.waiting, NOT GameState::waiting.

Circuits

// Exported circuit — callable from TypeScript, generates ZK proof
export circuit increment(): [] {
  counter.increment(1);
}

// Circuit with parameters and return value
export circuit getBalance(addr: Bytes<32>): Uint<64> {
  return balances.lookup(addr);
}

// Internal circuit — not exported, callable only from other circuits
circuit validateOwner(caller: Bytes<32>): Boolean {
  return caller == owner;
}

// Pure circuit — no state access, no side effects
export pure circuit hash(data: Bytes<32>): Bytes<32> {
  return persistentHash<Vector<1, Bytes<32>>>([data]);
}

CRITICAL: Return type is [] (empty tuple) for void circuits, NOT Void. The keyword function does NOT exist — use pure circuit for stateless computation.

Witnesses

Declared in Compact (no body), implemented in TypeScript:

// Compact — declaration only, ends with semicolon
witness localSecretKey(): Bytes<32>;
witness getAmount(max: Uint<64>): Uint<64>;
// TypeScript — implementation returns [newPrivateState, returnValue]
export const witnesses = {
  localSecretKey: ({ privateState }: WitnessContext<Ledger, PrivateState>):
    [PrivateState, Uint8Array] => [privateState, privateState.secretKey],
  getAmount: ({ privateState }: WitnessContext<Ledger, PrivateState>, max: bigint):
    [PrivateState, bigint] => [privateState, privateState.amount],
};

Disclosure — The Core Privacy Primitive

// MUST wrap witness-derived values for ledger writes or conditionals
owner = disclose(publicKey(localSecretKey()));

// Assertions on private values
assert(disclose(caller == storedOwner), "Not authorized");

// Branching on private values
if (disclose(guess == secret)) { /* ... */ }

CRITICAL: From Compact 0.16+, disclose() is MANDATORY for all witness-derived values written to ledger state or used in boolean expressions affecting control flow. Omitting it causes compilation errors.

Constructor

constructor() {
  counter.increment(1);
  owner = disclose(publicKey(localSecretKey()));
}

Common Operations

// Counter
counter.increment(1);          counter.decrement(1);
counter.read();                counter.lessThan(100);

// Map
balances.insert(key, value);   balances.remove(key);
balances.lookup(key);          balances.member(key);

// Maybe
const opt = some<Field>(42);   const empty = none<Field>();
if (opt.is_some) { const val = opt.value; }

// Either (used for wallet-or-contract addresses)
const wallet = left<ZswapCoinPublicKey, ContractAddre
Compartilhar X LinkedIn