From eef0379ab2735f9c958812b93c6264addbb654aa Mon Sep 17 00:00:00 2001 From: Dimitris Marlagkoutsos Date: Fri, 24 Apr 2026 19:45:38 +0200 Subject: [PATCH 1/3] fix(evm-wallet-experiment): install ca-certificates in evm Docker image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Foundry nightly 1.6.0-nightly (9439c7bdb9 2026-04-22) requires a CA bundle on disk even for plain-http localhost RPC calls. Without it, `cast bn` in the container entrypoint's wait loop fails with "No CA certificates were loaded from the system", so the entrypoint never deploys the delegation framework contracts, `contracts.json` is never written, and the evm container never goes healthy — blocking the whole Docker e2e stack. Pre-existing issue surfaced while running docker:e2e for PR #943. Not related to the SES-lockdown cleanup theme, but blocks verification. Co-Authored-By: Claude Opus 4.7 (1M context) --- packages/evm-wallet-experiment/docker/Dockerfile.evm | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/evm-wallet-experiment/docker/Dockerfile.evm b/packages/evm-wallet-experiment/docker/Dockerfile.evm index ed56433c9e..92c894686a 100644 --- a/packages/evm-wallet-experiment/docker/Dockerfile.evm +++ b/packages/evm-wallet-experiment/docker/Dockerfile.evm @@ -2,6 +2,14 @@ FROM ghcr.io/foundry-rs/foundry:latest AS foundry FROM node:22-slim +# `cast` (Foundry nightly 2026-04-22+) requires a CA bundle on disk even for +# plain-http localhost RPC calls, so `node:22-slim` — which ships without +# ca-certificates — makes the entrypoint's `cast bn` wait loop hang. Install +# it once at build time. +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates \ + && rm -rf /var/lib/apt/lists/* + WORKDIR /app # Copy anvil + cast from the foundry image From cd4065c491875306861d66b18e0f0a6334d95e58 Mon Sep 17 00:00:00 2001 From: Dimitris Marlagkoutsos Date: Fri, 24 Apr 2026 19:45:49 +0200 Subject: [PATCH 2/3] fix(evm-wallet-experiment): docker e2e ALLOWED_HOSTS must be hostnames only After PR #942 (Snaps network endowment factory) introduced the `network-caveat.ts` matcher with strict "hostname-only, no port" semantics (see packages/ocap-kernel/src/vats/network-caveat.ts:17-20), the e2e allowlist entries `['evm:8545', 'bundler:4337']` never match `URL.hostname` (which is just `'evm'` / `'bundler'`). Every fetch out of the provider vat was rejected with "Invalid host: evm", causing every docker e2e test to fail at `createSmartAccount`. Drop the ports to match the caveat's contract. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../test/e2e/docker/helpers/scenarios.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/evm-wallet-experiment/test/e2e/docker/helpers/scenarios.ts b/packages/evm-wallet-experiment/test/e2e/docker/helpers/scenarios.ts index ea0263e0d0..a45b2ab93f 100644 --- a/packages/evm-wallet-experiment/test/e2e/docker/helpers/scenarios.ts +++ b/packages/evm-wallet-experiment/test/e2e/docker/helpers/scenarios.ts @@ -32,7 +32,10 @@ const TEST_MNEMONIC = const CHAIN_ID = 31337; const EVM_RPC_URL = 'http://evm:8545'; const BUNDLER_URL = 'http://bundler:4337'; -const ALLOWED_HOSTS = ['evm:8545', 'bundler:4337']; +// Hostnames only — the kernel's network caveat (packages/ocap-kernel +// /src/vats/network-caveat.ts) matches `URL.hostname`, which never +// includes a port. +const ALLOWED_HOSTS = ['evm', 'bundler']; export type HomeResult = { kref: string; From 7e181b9c09ab3b61e86574be27fb587f06c7bc76 Mon Sep 17 00:00:00 2001 From: Dimitris Marlagkoutsos Date: Fri, 24 Apr 2026 19:46:04 +0200 Subject: [PATCH 3/3] fix(evm-wallet-experiment): surface underlying twin errors in multi-twin wrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `away-coordinator.transferNative` / `transferFungible` wrappers (introduced in PR #939 when the coordinator was split) wrap per-twin rejections as `throw new Error('All delegation twins failed', { cause: errors })`. The kernel's RPC error serialization only propagates `Error.message`, not `Error.cause`, so callers (including `run-delegation-twin-e2e.mjs`) only see the generic "All delegation twins failed" — which loses the actual reason (e.g. "Insufficient budget: requested 3, remaining 2"). Concatenate the cause messages into the wrapper's message text so the specific per-twin rejection reason survives to the caller. Keep the structured `cause` array intact for programmatic consumers. Unblocks the "enforces cumulativeSpend locally" assertion in the delegation-twin docker e2e test. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/vats/away-coordinator.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/evm-wallet-experiment/src/vats/away-coordinator.ts b/packages/evm-wallet-experiment/src/vats/away-coordinator.ts index 23f6fc9192..c2301ec32c 100644 --- a/packages/evm-wallet-experiment/src/vats/away-coordinator.ts +++ b/packages/evm-wallet-experiment/src/vats/away-coordinator.ts @@ -1811,7 +1811,14 @@ export function buildRootObject( errors.push(error); } } - throw new Error('All delegation twins failed', { cause: errors }); + throw new Error( + `All delegation twins failed: ${errors + .map((cause) => + cause instanceof Error ? cause.message : String(cause), + ) + .join('; ')}`, + { cause: errors }, + ); } if (homeSection) { return E(homeSection).transferNative(to, amt); @@ -1852,7 +1859,14 @@ export function buildRootObject( errors.push(error); } } - throw new Error('All delegation twins failed', { cause: errors }); + throw new Error( + `All delegation twins failed: ${errors + .map((cause) => + cause instanceof Error ? cause.message : String(cause), + ) + .join('; ')}`, + { cause: errors }, + ); } if (homeSection) { return E(homeSection).transferFungible(token, to, amt);