plugins/midnight-tooling/skills/contract-calling/SKILL.md
Use when calling deployed Midnight contracts from Node.js backends, querying contract state, executing state-changing transactions, building API endpoints that interact with contracts, or automating contract interactions.
npx skillsauth add aaronbassett/midnight-knowledgebase midnight-tooling:contract-callingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Interact with deployed Midnight contracts from Node.js backends, including read-only queries and state-changing transactions with proof generation.
| Type | Proof Required | State Change | Gas Cost | Use Case | |------|----------------|--------------|----------|----------| | Read-only query | No | No | None | Fetching current state | | State change | Yes | Yes | Variable | Updating ledger state |
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Your Code │────▶│ Contract │────▶│ Prover │
│ │ │ Client │ │ Service │
└─────────────┘ └──────────────┘ └─────────────┘
│
▼
┌──────────────┐ ┌─────────────┐
│ Indexer │────▶│ Midnight │
│ Client │ │ Network │
└──────────────┘ └─────────────┘
Compact contracts define circuits that can be invoked:
// Read-only circuit - no proof needed
circuit get_balance(address: Address): Uint {
return ledger.balances[address];
}
// State-changing circuit - requires proof
circuit transfer(to: Address, amount: Uint): Void {
// Generates proof, updates ledger
ledger.balances[sender] -= amount;
ledger.balances[to] += amount;
}
| Document | Description | |----------|-------------| | api-client-setup.md | SDK initialization and wallet connection | | error-handling.md | Error types, retries, and timeout handling |
| Example | Description | |---------|-------------| | read-query/ | Query contract state without proofs | | state-change/ | Execute state-changing transactions |
import { connectContract } from '@midnight-ntwrk/midnight-js-contracts';
import { createWallet } from '@midnight-ntwrk/midnight-js-wallet';
import { Contract } from './build/contract.cjs';
const wallet = await createWallet({ seed: process.env.WALLET_SEED! });
const contract = await connectContract({
address: '0x1234...', // Deployed contract address
artifact: Contract,
wallet,
config: {
indexer: 'https://indexer.testnet.midnight.network',
indexerWs: 'wss://indexer.testnet.midnight.network/ws',
prover: 'https://prover.testnet.midnight.network',
},
});
// Call read-only circuit (no proof generation)
const balance = await contract.query.get_balance({
address: '0xabc...',
});
console.log('Balance:', balance);
// Call state-changing circuit (generates proof)
const result = await contract.call.transfer({
to: '0xdef...',
amount: 100n,
});
// Wait for confirmation
const confirmed = await result.waitForConfirmation();
console.log('Transfer confirmed:', confirmed.txHash);
import { connectContract } from '@midnight-ntwrk/midnight-js-contracts';
import type { ContractMethods, ContractState } from './build/contract.d.cts';
class TokenClient {
private contract: ConnectedContract<ContractState, ContractMethods>;
static async connect(
address: string,
wallet: Wallet,
config: NetworkConfig
): Promise<TokenClient> {
const client = new TokenClient();
client.contract = await connectContract({
address,
artifact: Contract,
wallet,
config,
});
return client;
}
async getBalance(address: string): Promise<bigint> {
return this.contract.query.get_balance({ address });
}
async transfer(to: string, amount: bigint): Promise<TransactionResult> {
const result = await this.contract.call.transfer({ to, amount });
return result.waitForConfirmation();
}
}
async function batchGetBalances(
contract: ConnectedContract,
addresses: string[]
): Promise<Map<string, bigint>> {
const results = new Map<string, bigint>();
// Run queries in parallel
const balances = await Promise.all(
addresses.map((addr) =>
contract.query.get_balance({ address: addr })
.then((balance) => ({ addr, balance }))
)
);
for (const { addr, balance } of balances) {
results.set(addr, balance);
}
return results;
}
interface TransactionOptions {
timeout?: number;
confirmations?: number;
onProofProgress?: (progress: number) => void;
}
async function executeTransaction<T>(
callFn: () => Promise<PendingTransaction<T>>,
options: TransactionOptions = {}
): Promise<ConfirmedTransaction<T>> {
const { timeout = 120000, confirmations = 1, onProofProgress } = options;
const pending = await callFn();
// Monitor proof generation progress
if (onProofProgress) {
pending.onProgress(onProofProgress);
}
const result = await pending.waitForConfirmation({
timeout,
confirmations,
});
if (result.status !== 'confirmed') {
throw new Error(`Transaction failed: ${result.error || 'timeout'}`);
}
return result;
}
// Usage
const result = await executeTransaction(
() => contract.call.transfer({ to: recipient, amount: 100n }),
{
timeout: 180000,
onProofProgress: (p) => console.log(`Proof: ${(p * 100).toFixed(0)}%`),
}
);
// For circuits with private witness data
const result = await contract.call.private_transfer({
to: recipient,
amount: 100n,
// Private inputs are handled by the SDK
// They never leave your backend
});
Common errors when calling contracts:
| Error | Cause | Solution |
|-------|-------|----------|
| Contract not found | Invalid address | Verify contract address |
| Proof generation failed | Invalid witness | Check circuit inputs |
| Insufficient balance | Low DUST | Fund wallet |
| Circuit execution failed | Assertion violated | Review circuit logic |
| Timeout | Slow network/prover | Increase timeout |
See error-handling.md for detailed error recovery strategies.
contract-deployment - Deploying contracts before callinglifecycle-management - Managing contract statemidnight-proofs plugin - Server-side proof optimization/midnight:check - Verify environment is configuredtools
Use when setting up Midnight development environment, installing Compact compiler and developer tools, configuring proof server, verifying prerequisites, or getting started with Midnight development.
tools
--- name: midnight-tooling:midnight-debugging description: Use when encountering Midnight errors like "compact: command not found", "ERR_UNSUPPORTED_DIR_IMPORT", version mismatches, proof server failures, "@midnight-ntwrk" package errors, or compilation failures. --- # Midnight Environment Debugging Expert knowledge for identifying and resolving common Midnight development toolchain issues. ## Diagnostic Approach When encountering Midnight-related errors, follow this systematic approach: 1.
tools
Use when checking Midnight version compatibility, understanding pragma language_version, verifying compiler and runtime version relationships, or troubleshooting version mismatch errors between Midnight components.
tools
Use when setting up CI/CD for Midnight projects, configuring GitHub Actions for Compact contract compilation, running TypeScript tests in CI, validating version consistency, or automating contract builds.