Live proof
Audience: contributors and reviewers who want on-chain evidence that the plugin signs with real KMS keys.
Status: the latest run of the live suite on Sepolia (#44), with the transaction matrix of #144. pnpm run docs:live-proof renders this page from test/live/proof.json, which the run wrote; do not edit it by hand.
Run
| Field | Value |
|---|---|
| Date | 2026-10-16, blocks mined from 06:22:24 to 06:26:36 UTC |
| Commit | eeec83b |
| Chain id | 11155111 (Sepolia) |
| Blocks | 11925619 to 11925638 |
| Command | HARDHAT_KMS_LIVE_NETWORK=sepolia pnpm run test:live |
| Providers | AWS KMS, Google Cloud KMS and Azure Key Vault, in parallel |
| Gas prices | 1.00 to 1.00 gwei for types 0 and 1; 0.00 to 1.00 gwei for types 2 and 4 |
Every transaction below was signed by the provider's KMS key through the plugin, except where a case says another key signed. The suite waited for each receipt and checked its status, its sender and its type against the case table in test/live/matrix.ts. A run that misses a receipt for any live cell fails, and writes no proof.
The personal_sign and eth_signTypedData_v4 signatures are checked with eth_call: LiveCheck rebuilds the EIP-191 and EIP-712 digests on chain and recovers the KMS account with ecrecover. These checks send no transaction, so they have no hash.
Each account ends the run with no code. Its EIP-7702 delegation is cleared by the last case, and the throwaway key whose authorization the account sent is cleared by a second transaction in the same case. Slot 0 of each account's storage keeps the count that the delegated add wrote; clearing a delegation does not reset storage.
Coverage matrix
One decision per action and type. Live cells run on Sepolia and on the fork, fork cells only on the fork, unit cells only in the unit or integration tests, and refused cells are refused by the plugin before any request. Each live and fork cell runs once per provider.
| Action | Type 0 (legacy) | Type 1 (EIP-2930) | Type 2 (EIP-1559) | Type 3 (EIP-4844) | Type 4 (EIP-7702) |
|---|---|---|---|---|---|
| ETH to another EOA | Live | Live | Live | Refused (r) | Live |
| ETH to self | Fork (a) | Fork (a) | Live | Refused (r) | Live |
| Contract deploy | Live | Live | Live | N/A (b) | N/A (c) |
| Contract call | Live | Live | Live | Refused (r) | Live |
| Payable contract call | Live | Live | Live | Refused (r) | Live |
| Reverting transaction, mined with status 0 | Fork (d) | Fork (d) | Live | Refused (r) | Fork (d) |
| Replacement (same nonce, higher fee) | Fork (e) | Fork (e) | Fork (e), unit | Refused (r) | Fork (e) |
| EIP-7702 set delegation | N/A (f) | N/A (f) | N/A (f) | N/A (f) | Live |
| EIP-7702 clear delegation | N/A (f) | N/A (f) | N/A (f) | N/A (f) | Live |
| Sponsored: we send another key's authorization | N/A (f) | N/A (f) | N/A (f) | N/A (f) | Live |
| Sponsored: another account sends our authorization | N/A (g) | N/A (g) | N/A (g) | N/A (g) | Fork (h) |
| Signature | Decision |
|---|---|
personal_sign | Live |
eth_signTypedData_v4 | Live |
eth_sign | Live |
Reasons:
- (a) A self-send of type 0 or 1 takes the same fill and signing path as a send to another EOA of the same type, which runs live. Self-sends of types 2 and 4 run live.
- (b) EIP-4844: "
to… MUST NOT benil… blob transactions cannot have the form of a create transaction." The plugin refuses blob transactions anyway. - (c) EIP-7702 gives
destinationthe semantics of EIP-4844: "this implies a null destination is not valid." - (d) The revert path does not depend on the type: the receipt has status 0, and the next transaction whose nonce the plugin fills carries the account's count after the revert, which the type 2 case proves on Sepolia. The type 4 case also checks that the delegation stays applied, since EIP-7702 does not roll back processed authorizations when execution fails.
- (e) A replacement needs a transaction that stays pending. On Sepolia that means pricing one below the base fee through a load-balanced public RPC, where a backend may refuse it or mine it, and a stuck nonce blocks the account. In fork mode the case turns automine off with
evm_setAutomine, sends, sends the replacement with double the fees, mines, and checks that only the replacement was mined. - (f) EIP-7702: only a set-code transaction (type 4) carries an
authorization_list, and the list must not be empty. The plugin picks type 4 exactly whenauthorizationListis present and refuses agasPricenext to it. - (g) The other account signs the outer transaction; the plugin signs only the authorization, which only type 4 carries (EIP-7702).
- (h) On Sepolia the KMS account would first have to fund a second key, and ETH would stay there. In fork mode
anvil_setBalancefunds a throwaway local sender for free. The KMS key signs the authorization with its current nonce, not nonce + 1, since another account sends it. - (r) EIP-4844 blob transactions: the plugin refuses them before any request.
Unit tests:
packages/hardhat-kms/test/unit/rpc/transaction-filler.test.ts, "refuses blob transactions before any request":eth-to-eoa/eip4844,eth-to-self/eip4844,call/eip4844,payable-call/eip4844,revert/eip4844,replacement/eip4844packages/hardhat-kms/test/integration/send-lock.test.ts, "keeps an explicit nonce and sends same-nonce replacements with higher fees":replacement/eip1559
Not in the matrix:
- CREATE2 factory deploy: The plugin sees a call to the factory, which is the contract call row. It never builds the CREATE2 address itself.
Cases:
| Case | Mode | What it sends |
|---|---|---|
deploy-live-check | live | deploy LiveCheck |
eth-to-eoa-legacy | live | 1 wei to a fresh address |
eth-to-eoa-eip2930 | live | 1 wei to a fresh address, with an access list |
eth-to-eoa-eip1559 | live | 1 wei to a fresh address |
self-send-legacy | fork | 1 wei to itself |
self-send-eip2930 | fork | 1 wei to itself, with an access list |
self-send-eip1559 | live | 1 wei to itself |
deploy-minimal-legacy | live | deploy a 3-byte contract |
deploy-minimal-eip2930 | live | deploy a 3-byte contract, with an access list |
revert-eip1559 | live | an unknown selector to LiveCheck, with a gas limit of 50,000 |
revert-legacy | fork | an unknown selector to LiveCheck, with a gas limit of 50,000 |
revert-eip2930 | fork | an unknown selector to LiveCheck, with an access list and a gas limit of 50,000 |
call-legacy | live | add(1) with 1 wei |
call-eip2930 | live | add(1) with 1 wei, with an access list |
call-eip1559 | live | add(1) with 1 wei |
replace-legacy | fork | replace a pending 1 wei self-send |
replace-eip2930 | fork | replace a pending 1 wei self-send, with an access list |
replace-eip1559 | fork | replace a pending 1 wei self-send |
delegate-and-call | live | delegate to LiveCheck and call add(1) on itself with 1 wei |
signatures | live | LiveCheck recovers a personal_sign, an eth_sign and an eth_signTypedData_v4 signature |
sponsor-other | live | 1 wei to the fresh address, carrying a throwaway key's authorization to LiveCheck; a second transaction clears that delegation |
sponsored-by-other | fork | a funded local account sends our authorization, delegating to the 3-byte contract |
revert-eip7702 | fork | delegate back to LiveCheck and send an unknown selector to itself, with a gas limit of 100,000 |
replace-eip7702 | fork | replace a pending self-send that carries an authorization |
clear-delegation | live | authorize the zero address and send 1 wei to itself |
AWS KMS
- Account:
0x0b545a5a4cA04252184A7813D0D4D3fBA31Af2fd LiveCheck:0x5E2a0599E498191CC8664D151259092B6bc9e15B- Spent: 0.000926995599298991 ETH
| Action | Type 0 (legacy) | Type 1 (EIP-2930) | Type 2 (EIP-1559) | Type 3 (EIP-4844) | Type 4 (EIP-7702) |
|---|---|---|---|---|---|
| ETH to another EOA | 0x4332f745 | 0xd620b4e6 | 0x51e1fc2c | Refused (r) | 0x393614a0 |
| ETH to self | fork only | fork only | 0x9dc5f855 | Refused (r) | 0x488d0ed7 |
| Contract deploy | 0x7d40a12c | 0xeae7ceb7 | 0x3d50e4dd | N/A (b) | N/A (c) |
| Contract call | 0xc15345db | 0x70034856 | 0xe39fad17 | Refused (r) | 0xcd045bc3 |
| Payable contract call | 0xc15345db | 0x70034856 | 0xe39fad17 | Refused (r) | 0xcd045bc3 |
| Reverting transaction, mined with status 0 | fork only | fork only | 0x230cf20b | Refused (r) | fork only |
| Replacement (same nonce, higher fee) | fork only | fork only | fork only | Refused (r) | fork only |
| EIP-7702 set delegation | N/A (f) | N/A (f) | N/A (f) | N/A (f) | 0xcd045bc3 |
| EIP-7702 clear delegation | N/A (f) | N/A (f) | N/A (f) | N/A (f) | 0x488d0ed7 |
| Sponsored: we send another key's authorization | N/A (f) | N/A (f) | N/A (f) | N/A (f) | 0x393614a0 |
| Sponsored: another account sends our authorization | N/A (g) | N/A (g) | N/A (g) | N/A (g) | fork only |
| Signature | Proof |
|---|---|
personal_sign | eth_call at block 11925630 |
eth_signTypedData_v4 | eth_call at block 11925630 |
eth_sign | eth_call at block 11925630 |
| Case | Step | Type | Status | Block | Transaction |
|---|---|---|---|---|---|
deploy-live-check | deploy LiveCheck | 2 | 1 | 11925619 | 0x3d50e4dd |
eth-to-eoa-legacy | 1 wei to a fresh address | 0 | 1 | 11925620 | 0x4332f745 |
eth-to-eoa-eip2930 | 1 wei to a fresh address | 1 | 1 | 11925621 | 0xd620b4e6 |
eth-to-eoa-eip1559 | 1 wei to a fresh address | 2 | 1 | 11925622 | 0x51e1fc2c |
self-send-eip1559 | 1 wei to itself | 2 | 1 | 11925623 | 0x9dc5f855 |
deploy-minimal-legacy | deploy a 3-byte contract | 0 | 1 | 11925624 | 0x7d40a12c |
deploy-minimal-eip2930 | deploy a 3-byte contract | 1 | 1 | 11925625 | 0xeae7ceb7 |
revert-eip1559 | an unknown selector to LiveCheck | 2 | 0 | 11925626 | 0x230cf20b |
call-legacy | add(1) with 1 wei | 0 | 1 | 11925627 | 0xc15345db |
call-eip2930 | add(1) with 1 wei | 1 | 1 | 11925628 | 0x70034856 |
call-eip1559 | add(1) with 1 wei | 2 | 1 | 11925629 | 0xe39fad17 |
call-eip1559 | add(1) with 1 wei, filled while the first was pending | 2 | 1 | 11925629 | 0x99bd397d |
delegate-and-call | delegate to LiveCheck and add(1) with 1 wei | 4 | 1 | 11925630 | 0xcd045bc3 |
sponsor-other | 1 wei to a fresh address, with a throwaway key's authorization | 4 | 1 | 11925633 | 0x393614a0 |
sponsor-other | clear the throwaway key's delegation | 4 | 1 | 11925634 | 0x03cfbf62 |
clear-delegation | clear the delegation, with 1 wei to itself | 4 | 1 | 11925635 | 0x488d0ed7 |
Google Cloud KMS
- Account:
0x728743B36DE6236f6d03409563a7E2c39a00EE17 LiveCheck:0xd47e085f075C8732F23380a3689A3D46b63c6161- Spent: 0.000958795598620991 ETH
| Action | Type 0 (legacy) | Type 1 (EIP-2930) | Type 2 (EIP-1559) | Type 3 (EIP-4844) | Type 4 (EIP-7702) |
|---|---|---|---|---|---|
| ETH to another EOA | 0xd10a4192 | 0x8e302c52 | 0x990cafa6 | Refused (r) | 0x6a4ca6b3 |
| ETH to self | fork only | fork only | 0xa407484a | Refused (r) | 0x147b3514 |
| Contract deploy | 0x4b6731b7 | 0xd4ea5bc6 | 0x906b46b3 | N/A (b) | N/A (c) |
| Contract call | 0x4fd85d4e | 0xae47e40a | 0x6b14fbf7 | Refused (r) | 0xa6f9c688 |
| Payable contract call | 0x4fd85d4e | 0xae47e40a | 0x6b14fbf7 | Refused (r) | 0xa6f9c688 |
| Reverting transaction, mined with status 0 | fork only | fork only | 0x221ca29a | Refused (r) | fork only |
| Replacement (same nonce, higher fee) | fork only | fork only | fork only | Refused (r) | fork only |
| EIP-7702 set delegation | N/A (f) | N/A (f) | N/A (f) | N/A (f) | 0xa6f9c688 |
| EIP-7702 clear delegation | N/A (f) | N/A (f) | N/A (f) | N/A (f) | 0x147b3514 |
| Sponsored: we send another key's authorization | N/A (f) | N/A (f) | N/A (f) | N/A (f) | 0x6a4ca6b3 |
| Sponsored: another account sends our authorization | N/A (g) | N/A (g) | N/A (g) | N/A (g) | fork only |
| Signature | Proof |
|---|---|
personal_sign | eth_call at block 11925630 |
eth_signTypedData_v4 | eth_call at block 11925630 |
eth_sign | eth_call at block 11925630 |
| Case | Step | Type | Status | Block | Transaction |
|---|---|---|---|---|---|
deploy-live-check | deploy LiveCheck | 2 | 1 | 11925619 | 0x906b46b3 |
eth-to-eoa-legacy | 1 wei to a fresh address | 0 | 1 | 11925620 | 0xd10a4192 |
eth-to-eoa-eip2930 | 1 wei to a fresh address | 1 | 1 | 11925621 | 0x8e302c52 |
eth-to-eoa-eip1559 | 1 wei to a fresh address | 2 | 1 | 11925622 | 0x990cafa6 |
self-send-eip1559 | 1 wei to itself | 2 | 1 | 11925623 | 0xa407484a |
deploy-minimal-legacy | deploy a 3-byte contract | 0 | 1 | 11925624 | 0x4b6731b7 |
deploy-minimal-eip2930 | deploy a 3-byte contract | 1 | 1 | 11925625 | 0xd4ea5bc6 |
revert-eip1559 | an unknown selector to LiveCheck | 2 | 0 | 11925626 | 0x221ca29a |
call-legacy | add(1) with 1 wei | 0 | 1 | 11925627 | 0x4fd85d4e |
call-eip2930 | add(1) with 1 wei | 1 | 1 | 11925628 | 0xae47e40a |
call-eip1559 | add(1) with 1 wei | 2 | 1 | 11925629 | 0x6b14fbf7 |
call-eip1559 | add(1) with 1 wei, filled while the first was pending | 2 | 1 | 11925629 | 0xb421daf4 |
delegate-and-call | delegate to LiveCheck and add(1) with 1 wei | 4 | 1 | 11925630 | 0xa6f9c688 |
sponsor-other | 1 wei to a fresh address, with a throwaway key's authorization | 4 | 1 | 11925633 | 0x6a4ca6b3 |
sponsor-other | clear the throwaway key's delegation | 4 | 1 | 11925634 | 0xbccd1388 |
clear-delegation | clear the delegation, with 1 wei to itself | 4 | 1 | 11925635 | 0x147b3514 |
Azure Key Vault
- Account:
0x9626Fb8498C69d88F8C080835C3Cd328453D3004 LiveCheck:0x35261b91fabb143e375F4f284195e47378a77feA- Spent: 0.000878532100494578 ETH
| Action | Type 0 (legacy) | Type 1 (EIP-2930) | Type 2 (EIP-1559) | Type 3 (EIP-4844) | Type 4 (EIP-7702) |
|---|---|---|---|---|---|
| ETH to another EOA | 0x40eee9a8 | 0x8dea9488 | 0xa5430eb7 | Refused (r) | 0x46166a99 |
| ETH to self | fork only | fork only | 0x9deeef26 | Refused (r) | 0x420c8d8b |
| Contract deploy | 0xfaab96e7 | 0xec8d87c5 | 0xb319c000 | N/A (b) | N/A (c) |
| Contract call | 0xd5a08123 | 0xeb00dadf | 0xd68b8dc9 | Refused (r) | 0x4725b166 |
| Payable contract call | 0xd5a08123 | 0xeb00dadf | 0xd68b8dc9 | Refused (r) | 0x4725b166 |
| Reverting transaction, mined with status 0 | fork only | fork only | 0x81f6e7b1 | Refused (r) | fork only |
| Replacement (same nonce, higher fee) | fork only | fork only | fork only | Refused (r) | fork only |
| EIP-7702 set delegation | N/A (f) | N/A (f) | N/A (f) | N/A (f) | 0x4725b166 |
| EIP-7702 clear delegation | N/A (f) | N/A (f) | N/A (f) | N/A (f) | 0x420c8d8b |
| Sponsored: we send another key's authorization | N/A (f) | N/A (f) | N/A (f) | N/A (f) | 0x46166a99 |
| Sponsored: another account sends our authorization | N/A (g) | N/A (g) | N/A (g) | N/A (g) | fork only |
| Signature | Proof |
|---|---|
personal_sign | eth_call at block 11925630 |
eth_signTypedData_v4 | eth_call at block 11925630 |
eth_sign | eth_call at block 11925630 |
| Case | Step | Type | Status | Block | Transaction |
|---|---|---|---|---|---|
deploy-live-check | deploy LiveCheck | 2 | 1 | 11925619 | 0xb319c000 |
eth-to-eoa-legacy | 1 wei to a fresh address | 0 | 1 | 11925620 | 0x40eee9a8 |
eth-to-eoa-eip2930 | 1 wei to a fresh address | 1 | 1 | 11925621 | 0x8dea9488 |
eth-to-eoa-eip1559 | 1 wei to a fresh address | 2 | 1 | 11925622 | 0xa5430eb7 |
self-send-eip1559 | 1 wei to itself | 2 | 1 | 11925623 | 0x9deeef26 |
deploy-minimal-legacy | deploy a 3-byte contract | 0 | 1 | 11925624 | 0xfaab96e7 |
deploy-minimal-eip2930 | deploy a 3-byte contract | 1 | 1 | 11925625 | 0xec8d87c5 |
revert-eip1559 | an unknown selector to LiveCheck | 2 | 0 | 11925626 | 0x81f6e7b1 |
call-legacy | add(1) with 1 wei | 0 | 1 | 11925627 | 0xd5a08123 |
call-eip2930 | add(1) with 1 wei | 1 | 1 | 11925628 | 0xeb00dadf |
call-eip1559 | add(1) with 1 wei | 2 | 1 | 11925629 | 0xd68b8dc9 |
call-eip1559 | add(1) with 1 wei, filled while the first was pending | 2 | 1 | 11925629 | 0x3def8c98 |
delegate-and-call | delegate to LiveCheck and add(1) with 1 wei | 4 | 1 | 11925630 | 0x4725b166 |
sponsor-other | 1 wei to a fresh address, with a throwaway key's authorization | 4 | 1 | 11925633 | 0x46166a99 |
sponsor-other | clear the throwaway key's delegation | 4 | 1 | 11925635 | 0xefb92377 |
clear-delegation | clear the delegation, with 1 wei to itself | 4 | 1 | 11925638 | 0x420c8d8b |
The providers together spent 0.00276432329841456 ETH.