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:
-
Import the SDK
import * as Midday from '@no-witness-labs/midday-sdk';import * as CounterContract from './contracts/counter/contract/index.js'; -
Create a client
const client = await Midday.Client.create({seed: 'your-64-char-hex-seed',networkConfig: Midday.Config.NETWORKS.local,privateStateProvider: Midday.PrivateState.inMemoryPrivateStateProvider(),}); -
Load contract
const loaded = await client.loadContract({module: CounterContract,zkConfig: Midday.ZkConfig.fromPath('./contracts/counter'),privateStateId: 'my-counter',}); -
Deploy the contract (returns a
DeployedContracthandle)const deployed = await loaded.deploy();console.log(`Deployed at: ${deployed.address}`); -
Call contract actions (typed)
await deployed.actions.increment(); -
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 neededconst 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 flowconst 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 — compositionalconst 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
- Learn about Configuration options
- Explore Contract Operations
- Set up Browser Usage with Lace wallet