diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 3c426a8..cb04a66 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -6,6 +6,10 @@ inputs: description: "Skip Compact compiler installation" required: false default: "false" + compact-prerelease: + description: "Pre-release Compact compiler to fetch from GitHub releases (bridge until the toolchain ships stable). Keep in sync with setup.ts COMPACTC_VERSION." + required: false + default: "0.33.0-rc.2" runs: using: "composite" @@ -44,3 +48,27 @@ runs: uses: midnightntwrk/setup-compact-action@4130145456ad3f45934788dd4a65647eb283e658 # loose commit/not released with: compact-version: "0.31.0" + + # The tests pin a pre-release compiler (secp256k1 / 0.18 runtime) that + # `compact update` does not serve, so fetch its release asset directly and + # drop it where `compact +` looks. Remove once the toolchain ships + # a stable release (then just bump compact-version above). + - name: Install pre-release Compact toolchain + if: ${{ inputs.skip-compact != 'true' }} + shell: bash + env: + VER: ${{ inputs.compact-prerelease }} + run: | + set -euo pipefail + # Reuse the platform dir the CLI already created for the stable install + # (e.g. x86_64-unknown-linux-musl), so the pre-release lands where the + # `+` selector resolves it; fall back to the host triple. + PLAT="$(basename "$(find "$HOME/.compact/versions" -mindepth 2 -maxdepth 2 -type d 2>/dev/null | head -1)" 2>/dev/null || true)" + [ -z "$PLAT" ] && PLAT="$(uname -m)-unknown-linux-musl" + DEST="$HOME/.compact/versions/$VER/$PLAT" + mkdir -p "$DEST" + curl -fsSL -o /tmp/compactc.zip \ + "https://github.com/LFDT-Minokawa/compact/releases/download/compactc-v$VER/compactc_v${VER}_${PLAT}.zip" + unzip -oq /tmp/compactc.zip -d "$DEST" + chmod +x "$DEST"/* + compact compile +"$VER" --version diff --git a/packages/simulator/package.json b/packages/simulator/package.json index 726e5c5..a5f1fc8 100644 --- a/packages/simulator/package.json +++ b/packages/simulator/package.json @@ -41,8 +41,10 @@ "clean": "git clean -fXd" }, "devDependencies": { - "@midnight-ntwrk/midnight-js-contracts": "^4.1.0", - "@midnight-ntwrk/midnight-js-types": "^4.1.0", + "@midnight-ntwrk/midnight-js-contracts": "5.0.0-beta.6", + "@midnight-ntwrk/midnight-js-types": "5.0.0-beta.6", + "@noble/curves": "^2.2.0", + "@noble/hashes": "^2.2.0", "@tsconfig/node24": "^24.0.3", "@types/node": "26.1.2", "fast-check": "^4.5.2", @@ -50,12 +52,11 @@ "vitest": "^4.1.9" }, "dependencies": { - "@midnight-ntwrk/compact-runtime": "0.16.0", - "@midnight-ntwrk/ledger-v8": "8.1.0" + "@midnight-ntwrk/compact-runtime": "0.18.0-rc.1" }, "peerDependencies": { - "@midnight-ntwrk/midnight-js-contracts": "^4.1.0", - "@midnight-ntwrk/midnight-js-types": "^4.1.0" + "@midnight-ntwrk/midnight-js-contracts": "^5.0.0-beta.6", + "@midnight-ntwrk/midnight-js-types": "^5.0.0-beta.6" }, "peerDependenciesMeta": { "@midnight-ntwrk/midnight-js-contracts": { diff --git a/packages/simulator/src/core/AbstractSimulator.ts b/packages/simulator/src/core/AbstractSimulator.ts index b8af16d..c179fe8 100644 --- a/packages/simulator/src/core/AbstractSimulator.ts +++ b/packages/simulator/src/core/AbstractSimulator.ts @@ -93,7 +93,7 @@ export abstract class AbstractSimulator * @returns The current private state of type P */ public getPrivateState(): P { - return this.circuitContext.currentPrivateState; + return this.circuitContext.callContext.currentPrivateState as P; } /** @@ -102,7 +102,7 @@ export abstract class AbstractSimulator * @returns The current state value containing the ledger data */ public getContractState(): StateValue { - return this.circuitContext.currentQueryContext.state.state; + return this.circuitContext.callContext.currentQueryContext.state.state; } /** @@ -130,12 +130,13 @@ export abstract class AbstractSimulator const original = Reflect.get(target, prop, receiver); if (typeof original !== 'function') return original; - return (...args: unknown[]) => { + return async (...args: unknown[]) => { const fn = original as ( ctx: CircuitContext

, ...args: unknown[] - ) => { result: unknown }; - const result = fn(context(), ...args).result; + ) => { result: unknown } | Promise<{ result: unknown }>; + // 0.18 circuits are async; `await` also tolerates the older sync shape. + const { result } = await fn(context(), ...args); // Auto-reset single-use caller override this.callerOverride = null; @@ -172,13 +173,16 @@ export abstract class AbstractSimulator const original = Reflect.get(target, prop, receiver); if (typeof original !== 'function') return original; - return (...args: unknown[]) => { + return async (...args: unknown[]) => { const fn = original as ( ctx: CircuitContext

, ...args: unknown[] - ) => { result: unknown; context: CircuitContext

}; + ) => + | { result: unknown; context: CircuitContext

} + | Promise<{ result: unknown; context: CircuitContext

}>; - const { result, context: newCtx } = fn(context(), ...args); + // 0.18 circuits are async; `await` also tolerates the older sync shape. + const { result, context: newCtx } = await fn(context(), ...args); updateContext(newCtx); // Auto-reset single-use caller override diff --git a/packages/simulator/src/core/CircuitContextManager.ts b/packages/simulator/src/core/CircuitContextManager.ts index 0928d1a..ec578f8 100644 --- a/packages/simulator/src/core/CircuitContextManager.ts +++ b/packages/simulator/src/core/CircuitContextManager.ts @@ -4,10 +4,9 @@ import { type ConstructorContext, type ContractAddress, type ContractState, - CostModel, + createCircuitContext, createConstructorContext, type EncodedZswapLocalState, - QueryContext, } from '@midnight-ntwrk/compact-runtime'; /** @@ -16,12 +15,36 @@ import { * Handles initialization and lifecycle management of the `CircuitContext`, * which includes private state, public (ledger) state, zswap local state, and transaction context. */ +/** Shape of a compiled contract's constructor result (sync or async in 0.18). */ +type InitialStateResult

= { + currentPrivateState: P; + currentContractState: ContractState; + currentZswapLocalState: EncodedZswapLocalState; +}; + export class CircuitContextManager

{ - public context: CircuitContext

; + // Assigned by the async `init()`; the manager is always constructed and then + // awaited (`init`) before any circuit call reads the context. + public context!: CircuitContext

; + + private readonly contract: { + initialState: ( + ctx: ConstructorContext

, + ...args: any[] + ) => InitialStateResult

| Promise>; + }; + private readonly privateState: P; + private readonly coinPK: CoinPublicKey; + private readonly contractAddress: ContractAddress; + private readonly contractArgs: any[]; /** * Creates an instance of `CircuitContextManager`. * + * @remarks compact-runtime 0.18 made `initialState` (and every circuit) async, + * so the constructor only records inputs; the context is built by the async + * {@link init}, which callers must await before using the manager. + * * @param contract - A compiled Compact contract instance exposing `initialState()` * @param contract.initialState - Function that initializes contract state given a constructor context * @param privateState - The initial private state to inject into the contract @@ -34,34 +57,44 @@ export class CircuitContextManager

{ initialState: ( ctx: ConstructorContext

, ...args: any[] - ) => { - currentPrivateState: P; - currentContractState: ContractState; - currentZswapLocalState: EncodedZswapLocalState; - }; + ) => InitialStateResult

| Promise>; }, privateState: P, coinPK: CoinPublicKey, contractAddress: ContractAddress, ...contractArgs: any[] ) { - const initCtx = createConstructorContext(privateState, coinPK); + this.contract = contract; + this.privateState = privateState; + this.coinPK = coinPK; + this.contractAddress = contractAddress; + this.contractArgs = contractArgs; + } + + /** + * Runs the contract constructor and builds the initial `CircuitContext`. + * Must be awaited once, after construction, before any circuit call. + */ + async init(): Promise { + const initCtx = createConstructorContext(this.privateState, this.coinPK); const { currentPrivateState, currentContractState, currentZswapLocalState, - } = contract.initialState(initCtx, ...contractArgs); - - // Extract ChargedState from the compiler-generated ContractState - const chargedState = currentContractState.data; + } = await this.contract.initialState(initCtx, ...this.contractArgs); - this.context = { - currentPrivateState, + // compact-runtime 0.18 restructured `CircuitContext` into a call-tree + // (`callContext` + per-contract `queryContexts`/`gasCosts`). Build it via + // the runtime's `createCircuitContext` factory rather than a hand-rolled + // literal so every required field is populated correctly. + this.context = createCircuitContext

( + 'circuit', + this.contractAddress, currentZswapLocalState, - currentQueryContext: new QueryContext(chargedState, contractAddress), - costModel: CostModel.initialCostModel(), - }; + currentContractState.data, + currentPrivateState, + ); } /** @@ -88,6 +121,6 @@ export class CircuitContextManager

{ * @param newPrivateState - The new private state to set in the current context */ updatePrivateState(newPrivateState: P) { - this.context.currentPrivateState = newPrivateState; + this.context.callContext.currentPrivateState = newPrivateState; } } diff --git a/packages/simulator/src/core/ContractSimulator.ts b/packages/simulator/src/core/ContractSimulator.ts index 2b114a3..914af9a 100644 --- a/packages/simulator/src/core/ContractSimulator.ts +++ b/packages/simulator/src/core/ContractSimulator.ts @@ -1,5 +1,6 @@ import { type CircuitContext, + copyCircuitContext, emptyZswapLocalState, } from '@midnight-ntwrk/compact-runtime'; import { AbstractSimulator } from './AbstractSimulator.js'; @@ -43,15 +44,16 @@ export abstract class ContractSimulator extends AbstractSimulator { const activeCaller = this.callerOverride || this.persistentCallerOverride; const baseCtx = this.circuitContext; - return { - currentPrivateState: baseCtx.currentPrivateState, - currentQueryContext: baseCtx.currentQueryContext, - currentZswapLocalState: activeCaller - ? emptyZswapLocalState(activeCaller) - : baseCtx.currentZswapLocalState, - costModel: baseCtx.costModel, - gasLimit: baseCtx.gasLimit, - }; + if (!activeCaller) { + return baseCtx; + } + + // compact-runtime 0.18: the caller-scoped fields live on `callContext`. + // Copy (shallow-clones `callContext`) before overriding the Zswap local + // state so the base context is left untouched. + const ctx = copyCircuitContext(baseCtx) as CircuitContext

; + ctx.callContext.currentZswapLocalState = emptyZswapLocalState(activeCaller); + return ctx; } /** diff --git a/packages/simulator/src/factory/createDrySimulator.ts b/packages/simulator/src/factory/createDrySimulator.ts index 5e65dd5..33d6fbf 100644 --- a/packages/simulator/src/factory/createDrySimulator.ts +++ b/packages/simulator/src/factory/createDrySimulator.ts @@ -34,7 +34,9 @@ export function createDrySimulator< >(config: SimulatorConfig) { return class GeneratedSimulator extends ContractSimulator { contract: TContract; - readonly contractAddress: string; + // Assigned by the async `init()` (0.18 made `initialState` async, so the + // address — read from the built context — is not known at construction). + contractAddress!: string; public _witnesses: W; /** @@ -65,8 +67,18 @@ export function createDrySimulator< contractAddress, ...processedArgs, ); + } - this.contractAddress = this.circuitContext.currentQueryContext.address; + /** + * Runs the contract constructor and finalizes state. Must be awaited once, + * after construction, before any circuit call. Split out from the + * constructor because compact-runtime 0.18 made `initialState` async. + */ + async init(): Promise { + await this.circuitContextManager.init(); + this.contractAddress = + this.circuitContext.callContext.currentQueryContext.address; + return this; } public _pureCircuitProxy?: ContextlessCircuits< @@ -144,7 +156,7 @@ export function createDrySimulator< */ getPublicState(): L { return config.ledgerExtractor( - this.circuitContext.currentQueryContext.state.state, + this.circuitContext.callContext.currentQueryContext.state.state, ); } @@ -191,8 +203,8 @@ export function createDrySimulator< const circuitCtx = this.circuitContext; return { ledger: this.getPublicState(), - privateState: circuitCtx.currentPrivateState, - contractAddress: circuitCtx.currentQueryContext.address, + privateState: circuitCtx.callContext.currentPrivateState as P, + contractAddress: circuitCtx.callContext.currentQueryContext.address, }; } }; diff --git a/packages/simulator/src/factory/createSimulator.ts b/packages/simulator/src/factory/createSimulator.ts index ee83bc9..006123b 100644 --- a/packages/simulator/src/factory/createSimulator.ts +++ b/packages/simulator/src/factory/createSimulator.ts @@ -85,6 +85,9 @@ export function createSimulator< // evaluator in live (D2). In live this runs `initialState` in memory only — // it is never deployed on-chain. const localSim = new DrySimClass(contractArgs, options); + // 0.18: `initialState` is async, so the constructor defers the constructor + // run to `init()`. Await it before deriving names / wiring any backend. + await localSim.init(); const contract = localSim.contract; const impureNames = Object.keys(contract.impureCircuits); const impureSet = new Set(impureNames); @@ -246,6 +249,15 @@ export function createSimulator< return this._signers; } + /** + * The deployed contract's address. Needed by callers that must reconstruct + * a circuit's message digest off-chain (e.g. signing an operation bound to + * `kernel.self()`). + */ + get contractAddress(): string { + return this._backend.contractAddress; + } + /** * Sets the caller for the next call only, then reverts. * diff --git a/packages/simulator/src/signers/Signers.ts b/packages/simulator/src/signers/Signers.ts index e913340..a39eb6b 100644 --- a/packages/simulator/src/signers/Signers.ts +++ b/packages/simulator/src/signers/Signers.ts @@ -1,6 +1,5 @@ import { type CoinPublicKey, - convertFieldToBytes, encodeCoinPublicKey, } from '@midnight-ntwrk/compact-runtime'; import type { BackendKind } from '../backend/Backend.js'; @@ -39,7 +38,10 @@ export type Either = { const aliasToHex = (alias: string): CoinPublicKey => Buffer.from(alias, 'ascii').toString('hex').padStart(64, '0'); -const zeroBytes = (): Uint8Array => convertFieldToBytes(32, 0n, ''); +// A 32-byte zero array. Previously derived via the runtime's +// `convertFieldToBytes(32, 0n, '')`, which was removed in compact-runtime 0.18; +// the value is identical (the byte encoding of field element 0). +const zeroBytes = (): Uint8Array => new Uint8Array(32); /** * Configuration for {@link Signers}. diff --git a/packages/simulator/src/utils/CircuitContextUtils.ts b/packages/simulator/src/utils/CircuitContextUtils.ts index 420ac75..96da6a1 100644 --- a/packages/simulator/src/utils/CircuitContextUtils.ts +++ b/packages/simulator/src/utils/CircuitContextUtils.ts @@ -3,9 +3,7 @@ import { type CircuitContext, type CoinPublicKey, type ContractAddress, - CostModel, - emptyZswapLocalState, - QueryContext, + createCircuitContext, } from '@midnight-ntwrk/compact-runtime'; import type { IContractSimulator } from '../types/index.js'; @@ -27,12 +25,16 @@ export function useCircuitContext

( sender: CoinPublicKey, contractAddress: ContractAddress, ): CircuitContext

{ - return { - currentPrivateState: privateState, - currentQueryContext: new QueryContext(chargedState, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - costModel: CostModel.initialCostModel(), - }; + // compact-runtime 0.18: `createCircuitContext` populates the full call-tree + // shape (callContext + queryContexts/gasCosts) and derives an empty Zswap + // local state from `sender`. + return createCircuitContext

( + 'circuit', + contractAddress, + sender, + chargedState, + privateState, + ); } /** @@ -50,17 +52,18 @@ export function useCircuitContextSender< >(contract: C, sender: CoinPublicKey): CircuitContext

{ const currentCircuitContext = contract.circuitContext; const currentPrivateState = contract.getPrivateState(); - const existingChargedState = currentCircuitContext.currentQueryContext.state; + const existingChargedState = + currentCircuitContext.callContext.currentQueryContext.state; const contractAddress = contract.contractAddress; - return { + return createCircuitContext

( + 'circuit', + contractAddress, + sender, + existingChargedState, currentPrivateState, - currentQueryContext: new QueryContext( - existingChargedState, - contractAddress, - ), - currentZswapLocalState: emptyZswapLocalState(sender), - costModel: currentCircuitContext.costModel, - gasLimit: currentCircuitContext.gasLimit, - }; + undefined, + currentCircuitContext.gasLimit, + currentCircuitContext.costModel, + ); } diff --git a/packages/simulator/test/fixtures/sample-contracts/Ecdsa.compact b/packages/simulator/test/fixtures/sample-contracts/Ecdsa.compact new file mode 100644 index 0000000..afcc00e --- /dev/null +++ b/packages/simulator/test/fixtures/sample-contracts/Ecdsa.compact @@ -0,0 +1,34 @@ +// Sample contract for testing +// DO NOT USE IN PRODUCTION!!! + +pragma language_version >= 0.20.0; + +import CompactStandardLibrary; + +// Re-export the secp256k1 types so the generated TS exposes them. +export { Secp256k1EcdsaSignature, Secp256k1Point }; + +// Records the outcome of the last stored verification, so the simulator's +// impure/state path is exercised (not just a pure passthrough). +export ledger lastVerified: Boolean; + +// Ethereum-style: hash `msg` with keccak256 in-circuit, then verify the ECDSA +// signature over that digest. Pure, no ledger or witness access. +export circuit verifyEthereum( + msg: Bytes<32>, + sig: Secp256k1EcdsaSignature, + pk: Secp256k1Point +): Boolean { + return secp256k1EcdsaVerify(keccak256>(msg), sig, pk); +} + +// Same verification, but records the outcome on-ledger (impure). +export circuit verifyAndStore( + msg: Bytes<32>, + sig: Secp256k1EcdsaSignature, + pk: Secp256k1Point +): Boolean { + const ok = secp256k1EcdsaVerify(keccak256>(msg), sig, pk); + lastVerified = disclose(ok); + return ok; +} diff --git a/packages/simulator/test/fixtures/sample-contracts/witnesses/EcdsaWitnesses.ts b/packages/simulator/test/fixtures/sample-contracts/witnesses/EcdsaWitnesses.ts new file mode 100644 index 0000000..20234df --- /dev/null +++ b/packages/simulator/test/fixtures/sample-contracts/witnesses/EcdsaWitnesses.ts @@ -0,0 +1,5 @@ +// Ecdsa has no witnesses and no private state; the verification circuits take +// all their inputs as arguments. +export type EcdsaPrivateState = Record; +export const EcdsaPrivateState: EcdsaPrivateState = {}; +export const EcdsaWitnesses = () => ({}); diff --git a/packages/simulator/test/fixtures/utils/address.ts b/packages/simulator/test/fixtures/utils/address.ts index fefd04b..221a7ce 100644 --- a/packages/simulator/test/fixtures/utils/address.ts +++ b/packages/simulator/test/fixtures/utils/address.ts @@ -1,8 +1,7 @@ import { - convertFieldToBytes, encodeCoinPublicKey, + encodeContractAddress, } from '@midnight-ntwrk/compact-runtime'; -import { encodeContractAddress } from '@midnight-ntwrk/ledger-v8'; import type * as Compact from '../artifacts/SampleZOwnable/contract/index.js'; const PREFIX_ADDRESS = '0200'; @@ -91,8 +90,10 @@ export const generateEitherPubKeyPair = (str: string) => Compact.Either, ]; -export const zeroUint8Array = (length = 32) => - convertFieldToBytes(length, 0n, ''); +// A zero-filled byte array of `length`. (Previously `convertFieldToBytes(length, +// 0n, '')` from compact-runtime 0.16, which was removed in 0.18; a `new +// Uint8Array` is zero-initialized and behaves identically here.) +export const zeroUint8Array = (length = 32) => new Uint8Array(length); export const ZERO_KEY = { is_left: true, diff --git a/packages/simulator/test/integration/Ecdsa.test.ts b/packages/simulator/test/integration/Ecdsa.test.ts new file mode 100644 index 0000000..ad6e493 --- /dev/null +++ b/packages/simulator/test/integration/Ecdsa.test.ts @@ -0,0 +1,47 @@ +import { secp256k1 } from '@noble/curves/secp256k1.js'; +import { keccak_256 } from '@noble/hashes/sha3.js'; +import { beforeAll, describe, expect, it } from 'vitest'; +import { EcdsaSimulator } from './EcdsaSimulator'; + +// Deterministic inputs: a fixed secret key plus RFC 6979 signing yields a stable +// signature, so the vector below is reproducible without any randomness. +const SK = Uint8Array.from({ length: 32 }, (_, i) => i + 1); // 0x0102…20 — a valid scalar +const pubAffine = secp256k1.Point.fromBytes( + secp256k1.getPublicKey(SK), +).toAffine(); +const pk = { x: pubAffine.x, y: pubAffine.y, identity: false }; + +const msg = new Uint8Array(32).fill(0xab); +// The circuit hashes msg with keccak256, so sign the keccak digest off-circuit. +const signed = secp256k1.Signature.fromBytes( + secp256k1.sign(keccak_256(msg), SK, { format: 'recovered', prehash: false }), + 'recovered', +); +const sig = { r: signed.r, s: signed.s }; +// Bump s so the signature no longer verifies. +const tampered = { r: signed.r, s: signed.s + 1n }; + +describe('[ECDSA] simulator runs secp256k1EcdsaVerify end-to-end', () => { + let sim: EcdsaSimulator; + beforeAll(async () => { + sim = await EcdsaSimulator.create(); + }); + + it('pure verifyEthereum accepts a valid signature', async () => { + expect(await sim.verifyEthereum(msg, sig, pk)).toBe(true); + }); + + it('pure verifyEthereum rejects a tampered signature', async () => { + expect(await sim.verifyEthereum(msg, tampered, pk)).toBe(false); + }); + + it('impure verifyAndStore records a valid result on-ledger', async () => { + expect(await sim.verifyAndStore(msg, sig, pk)).toBe(true); + expect((await sim.getPublicState()).lastVerified).toBe(true); + }); + + it('impure verifyAndStore records a tampered result as false', async () => { + expect(await sim.verifyAndStore(msg, tampered, pk)).toBe(false); + expect((await sim.getPublicState()).lastVerified).toBe(false); + }); +}); diff --git a/packages/simulator/test/integration/EcdsaSimulator.ts b/packages/simulator/test/integration/EcdsaSimulator.ts new file mode 100644 index 0000000..4fd828e --- /dev/null +++ b/packages/simulator/test/integration/EcdsaSimulator.ts @@ -0,0 +1,64 @@ +import type { Secp256k1Point } from '@midnight-ntwrk/compact-runtime'; +import { createSimulator, type SimulatorOptions } from '../../src/index'; +import { + Contract as EcdsaContract, + ledger, +} from '../fixtures/artifacts/Ecdsa/contract/index.js'; +import { + EcdsaPrivateState, + EcdsaWitnesses, +} from '../fixtures/sample-contracts/witnesses/EcdsaWitnesses'; + +/** Runtime shape the generated circuits accept for an ECDSA signature. */ +export type Secp256k1EcdsaSignature = { r: bigint; s: bigint }; +export type { Secp256k1Point }; + +/** + * Base simulator + */ +const EcdsaSimulatorBase = createSimulator< + EcdsaPrivateState, + ReturnType, + ReturnType, + EcdsaContract +>({ + contractFactory: (witnesses) => + new EcdsaContract(witnesses), + defaultPrivateState: () => EcdsaPrivateState, + contractArgs: () => [], + ledgerExtractor: (state) => ledger(state), + witnessesFactory: () => EcdsaWitnesses(), +}); + +/** + * Ecdsa Simulator + */ +export class EcdsaSimulator extends EcdsaSimulatorBase { + static async create( + options: SimulatorOptions< + EcdsaPrivateState, + ReturnType + > = {}, + ): Promise { + // biome-ignore lint/complexity/noThisInStatic: super.create must keep the subclass `this` + return super.create([], options) as Promise; + } + + /** Pure: verify an Ethereum-style ECDSA signature (no state change). */ + public verifyEthereum( + msg: Uint8Array, + sig: Secp256k1EcdsaSignature, + pk: Secp256k1Point, + ): Promise { + return this.circuits.pure.verifyEthereum(msg, sig, pk); + } + + /** Impure: verify and record the outcome on-ledger. */ + public verifyAndStore( + msg: Uint8Array, + sig: Secp256k1EcdsaSignature, + pk: Secp256k1Point, + ): Promise { + return this.circuits.impure.verifyAndStore(msg, sig, pk); + } +} diff --git a/packages/simulator/test/integration/SampleZOwnable.test.ts b/packages/simulator/test/integration/SampleZOwnable.test.ts index e146718..e8fe7f6 100644 --- a/packages/simulator/test/integration/SampleZOwnable.test.ts +++ b/packages/simulator/test/integration/SampleZOwnable.test.ts @@ -1,10 +1,27 @@ import { CompactTypeBytes, CompactTypeVector, - convertFieldToBytes, persistentHash, } from '@midnight-ntwrk/compact-runtime'; import { beforeEach, describe, expect, it } from 'vitest'; + +// Serialize a field/counter value to a fixed-length byte array. Replaces the +// runtime's `convertFieldToBytes(length, value, '')`, removed in compact-runtime +// 0.18. Little-endian, matching the contract's Uint→Bytes<32> encoding. +const convertFieldToBytes = ( + length: number, + value: bigint, + _pad: string, +): Uint8Array => { + const out = new Uint8Array(length); + let v = value; + for (let i = 0; i < length; i++) { + out[i] = Number(v & 0xffn); + v >>= 8n; + } + return out; +}; + import type { ZswapCoinPublicKey } from '../fixtures/artifacts/SampleZOwnable/contract/index.js'; import { SampleZOwnablePrivateState } from '../fixtures/sample-contracts/witnesses/SampleZOwnableWitnesses.js'; import * as utils from '../fixtures/utils/address.js'; diff --git a/packages/simulator/test/setup.ts b/packages/simulator/test/setup.ts index a59b0cf..a912ccd 100644 --- a/packages/simulator/test/setup.ts +++ b/packages/simulator/test/setup.ts @@ -3,13 +3,13 @@ * Runs once before all tests via Vitest's globalSetup. */ -import { exec, type SpawnSyncReturns } from 'node:child_process'; -import { existsSync, mkdirSync, statSync } from 'node:fs'; +import { execFile } from 'node:child_process'; +import { existsSync, mkdirSync, readFileSync, statSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; import { promisify } from 'node:util'; -const execAsync = promisify(exec); +const execFileAsync = promisify(execFile); const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); @@ -21,29 +21,9 @@ const CONTRACT_FILES = [ 'Simple.compact', 'Witness.compact', 'SampleZOwnable.compact', + 'Ecdsa.compact', ]; -function isSpawnSyncRet( - err: unknown, -): err is SpawnSyncReturns { - if (typeof err !== 'object' || err === null) { - return false; - } - - const typedErr = err as Partial> & - Record; - - const okErr = typedErr.error instanceof Error; - const okStdout = - typeof typedErr.stdout === 'string' || Buffer.isBuffer(typedErr.stdout); - const okStderr = - typeof typedErr.stderr === 'string' || Buffer.isBuffer(typedErr.stderr); - const okStatus = - typeof typedErr.status === 'number' || typedErr.status === null; - - return okErr && okStdout && okStderr && okStatus; -} - async function compileContract(contractFile: string): Promise { const inputPath = join(SAMPLE_CONTRACTS_DIR, contractFile); const contractName = contractFile.replace('.compact', ''); @@ -68,20 +48,33 @@ async function compileContract(contractFile: string): Promise { mkdirSync(outputDir, { recursive: true }); mkdirSync(join(outputDir, 'keys'), { recursive: true }); - const command = `compact compile --skip-zk "${inputPath}" "${outputDir}"`; + // Pin the compiler to the ECDSA/0.18-runtime toolchain. The default toolchain + // (compactc 0.31.x) emits code expecting compact-runtime 0.16.0, which the + // 0.18.0-rc.1 runtime this package now depends on rejects at load time. + // Override via COMPACTC_VERSION if a newer pinned toolchain is installed. + const compilerVersion = process.env.COMPACTC_VERSION ?? '0.33.0-rc.2'; + // secp256k1 primitives (e.g. secp256k1EcdsaVerify) exist only in the ZKIR v3 + // backend, so contracts that use them must opt in; others stay on the default. + const usesSecp256k1 = /secp256k1/i.test(readFileSync(inputPath, 'utf8')); + + // execFile (no shell) with an argument array: the compiler version and paths + // are passed as discrete args, never interpolated into a command string, so + // none of them can inject shell. + const args = [ + 'compile', + `+${compilerVersion}`, + ...(usesSecp256k1 ? ['--feature-zkir-v3'] : []), + '--skip-zk', + inputPath, + outputDir, + ]; try { - await execAsync(command); + await execFileAsync('compact', args); } catch (err: unknown) { - if (!isSpawnSyncRet(err)) { - throw err; - } - - if (err.status === 127) { - throw new Error( - '`compact` not found (exit code 127). Is it installed and on PATH?', - ); + // Without a shell, a missing `compact` binary surfaces as ENOENT. + if ((err as { code?: unknown } | null)?.code === 'ENOENT') { + throw new Error('`compact` not found. Is it installed and on PATH?'); } - throw err; } diff --git a/packages/simulator/test/unit/core/StateManager.test.ts b/packages/simulator/test/unit/core/StateManager.test.ts index a765cd6..9333349 100644 --- a/packages/simulator/test/unit/core/StateManager.test.ts +++ b/packages/simulator/test/unit/core/StateManager.test.ts @@ -33,7 +33,7 @@ describe('CircuitContextManager', () => { * Parametrize me! */ describe('constructor', () => { - beforeEach(() => { + beforeEach(async () => { mockContract = new MockSimple(SimpleWitnesses()); initialPrivateState = {}; @@ -44,11 +44,14 @@ describe('CircuitContextManager', () => { dummyContractAddress(), ); + // compact-runtime 0.18: the constructor no longer builds the context; + // init() runs the contract constructor and populates it. + await circuitCtxManager.init(); ctx = circuitCtxManager.getContext(); }); it('should set private state', () => { - expect(ctx.currentPrivateState).toEqual(initialPrivateState); + expect(ctx.callContext.currentPrivateState).toEqual(initialPrivateState); }); it('should set zswap local state', () => { @@ -60,26 +63,36 @@ describe('CircuitContextManager', () => { inputs: [], outputs: [], }; - expect(ctx.currentZswapLocalState).toEqual(expectedZswapState); + expect(ctx.callContext.currentZswapLocalState).toEqual( + expectedZswapState, + ); }); it('should set original state', () => { - expect(ctx.currentQueryContext).toBeInstanceOf(QueryContext); - expect(ctx.currentQueryContext).toHaveProperty('__wbg_ptr'); - expect((ctx.currentQueryContext as any).__wbg_ptr).toBeTypeOf('number'); + expect(ctx.callContext.currentQueryContext).toBeInstanceOf(QueryContext); + expect(ctx.callContext.currentQueryContext).toHaveProperty('__wbg_ptr'); + expect((ctx.callContext.currentQueryContext as any).__wbg_ptr).toBeTypeOf( + 'number', + ); }); it('should set tx ctx', () => { // Need to go deeper - expect(ctx.currentQueryContext).toBeInstanceOf(QueryContext); - expect(ctx.currentQueryContext.address).toEqual(dummyContractAddress()); - expect(ctx.currentQueryContext.state).toBeInstanceOf(ChargedState); - expect(ctx.currentQueryContext.state).toHaveProperty('__wbg_ptr'); + expect(ctx.callContext.currentQueryContext).toBeInstanceOf(QueryContext); + expect(ctx.callContext.currentQueryContext.address).toEqual( + dummyContractAddress(), + ); + expect(ctx.callContext.currentQueryContext.state).toBeInstanceOf( + ChargedState, + ); + expect(ctx.callContext.currentQueryContext.state).toHaveProperty( + '__wbg_ptr', + ); }); }); describe('setContext', () => { - beforeEach(() => { + beforeEach(async () => { mockContract = new MockSimple(SimpleWitnesses()); initialPrivateState = {}; @@ -90,6 +103,9 @@ describe('CircuitContextManager', () => { dummyContractAddress(), ); + // compact-runtime 0.18: the constructor no longer builds the context; + // init() runs the contract constructor and populates it. + await circuitCtxManager.init(); ctx = circuitCtxManager.getContext(); }); @@ -120,7 +136,7 @@ describe('CircuitContextManager', () => { // Query ctx const modifiedTxCtx: QueryContext = { - ...ctx.currentQueryContext, + ...ctx.callContext.currentQueryContext, address: encodeToAddress('otherAddress'), } as unknown as QueryContext; diff --git a/yarn.lock b/yarn.lock index e93a9fe..7178780 100644 --- a/yarn.lock +++ b/yarn.lock @@ -105,16 +105,16 @@ __metadata: languageName: node linkType: hard -"@effect/platform@npm:^0.95.0": - version: 0.95.0 - resolution: "@effect/platform@npm:0.95.0" +"@effect/platform@npm:^0.96.1": + version: 0.96.3 + resolution: "@effect/platform@npm:0.96.3" dependencies: find-my-way-ts: "npm:^0.1.6" - msgpackr: "npm:^1.11.4" + msgpackr: "npm:^1.11.10" multipasta: "npm:^0.2.7" peerDependencies: - effect: ^3.20.0 - checksum: 10/ae3f3bd441f77bb0f3bb71f954d3a06be2565e4d924eba8c7d5c898da32d893f42c4af0e5c6fee5a1ba087ab7d2d1dae8734a4b1e830baeb654fcccd63c996bb + effect: ^3.21.5 + checksum: 10/55cd490e29b98fe407e43bb57fa5ecb1c13b91a3056494a6d1d786378865d915aa83dcb95c8272c2039784c2424a21c00b0bd3fcc296bc7b05424e82a179130f languageName: node linkType: hard @@ -179,119 +179,131 @@ __metadata: languageName: node linkType: hard -"@midnight-ntwrk/compact-js@npm:2.5.1": - version: 2.5.1 - resolution: "@midnight-ntwrk/compact-js@npm:2.5.1" +"@midnight-ntwrk/compact-js@npm:2.5.5-rc.7": + version: 2.5.5-rc.7 + resolution: "@midnight-ntwrk/compact-js@npm:2.5.5-rc.7" dependencies: - "@effect/platform": "npm:^0.95.0" - "@midnight-ntwrk/compact-runtime": "npm:0.16.0" - "@midnight-ntwrk/ledger-v8": "npm:^8.0.3" - "@midnight-ntwrk/platform-js": "npm:^2.2.4" - effect: "npm:^3.20.0" + "@effect/platform": "npm:^0.96.1" + "@midnight-ntwrk/compact-runtime": "npm:0.18.0-rc.1" + "@midnight-ntwrk/platform-js": "npm:^3.0.0" + "@midnightntwrk/ledger-v9": "npm:^1.0.0-rc.3" + "@noble/hashes": "npm:^2.2.0" + effect: "npm:^3.21.4" tslib: "npm:^2.8.1" - checksum: 10/ee041b88d8fd43dc63f8cbb6b02f2eb0d6445921633b032e1dd3e909c75be8ca8f311cee70d16a9d06795bbb94172d2a6797799ee3870f29a8aa42e7e3e153b6 + checksum: 10/4546878614e72da0133d923ea2a54017372d4d04c6290dfca293b525b2c53a95c0f44dd4262c0d6104391870a8efe4677118552f42d54a1da04130f34ec71012 languageName: node linkType: hard -"@midnight-ntwrk/compact-runtime@npm:0.16.0": - version: 0.16.0 - resolution: "@midnight-ntwrk/compact-runtime@npm:0.16.0" +"@midnight-ntwrk/compact-runtime@npm:0.18.0-rc.1": + version: 0.18.0-rc.1 + resolution: "@midnight-ntwrk/compact-runtime@npm:0.18.0-rc.1" dependencies: - "@midnight-ntwrk/onchain-runtime-v3": "npm:^3.0.0" + "@midnightntwrk/onchain-runtime-v4": "npm:^4.0.0-rc.3" + "@noble/curves": "npm:^2.2.0" + "@noble/hashes": "npm:^2.0.1" "@types/object-inspect": "npm:^1.8.1" object-inspect: "npm:^1.12.3" - checksum: 10/ef0c68d53bba6a04f336094c82c26b781082d7ce4ee09f0539009fb108776b36ea24b9a774292d9bbf9722b8a78d47254b5f80a613d4010a7f7d108514243023 + checksum: 10/37bc76bd3e3bb81ef10fd7d0f69e7fe0001496401bf2a7a3c731285e76926763aeed24dff1af5b686ee3a8a02a93553be56293c173f0346f84b9987b6e6767bf languageName: node linkType: hard -"@midnight-ntwrk/ledger-v8@npm:8.1.0, @midnight-ntwrk/ledger-v8@npm:^8.0.3, @midnight-ntwrk/ledger-v8@npm:^8.1.0": - version: 8.1.0 - resolution: "@midnight-ntwrk/ledger-v8@npm:8.1.0" - checksum: 10/10d56076b0333a502f157c816f8cfebefc8d50221cb20c6db15abcbf2d0092bdaf7e9bc1bd19a6d9f51455547c713c916cb16d4a7d18e83cba0e172ad6e2a507 - languageName: node - linkType: hard - -"@midnight-ntwrk/midnight-js-contracts@npm:^4.1.0": - version: 4.1.1 - resolution: "@midnight-ntwrk/midnight-js-contracts@npm:4.1.1" +"@midnight-ntwrk/midnight-js-contracts@npm:5.0.0-beta.6": + version: 5.0.0-beta.6 + resolution: "@midnight-ntwrk/midnight-js-contracts@npm:5.0.0-beta.6" dependencies: - "@midnight-ntwrk/midnight-js-network-id": "npm:4.1.1" - "@midnight-ntwrk/midnight-js-protocol": "npm:4.1.1" - "@midnight-ntwrk/midnight-js-types": "npm:4.1.1" - "@midnight-ntwrk/midnight-js-utils": "npm:4.1.1" - checksum: 10/93791613419dd914cbd4db6c0bc75cebb093962e4162a391d298e2ae705e53c2e87a40fa923fd9a9a6a31cdb91bede0836673beea14d4a594e15da250a1b4feb + "@midnight-ntwrk/midnight-js-network-id": "npm:5.0.0-beta.6" + "@midnight-ntwrk/midnight-js-protocol": "npm:5.0.0-beta.6" + "@midnight-ntwrk/midnight-js-types": "npm:5.0.0-beta.6" + "@midnight-ntwrk/midnight-js-utils": "npm:5.0.0-beta.6" + effect: "npm:^3.20.0" + checksum: 10/1725f56a831a768a867f5275811761564aed035ef58db5417b4f920e09de7475aeb002f8383ba74629fa8fc6444d48b9707df02a05add18347ab7909bd0462b1 languageName: node linkType: hard -"@midnight-ntwrk/midnight-js-network-id@npm:4.1.1": - version: 4.1.1 - resolution: "@midnight-ntwrk/midnight-js-network-id@npm:4.1.1" - checksum: 10/ac2f06da0d3bdec6ee83fe84312d8d012b398dad8e23896727c8de10df51eefeeff8eff2de29079c534e090f7cc8520f6e0763a324b560dfe1a0f1d55f2ca2a3 +"@midnight-ntwrk/midnight-js-network-id@npm:5.0.0-beta.6": + version: 5.0.0-beta.6 + resolution: "@midnight-ntwrk/midnight-js-network-id@npm:5.0.0-beta.6" + checksum: 10/431fcb220957d931def94c59714b89b3c05f2542723eb9f82fe0eb4726eb9866c778d61e84c1c8187d5ecbe41faba0b53fd5ff9bbbdefc1f28822d22dc3be4ec languageName: node linkType: hard -"@midnight-ntwrk/midnight-js-protocol@npm:4.1.1": - version: 4.1.1 - resolution: "@midnight-ntwrk/midnight-js-protocol@npm:4.1.1" +"@midnight-ntwrk/midnight-js-protocol@npm:5.0.0-beta.6": + version: 5.0.0-beta.6 + resolution: "@midnight-ntwrk/midnight-js-protocol@npm:5.0.0-beta.6" dependencies: - "@midnight-ntwrk/compact-js": "npm:2.5.1" - "@midnight-ntwrk/compact-runtime": "npm:0.16.0" - "@midnight-ntwrk/ledger-v8": "npm:8.1.0" - "@midnight-ntwrk/onchain-runtime-v3": "npm:3.0.0" - "@midnight-ntwrk/platform-js": "npm:2.2.4" - checksum: 10/bfd6195e90b8c0fbc178b32ff9f8223f377d48a55a4a6fdedba424ede77c2234eac75555263b73a61f3ca14d2cc27ed935b3efae15daa6a475a00db4a696e7a1 + "@midnight-ntwrk/compact-js": "npm:2.5.5-rc.7" + "@midnight-ntwrk/compact-runtime": "npm:0.18.0-rc.1" + "@midnight-ntwrk/platform-js": "npm:3.0.0" + "@midnightntwrk/ledger-v9": "npm:1.0.0-rc.3" + "@midnightntwrk/onchain-runtime-v4": "npm:4.0.0-rc.3" + checksum: 10/f9c2fde499e5a2e52e84374a934c94c3c94a7fcd4e03ac9931f4093ce6b270d39a4187b838b2d9a6497624f9e2c44591b0f5f542c7a1e7f70177af9eabcf95a8 languageName: node linkType: hard -"@midnight-ntwrk/midnight-js-types@npm:4.1.1, @midnight-ntwrk/midnight-js-types@npm:^4.1.0": - version: 4.1.1 - resolution: "@midnight-ntwrk/midnight-js-types@npm:4.1.1" +"@midnight-ntwrk/midnight-js-types@npm:5.0.0-beta.6": + version: 5.0.0-beta.6 + resolution: "@midnight-ntwrk/midnight-js-types@npm:5.0.0-beta.6" dependencies: - "@midnight-ntwrk/midnight-js-protocol": "npm:4.1.1" + "@midnight-ntwrk/midnight-js-protocol": "npm:5.0.0-beta.6" effect: "npm:^3.20.0" pino: "npm:^10.3.1" rxjs: "npm:^7.8.2" - checksum: 10/a11a994f0838968954f01146c9f5f65f29c8e30fe305401a3f0cef15b6a75802078d2c8c4abe6ef743585a12a05b4d9d30dbe1bb7177699cd2623302fb2b619e + checksum: 10/f28d6c18e2004c85e36e1240caba49cef2f636c2f0c7afbbd52e40804c9cbb01014d13bd0c239338f569367ca61e61d4ac1892475c757e9f8a0c3237aa2e4bad languageName: node linkType: hard -"@midnight-ntwrk/midnight-js-utils@npm:4.1.1": - version: 4.1.1 - resolution: "@midnight-ntwrk/midnight-js-utils@npm:4.1.1" +"@midnight-ntwrk/midnight-js-utils@npm:5.0.0-beta.6": + version: 5.0.0-beta.6 + resolution: "@midnight-ntwrk/midnight-js-utils@npm:5.0.0-beta.6" dependencies: - "@midnight-ntwrk/midnight-js-network-id": "npm:4.1.1" - "@midnight-ntwrk/midnight-js-protocol": "npm:4.1.1" - "@midnight-ntwrk/wallet-sdk-address-format": "npm:^3.1.0" - checksum: 10/73f3ab682bd0ea37b988bc34e8036bc03d748b1df534ea57764c7fc656a235ea3287ca55481d57be956455ff4a8334e805c99d87d95c998f1879b5b7743dc18c + "@midnight-ntwrk/midnight-js-network-id": "npm:5.0.0-beta.6" + "@midnight-ntwrk/midnight-js-protocol": "npm:5.0.0-beta.6" + "@midnightntwrk/wallet-sdk-address-format": "npm:4.0.0-beta.2" + "@noble/hashes": "npm:^2.2.0" + checksum: 10/1fe56fd750f6f6b24639f9e6e98f036296f9884c24b424c947d33aebdb31c1ee5ba9004ae1f51bb30326e73ce98522aa36f8d34b665272ac7d1588321e6e00bc languageName: node linkType: hard -"@midnight-ntwrk/onchain-runtime-v3@npm:3.0.0, @midnight-ntwrk/onchain-runtime-v3@npm:^3.0.0": +"@midnight-ntwrk/platform-js@npm:3.0.0, @midnight-ntwrk/platform-js@npm:^3.0.0": version: 3.0.0 - resolution: "@midnight-ntwrk/onchain-runtime-v3@npm:3.0.0" - checksum: 10/873aeb9e631c3678373c62b5aef847de454de94427028fb3d3f28bfdc8b2c02a3c770bd79d9bfef183eb9db6fb8c23e6826636f2e512ffd6eacbcf7cc0651c5d + resolution: "@midnight-ntwrk/platform-js@npm:3.0.0" + dependencies: + "@effect/platform": "npm:^0.96.1" + effect: "npm:^3.21.0" + tslib: "npm:^2.8.1" + checksum: 10/1ca2b3bab95c909837de33d9f871c502e38091a40d14bb240a43e304abaae009172a414e4a9cdf49b5655e7c42b20fa62b17a6d8489e5942f4d8a19ba04de940 languageName: node linkType: hard -"@midnight-ntwrk/platform-js@npm:2.2.4, @midnight-ntwrk/platform-js@npm:^2.2.4": - version: 2.2.4 - resolution: "@midnight-ntwrk/platform-js@npm:2.2.4" - dependencies: - "@effect/platform": "npm:^0.95.0" - effect: "npm:^3.20.0" - tslib: "npm:^2.8.1" - checksum: 10/1650bb7e54a64740aaaf27f7e84b7bffdb08611c994bbf54208db43a0a11d10ea8994f05d82e848d60d6fcee8a9b3a5db770d306262b99547e71185d52614825 +"@midnightntwrk/ledger-v9@npm:1.0.0-rc.3": + version: 1.0.0-rc.3 + resolution: "@midnightntwrk/ledger-v9@npm:1.0.0-rc.3" + checksum: 10/5d2c2ff808b6dcc8f8ba2b75f81467c9bc4904e625e246bea1f8c77be7eb6d06cac28b189d1f6b708a85559ddf133efe93147da12169db48f927c72f414d0fa7 languageName: node linkType: hard -"@midnight-ntwrk/wallet-sdk-address-format@npm:^3.1.0": - version: 3.1.2 - resolution: "@midnight-ntwrk/wallet-sdk-address-format@npm:3.1.2" +"@midnightntwrk/ledger-v9@npm:^1.0.0-rc.3": + version: 1.0.0-rc.4 + resolution: "@midnightntwrk/ledger-v9@npm:1.0.0-rc.4" + checksum: 10/b30b7d0e72003a97e2fe119e9d1cdd5d47ef5ad8bc82d8143486031b42f407b2fe80b97460d4d4cb44d96630d629df82bbac88cbe012f56ba13189c9e9805c58 + languageName: node + linkType: hard + +"@midnightntwrk/onchain-runtime-v4@npm:4.0.0-rc.3, @midnightntwrk/onchain-runtime-v4@npm:^4.0.0-rc.3": + version: 4.0.0-rc.3 + resolution: "@midnightntwrk/onchain-runtime-v4@npm:4.0.0-rc.3" + checksum: 10/394a4ff27b575b0e30bcb5ca05c2f89dc3bc7915103aa592c1d89bb32ff8589ac732d4d0bdafb4a99a9757e1a41ce21955f68148f783edb83b21988b24154078 + languageName: node + linkType: hard + +"@midnightntwrk/wallet-sdk-address-format@npm:4.0.0-beta.2": + version: 4.0.0-beta.2 + resolution: "@midnightntwrk/wallet-sdk-address-format@npm:4.0.0-beta.2" dependencies: - "@midnight-ntwrk/ledger-v8": "npm:^8.1.0" + "@midnightntwrk/ledger-v9": "npm:1.0.0-rc.3" "@scure/base": "npm:^2.0.0" "@subsquid/scale-codec": "npm:^4.0.1" - checksum: 10/f3e2374c1dd8e31310aa464fa2afecca3cca92b923a999bfcba2922225b907e5387b94a70e6a8c06e8fb9d51fd9140a08c827c13f8a9191fd18d597cb5ab7b0c + checksum: 10/7313ae764b1051a3f75f7781db67c27cad8a52b8c9a512f0508f17dbb39641692f737237e21c902c48fa04ebe552eb704a15ee9a7b6b1d3c971c6ad6a4b08235 languageName: node linkType: hard @@ -349,6 +361,29 @@ __metadata: languageName: node linkType: hard +"@noble/curves@npm:^2.2.0": + version: 2.2.0 + resolution: "@noble/curves@npm:2.2.0" + dependencies: + "@noble/hashes": "npm:2.2.0" + checksum: 10/f9545e55bb8b6cdf2618c936870b9229339c90b25f129fc368b4b534e723f274e5c0daf8abca2f891bcf0a59c3b49c5ac5205899aec07f5251f545ec616e3aa9 + languageName: node + linkType: hard + +"@noble/hashes@npm:2.2.0, @noble/hashes@npm:^2.0.1": + version: 2.2.0 + resolution: "@noble/hashes@npm:2.2.0" + checksum: 10/b1b78bedc2a01394be047429f3d888905015fe8a09f1b7e43e0b5736b54133df62f73dcc73ede43af38e96e86156afb45b86973fdeaa95d9f0880333c3fc0907 + languageName: node + linkType: hard + +"@noble/hashes@npm:^2.2.0": + version: 2.3.0 + resolution: "@noble/hashes@npm:2.3.0" + checksum: 10/2a980fa3257269d0f2f0c65ad30033a395121a523cb207bd5e481054cabf21af3cce87a8d657a3d7409924ec28f7fcaaf3fb01150813ac3c9e16964a95ae0ab7 + languageName: node + linkType: hard + "@openzeppelin/compact-builder@workspace:^, @openzeppelin/compact-builder@workspace:packages/builder": version: 0.0.0-use.local resolution: "@openzeppelin/compact-builder@workspace:packages/builder" @@ -386,18 +421,19 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin/compact-simulator@workspace:packages/simulator" dependencies: - "@midnight-ntwrk/compact-runtime": "npm:0.16.0" - "@midnight-ntwrk/ledger-v8": "npm:8.1.0" - "@midnight-ntwrk/midnight-js-contracts": "npm:^4.1.0" - "@midnight-ntwrk/midnight-js-types": "npm:^4.1.0" + "@midnight-ntwrk/compact-runtime": "npm:0.18.0-rc.1" + "@midnight-ntwrk/midnight-js-contracts": "npm:5.0.0-beta.6" + "@midnight-ntwrk/midnight-js-types": "npm:5.0.0-beta.6" + "@noble/curves": "npm:^2.2.0" + "@noble/hashes": "npm:^2.2.0" "@tsconfig/node24": "npm:^24.0.3" "@types/node": "npm:26.1.2" fast-check: "npm:^4.5.2" typescript: "npm:^6.0.3" vitest: "npm:^4.1.9" peerDependencies: - "@midnight-ntwrk/midnight-js-contracts": ^4.1.0 - "@midnight-ntwrk/midnight-js-types": ^4.1.0 + "@midnight-ntwrk/midnight-js-contracts": ^5.0.0-beta.6 + "@midnight-ntwrk/midnight-js-types": ^5.0.0-beta.6 peerDependenciesMeta: "@midnight-ntwrk/midnight-js-contracts": optional: true @@ -932,6 +968,16 @@ __metadata: languageName: node linkType: hard +"effect@npm:^3.21.0, effect@npm:^3.21.4": + version: 3.22.1 + resolution: "effect@npm:3.22.1" + dependencies: + "@standard-schema/spec": "npm:^1.0.0" + fast-check: "npm:^3.23.1" + checksum: 10/00575333225e2dabf0a873e993357ad0e923476db7a44f24b8a65f766683ac9cbc98b2b30a299a65b581694709d35df85f46fb6fa6f5c922c134aa5e2dea6ce5 + languageName: node + linkType: hard + "env-paths@npm:^2.2.0": version: 2.2.1 resolution: "env-paths@npm:2.2.1" @@ -1260,7 +1306,7 @@ __metadata: languageName: node linkType: hard -"msgpackr@npm:^1.11.4": +"msgpackr@npm:^1.11.10": version: 1.12.1 resolution: "msgpackr@npm:1.12.1" dependencies: