Dambi is an open-source wallet-side transaction and signature policy engine for Web3 signing safety. It maintains a reusable Rust/WASM policy evaluator, declarative EVM calldata and EIP-712 decoder registry, protocol coverage tests, and browser enforcement surfaces so wallet actions can be decoded, reviewed, and evaluated before the user signs.
At runtime, Dambi intercepts wallet RPC in the browser, decodes each transaction, typed signature, or supported venue order into a semantic action, and evaluates that action against a Cedar policy set — warning or blocking before the signature leaves the wallet.
The repository is a hybrid Rust + TypeScript monorepo:
- a Rust/Cedar policy engine compiled to WASM and embedded in the extension,
- a browser extension (Chrome MV3 / Firefox MV2) that hosts that WASM and a policy-management dashboard,
- a stateful Rust backend (
policy-server) for auth, wallets, and predicted state deltas, - a registry (
registryV2) of adapter manifests + token metadata that drives decoding.
Dambi's public contribution surface is the decoder and policy infrastructure, not just the packaged browser extension. Useful contributions include:
- adding or correcting declarative protocol manifests under
registryV2/, - expanding EVM calldata, EIP-712, and venue-order decoder coverage,
- adding real/synthetic regression fixtures for high-risk wallet actions,
- improving Cedar policy schemas and
ActionBodylowering, - hardening fail-closed behavior in the extension service worker and WASM bridge,
- improving release, registry, and security automation.
Start with CONTRIBUTING.md. Security-sensitive reports should follow SECURITY.md. Maintainer roles and merge/release ownership are documented in GOVERNANCE.md.
Current near-term OSS work is tracked through public GitHub issues and milestones. The active focus areas are:
- decoder registry hardening and protocol onboarding review automation,
- policy regression generation for wallet-draining and signature-risk cases,
- Codex-assisted PR review for manifest, schema, and lowering changes,
- release checks for Chrome Web Store and registry bundle publication,
- security review of wallet interception, typed-data normalization, and fail-closed paths.
dApp → window.ethereum ──intercept──▶ extension service worker
│
├─ decode calldata / typed-data (registryV2 manifests)
│ └─▶ ActionBody tree
│
├─ lower ActionBody → Cedar request
│ └─▶ in-SW WASM Cedar eval → Verdict (Pass / Warn / Fail)
│
└─ (optional) policy-server ── predicted StateDeltas, auth, wallets
- The extension intercepts wallet transactions and EIP-712 / personal signatures.
- Decoders (driven by
registryV2manifests) turn raw calldata / typed-data into a typedActionBodytree (see Action model). - The Rust engine lowers that
ActionBodyto a Cedar request and evaluates it against the installed policies — all inside the service worker via WASM. No network round-trip is required for a verdict. policy-serveris the stateful backend: Google OAuth, wallet/account state, and an/evaluateendpoint that returns predictedStateDeltas from the asset-model reducer. The extension owns the final verdict; the server supplies state context.
The version suffixes are protocol names, not "old vs new" — they coexist on purpose and renaming them would churn every call site. What each one means:
| Name | What it is |
|---|---|
ActionBody / v3 decode |
The declarative calldata/typed-data decoder driven by registryV2 manifests (declarative_route_*_v3). "v3" names the decode-registry format. |
v2 evaluation (evaluate_action_v2, manifest_v2) |
The stateless per-request Cedar evaluation: {policy, manifest} bundles + trigger matching + policy_rpc enrichment planning. "v2" names the policy-bundle contract. |
ps2:* |
The extension's policy-storage namespace (account ⊃ wallets ⊃ bindings/packages) and its service-worker message family. The dashboard/popup manage policies exclusively through it. |
verdictSource: "declarative-v2" | "fail_closed" |
Where a verdict came from: a real policy evaluation, or the fail-closed tail (undecodable request, engine fault). fail_closed is a safety semantic, not a legacy marker. |
registryV2/ |
The adapter-manifest registry that feeds the v3 decoder. The registry-api/ proxy fronts its private deployment. |
If you add a new protocol revision, give it a name here and keep the old one documented until it is actually deleted.
| Path | What |
|---|---|
browser-extension/ |
Chrome MV3 / Firefox MV2 extension: service worker (eval), content scripts, popup, confirm page, and the options-page dashboard. See its README. |
browser-extension/dashboard/ |
Standalone Vite + React policy-management UI, also built into the extension's options page. See its README. |
browser-extension/sdk/ |
The @dambi/sdk extension client the dashboard talks to. |
crates/policy-engine/ |
Core runtime: the ActionBody → Cedar lowering, the Cedar PolicyEngine wrapper, and bundled schema composition. |
crates/policy-engine-wasm/ |
wasm-bindgen bridge that exposes the engine (+ typed .d.ts) to the extension. |
crates/policy-server/ |
Stateful backend. Sub-crates: server/ (Axum HTTP), db/, sync/, and the asset-model/{state,action,transition} reducer. See local deploy README. |
crates/adapters/ |
Decode support: abi-resolver (Sourcify-backed ABI lookup) and mappers. |
crates/integration-tests/ |
ActionBody[] decode harness — replays real calldata / typed-data through the production decoders. See its README. |
registryV2/ |
Adapter manifests, token metadata, and the build script that emits the runtime decode index/. |
registry-api/ |
Cloud Run reverse-proxy that fronts the private adapter registry. See its README. |
schema/policy-schema/ |
Cedar schema: core.cedarschema + per-domain action schemas under actions/. |
The authoritative Rust crate list is the [workspace] members in
Cargo.toml.
The policy input is the v3 hierarchical ActionBody tree, defined in
crates/policy-server/asset-model/action (policy-action) and re-exported by
crates/policy-engine as action::v3. An Action is { meta, body } where
meta carries submission info (OnchainTx vs OffchainSig) and body is one
domain variant:
// crates/policy-server/asset-model/action/src/lib.rs
pub enum ActionBody {
Token(TokenAction),
Amm(AmmAction),
Lending(LendingAction),
Airdrop(AirdropAction),
Launchpad(LaunchpadAction),
Perp(PerpAction),
LiquidStaking(LiquidStakingAction),
Permission(PermissionAction),
Yield(YieldAction),
Restaking(RestakingAction),
Staking(StakingAction),
Governance(GovernanceAction),
HyperliquidCore(HyperliquidCoreAction),
Marketplace(MarketplaceAction),
Multicall { actions: Vec<ActionBody> }, // batched (e.g. Universal Router)
Unknown { target, chain, calldata, value }, // unidentified — policy default: warn / deny
}Each domain has a matching Cedar schema fragment under
schema/policy-schema/actions/<domain>/. Multicall recurses (a Universal
Router execution decodes into nested ActionBody entries), and Unknown is the
fail-closed branch for calls no adapter recognizes.
cargo test --workspace # or: scripts/test-all.sh (adds clippy/fmt + extension)
cargo clippy --workspace --all-targets -- -D warnings
cargo fmt --allscripts/test-all.sh runs the full sweep (cargo test + clippy + fmt, then the
extension typecheck / vitest / chrome build); scripts/lint.sh is the
fix-everything counterpart (cargo fmt + clippy --fix + yarn lint).
The
crates/integration-testsdecode harness reads a generated index atregistryV2/index/(a build artifact, not tracked). Regenerate it first:cd registryV2 && npm ci && npm run build
scripts/wasm-build.shRuns wasm-pack build crates/policy-engine-wasm --target web --release and
copies the artifact into browser-extension/backend/wasm/ and
browser-extension/public/wasm/. The extension's yarn prepare:wasm step calls
this script, so a normal extension build picks it up automatically.
A Yarn 4 workspace at browser-extension/ (the dashboard is a nested
workspace). Loadable builds are produced by two pipelines into
dist/<browser>/: webpack (SW / content scripts / popup / confirm) and Vite
(the options-page dashboard).
cd browser-extension
yarn install
yarn build:ext # chrome (webpack) + dashboard (vite) → dist/chrome/
# or, for live dev:
yarn dev:chrome # webpack --watch; run `cd dashboard && yarn dev` alongside for the dashboardBuild-time config is via env vars — most importantly DAMBI_SERVER_URL (the
policy-server the extension calls; default http://127.0.0.1:8788) and
REGISTRY_BASE_URL. See browser-extension/README.md
for the full matrix, load instructions, and the local-server workflow.
cp .env.local.example .env.local # fill JWT_SECRET, GOOGLE_*, DATABASE_URL, …
scripts/start-policy-server.sh local # = cargo run -p policy-server --bin policy-server
# or via the root package.json:
yarn server:local
curl http://127.0.0.1:8788/readyzstart-policy-server.sh <profile> loads .env.<profile> then runs the server;
local targets the dashboard at http://127.0.0.1:5173, ext targets the
in-extension OAuth flow. For a prod-like local Kubernetes loop see
crates/policy-server/server/deploy/local/README.md
(scripts/policy-server-local-k8s.sh).
.github/workflows/ci.yml runs on every PR and
push to main; new pushes cancel the previous in-flight run for that branch.
rust and wasm run in parallel; extension waits only on the wasm pkg
artifact.
- rust — builds the
registryV2index (npm), thencargo fmt --check,cargo clippy -D warnings,cargo test(doctests included), andcargo docwith-D warnings. - wasm —
wasm-pack build crates/policy-engine-wasm(artifact reused by the extension job) and headless-Chromewasm-bindgentests. - extension —
yarn typecheck, vitest, Chrome MV3 build + zip, the dashboard build (uploaded per-PR so reviewers can sideload). Firefox MV2 build/zip runs onmainonly. - secrets-scan — gitleaks over the full history.
dependency-policy.yml (cargo audit + cargo deny) runs when dependency files change and weekly.
To reproduce the suite locally, run cargo test (with the registry index built,
above) and cd browser-extension && yarn test.
Cedar evaluates against calldata-derived primitives plus optional remote facts.
A policy bundle may ship a .policy-rpc.json manifest that declares which
backend method supplies a fact (e.g. a USD valuation), which params to send, and
which response field is projected into the Cedar context. The extension asks
WASM to plan those calls, sends them to policy-server, then asks WASM to
materialize the responses and evaluate Cedar. The engine itself performs no
direct oracle / balance / allowance lookups.
Licensed under the Apache License, Version 2.0. See LICENSE and NOTICE.