Skip to main content

ownerwatch

ci release license

Self-hosted monitor that alerts you the moment the admin surface of your EVM contracts changes.

Most protocol losses in 2025-2026 started with a key, a role or a proxy changing hands, not with a clever exploit. ownerwatch watches the events that mean "someone just gained control" and pushes them to Discord, Slack, Telegram or any webhook within seconds. No account, no SaaS, no third party holding your contract list. One YAML file and a Docker container.

What it watches

Every address in your config gets the full catalog:

Standard Events Severity
Ownable / Ownable2Step OwnershipTransferred, OwnershipTransferStarted critical / high
AccessControl RoleGranted, RoleRevoked, RoleAdminChanged high / critical
ERC-1967 proxies Upgraded, AdminChanged, BeaconUpgraded critical
Pausable Paused, Unpaused medium
TimelockController CallScheduled, CallExecuted, Cancelled, MinDelayChange high / critical
Legacy Timelock (Compound, Uniswap and forks) NewAdmin, NewPendingAdmin, NewDelay, QueueTransaction, ExecuteTransaction, CancelTransaction medium to critical
Governor (OpenZeppelin and GovernorBravo) ProposalCreated, ProposalQueued, ProposalExecuted, ProposalCanceled, VotingDelaySet, VotingPeriodSet, ProposalThresholdSet, QuorumNumeratorUpdated, TimelockChange, NewImplementation medium to critical
Aragon OS (Lido and others) SetApp, SetPermission, ChangePermissionManager, StartVote, ExecuteVote medium to critical
Safe AddedOwner, RemovedOwner, ChangedThreshold, EnabledModule, DisabledModule, ChangedGuard, ChangedFallbackHandler, ExecutionFromModuleSuccess, ExecutionSuccess, ExecutionFailure info to critical
ERC-20 treasuries Transfer out above a threshold you set high
NFT treasuries Any ERC-721 or ERC-1155 transfer out high
Native balance ETH balance of a treasury falls by more than a threshold between polls high

Safe queues. Add a Safe under safes: and ownerwatch polls the Safe Transaction Service: you get an alert when a transaction is proposed, and a critical one when it has collected enough signatures to execute. That is the moment to act; the on-chain events above are the record of what already happened.

Timelock and Safe-queue alerts show the call being made: full function and arguments when the target is verified on Sourcify, otherwise the signature from the openchain and 4byte databases, otherwise the raw selector. Set explorer_url and every alert carries a clickable transaction link.

Run ownerwatch events to print the catalog.

Quick start

pip install git+https://github.com/imal1ice/ownerwatch
cp config.example.yaml config.yaml   # add your contracts and a Discord/Telegram target
ownerwatch run --config config.yaml

Or with Docker:

docker compose up -d        # uses ./config.yaml, keeps state in a named volume

A hardened systemd unit is in deploy/ownerwatch.service.

Several chains in one process: put shared settings at the top level and a chains: list underneath, see examples/multichain.yaml.

Don't know what to watch? Point probe at your main contract and it walks the owner/admin/proxy chain, tells you who can upgrade or pause it, flags EOAs and 1-of-N Safes, and prints a config:

ownerwatch probe --rpc https://eth.drpc.org --safe-chain eth --label Acme 0xYourProxy 0xYourSafe
ownerwatch probe --rpc https://eth.drpc.org --roles-from-logs 0xAccessControlContract   # every current role holder, replayed from logs since deployment
ownerwatch probe --config config.yaml --markdown --label Acme > admin-surface.md   # monthly report of everything you watch; set probe_rpc_url per chain if rpc_url rejects eth_call

--roles-from-logs finds the creation block on Sourcify and reads the history from a free public log gateway on Ethereum, Optimism, Arbitrum, Gnosis and Polygon; on Base (and for any chain without one) pass --logs-rpc with an RPC that serves wide eth_getLogs ranges, or --from-block to bound the scan.

Want that check in CI? examples/github-action-drift.yml re-probes weekly and fails when a signer, delay or proxy admin changes from the committed report.

</code></pre>
<p>Other commands:</p>
<pre><code class="language-bash">ownerwatch validate                         # check the config, the RPC and that every address has code
ownerwatch test-alert                       # push a test message through your sinks
ownerwatch run --once                       # single scan, for cron
ownerwatch backfill --from-block N --to-block M   # replay history, prints what you would have seen
ownerwatch events                           # list the catalog

See docs/what-to-watch.md for the control-graph model behind the catalog, and docs/sample-alerts.md for real alerts replayed from mainnet history.

Examples

examples/ has verified configs for Uniswap, Compound, Arbitrum, Aave and the Optimism Foundation Safe on mainnet. Backfill one to see what alerts look like on real history:

ownerwatch backfill --config examples/aave-mainnet.yaml --from-block 22000000 --to-block 22050000

How it works

  • Polls eth_getLogs for the catalog's topic hashes on your addresses, in chunks that fit public RPCs.
  • Waits confirmations blocks behind the head so small reorgs don't produce ghost alerts.
  • Persists a block cursor to state/, so a restart resumes where it left off with no duplicates.
  • Alert delivery never stops the poller: a dead webhook is logged and skipped.
  • Set heartbeat_url to a dead-man's-switch (healthchecks.io or similar) and you get paged when ownerwatch itself stops polling. Quiet and dead must not look the same.
  • Works on any EVM chain, one process can watch several.

Hosted tier

Don't want to run it? I run it for you, per chain, paid in USDC on-chain through contracts/src/Subscriptions.sol: approve, call subscribe(periods, chains, maxCost, configRef), send me the config. No invoices, no accounts, no KYC either way. Details in docs/hosted.md. Deployment address will be listed here once live; until then open an issue. The operator side is ownerwatch hosted --rpc ... --subscriptions 0x... --configs configs/: it starts a watcher for every address with an active subscription and stops it when the subscription lapses.

cd contracts && forge install foundry-rs/forge-std --no-git && forge test

Roadmap

  • Native balance and NFT alerts for Safe queues (currently on-chain only)

Support the project

ownerwatch is free and MIT licensed. If it saves you a 3am incident, fund the work:

Need it deployed, extended or integrated with your alerting stack? Open an issue or reach out on GitHub.

Development

python3 -m venv .venv && .venv/bin/pip install -e . pytest
.venv/bin/pytest        # end-to-end test against a local anvil node; needs foundry

Services

ownerwatch is free and self-hosted. If you would rather have someone do the work:

  • Admin-surface review: every owner, proxy admin, role holder and Safe signer in your deployment, replayed from logs, with a written report and a ready-to-run ownerwatch config. Flat $400 in USDC, delivered within 48 hours.
  • Hosted monitoring: I run ownerwatch for you on a dedicated server with a heartbeat check, and alert your Discord, Slack or Telegram. $300 per month per chain, paid in USDC on-chain. Offered to teams already running the self-hosted version.

Contact: imal1ice@proton.me. Wallet for payments: 0x874D018623EeBb398B898AC7AB0c97506244141B.

Metadata

Release files for ownerwatch 0.7.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ownerwatch 0.7.3
File Size Uploaded Provenance
ownerwatch-0.7.3.tar.gz 43.5 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for ownerwatch 0.7.3
File Interpreter ABI Platform
ownerwatch-0.7.3-py3-none-any.whl Python 3 none any Details

Total release size: 79.7 kB

Release files / ownerwatch-0.7.3.tar.gz

Download URL ownerwatch-0.7.3.tar.gz
Size 43.5 kB
Tags Source
SHA-256 checksum
How to use checksums
464690f7db25b4db61b22917553cd89e326d06235be7425b546a23b480535491
BLAKE2b-256 checksum
How to use checksums
79e8b1ad42660ac1bd768cdaec8a7cd42728d47a774ddb85d533c5b418a411ad
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

Release files / ownerwatch-0.7.3-py3-none-any.whl

Download URL ownerwatch-0.7.3-py3-none-any.whl
Size 36.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0686f432cbc477ca3aeb55d369ec1164706b02357af053b3c91f45576b45109c
BLAKE2b-256 checksum
How to use checksums
1913a61695a4bde82cbba6c76efde303de0be205d80bf8ecb8c79c8b70f80a5a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

Security for ownerwatch 0.7.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for ownerwatch-0.7.3.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.7.3 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page