diff --git a/EIPS/eip-7039.md b/EIPS/eip-7039.md index 77f1ef433a6f9b..36554d8becc43f 100644 --- a/EIPS/eip-7039.md +++ b/EIPS/eip-7039.md @@ -76,7 +76,31 @@ A request without a transferred reply port SHALL NOT be considered an error, eve ### Icon Images - +Wallets and pages MAY display an icon for a provider using the `icon` URI from `ProviderInfo`. To ensure interoperability and security, the following rules apply: + +- The `icon` value MUST be a URI string. +- The URI scheme MUST be one of: `https:` or `data:`. User agents MAY additionally support implementation-specific extension schemes (e.g., browser extension origins) but SHOULD NOT rely on them for cross-implementation compatibility. +- When using `https:`: + - The resource MUST be served over TLS with a valid certificate. + - The response MUST include a correct `Content-Type` (e.g., `image/png`, `image/webp`, or `image/svg+xml`). + - Implementations SHOULD set cache headers to allow safe caching and reduce network load. +- When using `data:`: + - The media type MUST be `image/png`, `image/webp`, or `image/svg+xml`. + - Implementations SHOULD prefer `data:` URIs only for small icons (e.g., ≤ 10 KiB) to avoid bloating messages. +- Format and dimensions: + - The icon SHOULD be square. + - The icon SHOULD be at least 64×64 CSS pixels, and it is RECOMMENDED to provide 128×128 or higher for HiDPI displays. + - Implementations SHOULD render the icon within a square viewport and MAY downscale larger images. + - Transparent backgrounds are RECOMMENDED. +- SVG-specific requirements: + - SVG icons MUST NOT contain scripts, external resource references, or event handlers, and MUST be sanitized before rendering. + - User agents SHOULD reject SVGs that reference remote resources (fonts, images) or contain potentially executable content. +- Privacy and tracking: + - Icon URLs SHOULD be stable and MUST NOT contain per-user or per-request identifiers. + - Implementations SHOULD avoid initiating third-party network requests solely to render an icon; `data:` URIs MAY be used to mitigate cross-origin fetches when appropriate. +- Security: + - Consumers MUST validate that the reported media type matches the actual content and SHOULD cap the maximum icon payload size. + - Mixed content MUST be avoided; `http:` icons MUST NOT be used in secure contexts. ## Rationale @@ -88,11 +112,115 @@ While not backwards compatible with EIP-1193, this proposal uses extremely simil It is possible to implement an EIP-1193 compatible provider using this proposal like so: - +```typescript +// Minimal EIP-1193 provider built on SHADOW (web page side) +// See: https://eips.ethereum.org/EIPS/eip-1193 + +type RequestArguments = { + method: string; + params?: unknown[] | object; +}; + +type ProviderRpcError = { + code: number; + message: string; + data?: unknown; +}; + +class ShadowProvider { + private primaryPort: MessagePort | null = null; + private iframe: HTMLIFrameElement | null = null; + + async connect(): Promise { + if (this.primaryPort) return; + + const iframe = document.createElement('iframe'); + iframe.style.display = 'none'; + iframe.src = 'web+evm://'; + + const primaryPort = await new Promise((resolve, reject) => { + const onMessage = (event: MessageEvent) => { + if (event.source !== iframe.contentWindow) return; + // Expect the first message to transfer a port for primary communication + const [port] = event.ports || []; + if (!port) return; + window.removeEventListener('message', onMessage); + resolve(port); + }; + window.addEventListener('message', onMessage); + // Safety timeout in case no wallet responds + setTimeout(() => reject(new Error('Wallet did not respond')), 10_000); + }); + + document.body.appendChild(iframe); + this.iframe = iframe; + this.primaryPort = primaryPort; + this.primaryPort.start(); + } + + async request(args: RequestArguments): Promise { + if (!this.primaryPort) throw new Error('Not connected'); + + const channel = new MessageChannel(); + const { port1, port2 } = channel; + + const response = await new Promise<{ result?: T; error?: ProviderRpcError }>((resolve) => { + const onMessage = (event: MessageEvent) => { + port1.removeEventListener('message', onMessage as EventListener); + port1.close(); + resolve(event.data); + }; + port1.addEventListener('message', onMessage as EventListener); + port1.start(); + this.primaryPort!.postMessage(args, [port2]); + }); + + if (response.error) { + const { code, message } = response.error; + const err = new Error(message) as Error & { code?: number }; + err.code = code; + throw err; + } + return response.result as T; + } +} + +// Usage example +(async () => { + const provider = new ShadowProvider(); + await provider.connect(); + // Example JSON-RPC call via EIP-1193 semantics + const chainId = await provider.request({ method: 'eth_chainId' }); + console.log('chainId', chainId); +})(); +``` ## Security Considerations - +The following non-exhaustive list outlines key security requirements and recommendations: + +- Message origin and source validation: + - Web pages MUST verify that the initial `message` event's `source` equals the created `iframe`'s `contentWindow` before trusting any transferred port. + - Where an origin is available, implementations SHOULD verify that it matches an expected wallet origin; wallets served from `https:` origins are RECOMMENDED. + - Parties MUST ignore messages from unexpected sources and MUST treat unknown messages as untrusted data. +- Use of `MessagePort`: + - Only the transferred primary port SHOULD be used for subsequent requests; additional unsolicited ports MUST be ignored. + - Implementations SHOULD bound the lifetime of reply ports and MUST post at most one response message per request. +- Permissioning and user consent: + - Wallets MUST gate sensitive methods (e.g., transaction signing, key export) behind explicit user consent and per-origin permissions, consistent with EIP-1193 expectations. + - Wallets SHOULD present confirmation UX outside the embedded `iframe` context to reduce clickjacking risk. +- Input validation and rate limiting: + - Responders MUST validate JSON-RPC method names and parameters and SHOULD apply size limits and schema checks. + - Implementations SHOULD enforce per-origin rate limits and timeouts to mitigate denial-of-service. +- Icon handling security: + - Icons MUST be loaded over secure transports; `http:` MUST NOT be used in secure contexts. + - SVG icons MUST be sanitized and MUST NOT execute scripts or reference external resources. + - Implementations SHOULD cap icon file size and dimensions. +- Privacy: + - Implementations SHOULD avoid leaking browsing context information via icon URLs or request headers and SHOULD favor stable, cacheable URLs or `data:` URIs. + - Wallets SHOULD avoid embedding third-party content within the transport `iframe`. +- Content Security Policy (CSP): + - Pages and wallets SHOULD configure CSP such that only intended image and messaging endpoints are permitted (e.g., `img-src` and `connect-src`). Both providers and web pages MUST verify the origin of messages before trusting them.