From 794932906c822fc44e12f35422778271338db7a3 Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Thu, 7 Aug 2025 13:18:59 +0530 Subject: [PATCH 1/5] test initial iteration --- src/tasks/copy-template-files.ts | 4 +++- templates/utils.js | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tasks/copy-template-files.ts b/src/tasks/copy-template-files.ts index d6036d38f8..8c3f0acffd 100644 --- a/src/tasks/copy-template-files.ts +++ b/src/tasks/copy-template-files.ts @@ -274,7 +274,9 @@ const processTemplatedFiles = async ( return accumulated; }, freshArgs); - const output = fileTemplate(combinedArgs); + console.log("The solidityFramework is:", solidityFramework); + + const output = fileTemplate({ ...combinedArgs, solidityFramework: [solidityFramework || ""] }); const targetPath = path.join( targetDir, diff --git a/templates/utils.js b/templates/utils.js index e4f7b354ef..51883b1731 100644 --- a/templates/utils.js +++ b/templates/utils.js @@ -59,6 +59,9 @@ export const deepMerge = (...args) => { export const withDefaults = (template, expectedArgsDefaults, debug = false) => { + expectedArgsDefaults.solidityFramework = "" + console.log("The expectedArgsDefault are:" + ) const callerFile = getCallerFile(); return receivedArgs => { From 4e6e5bcd6e874ad502c25629c42abc7da6486e3b Mon Sep 17 00:00:00 2001 From: Rinat Date: Thu, 7 Aug 2025 18:18:21 +0300 Subject: [PATCH 2/5] feat: pass solidity framework to all the template files --- src/tasks/copy-template-files.ts | 14 +++++++++++--- src/utils/consts.ts | 4 ++++ templates/utils.js | 24 +++++++++++++++--------- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/tasks/copy-template-files.ts b/src/tasks/copy-template-files.ts index 8c3f0acffd..476e981fd4 100644 --- a/src/tasks/copy-template-files.ts +++ b/src/tasks/copy-template-files.ts @@ -9,7 +9,13 @@ import path from "path"; import { promisify } from "util"; import link from "../utils/link"; import { getArgumentFromExternalExtensionOption } from "../utils/external-extensions"; -import { BASE_DIR, SOLIDITY_FRAMEWORKS, SOLIDITY_FRAMEWORKS_DIR, EXAMPLE_CONTRACTS_DIR } from "../utils/consts"; +import { + BASE_DIR, + SOLIDITY_FRAMEWORKS, + SOLIDITY_FRAMEWORKS_DIR, + EXAMPLE_CONTRACTS_DIR, + GLOBAL_ARGS_DEFAULTS, +} from "../utils/consts"; const EXTERNAL_EXTENSION_TMP_DIR = "tmp-external-extension"; @@ -274,9 +280,11 @@ const processTemplatedFiles = async ( return accumulated; }, freshArgs); - console.log("The solidityFramework is:", solidityFramework); + const globalArgs = { + solidityFramework: [solidityFramework || GLOBAL_ARGS_DEFAULTS.solidityFramework], + }; - const output = fileTemplate({ ...combinedArgs, solidityFramework: [solidityFramework || ""] }); + const output = fileTemplate({ ...combinedArgs, ...globalArgs }); const targetPath = path.join( targetDir, diff --git a/src/utils/consts.ts b/src/utils/consts.ts index b6a942488d..3c8a7401a4 100644 --- a/src/utils/consts.ts +++ b/src/utils/consts.ts @@ -6,3 +6,7 @@ export const SOLIDITY_FRAMEWORKS = { HARDHAT: "hardhat", FOUNDRY: "foundry", } as const; + +export const GLOBAL_ARGS_DEFAULTS = { + solidityFramework: "", +}; diff --git a/templates/utils.js b/templates/utils.js index 51883b1731..4ed7a8a439 100644 --- a/templates/utils.js +++ b/templates/utils.js @@ -57,26 +57,32 @@ export const deepMerge = (...args) => { return finalConfig; }; +// copy of the defaults from the src/utils/consts.ts file +const GLOBAL_ARGS_DEFAULTS = { + solidityFramework: "", +}; + export const withDefaults = (template, expectedArgsDefaults, debug = false) => { - expectedArgsDefaults.solidityFramework = "" - console.log("The expectedArgsDefault are:" - ) const callerFile = getCallerFile(); return receivedArgs => { - const argsWithDefault = Object.fromEntries( - Object.entries(expectedArgsDefaults).map(([argName, argDefault]) => [ + const globalArgsNames = Object.keys(GLOBAL_ARGS_DEFAULTS); + const receivedGlobalArgs = globalArgsNames.reduce((acc, arg) => { + acc[arg] = receivedArgs[arg][0]; return acc;}, {}); + + const argsWithDefaultsAndGlobals = Object.fromEntries( + Object.entries({...expectedArgsDefaults, ...receivedGlobalArgs}).map(([argName, argDefault]) => [ argName, receivedArgs[argName] ?? [argDefault], ]), ); if (debug) { - console.log(argsWithDefault, expectedArgsDefaults, receivedArgs); + console.log(argsWithDefaultsAndGlobals, expectedArgsDefaults, receivedArgs); } - const expectedArgsNames = Object.keys(expectedArgsDefaults); + const expectedArgsNames = Object.keys(argsWithDefaultsAndGlobals); Object.keys(receivedArgs).forEach(receivedArgName => { if (!expectedArgsNames.includes(receivedArgName)) { throw new Error( @@ -87,7 +93,7 @@ export const withDefaults = } const receivedType = getType(receivedArgs[receivedArgName][0]); - const expectedType = getType(expectedArgsDefaults[receivedArgName]); + const expectedType = getType(argsWithDefaultsAndGlobals[receivedArgName][0]); if (receivedType !== expectedType) { throw new Error( @@ -98,7 +104,7 @@ export const withDefaults = } }); - return template(argsWithDefault); + return template(argsWithDefaultsAndGlobals); }; }; From 64a1b6986c5a1dc738598265a192c6575b911e20 Mon Sep 17 00:00:00 2001 From: Rinat Date: Thu, 7 Aug 2025 18:49:06 +0300 Subject: [PATCH 3/5] fix: remove old solidityFramework vars --- templates/base/.cursor/rules/scaffold-eth.mdc.template.mjs | 6 +++--- templates/base/README.md.template.mjs | 7 +++---- .../foundry/.cursor/rules/scaffold-eth.mdc.args.mjs | 1 - templates/solidity-frameworks/foundry/README.md.args.mjs | 1 - .../hardhat/.cursor/rules/scaffold-eth.mdc.args.mjs | 1 - templates/solidity-frameworks/hardhat/README.md.args.mjs | 1 - templates/utils.js | 2 ++ 7 files changed, 8 insertions(+), 11 deletions(-) diff --git a/templates/base/.cursor/rules/scaffold-eth.mdc.template.mjs b/templates/base/.cursor/rules/scaffold-eth.mdc.template.mjs index 0136ba6167..d0602bafd4 100644 --- a/templates/base/.cursor/rules/scaffold-eth.mdc.template.mjs +++ b/templates/base/.cursor/rules/scaffold-eth.mdc.template.mjs @@ -1,4 +1,4 @@ -import { withDefaults } from "../../../utils.js" +import { withDefaults, upperCaseFirstLetter } from "../../../utils.js" const contents = ({ solidityFramework, deployScriptDir }) => { return `--- @@ -11,7 +11,7 @@ This codebase contains Scaffold-ETH 2 (SE-2), everything you need to build dApps It's a yarn monorepo that contains following packages: -${Boolean(solidityFramework[0]) ? `- ${solidityFramework[0].toUpperCase()} (\`packages/${solidityFramework[0]}\`): The solidity framework to write, test and deploy EVM Smart Contracts.` : ""} +${Boolean(solidityFramework[0]) ? `- ${upperCaseFirstLetter(solidityFramework[0])} (\`packages/${solidityFramework[0]}\`): The solidity framework to write, test and deploy EVM Smart Contracts.` : ""} - NextJS (\`packages/nextjs\`): The UI framework extended with utilities to make interacting with Smart Contracts easy (using Next.js App Router, not Pages Router). @@ -115,4 +115,4 @@ They live under \`packages/nextjs/components/scaffold-eth\`. Find the relevant information from the documentation and the codebase. Think step by step before answering the question.` } -export default withDefaults(contents, { solidityFramework: "", deployScriptDir: "" }); +export default withDefaults(contents, { deployScriptDir: "" }); diff --git a/templates/base/README.md.template.mjs b/templates/base/README.md.template.mjs index 33d616ac64..b4c2d180e9 100644 --- a/templates/base/README.md.template.mjs +++ b/templates/base/README.md.template.mjs @@ -1,4 +1,4 @@ -import { withDefaults } from "../utils.js"; +import { upperCaseFirstLetter, withDefaults } from "../utils.js"; const getQuickStart = ({ solidityFramework, @@ -26,7 +26,7 @@ ${ yarn chain \`\`\` -This command starts a local Ethereum network using ${solidityFramework[0]}. The network runs on your local machine and can be used for testing and development. You can customize the network configuration in ${networkConfigPath[0]}. +This command starts a local Ethereum network using ${upperCaseFirstLetter(solidityFramework[0])}. The network runs on your local machine and can be used for testing and development. You can customize the network configuration in ${networkConfigPath[0]}. 3. On a second terminal, deploy the test contract: @@ -84,7 +84,7 @@ const contents = ({ 🧪 An open-source, up-to-date toolkit for building decentralized applications (dapps) on the Ethereum blockchain. It's designed to make it easier for developers to create and deploy smart contracts and build user interfaces that interact with those contracts. ⚙️ Built using NextJS, RainbowKit, ${ - Boolean(solidityFramework[0]) ? solidityFramework[0] + ", " : "" + Boolean(solidityFramework[0]) ? upperCaseFirstLetter(solidityFramework[0]) + ", " : "" }Wagmi, Viem, and Typescript. ${ Boolean(solidityFramework[0]) @@ -128,7 +128,6 @@ Please see [CONTRIBUTING.MD](https://github.com/scaffold-eth/scaffold-eth-2/blob export default withDefaults(contents, { skipQuickStart: false, - solidityFramework: "", networkConfigPath: "", contractsPath: "", scriptsPath: "", diff --git a/templates/solidity-frameworks/foundry/.cursor/rules/scaffold-eth.mdc.args.mjs b/templates/solidity-frameworks/foundry/.cursor/rules/scaffold-eth.mdc.args.mjs index 3313fd0edb..41c7de4cc5 100644 --- a/templates/solidity-frameworks/foundry/.cursor/rules/scaffold-eth.mdc.args.mjs +++ b/templates/solidity-frameworks/foundry/.cursor/rules/scaffold-eth.mdc.args.mjs @@ -1,3 +1,2 @@ -export const solidityFramework = "foundry"; export const deployScriptDir = "script"; diff --git a/templates/solidity-frameworks/foundry/README.md.args.mjs b/templates/solidity-frameworks/foundry/README.md.args.mjs index 750d91ae8e..d2cedcf930 100644 --- a/templates/solidity-frameworks/foundry/README.md.args.mjs +++ b/templates/solidity-frameworks/foundry/README.md.args.mjs @@ -1,4 +1,3 @@ -export const solidityFramework = "Foundry"; export const networkConfigPath = `\`packages/foundry/foundry.toml\``; export const contractsPath = `\`packages/foundry/contracts\``; export const scriptsPath = `\`packages/foundry/script\``; diff --git a/templates/solidity-frameworks/hardhat/.cursor/rules/scaffold-eth.mdc.args.mjs b/templates/solidity-frameworks/hardhat/.cursor/rules/scaffold-eth.mdc.args.mjs index 88ebcf7e1a..1da74e3606 100644 --- a/templates/solidity-frameworks/hardhat/.cursor/rules/scaffold-eth.mdc.args.mjs +++ b/templates/solidity-frameworks/hardhat/.cursor/rules/scaffold-eth.mdc.args.mjs @@ -1,3 +1,2 @@ -export const solidityFramework = "hardhat"; export const deployScriptDir = "deploy"; diff --git a/templates/solidity-frameworks/hardhat/README.md.args.mjs b/templates/solidity-frameworks/hardhat/README.md.args.mjs index a390c43e46..872a5c59d8 100644 --- a/templates/solidity-frameworks/hardhat/README.md.args.mjs +++ b/templates/solidity-frameworks/hardhat/README.md.args.mjs @@ -1,4 +1,3 @@ -export const solidityFramework = "Hardhat"; export const networkConfigPath = `\`packages/hardhat/hardhat.config.ts\``; export const contractsPath = `\`packages/hardhat/contracts\``; export const scriptsPath = `\`packages/hardhat/deploy\``; diff --git a/templates/utils.js b/templates/utils.js index 4ed7a8a439..eb6d9e2a34 100644 --- a/templates/utils.js +++ b/templates/utils.js @@ -1,6 +1,8 @@ import { inspect } from "util"; import createDeepMerge from "@fastify/deepmerge"; +export const upperCaseFirstLetter = (str) => str.charAt(0).toUpperCase() + str.slice(1); + const getType = (value) => { if (Array.isArray(value)) { return 'array'; From 7f54b7d5073f8469e32f60a577d2a2a3f8218a74 Mon Sep 17 00:00:00 2001 From: Rinat Date: Fri, 17 Oct 2025 11:30:15 +0300 Subject: [PATCH 4/5] feat: add possibility to use functions with global args --- templates/utils.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/templates/utils.js b/templates/utils.js index eb6d9e2a34..cdd1c4baf4 100644 --- a/templates/utils.js +++ b/templates/utils.js @@ -74,10 +74,13 @@ export const withDefaults = acc[arg] = receivedArgs[arg][0]; return acc;}, {}); const argsWithDefaultsAndGlobals = Object.fromEntries( - Object.entries({...expectedArgsDefaults, ...receivedGlobalArgs}).map(([argName, argDefault]) => [ - argName, - receivedArgs[argName] ?? [argDefault], - ]), + Object.entries({...expectedArgsDefaults, ...receivedGlobalArgs}).map(([argName, argDefault]) => { + const receivedArg = receivedArgs[argName] ?? [argDefault]; + if (receivedArg[0] instanceof Function) { + return [argName, [receivedArg[0](receivedGlobalArgs)]]; + } + return [argName, receivedArg]; + }), ); if (debug) { @@ -94,7 +97,10 @@ export const withDefaults = ); } - const receivedType = getType(receivedArgs[receivedArgName][0]); + let receivedType = getType(receivedArgs[receivedArgName][0]); + if (receivedType === "function") { + receivedType = getType(receivedArgs[receivedArgName][0]({receivedGlobalArgs})); + } const expectedType = getType(argsWithDefaultsAndGlobals[receivedArgName][0]); if (receivedType !== expectedType) { From 8f7b719216b58c3de76991d108d8d1eb7b077d07 Mon Sep 17 00:00:00 2001 From: Rinat Date: Fri, 17 Oct 2025 12:14:39 +0300 Subject: [PATCH 5/5] feat: add the info to TEMPLATING.md --- contributors/TEMPLATING.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/contributors/TEMPLATING.md b/contributors/TEMPLATING.md index 3de4ae1614..7606992634 100644 --- a/contributors/TEMPLATING.md +++ b/contributors/TEMPLATING.md @@ -144,6 +144,28 @@ export default { one: 1, two: 2} To avoid issues when named arguments have typos, the `withDefaults` utility will also throw an error when an argument is passed with a name that wasn't expected by the template. +### Using global variables in args file content + +You can use global variables in your argument values by defining your argument values as functions. + +Instead of static values, export functions that receive global variables as parameters and return the desired content. + +**Important:** The function's return type must match the default argument value type defined in the template. + +Example: + +```js +// Static value (basic approach) +export const description = "Hello world"; + +// Dynamic value using global variables (advanced approach) +export const description = ({ solidityFramework }) => `Hello ${solidityFramework}`; +``` + +**Available global variables:** + +- `solidityFramework` - The selected Solidity framework (e.g., "hardhat", "foundry") + # Args files injection in Template files For each Template file, we search on the extensions the user selected for the existence of Args files in the exact same relative path. If Args files are found, we combine them into an array.