A decentralized counter game built on the Movement blockchain, featuring dual wallet support with Privy social login and native Aptos wallets.
-
Dual Wallet Support
- 🔐 Privy social login (Email, Twitter, Google, GitHub, Discord)
- 💼 Native Aptos wallets (Nightly, etc.)
- 🔄 Seamless switching between wallet types
-
Game Mechanics
- ➕ Increment/Decrement counter
- 📊 Level up system (every 100 points = 1 level)
- 🔥 Streak tracking
- ⏱️ Debounced transaction batching
- 🎯 Real-time blockchain sync
-
User Experience
- 🎨 Modern, responsive UI with Tailwind CSS
- 🌈 Dynamic level emojis and colors
- 📱 Mobile-friendly design
- 🔔 Toast notifications for all actions
- ⚡ Optimistic UI updates
- Frontend: Next.js 16, React 18, TypeScript
- Blockchain: Movement Network (Aptos-based)
- Wallet Integration:
- Privy SDK for social login
- Aptos Wallet Adapter for native wallets
- Smart Contract: Move language
- Styling: Tailwind CSS, Radix UI components
- State Management: React hooks
- Node.js 18+ and Yarn
- Movement CLI (for smart contract deployment)
- A wallet (Nightly recommended for native wallet support)
git clone <repository-url>
cd Movement-Counter-template
yarn installCreate a .env.local file in the root directory:
NEXT_PUBLIC_PRIVY_APP_ID=your_privy_app_idGet your Privy App ID from Privy Dashboard
Navigate to the modules directory and deploy the counter contract:
cd modules
# Initialize Movement CLI for testnet
movement init --network custom \
--rest-url https://testnet.movementnetwork.xyz/v1 \
--faucet-url https://faucet.testnet.movementnetwork.xyz/
# Update Move.toml with your address
# Edit Move.toml and set counter="<your-address>"
# Deploy the contract
movement move deployUpdate the contract address in app/lib/aptos.ts:
export const CONTRACT_ADDRESS = 'your_deployed_contract_address';yarn devOpen http://localhost:3000 to see the app.
The app uses a centralized network configuration system. To switch between mainnet and testnet, edit app/lib/aptos.ts:
// Change this to switch networks
export const CURRENT_NETWORK = 'testnet'; // or 'mainnet'
export const MOVEMENT_CONFIGS = {
mainnet: {
chainId: 126,
name: "Movement Mainnet",
fullnode: "https://full.mainnet.movementinfra.xyz/v1",
explorer: "mainnet"
},
testnet: {
chainId: 250,
name: "Movement Testnet",
fullnode: "https://testnet.movementnetwork.xyz/v1",
explorer: "testnet"
}
};-
Privy Wallet:
- User logs in with social account
- Privy creates an embedded Aptos wallet
- Transactions signed with Privy's
signRawHash - User pays gas fees
-
Native Wallet:
- User connects wallet (e.g., Nightly)
- Wallet adapter handles connection
- Transactions signed via wallet popup
- User pays gas fees
- User clicks increment/decrement buttons
- Actions are debounced (2-second delay)
- Multiple actions batched into single transaction
- Transaction submitted to Movement blockchain
- UI updates optimistically
- Blockchain state refreshed on confirmation
// Increment counter
public entry fun add_counter(account: &signer, amount: u64)
// Decrement counter
public entry fun subtract_counter(account: &signer, amount: u64)
// Get counter value
#[view]
public fun get_counter(addr: address): u64Movement-Counter-template/
├── app/
│ ├── components/
│ │ ├── CounterArena.tsx # Main game arena
│ │ ├── counterItem.tsx # Counter logic & UI
│ │ ├── LoginPage.tsx # Landing page
│ │ ├── wallet-selection-modal.tsx # Wallet connection modal
│ │ ├── wallet-provider.tsx # Wallet adapter provider
│ │ └── ui/ # Reusable UI components
│ ├── lib/
│ │ ├── aptos.ts # Aptos SDK & network config
│ │ ├── transactions.ts # Transaction submission logic
│ │ └── privy-movement.ts # Privy wallet utilities
│ ├── providers.tsx # App-level providers
│ └── page.tsx # Main page component
├── modules/
│ ├── sources/
│ │ └── counter.move # Smart contract
│ └── Move.toml # Move package config
└── package.json
- Handles counter state and UI
- Manages transaction debouncing
- Supports both wallet types
- Real-time blockchain sync
- Unified wallet connection interface
- Privy social login
- Native wallet detection
- Network configuration
submitCounterTransaction()- Privy wallet transactionssubmitCounterTransactionNative()- Native wallet transactionsfetchCounterValue()- Read blockchain state
- Level System: Emojis change based on level (🌱 → 🌳 → 🏆)
- Color Coding: Counter color reflects value (green = high, red = negative)
- Progress Bar: Visual level progress indicator
- Pending Actions: Shows queued transactions
- Toast Notifications: Success/error feedback
- No private keys stored in frontend
- Privy handles wallet security
- Users control their own gas fees
- All transactions require user approval (native wallets)
Ensure your wallet is connected to Movement Testnet (Chain ID: 250)
- Check wallet has sufficient MOVE tokens for gas
- Verify contract address is correct
- Check network configuration
- Verify
NEXT_PUBLIC_PRIVY_APP_IDis set correctly - Check Privy dashboard for app configuration
Contributions are welcome! Please feel free to submit a Pull Request.
Built with ❤️ on Movement Network