wardcrest
On this page

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, warning or critical. 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: pending for Safe proposals and scheduled timelock operations that have not executed yet, unconfirmed for Bitcoin transactions in the mempool, confirmed for everything in a processed block.
  • Status: open, acknowledged or resolved, 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.

Payload
{
  "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.

Node.js
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));
}
Python
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.