Split out from the method-A pairing adoption work (agent-initiated pairing — agent submits a request, the master claims by scanning a QR; the IoT "unbox → scan the code on the device" model, replacing #149's master-mints-link-code front-half).
Why
Part of method A is device-initiated unbind (factory reset → re-pair to a new owner). That requires the device to clear its own on-chain binding — but the contract currently doesn't allow it.
Current limitation
SidecarRegistry.revokeAgentDevice(bytes32 deviceKeyHash) requires msg.sender == operatorMasterWallet[entry.operatorOmni] — only the master can revoke a device. A device has no way to revoke itself.
Interim (shipped in the A-adoption PR, NOT this issue)
Factory reset = local K10 wipe + re-pair with a fresh key; the old on-chain device entry orphans (inert — the old key is destroyed, so it can never sign/mint again). Secure, but the registry keeps a stale row, and the old master's getDevice still shows the binding.
This issue — true device-initiated on-chain revocation
Add a device-key-signed self-revoke path so a device can clear its own binding on-chain. Sketch:
// EIP-191 sig by the device's K10 over a revoke payload (chainId + registry + deviceKeyHash + nonce),
// verified via ecrecover == the registered device's pubkey. No master signature required.
function revokeAgentDeviceBySelf(bytes32 deviceKeyHash, bytes calldata deviceSig) external;
Scope (why it's separate + heavier)
- Contract change to
SidecarRegistry.sol (new method + a self-revoke nonce/replay guard) — pin evm_version = london per CLAUDE.md.
- Heima MAINNET redeploy + migration of the deployed registry (the live v2 stage-1 address in
docs/spec/deployed-contracts.md) — the heavy/risky part the A-adoption PR avoids.
- Broker / CLI / daemon wiring for the self-revoke (
agentkeys device unbind on the agent side).
- Harness coverage: agent self-revoke → re-pair to a new master → old binding shows revoked on-chain.
References
🤖 Filed as the split-out follow-up to method-A pairing adoption.
Split out from the method-A pairing adoption work (agent-initiated pairing — agent submits a request, the master claims by scanning a QR; the IoT "unbox → scan the code on the device" model, replacing #149's master-mints-link-code front-half).
Why
Part of method A is device-initiated unbind (factory reset → re-pair to a new owner). That requires the device to clear its own on-chain binding — but the contract currently doesn't allow it.
Current limitation
SidecarRegistry.revokeAgentDevice(bytes32 deviceKeyHash)requiresmsg.sender == operatorMasterWallet[entry.operatorOmni]— only the master can revoke a device. A device has no way to revoke itself.Interim (shipped in the A-adoption PR, NOT this issue)
Factory reset = local K10 wipe + re-pair with a fresh key; the old on-chain device entry orphans (inert — the old key is destroyed, so it can never sign/mint again). Secure, but the registry keeps a stale row, and the old master's
getDevicestill shows the binding.This issue — true device-initiated on-chain revocation
Add a device-key-signed self-revoke path so a device can clear its own binding on-chain. Sketch:
Scope (why it's separate + heavier)
SidecarRegistry.sol(new method + a self-revoke nonce/replay guard) — pinevm_version = londonper CLAUDE.md.docs/spec/deployed-contracts.md) — the heavy/risky part the A-adoption PR avoids.agentkeys device unbindon the agent side).References
crates/agentkeys-chain/src/SidecarRegistry.sol(revokeAgentDevice,revokeMasterDevice).🤖 Filed as the split-out follow-up to method-A pairing adoption.