How to Publish a Contract
Publishing a Lambit contract means shipping everything a downstream caller needs to instantiate and spend it without importing your authoring source:
- compiled artifact JSON (ABI + locking script template)
- constructor and state schema metadata already embedded in the artifact
- a pinned package version and usage notes
- tests that prove the artifact and runtime surface stay stable
There is no separate on-chain publish step. Deployment still happens through a provider; this guide covers packaging the contract for npm (or a private registry) so other projects can depend on it.
What to publish
| Artifact | Why callers need it |
|---|---|
| Compiled artifact JSON | Locking script template, ABI, state props, and library metadata |
| TypeScript types / entrypoint | Ergonomic imports such as import { Vault } from '@acme/vault-contracts' |
| README usage notes | Constructor args, initial state shape, and example deploy/call flow |
| Tests | Regression coverage for compile output and representative spends |
Callers can bind props in-process (Vault({ owner })) or load artifact JSON with createInstance({ artifact, constructorArgs, state }).
Compile artifacts before publish
Use the CLI to emit artifact JSON from your contract module:
npx lambit compile ./src/contracts/vault.ts --out-dir artifacts
To compile a single export:
npx lambit artifact ./src/contracts/vault.ts --export Vault --output artifacts/Vault.json
You can also compile programmatically with buildArtifact(Vault) after binding props, but the CLI output is what most packages ship alongside dist/.
lambit compile and lambit artifact execute the target module. Only run them on trusted code in CI or on your own machine.
Package layout
A typical publishable contract package looks like this:
@acme/vault-contracts/
├── dist/ # tsc output (types + re-exports)
├── artifacts/
│ └── Vault.json # compiled artifact JSON
├── src/
│ └── contracts/
│ └── vault.ts # authoring source (optional but recommended)
├── test/
│ └── vault.test.ts
├── package.json
└── README.md
Expose contracts from dist/ and include artifacts in the published tarball:
{
"name": "@acme/vault-contracts",
"version": "0.1.0",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist",
"artifacts"
],
"scripts": {
"build": "tsc --project tsconfig.json",
"contracts:compile": "lambit compile ./src/contracts/vault.ts --out-dir artifacts",
"prepublishOnly": "npm run build && npm run contracts:compile && npm test"
},
"dependencies": {
"@opcat-labs/lambit": "^0.1.0"
}
}
Pin @opcat-labs/lambit to the compiler/runtime version you tested against. Artifact compatibility can change across compiler releases.
Export surface
Keep the public entrypoint small. Re-export bound contract definitions and, when useful, precompiled artifacts:
// src/index.ts
export { Vault } from './contracts/vault.js';
import vaultArtifact from '../artifacts/Vault.json' with { type: 'json' };
export const VaultArtifact = vaultArtifact;
Consumers then choose either the bound definition or artifact-first deployment:
import { Vault, VaultArtifact, createInstance, attachDeployedMethods } from '@acme/vault-contracts';
import { createMemoryProvider } from '@opcat-labs/lambit';
// Bound-contract path
const vault = Vault({ owner: '11'.repeat(33) });
const deployed = await vault.deploy({ balance: 1_000n }, { provider, satoshis: 5_000n });
// Artifact-first path
const instance = createInstance({
artifact: VaultArtifact,
constructorArgs: { owner: '11'.repeat(33) },
state: { balance: 1_000n },
});
const deployedFromArtifact = attachDeployedMethods(await provider.deploy(instance, 5_000n));
Publishing reusable libraries
Reusable script fragments belong in library() helpers, not in deployable contracts. See Composition for the library() authoring model.
Libraries compile into artifact libraries metadata and can ship in the same npm package as the contracts that reference them. Test libraries the same way you test contracts: compile coverage plus representative MemoryProvider spends when the library participates in a spend path.
Test before you publish
Minimum checklist:
lambit compilesucceeds for every exported contract.- Constructor and state validation failures are covered where you expose custom hooks.
- At least one MemoryProvider deploy/spend path succeeds for each public method you document.
- Published artifact JSON matches the in-process
bound.artifactfor the same constructor/state inputs.
Use How to Test a Contract for the offline verification pattern and How to Verify a Contract for comparing published artifacts against deployed UTXOs.
Publish to npm
When the package builds and tests pass:
npm publish --access public
For scoped private packages, omit --access public and publish to your registry of choice.
Document in the README:
- required constructor props and initial state
- which network(s) you tested (memory provider, OP_CAT testnet, etc.)
- example deploy/call snippet
- the
@opcat-labs/lambitversion the artifacts were built with