From 090cb6c019004874544ac40798d835c6b32a3d8d Mon Sep 17 00:00:00 2001 From: Rinat Date: Wed, 14 Oct 2026 17:08:04 +0400 Subject: [PATCH 1/5] foundry: update packages/foundry JS deps (dotenv 18, ethers 6, prettier 3, toml 5) --- .changeset/foundry-deps-update.md | 5 +++++ .../foundry/packages/foundry/package.json | 13 ++++++------- .../foundry/scripts-js/checkAccountBalance.js | 7 ++++--- .../packages/foundry/scripts-js/generateTsAbis.js | 6 +++--- 4 files changed, 18 insertions(+), 13 deletions(-) create mode 100644 .changeset/foundry-deps-update.md diff --git a/.changeset/foundry-deps-update.md b/.changeset/foundry-deps-update.md new file mode 100644 index 0000000000..f8914708e5 --- /dev/null +++ b/.changeset/foundry-deps-update.md @@ -0,0 +1,5 @@ +--- +"create-eth": patch +--- + +foundry: update JS deps in `packages/foundry` (dotenv 18, ethers 6, prettier 3, qrcode 1.5.4, toml 5, shx 0.4), drop unused `envfile`. Port `checkAccountBalance.js` to the ethers v6 API and `generateTsAbis.js` to async `prettier.format`. diff --git a/templates/solidity-frameworks/foundry/packages/foundry/package.json b/templates/solidity-frameworks/foundry/packages/foundry/package.json index 9125357b77..be68d9b1b1 100644 --- a/templates/solidity-frameworks/foundry/packages/foundry/package.json +++ b/templates/solidity-frameworks/foundry/packages/foundry/package.json @@ -20,14 +20,13 @@ "postinstall": "shx cp -n .env.example .env" }, "dependencies": { - "dotenv": "~16.3.1", - "envfile": "~6.18.0", - "ethers": "~5.7.1", - "prettier": "~2.8.8", - "qrcode": "~1.5.3", - "toml": "~3.0.0" + "dotenv": "~18.0.5", + "ethers": "~6.17.0", + "prettier": "~3.9.9", + "qrcode": "~1.5.4", + "toml": "~5.0.0" }, "devDependencies": { - "shx": "^0.3.4" + "shx": "^0.4.0" } } diff --git a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/checkAccountBalance.js b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/checkAccountBalance.js index 8a3db22e19..668d6f19ca 100644 --- a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/checkAccountBalance.js +++ b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/checkAccountBalance.js @@ -40,12 +40,11 @@ async function getBalanceForEachNetwork(address) { const networkUrl = replaceENVAlchemyKey(rpcEndpoints[networkName]); console.log(`\n--${networkName}-- šŸ“”`); + const provider = new ethers.JsonRpcProvider(networkUrl, undefined, { staticNetwork: true }); try { - const provider = new ethers.providers.JsonRpcProvider(networkUrl); - // Get balance and format it const balance = await provider.getBalance(address); - const formattedBalance = +ethers.utils.formatUnits(balance); + const formattedBalance = +ethers.formatUnits(balance); console.log(" Balance:", formattedBalance); console.log(" Nonce:", await provider.getTransactionCount(address)); @@ -53,6 +52,8 @@ async function getBalanceForEachNetwork(address) { console.log( ` āŒ Can't connect to network ${networkName}: ${e.message}` ); + } finally { + provider.destroy(); } } } catch (error) { diff --git a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/generateTsAbis.js b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/generateTsAbis.js index c679bc19a3..4b20f1247a 100644 --- a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/generateTsAbis.js +++ b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/generateTsAbis.js @@ -202,7 +202,7 @@ function processAllDeployments(broadcastPath) { return allContracts; } -function main() { +async function main() { const current_path_to_broadcast = join(__dirname, "..", "broadcast"); const current_path_to_deployments = join(__dirname, "..", "deployments"); @@ -273,7 +273,7 @@ function main() { writeFileSync( `${NEXTJS_TARGET_DIR}deployedContracts.ts`, - format(fileTemplate("~~/utils/scaffold-eth/contract"), { + await format(fileTemplate("~~/utils/scaffold-eth/contract"), { parser: "typescript", // Match the nextjs prettier config (printWidth 120) so the generated file // passes the frontend lint/build instead of defaulting to printWidth 80. @@ -287,7 +287,7 @@ function main() { } try { - main(); + await main(); } catch (error) { console.error("Error:", error); process.exitCode = 1; From e487c692eb08276652ce9ee210a783f3f7d4626b Mon Sep 17 00:00:00 2001 From: Rinat Date: Wed, 14 Oct 2026 17:27:55 +0400 Subject: [PATCH 2/5] foundry: replace ethers with viem in checkAccountBalance.js --- .../{.prettier.json => .prettierrc.json} | 0 .../foundry/packages/foundry/package.json | 4 +-- .../foundry/scripts-js/checkAccountBalance.js | 28 +++++++++---------- 3 files changed, 15 insertions(+), 17 deletions(-) rename templates/solidity-frameworks/foundry/packages/foundry/{.prettier.json => .prettierrc.json} (100%) diff --git a/templates/solidity-frameworks/foundry/packages/foundry/.prettier.json b/templates/solidity-frameworks/foundry/packages/foundry/.prettierrc.json similarity index 100% rename from templates/solidity-frameworks/foundry/packages/foundry/.prettier.json rename to templates/solidity-frameworks/foundry/packages/foundry/.prettierrc.json diff --git a/templates/solidity-frameworks/foundry/packages/foundry/package.json b/templates/solidity-frameworks/foundry/packages/foundry/package.json index be68d9b1b1..c3513c91cc 100644 --- a/templates/solidity-frameworks/foundry/packages/foundry/package.json +++ b/templates/solidity-frameworks/foundry/packages/foundry/package.json @@ -21,10 +21,10 @@ }, "dependencies": { "dotenv": "~18.0.5", - "ethers": "~6.17.0", "prettier": "~3.9.9", "qrcode": "~1.5.4", - "toml": "~5.0.0" + "toml": "~5.0.0", + "viem": "~2.57.3" }, "devDependencies": { "shx": "^0.4.0" diff --git a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/checkAccountBalance.js b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/checkAccountBalance.js index 668d6f19ca..0b21d063f9 100644 --- a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/checkAccountBalance.js +++ b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/checkAccountBalance.js @@ -6,10 +6,9 @@ import { fileURLToPath } from "url"; import { toString } from "qrcode"; import { readFileSync } from "fs"; import { parse } from "toml"; -import { ethers } from "ethers"; +import { createPublicClient, formatEther, http } from "viem"; -const ALCHEMY_API_KEY = - process.env.ALCHEMY_API_KEY || "IZYEU2cWBgnFmgiTAgpWD"; +const ALCHEMY_API_KEY = process.env.ALCHEMY_API_KEY || "IZYEU2cWBgnFmgiTAgpWD"; // Load environment variables const __filename = fileURLToPath(import.meta.url); @@ -40,20 +39,19 @@ async function getBalanceForEachNetwork(address) { const networkUrl = replaceENVAlchemyKey(rpcEndpoints[networkName]); console.log(`\n--${networkName}-- šŸ“”`); - const provider = new ethers.JsonRpcProvider(networkUrl, undefined, { staticNetwork: true }); try { + const client = createPublicClient({ transport: http(networkUrl, { retryCount: 0 }) }); + // Get balance and format it - const balance = await provider.getBalance(address); - const formattedBalance = +ethers.formatUnits(balance); + const balance = await client.getBalance({ address }); + const formattedBalance = +formatEther(balance); console.log(" Balance:", formattedBalance); - console.log(" Nonce:", await provider.getTransactionCount(address)); + console.log(" Nonce:", await client.getTransactionCount({ address })); } catch (e) { - console.log( - ` āŒ Can't connect to network ${networkName}: ${e.message}` - ); - } finally { - provider.destroy(); + // viem errors: HTTP failures carry a status, RPC/network errors carry a one-line reason in details + const reason = e.status ? `HTTP ${e.status}` : (e.details || e.shortMessage || e.message).split("\n")[0]; + console.log(` āŒ Can't connect to network ${networkName}: ${reason}`); } } } catch (error) { @@ -66,7 +64,7 @@ async function checkAccountBalance() { // Step 1: List accounts and let user select one console.log("šŸ“‹ Listing available accounts..."); const selectedKeystore = await listKeystores( - "Select a keystore to display its balance (enter the number, e.g., 1): " + "Select a keystore to display its balance (enter the number, e.g., 1): ", ); if (!selectedKeystore) { @@ -96,10 +94,10 @@ async function checkAccountBalance() { // Run the function if this script is called directly if (process.argv[1] === fileURLToPath(import.meta.url)) { - checkAccountBalance().catch((error) => { + checkAccountBalance().catch(error => { console.error(error); process.exit(1); }); } -export { checkAccountBalance }; \ No newline at end of file +export { checkAccountBalance }; From a46349f00b8bf43c5b9ead6f51bda24ad556806b Mon Sep 17 00:00:00 2001 From: Rinat Date: Wed, 14 Oct 2026 17:27:57 +0400 Subject: [PATCH 3/5] foundry: fix prettier config filename and format scripts-js with it --- .../foundry/scripts-js/generateKeystore.js | 33 +++---- .../foundry/scripts-js/generateTsAbis.js | 86 ++++++------------- .../foundry/scripts-js/importAccount.js | 28 +++--- .../foundry/scripts-js/listKeystores.js | 20 ++--- .../packages/foundry/scripts-js/parseArgs.js | 26 ++---- .../packages/foundry/scripts-js/revealPK.js | 4 +- .../scripts-js/selectOrCreateKeystore.js | 50 ++++------- 7 files changed, 81 insertions(+), 166 deletions(-) diff --git a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/generateKeystore.js b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/generateKeystore.js index 7c5d7a5cb8..a22c1fc8cc 100644 --- a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/generateKeystore.js +++ b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/generateKeystore.js @@ -17,16 +17,13 @@ async function createKeystore() { }); if (newWalletResult.error || newWalletResult.status !== 0) { - console.error( - "\nāŒ Error generating new wallet:", - newWalletResult.stderr || newWalletResult.error - ); + console.error("\nāŒ Error generating new wallet:", newWalletResult.stderr || newWalletResult.error); process.exit(1); } const privateKey = newWalletResult.stdout .split("\n") - .find((line) => line.includes("Private key:")) + .find(line => line.includes("Private key:")) ?.split(":")[1] ?.trim(); @@ -35,7 +32,7 @@ async function createKeystore() { process.exit(1); } - const keystoreName = await new Promise((resolve) => { + const keystoreName = await new Promise(resolve => { rl.question("\nEnter name for new keystore: ", resolve); }); @@ -43,21 +40,15 @@ async function createKeystore() { rl.close(); return new Promise((resolve, reject) => { - const importProcess = spawn( - "cast", - ["wallet", "import", keystoreName, "--private-key", privateKey], - { - stdio: "inherit", - } - ); + const importProcess = spawn("cast", ["wallet", "import", keystoreName, "--private-key", privateKey], { + stdio: "inherit", + }); - importProcess.on("close", (code) => { + importProcess.on("close", code => { if (code === 0) { + console.log("\nšŸ’° Fund the address and re-run the deploy command to use this keystore."); console.log( - "\nšŸ’° Fund the address and re-run the deploy command to use this keystore." - ); - console.log( - `\nTIP: Use \`yarn account\` and select \`${keystoreName}\` keystore to check if the address is funded.` + `\nTIP: Use \`yarn account\` and select \`${keystoreName}\` keystore to check if the address is funded.`, ); process.exit(0); } else { @@ -78,13 +69,13 @@ async function createKeystore() { // Run the function if this script is called directly if (process.argv[1] === fileURLToPath(import.meta.url)) { createKeystore() - .then((keystoreName) => { + .then(keystoreName => { process.exit(0); }) - .catch((error) => { + .catch(error => { console.error(error); process.exit(1); }); } -export { createKeystore }; \ No newline at end of file +export { createKeystore }; diff --git a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/generateTsAbis.js b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/generateTsAbis.js index 4b20f1247a..ce4ba4fad0 100644 --- a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/generateTsAbis.js +++ b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/generateTsAbis.js @@ -1,11 +1,4 @@ -import { - readdirSync, - statSync, - readFileSync, - existsSync, - mkdirSync, - writeFileSync, -} from "fs"; +import { readdirSync, statSync, readFileSync, existsSync, mkdirSync, writeFileSync } from "fs"; import { join, dirname } from "path"; import { fileURLToPath } from "url"; import { format } from "prettier"; @@ -54,12 +47,7 @@ function getDeploymentHistory(broadcastPath) { // Sort files to process them in chronological order const runFiles = files - .filter( - (file) => - file.startsWith("run-") && - file.endsWith(".json") && - !file.includes("run-latest") - ) + .filter(file => file.startsWith("run-") && file.endsWith(".json") && !file.includes("run-latest")) .sort((a, b) => { // Extract run numbers and compare them const runA = parseInt(a.match(/run-(\d+)/)?.[1] || "0"); @@ -68,9 +56,7 @@ function getDeploymentHistory(broadcastPath) { }); for (const file of runFiles) { - const { transactions, receipts } = parseTransactionAndReceiptRun( - join(broadcastPath, file) - ); + const { transactions, receipts } = parseTransactionAndReceiptRun(join(broadcastPath, file)); for (const tx of transactions) { if (tx.transactionType === "CREATE" || tx.transactionType === "CREATE2") { @@ -80,7 +66,7 @@ function getDeploymentHistory(broadcastPath) { address: tx.contractAddress, deploymentFile: file, transaction: tx, - receipt: receipts.find((r) => r.transactionHash === tx.hash), + receipt: receipts.find(r => r.transactionHash === tx.hash), }); } } @@ -112,9 +98,7 @@ function getInheritedFromContracts(artifact) { for (const astNode of artifact.ast.nodes) { if (astNode.nodeType == "ContractDefinition") { if (astNode.baseContracts.length > 0) { - inheritedFromContracts = astNode.baseContracts.map( - ({ baseName }) => baseName.name - ); + inheritedFromContracts = astNode.baseContracts.map(({ baseName }) => baseName.name); } } } @@ -146,25 +130,20 @@ function processAllDeployments(broadcastPath) { const scriptFolders = getDirectories(broadcastPath); const allDeployments = new Map(); - scriptFolders.forEach((scriptFolder) => { + scriptFolders.forEach(scriptFolder => { const scriptPath = join(broadcastPath, scriptFolder); const chainFolders = getDirectories(scriptPath); - chainFolders.forEach((chainId) => { + chainFolders.forEach(chainId => { const chainPath = join(scriptPath, chainId); const deploymentHistory = getDeploymentHistory(chainPath); - deploymentHistory.forEach((deployment) => { - const timestamp = parseInt( - deployment.deploymentFile.match(/run-(\d+)/)?.[1] || "0" - ); + deploymentHistory.forEach(deployment => { + const timestamp = parseInt(deployment.deploymentFile.match(/run-(\d+)/)?.[1] || "0"); const key = `${chainId}-${deployment.contractName}`; // Only update if this deployment is newer - if ( - !allDeployments.has(key) || - timestamp > allDeployments.get(key).timestamp - ) { + if (!allDeployments.has(key) || timestamp > allDeployments.get(key).timestamp) { allDeployments.set(key, { ...deployment, timestamp, @@ -179,7 +158,7 @@ function processAllDeployments(broadcastPath) { const allContracts = {}; - allDeployments.forEach((deployment) => { + allDeployments.forEach(deployment => { const { chainId, contractName } = deployment; const artifact = getArtifactOfContract(contractName); @@ -210,19 +189,15 @@ async function main() { const deployments = {}; // Load existing deployments from deployments directory - Deploymentchains.forEach((chain) => { + Deploymentchains.forEach(chain => { if (!chain.endsWith(".json")) return; chain = chain.slice(0, -5); - var deploymentObject = JSON.parse( - readFileSync(`${current_path_to_deployments}/${chain}.json`) - ); + var deploymentObject = JSON.parse(readFileSync(`${current_path_to_deployments}/${chain}.json`)); deployments[chain] = deploymentObject; }); // Process all deployments from all script folders - const allGeneratedContracts = processAllDeployments( - current_path_to_broadcast - ); + const allGeneratedContracts = processAllDeployments(current_path_to_broadcast); // Update contract keys based on deployments if they exist Object.entries(allGeneratedContracts).forEach(([chainId, contracts]) => { @@ -244,25 +219,18 @@ async function main() { } // Generate the deployedContracts content - const fileContent = Object.entries(allGeneratedContracts).reduce( - (content, [chainId, chainConfig]) => { - const cleanedChainConfig = Object.fromEntries( - Object.entries(chainConfig).map(([contractName, contractData]) => { - const { deploymentFile, deploymentScript, ...rest } = contractData; - return [contractName, rest]; - }) - ); - return `${content}${parseInt(chainId).toFixed(0)}:${JSON.stringify( - cleanedChainConfig, - null, - 2 - )},`; - }, - "" - ); + const fileContent = Object.entries(allGeneratedContracts).reduce((content, [chainId, chainConfig]) => { + const cleanedChainConfig = Object.fromEntries( + Object.entries(chainConfig).map(([contractName, contractData]) => { + const { deploymentFile, deploymentScript, ...rest } = contractData; + return [contractName, rest]; + }), + ); + return `${content}${parseInt(chainId).toFixed(0)}:${JSON.stringify(cleanedChainConfig, null, 2)},`; + }, ""); // Write the files - const fileTemplate = (importPath) => ` + const fileTemplate = importPath => ` ${generatedContractComment} import { GenericContractsDeclaration } from "${importPath}"; @@ -278,12 +246,10 @@ async function main() { // Match the nextjs prettier config (printWidth 120) so the generated file // passes the frontend lint/build instead of defaulting to printWidth 80. printWidth: 120, - }) + }), ); - console.log( - `šŸ“ Updated TypeScript contract definition file on ${NEXTJS_TARGET_DIR}deployedContracts.ts` - ); + console.log(`šŸ“ Updated TypeScript contract definition file on ${NEXTJS_TARGET_DIR}deployedContracts.ts`); } try { diff --git a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/importAccount.js b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/importAccount.js index cec68bc39e..4d148f674b 100644 --- a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/importAccount.js +++ b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/importAccount.js @@ -15,8 +15,8 @@ function prompt(question) { output, }); - return new Promise((resolve) => { - rl.question(question, (answer) => { + return new Promise(resolve => { + rl.question(question, answer => { rl.close(); resolve(answer); }); @@ -41,24 +41,18 @@ async function importAccount() { // Check if account name is scaffold-eth-default if (accountName === "scaffold-eth-default") { - console.error( - "\nāŒ Cannot use 'scaffold-eth-default' as account name. This is reserved for local development." - ); + console.error("\nāŒ Cannot use 'scaffold-eth-default' as account name. This is reserved for local development."); process.exit(1); } - const importProcess = spawn( - "cast", - ["wallet", "import", accountName, "--interactive"], - { - stdio: "inherit", - shell: true, - cwd: process.cwd(), - } - ); + const importProcess = spawn("cast", ["wallet", "import", accountName, "--interactive"], { + stdio: "inherit", + shell: true, + cwd: process.cwd(), + }); // Handle process completion - importProcess.on("close", (code) => { + importProcess.on("close", code => { if (code === 0) { process.exit(0); } else { @@ -73,7 +67,7 @@ async function importAccount() { } // Run the import function -importAccount().catch((error) => { +importAccount().catch(error => { console.error("\nāŒ Unexpected error:", error); process.exit(1); -}); \ No newline at end of file +}); diff --git a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/listKeystores.js b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/listKeystores.js index acf34c6250..9d7a7e0d28 100644 --- a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/listKeystores.js +++ b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/listKeystores.js @@ -3,9 +3,7 @@ import { join } from "path"; import readline from "readline"; import { fileURLToPath } from "url"; -async function listKeystores( - selectMessage = "Select a keystore (enter the number, e.g., 1):" -) { +async function listKeystores(selectMessage = "Select a keystore (enter the number, e.g., 1):") { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, @@ -14,14 +12,10 @@ async function listKeystores( const keystorePath = join(process.env.HOME, ".foundry", "keystores"); try { - const keystores = readdirSync(keystorePath).filter( - (keystore) => keystore !== "scaffold-eth-default" - ); + const keystores = readdirSync(keystorePath).filter(keystore => keystore !== "scaffold-eth-default"); if (keystores.length === 0) { - console.error( - "\nāŒ No keystores found in ~/.foundry/keystores, please create a new keystore by running:" - ); + console.error("\nāŒ No keystores found in ~/.foundry/keystores, please create a new keystore by running:"); console.log("\n\tyarn account:generate\n"); process.exit(1); } @@ -34,7 +28,7 @@ async function listKeystores( return { keystore }; }); - const answer = await new Promise((resolve) => { + const answer = await new Promise(resolve => { rl.question(`\n${selectMessage}`, resolve); }); @@ -59,13 +53,13 @@ async function listKeystores( // Run the selection if this script is called directly if (process.argv[1] === fileURLToPath(import.meta.url)) { listKeystores() - .then((keystore) => { + .then(keystore => { console.log("\nšŸ”‘ Selected keystore:", keystore); }) - .catch((error) => { + .catch(error => { console.error(error); process.exit(1); }); } -export { listKeystores }; \ No newline at end of file +export { listKeystores }; diff --git a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/parseArgs.js b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/parseArgs.js index 2eb6f137de..5e8222ba01 100644 --- a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/parseArgs.js +++ b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/parseArgs.js @@ -53,12 +53,7 @@ function validateKeystore(keystoreName) { return true; // Default keystore is always valid } - const keystorePath = join( - process.env.HOME, - ".foundry", - "keystores", - keystoreName - ); + const keystorePath = join(process.env.HOME, ".foundry", "keystores", keystoreName); return existsSync(keystorePath); } @@ -71,7 +66,7 @@ try { if (!parsedToml.rpc_endpoints[network]) { console.log( `\nāŒ Error: Network '${network}' not found in foundry.toml!`, - "\nPlease check `foundry.toml` for available networks in the [rpc_endpoints] section or add a new network." + "\nPlease check `foundry.toml` for available networks in the [rpc_endpoints] section or add a new network.", ); process.exit(1); } @@ -80,10 +75,7 @@ try { process.exit(1); } -if ( - process.env.LOCALHOST_KEYSTORE_ACCOUNT !== "scaffold-eth-default" && - network === "localhost" -) { +if (process.env.LOCALHOST_KEYSTORE_ACCOUNT !== "scaffold-eth-default" && network === "localhost") { console.log(` āš ļø Warning: Using ${process.env.LOCALHOST_KEYSTORE_ACCOUNT} keystore account on localhost. @@ -101,9 +93,7 @@ if (network !== "localhost") { // Use the keystore provided via command line argument if (!validateKeystore(keystoreArg)) { console.log(`\nāŒ Error: Keystore '${keystoreArg}' not found!`); - console.log( - `Please check that the keystore exists in ~/.foundry/keystores/` - ); + console.log(`Please check that the keystore exists in ~/.foundry/keystores/`); process.exit(1); } selectedKeystore = keystoreArg; @@ -120,15 +110,11 @@ if (network !== "localhost") { // Allow overriding the localhost keystore with --keystore flag if (!validateKeystore(keystoreArg)) { console.log(`\nāŒ Error: Keystore '${keystoreArg}' not found!`); - console.log( - `Please check that the keystore exists in ~/.foundry/keystores/` - ); + console.log(`Please check that the keystore exists in ~/.foundry/keystores/`); process.exit(1); } selectedKeystore = keystoreArg; - console.log( - `\nšŸ”‘ Using keystore: ${selectedKeystore} for localhost deployment` - ); + console.log(`\nšŸ”‘ Using keystore: ${selectedKeystore} for localhost deployment`); } // Check for default account on live network diff --git a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/revealPK.js b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/revealPK.js index a0b48ef388..1045434865 100644 --- a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/revealPK.js +++ b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/revealPK.js @@ -6,7 +6,7 @@ async function revealPk() { console.log("šŸ‘€ This will reveal your private key on the console."); const selectedKeystore = await listKeystores( - "Select a keystore to reveal its private key (enter the number, e.g., 1): " + "Select a keystore to reveal its private key (enter the number, e.g., 1): ", ); if (!selectedKeystore) { @@ -31,7 +31,7 @@ async function revealPk() { } } -revealPk().catch((error) => { +revealPk().catch(error => { console.error("\nāŒ Unexpected error:", error); process.exit(1); }); diff --git a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/selectOrCreateKeystore.js b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/selectOrCreateKeystore.js index 232a7f28f3..6f1699f62e 100644 --- a/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/selectOrCreateKeystore.js +++ b/templates/solidity-frameworks/foundry/packages/foundry/scripts-js/selectOrCreateKeystore.js @@ -15,15 +15,11 @@ async function selectOrCreateKeystore() { try { const keystores = existsSync(keystorePath) - ? readdirSync(keystorePath).filter( - (keystore) => keystore !== "scaffold-eth-default" - ) - : []; + ? readdirSync(keystorePath).filter(keystore => keystore !== "scaffold-eth-default") + : []; if (keystores.length === 0) { - console.log( - "\nāŒ No keystores found in ~/.foundry/keystores, please select 0 to create a new keystore" - ); + console.log("\nāŒ No keystores found in ~/.foundry/keystores, please select 0 to create a new keystore"); } console.log("\nšŸ”‘ Available keystores:"); @@ -35,11 +31,8 @@ async function selectOrCreateKeystore() { return { keystore }; }); - const answer = await new Promise((resolve) => { - rl.question( - "\nSelect a keystore or create new (enter number): ", - resolve - ); + const answer = await new Promise(resolve => { + rl.question("\nSelect a keystore or create new (enter number): ", resolve); }); const selection = parseInt(answer); @@ -50,16 +43,13 @@ async function selectOrCreateKeystore() { }); if (newWalletResult.error || newWalletResult.status !== 0) { - console.error( - "\nāŒ Error generating new wallet:", - newWalletResult.stderr || newWalletResult.error - ); + console.error("\nāŒ Error generating new wallet:", newWalletResult.stderr || newWalletResult.error); process.exit(1); } const privateKey = newWalletResult.stdout .split("\n") - .find((line) => line.includes("Private key:")) + .find(line => line.includes("Private key:")) ?.split(":")[1] ?.trim(); @@ -68,7 +58,7 @@ async function selectOrCreateKeystore() { process.exit(1); } - const keystoreName = await new Promise((resolve) => { + const keystoreName = await new Promise(resolve => { rl.question("\nEnter name for new keystore: ", resolve); }); @@ -76,21 +66,15 @@ async function selectOrCreateKeystore() { rl.close(); return new Promise((resolve, reject) => { - const importProcess = spawn( - "cast", - ["wallet", "import", keystoreName, "--private-key", privateKey], - { - stdio: "inherit", - } - ); + const importProcess = spawn("cast", ["wallet", "import", keystoreName, "--private-key", privateKey], { + stdio: "inherit", + }); - importProcess.on("close", (code) => { + importProcess.on("close", code => { if (code === 0) { + console.log("\nšŸ’° Fund the address and re-run the deploy command to use this keystore."); console.log( - "\nšŸ’° Fund the address and re-run the deploy command to use this keystore." - ); - console.log( - `\nTIP: Use \`yarn account\` and select \`${keystoreName}\` keystore to check if the address is funded.` + `\nTIP: Use \`yarn account\` and select \`${keystoreName}\` keystore to check if the address is funded.`, ); process.exit(0); } else { @@ -122,13 +106,13 @@ async function selectOrCreateKeystore() { // Run the selection if this script is called directly if (process.argv[1] === fileURLToPath(import.meta.url)) { selectKeystore() - .then((keystore) => { + .then(keystore => { console.log("\nšŸ”‘ Selected keystore:", keystore); }) - .catch((error) => { + .catch(error => { console.error(error); process.exit(1); }); } -export { selectOrCreateKeystore }; \ No newline at end of file +export { selectOrCreateKeystore }; From a04b3231a35e3106ec7e88e17a6828e140de24d3 Mon Sep 17 00:00:00 2001 From: Rinat Date: Wed, 14 Oct 2026 17:27:58 +0400 Subject: [PATCH 4/5] foundry: fix dead rpc endpoints in foundry.toml --- .changeset/foundry-deps-update.md | 2 +- .../foundry/packages/foundry/foundry.toml.template.mjs | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.changeset/foundry-deps-update.md b/.changeset/foundry-deps-update.md index f8914708e5..0e0d699879 100644 --- a/.changeset/foundry-deps-update.md +++ b/.changeset/foundry-deps-update.md @@ -2,4 +2,4 @@ "create-eth": patch --- -foundry: update JS deps in `packages/foundry` (dotenv 18, ethers 6, prettier 3, qrcode 1.5.4, toml 5, shx 0.4), drop unused `envfile`. Port `checkAccountBalance.js` to the ethers v6 API and `generateTsAbis.js` to async `prettier.format`. +foundry: update JS deps in `packages/foundry` (dotenv 18, prettier 3, qrcode 1.5.4, toml 5, shx 0.4, viem instead of ethers), drop unused `envfile`. `checkAccountBalance.js` now uses a viem public client; `generateTsAbis.js` awaits `prettier.format`. Rename `.prettier.json` to `.prettierrc.json` so the intended config applies and format `scripts-js` with it. `foundry.toml`: live mainnet Alchemy host, `polygonAmoy` and `polygonZkEvmCardona` instead of the dead Mumbai / zkEVM testnet endpoints, PGN removed. diff --git a/templates/solidity-frameworks/foundry/packages/foundry/foundry.toml.template.mjs b/templates/solidity-frameworks/foundry/packages/foundry/foundry.toml.template.mjs index 8a786cf0b2..6c5fcc394a 100644 --- a/templates/solidity-frameworks/foundry/packages/foundry/foundry.toml.template.mjs +++ b/templates/solidity-frameworks/foundry/packages/foundry/foundry.toml.template.mjs @@ -19,30 +19,28 @@ ${extraProfileDefaults.filter(Boolean).join("\n")} [rpc_endpoints] default_network = "http://127.0.0.1:8545" -mainnet = "https://eth-mainnet.alchemyapi.io/v2/\${ALCHEMY_API_KEY}" +mainnet = "https://eth-mainnet.g.alchemy.com/v2/\${ALCHEMY_API_KEY}" sepolia = "https://eth-sepolia.g.alchemy.com/v2/\${ALCHEMY_API_KEY}" arbitrum = "https://arb-mainnet.g.alchemy.com/v2/\${ALCHEMY_API_KEY}" arbitrumSepolia = "https://arb-sepolia.g.alchemy.com/v2/\${ALCHEMY_API_KEY}" optimism = "https://opt-mainnet.g.alchemy.com/v2/\${ALCHEMY_API_KEY}" optimismSepolia = "https://opt-sepolia.g.alchemy.com/v2/\${ALCHEMY_API_KEY}" polygon = "https://polygon-mainnet.g.alchemy.com/v2/\${ALCHEMY_API_KEY}" -polygonMumbai = "https://polygon-mumbai.g.alchemy.com/v2/\${ALCHEMY_API_KEY}" +polygonAmoy = "https://polygon-amoy.g.alchemy.com/v2/\${ALCHEMY_API_KEY}" polygonZkEvm = "https://zkevm-rpc.com" -polygonZkEvmTestnet = "https://rpc.public.zkevm-test.net" +polygonZkEvmCardona = "https://rpc.cardona.zkevm-rpc.com" gnosis = "https://rpc.gnosischain.com" chiado = "https://rpc.chiadochain.net" base = "https://mainnet.base.org" baseSepolia = "https://sepolia.base.org" scrollSepolia = "https://sepolia-rpc.scroll.io" scroll = "https://rpc.scroll.io" -pgn = "https://rpc.publicgoods.network" -pgnTestnet = "https://sepolia.publicgoods.network" ${extraRpcEndpoints.filter(Boolean).join("\n")} localhost = "http://127.0.0.1:8545" [etherscan] -polygonMumbai = { key = "\${ETHERSCAN_API_KEY}" } +polygonAmoy = { key = "\${ETHERSCAN_API_KEY}" } sepolia = { key = "\${ETHERSCAN_API_KEY}" } ${extraEthercsanConfig.filter(Boolean).join("\n")} From 21348d4c8edfe555a11bd3ddc499a8db5518e165 Mon Sep 17 00:00:00 2001 From: Rinat Date: Wed, 14 Oct 2026 20:35:59 +0400 Subject: [PATCH 5/5] extensions: drop challenges whose branches no longer exist challenge-state-channels, challenge-multisig, challenge-svg-nft are gone from scaffold-eth/se-2-challenges (404), so `-e ` failed. Co-Authored-By: Claude Fable 5.1 --- .changeset/foundry-deps-update.md | 2 ++ src/extensions/challenges.ts | 18 ------------------ 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/.changeset/foundry-deps-update.md b/.changeset/foundry-deps-update.md index 0e0d699879..903fa9f7a7 100644 --- a/.changeset/foundry-deps-update.md +++ b/.changeset/foundry-deps-update.md @@ -3,3 +3,5 @@ --- foundry: update JS deps in `packages/foundry` (dotenv 18, prettier 3, qrcode 1.5.4, toml 5, shx 0.4, viem instead of ethers), drop unused `envfile`. `checkAccountBalance.js` now uses a viem public client; `generateTsAbis.js` awaits `prettier.format`. Rename `.prettier.json` to `.prettierrc.json` so the intended config applies and format `scripts-js` with it. `foundry.toml`: live mainnet Alchemy host, `polygonAmoy` and `polygonZkEvmCardona` instead of the dead Mumbai / zkEVM testnet endpoints, PGN removed. + +Remove `challenge-state-channels`, `challenge-multisig` and `challenge-svg-nft` from the extensions list: these branches no longer exist in `scaffold-eth/se-2-challenges`, so `-e ` failed. diff --git a/src/extensions/challenges.ts b/src/extensions/challenges.ts index c82edcfaf9..db8f121a92 100644 --- a/src/extensions/challenges.ts +++ b/src/extensions/challenges.ts @@ -31,24 +31,6 @@ export const challenges: Extension[] = [ repository: "https://github.com/scaffold-eth/se-2-challenges", branch: "challenge-dex", }, - { - extensionFlagValue: "challenge-state-channels", - description: "Speedrun Ethereum Challenge: A State Channel Application.", - repository: "https://github.com/scaffold-eth/se-2-challenges", - branch: "challenge-state-channels", - }, - { - extensionFlagValue: "challenge-multisig", - description: "Speedrun Ethereum Challenge: Multisig Wallet.", - repository: "https://github.com/scaffold-eth/se-2-challenges", - branch: "challenge-multisig", - }, - { - extensionFlagValue: "challenge-svg-nft", - description: "Speedrun Ethereum Challenge: SVG NFT.", - repository: "https://github.com/scaffold-eth/se-2-challenges", - branch: "challenge-svg-nft", - }, { extensionFlagValue: "challenge-oracles", description: "Speedrun Ethereum Challenge: Oracles.",