Everything needed to go from zero to a deployed Hardhat smart contract on Polygon Amoy testnet. Covers Git Bash, private keys, .env configuration, Polygonscan API, faucet funding, wallet address retrieval, and deployment. Built from the actual Salud Vault setup session April 2026.
01 Prerequisites & Tools
| Tool | Version | Where to Get | Notes |
|---|---|---|---|
| Node.js | v20+ (v24 confirmed) | nodejs.org | Includes npm automatically |
| Git + Git Bash | Any recent | git-scm.com | Use Git Bash, NOT PowerShell |
| VS Code | Any recent | code.visualstudio.com | For editing .env and config files |
| Hardhat | v2 (npm install) | hardhat.org | Installed per-project, not globally |
PowerShell handles paths and Node.js commands differently and causes Hardhat errors. Right-click your project folder in Windows Explorer and select "Git Bash Here" to open it in the right directory automatically. All commands in this guide assume Git Bash.
02 Project Directory & Shell
C:\Users\Admin\Documents\ai coding\salud\.claude\worktrees\romantic-morse.claude\worktrees\[branch-name] path. Check the Claude Code conversation for the exact branch name if starting a new project.# Git Bash uses forward slashes and /c/ instead of C:\ cd "/c/Users/Admin/Documents/ai coding/salud/.claude/worktrees/romantic-morse" # Confirm you are in the right place ls # You should see: hardhat.config.ts package.json contracts/ scripts/ test/ .env
PowerShell: C:\Users\Admin\Documents\ai coding\salud
Git Bash: /c/Users/Admin/Documents/ai coding/salud
Always use the Git Bash format (forward slashes, /c/). Wrap paths with spaces in double quotes.
03 Create the .env File
The .env file stores private keys and API keys. It must be in the same folder as hardhat.config.ts. The project ships with a .env.example template — copy it to create your real file.
# Copy the template cp .env.example .env # Verify it exists ls -la | grep .env # Should show: .env and .env.example # Open in VS Code to fill in your keys code .env
# Wallet (see Section 04 for formatting rules) PRIVATE_KEY=yourprivatekeyhere64charsno0xprefix # Polygon RPC Endpoints POLYGON_AMOY_RPC_URL=https://rpc-amoy.polygon.technology POLYGON_MAINNET_RPC_URL=https://polygon-rpc.com # Block Explorer Verification (see Section 05) POLYGONSCAN_API_KEY=yourapikeyfrometherscan # Alchemy (optional but more reliable than public RPC) ALCHEMY_AMOY_URL=https://polygon-amoy.g.alchemy.com/v2/yourkey ALCHEMY_MAINNET_URL=https://polygon-mainnet.g.alchemy.com/v2/yourkey
Run this right after creating your .env file. If a private key is ever pushed to GitHub, consider that wallet compromised — generate a new one immediately.
echo ".env" >> .gitignore cat .gitignore # verify .env appears in the list
Every Hardhat command prints a confirmation line. Look for:
◇ injected env (8) from .env — the number must be greater than 0
If you see injected env (0), your .env is missing from the current folder. Fix it with: cp "/c/Users/Admin/Documents/ai coding/salud/.env" .
04 Private Key Setup
Create a separate wallet exclusively for development. It holds testnet MATIC only. Never store a private key in a file on your computer for a wallet that holds real funds.
MetaMask: Account menu → Export Private Key
Or Hardhat generates one during project setup. The key is a 64-character hex string that looks like random letters and numbers.
Remove the 0x prefix if present
No quotes around the value
No spaces around the = sign
Exactly 64 characters long
Hardhat adds 0x automatically
# WRONG - has 0x prefix PRIVATE_KEY=0xabc123yourkeyhere # CORRECT - raw 64-char hex, no prefix PRIVATE_KEY=abc123yourkeyhere64characterstotal
05 Polygonscan API Key
Since mid-2025 Etherscan uses a unified API key across all chains. One key works for Polygon Amoy testnet, Polygon mainnet, Ethereum, and others.
SaludVaultYou must verify your email first. Check your inbox for the Etherscan confirmation email. Unverified accounts cannot access API key generation. Make sure you are fully logged in, not just registered. X (Twitter) login also works if you prefer.
# WRONG - angle brackets are just placeholders, remove them entirely POLYGONSCAN_API_KEY=<your_api_key_here> # CORRECT - raw key value right after the equals sign POLYGONSCAN_API_KEY=ABC123DEF456youractualkey
06 hardhat.config.ts Reference
The network is named polygonAmoy (camelCase). Using --network amoy throws HH100 error. Always use --network polygonAmoy in every command.
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
import * as dotenv from "dotenv";
dotenv.config();
// Accepts private key with or without 0x prefix
function normalizeKey(pk: string | undefined): string[] {
if (!pk || pk.trim() === "") return [];
const trimmed = pk.trim();
return [trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`];
}
const config: HardhatUserConfig = {
solidity: {
version: "0.8.28",
settings: {
optimizer: { enabled: true, runs: 200 },
evmVersion: "cancun",
},
},
networks: {
hardhat: {},
polygonAmoy: { // always use this exact name
url: process.env.POLYGON_AMOY_RPC_URL || "https://rpc-amoy.polygon.technology",
accounts: normalizeKey(process.env.PRIVATE_KEY),
chainId: 80002,
gasPrice: "auto",
},
polygon: {
url: process.env.POLYGON_MAINNET_RPC_URL || "https://polygon-rpc.com",
accounts: normalizeKey(process.env.PRIVATE_KEY),
chainId: 137,
},
},
etherscan: {
apiKey: {
polygonAmoy: process.env.POLYGONSCAN_API_KEY || "",
polygon: process.env.POLYGONSCAN_API_KEY || "",
},
customChains: [{
network: "polygonAmoy",
chainId: 80002,
urls: {
apiURL: "https://api-amoy.polygonscan.com/api",
browserURL: "https://amoy.polygonscan.com",
},
}],
},
sourcify: { enabled: true },
};
export default config;
07 Get Your Wallet Address
Your private key and your wallet address are two different things. The address is public (safe to share with the faucet). The private key is secret. Hardhat derives the address from your key automatically.
# Open the Hardhat console npx hardhat console --network polygonAmoy # Type each line separately and press Enter after each const [deployer] = await ethers.getSigners() console.log(deployer.address) # Prints: 0x742d35Cc6634C0532925a3b8D4C9C2... # Exit the console when done .exit
When you run const [deployer] = await ethers.getSigners() the console prints undefined. This is correct — it means the assignment worked with no return value. Type console.log(deployer.address) on the next line to see your address.
You do not need MetaMask. The Hardhat console derives your address directly from the private key in .env. MetaMask is optional for this workflow entirely.
08 Fund with Amoy MATIC (Faucet)
You need at least 1 MATIC on Polygon Amoy to pay gas for testnet deployments. The faucet gives 0.5 MATIC per request — submit twice to reach 1 MATIC.
0x... value)The faucet wants your wallet address (~42 characters, starts with 0x, from Section 07). Your private key is 64 characters and is secret — never paste it anywhere except your .env file.
npx hardhat console --network polygonAmoy const [deployer] = await ethers.getSigners() const bal = await ethers.provider.getBalance(deployer.address) console.log(ethers.formatEther(bal)) # Should print "1.0" or "0.5" -- anything above 0 and you are ready .exit
09 Deploy to Polygon Amoy
# 1. Navigate to project root cd "/c/Users/Admin/Documents/ai coding/salud/.claude/worktrees/romantic-morse" # 2. Compile all contracts npx hardhat compile # 3. Run the full test suite -- all tests should pass before deploying npx hardhat test # 4. Deploy to Amoy testnet npx hardhat run scripts/deploy.ts --network polygonAmoy # 5. Verify contracts on Polygonscan (paste the address printed by deploy) npx hardhat verify --network polygonAmoy 0xYourDeployedContractAddress
◇ injected env (8) from .env
Deploying SaludTokens with account: 0x742d35...
SaludTokens deployed to: 0x8a3f91Dd7745D164...
SaludID deployed to: 0xB2c4e1Ff8834A297...
Deployment manifest saved to deployments/amoy.json
10 Troubleshooting Reference
| Error | Cause | Fix |
|---|---|---|
HH100: Network amoy doesn't exist | Wrong network name | Use --network polygonAmoy (camelCase) |
injected env (0) from .env | .env missing from current folder | cp "/c/Users/Admin/Documents/ai coding/salud/.env" . |
| Invalid address from private key | 0x prefix in PRIVATE_KEY | Remove 0x from start of key in .env. Key = 64 chars. |
command not found with brackets | Pasted with rich text formatting | Type commands manually, do not paste. Brackets are paste artefacts. |
| Faucet GitHub login gives 404 | Known faucet OAuth issue | Use X (Twitter) login instead — works reliably |
ls is not defined in console | Ran bash command inside Node.js console | Type .exit first, then run bash commands |
undefined after getSigners() | Normal — not an error | Assignment worked. Run console.log(deployer.address) next. |
| hardhat.config.ts not found | Wrong directory | Navigate to /c/Users/Admin/Documents/ai coding/salud/.claude/worktrees/romantic-morse |
| Insufficient funds for gas | No Amoy MATIC in wallet | faucet.polygon.technology → X login → Polygon Amoy → 0.5 MATIC x2 |
| PowerShell path errors | Wrong shell | Switch to Git Bash. Right-click project folder → "Git Bash Here" |
ls -la | grep .env shows itinjected env (N) where N is greater than 0npx hardhat compile runs with no errorsnpx hardhat test passes all testsNavigate: cd "/c/Users/Admin/Documents/ai coding/salud/.claude/worktrees/romantic-morse"
Console: npx hardhat console --network polygonAmoy
Get address: const [d] = await ethers.getSigners(); console.log(d.address)
Check balance: console.log(ethers.formatEther(await ethers.provider.getBalance(d.address)))
Compile: npx hardhat compile
Test: npx hardhat test
Deploy: npx hardhat run scripts/deploy.ts --network polygonAmoy
Faucet: faucet.polygon.technology → X login → Polygon Amoy → paste wallet address