Skip to content

Vault and ENS: build around the deployed contracts, headless custody and ens, no fixed waits left - #2

Merged
baairon merged 5 commits into
masterfrom
claude/wonderful-wright-obszfp
Oct 6, 2026
Merged

baairon merged 5 commits into
masterfrom
claude/wonderful-wright-obszfp

Conversation

@baairon

@baairon baairon commented Oct 6, 2026 •

Copy link
Copy Markdown
Owner

Summary

Covers what the network pass (7169b11) left out. The Solidity is untouched.

  • Vault builds. Known runtime builds are recognized by hash. An existing Vault may run any known build; a fresh deploy must be the current build. The deposit preflight reads heldAgent() only on builds that have it, otherwise agentOwner, and simulates the registry deposit before the wallet opens. Vault custom errors (NotOwner, NotAuthorized, …) now decode by name.

  • Custody fixes:

    • operators are re-approved after a redeposit, since each deposit wipes approvals;
    • a failed read is never treated as "revoked", "no Vault" or "accept";
    • a fresh Vault's address is saved right after deploy, so a retry reuses it;
    • switching to Simple clears the Vault address;
    • a second send of the same kind is blocked while one is in flight;
    • the ownership cache is cleared after each custody transaction, instead of being trusted for 30 seconds.
  • No fixed waits. One paced helper replaces the fixed loops. It waits for the receipt block, looks again once per new block, and stops at the 60 s backoff ceiling. It covers Vault confirmations, operator verification and the gas estimate; a revert now surfaces at once.

  • Log scans. scanLogs uses each host's learned block range and names the limit when one applies, such as mainnet.base.org's 500 blocks. It hands over when an endpoint lacks history and says why. Dead discoverVaultedTokens is removed.

  • ENS:

    • reads use the adaptive transport;
    • an unreadable record is an error instead of "no record";
    • every ENS transaction waits for its receipt;
    • gas is estimated from the signer;
    • Delete clears the agent records first;
    • creating a name no longer changes custody.
  • New commands:

    • ethagent custody [--verify]: read-only, with eth_call permission simulations; exits 4 on a mismatch.
    • ethagent ens: read-only.
    • ens <name>, ens --unlink and ens --set/--clear: preview until --yes. They sign in the browser or with --operator, refuse unless the signer controls the name, and publish name changes in one owner-signed save.
  • CI. New GitHub Actions workflow:

    • typecheck and test on Node 20 and 22;
    • forge build and forge test for the contracts.

    forge fmt --check is left out on purpose: reformatting Vault.sol would change its metadata hash, so new deploys would stop matching the recorded build.

  • Docs and guidance. README, --help and agent guidance are updated.

Testing done

  • After a clean npm ci, npm run typecheck is clean and npm test passes all 732 tests.
  • New tests cover:
    • the builds table and the deposit preflight without heldAgent();
    • paced checks with mocked time, including the ceiling;
    • scanLogs learning a 500-block limit and handing over;
    • custody output and simulations;
    • ens previews, multicall encoding and old-name clearing;
    • signer refusals and exit codes 2 and 3;
    • the local-key sender and runOperatorSave;
    • the paced gas estimate and the adaptive ENS client.

Remaining for testing (unsandboxed agent)

This sandbox has no RPC access, so the live checks below are still open. All are non-destructive; nothing else should be sent.

  1. Pre-release Vault hash (required). PRE_RELEASE_VAULT_BUILD_HASH in src/identity/registry/vault/builds.ts is undefined. Run ethagent custody --json and take vault.code.hash from Vault 0x6bdC…51d7: it should be 1,955 bytes and start 0xf8f23197. Set the constant to it. Until then, that Vault reads as "not a known Vault build" and re-deposits are refused. The current build (0x97141f0f…) and the first committed build (0xfea7e898…) were reproduced from source with solc 0.8.24.

  2. Custody verify. ethagent custody --verify on that Vault should show:

    • the pre-release build recognized, with no heldAgent();
    • the owner withdrawing and the owner changing an operator: would succeed;
    • the operator rotating: would succeed;
    • the operator withdrawing: refused (NotOwner);
    • a stranger rotating: refused (NotAuthorized); a stranger withdrawing: refused (NotOwner);
    • exit 0.
  3. ENS read. ethagent ens --json for meow.femboi.eth should show addr = owner, the token and ENSIP-25 records, the link OK, and the operator key able to sign.

  4. ENS previews only (no --yes), via keychain exec ethagent -- ethagent ens … --operator:

    • ens <new>.femboi.eth --operator;
    • ens --set url=… --operator.

    Every independent step's simulation should read "would succeed" from the operator.

  5. Deposit preflight. Simulate it against the real Vault. A refusal should decode by name.

  6. One operator save. Run one keychain operator-save on this branch's build.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw

claude added 5 commits October 6, 2026 21:13
…stody and ens commands, and replace the remaining fixed waits

- Recognize deployed Vault builds by runtime hash (current and first committed; a slot for the pre-release build without heldAgent()). An existing Vault may run any known build; a fresh deploy must be the current one. The deposit preflight reads heldAgent() only where it exists, otherwise agentOwner, and simulates the registry deposit before the wallet opens. Vault custom errors decode by name. Reconciliation reports the build instead of treating any code as a Vault.
- Custody fixes: re-approve local operators after a redeposit (each deposit starts a new operator epoch), never treat a failed read as "revoked", "no Vault", or "accept", save a fresh Vault's address right after the deploy so a retry reuses it, clear the Vault address when switching to Simple, block a second send while one is in flight, classify ownership read errors by the transport's types, and clear the ownership cache after every custody transaction instead of trusting it for 30 seconds.
- Replace the fixed attempt counts with one paced helper: wait for the endpoint to reach the receipt block, look again once per new block with doubling pauses up to the 60 second backoff ceiling, and stop at once on a definitive answer. It covers the post-deploy code check, deposit and withdraw confirmation, operator verification, and the gas estimate, where a revert now surfaces at once and by name.
- Add scanLogs: start from each host's learned block range, take the limit an endpoint names or halve on a range refusal, remember it in hosts.json, hand over when an endpoint refuses the depth of history, and say why when none can. The registry transfer scan uses it; the unused discoverVaultedTokens and its unreachable pick-token step are removed.
- ENS: reads go through the adaptive transport with cancel-only waits, an unreadable record or resolver is an error instead of "no record", every ENS transaction waits for its receipt (no time limit, cancelable) and records a pending tx, gas is estimated from the signer, Delete clears the agent records before removing the subdomain, and creating a name no longer changes custody or lists the owner as its own operator.
- The operator key sends through the adaptive transport (one endpoint per broadcast) with the prepared gas and fees.
- New `ethagent custody [--verify]`: Vault, build, holder, Vault-level owner, operators, and eth_call simulations of each permission (exit 4 on a mismatch).
- New `ethagent ens`: show the linked name and its records; `ens <name>`, `ens --unlink`, and `ens --set/--clear` preview until --yes, sign ENS transactions in one browser tab or with --operator, refuse unless the signer controls the name, and publish a name change in one owner-signed save.
- Document the commands, ETHAGENT_RPC_URL, and ETHAGENT_IPFS_API_URL, correct which history commands go online, and tell agents that previews are theirs to run and --yes is the user's.
- Fix the three type errors on the base branch.
- Tests: builds and capability preflight, paced checks with mocked time, scanLogs learning a 500-block limit, custody output and simulations, ens previews, diffs, multicall encoding and old-name clearing, signer refusals and exit codes, the local-key sender, runOperatorSave, the paced gas estimate, and the ENS client.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw
…racts with forge

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw
Reformatting Vault.sol would change the compiled metadata hash, so new
deploys would stop matching the recorded current build. The deployed
source stays as it is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw
The Base chain client type does not narrow to a plain PublicClient under
the lockfile's viem types, which failed typecheck in CI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw
…s commands

Match the README and help conventions (<ref>, <path>): <name>, <key>=<value>,
<key>, and <args> instead of agent.yourname.eth, url=https://example.com,
k=v, and ellipses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw
@baairon
baairon merged commit a82ec9b into master Oct 6, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants