Skip to content

Quick Start

This guide walks you through creating a client, deploying a contract, and calling contract actions.

Promise API

The simplest way to get started. The SDK uses a Client-centric hub pattern — everything flows from the client:

  1. Import the SDK

    import * as Midday from '@no-witness-labs/midday-sdk';
    import * as CounterContract from './contracts/counter/contract/index.js';
  2. Create a client

    const client = await Midday.Client.create({
    seed: 'your-64-char-hex-seed',
    networkConfig: Midday.Config.NETWORKS.local,
    privateStateProvider: Midday.PrivateState.inMemoryPrivateStateProvider(),
    });
  3. Load contract

    const loaded = await client.loadContract({
    module: CounterContract,
    zkConfig: Midday.ZkConfig.fromPath('./contracts/counter'),
    privateStateId: 'my-counter',
    });
  4. Deploy the contract (returns a DeployedContract handle)

    const deployed = await loaded.deploy();
    console.log(`Deployed at: ${deployed.address}`);
  5. Call contract actions (typed)

    await deployed.actions.increment();
  6. Read contract state

    const state = await deployed.ledgerState();
    console.log(state.counter);

Effect API

For developers who prefer functional programming. Effect users get composable operations via the .effect namespace:

import * as Midday from '@no-witness-labs/midday-sdk';
import * as CounterContract from './contracts/counter/contract/index.js';
import { Effect } from 'effect';
const program = Effect.gen(function* () {
// Create client (Effect version)
const client = yield* Midday.Client.effect.create({
seed: 'your-64-char-hex-seed',
networkConfig: Midday.Config.NETWORKS.local,
privateStateProvider: Midday.PrivateState.inMemoryPrivateStateProvider(),
});
// Load contract via client (Effect version)
const loaded = yield* client.effect.loadContract({
module: CounterContract,
zkConfig: Midday.ZkConfig.fromPath('./contracts/counter'),
privateStateId: 'my-counter',
});
// Deploy (returns DeployedContract)
const deployed = yield* loaded.effect.deploy();
// Call action (typed)
yield* deployed.effect.actions.increment();
// Read state
const state = yield* deployed.effect.ledgerState();
return state;
});
const result = await Midday.Runtime.runEffectPromise(program);

Effect with Dependency Injection

For larger applications that benefit from testability, use the Layer-based approach. Client.layer() creates a scoped layer — the client is automatically closed when the Effect completes:

import * as Midday from '@no-witness-labs/midday-sdk';
import { Effect } from 'effect';
// Create a scoped client layer (auto-closes when done)
const ClientLayer = Midday.Client.layer({
seed: 'your-64-char-hex-seed',
networkConfig: Midday.Config.NETWORKS.local,
privateStateProvider: Midday.PrivateState.inMemoryPrivateStateProvider(),
});
const program = Effect.gen(function* () {
// Get the pre-configured client from context
const client = yield* Midday.Client.MiddayClientService;
// Load contract
const loaded = yield* client.effect.loadContract({
module: CounterContract,
zkConfig: Midday.ZkConfig.fromPath('./contracts/counter'),
privateStateId: 'my-counter',
});
// Deploy and interact
const deployed = yield* loaded.effect.deploy();
yield* deployed.effect.actions.increment();
const state = yield* deployed.effect.ledgerState();
return state;
});
// Run with the layer — no manual cleanup needed
const result = await Effect.runPromise(
program.pipe(Effect.provide(ClientLayer))
);

For advanced use with devnet management, see the Effect API guide which covers Cluster.managedLayer() and full layer composition.

API Pattern

The SDK follows these principles:

  • Effect is source of truth: All logic is implemented as Effect functions
  • Client is the hub: Everything flows from the client
  • Two interfaces: .effect.method() for Effect users, .method() for Promise users
  • Per-contract zkConfig: Each contract loads its own zk circuits via loadContract
  • Two-handle pattern: LoadedContract (after load) → DeployedContract (after deploy/join)
// Promise user — simple flow
const client = await Midday.Client.create(config);
const loaded = await client.loadContract({ module, zkConfig, privateStateId: 'my-id' });
const deployed = await loaded.deploy();
await deployed.actions.increment();
// Effect user — compositional
const client = yield* Midday.Client.effect.create(config);
const loaded = yield* client.effect.loadContract({ module, zkConfig, privateStateId: 'my-id' });
const deployed = yield* loaded.effect.deploy();
yield* deployed.effect.actions.increment();

Next Steps