nite-api
v0.0.14
Published
A dynamic contract api wrapper for midnight compact smart contracts
Maintainers
Readme
nite-api
TypeScript helpers for working with deployed Midnight Compact contracts.
This package wraps the lower-level Midnight JS contract APIs with a small, typed interface for:
- deploying a compiled contract
- joining an already deployed contract
- calling transaction circuits dynamically
- observing public and private contract state together
- building compiled contract objects from a contract class, witnesses, and compiled assets
Installation
npm install nite-apiPeer runtime expectations:
- Node.js 18+
- a Midnight-compatible provider setup
- a compiled Compact contract and its assets
What It Exports
DynamicContractAPI
DynamicContractAPI is the main wrapper around Midnight's deployed contract APIs.
It provides:
DynamicContractAPI.deploy(...)DynamicContractAPI.join(...)api.callTx(...)api.contractStateapi.deployedContractAddress
utils.createCompiledContract
Helper for creating a CompiledContract from:
- a contract tag
- a contract class
- witness implementations
- a compiled assets path
Quick Start
import { DynamicContractAPI, utils } from 'nite-api';
const compiledContract = utils.createCompiledContract('counter', CounterContract, witnesses, './artifacts/counter');
const api = await DynamicContractAPI.deploy({
providers,
compiledContract,
privateStateId,
initialPrivateState,
args: [],
logger,
});
await api.callTx('increment' as any, txContext, 1n);Usage
Create a compiled contract
import { utils } from 'nite-api';
const compiledContract = utils.createCompiledContract(
'my-contract',
MyContract,
witnesses, // Pass an empty object if no witness is used by your contract
'./artifacts/my-contract',
);Deploy a contract
NB: The type for your providers should be constructed as follow DynamicProviders<TContractType, typeof yourPrivateStateId>
import { DynamicProviders } from 'nite-api';
const walletAndMidnightProvider = await createWalletAndMidnightProvider(walletCtx);
const zkConfigProvider = new NodeZkConfigProvider<TCircuitId>("./path to your compiled artifact");
const providers: DynamicProviders<TContractType, typeof yourPrivateStateId> = {
privateStateProvider: levelPrivateStateProvider<typeof yourPrivateStateId>({
privateStateStoreName: contractConfig.privateStateStoreName,
walletProvider: walletAndMidnightProvider,
}),
publicDataProvider: indexerPublicDataProvider(config.indexer, config.indexerWS),
zkConfigProvider,
proofProvider: httpClientProofProvider(config.proofServer, zkConfigProvider),
walletProvider: walletAndMidnightProvider,
midnightProvider: walletAndMidnightProvider,
};import { DynamicContractAPI } from 'nite-api';
const api = await DynamicContractAPI.deploy<TContractType, typeof yourPrivateStateId>({
providers,
compiledContract,
privateStateId,
initialPrivateState,
args: [],
logger,
});
console.log(api.deployedContractAddress);If your contract does not require private state during deployment:
const api = await DynamicContractAPI.deploy<TContractType, typeof yourPrivateStateId>({
providers,
compiledContract,
args: [],
});Join an existing deployment
const api = await DynamicContractAPI.join<TContractType, typeof yourPrivateStateId>({
providers,
compiledContract,
contractAddress: '...',
privateStateId,
initialPrivateState,
logger,
});Call a transaction circuit
callTx forwards to the underlying Midnight deployedContract.callTx map. It also automatically detects a union of all callable contract circuit names and their arguments, to be passed sequentially.
await api.callTx('increment', 1n);
await api.callTx('transfer', recipient, amount);
await api.callTx('ping');
await api.callTx('ping', txContext, user); //Allowed to pass a transaction contextThe exact arguments depend on the generated circuit function types from your Midnight contract bindings. If a circuit takes no parameters, call it with just the circuit name.
Observe contract state
contractState is an RxJS observable that emits:
[publicContractState, privateStateOrNull];Example:
import ledger from '/path to your compiled contract';
const subscription = api.contractState.subscribe(([publicState, privateState]) => {
console.log('public', publicState);
/* Format contract state using ledger() generated as artifact for compiled contract */
const ledgerState = ledger(publicState.data);
console.log('private', privateState);
});
subscription.unsubscribe();If no privateStateId is supplied, the second tuple item is null.
API Reference
DynamicContractAPI.deploy(options)
Deploys a new contract instance and returns a DynamicContractAPI.
Important fields:
providers: Midnight provider setcompiledContract: compiled contract objectprivateStateId: optional private state identifierinitialPrivateState: optional initial private stateargs: optional contract initialization argumentslogger: optionalpinologger
DynamicContractAPI.join(options)
Attaches to an already deployed contract and returns a DynamicContractAPI.
Important fields:
providers: Midnight provider setcompiledContract: compiled contract objectcontractAddress: deployed contract addressprivateStateId: optional private state identifierinitialPrivateState: optional initial private statelogger: optionalpinologger
api.callTx(circuitName, ...args)
Calls a transaction circuit from the underlying deployed contract.
Behavior:
- throws if
circuitNameis not found - forwards all arguments to the underlying circuit function
- allows zero arguments for circuits that do not accept parameters
api.contractState
RxJS Observable<[ContractState, PrivateState | null]>
Behavior:
- subscribes to public contract state updates
- resolves private state once when
privateStateIdis present - emits
nullfor private state when noprivateStateIdis provided - shaped/formated using the
ledger()provided in compiled contract artifact
Development
Install dependencies:
npm installBuild:
npm run buildRun tests:
npm testWatch tests:
npm run test:watchPublishing Checklist
Before publishing to npm, verify:
package.jsonhas correctname,version,description,repository,homepage,bugs,keywords, andauthor- the build output in
dist/is current README.mdreflects the published API- tests pass
- exported types and paths are correct
Recommended publish flow:
npm test
npm run build
npm version patch
npm publishNotes:
npm version patchrequires a clean git working tree- use
npm version minorornpm version majorwhen appropriate - if you need to bump the version without creating a git tag or commit, use
npm version patch --no-git-tag-version
Notes
- This package is ESM-only.
- It is a thin wrapper over Midnight SDK contracts, so consumers still need the relevant Midnight runtime setup.
callTxargument types come from the generated Midnight contract bindings, not from this package alone.
License
MIT
