Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d918374
Add multisig signer (#424)
andrew-fleming May 5, 2026
8a43259
Multisig contracts (#378)
pepebndc May 7, 2026
7379689
Bump github/codeql-action from 4.35.1 to 4.35.3 (#491)
dependabot[bot] May 6, 2026
a54e3d6
Bump step-security/harden-runner from 2.19.0 to 2.19.1 (#490)
dependabot[bot] May 6, 2026
9a1f8f1
Bump ora from 9.3.0 to 9.4.0 (#463)
dependabot[bot] May 6, 2026
f2621ca
feat: tests for cma
0xisk Apr 22, 2026
90a8e0d
refactor: adding integration tests for the cma tests
0xisk Apr 23, 2026
be58074
feat: upgradability tests wip
0xisk Apr 30, 2026
7756efd
feat: wip cma integration tests
0xisk May 5, 2026
5b1a15d
fix: revert moving the mocks
0xisk May 5, 2026
c2e54d6
feat: wip cma ownable integration tests
0xisk May 6, 2026
8597a22
feat: wip cma ownable integration tests
0xisk May 6, 2026
31eb0c4
feat: wip cma ownable integration tests
0xisk May 6, 2026
f4affb7
refactor: apply fix for some tests
0xisk May 6, 2026
16b3549
test: finsh testing multiple updates
0xisk May 6, 2026
918dddf
test: more edge cases
0xisk May 7, 2026
82e880e
refactor: enhance the strcuture and folder namings
0xisk May 7, 2026
d3d5a87
refactor: update the docs
0xisk May 7, 2026
9f5b51a
chore: sync yarn.lock after removing fast-check from contracts
0xisk May 7, 2026
633ba0c
refactor: only use the SDK
0xisk May 8, 2026
5d36d68
feat: implement schnorr signature scheme
0xisk May 8, 2026
ccded87
feat: implement jubjub module
0xisk May 8, 2026
dc1ad75
feat: implement schnorr multisig contract
0xisk May 8, 2026
9a79fee
feat: implement schnorr frost multisig contract
0xisk May 10, 2026
d8c8c48
feat: implement schnorr ring multisig contract
0xisk May 11, 2026
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
2 changes: 1 addition & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:

steps:
- name: Harden Runner
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: audit

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:

steps:
- name: Harden Runner
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: audit

Expand All @@ -39,13 +39,13 @@ jobs:
skip-compact: "true"

- name: Initialize CodeQL
uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
uses: github/codeql-action/init@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
with:
languages: ${{ matrix.language }}
# We can add custom queries later when needed
# queries: security-extended

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
uses: github/codeql-action/analyze@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
with:
category: "/language:${{ matrix.language }}"
2 changes: 1 addition & 1 deletion .github/workflows/prepare-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:

steps:
- name: Harden Runner
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: audit

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:

steps:
- name: Harden Runner
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: audit

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
# actions: read
steps:
- name: Harden Runner
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: audit

Expand All @@ -56,6 +56,6 @@ jobs:
retention-days: 5

- name: Upload SARIF to GitHub Code Scanning
uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
uses: github/codeql-action/upload-sarif@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
with:
sarif_file: results.sarif
70 changes: 70 additions & 0 deletions .github/workflows/test-integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Compact Contracts Integration Suite

on:
pull_request:
types: [labeled, synchronize]
schedule:
- cron: "0 6 * * *" # nightly at 06:00 UTC
workflow_dispatch:

jobs:
run-integration:
# Run on scheduled/manual triggers, or on PRs carrying the `integration` label.
if: >
github.event_name == 'schedule' ||
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'pull_request' &&
contains(github.event.pull_request.labels.*.name, 'integration'))
name: Run Integration Suite
runs-on: ubuntu-24.04
permissions:
contents: read
timeout-minutes: 30

steps:
- name: Harden Runner
uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1
with:
egress-policy: audit

- name: Check out code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 2

- name: Setup Environment
uses: ./.github/actions/setup

- name: Compile contracts
run: turbo compact --filter=@openzeppelin/compact-contracts

- name: Start local Midnight stack
run: make env-up

- name: Wait for local stack health
run: |
for i in $(seq 1 60); do
if docker compose -f local-env.yml ps --format json | \
grep -q '"Health":"healthy"'; then
echo "Local stack healthy"; exit 0
fi
sleep 5
done
echo "Local stack did not become healthy in time"
docker compose -f local-env.yml ps
exit 1

- name: Run integration tests
run: yarn test:integration

- name: Upload container logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: midnight-stack-logs
path: logs/
if-no-files-found: warn

- name: Tear down local stack
if: always()
run: make env-down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:

steps:
- name: Harden Runner
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: audit

Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,5 @@ coverage
*~

*temp

.claude/
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
diff --git a/dist/index.d.ts b/dist/index.d.ts
index 1f59ed0c5820b3d71f1ea3ab640417ae56c19dd4..88a91bb053007b2c46e6862fea1b819442735a73 100644
--- a/dist/index.d.ts
+++ b/dist/index.d.ts
@@ -1,3 +1,5 @@
export * from './UnshieldedWallet.js';
export { type UnshieldedTransactionHistoryEntry, UnshieldedSectionSchema } from './v1/TransactionHistory.js';
export * from './KeyStore.js';
+// TODO(remove-once-published): see dist/index.js for context.
+export { InMemoryTransactionHistoryStorage } from '@midnight-ntwrk/wallet-sdk-abstractions';
diff --git a/dist/index.js b/dist/index.js
index 308ce3f288804e7232ba80213c8978df0e55a3f5..738ec7c66b83e1d2460c4b2ec831b75928cee619 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -13,3 +13,11 @@
export * from './UnshieldedWallet.js';
export { UnshieldedSectionSchema } from './v1/TransactionHistory.js';
export * from './KeyStore.js';
+// TODO(remove-once-published): testkit-js@4.0.2 imports
+// `InMemoryTransactionHistoryStorage` from this package's root, but the 3.0.0
+// release moved it to `@midnight-ntwrk/wallet-sdk-abstractions` without
+// keeping a re-export. The yarn patch that wraps this file restores the
+// re-export so the integration harness loads. Drop the patch once the SDK
+// publishes a version that re-exports it natively (or testkit-js is upgraded
+// to import from `@midnight-ntwrk/wallet-sdk-abstractions`).
+export { InMemoryTransactionHistoryStorage } from '@midnight-ntwrk/wallet-sdk-abstractions';
13 changes: 13 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# TODO(remove-once-published): `@midnight-ntwrk/wallet-sdk-unshielded-wallet@3.0.0`
# is patched (see package.json#resolutions and .yarn/patches/) to re-export
# `InMemoryTransactionHistoryStorage` from `@midnight-ntwrk/wallet-sdk-abstractions`.
# testkit-js@4.0.2's compiled output imports that symbol from this package's root,
# but the 3.0.0 release dropped the re-export. The patch is a single-line
# `export { InMemoryTransactionHistoryStorage } from '@midnight-ntwrk/wallet-sdk-abstractions';`
# in dist/index.js (and the matching .d.ts) — no behaviour change, just surface.
# Remove the patch entry from package.json#resolutions and delete
# .yarn/patches/@midnight-ntwrk-wallet-sdk-unshielded-wallet-* once either
# (a) testkit-js is upgraded to import from `@midnight-ntwrk/wallet-sdk-abstractions`,
# or (b) `@midnight-ntwrk/wallet-sdk-unshielded-wallet@>=3.x` re-exports the
# symbol from root. See contracts/src/crypto/CRYPTO_NOTES.md for context.

compressionLevel: mixed

enableGlobalCache: false
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Added

- Signer module in multisig directory (#424)

### Changes

- Add defensive Buffer copy to ZOwnablePKWitnesses (#397)
Expand Down
31 changes: 31 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
COMPOSE_FILE := local-env.yml
LOGS_DIR := logs
SERVICES := proof-server indexer node

.PHONY: env-up env-down env-logs env-logs-clean env-status

## Start local environment and stream logs to logs/
env-up: env-down
docker compose -f $(COMPOSE_FILE) up -d
@mkdir -p $(LOGS_DIR)
@for svc in $(SERVICES); do \
docker compose -f $(COMPOSE_FILE) logs -f --no-log-prefix $$svc > $(LOGS_DIR)/$$svc.log 2>&1 & \
done
@echo "Logs streaming to $(LOGS_DIR)/"

## Stop local environment
env-down:
@-pkill -f "docker compose -f $(COMPOSE_FILE) logs" 2>/dev/null || true
docker compose -f $(COMPOSE_FILE) down

## Tail all logs
env-logs:
tail -f $(LOGS_DIR)/*.log

## Clear log files
env-logs-clean:
rm -rf $(LOGS_DIR)/*.log

## Show container status
env-status:
docker compose -f $(COMPOSE_FILE) ps
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,34 @@ turbo compact

### Run tests

#### Unit tests

In-memory simulator, no network. Completes in seconds:

```bash
turbo test
```

#### Integration tests

Drive the modules against a real local Midnight stack (proof-server + indexer + node). Contracts are deployed, transactions are proven and submitted, and assertions read live ledger state. Useful for exercising the contract-maintenance authority (CMA) upgrade pathway, multi-signer access control, and any behaviour the simulator can't model.

Bring up the local stack, then run the suite:

```bash
make env-up
yarn test:integration
make env-down # when finished
```

**Expect this to be slow.** Each `describe` typically deploys a fresh contract and the genesis-funded wallet syncs against the local indexer (~30s per fresh deploy) before transactions can be submitted. The full suite (15 spec files, ~50 tests) takes **~60–65 minutes** wall-clock end-to-end.

The dominant cost is per-describe wallet sync; iterating on a single spec is much faster than running everything. Filter to one file via vitest's `--config` invocation directly if you're in `contracts/`:

```bash
cd contracts && yarn test:integration:watch -- specs/cma/freeze.spec.ts
```

### Check/apply Biome formatter

```bash
Expand Down
40 changes: 39 additions & 1 deletion contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,20 @@
"compact": "compact-compiler",
"compact:access": "compact-compiler --dir access",
"compact:archive": "compact-compiler --dir archive",
"compact:multisig": "compact-compiler --dir multisig",
"compact:security": "compact-compiler --dir security",
"compact:token": "compact-compiler --dir token",
"compact:utils": "compact-compiler --dir utils",
"compact:mocks": "compact-compiler --src-root mocks",
"compact:mocks:access": "compact-compiler --src-root mocks --dir access",
"compact:mocks:security": "compact-compiler --src-root mocks --dir security",
"compact:mocks:token": "compact-compiler --src-root mocks --dir token",
"compact:mocks:utils": "compact-compiler --src-root mocks --dir utils",
"compact:integration-mocks": "compact-compiler --src-root test/integration/_mocks",
"build": "compact-builder",
"test": "compact-compiler --skip-zk && vitest run",
"test:integration": "COMPACT_TOOLCHAIN_VERSION=0.30.0 yarn compact && COMPACT_TOOLCHAIN_VERSION=0.30.0 yarn compact:integration-mocks && vitest run --config vitest.integration.config.ts",
"test:integration:watch": "vitest --config vitest.integration.config.ts",
"types": "tsc -p tsconfig.json --noEmit",
"clean": "git clean -fXd"
},
Expand All @@ -42,11 +51,40 @@
"@openzeppelin-compact/compact": "workspace:^"
},
"devDependencies": {
"@apollo/client": "^3.11.8",
"@midnight-ntwrk/compact-js": "2.5.0",
"@midnight-ntwrk/ledger-v8": "8.0.3",
"@midnight-ntwrk/midnight-js-contracts": "4.0.2",
"@midnight-ntwrk/midnight-js-http-client-proof-provider": "4.0.2",
"@midnight-ntwrk/midnight-js-indexer-public-data-provider": "4.0.2",
"@midnight-ntwrk/midnight-js-level-private-state-provider": "4.0.2",
"@midnight-ntwrk/midnight-js-network-id": "4.0.2",
"@midnight-ntwrk/midnight-js-node-zk-config-provider": "4.0.2",
"@midnight-ntwrk/midnight-js-types": "4.0.2",
"@midnight-ntwrk/midnight-js-utils": "4.0.2",
"@midnight-ntwrk/testkit-js": "4.0.2",
"@midnight-ntwrk/wallet-sdk": "1.0.0",
"@openzeppelin-compact/contracts-simulator": "workspace:^",
"@scure/bip39": "^1.2.1",
"@tsconfig/node24": "^24.0.4",
"@types/node": "24.10.0",
"axios": "^1.12.0",
"buffer": "^6.0.3",
"cross-fetch": "^4.0.0",
"effect": "^3.20.0",
"fetch-retry": "^6.0.0",
"graphql": "^16.8.1",
"graphql-ws": "^5.16.0",
"isomorphic-ws": "^5.0.0",
"level": "^8.0.1",
"pino": "^9.7.0",
"pino-pretty": "^13.0.0",
"rxjs": "^7.8.1",
"superjson": "^2.2.1",
"testcontainers": "^10.28.0",
"ts-node": "^10.9.2",
"typescript": "^5.9.3",
"vitest": "^4.1.2"
"vitest": "^4.1.2",
"ws": "^8.16.0"
}
}
Loading