Skip to content
Draft
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
790f6e7
feat: implement Contract Builder adapter with configuration, retry lo…
sp-io Dec 2, 2025
1bbceb6
feat: add private state management and witness functionality to Contr…
sp-io Dec 3, 2025
cb811de
feat: update peerDependencies and peerDependenciesMeta in package.jso…
sp-io Dec 3, 2025
839bacf
feat: enhance private state management with snapshot and restore func…
sp-io Dec 8, 2025
87ec131
feat: enhance type safety and documentation for Contract Adapter and …
sp-io Dec 8, 2025
f305042
feat: refactor ContractAdapterBuilder to use findDeployedContract and…
sp-io Dec 8, 2025
e1eb999
feat: enhance type safety by refining types in adapter and contract f…
sp-io Dec 9, 2025
22482b7
feat: improve type safety and refactor witness-related types and cons…
sp-io Dec 9, 2025
0bdc1cf
feat: enhance type safety and re-export contract utilities and types
sp-io Dec 9, 2025
c4d4db6
Merge branch 'main' into feat/builder
sp-io Dec 9, 2025
672416d
feat: enhance type safety and re-export contract utilities and types
sp-io Dec 9, 2025
80f7cda
feat: improve type safety by replacing 'any' types with specific type…
sp-io Dec 9, 2025
5cbd5d0
feat: streamline contract adapter by removing event handling and impr…
sp-io Dec 10, 2025
5bfe250
feat: re-export WitnessContext for improved type compatibility and cl…
sp-io Dec 10, 2025
fd2f8e1
feat: re-export WitnessContext for improved type compatibility and cl…
sp-io Dec 10, 2025
44de17f
feat: fix typing issues
sp-io Dec 10, 2025
9416d73
feat: fix typing issues
sp-io Dec 11, 2025
51c1bfb
⏺ fix: correct provider import names and replace ContractProvidersCon…
sp-io Dec 15, 2025
c833b98
add dev dependencies
sp-io Dec 22, 2025
f2226e5
fix bug
sp-io Dec 22, 2025
8b1f30c
fix bug
sp-io Dec 22, 2025
e9870d1
add type inferring for usage simplicity
sp-io Dec 22, 2025
0ad6981
compiler version upgrade
sp-io Dec 22, 2025
010b1ff
Merge branch 'main' into feat/builder
sp-io Dec 22, 2025
5b3f332
compiler version upgrade
sp-io Dec 22, 2025
b549341
Merge branch 'main' into feat/builder
sp-io Dec 22, 2025
0ba86f5
add types inferring
sp-io Dec 22, 2025
38e2df2
update docs
sp-io Dec 22, 2025
84f8ec4
Update packages/contract-builder/tests/unit/retry-logic.test.ts
sp-io Dec 23, 2025
a73251f
Update packages/contract-builder/tests/unit/WitnessManager.test.ts
sp-io Dec 23, 2025
128cce0
Update packages/contract-builder/tests/unit/WitnessInterceptor.test.ts
sp-io Dec 23, 2025
e280fd0
Update packages/contract-builder/src/adapter/ContractAdapter.ts
sp-io Dec 23, 2025
5e39630
Update packages/contract-builder/src/adapter/ContractAdapterBuilder.ts
sp-io Dec 23, 2025
8cacbbb
Update packages/contract-builder/src/adapter/ContractProxy.ts
sp-io Dec 23, 2025
f3582b9
Update packages/contract-builder/src/adapter/WitnessInterceptor.ts
sp-io Dec 23, 2025
d988a61
Update packages/contract-builder/src/adapter/WitnessManager.ts
sp-io Dec 23, 2025
8576e77
Update packages/contract-builder/tests/unit/ContractProxy.test.ts
sp-io Dec 23, 2025
fafb377
Update packages/contract-builder/tests/unit/PrivateStateManager.test.ts
sp-io Dec 23, 2025
19c24a9
Update packages/contract-builder/src/utils/logger-wrapper.ts
sp-io Dec 23, 2025
7279659
add licenses
sp-io Dec 23, 2025
2a4b8d8
remove redundant event types and wallet provider creation logic
sp-io Dec 23, 2025
b14269d
remove unused PrivateStateProvider import
sp-io Dec 23, 2025
a2e13b8
remove retry logic, simplify things
sp-io Dec 23, 2025
4a7f872
refactor ContractAdapter to use factory method, simplify type handling
sp-io Dec 23, 2025
2b21d38
cleaner config
sp-io Dec 23, 2025
101dac3
cleanup: remove unused types, simplify logic, and refactor test struc…
sp-io Dec 23, 2025
948eae6
add base preset provider creation utilities for shared environments
sp-io Dec 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
580 changes: 580 additions & 0 deletions packages/contract-builder/README.md

Large diffs are not rendered by default.

68 changes: 68 additions & 0 deletions packages/contract-builder/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{
"name": "@midnight-ntwrk/midnight-js-contract-builder",
"version": "0.1.0",
"description": "Simplified API for deploying and interacting with Midnight smart contracts",
"main": "dist/index.cjs",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": {
"import": "./dist/index.d.mts",
"require": "./dist/index.d.cts"
},
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
},
"repository": "git@github.com:midnight-ntwrk/artifacts",
"packageManager": "yarn@4.10.3",
"author": "IOHK",
"license": "Apache-2.0",
"keywords": [
"midnight",
"smart-contracts",
"blockchain",
"dapp",
"contract-builder"
],
"scripts": {
"clean": "rm -rf dist tsconfig.build.tsbuildinfo .rollup.cache reports coverage",
"build": "rollup -c rollup.config.mjs",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"deploy": "yarn npm publish"
},
"dependencies": {
"@midnight-ntwrk/midnight-js-contracts": "workspace:*",
"@midnight-ntwrk/midnight-js-network-id": "workspace:*",
"@midnight-ntwrk/midnight-js-types": "workspace:*",
"@midnight-ntwrk/midnight-js-utils": "workspace:*"
},
"peerDependencies": {
"@midnight-ntwrk/midnight-js-fetch-zk-config-provider": "workspace:*",
"@midnight-ntwrk/midnight-js-http-client-proof-provider": "workspace:*",
"@midnight-ntwrk/midnight-js-indexer-public-data-provider": "workspace:*",
"@midnight-ntwrk/midnight-js-level-private-state-provider": "workspace:*",
"@midnight-ntwrk/midnight-js-node-zk-config-provider": "workspace:*"
},
"peerDependenciesMeta": {
"@midnight-ntwrk/midnight-js-fetch-zk-config-provider": {
"optional": true
},
"@midnight-ntwrk/midnight-js-level-private-state-provider": {
"optional": true
},
"@midnight-ntwrk/midnight-js-node-zk-config-provider": {
"optional": true
}
},
"files": [
"dist/"
],
"devDependencies": {
"@fast-check/vitest": "^0.2.1",
"vitest": "^4.0.0"
}
}
4 changes: 4 additions & 0 deletions packages/contract-builder/rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { createRollupConfig } from '../../build-tools/rollup.config.factory.mjs';
import packageJson from './package.json' with { type: 'json' };

export default createRollupConfig(packageJson);
165 changes: 165 additions & 0 deletions packages/contract-builder/src/adapter/ContractAdapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/**
Comment thread
sp-io marked this conversation as resolved.
* Main Contract Adapter class that wraps a deployed contract
*/

import { mergeAdapterConfig } from '../config/AdapterConfig.js';
import { PrivateStateNotConfiguredError } from '../errors/PrivateStateError.js';
import type { PrivateStateManager } from '../private-state/PrivateStateManager.js';
import type { AdapterConfig, ContractAdapter as IContractAdapter } from '../types/adapter-types.js';
import type { DeployedContract, DeployTxData } from '../types/contract-types.js';
import { createContractProxy, EventEmitter, type EventHandler } from './ContractProxy.js';

/**
* ContractAdapter wraps a deployed contract and provides:
* - Automatic method proxying with interceptors
* - Built-in error handling
* - Retry logic for transient failures
* - Event emission for monitoring
* - Logging integration
* - Private state management (optional)
*/
export class ContractAdapter<TContract, TPrivateState = undefined> {
readonly eventEmitter: EventEmitter;
private readonly proxy: DeployedContract<TContract>;
private readonly privateStateManager?: PrivateStateManager<TPrivateState>;

constructor(
private readonly deployedContract: DeployedContract<TContract>,
private readonly config: AdapterConfig = {},
options?: {
privateStateManager?: PrivateStateManager<TPrivateState>;
}
) {
this.privateStateManager = options?.privateStateManager;
// Merge with default config
const mergedConfig = mergeAdapterConfig(config);

// Create event emitter
this.eventEmitter = new EventEmitter();

// Register any pre-configured event handlers
if (mergedConfig.eventHandlers) {
Object.entries(mergedConfig.eventHandlers).forEach(([event, handler]) => {
this.eventEmitter.on(event, handler as EventHandler);
});
}

// Create the proxy
this.proxy = createContractProxy({
contract: deployedContract,
logger: mergedConfig.logger,
retryConfig: mergedConfig.retry,
errorHandler: mergedConfig.errorHandler,
eventEmitter: this.eventEmitter
});

// Return proxy to make this object behave like the contract
return this.createAdapterProxy() as unknown as ContractAdapter<TContract, TPrivateState>;
}

/**
* Register an event handler
*/
private registerEventHandler(event: string, handler: EventHandler): this {
this.eventEmitter.on(event, handler);
return this;
}

/**
* Get contract address
*/
get address(): string {
return this.deployedContract.address;
}

/**
* Get deployment transaction data
*/
get deployTxData(): DeployTxData {
return this.deployedContract.deployTxData;
}

/**
* Get the current private state
*/
async getPrivateState(): Promise<TPrivateState | null> {
if (!this.privateStateManager) {
throw new PrivateStateNotConfiguredError();
}

return await this.privateStateManager.getState();
}

/**
* Set the private state
*/
async setPrivateState(state: TPrivateState): Promise<void> {
if (!this.privateStateManager) {
throw new PrivateStateNotConfiguredError();
}

return await this.privateStateManager.setState(state);
}

/**
* Get the private state ID
*/
getPrivateStateId(): string | undefined {
return this.privateStateManager?.getStateId();
}

/**
* Creates a proxy that combines contract methods with adapter methods
*/
private createAdapterProxy(): IContractAdapter<TContract, TPrivateState> {
// Capture reference to this for use in proxy
// eslint-disable-next-line @typescript-eslint/no-this-alias
const adapter = this;

const adapterProxy = new Proxy(this.proxy, {
get(target: DeployedContract<TContract>, prop: string | symbol): unknown {
// Handle 'on' method for event registration
if (prop === 'on') {
return (event: string, handler: EventHandler) => {
adapter.registerEventHandler(event, handler);
return adapterProxy;
};
}

// Handle address
if (prop === 'address') {
return adapter.address;
}

// Handle deployTxData
if (prop === 'deployTxData') {
return adapter.deployTxData;
}

// Handle private state methods
if (prop === 'getPrivateState') {
return () => adapter.getPrivateState();
}

if (prop === 'setPrivateState') {
return (state: TPrivateState) => adapter.setPrivateState(state);
}

if (prop === 'getPrivateStateId') {
return () => adapter.getPrivateStateId();
}

// Forward to the proxied contract's callTx methods
const callTx = target.callTx;
if (callTx && typeof callTx === 'object' && prop in callTx) {
return (callTx as Record<string | symbol, unknown>)[prop];
}

// Forward to target
return (target as unknown as Record<string | symbol, unknown>)[prop];
}
});

return adapterProxy as unknown as IContractAdapter<TContract, TPrivateState>;
}
}
Loading
Loading