Wallet-side transaction & signature policy engine. dambi intercepts wallet RPC in the browser, decodes each transaction or EIP-712 signature into a typed semantic action, and evaluates that action against a Cedar policy set — warning or blocking before the user signs.
The repo 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.
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.
MIT.