Documentation
Everything you need to watch your treasury, admin keys and Bitcoin wallets with Wardcrest, and to wire its alerts into the tools your team already uses.
Getting started
- Create an account and confirm your email. Each person can belong to several workspaces; billing, monitors and channels belong to a workspace.
- Add a channel under Channels, email works immediately for your own address; Slack, Discord, Telegram, PagerDuty and webhooks take a minute. Send a test.
- Create a monitor from a template, paste the address and route it to one or more channels with a minimum severity each.
- Turn on two-factor authentication under Settings → Your account, and ask your team to do the same.
Supported chains: Bitcoin, Ethereum, Base, Arbitrum One, OP Mainnet, Polygon PoS, BNB Smart Chain. Each chain is processed at a fixed confirmation depth to avoid alerting on blocks that are later reorganised; if that happens anyway, the affected alerts are retracted and the retraction is delivered to the same channels.
Monitor types
Safe guard
Alerts on every configuration change to a Safe (owners, threshold, modules, guards, fallback handler) and on executed or failed transactions. Detects implementation (singleton) changes even when no event is emitted, and can analyse pending proposals before they execute.
- safe
- Safe address (EVM).
- configChanges
- Owners, threshold, modules, guards, fallback handler. Default on.
- executions / failures
- Executed and failed transactions. Default on.
- moduleExecutions
- Transactions executed by modules, which bypass owner signatures. Default on.
- incoming
- Incoming native transfers. Default off.
- pendingTransactions
- Analyse proposals in the Safe Transaction Service before they execute: decoded calls, delegatecalls, risky approvals, hash recomputation, conflicting nonces. Pro and above.
- driftChecks
- Periodically re-read the singleton, guard and fallback-handler storage so silent changes are caught. Default on.
Contract admin
Watches the admin surface of a contract: EIP-1967 proxy upgrades and admin changes, ownership transfers, AccessControl role grants, pausing and re-initialisation, plus periodic reads of the proxy storage slots so silent changes are caught too.
- contract
- Contract or proxy address.
- upgrades
- EIP-1967 implementation, admin and beacon changes.
- ownership
- Ownable transfers, including two-step pending owners.
- roles
- AccessControl grants, revocations and admin-role changes; privileged roles are critical.
- pause
- Paused and unpaused.
- initialization
- Initialized events, re-initialisation of a live proxy is a classic takeover.
- driftChecks
- Scheduled reads of proxy slots and owner, so changes without events are caught.
Timelock
Decodes operations queued in an OpenZeppelin TimelockController or Compound-style Timelock the moment they are scheduled, so upgrades, ownership transfers and role changes are flagged while there is still time to react.
- timelock
- Timelock contract address.
- scheduled
- New scheduled operations, with the time they become executable, your window to react.
- executed / cancelled
- Operations executed or cancelled.
- adminChanges
- Changes to the delay and to the timelock’s own roles.
Wallet activity
Alerts when funds move in or out of the addresses you list (native coin and ERC-20 tokens) and on any transaction the address sends, including approvals. Filter by direction, token and minimum value; address-poisoning spam is hidden by default.
- addresses
- Up to 100 EVM addresses, each with an optional label.
- direction
- in, out or both.
- assets
- all, native or tokens; optionally restrict to specific token contracts.
- minNative / minUsd
- Ignore movements below a native amount or a USD value (priced from Chainlink).
- anyOutgoingTx
- Alert on every transaction sent from the address, including approvals and contract calls. Default on.
- hideSpam
- Hide zero-value and unpriced airdrops used for address poisoning. Default on.
Bitcoin wallet
Watches Bitcoin addresses or a whole wallet from its extended public key (xpub/ypub/zpub, including Taproot). Defaults to alerting on any spend (a tripwire for cold storage) with optional mempool detection before the first confirmation.
- addresses
- Up to 200 Bitcoin addresses (legacy, P2SH, SegWit, Taproot).
- xpubs
- Up to 5 extended public keys (xpub/ypub/zpub, or tpub-style with an explicit script type). Receive and change chains are scanned with a gap limit of 10–200 (default 20). Keys are encrypted at rest and never shown again.
- direction
- in, out or both (default out, spending from cold storage).
- minBtc
- Ignore movements below this amount.
- mempool
- Alert on unconfirmed transactions, then upgrade the same alert on confirmation. Pro and above.
Balance threshold
Checks a balance on a schedule and alerts once when it crosses your threshold, then re-arms when it recovers. Useful for hot-wallet float, gas wallets and reserve floors.
- address
- Any supported address, EVM or Bitcoin.
- asset
- native, or an ERC-20 contract address on EVM chains.
- condition / threshold
- below or above a whole-unit amount. The monitor fires once, then re-arms after the balance crosses back.
Token flows
Alerts on transfers of a specific token above a size you choose, including mints and burns: for issuers, treasuries and protocol tokens.
- token
- ERC-20 contract.
- minAmount
- Smallest transfer to report, in whole tokens.
- includeMints / includeBurns
- Report transfers from or to the zero address.
- fromFilter / toFilter
- Only transfers from or to these addresses (up to 25 each).
Custom event
Paste an event signature and optional conditions on its parameters. Wardcrest decodes matching logs from the contract and alerts with the decoded values.
- contract
- Contract emitting the event.
- event
- Solidity signature with named parameters, e.g. Transfer(address indexed from, address indexed to, uint256 value).
- conditions
- Up to 5: eq, neq, gt, gte, lt, lte on a parameter. Numbers are raw integer units; addresses and booleans support eq and neq.
Alerts
- Severity:
info,warningorcritical. Templates choose sensible defaults per event (a new Safe owner is critical, an incoming transfer is info); you set a monitor’s baseline severity and each channel’s minimum. - Stage:
pendingfor Safe proposals and scheduled timelock operations that have not executed yet,unconfirmedfor Bitcoin transactions in the mempool,confirmedfor everything in a processed block. - Status:
open,acknowledgedorresolved, set from the inbox or the API. Retracted alerts were undone by a chain reorganisation.
Channels
- Email: addresses outside your team must confirm once, and every alert email has a one-click unsubscribe.
- Slack and Discord: paste an incoming-webhook URL. Only official Slack and Discord webhook hosts are accepted.
- Telegram: Wardcrest gives you a one-time link to its bot; open it in the chat or group that should receive alerts.
- PagerDuty: an Events API v2 integration key. Critical alerts trigger incidents, and a retraction resolves the incident it opened.
- Webhooks: signed JSON to your HTTPS endpoint; see below.
Webhooks
Wardcrest POSTs JSON to your endpoint with three headers: Wardcrest-Signature, Wardcrest-Event (alert.created, alert.retracted or test) and Wardcrest-Delivery (unique per delivery, so you can ignore duplicates). Answer with any 2xx status within 10 seconds; failed deliveries are retried with exponential backoff and every attempt is listed on the alert.
{
"id": "6f1c…", // delivery ID, also in Wardcrest-Delivery
"type": "alert.created", // or "alert.retracted", "test"
"api_version": "2026-09-01",
"created_at": "2026-09-11T09:14:03.120Z",
"workspace": { "id": "…", "name": "Acme Treasury" },
"data": {
"alert": {
"id": "…",
"url": "https://…/app/alerts/…",
"severity": "critical",
"kind": "safe_owner_added",
"stage": "confirmed", // "pending" | "unconfirmed" | "confirmed"
"title": "Owner added to Treasury Safe",
"summary": "…",
"chain": "ethereum",
"monitor": { "id": "…", "name": "Treasury Safe" },
"tx_hash": "0x…",
"block_number": 20931774,
"created_at": "2026-09-11T09:14:02.000Z",
"fields": [{ "label": "New owner", "value": "0x…" }],
"links": [{ "label": "Transaction", "url": "https://etherscan.io/tx/0x…" }],
"risks": [],
"data": {}
}
}
}Wardcrest-Signature has the form t=<unix seconds>,v1=<hex>, where v1 is the HMAC-SHA256 of t + "." + raw body keyed with the channel’s signing secret. Reject requests whose timestamp is more than five minutes old. The secret is shown when you create the channel and can be revealed or rotated from the Channels page.
import crypto from 'node:crypto';
// rawBody: the exact bytes received — verify before parsing JSON.
export function verifyWardcrest(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(signatureHeader.split(',').map((p) => p.split('=')));
const t = Number(parts.t);
if (!Number.isInteger(t) || Math.abs(Date.now() / 1000 - t) > 300) return false; // replay window
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
const got = Buffer.from(parts.v1 ?? '');
return got.length === expected.length && crypto.timingSafeEqual(got, Buffer.from(expected));
}import hashlib, hmac, time
def verify_wardcrest(raw_body: bytes, signature_header: str, secret: str) -> bool:
parts = dict(p.split("=", 1) for p in signature_header.split(","))
t = int(parts.get("t", "0"))
if abs(time.time() - t) > 300: # replay window
return False
expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts.get("v1", ""))Trust pages and badges
Publish a page at /trust/your-name that lists the monitors you choose, their chains and live engine health, optionally with the watched addresses. Embed the SVG badge in your README or docs; it reads monitored, delayed or inactive. Set it up under Settings → Trust page.
Billing
Plans are priced in US dollars and paid in bitcoin, a month or a year at a time. There are no automatic charges: owners get reminders 7 days and 1 day before the end, then 3 days of grace. Current limits: Free 3 monitors, Pro 25, Team 150, Business 500, see pricing for everything else.
Building an integration? Continue with the API reference, or start at the developers hub.