A QA engineer that understands crypto and wallets.

Every flow of your dApp tested on forks, including the odd cases real users run into.

How it works

  1. Finds the flows that move money and writes a test for each: a goal, an expected result, short steps.

  2. Write your own tests or edit the ones it wrote. Say what should happen in plain words, and an LLM checks it on every run, not just a fixed script.

  3. Runs every test with its own wallet on a local fork. Real contracts.

    EthereumBaseArbitrumOptimismPolygonBNB ChainForks of six chains today
  4. Replays each flow the way users break it: rejected, wrong network, switched account, slow RPC.

  5. Runs again from CI on every commit or release, and every day on your live app. When a test stops passing, you hear about it in Slack, Telegram or email.

In CI

Runs on every change.

The same tests from the CLI or a GitHub Action, with JUnit, JSON and Markdown reports.

$ dappdrill run --unhappy

Running 14 tests on https://harborvault.xyz

✓Deposit hUSDC into the vault41s

✓Withdraw hUSDC38s

✓Withdraw half of the deposit35s

✓Claim the deposit bonus22s

✓Get test hUSDC9s

✓Connect a wallet6s

✗Deposit hUSDC into the vault · Rejected in wallet17s

The Deposit button stays on “Confirming…” after the wallet rejects.

✓Deposit hUSDC into the vault · Slow RPC58s

✗Deposit hUSDC into the vault · Wrong network12s

The deposit was sent without asking to switch networks.

✓Deposit hUSDC into the vault · Switched account24s

✓Deposit hUSDC into the vault · Not enough gas14s

✓Withdraw hUSDC · Rejected in wallet16s

✓Withdraw hUSDC · Slow RPC52s

✗Withdraw hUSDC · Not enough gas13s

Clicking Withdraw does nothing and shows no message.

11 of 14 passed, 3 failed. Videos and screenshots: dappdrill-out/artifacts

.github/workflows/dappdrill.yml

- uses: dappdrill/dappdrill/.github/actions/dappdrill@main
  with:
    url: ${{ steps.preview.outputs.url }}
    unhappy: "true"

The contract

Audited, fuzzed, proven, bountied.

  • Audits
  • Fuzzing and invariant tests
  • Formal verification
  • Bug bounties after launch

The screen

Clicked through by hand, the day before release.

  • What happens when the user rejects?
  • Wrong network? A switched account?
  • Two wallets installed?
  • A slow RPC?

On live frontends

Most bugs aren’t attacks. They’re a real user doing something unexpected.

  1. Compound / Slow RPC

    One click sent two deposits.

    two supply() calls, 6 ms apart

    Supply
    1 clicksupply() ×2
  2. Compound / Two wallets

    The user picked MetaMask. The app talked to Rabby.

    EIP-6963 choice ignored

    dApp
    MetaMask picked
    Rabby used
  3. pod / Wrong network

    Sign-in hangs on “Connecting…” forever.

    no switch prompt, no message

    Connecting…3:02

Found by DappDrill on live frontends, run on local forks, November 2026. Each finding checked by hand.

Paste a URL. Get a bug report.

We let teams in a few at a time, and write to you when there’s room.