From c8279f0e696bbff2b051b364019b15e91c71df6a Mon Sep 17 00:00:00 2001 From: Manuel Wedler Date: Mon, 2 Mar 2026 17:31:19 +0100 Subject: [PATCH 1/7] Add Renovate config --- renovate.json | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 renovate.json diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..9ff60cb --- /dev/null +++ b/renovate.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "configMigration": true, + "extends": ["config:recommended", "schedule:daily"], + "packageRules": [ + { + "matchUpdateTypes": [ + "minor", + "patch", + "pin", + "digest", + "lockFileMaintenance", + "rollback", + "bump" + ], + "groupName": "all patch and minor dependencies", + "groupSlug": "all-patch-and-minor" + } + ], + "ignoreDeps": ["node", "cimg/node"], + "major": { + "dependencyDashboardApproval": true + }, + "rangeStrategy": "pin", + "timezone": "Europe/Berlin", + "schedule": ["before 6am on tuesday"] +} From 789857c02af38d6b4b4094bd8e815a43a3b957a1 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 3 Mar 2026 08:26:28 +0000 Subject: [PATCH 2/7] Merge pull request #27 from renovate-bot/renovate/all-patch-and-minor Pin dependencies --- package-lock.json | 56 +++++++++++++++++++++++++++-------------------- package.json | 42 +++++++++++++++++------------------ 2 files changed, 53 insertions(+), 45 deletions(-) diff --git a/package-lock.json b/package-lock.json index 26d8968..bafc9bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,33 +5,33 @@ "packages": { "": { "dependencies": { - "@ethereum-sourcify/lib-sourcify": "^2.3.0", - "@headlessui/react": "^2.2.4", + "@ethereum-sourcify/lib-sourcify": "2.3.0", + "@headlessui/react": "2.2.4", "@react-router/node": "^7.5.3", - "@react-router/serve": "^7.5.3", - "@solidity-parser/parser": "^0.20.1", + "@react-router/serve": "7.6.2", + "@solidity-parser/parser": "0.20.1", "diff": "^8.0.2", - "ethers": "^6.14.4", - "fuse.js": "^7.1.0", - "isbot": "^5.1.27", - "react": "^19.1.0", - "react-dom": "^19.1.0", - "react-icons": "^5.5.0", + "ethers": "6.15.0", + "fuse.js": "7.1.0", + "isbot": "5.1.28", + "react": "19.1.0", + "react-dom": "19.1.0", + "react-icons": "5.5.0", "react-router": "^7.5.3", - "react-tooltip": "^5.29.1", - "serve": "^14.2.5" + "react-tooltip": "5.29.1", + "serve": "14.2.5" }, "devDependencies": { - "@ethereum-sourcify/compilers-types": "^1.0.7", - "@react-router/dev": "^7.5.3", - "@tailwindcss/vite": "^4.1.4", - "@types/node": "^20", - "@types/react": "^19.1.2", - "@types/react-dom": "^19.1.2", - "tailwindcss": "^4.1.4", - "typescript": "^5.8.3", + "@ethereum-sourcify/compilers-types": "1.0.7", + "@react-router/dev": "7.6.2", + "@tailwindcss/vite": "4.1.10", + "@types/node": "20.19.1", + "@types/react": "19.1.8", + "@types/react-dom": "19.1.6", + "tailwindcss": "4.1.10", + "typescript": "5.8.3", "vite": "^6.3.3", - "vite-tsconfig-paths": "^5.1.4" + "vite-tsconfig-paths": "5.1.4" } }, "node_modules/@adraffy/ens-normalize": { @@ -1423,6 +1423,7 @@ "version": "2.2.4", "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.2.4.tgz", "integrity": "sha512-lz+OGcAH1dK93rgSMzXmm1qKOJkBUqZf1L4M8TWLNplftQD3IkoEDdUFNfAn4ylsN6WOTVtWaLmvmaHOUk1dTA==", + "license": "MIT", "dependencies": { "@floating-ui/react": "^0.26.16", "@react-aria/focus": "^3.20.2", @@ -2198,7 +2199,8 @@ "node_modules/@solidity-parser/parser": { "version": "0.20.1", "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.20.1.tgz", - "integrity": "sha512-58I2sRpzaQUN+jJmWbHfbWf9AKfzqCI8JAdFB0vbyY+u8tBRcuTt9LxzasvR0LGQpcRv97eyV7l61FQ3Ib7zVw==" + "integrity": "sha512-58I2sRpzaQUN+jJmWbHfbWf9AKfzqCI8JAdFB0vbyY+u8tBRcuTt9LxzasvR0LGQpcRv97eyV7l61FQ3Ib7zVw==", + "license": "MIT" }, "node_modules/@swc/helpers": { "version": "0.5.17", @@ -3628,6 +3630,7 @@ "version": "22.7.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", + "license": "MIT", "dependencies": { "undici-types": "~6.19.2" } @@ -3635,12 +3638,14 @@ "node_modules/ethers/node_modules/tslib": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "license": "0BSD" }, "node_modules/ethers/node_modules/undici-types": { "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "license": "MIT" }, "node_modules/execa": { "version": "5.1.1", @@ -3876,6 +3881,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.1.0.tgz", "integrity": "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==", + "license": "Apache-2.0", "engines": { "node": ">=10" } @@ -5304,6 +5310,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz", "integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==", + "license": "MIT", "peerDependencies": { "react": "*" } @@ -5353,6 +5360,7 @@ "version": "5.29.1", "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.29.1.tgz", "integrity": "sha512-rmJmEb/p99xWhwmVT7F7riLG08wwKykjHiMGbDPloNJk3tdI73oHsVOwzZ4SRjqMdd5/xwb/4nmz0RcoMfY7Bw==", + "license": "MIT", "dependencies": { "@floating-ui/dom": "^1.6.1", "classnames": "^2.3.0" diff --git a/package.json b/package.json index 965f91a..fc51157 100644 --- a/package.json +++ b/package.json @@ -9,32 +9,32 @@ "typecheck": "react-router typegen && tsc" }, "dependencies": { - "@ethereum-sourcify/lib-sourcify": "^2.3.0", - "@headlessui/react": "^2.2.4", + "@ethereum-sourcify/lib-sourcify": "2.3.0", + "@headlessui/react": "2.2.4", "@react-router/node": "^7.5.3", - "@react-router/serve": "^7.5.3", - "@solidity-parser/parser": "^0.20.1", + "@react-router/serve": "7.6.2", + "@solidity-parser/parser": "0.20.1", "diff": "^8.0.2", - "ethers": "^6.14.4", - "fuse.js": "^7.1.0", - "isbot": "^5.1.27", - "react": "^19.1.0", - "react-dom": "^19.1.0", - "react-icons": "^5.5.0", + "ethers": "6.15.0", + "fuse.js": "7.1.0", + "isbot": "5.1.28", + "react": "19.1.0", + "react-dom": "19.1.0", + "react-icons": "5.5.0", "react-router": "^7.5.3", - "react-tooltip": "^5.29.1", - "serve": "^14.2.5" + "react-tooltip": "5.29.1", + "serve": "14.2.5" }, "devDependencies": { - "@ethereum-sourcify/compilers-types": "^1.0.7", - "@react-router/dev": "^7.5.3", - "@tailwindcss/vite": "^4.1.4", - "@types/node": "^20", - "@types/react": "^19.1.2", - "@types/react-dom": "^19.1.2", - "tailwindcss": "^4.1.4", - "typescript": "^5.8.3", + "@ethereum-sourcify/compilers-types": "1.0.7", + "@react-router/dev": "7.6.2", + "@tailwindcss/vite": "4.1.10", + "@types/node": "20.19.1", + "@types/react": "19.1.8", + "@types/react-dom": "19.1.6", + "tailwindcss": "4.1.10", + "typescript": "5.8.3", "vite": "^6.3.3", - "vite-tsconfig-paths": "^5.1.4" + "vite-tsconfig-paths": "5.1.4" } } From 487af29f9036ec6126ca200245c3166d7e426e87 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 3 Mar 2026 08:32:48 +0000 Subject: [PATCH 3/7] Update dependency vite to v6.4.1 [SECURITY] (#25) --- package-lock.json | 66 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index bafc9bb..53cfe2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2438,6 +2438,66 @@ "node": ">=14.0.0" } }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.4.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.0.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.4.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.10", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.9.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { + "version": "0.9.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { + "version": "2.8.0", + "dev": true, + "inBundle": true, + "license": "0BSD", + "optional": true + }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { "version": "4.1.10", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.10.tgz", @@ -6350,9 +6410,9 @@ } }, "node_modules/vite": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", - "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "dev": true, "license": "MIT", "dependencies": { From d88698528f90cf036536bd50f69eea97f70d3bfc Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 3 Mar 2026 08:34:48 +0000 Subject: [PATCH 4/7] Update dependency diff to v8.0.3 [SECURITY] (#24) --- package-lock.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 53cfe2d..bb6685a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3443,9 +3443,10 @@ } }, "node_modules/diff": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", - "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz", + "integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } From 3cda737956f351a91639487199fd17ee4236a343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Tue, 24 Mar 2026 09:23:17 +0300 Subject: [PATCH 5/7] feat: add Fe language support for contract verification Support verifying Fe smart contracts following the Fe language support added to the Sourcify server. Changes include: - Language selector button with Fe icon - Fe compiler versions fetched from GitHub releases (2025+ only, prereleases shown by default) - .fe file extension support in file upload with Fe icon - Contract identifier parsing for Fe (filename-based like Vyper, format: src/file.fe:Name) - Compiler settings panel hidden for Fe (no EVM version or optimizer) - EVM version not required in form validation for Fe - API request sends language as "Fe" to Sourcify server Co-Authored-By: Claude Opus 4.6 --- .../verification/CompilerSelector.tsx | 31 ++++++++----- .../verification/CompilerSettings.tsx | 7 ++- .../verification/ContractIdentifier.tsx | 29 ++++++++++-- .../verification/EvmVersionSelector.tsx | 2 +- app/components/verification/FileUpload.tsx | 12 +++-- .../verification/LanguageSelector.tsx | 19 ++++++++ app/contexts/CompilerVersionsContext.tsx | 45 +++++++++++++++++++ app/data/verificationMethods.tsx | 1 + app/hooks/useFormValidation.ts | 7 ++- app/types/verification.ts | 3 +- app/utils/sourcifyApi.ts | 6 +-- public/fe.svg | 18 ++++++++ 12 files changed, 152 insertions(+), 28 deletions(-) create mode 100644 public/fe.svg diff --git a/app/components/verification/CompilerSelector.tsx b/app/components/verification/CompilerSelector.tsx index 7684d63..62d68af 100644 --- a/app/components/verification/CompilerSelector.tsx +++ b/app/components/verification/CompilerSelector.tsx @@ -1,6 +1,6 @@ import React, { useState } from "react"; import { useCompilerVersions } from "../../contexts/CompilerVersionsContext"; -import type { SolidityVersion, VyperVersion } from "../../contexts/CompilerVersionsContext"; +import type { SolidityVersion, VyperVersion, FeVersion } from "../../contexts/CompilerVersionsContext"; import type { Language, SelectedMethod } from "../../types/verification"; interface CompilerSelectorProps { @@ -21,14 +21,18 @@ export default function CompilerSelector({ officialSolidityVersions, vyperVersions, officialVyperVersions, + feVersions, + officialFeVersions, isSolidityLoading, isVyperLoading, + isFeLoading, solidityError, vyperError, + feError, } = useCompilerVersions(); const [showNightlyBuilds, setShowNightlyBuilds] = useState(false); - const [showPrereleases, setShowPrereleases] = useState(false); + const [showPrereleases, setShowPrereleases] = useState(language === "fe"); // Don't show if language is null or if using metadata/framework methods if (!language || !selectedMethod) { @@ -43,8 +47,8 @@ export default function CompilerSelector({ return null; } - const isLoading = language === "solidity" ? isSolidityLoading : isVyperLoading; - const compilerError = language === "solidity" ? solidityError : vyperError; + const isLoading = language === "solidity" ? isSolidityLoading : language === "vyper" ? isVyperLoading : isFeLoading; + const compilerError = language === "solidity" ? solidityError : language === "vyper" ? vyperError : feError; if (isLoading) { return ( @@ -72,27 +76,32 @@ export default function CompilerSelector({ const getVersionsToShow = () => { if (language === "solidity") { return showNightlyBuilds ? solidityVersions : officialSolidityVersions; - } else { + } else if (language === "vyper") { return showPrereleases ? vyperVersions : officialVyperVersions; + } else { + return showPrereleases ? feVersions : officialFeVersions; } }; const versionsToShow = getVersionsToShow(); - const formatVersionForDisplay = (version: SolidityVersion | VyperVersion) => { + const formatVersionForDisplay = (version: SolidityVersion | VyperVersion | FeVersion) => { if (language === "solidity") { return (version as SolidityVersion).version; + } else if (language === "vyper") { + return (version as VyperVersion).longVersion; } else { - const vyperVersion = version as VyperVersion; - return vyperVersion.longVersion; + return (version as FeVersion).version; } }; - const getVersionValue = (version: SolidityVersion | VyperVersion) => { + const getVersionValue = (version: SolidityVersion | VyperVersion | FeVersion) => { if (language === "solidity") { return (version as SolidityVersion).version; - } else { + } else if (language === "vyper") { return (version as VyperVersion).longVersion; + } else { + return (version as FeVersion).version; } }; @@ -147,7 +156,7 @@ export default function CompilerSelector({ htmlFor={`show${language === "solidity" ? "Nightly" : "Prerelease"}`} className="ml-2 block text-sm text-gray-700" > - {language === "solidity" ? "Show nightly builds" : "Show prereleases"} + {language === "solidity" ? "Show nightly builds" : "Show alpha/prereleases"} diff --git a/app/components/verification/CompilerSettings.tsx b/app/components/verification/CompilerSettings.tsx index 6bb631d..c8c45a4 100644 --- a/app/components/verification/CompilerSettings.tsx +++ b/app/components/verification/CompilerSettings.tsx @@ -25,8 +25,11 @@ export default function CompilerSettings({ onOptimizerEnabledChange, onOptimizerRunsChange, }: CompilerSettingsProps) { - // Only show for single-file and multiple-files methods - const shouldShow = !isFrameworkMethod && (selectedMethod === "single-file" || selectedMethod === "multiple-files"); + // Only show for single-file and multiple-files methods, and not for Fe (no compiler settings) + const shouldShow = + !isFrameworkMethod && + selectedLanguage !== "fe" && + (selectedMethod === "single-file" || selectedMethod === "multiple-files"); if (!shouldShow) return null; diff --git a/app/components/verification/ContractIdentifier.tsx b/app/components/verification/ContractIdentifier.tsx index 0e9e3e7..3d73599 100644 --- a/app/components/verification/ContractIdentifier.tsx +++ b/app/components/verification/ContractIdentifier.tsx @@ -91,6 +91,16 @@ export default function ContractIdentifier({ fullIdentifier: `${filePath}:${contractName}`, }); } + } else if (selectedLanguage === "fe" && filePath.endsWith(".fe")) { + // For Fe, generate contract identifier from file path + const contractName = filePath.split("/").pop()?.replace(".fe", "") || ""; + if (contractName) { + contracts.push({ + fileName: filePath, + contractName, + fullIdentifier: `${filePath}:${contractName}`, + }); + } } } } @@ -110,6 +120,14 @@ export default function ContractIdentifier({ contractName, fullIdentifier: `${file.name}:${contractName}`, }); + } else if (selectedLanguage === "fe" && file.name.endsWith(".fe")) { + // For Fe, generate contract identifier from file name + const contractName = file.name.replace(".fe", ""); + contracts.push({ + fileName: file.name, + contractName, + fullIdentifier: `${file.name}:${contractName}`, + }); } } } @@ -172,7 +190,7 @@ export default function ContractIdentifier({ for (const child of ast.children) { if (child.type === "ContractDefinition" && child.name) { if (!fileName) { - const extension = selectedLanguage === "solidity" ? ".sol" : ".vy"; + const extension = selectedLanguage === "solidity" ? ".sol" : selectedLanguage === "vyper" ? ".vy" : ".fe"; fileName = `${child.name}${extension}`; } @@ -207,6 +225,9 @@ export default function ContractIdentifier({ if (selectedLanguage === "vyper") { return "contracts/MyContract.vy:MyContract"; } + if (selectedLanguage === "fe") { + return "src/counter.fe:Counter"; + } return "contracts/Storage.sol:Storage"; }; @@ -267,12 +288,12 @@ export default function ContractIdentifier({ {uploadedFiles.length > 0 && parsedContracts.length === 0 && !isParsingFiles && - selectedLanguage === "vyper" && ( + (selectedLanguage === "vyper" || selectedLanguage === "fe") && (
-

Available Vyper files:

+

Available {selectedLanguage === "vyper" ? "Vyper" : "Fe"} files:

    {uploadedFiles - .filter((file) => file.name.endsWith(".vy")) + .filter((file) => file.name.endsWith(selectedLanguage === "vyper" ? ".vy" : ".fe")) .map((file, index) => (
  • • {file.name}
  • ))} diff --git a/app/components/verification/EvmVersionSelector.tsx b/app/components/verification/EvmVersionSelector.tsx index 4c7e3b2..2a1c4e7 100644 --- a/app/components/verification/EvmVersionSelector.tsx +++ b/app/components/verification/EvmVersionSelector.tsx @@ -40,7 +40,7 @@ export default function EvmVersionSelector({ selectedEvmVersion, onEvmVersionSelect, }: EvmVersionSelectorProps) { - if (!selectedLanguage) return null; + if (!selectedLanguage || selectedLanguage === "fe") return null; const evmVersions = selectedLanguage === "vyper" ? VYPER_EVM_VERSIONS : SOLIDITY_EVM_VERSIONS; diff --git a/app/components/verification/FileUpload.tsx b/app/components/verification/FileUpload.tsx index 155e3bb..ee7c59f 100644 --- a/app/components/verification/FileUpload.tsx +++ b/app/components/verification/FileUpload.tsx @@ -23,14 +23,16 @@ const getLanguageExtensions = (language: Language | null): string[] => { return [".sol"]; case "vyper": return [".vy"]; + case "fe": + return [".fe"]; default: - return [".sol", ".vy"]; + return [".sol", ".vy", ".fe"]; } }; const getFileRequirements = (method: VerificationMethod, language: Language | null): FileRequirement => { const sourceExtensions = getLanguageExtensions(language); - const languageName = language === "vyper" ? "Vyper" : "Solidity"; + const languageName = language === "vyper" ? "Vyper" : language === "fe" ? "Fe" : "Solidity"; switch (method) { case "std-json": @@ -99,7 +101,7 @@ export default function FileUpload({ if (["std-json", "metadata-json", "build-info"].includes(selectedMethod)) { return ".json"; } - return selectedLanguage === "vyper" ? ".vy" : ".sol"; + return selectedLanguage === "vyper" ? ".vy" : selectedLanguage === "fe" ? ".fe" : ".sol"; }; const validateFileName = (fileName: string): string | null => { @@ -238,6 +240,8 @@ export default function FileUpload({ return Solidity; case "vy": return Vyper; + case "fe": + return Fe; default: return ; } @@ -423,7 +427,7 @@ export default function FileUpload({ onFilesChange([]); } }} - placeholder={selectedLanguage === "vyper" ? "MyContract.vy" : "MyContract.sol"} + placeholder={selectedLanguage === "vyper" ? "MyContract.vy" : selectedLanguage === "fe" ? "MyContract.fe" : "MyContract.sol"} className={`w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-cerulean-blue-500 focus:border-cerulean-blue-500 ${ fileNameError ? "border-red-300" : "border-gray-300" }`} diff --git a/app/components/verification/LanguageSelector.tsx b/app/components/verification/LanguageSelector.tsx index 3e50dc9..af5b495 100644 --- a/app/components/verification/LanguageSelector.tsx +++ b/app/components/verification/LanguageSelector.tsx @@ -47,6 +47,25 @@ export default function LanguageSelector({ selectedLanguage, onLanguageSelect }: Vyper + +
); diff --git a/app/contexts/CompilerVersionsContext.tsx b/app/contexts/CompilerVersionsContext.tsx index 7f44e76..2645003 100644 --- a/app/contexts/CompilerVersionsContext.tsx +++ b/app/contexts/CompilerVersionsContext.tsx @@ -12,6 +12,11 @@ export interface VyperVersion { isPrerelease: boolean; } +export interface FeVersion { + version: string; + isPrerelease: boolean; +} + interface CompilerVersionsContextType { // Solidity versions solidityVersions: SolidityVersion[]; @@ -21,19 +26,26 @@ interface CompilerVersionsContextType { vyperVersions: VyperVersion[]; officialVyperVersions: VyperVersion[]; + // Fe versions + feVersions: FeVersion[]; + officialFeVersions: FeVersion[]; + // Loading states isSolidityLoading: boolean; isVyperLoading: boolean; + isFeLoading: boolean; // Error states solidityError: string | null; vyperError: string | null; + feError: string | null; } const CompilerVersionsContext = createContext(undefined); const SOLC_VERSIONS_LIST_URL = "https://raw.githubusercontent.com/ethereum/solc-bin/gh-pages/bin/list.txt"; const VYPER_VERSIONS_LIST_URL = "https://vyper-releases-mirror.hardhat.org/list.json"; +const FE_VERSIONS_LIST_URL = "https://api.github.com/repos/argotorg/fe/releases"; function formatSolidityVersionName(filename: string): SolidityVersion { // Remove "soljson-v" prefix and ".js" suffix @@ -66,10 +78,15 @@ export function CompilerVersionsProvider({ children }: { children: React.ReactNo const [vyperVersions, setVyperVersions] = useState([]); const [officialVyperVersions, setOfficialVyperVersions] = useState([]); + const [feVersions, setFeVersions] = useState([]); + const [officialFeVersions, setOfficialFeVersions] = useState([]); + const [isSolidityLoading, setIsSolidityLoading] = useState(true); const [isVyperLoading, setIsVyperLoading] = useState(true); + const [isFeLoading, setIsFeLoading] = useState(true); const [solidityError, setSolidityError] = useState(null); const [vyperError, setVyperError] = useState(null); + const [feError, setFeError] = useState(null); // Fetch Solidity versions useEffect(() => { @@ -123,6 +140,30 @@ export function CompilerVersionsProvider({ children }: { children: React.ReactNo }); }, []); + // Fetch Fe versions + useEffect(() => { + fetch(FE_VERSIONS_LIST_URL) + .then((response) => response.json()) + .then((data: { tag_name: string; published_at: string; assets: { name: string }[] }[]) => { + const allVersionsList: FeVersion[] = data + .filter((release) => release.assets.length > 0 && new Date(release.published_at).getFullYear() >= 2025) + .map((release) => { + const version = release.tag_name.replace(/^v/, ""); + const isPrerelease = /alpha|beta|rc/i.test(version); + return { version, isPrerelease }; + }); + + setFeVersions(allVersionsList); + setOfficialFeVersions(allVersionsList.filter((v) => !v.isPrerelease)); + setIsFeLoading(false); + }) + .catch((error) => { + console.error("Failed to fetch Fe versions:", error); + setIsFeLoading(false); + setFeError("Failed to fetch Fe compiler versions"); + }); + }, []); + return ( {children} diff --git a/app/data/verificationMethods.tsx b/app/data/verificationMethods.tsx index 56dd28c..921a7e1 100644 --- a/app/data/verificationMethods.tsx +++ b/app/data/verificationMethods.tsx @@ -53,6 +53,7 @@ export const solidityMetadataMethod: VerificationMethodObject = { export const verificationMethods: VerificationMethods = { solidity: [...baseVerificationMethods, solidityMetadataMethod], vyper: baseVerificationMethods, + fe: baseVerificationMethods, }; export const frameworkMethods: FrameworkMethodObject[] = [ diff --git a/app/hooks/useFormValidation.ts b/app/hooks/useFormValidation.ts index 0d532c7..75a8e2a 100644 --- a/app/hooks/useFormValidation.ts +++ b/app/hooks/useFormValidation.ts @@ -87,9 +87,12 @@ export function useFormValidation({ const areFilesRequired = languageString && selectedMethod && ["single-file", "multiple-files", "std-json", "metadata-json", "build-info"].includes(selectedMethod); - // Check if EVM version is required (for all languages, not for metadata-json, hardhat, or foundry methods) + // Check if EVM version is required (not for Fe which has no EVM version setting, or metadata-json/framework methods) const isEvmVersionRequired = - languageString && selectedMethod && ["single-file", "multiple-files"].includes(selectedMethod); + languageString && + selectedLanguage !== "fe" && + selectedMethod && + ["single-file", "multiple-files"].includes(selectedMethod); const validateFiles = () => { if (!areFilesRequired) return true; diff --git a/app/types/verification.ts b/app/types/verification.ts index 8c5d31f..4b606ee 100644 --- a/app/types/verification.ts +++ b/app/types/verification.ts @@ -1,4 +1,4 @@ -export type Language = "solidity" | "vyper"; +export type Language = "solidity" | "vyper" | "fe"; // Verification method IDs export type VerificationMethod = "single-file" | "multiple-files" | "std-json" | "metadata-json" | "build-info"; @@ -27,6 +27,7 @@ export interface FrameworkMethodObject { export interface VerificationMethods { solidity: VerificationMethodObject[]; vyper: VerificationMethodObject[]; + fe: VerificationMethodObject[]; } export interface FrameworkMessages { diff --git a/app/utils/sourcifyApi.ts b/app/utils/sourcifyApi.ts index 9f11223..9e42c76 100644 --- a/app/utils/sourcifyApi.ts +++ b/app/utils/sourcifyApi.ts @@ -95,13 +95,13 @@ async function buildStandardJsonInput( } // For Vyper, no optimization settings are added - // Only include evmVersion if it's not "default" - if (settings.evmVersion?.toLowerCase() !== "default") { + // Only include evmVersion if it's set and not "default" + if (settings.evmVersion && settings.evmVersion.toLowerCase() !== "default") { standardJsonSettings.evmVersion = settings.evmVersion; } return { - language: language === "vyper" ? "Vyper" : "Solidity", + language: language === "vyper" ? "Vyper" : language === "fe" ? "Fe" : "Solidity", sources, settings: standardJsonSettings, }; diff --git a/public/fe.svg b/public/fe.svg new file mode 100644 index 0000000..05d84dd --- /dev/null +++ b/public/fe.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + From 627045e23243409d23d0aabea88881981f18fe18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Tue, 24 Mar 2026 09:27:17 +0300 Subject: [PATCH 6/7] fix: parse Fe contract names using pub contract regex Instead of deriving the contract name from the filename, scan the source content for `pub contract ` declarations, consistent with how the Sourcify server compilers package identifies Fe contracts. Co-Authored-By: Claude Opus 4.6 --- .../verification/ContractIdentifier.tsx | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/app/components/verification/ContractIdentifier.tsx b/app/components/verification/ContractIdentifier.tsx index 3d73599..4e68481 100644 --- a/app/components/verification/ContractIdentifier.tsx +++ b/app/components/verification/ContractIdentifier.tsx @@ -92,15 +92,8 @@ export default function ContractIdentifier({ }); } } else if (selectedLanguage === "fe" && filePath.endsWith(".fe")) { - // For Fe, generate contract identifier from file path - const contractName = filePath.split("/").pop()?.replace(".fe", "") || ""; - if (contractName) { - contracts.push({ - fileName: filePath, - contractName, - fullIdentifier: `${filePath}:${contractName}`, - }); - } + const feContracts = parseFeFileContent(filePath, sourceContent); + contracts.push(...feContracts); } } } @@ -121,13 +114,9 @@ export default function ContractIdentifier({ fullIdentifier: `${file.name}:${contractName}`, }); } else if (selectedLanguage === "fe" && file.name.endsWith(".fe")) { - // For Fe, generate contract identifier from file name - const contractName = file.name.replace(".fe", ""); - contracts.push({ - fileName: file.name, - contractName, - fullIdentifier: `${file.name}:${contractName}`, - }); + const content = await file.text(); + const feContracts = parseFeFileContent(file.name, content); + contracts.push(...feContracts); } } } @@ -176,6 +165,19 @@ export default function ContractIdentifier({ } }, [isDropdownOpen]); + const parseFeFileContent = (fileName: string, content: string): ParsedContract[] => { + const contracts: ParsedContract[] = []; + const matches = content.matchAll(/pub\s+contract\s+(\w+)/g); + for (const match of matches) { + contracts.push({ + fileName, + contractName: match[1], + fullIdentifier: `${fileName}:${match[1]}`, + }); + } + return contracts; + }; + const parseFileContent = async (fileName: string | null, content: string): Promise => { try { const ast = parse(content, { From 98c52b3e22864b6953e41b2d4b2328eeabe27921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Thu, 26 Mar 2026 09:31:37 +0300 Subject: [PATCH 7/7] feat: improve Fe compiler version UI and show server URL in dev - Always show all Fe versions (including prereleases) and hide the toggle since all current Fe releases are alpha/prereleases - Filter Fe versions to only show releases after March 20, 2026 - Display server URL in the environment prefix for non-production envs Co-Authored-By: Claude Opus 4.6 --- app/components/PageLayout.tsx | 2 +- .../verification/CompilerSelector.tsx | 46 ++++++++++--------- app/contexts/CompilerVersionsContext.tsx | 2 +- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/app/components/PageLayout.tsx b/app/components/PageLayout.tsx index 0f778eb..1b31f27 100644 --- a/app/components/PageLayout.tsx +++ b/app/components/PageLayout.tsx @@ -39,7 +39,7 @@ export default function PageLayout({ children, maxWidth = "max-w-4xl", title, su const envPrefix = import.meta.env.VITE_ENV && import.meta.env.VITE_ENV !== "production" - ? `(${import.meta.env.VITE_ENV} environment) ` + ? `(${import.meta.env.VITE_ENV} environment - ${serverUrl}) ` : ""; return ( diff --git a/app/components/verification/CompilerSelector.tsx b/app/components/verification/CompilerSelector.tsx index 62d68af..ec7d3c6 100644 --- a/app/components/verification/CompilerSelector.tsx +++ b/app/components/verification/CompilerSelector.tsx @@ -79,7 +79,7 @@ export default function CompilerSelector({ } else if (language === "vyper") { return showPrereleases ? vyperVersions : officialVyperVersions; } else { - return showPrereleases ? feVersions : officialFeVersions; + return feVersions; } }; @@ -138,27 +138,29 @@ export default function CompilerSelector({ -
- { - if (language === "solidity") { - setShowNightlyBuilds(e.target.checked); - } else { - setShowPrereleases(e.target.checked); - } - }} - className="h-4 w-4 text-cerulean-blue-600 focus:ring-cerulean-blue-500 border-gray-300 rounded" - /> - -
+ {language !== "fe" && ( +
+ { + if (language === "solidity") { + setShowNightlyBuilds(e.target.checked); + } else { + setShowPrereleases(e.target.checked); + } + }} + className="h-4 w-4 text-cerulean-blue-600 focus:ring-cerulean-blue-500 border-gray-300 rounded" + /> + +
+ )} ); diff --git a/app/contexts/CompilerVersionsContext.tsx b/app/contexts/CompilerVersionsContext.tsx index 2645003..7c3f7a1 100644 --- a/app/contexts/CompilerVersionsContext.tsx +++ b/app/contexts/CompilerVersionsContext.tsx @@ -146,7 +146,7 @@ export function CompilerVersionsProvider({ children }: { children: React.ReactNo .then((response) => response.json()) .then((data: { tag_name: string; published_at: string; assets: { name: string }[] }[]) => { const allVersionsList: FeVersion[] = data - .filter((release) => release.assets.length > 0 && new Date(release.published_at).getFullYear() >= 2025) + .filter((release) => release.assets.length > 0 && new Date(release.published_at) >= new Date("2026-03-20")) .map((release) => { const version = release.tag_name.replace(/^v/, ""); const isPrerelease = /alpha|beta|rc/i.test(version);