Skip to content

feat(runner): Solidity & Flow EVM support#191

Open
lmcmz wants to merge 84 commits intomainfrom
feat/solidity-evm-runner
Open

feat(runner): Solidity & Flow EVM support#191
lmcmz wants to merge 84 commits intomainfrom
feat/solidity-evm-runner

Conversation

@lmcmz
Copy link
Member

@lmcmz lmcmz commented Mar 14, 2026

Summary

Adds dual-language (Cadence + Solidity) support to the Runner IDE, replacing the outdated PR #159 with a clean reimplementation on current main.

  • Server-side Solidity LSPsolidity-language-server (Rust binary) via /lsp-sol WebSocket, mirroring existing Cadence LSP pattern
  • Multi-language editor — Monaco auto-detects .sol vs .cdc, parameterized LSP adapter, Solidity syntax highlighting
  • EVM wallet — wagmi + viem with Flow EVM chains (mainnet 747, testnet 545), dual wallet UI (Flow + EVM), local key EOA support
  • Client-side Solidity compilation — solc WASM in browser, context-aware run button (orange "Compile" for .sol, green "Run" for .cdc)
  • Solidity templates — Simple Storage, ERC-20 Token, Cross-VM (Cadence ↔ EVM)

Architecture

Frontend:  CadenceEditor (auto language) → useLsp / useSolidityLsp → MonacoLspAdapter(languageId)
Wallet:    FCL + LocalKey (Cadence) | wagmi + viem (EVM) — both via LocalKey EOA
Compile:   solc WASM (browser-side) → ABI + bytecode
Server:    /lsp → Cadence LSP (port 3002) | /lsp-sol → Solidity LSP (port 3004)
Docker:    solidity-language-server v0.1.32 binary added

New files

  • runner/server/src/solidityLspClient.ts — Solidity LSP client (stdio JSON-RPC)
  • runner/src/editor/useSolidityLsp.ts — Solidity LSP React hook
  • runner/src/flow/evmChains.ts — Flow EVM chain definitions
  • runner/src/flow/wagmiConfig.ts — wagmi config
  • runner/src/flow/evmExecute.ts — solc WASM compile module
  • runner/src/types/solc.d.ts — solc type declaration

Modified files

  • runner/server/src/index.ts — add /lsp-sol WebSocket handler
  • runner/nginx.conf — add /lsp-sol proxy
  • runner/Dockerfile — add solidity-language-server binary
  • runner/src/editor/monacoLspAdapter.ts — parameterize language ID
  • runner/src/editor/CadenceEditor.tsx — language-aware for .sol
  • runner/src/fs/fileSystem.ts — Solidity templates
  • runner/src/components/FileExplorer.tsx — .sol file icons
  • runner/src/components/WalletButton.tsx — dual wallet (Flow + EVM)
  • runner/src/auth/localKeyManager.ts — EVM EOA derivation
  • runner/src/main.tsx — WagmiProvider wrapper
  • runner/src/App.tsx — Solidity LSP + compile handler + run routing

Test plan

  • Open runner, verify existing Cadence templates work unchanged
  • Create "Simple Storage (Solidity)" from template picker
  • Verify .sol file has syntax highlighting and blue icon
  • Click "Compile" — verify compilation output in result panel
  • Connect MetaMask to Flow EVM testnet — verify dual wallet shows EVM address
  • Switch to .cdc file — verify button switches back to green "Run"
  • Try "Cross-VM" template — verify both .sol and .cdc files present

Notes

🤖 Generated with Claude Code

zenabot27 and others added 14 commits March 15, 2026 01:55
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mirrors CadenceLSPClient but spawns `solidity-language-server --stdio`
(Rust binary from mmsaki/solidity-language-server). Uses LSP
Content-Length framing over stdio, supports initialize/request/notify/
shutdown lifecycle, and emits notification events for server-to-client
forwarding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a second WebSocketServer on port 3004 at /lsp-sol that forwards
JSON-RPC between WebSocket clients and a shared SolidityLSPClient
instance. Handles init, initialize, initialized, didOpen, didChange,
didClose, and generic request/notification forwarding. Includes
per-connection doc tracking and cleanup on disconnect, plus graceful
shutdown integration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Route /lsp-sol through nginx to the Solidity LSP WebSocket server on
port 3004, with HTTP/1.1 upgrade support and 24h read timeout matching
the existing /lsp Cadence endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Download and install the Rust-based solidity-language-server v0.1.32
binary from mmsaki/solidity-language-server in the final nginx:alpine
stage. Also expose port 3004 for the Solidity LSP WebSocket server.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add wagmi and react-query providers to main.tsx entry point, wrapping
the existing AuthProvider + Router tree. This enables wagmi hooks
(useAccount, useConnect, useDisconnect) throughout the app.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add "EVM Wallet" option to the connect dropdown using wagmi hooks
(useAccount, useConnect, useDisconnect) with injected connector. When
connected with EVM wallet and editing Solidity files, show address with
orange accent and Globe icon. All existing Flow/FCL wallet functionality
remains unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add evmAddressFromSecp256k1() to derive EVM addresses from secp256k1
public keys via keccak256 (last 20 bytes), and getEvmAddress() as a
convenience wrapper for LocalKey objects. Uses viem's keccak256.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…uage support

Add languageId option to MonacoLspAdapterOptions so the adapter can register
Monaco providers (completion, hover, definition, signature help, diagnostics)
for any language, not just Cadence. Defaults to CADENCE_LANGUAGE_ID when
not specified.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Create a simplified LSP hook for Solidity that connects to /lsp-sol
WebSocket endpoint (server mode only, no WASM fallback). Only activates
when enabled=true (i.e., project has .sol files). Handles document
open/change/close sync for .sol files only.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Detect language from file path extension (.sol vs .cdc). Set Monaco
language and theme dynamically — Solidity files use 'sol' language with
vs-dark/vs themes; Cadence files keep existing Cadence themes. Skip
Cadence-specific language/theme/TextMate registration for .sol files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add three new templates for Solidity/EVM development:
- Simple Storage: basic getter/setter contract (pragma 0.8.24)
- ERC-20 Token: transfer/approve/transferFrom implementation
- Cross-VM: Solidity Counter + Cadence script calling EVM.run()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add blue file icon for .sol files in the tree view
- Preserve .sol extension in auto-extension logic (InlineFolderInput
  and handleCreate) instead of forcing .cdc
- Update placeholder text to mention .sol

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add solc WASM dependency for browser-side Solidity compilation
- Create evmExecute.ts with compileSolidity() function
- Wire useSolidityLsp hook into App for .sol file LSP support
- Add handleRunSolidity handler for compile flow
- Route handleRun by file type (.sol vs .cdc)
- Update run button label/color for Solidity (orange, "Compile")
- Route LSP notifications by file extension

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
zenabot27 and others added 15 commits March 15, 2026 02:20
When EVM wallet is connected, handleRunSolidity now auto-deploys the
compiled contract to Flow EVM via walletClient.deployContract() and
shows the contract address + tx hash in the result panel.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Uses wagmi useSwitchChain to keep EVM wallet chain in sync with the
Flow network selector (mainnet→747, testnet→545).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move solc compilation to a Web Worker to avoid Emscripten/WASM issues
  on the browser main thread (cwrap errors, >8MB sync compile block)
- Worker loads soljson.js via fetch+eval to preserve Emscripten globals
- Add vite-plugin-node-polyfills for Node.js builtins (util, stream, etc.)
- Add 8 Playwright e2e tests covering: template loading, editor mode,
  compilation, error handling, file explorer, and cross-VM file switching
- Update playwright.config.ts for WebAssembly unlimited sync compilation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Covers: contract interaction, multi-file imports, constructor args,
revert reason parsing, solc version selection, gas estimation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add contract interaction utilities for deployed Solidity contracts:
- callContractRead() for view/pure function calls
- callContractWrite() for state-changing transactions
- estimateContractGas() for gas estimation
- categorizeAbiFunctions() to split ABI into read/write groups
- DeployedContract and ContractCallResult interfaces

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…or support

Parse EVM revert data into human-readable messages:
- Error(string) for require/revert with reason
- Panic(uint256) with well-known panic code descriptions
- Custom errors decoded against the contract ABI
- extractRevertData() to pull hex data from viem error objects

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Type-aware input component for Solidity ABI parameters using viem types.
Renders bool as toggle switch (orange/zinc), address/uint/int/bytes/string
as text inputs with appropriate placeholders, and arrays/tuples expecting
JSON. Includes parseParamValue helper for converting string inputs to
correct JS types (BigInt, boolean, etc.) for viem contract calls.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rsion selection

Support multi-file Solidity compilation by accepting a `sources` map in
addition to single-file input. Add solc version selection via the
Solidity CDN (binaries.soliditylang.org) with compiler caching per
version. Saves/restores `self.Module` when loading alternate versions to
prevent clobbering the bundled compiler. Contracts are now collected from
all source files in the output with a `sourceFile` field.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… evmExecute

Add compileSolidityMultiFile() for compiling multiple .sol files together
via the worker's new sources field. Add detectPragmaVersion() to extract
the solc version from pragma directives. Update compileSolidity() to
accept an optional solcVersion parameter. Add sourceFile field to
CompilationResult contract type.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…t calls

Wire parseRevertReason + extractRevertData from evmRevert.ts into:
- callContractWrite() catch block in evmContract.ts
- deploySolidity() catch block in evmExecute.ts

Both now decode Error(string), Panic(uint256), and custom errors
from revert data instead of showing raw viem error messages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…, and e2e tests

- Add deployedContract state + Interact tab in ResultPanel after successful deploy
- Wire multi-file Solidity compilation (collects all .sol files in project)
- Add pragma version detection for display in compilation results
- Prefer contract from active file in multi-file compilation output
- Fix CDN solc loading with Emscripten onRuntimeInitialized callback
- Add ContractInteraction component with read/write function cards
- Add 8 new e2e tests covering: pragma detection, multi-file compilation,
  constructor params, compilation errors, Interact tab visibility, bytecodeSize

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes: route naming consistency (/transaction/ not /tx/), address
detection logic for non-COA EVM addresses, parallel tx hash lookup,
cursor-based pagination strategy, search merge details, error states,
TypeScript type generation, and external link migration plan.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…caching)

- Define COAAccountPage vs EVMAccountPage routing trigger
- Fix /flow/v1/coa/ to /flow/coa/ (correct path)
- Add EVM_ADDR search pattern for 0x+40hex
- Add caching for EVM search endpoint
- Clarify Cadence→EVM tx resolution in parallel lookup

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
zenabot27 and others added 30 commits March 16, 2026 22:02
Add TxPreviewResponse, AddressPreviewResponse and related types to
blockscout.ts. Add fetchSearchPreview() to evm.ts for the new
/flow/search/preview endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ution

Adds GET /flow/search/preview?q={query}&type={tx|address} that performs
parallel lookups across Cadence DB and Blockscout EVM API, resolving
COA links and EVM<->Cadence transaction mappings with graceful degradation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ation

Add 'preview' search mode that fires an immediate (non-debounced) preview
API call for pattern-matched queries (EVM tx, Cadence tx, EVM address, Flow
account). Keeps quickMatches available for Enter-key fallback navigation
while the preview loads.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ships

Add preview mode rendering to SearchDropdown with rich cards for tx and
address previews, including Cadence/EVM cross-chain link display, loading
skeletons, error states, and keyboard navigation support.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
nx run-many fails in Docker scoped workspaces due to missing transitive
deps. Revert to explicit ordered builds (which are proven to work) and
add flowtoken to all three Dockerfiles.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause: Dockerfiles didn't COPY nx.json, so nx had no config and
ran all package builds in parallel. auth-core depends on flow-passkey
but flow-passkey hadn't finished building yet → build failure.

Locally this wasn't an issue because dist/ directories already existed
from prior builds. Docker starts fresh with no dist/.

Fix: COPY nx.json into all three Dockerfiles so nx can read
targetDefaults.build.dependsOn and build packages in correct order.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rename "Cadence Runner" → "Flow Runner" in header, title, meta tags
- Fix Cadence LSP sending .sol files for analysis (caused "unexpected
  token: identifier" errors on Solidity files)
- Split template grid into Cadence and Solidity sections with visual
  distinction (emerald borders for Cadence, orange for Solidity/EVM)
- Update default welcome comment to mention Solidity support

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ar search, deploy tab, Solidity purple branding

- Project identity persisted via URL (?project=slug for cloud, ?local=id for anonymous)
- CloudMeta saved to localStorage so page refresh reconnects to same project
- Anonymous multi-project support with local project store
- Import from Address dialog (Cadence via FCL, Solidity via Blockscout proxy)
- Cross-file search panel in sidebar with regex, replace, jump-to-line
- Deploy tab in activity bar navigates to /deploy page
- File menu in header (New Project, Open File/Folder, Import, Export, Share)
- Local file/folder import via browser file picker
- Solidity icon uses official SVG, all Solidity UI elements use purple branding
- 3 new Solidity templates (ERC-721, Multi-Sig, Staking Vault)
- ProjectSelector shown for anonymous users with local projects
- Template click immediately creates named project (no duplicate Untitled)
- Server proxy endpoint for Blockscout EVM contract fetching

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the EVM early return in TransactionDetail after all hook calls to
satisfy React's Rules of Hooks. Also remove unused `redirect` import and
prefix unused `_search` param in accounts/$address.tsx.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add 9 EVM proxy routes (Blockscout proxies and search preview) to the
specExcludedRoutes list in TestAllRoutesInSpec so they don't require
full OpenAPI documentation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Guard toLocaleString calls against undefined values (tx_count, block_height, contracts_count)
- Add HighlightMatch to preview hashes/addresses for search term highlighting
- Show EVM hash in EVM tx preview card
- Add ?view=evm param to EVM tx links so they render EVMTxDetail instead of
  being auto-resolved to parent Cadence tx
- Add view search param to txs/$txId route validation and loader

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…e auto-redirect

- Widen search bar from max-w-xl to max-w-3xl
- Update placeholder to mention public key
- Smaller text on mobile (text-xs) for long hashes
- Add max-h-70vh + overflow-y-auto to SearchDropdown for mobile
- Truncate long hashes in preview cards
- Remove Cadence auto-resolution from /txs/evm/$txId — now redirects
  with ?view=evm to show EVMTxDetail directly

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ovements

- Fix i.map crash: handle Blockscout token balance response as paginated or array
- Fix empty tx_hash in token transfers: support both tx_hash and transaction_hash fields
- Add tab to URL search params in EVMAccountPage
- Show contract name instead of "EVM Account" when available
- Add verified badge for verified contracts
- Add console warning for address info load failures

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…w requests

- Add blockscoutAPIKey field to Server struct, read from BLOCKSCOUT_API_KEY env
- Append apikey= query param in proxyBlockscout for rate limit bypass
- Pass API key in search preview handler's direct Blockscout calls
- Pass API key in enriched address handler's manual Blockscout request

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ionship

- When searching a Flow address, show Cadence result first with "Flow Address"
  label, then linked EVM as "↳ Linked EVM (COA)" indented
- When searching an EVM address, show EVM result first, then linked Flow as
  "Linked COA Owner"
- Add HighlightMatch to Cadence address in preview
- Update getFlatItems ordering to match visual order

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend returns `link` (not `coa_link`) and `coa_address` (not `evm_address`).
Updated frontend types and SearchDropdown to handle both field names.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…Ts tabs

- EVM addresses always render EVMAccountPage (no COAAccountPage)
- COA link shown as "Linked Flow Account" in header instead of tab group
- Split "Token Holdings" into separate "Tokens" and "NFTs" tabs
- COA accounts: reuse Cadence AccountTokensTab (with EVM subtab) and
  AccountNFTsTab for familiar token/NFT display
- Non-COA: keep EVMTokenHoldings for tokens, show message for NFTs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… external Blockscout

- Replace <a href=evm.flowindex.io> with <Link to=/accounts/{evmAddr}>
- Use ArrowRightLeft icon instead of ExternalLink (internal navigation)
- Clicking COA badge on Cadence account page now navigates to EVM account page

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- AddressLink: EVM addresses (COA/EOA) now show a small external link icon
  that opens the address on Blockscout (evm.flowindex.io)
- Default click on the address still navigates to internal FlowIndex page
- Icon has hover tooltip "Open in Blockscout"
- Applies everywhere AddressLink is used (tx lists, token transfers, etc.)
- Flow addresses (16 hex) do not show the icon
- New prop showBlockscoutLink to override default behavior

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rple color for EVM addresses

- Replace ExternalLink icon with official Blockscout symbol SVG
- Blockscout icon uses brand purple (#5353D3), 60% opacity → 100% on hover
- EVM addresses (COA/EOA) now render in purple instead of green
- Cadence/Flow addresses remain green
- Consistent visual distinction between Cadence and EVM address types

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…fordance

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…odal

- Remove ProjectSelector dropdown from sidebar, show simple project name label
- New ProjectManagerModal: search, rename, delete, open projects in a centered modal
- Add "Projects..." entry in File menu to open the modal
- Sidebar project label is clickable and opens the modal

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add top-level Cadence/EVM toggle on account page (only for COA accounts)
- Cadence view shows existing Cadence stats + tabs (Activity, Tokens, etc.)
- EVM view shows COA address info, EVM stats cards, and EVM tabs
  (Transactions, Internal Txs, Token Transfers, Tokens, NFTs)
- Fix Blockscout icon + arrow alignment in AddressLink component
- View state persisted in URL via ?view=evm search param

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move Cadence/EVM switcher between stats cards and tab bar
- New style: solid green (Cadence) / purple (EVM) fills with colored
  dot indicators, visually distinct from black/white content tabs
- Pass viewSwitcher as prop to EVMViewEmbed for consistent placement
- Blockscout external link icon now hidden by default, appears on
  hover over the address (reduces visual clutter in lists)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend:
- Add /flow/evm/address/{address}/nft proxy to Blockscout NFT endpoint
- Add route to specExcludedRoutes in test

Frontend:
- Add BSNFTInstance type with metadata (image, name, attributes)
- Add getEVMAddressNFTs API function with pagination
- Create EVMNFTsTab component with grid layout, image thumbnails,
  collection names, token IDs, and load-more pagination
- Replace AccountNFTsTab (Cadence data) with EVMNFTsTab (Blockscout
  data) in both EVMAccountPage and EVMViewEmbed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New /interact page: load any deployed EVM contract by address, fetch ABI from Blockscout, call read/write methods
- Sidebar "Test" tab (FlaskConical icon) navigates to /interact
- Blockscout proxy extended: returns ABI field, supports ?network=testnet
- Recent contracts persisted in localStorage (max 10)
- URL deep-linking: /interact?address=0x...&network=mainnet
- Manual ABI paste fallback for unverified contracts
- Tx hash links to FlowIndex (testnet-aware)
- Solidity branding: orange → violet across all components
- Vite dev proxy + nginx production proxy for /api/evm-contracts
- DeployedContract.deployTxHash now optional

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tools for Sim Studio to orchestrate AI agents on Flow Launch Panel:
- register_agent, list_agents, get_agent, update_agent
- post_comment (rate limited), upload_image (base64)
- list_tokens, get_token, get_quote (public, no auth)

API: https://agent-api-production-bab2.up.railway.app

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
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