A production-ready template for building full-stack decentralized applications with SvelteKit, Hardhat v3, and hardhat-deploy v2 with the rocketh deployment system.
This template extends the template-ethereum-contracts to include a fully configured web frontend, providing:
- Hot Contract Replacement (HCR): The equivalent of HMR (Hot Module Replacement) for smart contracts. Edit your contracts and see changes live while developing your app. This uses proxy patterns with a set of conventions to make it work seamlessly.
- Intuitive Deployment Scripts: Write deployment logic in plain TypeScript without learning a new DSL.
- Flexible Proxy Patterns: Declarative proxy deployment with
deployViaProxyfor upgradeable contracts. - Full Control: Access to all deployment parameters and lifecycle hooks.
- SvelteKit 5: Modern, fast, and reactive frontend framework with Svelte 5.
- Tailwind CSS 4: Utility-first CSS framework for rapid UI development.
- PWA Ready: Pre-configured Progressive Web App with service worker support.
- IPFS Compatible: Static adapter with relative paths for decentralized hosting.
- Auto-Generated Deployments: Contract ABIs and addresses automatically exported to the frontend.
- Zellij Layouts: Multiple pre-configured terminal layouts for different development scenarios.
- Live Reload: Changes to contracts automatically trigger recompilation, redeployment, and frontend updates.
- Type Safety: Full TypeScript support across contracts and frontend.
.
├── contracts/ # Smart contracts package
│ ├── src/ # Solidity source files
│ │ └── GreetingsRegistry/ # Contract organized by feature
│ │ ├── GreetingsRegistry.sol # Main contract
│ │ └── GreetingsRegistry.t.sol # Solidity tests (forge-style)
│ ├── deploy/ # Deployment scripts
│ ├── deployments/ # Deployment artifacts per network
│ ├── generated/ # Auto-generated artifacts and ABIs
│ ├── rocketh/ # Rocketh configuration
│ │ ├── config.ts # Account & extension configuration
│ │ ├── deploy.ts # Deploy script setup
│ │ └── environment.ts # Environment setup for tests/scripts
│ ├── scripts/ # Utility scripts
│ └── test/ # TypeScript tests
│ └── utils/ # Test utilities
├── web/ # SvelteKit frontend
│ ├── src/
│ │ ├── lib/ # Shared components and utilities
│ │ │ ├── core/ # Core utilities (notifications, service worker)
│ │ │ └── deployments.ts # Auto-generated contract deployments
│ │ ├── routes/ # SvelteKit routes
│ │ └── service-worker/ # PWA service worker
│ ├── static/ # Static assets
│ └── svelte.config.js # SvelteKit configuration
├── dev/ # Zellij layout configurations
├── package.json # Root monorepo configuration
└── pnpm-workspace.yaml # PNPM workspace definition
pnpm iWe recommend installing Zellij for an optimal development experience with pnpm start.
Start everything with a single command (requires Zellij):
pnpm startThis launches:
- A local Ethereum node
- Contract auto-compilation on file changes
- Contract auto-deployment on changes
- Frontend development server with hot reload
- Svelte type checking
If you prefer running services individually:
-
Start the local Ethereum node:
pnpm contracts:node:local
-
In another terminal, compile and deploy:
pnpm contracts:compile pnpm contracts:deploy localhost --skip-prompts pnpm contracts:export localhost --ts ../web/src/lib/deployments.ts
-
Start the web development server:
pnpm web:dev
pnpm contracts:compilepnpm contracts:compile:watchpnpm contracts:testThis runs both:
- Solidity tests (forge-style, using
forge-std) - TypeScript tests (using Node.js test runner with
earlassertions)
-
Configure your environment variables in
.env.local:MNEMONIC_<network>="your mnemonic phrase" ETHERSCAN_API_KEY=<api-key> # For verification
-
Deploy:
pnpm contracts:deploy <network>
pnpm contracts:verify <network>pnpm web:devpnpm web:buildpnpm web:serveBuild contracts and web frontend together:
pnpm build <network>Export contract addresses and ABIs to the frontend:
pnpm contracts:export <network> --ts ../web/src/lib/deployments.tsThis template provides multiple Zellij layouts for different development scenarios:
Runs everything locally:
- Local Ethereum node
- Contract compilation, deployment, and TypeScript build (all watching for changes)
- Web development server
- Svelte type checking
Use when you have contracts already deployed and want to develop the frontend:
- Exports existing deployment info
- Runs web development server
Develop against a remote network (testnet/mainnet):
- Watches and deploys to the remote network
- Runs web development server locally
Configure accounts in contracts/rocketh/config.ts:
export const config = {
accounts: {
deployer: { default: 0 }, // First account from mnemonic
admin: { default: 1 }, // Second account
},
// ...
} as const satisfies UserConfig;Networks are configured in contracts/hardhat.config.ts using helper functions:
addNetworksFromEnv(): Auto-configure networks fromETH_NODE_URI_*environment variablesaddNetworksFromKnownList(): Add configurations for well-known networksaddForkConfiguration(): Enable forking mode viaHARDHAT_FORKenv var
Configure the web app in web/src/web-config.json:
{
"name": "Template Website",
"title": "Template Website",
"description": "A template to build website",
"canonicalURL": "https://localhost",
"themeColor": "#000000"
}Deploy scripts are located in contracts/deploy/ and are executed in order (prefixed with numbers):
import { deployScript, artifacts } from "../rocketh/deploy.js";
export default deployScript(
async (env) => {
const { deployer, admin } = env.namedAccounts;
// Deploy an upgradeable contract
const deployment = await env.deployViaProxy(
"GreetingsRegistry",
{
account: deployer,
artifact: artifacts.GreetingsRegistry,
args: ["prefix:"],
},
{
owner: admin,
linkedData: {
/* metadata stored with deployment */
},
},
);
// Interact with the deployed contract
const contract = env.viem.getContract(deployment);
const message = await contract.read.messages([deployer]);
},
{ tags: ["GreetingsRegistry"] },
);Contract deployments are automatically exported to web/src/lib/deployments.ts. Import them in your Svelte components:
import { deployments } from "$lib/deployments";
// Access contract address
const address = deployments.GreetingsRegistry.address;
// Access contract ABI
const abi = deployments.GreetingsRegistry.abi;| Variable | Description |
|---|---|
ETH_NODE_URI_<network> |
RPC endpoint for the network |
MNEMONIC_<network> |
Mnemonic for account derivation |
MNEMONIC |
Fallback mnemonic if network-specific not set |
ETHERSCAN_API_KEY |
API key for contract verification |
Set SECRET as the value to use Hardhat's secret store:
ETH_NODE_URI_mainnet=SECRET # Uses configVariable('SECRET_ETH_NODE_URI_mainnet')The contracts package can be published for external consumption:
{
"exports": {
"./deploy/*": "./dist/deploy/*",
"./rocketh/*": "./dist/rocketh/*",
"./artifacts/*": "./dist/generated/artifacts/*",
"./abis/*": "./dist/generated/abis/*",
"./deployments/*": "./deployments/*",
"./src/*": "./src/*"
}
}pnpm contracts:build// Import ABIs
import { Abi_GreetingsRegistry } from "template-ethereum-contracts/abis/GreetingsRegistry.js";
// Import deployment info
import GreetingsRegistry from "template-ethereum-contracts/deployments/sepolia/GreetingsRegistry.json";Solidity linting is configured with slippy:
pnpm contracts:lintpnpm format # Format all code
pnpm format:check # Check formatting