Tappy
An AI agent wallet the agent can't drain. The agent holds one key, and you hold the other on a Flipper Zero. Every transaction is 2-of-2: the agent can propose anything, and nothing moves until a human physically presses the button.
Built for ETHOnline 2026
Agent wallets with spending limits already exist. A policy file is not a person. Tappy's second factor is a thumb.
How it works
you → chat → the agent proposes → agent signs → Flipper shows it → you press OK
↓
human signs → TappyGate.execute() → chain
TappyGate is a ~70-line contract that verifies both signatures over one EIP-712 digest.
Neither key can move funds alone.
Repo layout
| Path | What it is |
|---|---|
apps/hub |
API only: agent loop, proposal store, relayer, the iOS and bridge surfaces (T3 stack) |
apps/bridge |
Node process on the laptop: talks to the Flipper over USB, holds the human key (v1) |
apps/mobile |
React Native client — placeholder, not started |
packages/protocol |
Shared types, EIP-712 digest, the mock signer, the frozen test vector |
packages/contracts |
Foundry: TappyGate, MockToken, MockSwap, MockMerchant |
device/tappy-js |
The Flipper app (JavaScript) |
device/tappy-c |
On-device signing — stretch goal, not started |
docs/ |
SPEC.md, per-person briefs, spike log |
site/ |
The public page, deployed to GitHub Pages — it recomputes the digest in the browser |
Quick start
./scripts/setup.sh # installs pnpm + Foundry, creates .env files, runs the tests
Or by hand:
nvm use # Node 22
pnpm install
pnpm contracts:test # 13 tests, includes the cross-language digest vector
pnpm --filter @tappy/protocol test
Foundry is required for the contracts:
curl -L https://foundry.paradigm.xyz | bash && foundryup
foundryup prints the bin directory to add to your shell profile. It is ~/.foundry/bin on
most machines, but ~/.config/.foundry/bin if XDG_CONFIG_HOME is set — ./scripts/setup.sh
finds it either way.
OpenZeppelin comes from pnpm (foundry.toml remaps it into node_modules), so run
pnpm install before forge test.
You do not need a Flipper Zero to work on this. MockHumanSigner satisfies the same
interface as the real device and can auto-approve, auto-reject, or ask you y/n in the
terminal. Two thirds of the project is built against it.
Who's doing what
| Workstream | Owner | Start here | |
|---|---|---|---|
| A | contracts, protocol, deploys | @IGanjali | brief · issue #4 |
| B | iOS app, hub, agent loop | @ryannzander | brief · issue #2 |
| C | Flipper + bridge | @AnshuPlayz17 | brief · issue #1 |
Three issues are labelled blocker and should be picked up in hour one. Everything else is
labelled by milestone on the issue board.
Where to start reading
docs/HANDOFF.md— if you're picking this up on a new machine, start here.docs/SPEC.md— architecture, contract design, milestones, cut lines, demo script.- Your brief:
contracts·app·device CONTRIBUTING.md— branches, PRs, and the rules that keep three people out of each other's way.
Status
| Milestone | State |
|---|---|
| M0 scaffold, protocol, contracts, mock signer | done |
| M1 gate deployed on Sepolia | not started |
| M2 chat → agent → proposal → tx | not started |
| M3 Flipper in the loop | not started |
| M4 shop, swap, the attack scene | not started |
| M5 Arc + Hedera + Privy | not started |
| M6 on-device signing (stretch) | not started |
Honest limitations
- v1 keeps the human key on the laptop. The Flipper is the approval factor, not yet the
custodian. On-device secp256k1 is verified feasible (~0.1–0.3 s per signature) and specced in
device/tappy-c/README.md, but it needs a C app. See SPEC §1. - The device shows a summary the laptop sends. "What you see is what you sign" is v2.
- A connected laptop can inject button presses through the Flipper's CLI. In v1 the laptop holds the key anyway, so this changes nothing; the C version disables the CLI while running.
Testnet only. Do not put real funds anywhere near this.

Log in or sign up for Devpost to join the conversation.