Skip to content

feat: add dshield CLI + shared @dshield/core package - #159

Merged
tech-adrian merged 2 commits into
Dshield-xyz:devfrom
AJtheManager:deposit
Aug 30, 2026
Merged

feat: add dshield CLI + shared @dshield/core package#159
tech-adrian merged 2 commits into
Dshield-xyz:devfrom
AJtheManager:deposit

Conversation

@AJtheManager

Copy link
Copy Markdown
Contributor

Every DShield interaction previously required the Next.js frontend and a
browser-based wallet. This PR adds a dshield command-line client so power
users, integrators, and CI can script deposits, withdrawals, note management, and
compliance reports with no browser.

To satisfy the "no parallel reimplementation" requirement, it also extracts the
note / commitment / Merkle / proof / format logic into a new shared
@dshield/core package that both the frontend and the CLI consume. A note
minted by the CLI is spendable in the app and vice-versa, because they run the
exact same code.

A full deposit → withdraw cycle can be completed against a local/testnet
deployment using only the CLI
, no browser.

What changed

New: packages/core (@dshield/core)

Isomorphic (browser + Node), no localStorage / window / app-route fetch:

  • poseidon2.ts — Poseidon2 hasher, commitment / nullifier / KYC / recipient
    hashing, Merkle-tree builder.
  • notes.ts — the note codec: serializeNote/parseNote, compact link
    encoding, ShieldedNote, PENDING_LEAF_INDEX, generateRandomField,
    parseNotes.
  • prover-core.tsrunProof (Noir witness execution + UltraHonk proving).
  • prover.ts — circuit JSONs + witness builders + proveWithdrawal /
    proveCompliance / proveDisclosure.
  • report.tscomputeReportIdentity + formatReportText + ComplianceReport.
  • format.tsusdcToStroops, formatAmount, decimals/symbol.
  • Canonical copies of the four circuit JSONs + unit tests.

New: cli/ (@dshield/cli, bin dshield)

Commander-based CLI that runs its TypeScript source through tsx (no build
step). Commands:

  • dshield deposit --amount <usdc> [--dry-run] — shields USDC, prints a note.
    --dry-run builds + stores the note offline (no network/signing). On test
    networks it can mint test USDC via the issuer key to cover the deposit.
  • dshield withdraw (--note | --commitment) [--to] [--amount] — full or partial
    withdrawal with a real zero-knowledge proof; re-shields the remainder.
  • dshield notes list | export [--out] | import <input> — local note store.
  • dshield compliance disclose (--note | --commitment) [--out] [--offline]
    the on-chain compliance report (recomputes the commitment/nullifier and
    confirms deposit + withdrawal status), never embedding the note itself.

Wallet handling is distinct from the browser wallet-kit flow:

  • a local keypair (--secret-key / DSHIELD_SECRET_KEY / ~/.dshield/key /
    config), or
  • an external / hardware signer via --sign-with <command> (unsigned XDR on
    stdin → signed XDR on stdout).

Config resolves from flags → DSHIELD_* env → ~/.dshield/config.json
frontend/.env.local (deployment output, auto-detected) → defaults. Notes and
keyfile live under ~/.dshield. Full docs in cli/README.md.

Changed: frontend/ now consumes @dshield/core

  • poseidon2.ts, prover-core.ts, format.ts become thin re-exports of core.
  • notes.ts, prover.ts, report.ts import their shared halves from core and
    keep only the browser-specific parts (localStorage store, Web Worker, on-chain
    report assembly). App pages/components are unchanged — the @/lib/* public
    APIs are preserved.
  • @dshield/core is linked from source via a link: dependency +
    transpilePackages (Turbopack) in next.config.ts.

Workspace + CI

  • Root pnpm-workspace.yaml / package.json cover packages/* + cli
    (frontend/ intentionally keeps its own workspace + lockfile).
  • New CI cli job: typecheck, unit tests, dshield --help, and an offline
    dry-run deposit against a local home dir.
  • lint / frontend jobs additionally run a root install (so @dshield/core's
    runtime deps resolve) and refresh core's copy of the compiled hasher.json.

Acceptance criteria

  • Full deposit → withdraw cycle via the CLI alone, no browser. deposit,
    withdraw, notes, and compliance disclose mirror the frontend's exact
    Soroban contract calls and note lifecycle.
  • CLI reuses the frontend's note/commitment/proof logic — verified by
    @dshield/core existing and both the app and CLI importing it (no duplicated
    crypto). A CLI test asserts a deposited note's commitment equals
    core.computeCommitment(...).

Testing

  • @dshield/core: 18 unit tests (hashing parity vs the Noir fixture, note
    codec round-trips, witness mapping).
  • @dshield/cli: 8 tests (command parsing/help/version, offline dry-run deposit,
    notes import/list/export round-trip).
  • frontend: 153 unit tests pass; pnpm lint clean; next build succeeds
    consuming core from source.
  • CLI smoke: dshield --help and an offline dry-run deposit verified locally.

Notes / follow-ups

  • frontend/package.json gains a single link: dependency and next.config.ts
    gains transpilePackages — the minimum needed for the bundler to compile core
    from source; the frontend workspace root and CI install directory are otherwise
    unchanged.
  • compliance disclose produces the shipped on-chain report. The ZK
    threshold-disclosure proof is wired in @dshield/core (proveDisclosure) but
    not yet exposed as a CLI command.
  • A live deposit → withdraw against a network was not run in this change; it is
    exercised by the e2e job / just deploy + the new CLI commands.

closes #140

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feature: dshield-cli for scripted deposit/withdraw/compliance

2 participants