Skip to content

Repository files navigation

Onay: local signing companion

A second, independent check on every transaction before you sign.

Ethereum is built to be verifiable, and verification is cheap. Yet most users still sign transactions without independently checking what they approve. Onay makes that second check seamless: it verifies the transaction locally, explains what it does, and lets you compare against your wallet before signing.

Onay is a local desktop app with a thin browser extension that sits between the dapp and the wallet. It intercepts the signing request, verifies chain state through an embedded Helios light client, recompiles and verifies the source code locally, simulates the transaction, renders its intent in readable form with ERC-7730 clear signing, and finally displays the ERC-8213 calldata digest for an equivalence check with the wallet. Onay is view only: it holds no keys and does not replace your wallet.

The plan of record is PLAN.md.

What is in this repo

Folder What it is
app/ The desktop app (Tauri). The web user interface is in app/src/, the Rust side in app/src-tauri/. Also holds the relay (app/relay/) and the code that relay and app share (app/ipc/).
extension/ The Chrome extension (Manifest V3). No runtime dependencies.

Prerequisites

  • Node.js 22 or newer and pnpm. The exact pnpm version is pinned in package.json; pnpm switches to it automatically.

  • Rust through rustup. The compiler version is pinned in app/rust-toolchain.toml; rustup installs it on first use.

  • Google Chrome or Chromium, installed as a normal package. Snap and Flatpak browsers cannot start the relay.

  • Linux only: the Tauri system libraries.

    sudo apt install libwebkit2gtk-4.1-dev libdbus-1-dev build-essential curl wget file libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev
    
  • macOS only: the Xcode Command Line Tools (xcode-select --install).

Then install the JavaScript dependencies once, from the repo root:

pnpm install

Development

1. Run the app

pnpm --filter app tauri dev

This builds the relay, starts the web user interface with hot reload, compiles the app, and opens its window. At startup the app does two things:

  • It writes the native messaging host manifest for each installed browser, for example ~/.config/google-chrome/NativeMessagingHosts/dev.sourcify.onay.json. The manifest points to the relay in app/target/debug/.
  • It opens a Unix socket at $XDG_RUNTIME_DIR/onay/onay.sock (Linux) or $TMPDIR/onay/onay.sock (macOS).

The window lists both under "Browser link".

2. Load the extension

pnpm --filter extension build
  1. Open chrome://extensions and turn on "Developer mode".
  2. Click "Load unpacked" and select extension/dist.
  3. Check that the ID is jhopbgoicoiceialjejgojebmeijklbn. The app accepts only this ID. The key field in extension/manifest.json keeps it the same on every machine.

After a code change, build again and click the reload icon on the extension card.

3. Test the link

Click the Onay icon in the Chrome toolbar and press "Ping the app". The popup shows "The app answered", and the app window shows the ping and the pong under "Messages". If you quit the app and ping again, the popup says that the app is not running.

Checks

Run these before you push. Continuous integration (CI) runs the same commands.

Command Where What it does
pnpm -r build repo root Type-checks and builds the mock, the app's web user interface, and the extension.
pnpm -r lint repo root Runs oxlint.
cargo test app/ Runs the Rust tests, including one that drives the real relay binary.
cargo clippy --all-targets -- -D warnings app/ Rust lints.
cargo fmt --all --check app/ Rust formatting.
cargo deny check app/ Advisories, licenses, and sources of the Rust dependencies. Install once with cargo install --locked cargo-deny.

Production

Nothing is published yet. These commands produce the same artifacts a release will ship. Signing, notarization, and the release pipeline are tracked in issue 15.

The app package

pnpm --filter app bundle

This builds the relay in release mode, copies it to where Tauri expects an extra binary, and runs tauri build with the settings in app/src-tauri/tauri.bundle.conf.json. The packages land in app/target/release/bundle/:

  • Linux: a .deb in deb/ and an .rpm in rpm/.
  • macOS: Onay.app in macos/ and a .dmg in dmg/.

The package contains two binaries side by side: onay (the app) and onay-relay. To install and run on Debian or Ubuntu:

sudo apt install ./app/target/release/bundle/deb/Onay_0.0.0_amd64.deb
onay

Start the app once after installing. The first start writes the host manifest, now pointing to the installed relay (/usr/bin/onay-relay).

The extension package

pnpm --filter extension package

This writes extension/onay-extension.zip for the Chrome Web Store. It is the same code as the development build, without the key field in the manifest, because the store rejects it.

To keep the extension ID that the app accepts, the first upload to the store must include the private key as key.pem in the root of the zip. That key is extension/key.pem, which is not in the repo. After the first upload the store holds the key, and later uploads do not need it.

Development and production side by side

There is one host manifest per browser, and each start of the app overwrites it. The app you started last is the one the extension reaches. To switch back to the development build, start it again with pnpm --filter app tauri dev.

How the parts talk

web page -> extension -> Chrome -> relay -> app
                       (starts it)  (Unix socket)
  • The extension asks Chrome to connect to the host named dev.sourcify.onay.
  • Chrome reads the host manifest, checks that the extension ID is allowed, and starts the relay.
  • The relay connects to the app's socket and copies bytes in both directions. It does not read the messages.
  • No network port is opened at any point.

License

GPL-3.0-only.

User experience mock

The mock/ folder holds a clickable mock of the first release with fake data. It is live at sourcifyeth.github.io/onay. To run it locally: pnpm --filter mock dev.

About

Local signing companion: a second, independent check on every transaction before you sign

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages