Skip to content

Commit 68047c3

Browse files
committed
feat: add new and stable changes for midnight setup library
1 parent 706369a commit 68047c3

59 files changed

Lines changed: 2736 additions & 672 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 0 additions & 440 deletions
This file was deleted.

compact/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "@quick-starter/quick-starter-compact",
2+
"name": "@midnight-setup/midnight-setup-compact",
33
"description": "Compact fetcher",
44
"author": "IOG",
55
"license": "Apache-2.0",
@@ -8,7 +8,7 @@
88
"type": "module",
99
"packageManager": "yarn@4.0.0",
1010
"bin": {
11-
"run-compactc": "src/run-compactc.cjs"
11+
"run-compact": "src/run-compact.cjs"
1212
},
1313
"devDependencies": {
1414
"eslint": "^8.52.0",

compact/src/run-compactc.cjs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,16 @@ if (COMPACT_HOME_ENV != null) {
1515
compactPath = COMPACT_HOME_ENV;
1616
console.log(`COMPACT_HOME env variable is set; using Compact from ${compactPath}`);
1717
} else {
18-
compactPath = path.resolve(__dirname, '..', 'compactc');
18+
compactPath = path.resolve(__dirname, '..', 'compact');
1919
console.log(`COMPACT_HOME env variable is not set; using fetched compact from ${compactPath}`);
2020
}
2121

22-
// Debug: Print the full path to compactc and zkir
23-
console.log(`compactc path: ${path.resolve(compactPath, 'compactc')}`);
22+
// Debug: Print the full path to compact and zkir
23+
console.log(`compact path: ${path.resolve(compactPath, 'compact')}`);
2424
console.log(`zkir path: ${path.resolve(compactPath, 'zkir')}`);
2525

2626
// yarn runs everything with node...
27-
const child = childProcess.spawn(path.resolve(compactPath, 'compactc'), args, {
27+
const child = childProcess.spawn(path.resolve(compactPath, 'compact'), args, {
2828
stdio: 'inherit'
2929
});
3030
child.on('exit', (code, signal) => {

compact/turbo.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"extends": ["//"],
44
"tasks": {
55
"build": {
6-
"outputs": ["compactc/**"],
6+
"outputs": ["compact/**"],
77
"env": ["COMPACT_HOME"],
88
"inputs": ["src/**"],
99
"cache": true

docs/README.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

fetch-zk-params.sh

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/bin/sh
2+
# Copyright 2025 Brick Towers
3+
4+
set -e # exit on error
5+
set -x # print each command before executing
6+
7+
# Default CIRCUIT_PARAM_RANGE if not provided
8+
CIRCUIT_PARAM_RANGE=${CIRCUIT_PARAM_RANGE:-"10 11 12 13 14 15 16 17"}
9+
ZK_PARAMS_DIR=${ZK_PARAMS_DIR:-".cache/midnight/zk-params"}
10+
11+
# Create target directory
12+
mkdir -p "$ZK_PARAMS_DIR/zswap/4"
13+
14+
echo "📥 Downloading BLS Filecoin params..."
15+
for i in $CIRCUIT_PARAM_RANGE; do
16+
echo " ↳ bls_filecoin_2p$i"
17+
curl -sSLo "$ZK_PARAMS_DIR/bls_filecoin_2p$i" \
18+
"https://midnight-s3-fileshare-dev-eu-west-1.s3.eu-west-1.amazonaws.com/bls_filecoin_2p$i"
19+
done
20+
21+
echo "📥 Downloading zswap/4 circuits..."
22+
cd "$ZK_PARAMS_DIR/zswap/4" || exit 1
23+
for file in \
24+
output.bzkir output.prover output.verifier \
25+
sign.bzkir sign.prover sign.verifier \
26+
spend.bzkir spend.prover spend.verifier; do
27+
echo "$file"
28+
curl -sSLO "https://midnight-s3-fileshare-dev-eu-west-1.s3.eu-west-1.amazonaws.com/zswap/4/$file"
29+
done

packages/api/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "@quick-starter/quick-starter-api",
2+
"name": "@midnight-setup/midnight-setup-api",
33
"packageManager": "yarn@4.9.2",
44
"type": "module",
55
"main": "./dist/index.js",
@@ -21,7 +21,7 @@
2121
"build": "rm -rf dist && tsc --project tsconfig.build.json"
2222
},
2323
"dependencies": {
24-
"@quick-starter/quick-starter-contract": "workspace:*",
24+
"@midnight-setup/midnight-setup-contract": "workspace:*",
2525
"pino": "^8.16.1",
2626
"uuid": "^11.1.0",
2727
"ws": "8.17.1"

packages/api/src/common-types.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import type {
2+
PrivateStateProvider,
3+
ZKConfigProvider,
4+
ProofProvider,
5+
PublicDataProvider,
6+
WalletProvider,
7+
MidnightProvider
8+
} from "@midnight-ntwrk/midnight-js-types";
9+
10+
// Private state identifier for the contract
11+
export const MidnightSetupPrivateStateId = "midnight-setup-private-state";
12+
export type MidnightSetupPrivateStateId = typeof MidnightSetupPrivateStateId;
13+
14+
// Circuit keys type for proof provider
15+
export type TokenCircuitKeys = string;
16+
17+
// Contract providers interface with proper types
18+
export interface MidnightSetupContractProviders {
19+
privateStateProvider: PrivateStateProvider;
20+
zkConfigProvider: ZKConfigProvider<TokenCircuitKeys>;
21+
proofProvider: ProofProvider<TokenCircuitKeys>;
22+
publicDataProvider: PublicDataProvider;
23+
walletProvider: WalletProvider;
24+
midnightProvider: MidnightProvider;
25+
}
26+
27+
// Contract state types - using unknown for flexible state data
28+
export interface ContractStateData {
29+
readonly address: string;
30+
readonly data: unknown;
31+
readonly blockHeight?: string;
32+
readonly blockHash?: string;
33+
readonly message?: string;
34+
readonly error?: string;
35+
}
36+
37+
export interface LedgerStateData {
38+
readonly address: string;
39+
readonly ledgerState?: {
40+
readonly message: string | null;
41+
};
42+
readonly blockHeight?: string;
43+
readonly blockHash?: string;
44+
readonly rawData?: unknown;
45+
readonly parseError?: string;
46+
readonly error?: string;
47+
}
48+
49+
export type DerivedMidnightSetupContractState = {
50+
readonly protocolTVL: unknown[];
51+
readonly projects: unknown[];
52+
};

packages/api/src/index.ts

Lines changed: 222 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,222 @@
1-
// TODO: Only for folder structure. Adjust QuickStarterPrivateStateId based on your implementation.
2-
// Common types and constants
3-
export const QuickStarterPrivateStateId = 'quick-starter-private-state';
1+
import { Observable } from "rxjs";
2+
import { ContractAddress } from "@midnight-ntwrk/compact-runtime";
3+
import { type Logger } from "pino";
4+
import { ledger, Contract } from "@midnight-setup/midnight-setup-contract";
5+
import { deployContract, findDeployedContract } from "@midnight-ntwrk/midnight-js-contracts";
6+
import * as utils from "./utils.js";
7+
import {
8+
MidnightSetupContractProviders,
9+
MidnightSetupPrivateStateId,
10+
DerivedMidnightSetupContractState,
11+
ContractStateData,
12+
LedgerStateData,
13+
} from "./common-types.js";
14+
15+
export interface DeployedMidnightSetupAPI {
16+
readonly deployedContractAddress: ContractAddress;
17+
readonly state: Observable<DerivedMidnightSetupContractState>;
18+
getContractState: () => Promise<ContractStateData>;
19+
getLedgerState: () => Promise<LedgerStateData>;
20+
}
21+
/**
22+
* NB: Declaring a class implements a given type, means it must contain all defined properties and methods, then take on other extra properties or class
23+
*/
24+
25+
export class MidnightSetupAPI implements DeployedMidnightSetupAPI {
26+
deployedContractAddress: string;
27+
state: Observable<DerivedMidnightSetupContractState>;
28+
29+
private constructor(
30+
private providers: MidnightSetupContractProviders,
31+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
32+
public readonly allReadyDeployedContract: any,
33+
private logger?: Logger
34+
) {
35+
this.deployedContractAddress = allReadyDeployedContract.deployTxData.public.contractAddress;
36+
37+
// Real state observable
38+
this.state = new Observable(subscriber => {
39+
subscriber.next({
40+
protocolTVL: [],
41+
projects: [],
42+
});
43+
});
44+
}
45+
46+
async getContractState(): Promise<ContractStateData> {
47+
try {
48+
this.logger?.info("Getting contract state...", { address: this.deployedContractAddress });
49+
50+
// Try to get contract state from public data provider
51+
const contractState = await this.providers.publicDataProvider.queryContractState(this.deployedContractAddress);
52+
53+
if (contractState) {
54+
this.logger?.info("Contract state retrieved successfully");
55+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
56+
const stateAny = contractState as any;
57+
return {
58+
address: this.deployedContractAddress,
59+
data: contractState.data,
60+
blockHeight: stateAny.blockHeight?.toString(),
61+
blockHash: stateAny.blockHash?.toString(),
62+
};
63+
} else {
64+
this.logger?.warn("No contract state found");
65+
return {
66+
address: this.deployedContractAddress,
67+
data: null,
68+
message: "No contract state found at this address"
69+
};
70+
}
71+
} catch (error) {
72+
this.logger?.error("Failed to get contract state", { error: error instanceof Error ? error.message : error });
73+
return {
74+
address: this.deployedContractAddress,
75+
data: null,
76+
error: error instanceof Error ? error.message : "Failed to get contract state"
77+
};
78+
}
79+
}
80+
81+
async getLedgerState(): Promise<LedgerStateData> {
82+
try {
83+
this.logger?.info("Getting ledger state...", { address: this.deployedContractAddress });
84+
85+
const contractState = await this.getContractState();
86+
87+
if (contractState.data) {
88+
// Try to parse the ledger state
89+
try {
90+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
91+
const ledgerState = ledger(contractState.data as any);
92+
this.logger?.info("Ledger state parsed successfully");
93+
return {
94+
address: this.deployedContractAddress,
95+
ledgerState: {
96+
message: ledgerState.message ? new TextDecoder().decode(ledgerState.message) : null,
97+
},
98+
blockHeight: contractState.blockHeight,
99+
blockHash: contractState.blockHash,
100+
};
101+
} catch (parseError) {
102+
this.logger?.warn("Failed to parse ledger state", { error: parseError });
103+
return {
104+
address: this.deployedContractAddress,
105+
rawData: contractState.data,
106+
parseError: parseError instanceof Error ? parseError.message : "Failed to parse ledger state"
107+
};
108+
}
109+
} else {
110+
return {
111+
address: this.deployedContractAddress,
112+
error: contractState.error || contractState.message
113+
};
114+
}
115+
} catch (error) {
116+
this.logger?.error("Failed to get ledger state", { error: error instanceof Error ? error.message : error });
117+
return {
118+
address: this.deployedContractAddress,
119+
error: error instanceof Error ? error.message : "Failed to get ledger state"
120+
};
121+
}
122+
}
123+
124+
static async deployMidnightSetupContract(
125+
providers: MidnightSetupContractProviders,
126+
logger?: Logger
127+
): Promise<MidnightSetupAPI> {
128+
logger?.info("Deploying contract...");
129+
130+
try {
131+
// Get or create initial private state
132+
const initialPrivateState = await MidnightSetupAPI.getPrivateState(providers);
133+
134+
// Create contract instance with constructor arguments
135+
const contractInstance = new Contract({});
136+
137+
// Real contract deployment using the wallet
138+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
139+
const deployedContract = await deployContract(
140+
providers as any,
141+
{
142+
contract: contractInstance,
143+
initialPrivateState: initialPrivateState,
144+
privateStateId: MidnightSetupPrivateStateId,
145+
}
146+
);
147+
148+
logger?.info("Contract deployed successfully", {
149+
address: deployedContract.deployTxData.public.contractAddress
150+
});
151+
return new MidnightSetupAPI(providers, deployedContract, logger);
152+
} catch (error) {
153+
logger?.error("Failed to deploy contract", {
154+
error: error instanceof Error ? error.message : String(error),
155+
stack: error instanceof Error ? error.stack : undefined
156+
});
157+
throw error;
158+
}
159+
}
160+
161+
static async joinMidnightSetupContract(
162+
providers: MidnightSetupContractProviders,
163+
contractAddress: string,
164+
logger?: Logger
165+
): Promise<MidnightSetupAPI> {
166+
logger?.info("Joining contract...", { contractAddress });
167+
168+
try {
169+
// Get or create initial private state
170+
const initialPrivateState = await MidnightSetupAPI.getPrivateState(providers);
171+
172+
// Create contract instance
173+
const contractInstance = new Contract({});
174+
175+
// Real contract join using the wallet
176+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
177+
const existingContract = await findDeployedContract(
178+
providers as any,
179+
{
180+
contract: contractInstance,
181+
contractAddress: contractAddress,
182+
privateStateId: MidnightSetupPrivateStateId,
183+
initialPrivateState: initialPrivateState,
184+
}
185+
);
186+
187+
logger?.info("Successfully joined contract", {
188+
address: existingContract.deployTxData.public.contractAddress
189+
});
190+
return new MidnightSetupAPI(providers, existingContract, logger);
191+
} catch (error) {
192+
logger?.error("Failed to join contract", {
193+
error: error instanceof Error ? error.message : String(error),
194+
contractAddress
195+
});
196+
throw error;
197+
}
198+
}
199+
200+
private static async getPrivateState(
201+
providers: MidnightSetupContractProviders
202+
): Promise<Record<string, unknown>> {
203+
try {
204+
const existingPrivateState = await providers.privateStateProvider.get(
205+
MidnightSetupPrivateStateId
206+
);
207+
208+
// If no existing state, return empty object (the contract will initialize it)
209+
return existingPrivateState ?? {};
210+
} catch (error) {
211+
console.warn("Error getting private state, returning empty object:", error);
212+
return {};
213+
}
214+
}
215+
}
216+
217+
export * as utils from "./utils.js";
218+
219+
export * from "./common-types.js";
220+
221+
// Re-export types for external use
222+
export type { ContractStateData, LedgerStateData } from "./common-types.js";

packages/api/src/utils.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Logger } from "pino";
2+
3+
// Simple utility functions for proof server connection
4+
export const randomNonceBytes = (length: number, logger?: Logger): Uint8Array => {
5+
const newBytes = new Uint8Array(length);
6+
crypto.getRandomValues(newBytes);
7+
logger?.info("Random nonce bytes generated");
8+
return newBytes;
9+
}
10+
11+
export function hexStringToUint8Array(hexStr: string): Uint8Array {
12+
// Simple hex to Uint8Array conversion
13+
const hex = hexStr.replace(/^0x/, '');
14+
const bytes = new Uint8Array(hex.length / 2);
15+
16+
for (let i = 0; i < hex.length; i += 2) {
17+
bytes[i / 2] = parseInt(hex.substr(i, 2), 16);
18+
}
19+
20+
return bytes;
21+
}
22+
23+
export default { randomNonceBytes, hexStringToUint8Array };

0 commit comments

Comments
 (0)