Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/backmerge-20-05-26.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"create-eth": patch
---

- Deps: next 15 → 16 and minor frontend updates (https://github.com/scaffold-eth/scaffold-eth-2/pull/1280)
- new Alchemy key (https://github.com/scaffold-eth/scaffold-eth-2/pull/1287)
- hardhat v3 migration (https://github.com/scaffold-eth/scaffold-eth-2/pull/1272)
4 changes: 2 additions & 2 deletions .github/workflows/lint-instances.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ jobs:
git config --global user.name "Dummy User"
git config --global user.email "dummy@example.com"

- name: Setup Node.js 20.x
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
node-version: lts/*

- name: Install Dependencies
run: yarn
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ CLI to create decentralized applications (dapps) using Scaffold-ETH 2.

Before you begin, you need to install the following tools:

- [Node (>= v20.18.3)](https://nodejs.org/en/download/)
- [Node (>= v22.10.0)](https://nodejs.org/en/download/)
- Yarn ([v1](https://classic.yarnpkg.com/en/docs/install/) or [v2+](https://yarnpkg.com/getting-started/install))
- [Git](https://git-scm.com/downloads)

Expand Down
4 changes: 2 additions & 2 deletions templates/base/.lintstagedrc.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const path = require("path");

const buildNextEslintCommand = (filenames) =>
`yarn next:lint --fix --file ${filenames
`yarn workspace @se-2/nextjs eslint --fix ${filenames
.map((f) => path.relative(path.join("packages", "nextjs"), f))
.join(" --file ")}`;
.join(" ")}`;

const checkTypesNextCommand = () => "yarn next:check-types";

Expand Down
16 changes: 8 additions & 8 deletions templates/base/packages/nextjs/.prettierrc.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
module.exports = {
"arrowParens": "avoid",
"printWidth": 120,
"tabWidth": 2,
"trailingComma": "all",
"importOrder": ["^react$", "^next/(.*)$", "<THIRD_PARTY_MODULES>", "^@heroicons/(.*)$", "^~~/(.*)$"],
"importOrderSortSpecifiers": true,
"plugins": [require.resolve("@trivago/prettier-plugin-sort-imports")],
}
arrowParens: "avoid",
printWidth: 120,
tabWidth: 2,
trailingComma: "all",
importOrder: ["^react$", "^next/(.*)$", "<THIRD_PARTY_MODULES>", "^@heroicons/(.*)$", "^~~/(.*)$"],
importOrderSortSpecifiers: true,
plugins: [require.resolve("@trivago/prettier-plugin-sort-imports")],
};
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ ${
return { bytecode, assembly };
}`
: `async function fetchByteCodeAndAssembly(buildInfoDirectory: string, contractName: string) {
const contractPath = \`contracts/\${contractName}.sol\`;
const buildInfoFiles = fs.readdirSync(buildInfoDirectory);
const contractPath = \`project/contracts/\${contractName}.sol\`;
const buildInfoFiles = fs.readdirSync(buildInfoDirectory).filter(f => f.endsWith(".output.json"));
let bytecode = "";
let assembly = "";

Expand All @@ -60,7 +60,7 @@ ${

const buildInfo = JSON.parse(fs.readFileSync(filePath, "utf8"));

if (buildInfo.output.contracts[contractPath]) {
if (buildInfo.output?.contracts?.[contractPath]) {
for (const contract in buildInfo.output.contracts[contractPath]) {
bytecode = buildInfo.output.contracts[contractPath][contract].evm.bytecode.object;
assembly = buildInfo.output.contracts[contractPath][contract].evm.bytecode.opcodes;
Expand All @@ -86,13 +86,7 @@ const getContractData = async (address: Address) => {
}

const artifactsDirectory = path.join(
__dirname,
"..",
"..",
"..",
"..",
"..",
"..",
process.cwd(),
"..",
"${solidityFramework[0]}",
"${artifactsDirName[0]}"${isFoundry ? "" : `,
Expand Down
3 changes: 1 addition & 2 deletions templates/base/packages/nextjs/components/ThemeProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
"use client";

import * as React from "react";
import { ThemeProvider as NextThemesProvider } from "next-themes";
import { type ThemeProviderProps } from "next-themes/dist/types";
import { ThemeProvider as NextThemesProvider, type ThemeProviderProps } from "next-themes";

export const ThemeProvider = ({ children, ...props }: ThemeProviderProps) => {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const FaucetButton = () => {
className={
!isBalanceZero
? "ml-1"
: "ml-1 tooltip tooltip-bottom tooltip-primary tooltip-open font-bold before:left-auto before:transform-none before:content-[attr(data-tip)] before:-translate-x-2/5"
: "ml-1 tooltip tooltip-bottom tooltip-primary tooltip-open font-bold before:left-auto before:right-0 before:transform-none before:translate-none before:content-[attr(data-tip)]"
}
data-tip="Grab funds from faucet"
>
Expand Down
19 changes: 7 additions & 12 deletions templates/base/packages/nextjs/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
import { FlatCompat } from "@eslint/eslintrc";
import nextCoreWebVitals from "eslint-config-next/core-web-vitals";
import nextTypescript from "eslint-config-next/typescript";
import prettierConfig from "eslint-config-prettier";
import prettierPlugin from "eslint-plugin-prettier";
import { defineConfig } from "eslint/config";
import path from "node:path";
import { fileURLToPath } from "node:url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
});

export default defineConfig([
...nextCoreWebVitals,
...nextTypescript,
prettierConfig,
{
plugins: {
prettier: prettierPlugin,
},
extends: compat.extends("next/core-web-vitals", "next/typescript", "prettier"),

rules: {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/ban-ts-comment": "off",

"react-hooks/set-state-in-effect": "off",
"prettier/prettier": [
"warn",
{
Expand Down
2 changes: 1 addition & 1 deletion templates/base/packages/nextjs/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference path="./.next/types/routes.d.ts" />
import "./.next/dev/types/routes.d.ts";

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
4 changes: 0 additions & 4 deletions templates/base/packages/nextjs/next.config.ts.template.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ const defaultConfig = {
typescript: {
ignoreBuildErrors: '$$process.env.NEXT_PUBLIC_IGNORE_BUILD_ERROR === "true"$$',
},
eslint: {
ignoreDuringBuilds: '$$process.env.NEXT_PUBLIC_IGNORE_BUILD_ERROR === "true"$$',
},
webpack: `$$config => { config.resolve.fallback = { fs: false, net: false, tls: false }; config.externals.push("pino-pretty", "lokijs", "encoding"); return config; }$$`,
}

const contents = ({ preContent, configOverrides, postConfigContent, finalNextConfigName }) => {
Expand Down
67 changes: 33 additions & 34 deletions templates/base/packages/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
"private": true,
"version": "0.1.0",
"scripts": {
"build": "next build",
"build": "yarn lint && next build",
"lint": "yarn eslint .",
"check-types": "tsc --noEmit --incremental",
"dev": "next dev",
"format": "prettier --write . '!(node_modules|.next|contracts)/**/*'",
"lint": "next lint",
"format": "prettier --write . '!(node_modules|.next)/**/*'",
"serve": "next start",
"start": "next dev",
"vercel": "vercel --build-env YARN_ENABLE_IMMUTABLE_INSTALLS=false --build-env ENABLE_EXPERIMENTAL_COREPACK=1 --build-env VERCEL_TELEMETRY_DISABLED=1",
Expand All @@ -16,47 +16,46 @@
"vercel:login": "vercel login"
},
"dependencies": {
"@heroicons/react": "~2.1.5",
"@heroicons/react": "^2.2.0",
"@rainbow-me/rainbowkit": "2.2.9",
"@react-native-async-storage/async-storage": "~2.2.0",
"@react-native-async-storage/async-storage": "^2.2.0",
"@scaffold-ui/components": "^0.1.10",
"@scaffold-ui/debug-contracts": "^0.1.9",
"@scaffold-ui/hooks": "^0.1.8",
"@tanstack/react-query": "~5.59.15",
"blo": "~1.2.0",
"@tanstack/react-query": "^5.59.15",
"blo": "^2.0.0",
"burner-connector": "0.0.20",
"daisyui": "5.0.9",
"kubo-rpc-client": "~5.0.2",
"next": "~15.2.8",
"next-nprogress-bar": "~2.3.13",
"next-themes": "~0.3.0",
"qrcode.react": "~4.0.1",
"react": "~19.2.3",
"react-dom": "~19.2.3",
"react-hot-toast": "~2.4.0",
"usehooks-ts": "~3.1.0",
"daisyui": "^5.5.19",
"kubo-rpc-client": "^6.1.0",
"next": "^16.2.4",
"next-nprogress-bar": "^2.4.7",
"next-themes": "^0.4.6",
"qrcode.react": "^4.2.0",
"react": "^19.2.5",
"react-dom": "^19.2.5",
"react-hot-toast": "^2.6.0",
"usehooks-ts": "^3.1.1",
"viem": "2.39.0",
"wagmi": "2.19.5",
"zustand": "~5.0.0"
"zustand": "^5.0.12"
},
"devDependencies": {
"@tailwindcss/postcss": "4.0.15",
"@trivago/prettier-plugin-sort-imports": "~4.3.0",
"@types/node": "~18.19.50",
"@types/react": "~19.0.7",
"@tailwindcss/postcss": "^4.2.4",
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
"@types/node": "^18.19.130",
"@types/react": "^19.2.14",
"abitype": "1.0.6",
"autoprefixer": "~10.4.20",
"bgipfs": "~0.0.12",
"eslint": "~9.23.0",
"eslint-config-next": "~15.2.3",
"eslint-config-prettier": "~10.1.1",
"eslint-plugin-prettier": "~5.2.4",
"postcss": "~8.4.45",
"prettier": "~3.5.3",
"tailwindcss": "4.1.3",
"type-fest": "~4.26.1",
"typescript": "~5.8.2",
"vercel": "~51.2.1"
"bgipfs": "^0.0.18",
"eslint": "^9.39.0",
"eslint-config-next": "^16.2.4",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.5",
"postcss": "^8.5.10",
"prettier": "^3.8.3",
"tailwindcss": "^4.2.4",
"type-fest": "^5.6.0",
"typescript": "^5.8.2",
"vercel": "~52.0.0"
},
"packageManager": "yarn@4.13.0"
}
2 changes: 1 addition & 1 deletion templates/base/packages/nextjs/postcss.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = {
plugins: {
'@tailwindcss/postcss': {},
"@tailwindcss/postcss": {},
},
};
5 changes: 3 additions & 2 deletions templates/base/packages/nextjs/tsconfig.json.template.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const defaultTsConfig = {
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"jsx": "react-jsx",
"incremental": true,
"paths": {
"~~/*": ["./*"]
Expand All @@ -29,7 +29,8 @@ const defaultTsConfig = {
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": [
"node_modules"
Expand Down
5 changes: 2 additions & 3 deletions templates/base/packages/nextjs/utils/scaffold-eth/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import {
ExtractAbiFunction,
} from "abitype";
import type { ExtractAbiFunctionNames } from "abitype";
import type { Simplify } from "type-fest";
import type { MergeDeepRecord } from "type-fest/source/merge-deep";
import type { MergeDeep, Simplify } from "type-fest";
import {
Address,
Block,
Expand Down Expand Up @@ -58,7 +57,7 @@ const deepMergeContracts = <L extends Record<PropertyKey, any>, E extends Record
);
result[key] = { ...local[key], ...amendedExternal };
}
return result as MergeDeepRecord<AddExternalFlag<L>, AddExternalFlag<E>, { arrayMergeMode: "replace" }>;
return result as MergeDeep<AddExternalFlag<L>, AddExternalFlag<E>, { arrayMergeMode: "replace" }>;
};

const contractsData = deepMergeContracts(deployedContractsData, externalContractsData);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,44 +1,40 @@
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
import { Contract } from "ethers";
import { deployScript } from "../rocketh/deploy.js";
import * as artifacts from "../generated/artifacts/index.js";

/**
* Deploys a contract named "YourContract" using the deployer account and
* constructor arguments set to the deployer address
*
* @param hre HardhatRuntimeEnvironment object.
* @param env Rocketh environment object.
*/
const deployYourContract: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
/*
On localhost, the deployer account is the one that comes with Hardhat, which is already funded.
export default deployScript(
async env => {
/*
On localhost, the deployer account is the one that comes with Hardhat, which is already funded.

When deploying to live networks (e.g `yarn deploy --network sepolia`), the deployer account
should have sufficient balance to pay for the gas fees for contract creation.
When deploying to live networks (e.g `yarn deploy --network sepolia`), the deployer account
should have sufficient balance to pay for the gas fees for contract creation.

You can generate a random account with `yarn generate` or `yarn account:import` to import your
existing PK which will fill DEPLOYER_PRIVATE_KEY_ENCRYPTED in the .env file (then used on hardhat.config.ts)
You can run the `yarn account` command to check your balance in every network.
*/
const { deployer } = await hre.getNamedAccounts();
const { deploy } = hre.deployments;
You can generate a random account with `yarn generate` or `yarn account:import` to import your
existing PK which will fill DEPLOYER_PRIVATE_KEY_ENCRYPTED in the .env file (then used on hardhat.config.ts)
You can run the `yarn account` command to check your balance in every network.
*/
const { deployer } = env.namedAccounts;

await deploy("YourContract", {
from: deployer,
// Contract constructor arguments
args: [deployer],
log: true,
// autoMine: can be passed to the deploy function to make the deployment process faster on local networks by
// automatically mining the contract deployment transaction. There is no effect on live networks.
autoMine: true,
});
const yourContract = await env.deploy("YourContract", {
account: deployer,
artifact: artifacts.YourContract,
// Contract constructor arguments
args: [deployer],
});

// Get the deployed contract to interact with it after deploying.
const yourContract = await hre.ethers.getContract<Contract>("YourContract", deployer);
console.log("👋 Initial greeting:", await yourContract.greeting());
};

export default deployYourContract;

// Tags are useful if you have multiple deploy files and only want to run one of them.
// e.g. yarn deploy --tags YourContract
deployYourContract.tags = ["YourContract"];
// Read back from the deployed contract
const greeting = await env.read(yourContract, { functionName: "greeting" });
console.log("👋 Initial greeting:", greeting);
},
{
// Tags are useful if you have multiple deploy files and only want to run some of them.
// e.g. yarn deploy --tags YourContract
tags: ["YourContract"],
},
);
Loading
Loading