The crowdsale UI has been successfully integrated with the TimedCrowdsale smart contract.
The integration connects the 3D animated crowdsale UI to the on-chain smart contract, enabling:
- Real-time crowdsale data display (tokens sold, price, countdown, etc.)
- Wallet connection via RainbowKit
- Token purchases through the smart contract
- Whitelist verification
- Transaction status tracking
apps/web/src/contracts/
├── index.ts # Contract addresses and exports
├── timed-crowdsale.ts # TimedCrowdsale ABI
└── token.ts # Token (ERC20) ABI
apps/web/src/hooks/
├── use-crowdsale.ts # Read contract data (price, tokens sold, etc.)
└── use-buy-tokens.ts # Write function for purchasing tokens
apps/web/src/app/crowdsale/page.tsx- Integrated with contract hooksapps/web/src/components/ui/floating-particles.tsx- Fixed SSR hydration
First, start Anvil node:
anvil --port 3002In another terminal, deploy the contracts:
cd packages/contracts
# Deploy Token
forge script script/DeployToken.s.sol:DeployTokenScript \
--rpc-url http://localhost:3002 \
--broadcast \
--private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
# Deploy Crowdsale (note the token address from previous step)
forge script script/DeployCrowdsale.s.sol:DeployCrowdsaleScript \
--rpc-url http://localhost:3002 \
--broadcast \
--private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80Create apps/web/.env.local:
# Copy from example
cp apps/web/.env.local.example apps/web/.env.localEdit .env.local and add your deployed contract addresses:
NEXT_PUBLIC_TOKEN_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3
NEXT_PUBLIC_CROWDSALE_ADDRESS=0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
NEXT_PUBLIC_ANVIL_PORT=3002Before purchasing tokens, you need to be whitelisted:
cd packages/contracts
# Using forge script
forge script script/ManageWhitelist.s.sol:ManageWhitelistScript \
--rpc-url http://localhost:3002 \
--broadcast \
--private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
# Or using cast
export CROWDSALE_ADDRESS=0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
export YOUR_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
cast send $CROWDSALE_ADDRESS \
"whitelistAddress(address)" $YOUR_ADDRESS \
--rpc-url http://localhost:3002 \
--private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80cd apps/web
bun run devVisit http://localhost:3000/crowdsale
- Click "Connect Wallet" button
- Select your wallet (MetaMask, Burner Wallet, etc.)
- Make sure you're on Localhost network (Chain ID: 31337)
- After connecting, enter the amount of tokens you want
- The UI will calculate the ETH cost automatically
- Click "Buy Tokens"
- Approve the transaction in your wallet
- Wait for confirmation (toast notification will appear)
The UI automatically displays:
- Tokens Sold: Updated after each purchase
- Remaining: Tokens available for purchase
- Price (ETH): Current token price
- Progress: Visual progress bar showing sale completion %
- Countdown: Time until opening/closing
- Whitelist Status: Your whitelist verification status
const {
price, // Token price in wei
maxTokens, // Total tokens for sale
tokensSold, // Tokens already sold
openingTime, // Unix timestamp of opening
deadline, // Unix timestamp of closing
minContribution, // Minimum tokens to buy
maxContribution, // Maximum tokens to buy
isOpen, // Whether sale is currently open
tokenName, // Token name
tokenSymbol, // Token symbol
} = useCrowdsale();const { buyTokens, isPending, isSuccess } = useBuyTokens();
// Purchase tokens
await buyTokens(
tokenAmount, // Amount as string (e.g., "100")
ethAmount // ETH cost as string (e.g., "0.1")
);const { data: isWhitelisted } = useWhitelistStatus(address);- Spinner shown while loading contract data
- "Processing..." button state during transactions
- Skeleton states for missing data
- Network detection (shows error if contract not deployed)
- Whitelist verification (warns if not whitelisted)
- Sale status (shows message if sale not started)
- Toast notifications for transaction success/failure
- Mobile-friendly layout
- 3D animations with hardware acceleration
- Smooth transitions and hover effects
-
Display Contract Data
- Tokens sold updates correctly
- Price displays properly
- Countdown shows correct time
- Progress bar matches actual progress
-
Wallet Connection
- Connect/disconnect works
- Address displayed correctly
- Network switching detected
-
Whitelist
- Non-whitelisted users see warning
- Whitelisted users can proceed
- Status updates after whitelisting
-
Token Purchase
- Input validation (min/max)
- ETH cost calculated correctly
- Transaction submits successfully
- Toast notifications appear
- Balance updates after purchase
-
Sale Timing
- Shows "Opening In" before start
- Shows "Closing In" after start
- Prevents purchases when closed
- Check that contracts are deployed to Anvil
- Verify
.env.localhas correct addresses - Ensure Anvil is running on correct port
- Run the whitelist script for your address
- Check transaction was confirmed
- Refresh the page
- Check the
openingTimein contract - You may need to wait or redeploy with earlier opening time
- For testing, use
block.timestampor near-future timestamp
- Check you have enough ETH in wallet
- Verify amount is within min/max limits
- Ensure sale is open and you're whitelisted
- Check Anvil logs for revert reasons
-
Deploy to Testnet
- Update foundry.toml with testnet RPC
- Deploy to Sepolia or Base Sepolia
- Update .env.local with testnet addresses
-
Add More Features
- Token balance display
- Purchase history
- Referral system
- Bonus token calculations
-
Enhanced UI
- Transaction history table
- Wallet balance display
- Gas estimation
- Multiple wallet support
- wagmi: React hooks for Ethereum
- viem: TypeScript interface for Ethereum
- @rainbow-me/rainbowkit: Wallet connection UI
- @tanstack/react-query: Data fetching and caching
- react-hot-toast: Transaction notifications
- framer-motion: UI animations
Your crowdsale is now fully integrated and ready for testing! 🚀
Visit http://localhost:3000/crowdsale to see it in action.