Help us improve
Share bugs, ideas, or general feedback.
From compact-core
This skill should be used when the user asks about implementing Compact witness functions in TypeScript, the WitnessContext pattern, private state management, Compact-to-TypeScript type mappings (Field to bigint, Bytes to Uint8Array, Uint to bigint), compiler-generated .d.ts files (Witnesses interface, Circuits type, Contract class), the Compact JavaScript runtime, how contract.circuits works, pure circuits in TypeScript, reading ledger state from TypeScript, the witness return tuple pattern [PrivateState, ReturnValue], or how to connect a Compact contract to its TypeScript implementation.
npx claudepluginhub devrelaicom/midnight-expert --plugin compact-coreHow this skill is triggered — by the user, by Claude, or both
Slash command
/compact-core:compact-witness-tsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill covers the TypeScript half of every Compact contract: implementing witnesses, understanding compiler-generated types, and using the Contract runtime. For Compact witness declarations and disclosure rules, see `compact-structure`. For privacy patterns using witnesses, see `compact-privacy-disclosure`. For standard library functions referenced in witnesses, see `compact-standard-library`.
This skill should be used when the user asks to write, structure, or scaffold a Compact smart contract for Midnight, or asks about contract anatomy, pragma and imports, ledger declarations (including sealed ledger), data types (Field, Bytes, Uint, enums, structs), circuits, witnesses, constructors, export patterns, or disclosure rules. Also triggered by mentions of "pragma language_version", "CompactStandardLibrary", circuit definitions, or Compact common mistakes.
Cross-domain witness verification pipeline. Compiles the Compact contract, type-checks the TypeScript witness against the compiled contract's generated Witnesses type, runs structural checklist analysis (name matching, return tuple shape, WitnessContext usage, private state immutability, side effects), executes the circuit with the witness via JS runtime, and recommends devnet E2E to the orchestrator if needed. Loaded by @"midnight-verify:witness-verifier (agent)".
Use this skill when an agent needs real, compilable examples of Compact smart contracts, TypeScript witnesses, or tests. Covers beginner contracts (counter, bulletin board), reusable modules (access control, security, tokens, math, crypto, data structures, identity, utils), composed token contracts (fungible, NFT, multi-token, shielded), and full applications (CryptoKitties, ZK lending, real-world assets). All examples compile with pragma language_version >= 0.22 and full proof generation.
Share bugs, ideas, or general feedback.
This skill covers the TypeScript half of every Compact contract: implementing witnesses, understanding compiler-generated types, and using the Contract runtime. For Compact witness declarations and disclosure rules, see compact-structure. For privacy patterns using witnesses, see compact-privacy-disclosure. For standard library functions referenced in witnesses, see compact-standard-library.
Running compact compile src/mycontract.compact src/managed/mycontract produces a managed/ directory containing the generated TypeScript API:
src/managed/mycontract/
├── contract/
│ ├── index.js # Runtime implementation
│ ├── index.js.map # Source map
│ └── index.d.ts # Type declarations
├── compiler/ # Compiler metadata
├── keys/ # ZK proving/verifying keys
└── zkir/ # ZK intermediate representation (.bzkir files)
Key exports from contract/index.js:
import { Ledger, Witnesses, ImpureCircuits, Circuits, Contract, pureCircuits } from "./managed/mycontract/contract/index.js";
Ledger — TypeScript type matching the contract's ledger declarationsWitnesses — Interface defining required witness implementationsImpureCircuits — Type describing circuit functions that require witnesses (parameterized by private state PS)Circuits — Type describing available circuit functionsContract — Class that binds witnesses to circuitspureCircuits — Module-level const export for local-only pure circuit calls (no proof generated)ledger() — Function to parse on-chain state into typed objects| Compact Type | TypeScript Type | Notes |
|---|---|---|
Field | bigint | Runtime bounds checked (max field value) |
Uint<N> / Uint<0..N> | bigint | Runtime bounds checked |
Boolean | boolean | |
Bytes<N> | Uint8Array | Runtime length checked (N bytes) |
Opaque<"string"> | string | Pass-through |
Opaque<"Uint8Array"> | Uint8Array | Pass-through |
enum variants | number | Runtime membership checked |
struct { a: A, b: B } | { a: A, b: B } | Plain object |
Vector<N, T> / tuples | T[] | Runtime length checked |
Maybe<T> | { is_some: boolean; value: T } | Must export from Compact to use type |
Either<L, R> | { is_left: boolean; left: L; right: R } | Flat object with discriminator |
Counter | bigint | Via ledger() |
Map<K, V> | Custom accessor object | Via ledger(); has member(), size(), isEmpty(), Symbol.iterator |
Set<T> | Custom accessor object | Via ledger(); has member(), size(), isEmpty(), Symbol.iterator |
MerkleTreePath<value_type> | Nested structure | Array of sibling hashes + directions |
For complete type mapping details, runtime validation, and casting rules, see references/type-mappings.md.
Every witness function follows the same pattern:
import { WitnessContext } from "@midnight-ntwrk/compact-runtime";
import { Ledger } from "./managed/mycontract/contract/index.js";
// 1. Define private state type
type MyPrivateState = {
readonly secretKey: Uint8Array;
};
// 2. Create factory function
const createMyPrivateState = (secretKey: Uint8Array): MyPrivateState => ({
secretKey,
});
// 3. Implement witnesses object — keys must match Compact witness names exactly
export const witnesses = {
local_secret_key: ({
privateState,
}: WitnessContext<Ledger, MyPrivateState>): [MyPrivateState, Uint8Array] => [
privateState,
privateState.secretKey,
],
};
Key rules:
WitnessContext<Ledger, PrivateState>[PrivateState, ReturnValue] — a tuple of updated private state and the declared return valuewitnesses must match Compact witness function names exactlyFor WitnessContext API details, common patterns, and state management, see references/witness-implementation.md.
Private state holds off-chain data that witnesses access. It persists across circuit calls within a session:
// Simple: single secret key
type SimpleState = { readonly secretKey: Uint8Array };
// Complex: multiple values, per-contract scoping
type ComplexState = {
readonly secretKey: Uint8Array;
readonly localData: Map<string, string[]>;
};
To mutate private state, return a new object in the witness tuple:
store_data: (
{ privateState, contractAddress }: WitnessContext<Ledger, ComplexState>,
data: bigint[],
): [ComplexState, Uint8Array] => {
const updatedData = new Map(privateState.localData);
updatedData.set(contractAddress, data.map(String));
return [
{ ...privateState, localData: updatedData },
someComputedValue,
];
},
The compiler-generated Contract class binds witnesses to circuits:
import { Contract, pureCircuits, ledger } from "./managed/mycontract/contract/index.js";
// Local testing only — instantiate Contract directly with witnesses
const contractInstance = new Contract(witnesses);
// Production — use CompiledContract.make() from @midnight-ntwrk/compact-js
import { CompiledContract } from "@midnight-ntwrk/compact-js";
const compiledContract = await CompiledContract.make(contractInstance);
// Pure circuits — module-level export, local computation, no proof, no transaction
const hash = pureCircuits.computeHash(inputData);
// Read ledger state from on-chain data
const ledgerState = ledger(contractStateData);
const currentValue = ledgerState.myField;
For Contract class details, circuits vs impureCircuits, and the ledger function, see references/contract-runtime.md.
| Topic | Reference File |
|---|---|
| Complete type mapping table, CompactType<T>, runtime validation, casting rules | references/type-mappings.md |
| WitnessContext API, return tuples, common patterns, state transitions | references/witness-implementation.md |
| Contract class, circuits vs impureCircuits, pureCircuits, ledger() | references/contract-runtime.md |
Witness implementations can be mechanically verified against their contract declarations:
/midnight-verify:verify <contract.compact> <witnesses.ts>
This verifies:
Witnesses type[PrivateState, ReturnValue]), WitnessContext first parameter, private state immutability, no side effectsStrongly recommend running /midnight-verify:verify after writing or modifying any witness implementation. Do not consider a witness implementation complete until verification passes.