Security, audit and contract status
Will & Key is live software with an immutable contract. Its current version has internal tests and reviews by AI agents, and no completed independent audit. Verify the evidence before using it.
Deployments on Base
| Contract | Address | Status |
|---|---|---|
| InheritanceVault, version 2 | 0xA07b59d9249A996604A5fF482f1E564EdeE3A774 | Live since 28 September 2026 |
| InheritanceVault, version 1 | 0xC821849A1D74959753450409b594b23eCE7fEe2f | Retired: new vaults refused (see version 1) |
| Reminder billing | 0x60749aF621180de1DC05DB4f3d158D09dE979dC6 | Retired: every payment reverts |
Version 2 was deployed on 28 September 2026 in Base block 51900754, transaction 0x4bbd4b1d74924f64e0c817ff1815ade20a0141094c091003ec1f527b86413e8e. Its constructor set the administrator and the fee recipient (the Ledger key 0x883C821103B5415C53B11E584D3592205B5CdCA3 for both) and the claim fee (0.5%), and fixed for the life of the contract the tokens a vault can hold: USDC, WETH, cbBTC and EURC, with WETH as the wrapped native token (see which tokens). The administrator, the fee recipient and the fee can change later only as described under administrator powers; the token list cannot change at all.
Paid reminder sales are disabled on this website and, since 26 September 2026, on chain as well. The administrator set the retired billing contract's monthly price to the largest value the contract can store, so every payment to it now reverts and it records no new paid time. Only the administrator could reverse that. The transaction, in Base block 51,823,544: 0xf3485b1b4ec0f887838a2eec5181c3815e68913bc23b68570c3b635693a56cca. The reminder service it once paid for no longer runs. Do not send funds to it or call it directly. Refund requests for earlier payments are handled under the terms.
Bytecode evidence
Version 2's runtime bytecode, read from Base after its deployment on 28 September 2026, and its source:
- Version 2 keccak-256 of the runtime bytecode (EXTCODEHASH): 1b3c172193ad01100daefcbd31e16682210462a7455a50908e65c72b2d077f1b
- Version 2 SHA-256 of the raw runtime bytes: 959da8425b7446a5a50748fd193c930722e0b2786ce500f0c529a59dd6c89f32
- Version 2 source:
contracts/InheritanceVault.solin the source repository, 21,119 bytes of runtime code when compiled. The address's Contract tab on Basescan shows whether that source has been verified against the deployed bytecode.
Version 2 has one immutable variable: the wrapped native token's address (WETH), which the
deployment writes into the runtime code. So the code on chain is the compiled runtime with that
address filled into one 32-byte slot, whose position is in the compiler output
(immutableReferences). Basescan's verification allows for it; to compare by hand, fill
the slot first.
The retired contracts have no immutable variables, so their compiled runtime and their on-chain code are the same bytes. On 10 August 2026 both were compared byte-for-byte with the local compiler artifacts and matched, and both are source-verified on Basescan. Their fingerprints, re-read from Base on 26 September 2026:
- Version 1 keccak-256 of the runtime bytecode (EXTCODEHASH): 26a231771f3b5e7de6a09b3cd5a3e0d03fb5985d69b9bc4973db5f1e41af9733
- Version 1 SHA-256 of the raw runtime bytes: 89ca53b6aaea87fba5e3e0df7019b316f8a44304ef64569ea5a4978c4f9e4d60
- Retired reminder keccak-256 of the runtime bytecode (EXTCODEHASH): 67f23ec7a57f27c4c024c82ac45ef0e3a76e535b4f8224f2ce1de21c8029aec1
- Retired reminder SHA-256 of the raw runtime bytes: f2c577fd64b9038127473e87bb1c9981497962e36fde0b82f67465bf92e4bb61
Earlier versions of this page labelled the two keccak-256 values as SHA-256. The values were
right; the label was wrong. To reproduce any of them with Foundry's cast, replacing
ADDR with a contract address:
- keccak-256:
cast keccak $(cast code ADDR --rpc-url https://mainnet.base.org) - SHA-256 of the raw bytes:
cast code ADDR --rpc-url https://mainnet.base.org | sed 's/^0x//' | xxd -r -p | sha256sum
Hashing the hex text instead of the bytes gives a different SHA-256 value. The build settings of
all three contracts are Solidity 0.8.28, optimizer on with 200 runs, EVM target cancun. The
source repository
contains compiler settings, deployment records, tests, audit scope and the review reports. Version
1's deployed source is contracts/InheritanceVault.sol at the tag v1-base; a
renamed copy, so that both versions compile side by side, is kept as
contracts/v1/InheritanceVaultV1.sol.
Administrator powers
The administrator (owner) of all three contracts, and the fee recipient of both vault contracts, is a single Ledger hardware-wallet key, 0x883C821103B5415C53B11E584D3592205B5CdCA3. It is one key, not a multisig; moving administration to a multisig is recommended. Version 2 named it in its constructor, so it has held both roles there since the deployment on 28 September 2026, and the key that sent the deployment never held either. On version 1 and the billing contract it took over from the deploy key on 24 September 2026, in five transactions:
- Version 1 fee recipient set to the hardware wallet: 0x83f734ad7bf258d2d6daf64f64bb7562565d199ea0d506ae1e45fe2c5851e894
- Version 1 ownership transfer started: 0x29bc7cdd3ea9bc5b611645a231d22515d536e1bbf2ac42aa134041e875343f06
- Reminder contract ownership transfer started: 0x556b174a26f670fe481d08d6fef92cdaae8b789ae728effc8c462d962ddd0527
- Version 1 ownership accepted: 0x5a0bb97d2d421eccc399b6727c49ea37c008a0a7bb782d53cf5a59d1ce85d532
- Reminder contract ownership accepted: 0xff034fda9c4065a5dfa6579fa6afba3c6fb6be55da2c5b71ea323780077fd906
On the version 2 vault contract the administrator can do exactly this:
- pause or unpause new vault creation (
setCreationPaused). The pause blocks only vault creation. Top-ups, check-ins, withdrawals, claims, finalization and payouts keep working, so it cannot stop deposits into existing vaults; - change the global claim fee (
setClaimFee), within the 1% hard cap. A cut applies at once and cancels any pending raise. A raise is only announced: it takes effect 30 days later, and never lifts a vault above its creation-time ceiling. The permissionlessapplyClaimFeeonly records a raise whose 30 days have passed; - change the fee recipient (
setFeeRecipient). Removing it stops fees at once, pending claims included. Setting one again after a period with none takes effect 30 days later. The addresses the contract refuses as payouts are refused here too; - sweep surplus (
sweepSurplus), in ETH or a listed token only: the contract's balance above the vault balances and credits accounted in that asset; - transfer administration in two steps (
transferOwnership, thenacceptOwnershipby the new address). Renouncing it is disabled.
It cannot add or remove a token, take anything from a vault balance or credit beyond the settlement fee, change a beneficiary or any vault setting, cancel an owner withdrawal, block a valid claim settlement, raise a vault's fee above its creation-time ceiling, or make a raise, or a switch of fees back on, take effect in less than 30 days. Those limits are arithmetic in the bytecode, not promises. They rest on the fixed token list, whose tokens each live at one address and never change a balance on their own, and on every token payout, and every ETH payout to an address with code, being measured. They describe Will & Key, not token issuers: the issuers of USDC, EURC and cbBTC can pause, blocklist or upgrade their tokens, and so freeze every vault in that token at once, because all vaults in a token share one balance at the vault contract.
On version 1 the same key can pause or unpause creation, change the claim fee at once with no delay, change or unset the fee recipient, sweep surplus in any token, and transfer ownership in two steps. On the retired reminder contract it can change the price, withdraw its balance and transfer ownership.
Known limits of version 2
These are part of the design, disclosed rather than fixed. The mechanism page explains each one.
- No alerts. Will & Key sends no alerts of any kind: nobody will notify you if your timer expires or a claim is filed, and nobody notifies your heir.
- What cancels a claim. A check-in or a top-up does not cancel a pending claim. Before the horizon, Veto claim and a few other owner actions do; at or after it, only extending the horizon or withdrawing everything does.
- Finalizable is not final. Until a finalize transaction is mined, the owner's key can still cancel a claim whose window has ended. Heirs should finalize promptly.
- The heir's cancel. An heir can correct a payout address by cancelling and filing again, but safely only before the claim becomes finalizable, and a stolen heir key can use the same route to redirect the payout until settlement (the costs).
- The horizon is a long-stop, not a guaranteed payout date. Check-ins stop moving the deadline once it reaches the horizon, and an heir named at or after the horizon can claim at once (the horizon).
- Fees. Only a ceiling is fixed at creation, and a cut helps a claim only if it is still in force at settlement; see how the rate is set.
- Credits. After 30 days anyone may push a credit to its address, and the 30 days run per address, not per credit (credits).
- Payout addresses. The contract refuses a known list of addresses that could never pass a payout on, but no rule can recognise every such contract. Pay to an ordinary wallet.
- Check-in chain. Advanced, with no app support. A chain check-in is safe only if it is mined strictly before the deadline, because from then on the heir can claim first, and the chain's values are bearer credentials that can postpone the heir up to the horizon.
- Network inclusion. A veto must be included on chain in time. On Base a transaction can be forced in through Ethereum if the sequencer is down, which can take up to about 12 hours, so we recommend challenge windows of at least 14 days.
- Token issuers can freeze USDC, EURC or cbBTC for every vault at once.
- The creation pause stops only new vaults. Existing vaults keep accepting top-ups, so in a migration owners would be asked to withdraw in full, which closes the vault.
The retired version 1
Version 1, 0xC821849A1D74959753450409b594b23eCE7fEe2f, was the live vault from 9 August 2026 until 28 September 2026. It is immutable, so it could not be fixed or switched off. It was retired instead:
- New vaults are refused. The administrator paused its vault creation
(
setCreationPaused(true), transaction 0x195ddeb6ec795a327c430e772ab5239a10b4a682f172b10fefd41cfb2af647c7). Only the administrator could unpause it. - It held no user funds. Read from Base on 27 September 2026 (block 51,853,299): one vault had ever been created on it, the project's own test, since closed; it had no open vault; and its only balance was a 0.00002 ETH credit owed to the project's former deploy key, with none of the four tokens. With creation paused, new value could enter a version 1 vault only as a top-up of a vault that is still open.
- Credits can still be withdrawn. The pause does not affect
withdrawCredit, which anyone owed a version 1 credit can call on Basescan's Write Contract tab for that address. - The audit's findings still apply to it. Every contract behaviour the preliminary audit reported is still present in version 1 (the first row of results in numbers). Among them: it accepts any token, so the administrator's sweep can take deposits in a token that has two addresses (F01); check-in chain values can be reused across vaults (F02); payouts are all-or-nothing (F04); and fee changes apply at once (F06). They matter only for value in version 1. Do not send it funds.
Review and testing
- Version 1 shipped with 63 passing Hardhat contract tests. In August 2026 an internal adversarial review, run by the same system that wrote the code and not independent, fixed ten contract defects before it was deployed.
- In September 2026 a preliminary audit by AI auditing agents, at the project's request and not independent, reported 47 findings with executable evidence against version 1.
- Version 2 was written in response. Each of its contract fixes has a regression test that fails on version 1. Five fix-review rounds then raised 48 further issues, and a pre-launch review raised 16 more; none of those 16 was a defect in the contract. All are recorded in the changelog. Every one of these reviews was run by AI agents, none independent. On 27 September 2026 the version 2 test suite had 263 passing tests and none failing.
- No independent third-party audit of either version has been completed.
- A full-duration Base Sepolia lifecycle test of version 2, at least 14 days of real time for a complete create, claim, veto and settle cycle, has not been completed.
- The reminder watcher passed a 14-step local scenario in August 2026 against version 1 only. It has been retired and is not running.
The contract is non-upgradeable. A serious contract finding requires a new deployment and a clearly communicated migration; it cannot be silently patched. The creation pause cannot stop deposits into existing vaults, so a migration notice would ask owners to withdraw in full, which closes the vault.
Website security
The interface is a static Cloudflare Pages deployment. Runtime dependencies are self-hosted. A restrictive Content Security Policy blocks third-party scripts, framing, objects, workers and unapproved network destinations. Chain-derived values are rendered with text nodes rather than HTML injection.
Report a vulnerability
Never publish working exploit details, a seed phrase or private key. Open a minimal GitHub issue asking for a private contact channel, identifying only the affected component and whether funds may face immediate risk. A report is not automatically eligible for a bounty; no bounty program is currently promised.