This tutorial will guide you through setting up Hardhat for Sei EVM development and using OpenZeppelin contracts to build secure, standardized smart contracts. We’ll cover environment setup, contract creation, deployment, and show how to leverage OpenZeppelin’s pre-built components.
Deploy to Testnet FirstIt is highly recommended that you deploy to testnet (atlantic-2) first and verify everything works as expected before committing to mainnet. Doing so helps you catch bugs early, avoid unnecessary gas costs, and keep your users safe.
Try it before you install
Setting up the full toolchain takes a few minutes. If you just want to see a contract deploy to Sei, you can do both of these right now in the browser.
First, confirm the RPC endpoints you’ll put in hardhat.config respond:
Then add Sei testnet to your wallet and deploy a minimal Counter.sol from Remix — no Node, no install. In Remix: compile under Solidity Compiler, then Deploy & Run with Environment set to Injected Provider — MetaMask.
Table of Contents
Prerequisites
Before we begin, ensure you have the following installed:
- Node.js (v18.0.0 or later)
- npm (v7.0.0 or later) or yarn
- A code editor (VS Code recommended)
Setting Up Your Development Environment
Let’s create a new project and set up Hardhat:
When prompted, choose Hardhat 3 and a TypeScript project using Mocha and Ethers.js, then follow the prompts. This generates an ESM project ("type": "module" in package.json) with @nomicfoundation/hardhat-toolbox-mocha-ethers, ethers, Hardhat Ignition, TypeScript, and a ready-to-use tsconfig.json.
Then add the OpenZeppelin contract library:
Prefer a non-interactive setup (CI or scripted environments)? Do the same thing by hand — no prompts:The @nomicfoundation/hardhat-toolbox-mocha-ethers bundle pulls in ethers, Ignition, Mocha/Chai, and the keystore, network-helpers, verify, and typechain plugins — so this single install covers everything in this guide. If you hit peer-dependency errors, re-run with --legacy-peer-deps.
Configuring Hardhat for Sei EVM
Next, we’ll need to configure Hardhat to work with the Sei EVM. Update your hardhat.config.ts file:
Hardhat 3 is ESM-first and requires "type": "module" in package.json (the scaffold sets this for you). Each network needs an explicit type: 'http', and plugins load via the plugins array rather than the Hardhat 2 side-effect import '@nomicfoundation/hardhat-toolbox'. A local simulated network is provided automatically — no hardhat/localhost entry required.
Hardhat 3 reads secrets through configVariable(...), backed by an encrypted keystore — so your key is never stored in a plaintext file. Set it once:
You’ll be prompted to paste the private key of the account you deploy from; Hardhat stores it encrypted on your machine. For CI, export a SEI_PRIVATE_KEY environment variable instead — configVariable falls back to it.
Use a dedicated, throwaway deploy key funded with only what you need — never a personal wallet holding real funds.
Using OpenZeppelin Contracts
OpenZeppelin provides a library of secure, tested smart contract components that you can use to build your applications. The @openzeppelin/contracts package was already installed during setup, so you’re ready to import its contracts directly.
Creating and Deploying an ERC20 Token, ERC721 NFT or an Upgradeable UUPS Token
ERC20
ERC721
Upgradeable UUPS Token
Let’s create a simple ERC20 token using OpenZeppelin contracts. Create a new file in the contracts directory called SeiToken.sol:Now, create a deployment script in the ignition/modules directory called deploy-sei-token.ts:ignition/modules/deploy-sei-token.ts
To deploy the token to the Sei testnet: Now, let’s create an ERC721 NFT contract. Create a new file SeiNFT.sol in the contracts directory:Create a deployment script deploy-sei-nft.ts:scripts/deploy-sei-nft.ts
Deploy the NFT contract to the Sei testnet: Upgradeable contracts allow you to modify the contract’s logic after deployment without changing the contract address, which is crucial for fixing bugs or adding new features. The UUPS (Universal Upgradeable Proxy Standard) pattern is a popular way to implement upgradeability.For upgradeable contracts, also install the upgradeable variant of the OpenZeppelin library (the @openzeppelin/contracts package you installed earlier supplies the ERC1967 proxy):OpenZeppelin’s @openzeppelin/hardhat-upgrades plugin is built for Hardhat 2 and does not register with Hardhat 3’s plugins array. So this guide deploys the proxy directly using the ERC1967 standard and upgrades through UUPS upgradeToAndCall — no extra plugin, fully Hardhat 3-native. The tradeoff: you don’t get the plugin’s automatic storage-layout safety checks, so make sure each new version only appends state variables. You can validate layouts separately with @openzeppelin/upgrades-core. No hardhat.config.ts changes are needed beyond the configuration shown earlier.Now, let’s create an upgradeable ERC20 token. Create contracts/UpgradeableSeiToken.sol:contracts/UpgradeableSeiToken.sol
Note the Initializable base, the initializer modifier, the __ERC20_init / __Ownable_init calls, and the _authorizeUpgrade override — these are what make the contract safe to run behind a proxy. (OpenZeppelin v5’s UUPSUpgradeable is stateless, so there is no __UUPSUpgradeable_init to call.)Add a thin, named ERC1967 proxy so Hardhat emits an artifact you can deploy by name. Create contracts/SeiTokenProxy.sol:contracts/SeiTokenProxy.sol
Now create a deployment script scripts/deploy-upgradeable-token.ts. It deploys the implementation, then deploys the proxy with the initialize call encoded as constructor data so initialization happens atomically:scripts/deploy-upgradeable-token.ts
Deploy this to the testnet:Upgrading the ContractLet’s say you want to add a new feature or fix a bug. Create a new version of the contract, contracts/UpgradeableSeiTokenV2.sol:contracts/UpgradeableSeiTokenV2.sol
Now, create an upgrade script scripts/upgrade-token.ts. Replace PROXY_ADDRESS with the address printed when you deployed the proxy.Run the upgrade script:You have now successfully deployed and upgraded a UUPS contract on the Sei network using Hardhat and OpenZeppelin!
Testing Your Smart Contracts
Hardhat makes it easy to test your contracts before deploying them. Create a test file test/sei-token-test.ts:
Run your tests with:
Deploying to Sei Testnet and Mainnet
Once you’ve tested your contracts, you can deploy them to the Sei testnet or mainnet. To deploy, you’ll need:
- SEI tokens in your wallet for gas
- Your private key stored in the encrypted keystore (
npx hardhat keystore set SEI_PRIVATE_KEY) — or exported as a SEI_PRIVATE_KEY environment variable in CI
Deploy to the testnet:
Deploy to the mainnet (only when you’re ready for production):