Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Clairveil DApp

Korean version: README-kr.md

Clairveil DApp is a browser example for testing Clairveil privacy flows with Keplr and MetaMask.

The boundary is intentional:

  • DApp owns inputs, wallet UI, and result rendering.
  • ClairveilJS owns privacy logic: note creation, commitments, encrypted notes, note scan, note planning, prover payloads, disclosure encode/decode, and deposit/transfer/withdraw preparation.
  • Optional local server owns only static serving and local-test helpers such as faucet, local signers, and admin/auditor test routes.

For a public node deployment, the DApp needs the static assets, ClairveilJS, public RPC/REST endpoints, and a reviewed prover. Cosmos profiles use the Core v0.4.0 canonical DepositCircuit route at {proverUrl}/v1/prover/deposit by default, with an optional exact canonical endpoint or local/WASM provider override. EVM profiles keep their separately configured deposit-provider contract. A DApp backend is optional.

React sample screens

Both screens bundle React + JSX independently with esbuild. The regular sample enters through public/dapp-entry.jsx → public/dapp-view.jsx; custody enters through public/custody-entry.jsx → public/custody-view.jsx. HTML files only bootstrap the root and script. Existing CSS and run commands are preserved.

The regular JSX is divided into Wallet Session, Clair, Veiled, Relay Withdraw, Events, Auditor and related components. Its existing public/app.js transaction/recovery controller starts once per document after React's initial DOM commit and retains its DOM updates and event handling. This is not a rewrite of every regular-sample state into React hooks; do not remount this screen or replace it through client routing. Custody uses React state/effects to render the session and disposes subscriptions, polling and RPC resources on network changes, unmount and pagehide. Mounting never automatically connects or signs.

Default entry URLs are http://127.0.0.1:5173/ for the regular sample and http://127.0.0.1:4320/custody for custody. The custody server also accepts / and /custody.html for compatibility. Server origins and chain profiles stay separate. Existing screen assertions run against rendered JSX; test/custody-react.test.js connects the actual session module to synthetic wallets/RPC to check approval/signing separation, uncertain-result fences, invalidation and cleanup. These checks do not replace real-wallet E2E qualification.

Custody preview (CC-004 local host)

/custody uses the current pinned CC-004 SDK and extension-v1 raw JSON channels. npm run start:custody runs custody:local-build in the sibling clairveil-custody, verifies .spike-build/cc004-host build evidence/profiles and builds the web. That repository's tests/custody/sdk-package.json owns the package pin. The default consumer is .spike-build/cc004-consumer/node_modules; CC003_CONSUMER_DIR / CC003_SDK_TARBALL only relocate identical bytes. There is no fallback to the old CC-002 bridge or fixed-password setup UI.

Prerequisites are the prepared CC-004 SDK archive/consumer and running existing local chains/provers. The build does not install/publish SDKs or start/reset/fund chains. It reuses the cc002-local-1 Cosmos and maroo-zerofee-2 EVM local services, with network digests taken from the CC-004 deployment profiles.

npm run start:custody
# Separate terminal: synthetic RPC/React regression tests
npm run test:custody
# After building: actual extension/sample, synthetic chain wallets, no signing/broadcast
npm run test:custody:host
  1. In a disposable Chrome/Chromium profile (baseline Chromium 153), load ../clairveil-custody/.spike-build/cc004-host/extension and install Keplr or MetaMask. Reload the extension and web tab after rebuilding.
  2. Create or unlock the vault in the extension workbench, save and independently verify its backup, then approve “Trust local node and activate” for the selected chain. The former CC-002 public-wallet-JSON paste step and fixed test password are not used.
  3. Open http://127.0.0.1:4320/custody, select the network and connect the ordinary wallet. The Cosmos public key is automatically included in the connection request. Optionally select the balance-permission checkbox, request custody connection and approve it in the extension.
  4. Request a 1–999 base-unit deposit and approve privacy/prover disclosure in the extension. Explicitly sign with the ordinary wallet from the web and check the chain result. Only host-reported confirmed displays completion.
  5. With balance permission, use “Refresh scan and balances” in the workbench, then query balances from the web. Values are snapshots of the last response; only current + verified rows display amounts. Unknown/incomplete is never rendered as zero. Host verification lasts at most 30 seconds from observation; refresh the trusted scan when stale. Public sync is not supported.

Locking/closing the workbench or losing authority blocks new submission at the host. CC-004 has no separate CC-002 readiness probe: discovery uses a read-only capabilities RPC and explains locked/inactive/unresponsive states. Uncertain connection/deposit/submission requests are never automatically retried. Inspect past-operation recovery and restored-backup restrictions in the host workbench after restart. The sample does not yet expose a recovery-only connection UI.

React UI lives in public/custody-view.jsx, resource lifetime in public/custody-app.js, ordinary wallets in public/custody-wallet.js, and request authority/operation state in public/custody-session.js. The server exposes custody assets, read-only Cosmos proxies and a bounded same-origin broadcast route. The web never holds privacy keys, notes or witnesses or loads the legacy app.bundle.js. Transfer, withdraw and disclosure remain unsupported and disabled.

test:custody:host uses the actual built React page, extension, Argon2 vault, saved-backup verification and local nodes to verify connection approval, verified zero balances and deposit cancellation before export on both chains. Ordinary wallets are synthetic actors; any signing/broadcast fails the test. This does not replace real Keplr/MetaMask deposit requalification or production security qualification.

Start here: choose a chain and configure the web

Use a chain that includes the Clairveil privacy module and compatible queries, transactions, and prover contracts. You can connect to an already deployed chain or start one locally. Obtain its metadata and endpoint URLs from the chain operator. A regular Cosmos/EVM RPC endpoint alone does not provide Clairveil support.

Clairveil Core contains the reusable module and a reference chain for local testing. It is one available test host; the sample can also connect to other compatible chains.

1. Install the web dependencies

The current sample uses a local ClairveilJS checkout. Place the directories beside each other:

workspace/
  clairveil-samples/   # this repository
  clairveiljs/        # JavaScript SDK
  clairveil/          # optional: Core reference chain and local Go helpers

From the samples root, install the SDK and web dependencies:

cd ..
git clone https://github.com/DELIGHT-LABS/clairveiljs.git clairveiljs
cd clairveiljs
git checkout faf220d5b2fa1a186c30893ca74d765474015aee
npm ci
cd ../clairveil-samples
npm ci
npm run build:dapp

If the SDK directory already exists, use that checkout instead of cloning over it. Use a reviewed SDK ref compatible with this sample; the currently checked SDK commit is faf220d5b2fa1a186c30893ca74d765474015aee (package version 0.3.1, including the Cosmos v0.4 deposit contract). Check out that ref before npm ci when reproducing this snapshot. These commands require Node.js ^22.16.0 || >=24.0.0 and npm to support both the React tests' jsdom dependency and the pinned SDK's ES module dependencies. Node.js 22.16+ within the 22.x line is recommended.

2A. Test an already running chain

Start the chain using its own repository's instructions. In samples, choose the environment example for your chain:

# Choose one; back up an existing .env first:
cp .env.cosmos.example .env
# Or: cp .env.evm.example .env

Edit the copied .env with chain ID, RPC/REST, prover, denomination/decimals, prefixes, and wallet-specific values. Then run from the samples root in a fresh shell:

set -a
source .env
set +a
npm start

The examples default to public HTTPS endpoints with local helpers disabled. For local HTTP testing, follow the transport connection guide first. EVM local mode can automatically recover bundled public test keys during browser bootstrap; configure a compatible CLI and an isolated test home before enabling it. The EVM guide lists the required variables and limitations.

Restart the server and reload the browser after environment changes. The browser reads the config field in the /api/health response; inspect /api/config for the generated profile. This workflow needs no JSON edits. Only use public/dapp-config.json when separately choosing static hosting as described later.

2B. Start the Clairveil reference chain locally

Install Git, Make, Go 1.25.13, Python 3.9+, Bash, curl, Node.js 22.16+ (22.x) or 24+, and npm. Read the Core getting-started guide for circuit generation and machine requirements; use the documentation from the same Core ref you check out.

After step 1, clone Core beside the samples and run the samples' local runner:

Use a fresh terminal with no previously exported CLAIRVEIL_*, CLAIRVEILD_BIN, or CHAIN_ID settings; do not source the route 2A .env for this workflow. If your shell startup files export these settings, remove those exports from this session first. Starting a child shell from the configured terminal still inherits them. The runner does not clear existing transport, endpoint, denomination, or signer overrides: stale settings can keep the web connected to the previous chain or remote prover even while the local Core chain starts.

# From clairveil-samples:
cd ..
git clone https://github.com/DELIGHT-LABS/clairveil.git clairveil
cd clairveil
# Select a published Core ref compatible with this sample before initialization.
# Check the checked-out Core docs and SDK contract before using a newer release.
cd ../clairveil-samples
export CLAIRVEIL_HOME=/tmp/clairveil-dapp-local
export CHAIN_ID=clairveil-local-2
CLAIRVEIL_DAPP_HOST=127.0.0.1 npm run start:local

The runner executes make init in Core, which builds/installs the binaries, initializes the test accounts and audit key, and generates circuit artifacts. It then starts the reference chain, transfer/withdraw prover, samples deposit prover, and this web app. You do not need to run make init separately. Initial circuit generation can take time.

Service Default address
CometBFT RPC / Cosmos REST http://127.0.0.1:26657 / http://127.0.0.1:1317
Transfer/withdraw prover http://127.0.0.1:8080
Local Cosmos deposit prover http://127.0.0.1:8090
Samples web and same-origin prover proxy http://127.0.0.1:5173

This mode supplies chain profiles from the server automatically. The go.mod file belongs to the local deposit/auditor helpers and resolves Core through ../clairveil; static browser testing does not require Go or a local Core checkout.

Each npm run start:local invokes initialization again and backs up an existing chain home before replacing it. To use an existing chain without reinitializing it, leave that chain/prover running and use route 2A, or the manual server configuration in Run. Stop the local stack with Ctrl+C. After a chain reset, use the web's Reset & Rescan and a fresh test session/cache rather than reusing old notes.

The web may start before the transfer/withdraw prover finishes loading its artifacts. Before requesting proofs, check both prover health endpoints:

curl --fail http://127.0.0.1:8080/healthz
curl --fail http://127.0.0.1:8090/healthz

Both should return HTTP 200. Wait for artifact loading if either is not ready. The browser's Protocol: v0.3.1 ready label identifies the wallet protocol contract; it is also used with the supported Core v0.4 deposit route.

3. Run a wallet test

  1. Select your chain and connect Keplr or MetaMask. Check the chain ID, denomination, and displayed endpoints.
  2. Fund the transparent account. The local reference server offers Faucet; a deployed chain needs its own faucet or funded test account. Leave enough balance for network fees.
  3. Complete Setup Clairveil, then Deposit a small amount using the denomination shown beside the input. Wait for the transaction result and note scan.
  4. Transfer to a second test wallet's shielded address, scan in that wallet, and Withdraw to a transparent address.
  5. Check transaction hashes, balances, and note status after each step. Local admin audit decoding is available only when the corresponding local helper and test audit key are configured.

If health fails, check endpoint connectivity, chain ID, CORS, and the required privacy query routes first. If Deposit is unavailable, check the selected profile's canonical deposit prover/provider and protocol preflight. For an unresolved transaction, reconcile its existing hash before trying another submission.

Key Files

File Purpose
public/dapp-config.json Runtime chain profiles loaded by the statically hosted browser
public/dapp-config.js Source/default configuration helpers
public/app.js Browser UI and wallet flow
public/app.bundle.js Browser bundle generated by npm run build:dapp
server.js Local test helper server (faucet, local signer...)
scripts/dapp-local.sh Local loopback runner that uses the sibling Core checkout
.env.example Optional environment override template for local/server-backed runs
test/dapp-smoke.test.js Boundary and DApp smoke tests

The SDK is resolved from the sibling checkout through "clairveiljs": "file:../clairveiljs". Keep this repository beside both clairveiljs/ and clairveil/, then run npm install here after changing the SDK. The lockfile records the local package as ClairveilJS 0.3.1; the SDK is bundled into public/app.bundle.js and is not copied into this sample by hand. Local CLI and administrator helpers use the sibling Clairveil Core checkout.

To test another local ClairveilJS v0.3.1 worktree without changing package.json or the lockfile, set CLAIRVEILJS_DIR for the command. The DApp scripts validate the selected package and relink only the local node_modules/clairveiljs symlink:

CLAIRVEILJS_DIR=/absolute/path/to/clairveiljs-worktree npm run build:dapp
CLAIRVEILJS_DIR=/absolute/path/to/clairveiljs-worktree npm run test:dapp

Main Features

  • Chain profile dropdown; the default static config exposes Cosmos/Keplr, and EVM/MetaMask profiles can be added when the target chain provides a compatible privacy precompile
  • One shared Wallet Session panel
  • Transparent balance and public send
  • Deposit from transparent balance into veiled notes
  • Typed privacy_scan note discovery with encrypted cursor/note persistence, endpoint selection, cursor rollback, cache backup, forced rescan recovery, batch nullifier checks, and spendable-only filtering
  • Veiled transfer with note planning and self-transaction guidance
  • Direct withdraw from veiled notes or a product-defined relay handoff payload
  • Disclosure modes: none, public, recipient-encrypted
  • User and sender self-view disclosure decoding
  • Protocol preflight, asset binding, and reserve-invariant status
  • Privacy Events and Event Block views
  • Local signer, faucet, and auditor/admin test helpers in local mode

Architecture

Browser DApp
  -> ClairveilJS browser client
    -> Cosmos REST/RPC
    -> EVM JSON-RPC
    -> Prover HTTP
    -> Cosmos canonical DepositCircuit route or transport-specific provider
    -> Keplr / MetaMask

Optional local server
  -> static files
  -> /api/config, /api/health
  -> local faucet
  -> local signer CLI helpers
  -> local/admin auditor helpers

The DApp does not send wallet privacy preparation work to the server. Deposit, transfer, withdraw, scan, user disclosure decode, broadcast, and wait are handled by the browser ClairveilJS client.

Endpoints

Optional DApp Server

These routes exist only when server.js is running. In a public-node deployment, wallet privacy flows can run with the static DApp plus ClairveilJS without local helper routes.

Endpoint Mode Purpose
GET /api/config all Server-backed config and chain profiles
GET /api/health all Local node health, tree/audit config, local accounts
POST /api/local-signers/ensure local only Create local signer test accounts
GET /api/wallet/:name/show-address local only Show local signer transparent/shielded address
GET /api/wallet/:name/notes local only Scan local signer notes through CLI
POST /api/faucet local only Send local faucet funds to the connected wallet
POST /api/deposit local only Local CLI deposit test
GET /api/auditor/test-scalar local/admin only Test auditor scalar
POST /api/auditor/decode local/admin only Decode audit disclosure with an audit private scalar
POST /v1/prover/deposit local only Canonical Core v0.4.0 proxy to {CLAIRVEIL_COSMOS_DEPOSIT_PROVER_URL}/v1/prover/deposit, falling back to CLAIRVEIL_PROVER_URL
POST /v1/prover/deposit-legacy local only Legacy exact proxy to CLAIRVEIL_DEPOSIT_PROOF_URL for an explicitly configured EVM/product provider
POST /v1/prover/transfer / withdraw local only Same-origin proxy to the configured transfer/withdraw prover

The bundled prover proxy is a bounded local-development helper, not a public prover gateway. It requires both local-test mode and the explicit CLAIRVEIL_PROVER_PROXY_ENABLED=1 flag, accepts only direct loopback callers, requires application/json, omits cross-origin permission, rejects redirects, bounds and validates JSON responses, and applies per-client rate plus process-wide concurrency limits. Public mode rejects the proxy flag. Public Cosmos deployments use the canonical deposit route on CLAIRVEIL_PUBLIC_PROVER_URL unless they set a reviewed exact Cosmos override; EVM/product-specific deployments may set their own exact deposit URL. Every remote prover boundary needs reviewed authentication, rate/quota, metadata-only logging, and retention controls.

Browser ClairveilJS High-Level Calls

For local audit decoding on either Cosmos or EVM, the auditor key must derive the disclosure public key returned by the chain's audit_config; creating an unrelated key will not decrypt existing disclosures. By default the helper uses the local signer home and keyring backend. Set CLAIRVEIL_AUDITOR_HOME to a separate disposable keyring home containing auditor when needed (for example, the matching test key already exists under another name and the keyring rejects duplicate addresses). Restart the sample server after changing this setting. The test-scalar endpoint reports matches_audit_config; it must be true before testing Decode. This does not change the chain audit configuration and remains local/admin-only. Never import production custody keys into this test helper.

The DApp UI does not implement privacy preparation itself. It calls the high-level clairveiljs/browser-dapp API, and those calls use the selected chain profile's REST/RPC/prover/wallet APIs.

ClairveilJS call Network/API surface
health() RPC /status, REST /tree_state, REST /audit_config
getBalances(address) REST /cosmos/bank/v1beta1/balances/{address}
buildBankSendSignDoc(...) REST account info, Keplr signDirect
evmNativeSendTransaction(...) MetaMask eth_sendTransaction
prepareDeposit(...) Creates the note material; Cosmos obtains a canonical DepositCircuit proof from proverUrl, an exact canonical override, or an injected provider, while EVM retains its explicit provider contract; returns a Cosmos sign doc or EVM precompile tx
scanWalletNotes(...) Uses typed privacy_scan, persists the full cursor in the DApp's AES-GCM encrypted note store, and refreshes statuses with batch nullifier lookup
prepareTransfer(...) Scans notes, plans inputs, reads audit config, calls prover /v1/prover/transfer, creates disclosure payloads, then returns a Cosmos sign doc or EVM precompile tx
prepareWithdraw(...) Scans notes, plans inputs, calls prover /v1/prover/withdraw, then returns a Cosmos sign doc or EVM precompile tx
prepareRelayWithdraw(...) Produces a chain/recipient/expiry-bound relayer payload and, for EVM, a candidate transaction that the relayer must rebuild or byte-validate
signDirectAndBroadcast(...) Signs and broadcasts Cosmos txs while preserving the prepared note reservation lifecycle
waitForEvmTransaction(...) Waits for EVM transaction receipts
sendEvmTransaction(...) Revalidates the configured and connected EVM networks and submits the prepared transaction through the SDK
assertProtocolPreflight(...) / queryReserve(...) Validates circuit/asset config and the reserve invariant
fetchPrivacyEvents(...) Reads the REST privacy event feed
fetchBlockEvents(...) Reads block/tx events through RPC tx search
fetchAuditableTransfers(...) Filters auditable transfer events from the privacy event feed
decodeUserDisclosure(...) Loads tx/event disclosure payloads and decodes with wallet privacy material
decodeSelfViewDisclosure(...) Lets the originating wallet decode its sender self-view payload

ClairveilJS Browser Client -> Cosmos REST/RPC Endpoints

The active chain profile provides rest and rpc.

Endpoint Purpose
RPC /status Node health and authoritative latest block time/height for final confirmation and v0.3.1 expiry binding
RPC /tx_search Event Block / tx lookup
REST /cosmos/auth/v1beta1/account_info/{address} Account number and sequence for sign docs
REST /cosmos/bank/v1beta1/balances/{address} Transparent balance
REST /clairveil/privacy/v1/tree_state Merkle tree state
REST /clairveil/privacy/v1/privacy_scan Typed v2 note scan with (height, global_sequence, output_index) cursor
REST /clairveil/privacy/v1/events Privacy event UI/disclosure lookup and legacy fallback only
REST /clairveil/privacy/v1/commitment/{commitment_hex} Commitment metadata
REST POST /clairveil/privacy/v1/nullifiers Batch nullifier status (up to 1,000 per request)
REST /clairveil/privacy/v1/commitment_paths Exact-root Merkle witness snapshots
REST /clairveil/privacy/v1/reserve/{denom} Escrow reserve invariant
REST /clairveil/privacy/v1/assets/by_denom/{denom} Canonical asset binding
REST /clairveil/privacy/v1/audit_config Audit master public key
REST /clairveil/privacy/v1/disclosure_config Disclosure config
REST /clairveil/privacy/v1/circuit_config Circuit config

ClairveilJS Browser Client -> Prover Endpoints

The active profile provides proverUrl for transfer/withdraw. For Cosmos, ClairveilJS also appends /v1/prover/deposit to that base URL while preserving any path prefix. A Cosmos depositProofUrl is an optional exact canonical override. EVM continues to require its explicitly configured legacy deposit provider or URL; the SDK does not derive an EVM deposit endpoint from proverUrl.

Endpoint Purpose
POST /v1/prover/transfer Transfer proof
POST /v1/prover/withdraw Withdraw proof
POST {proverUrl}/v1/prover/deposit Core v0.4.0 canonical Cosmos deposit request/response
Exact Cosmos depositProofUrl Optional canonical V1 endpoint override
Exact EVM depositProofUrl or injected provider Existing EVM/product-specific deposit contract

The canonical Cosmos request contains only versioned compressed receiver keys, amount, asset ID, randomness, and note commitment. The response must be JSON with Cache-Control: no-store, nested V1 proof metadata, the exact request commitment, and a canonical 164-byte lowercase BN254 proof. Redirects, malformed headers/envelopes, commitment mismatches, and non-canonical proofs fail closed. Cancellation ends the browser's wait; it does not prove that an already-running remote solver stopped. The client does not automatically fail over the private witness to a second prover.

Cosmos Deposit is available when a canonical injected provider, exact canonical depositProofUrl, compatible proverAdapter.proveDeposit, or proverUrl is configured. EVM Deposit remains unavailable without its explicit legacy provider or exact URL.

Browser Wallet APIs

Cosmos profiles use Keplr:

  • experimentalSuggestChain
  • getKey
  • signArbitrary
  • signDirect

EVM profiles use MetaMask:

  • eth_chainId
  • wallet_switchEthereumChain
  • wallet_addEthereumChain
  • eth_requestAccounts
  • personal_sign
  • eth_estimateGas
  • eth_sendTransaction
  • eth_getTransactionReceipt

Adding Chains

Add static chain profiles to public/dapp-config.json, which is the exact artifact the browser loads when /api/health is unavailable. The checked-in static default exposes the Cosmos/Keplr profile only. To show EVM/MetaMask in a static deployment, add a complete EVM profile to that file. In server-backed mode, the browser instead uses the config embedded in /api/health; /api/config returns the same bare Web client config for diagnostics but is not the browser bootstrap source. The production verifier rejects a deployment when those two config payloads differ.

EVM profile fields are illustrated below as JavaScript. For static hosting, put the corresponding object in public/dapp-config.json → chainProfiles, using JSON syntax (quoted keys, no const, export, comments, or references to variables). Set activeChainProfileId in that JSON; changing this source example alone does not update the runtime artifact.

const myEvmProfile = {
  id: "my-evm",
  label: "My EVM Privacy Chain",
  chainName: "My EVM Privacy Chain",
  transport: "evm",
  wallet: "metamask",
  chainId: "my-evm-host-1",
  rpc: "https://cosmos-rpc.example.com",
  rest: "https://cosmos-rest.example.com",
  restEndpoints: ["https://cosmos-rest.example.com", "https://cosmos-rest-backup.example.com"],
  proverUrl: "https://prover.example.com",
  depositProofUrl: "https://deposit-proof.example.com/v1/prove",
  accountPrefix: "clair",
  shieldedPrefix: "clairs",
  denom: "utoken",
  displayDenom: "TOKEN",
  coinDecimals: 18,
  evmRpc: "https://evm-rpc.example.com",
  evmChainId: "0x1234",
  evmChainName: "My EVM Privacy Chain",
  evmPrivacyPrecompileAddress: "0x100000000000000000000000000000000000000b",
  evmDepositMode: "payable-exact-value",
  evmNativeDenom: "utoken",
  evmGasLimit: "0x989680",
  evmSendGasLimit: "0x5208"
};

export const defaultDappConfig = {
  // ...
  activeChainProfileId: myEvmProfile.id,
  chainProfiles: [clairveilProfile, myEvmProfile]
};

Cosmos profile requirements:

  • Clairveil privacy module embedded in the chain
  • /clairveil/privacy/v1/* REST query surface
  • Compatible /clairveil.privacy.v1.MsgDeposit, MsgTransfer, and MsgWithdraw
  • Correct account prefix, shielded prefix, denom, and decimals
  • Keplr signDirect support
  • Browser-accessible REST/RPC/prover CORS
  • Core v0.4.0 canonical POST /v1/prover/deposit support on proverUrl, or an explicitly reviewed canonical override/provider
  • Typed privacy_scan, batch nullifier, asset, reserve, and exact-root commitment-path query support

EVM profile requirements:

  • Browser-accessible EVM JSON-RPC
  • Host chain Cosmos REST/RPC for Clairveil privacy events and queries
  • Clairveil-compatible EVM IPrivacy precompile ABI
  • Fixed evmPrivacyPrecompileAddress published by the target chain
  • Clairveil privacy account prefix for EVM-derived identity material
  • Prover support for /v1/prover/transfer and /v1/prover/withdraw
  • An explicit evmDepositMode; payable-exact-value also requires evmNativeDenom === denom so the amount binds exactly to msg.value

This DApp does not support arbitrary EVM privacy ABI shapes. EVM Clairveil chains must use the same privacy precompile ABI and payload semantics.

Environment Overrides

server.js has local defaults so npm start can run without an env file. Use .env.example as the reference when you need to override local node, prover, chain profile, or LAN helper settings.

cd /path/to/clairveil-samples
cp .env.example .env
set -a; source .env; set +a
npm start

Common values:

Variable Purpose
CLAIRVEIL_DAPP_HOST / CLAIRVEIL_DAPP_PORT DApp server bind address and port; the server defaults to loopback and LAN exposure requires an explicit host override
CLAIRVEIL_DAPP_LOCAL_TEST_MODE 1 enables local helpers, 0 runs public-node mode
CLAIRVEIL_CHAIN_PROXY_ENABLED Opt-in 1 in local-test mode serves fixed loopback Cosmos REST/RPC through /chain-rest and /chain-rpc on the web origin; requires a 127.0.0.1 bind address and loopback upstreams. Browser endpoints use these paths unless explicitly overridden.
CLAIRVEIL_DAPP_PUBLIC_ORIGIN Required exact HTTPS browser origin in public-node mode
CLAIRVEIL_HOME / CHAIN_ID / CLAIRVEILD_BIN Local node home, chain id, and CLI binary
CLAIRVEIL_RPC / CLAIRVEIL_REST Server-side Cosmos/CometBFT endpoints
CLAIRVEIL_PUBLIC_RPC / CLAIRVEIL_PUBLIC_REST Browser/Keplr-visible endpoints; empty means reuse the server endpoints
CLAIRVEIL_PUBLIC_REST_ENDPOINTS Shared comma-separated browser REST failover set
CLAIRVEIL_COSMOS_RPC / CLAIRVEIL_COSMOS_REST Cosmos-profile browser endpoint overrides; these take precedence over the shared public endpoints
CLAIRVEIL_COSMOS_CHAIN_NAME / CLAIRVEIL_COSMOS_LABEL Cosmos chain name shown to Keplr and optional DApp selector label; a blank label inherits the chain name
CLAIRVEIL_COSMOS_CHAIN_ID / CLAIRVEIL_COSMOS_ACCOUNT_PREFIX / CLAIRVEIL_COSMOS_SHIELDED_PREFIX Cosmos identity overrides used by both the active browser profile and the server-side local signer/client; blank values inherit CHAIN_ID and the shared prefixes
CLAIRVEIL_COSMOS_COIN_TYPE / CLAIRVEIL_KEPLR_COIN_TYPE Cosmos BIP-44 coin type. The first is preferred; CLAIRVEIL_KEPLR_COIN_TYPE remains a compatible alias
CLAIRVEIL_COSMOS_REST_ENDPOINTS / CLAIRVEIL_EVM_HOST_REST_ENDPOINTS Optional profile-specific REST endpoint sets; these take precedence over the shared failover set
CLAIRVEIL_PROVER_URL / CLAIRVEIL_PUBLIC_PROVER_URL Server-side and browser-visible prover endpoints. An explicitly blank server URL leaves canonical local proxy routes unavailable (503)
CLAIRVEIL_PROVER_BEARER_TOKEN / CLAIRVEIL_PRIVACY_PROVER_BEARER_TOKEN Optional local proxy credential. A non-empty proxy-specific value takes precedence; a blank value falls back to the common proverd credential. Public mode rejects either credential
CLAIRVEIL_DEPOSIT_PROOF_URL / CLAIRVEIL_PUBLIC_DEPOSIT_PROOF_URL Legacy server-side/browser-visible exact DepositCircuit endpoint; used by the EVM/product-specific path, not as the Cosmos default
CLAIRVEIL_COSMOS_DEPOSIT_PROOF_URL Optional exact canonical Cosmos V1 endpoint override; omit to derive /v1/prover/deposit from proverUrl
CLAIRVEIL_EVM_DEPOSIT_PROOF_URL Exact EVM/product-specific deposit proof endpoint
CLAIRVEIL_PROVER_PROXY_ENABLED Explicitly enables the bounded proxy in local-test mode only; public-node mode rejects it
CLAIRVEIL_COSMOS_DEPOSIT_PROVER_URL Optional server-only canonical Cosmos deposit prover base used by the local proxy; never emitted as a browser endpoint
CLAIRVEIL_PROVER_PROXY_RATE_LIMIT_WINDOW_MS / CLAIRVEIL_PROVER_PROXY_RATE_LIMIT_MAX / CLAIRVEIL_PROVER_PROXY_MAX_IN_FLIGHT Local proxy request-rate and concurrency bounds
CLAIRVEIL_PROVER_PROXY_MAX_REQUEST_BYTES / CLAIRVEIL_PROVER_PROXY_MAX_RESPONSE_BYTES Positive local proxy request/response byte limits. The request limit defaults to 8388608 (8 MiB) and is enforced independently on the raw wire body and the decompressed gzip body
CLAIRVEIL_DAPP_UPSTREAM_TIMEOUT_MS / CLAIRVEIL_DAPP_UPSTREAM_MAX_RESPONSE_BYTES Timeout and JSON response-size limit for server-side health/read queries
CLAIRVEIL_DAPP_HEALTH_MAX_IN_FLIGHT Process-wide /api/health admission limit; excess requests receive a typed 503 response
CLAIRVEIL_ACCOUNT_PREFIX / CLAIRVEIL_SHIELDED_PREFIX Transparent and shielded address prefixes
CLAIRVEIL_DENOM / CLAIRVEIL_DISPLAY_DENOM / CLAIRVEIL_COIN_DECIMALS Shared coin metadata fallback
CLAIRVEIL_COSMOS_DISPLAY_DENOM / CLAIRVEIL_COSMOS_COIN_DECIMALS Optional Cosmos display metadata overrides; blank or absent values inherit the shared metadata
CLAIRVEIL_COSMOS_DENOM / CLAIRVEIL_EVM_DENOM / CLAIRVEIL_EVM_NATIVE_DENOM Transport-specific minimal denom; active transport values override CLAIRVEIL_DENOM, and EVM falls back to its native denom before the shared value
CLAIRVEIL_EVM_DEPOSIT_MODE / CLAIRVEIL_EVM_NATIVE_DENOM nonpayable or v0.3.1 payable-exact-value deposit binding
CLAIRVEIL_EVM_* Other optional EVM/MetaMask profile settings
CLAIRVEIL_DAPP_ALLOW_LAN_SIGNING / CLAIRVEIL_DAPP_ALLOW_LAN_ADMIN Explicit opt-in for exposing local signing/admin helpers on LAN. The bundled prover proxy remains loopback-only

Signer-mutating local helper routes accept only application/json POSTs whose Origin exactly matches the DApp request origin. Enabling LAN signing does not waive this same-origin requirement; open the DApp from that LAN origin and let the browser issue the request.

Privacy Flow

Setup Clairveil signs a root message with Keplr signArbitrary or MetaMask personal_sign. The wallet creates the root signature internally but returns that signature to the page. ClairveilJS running in the page derives RootSeed and the spend/view/disclosure private key material from the returned signature, so those values are present in page JavaScript memory and are not isolated inside a wallet plugin or Snap. ClairveilJS then derives the shielded address and disclosure public key and requires the v0.3.1 protocol preflight and initial note sync to complete. The note recovery UI can select a configured REST endpoint, roll the encrypted cursor back to a block height, or back up and reset the cache. Value-moving privacy actions stay disabled until preflight is ready and the cache is fully synced.

Deposit refreshes the transparent balance and checks the amount plus a configured gas-fee budget before proof work. It then creates a new note, commitment, and encrypted note, obtains a DepositCircuit proof, and runs protocol preflight. Cosmos profiles produce a Keplr sign doc with wallet fee editing enabled. EVM profiles produce privacy precompile calldata for MetaMask; payable-exact-value binds the minimal-unit amount exactly to transaction value. The prepared network fee or wallet-side fee estimate is shown before approval, then replaced after inclusion by the fee proven to have been charged on-chain. Cosmos uses ante-handler tx.fee or fee coin_spent events rather than the declared AuthInfo value, so a fee-free localnet displays Actual 0uclair. Transaction inclusion and local note recovery are shown separately. Cosmos recovery first verifies that the tx event contains the exact prepared commitment and encrypted note; both transports then require the commitment to appear in the encrypted local cache.

Transfer scans notes, plans inputs, creates any required self-transaction step, requests a transfer proof from the prover, creates disclosure payloads, and prepares the final Cosmos sign doc or EVM transaction. The post-prepare confirmation shows authoritative chain ID/time expiry, recipient, amount, exact change returned to the sender shielded address, disclosure plane, and self-view setting before wallet submission. Canceling this final screen discards the local proof and moves its prepared reservation to replan-required. Self-view is enabled by default and can be explicitly disabled with a recovery warning. For reservation-bound Cosmos transfer/withdraw documents, the DApp asks Keplr to preserve the prepared fee and memo because ProofReady binds the exact TxBody + AuthInfo; deposit remains wallet-fee editable because it does not reserve an input note.

Withdraw scans spendable notes, plans the withdraw, requests a withdraw proof, and prepares the final Cosmos sign doc or EVM transaction. Its result UI tracks nullifier-spent evidence separately from the bound transparent-receive evidence and reports success only after both reconcile. Relay handoff prepares the immutable payload without broadcasting it; the application exports the v0.3.1 schema_version, handoff_version, request, and payload layers as v2 and must deliver that JSON over its own trusted relayer transport. Before the JSON is exposed, the DApp records the relay handoff against the prepared reservation.

Transfer and withdraw preparation use a ClairveilJS note reservation manager backed by IndexedDB, Web Locks, and AES-GCM encrypted state derived from the wallet privacy material. The same manager and prepared reservation are passed to Cosmos and EVM submission, and the DApp heartbeats the ProofReady lease while wallet or relay handoff confirmation is pending. Reserved notes are labelled and excluded from the displayed plan-available balance, while unrelated unreserved notes remain eligible for new plans. The reservation recovery panel groups linked inputs by operation and only offers Discard proof & unlock notes when no broadcast attempt or relay handoff is recorded. It refreshes the authoritative note scan, requires every reserved nullifier to be explicitly unspent, and asks the wallet owner to approve proof discard. A live owned ProofReady lease then moves directly to ReplanRequired; an expired preparation first enters ManualReview and records the owner-approved resolution. Restarting a localnet with a fresh genesis under the same chain ID makes old nullifiers impossible to query on the new chain. In local-test mode only, the DApp can reset previous-genesis encrypted reservation state with separate wallet-owner approval when a complete scan is empty, reserve/deposit/withdraw totals are all zero, and every active reservation has no broadcast or relay evidence. A receipt polling timeout is shown as Unknown, never as proof of failure; the Reconcile action checks the tx hash first and then refreshes nullifier status. A transfer whose nullifier is spent is completed only after a paginated lookup at the authoritative included height finds the matching chain event and binds the stored tx hash, output commitment, audit disclosure digest, recipient hash, amount hash, and denom. Relay reconciliation validates an included transaction against the encrypted handoff before scanning spent notes: it decodes the Cosmos MsgWithdraw or compares the EVM target, calldata, value, and chain ID. A spent nullifier without a successful bound transaction is persisted as operation-level manual review and blocks a replacement withdraw. A query failure leaves the reservation locked; missing or conflicting operation evidence remains blocked for manual review.

The same-origin local relayer repeats nullifier preflight and atomically locks each canonical payload nullifier. Concurrent or replayed copies of the same payload share one submission, while any overlapping different payload is rejected. Faucet, local deposit, and relay broadcasts using the same signer account also share one account-sequence/nonce queue. An explicit nonzero Cosmos CheckTx response releases only this process-local submission gate because the node definitively rejected the transaction. Once the broadcaster has returned a valid exact tx hash, a later timeout, disconnect, or malformed status retains that hash with the account fence; a later signer request clears the fence only after an authoritative Cosmos tx query or EVM receipt query finds the transaction. An indexed Cosmos tx with a non-canonical execution code, or an EVM receipt with a non-canonical status, is returned as included=true, pending=false, unknown=true, and failed=null together with the exact hash; it is never cached or rendered as success. If the CLI fails before returning any valid hash, the process-local gate remains fail-closed but exact-hash reconciliation is impossible; such an identifier-less post-boundary result is never automatically retryable. The browser's durable reservation still follows its normal reconciliation policy.

Transparent EVM send and deposit tx hashes and unresolved status are persisted across reloads, so their actions remain disabled until the existing tx is reconciled as included or explicitly failed. EVM deposit preflight queries the target asset through the host-chain bank endpoint and the native gas balance through eth_getBalance; profiles with different denom and evmNativeDenom must satisfy both independently. Cached note balances are labelled unconfirmed, and private spend actions stay disabled until a full note scan reaches synced while protocol preflight is ready. Relay handoff JSON, reservation IDs, tx hash, and result state are encrypted with wallet-derived material and restored after setup; the UI displays the immutable recipient/chain/expiry and privacy warnings, then reports transaction inclusion and nullifier spent state separately. If authoritative block time proves that a handoff expired and every reserved nullifier is still unspent, the wallet owner can explicitly approve ManualReview -> ReplanRequired recovery and prepare a new payload.

Disclosure Review accepts the current event selection, an arbitrary tx hash, or pasted shielded_transfer event JSON for user, self-view, and local-admin audit planes. A verified report displays plane, policy, output index, commitment, digest, and verified=true. Decoded fields are rendered only when verification.verified === true; verification failures show verified=false and discard plaintext.

The DApp persists the note cache in browser localStorage as an AES-GCM envelope. Its key is derived from wallet root-signature material with HKDF and is scoped to chain profile and account. A legacy plaintext cache is deleted instead of migrated and requires Reset & Rescan; a corrupt/undecryptable cache fails closed and can be backed up before reset. The cache remains recoverable chain-derived data, not a substitute for wallet key backup.

If the separate private Cosmos transaction fence is corrupt, normal transaction actions remain blocked and the public pending-state clear does not touch it. Reviewed privacy reset is available only after Clairveil setup and protocol preflight. The wallet owner must close other DApp tabs, inspect Keplr activity and the explorer for the exact chain/account, confirm that no private transaction is pending or submitted, and type the displayed RESET <chain-id> <account> phrase. The DApp then holds the account lock, performs a full typed scan, requires zero active reservations and relay recoveries, clears only the exact encrypted reservation namespace, and removes the exact private fence last. Any scan, recovery, or storage failure leaves the fence fail-closed.

Transfer/withdraw proof requests carry an AbortSignal. The modal can cancel an in-flight request and retry against the same profile-pinned prover endpoint. Expiry is derived from the latest chain block time and the UI fails closed if that timestamp cannot be read.

The v0.3.1 one-proof batch APIs and server proxy path are intentionally not exposed in this UI. Keep serverFeatures.batchTransfer false until the target chain, prover, scan recovery, wallet confirmation, and downstream E2E suite are all validated together.

Preparation failures can leave linked notes in ManualReview even when no broadcast was recorded. The existing recovery card shows cached input notes and a bounded preparation-failure explanation when available; old records cannot recover an original error that was not saved. Use Discard proof & unlock notes for the existing chain-evidence and owner-approved proof-discard flow. Neither a timeout, cancellation, nor an unspent cache entry alone automatically unlocks a proof-stage reservation.

If a cancelled transfer/withdraw/relay preparation returns a completed result, the DApp drops its local proof and executable artifacts and records ManualReview with proof-discard/no-broadcast evidence. Notes remain locked until the wallet owner uses Discard proof & unlock notes. Recovery scans before and after approval, rejects any broadcast/handoff evidence or spent/missing input, and atomically moves only the selected operation's linked reservations to ReplanRequired. Other operations and cached notes are not deleted. A provider rejection without a result does not confirm remote proof deletion; use the same explicit recovery review, not an automatic timeout unlock. Failed persistence keeps the reservation locked. Proof cancellation is disabled once wallet submission or relay handoff begins; it cannot retract a submitted transaction or exported payload.

EVM deposit confirmation and recovery

Private EVM transfer/withdraw submissions use the same account lock and nonce preflight, before entering the SDK's durable broadcast boundary. The SDK receives its unchanged prepared transaction; the wallet request receives the explicit nonce. A preflight failure therefore creates no new broadcast attempt. This does not retroactively resolve an older hashless ManualReview operation: an advanced account nonce alone does not bind the failed wallet request to that reservation, and a zero-value helper input is not an exception to recovery checks.

Public EVM send/deposit requests query the configured RPC's latest and pending account nonces under the account lock and supply the pending nonce explicitly to the wallet. An already-used explicit nonce or a failed nonce preflight stops before the wallet request and creates no new pending marker. This reduces stale-wallet nonce errors but cannot stop a different application from submitting concurrently. After the wallet boundary, only explicit rejection (4001) automatically clears that exact hashless attempt; a nonce too low error may also describe a retry of an included transaction and remains unresolved. For an older hashless attempt, inspect wallet history and chain transactions, then use Clear unresolved wallet attempt and confirm the named send/deposit attempt. This clears only that reviewed attempt, preserves other transaction records and note reservations, and does not cancel or resubmit a transaction.

Before opening MetaMask, the sample saves the original SDK-prepared deposit transaction (including its verification metadata), sender, and encrypted-output recovery fields in a separate AES-GCM store scoped to the chain/profile/account. The public pending marker contains only the opaque recovery-record ID, attempt ID, and transaction hash/status—not calldata or note data. Storage failure prevents submission. Reconnect the same wallet and use Setup Clairveil to unlock this record, then Reconcile deposit tx; reconciliation never resubmits the transaction.

Submission confirmation and reconciliation both pass the original transaction and sender to the SDK. The sample explicitly uses one canonical block confirmation unless the SDK client has a configured finality policy; this is inclusion evidence, not irreversible finality. Missing receipts or failed identity/event/finality checks keep the pending fence. Inclusion alone does not complete a deposit: its owned encrypted note must also be recovered. Older hash-only entries use the exact canonical PrivacyDeposit event, sender, configured contract, commitment, amount/denom, and scanned note height; RPC calldata is never substituted for a missing original preparation. If the note is absent, keep the fence and use Reset & Rescan, then reconcile again.

Cosmos-EVM transfer recovery

For Cosmos-EVM transfer reconciliation, the wallet's Ethereum transaction hash can differ from the host-chain privacy event's transaction hash. The sample uses the profile's configured host RPC and EVM RPC to verify the successful receipt, matching canonical block/host chain ID, inclusion and hash of the Cosmos transaction bytes, and its unambiguous ethereum_tx.ethereumTxHash link. The indexed privacy event must exactly match an included event before its output commitment and audit digest are passed to the SDK with the original EVM hash for comparison against the prepared reservation. Same-height matches alone, missing indexing, ambiguous multi-EVM transactions, and mismatched outputs never complete an operation. These host-chain endpoints and hash-link events are required for this Cosmos-EVM recovery path; they are not assumed to exist on every EVM chain.

After cancellation is checked and disabled, but before wallet submission, reserved EVM operations save their original transaction and sender in the chain/profile/account-scoped evm-private encrypted recovery store. Transfer reconciliation binds this artifact to every reservation's tx_bytes_hash, reruns SDK transaction/privacy-receipt/finality verification, and supplies the actual successful receipt and verification results alongside the output evidence. Missing verification is not evidence of a wrong recipient. Use Note reservations → Reconcile for records with recoverable preparations. Older records without the original artifact remain unresolved; neither RPC calldata nor literal true flags may substitute for the missing verification. Do not resubmit the transfer or unlock consumed notes.

Direct EVM withdraw validation

Withdraw payloads use the host chain's bech32 recipient even when the user enters an EVM address. The sample converts the user's intended EVM recipient using the configured account prefix before passing expectedRecipient to the SDK; it never takes the expected value from the payload being checked. Wrong recipients and prefixes remain rejected. After submission, direct withdraw reconciliation reruns SDK verification from the encrypted original request, then derives the actual recipient and amount from the configured contract's unique PrivacyWithdraw receipt event. All input-spent and reservation evidence must still match before the operation succeeds. This does not release an older reservation left by a preparation failure.

Disclosure Mode

Mode Meaning
none No user disclosure is created. Explorers/events only show private payloads.
public The selected fields are written as a public report. No target pubkey is required.
recipient-encrypted The selected fields are encrypted so only the disclosure pubkey owner can decode them.

Test With Your Own Disclosure Pubkey

  1. Connect a wallet and click Setup Clairveil to derive your shielded address and disclosure pubkey.
  2. In the Wallet Session card, click Copy next to Disclosure pubkey.
  3. In Transfer (Veiled Send), turn on Advanced.
  4. Set Disclosure mode to recipient-encrypted.
  5. Paste your copied disclosure pubkey into Disclosure target.
  6. Check the fields you want to reveal, such as Amount + asset, From shielded address, and To shielded address.
  7. Send the transfer, then select the matching shielded_transfer in Privacy Events.
  8. Click 조회 in the event detail to decode the user disclosure with your wallet-derived privacy material.

To disclose to someone else, paste that person's disclosure pubkey into Disclosure target. A wallet address alone is not enough to create recipient-encrypted disclosure for them.

Run

Start the local node, transfer/withdraw prover, local-only DepositCircuit prover, and DApp together for a local test. The runner uses the sibling Core checkout at ../clairveil.

cd /path/to/clairveil-samples
npm run start:local

If 26657, 1317, 8080, 8090, or 5173 is already in use, stop the existing process first. Press Ctrl+C in this terminal to stop the local stack. The runner builds the example-only deposit prover under CLAIRVEIL_HOME, binds it to 127.0.0.1:8090, and configures the DApp proxy automatically.

For an existing chain, use the Cosmos or EVM connection guide. For manual reference-node startup below, use a clean shell as described in step 2B. Before starting the node, allow the local web origin in $CLAIRVEIL_HOME/config/config.toml:

# In the existing [rpc] section, replace the cors_allowed_origins value:
cors_allowed_origins = ["http://127.0.0.1:5173"]

Apply this edit after make init (which recreates the home) and before clairveild start. If you change the web port, update the allowed origin too. The REST flag below also enables CORS; it is for isolated local testing only, not public deployment. Server health success alone does not prove browser CORS access.

Start a local Clairveil node:

# From the Clairveil Core repository root:
export CLAIRVEIL_HOME=/tmp/clairveil-dapp-local
export CHAIN_ID=clairveil-local-2
make init
source "$CLAIRVEIL_HOME/clairveil.env"
# Apply the [rpc] CORS edit above before continuing.
clairveild start \
  --home "$CLAIRVEIL_HOME" \
  --minimum-gas-prices 0uclair \
  --api.enable \
  --api.enabled-unsafe-cors \
  --api.address tcp://127.0.0.1:1317

Start the DApp:

cd /path/to/clairveil-samples
npm install
CLAIRVEIL_PROVER_PROXY_ENABLED=1 \
CLAIRVEIL_PROVER_URL=http://127.0.0.1:8080 \
CLAIRVEIL_COSMOS_DEPOSIT_PROVER_URL=http://127.0.0.1:8090 \
CLAIRVEIL_HOME=/tmp/clairveil-dapp-local CHAIN_ID=clairveil-local-2 npm start -- --host 127.0.0.1

This manual form assumes compatible transfer/withdraw and canonical Cosmos deposit provers are already listening on ports 8080 and 8090. Prefer npm run start:local to build and start the complete loopback stack.

Open:

http://127.0.0.1:5173

Public Node Mode

CLAIRVEIL_DAPP_LOCAL_TEST_MODE=0 \
CLAIRVEIL_DAPP_PUBLIC_ORIGIN=https://app.example \
CLAIRVEIL_RPC=https://rpc.example \
CLAIRVEIL_REST=https://rest.example \
CLAIRVEIL_PROVER_URL=https://prover.example \
npm start

In this mode, local signer, faucet, local CLI deposit, and auditor test-secret routes are disabled. Wallet-driven send/deposit/transfer/withdraw/scan/decode still run in the browser through ClairveilJS.

Tests

.github/workflows/test.yml runs web/SDK contract checks and Go helper tests on pull requests and pushes to main. It checks out pinned SDK/Core commits beside the samples. This is automated validation only: it does not deploy the web, start a persistent chain, or run wallet E2E tests.

npm run check:dapp
npm run test:dapp
npm run check:clairveiljs
npm run test:clairveiljs
npm run check:clairveiljs:types
npm run test:release-contracts

npm run verify:release runs the static DApp checks, DApp/SDK integration tests, type checks, and required conformance fixtures. test:release-contracts invokes the SDK's exact-source verifier: it checks the 17-file v0.3.1 lifecycle/wallet snapshot against commit 0ff92839872de26b787a60d8e4d5822cc459855b and the three-file Core v0.4.0 deposit-prover overlay against annotated tag v0.4.0 at commit ca85b02708fdd75259d4d2ee2d671c21198cec69. The DApp does not inject or replace either fixture source. npm run verify:release:integration additionally requires a live local full-flow environment and the payable EVM driver; it fails instead of silently skipping when those dependencies are absent. The required conformance suite covers the canonical deposit wire plus expiry, replay, payload substitution, and duplicate-nullifier rejection.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages