A token verification system for Discord that grants roles based on Solana token holdings. This project consists of two main components:
- Web Application (
work-verify
): A Next.js application that connects to users' Solana wallets to verify token holdings. - Discord Bot (
work-discord-bot
): A Discord bot that manages verification requests and assigns roles based on token holdings.
This project allows Discord server administrators to create token-gated roles, where users must hold a specific amount of a Solana token to receive a special role. The system:
- Verifies wallet ownership through cryptographic signatures
- Checks token balances on the Solana blockchain
- Assigns Discord roles based on token holdings
- Periodically checks balances to add/remove roles as needed
- Stores user data in a Supabase database with automated migrations
The web application is deployed at: https://verify-bot.gib.work/
Note: You'll need a verification code from the Discord bot to use the application.
- Node.js (v18 or higher)
- pnpm (v10 or higher)
- Discord Bot Token and Application
- Supabase Account and Project
- Solana RPC URL (from providers like Helius, QuickNode, or Alchemy)
git clone https://github.com/gibwork/verify-bot.git
cd verify-bot
cd work-verify
# Install dependencies
pnpm install
# Create .env file from example
cp .env.example .env
Edit the .env
file with your configuration:
NEXT_PUBLIC_VERIFY_API_ENDPOINT=http://localhost:3001/api/verify-wallet
SOLANA_RPC_URL=your_solana_rpc_url
cd ../work-discord-bot
# Install dependencies
pnpm install
# Create .env file from example
cp .env.example .env
Edit the .env
file with your configuration:
# Discord Bot Configuration
DISCORD_TOKEN=your_discord_bot_token
CLIENT_ID=your_discord_application_id
GUILD_ID=your_discord_server_id
ROLE_ID=your_role_id
# Supabase Configuration
SUPABASE_URL=your_supabase_project_url
SUPABASE_KEY=your_supabase_anon_key
SUPABASE_DB_PASSWORD=your_database_password
SUPABASE_PROJECT_REF=your_project_reference
SUPABASE_ACCESS_TOKEN=your_access_token
# Other Configuration
SOLANA_RPC_URL=your_solana_rpc_url
CLIENT_URL=http://localhost:3000
PORT=3001
# Discord OAuth (for Supabase Auth)
DISCORD_CLIENT_ID=your_discord_oauth_client_id
DISCORD_CLIENT_SECRET=your_discord_oauth_client_secret
The project uses Supabase as its database with automated migrations. Follow these steps to set up your database:
- Create a Supabase project at supabase.com
- Set up the Supabase CLI:
cd work-discord-bot
pnpm add -D supabase
pnpm supabase login
- Initialize and apply migrations:
# Apply initial migration
pnpm migration:up
The initial migration will create the following schema:
CREATE TABLE holders (
id SERIAL PRIMARY KEY,
username TEXT NOT NULL,
discord_user_id TEXT UNIQUE NOT NULL,
address TEXT[] NOT NULL,
active BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
last_verified_at TIMESTAMP WITH TIME ZONE
);
For detailed information about the migrations system, see work-discord-bot/supabase/README.md.
# Create a new migration
pnpm migration:new <name>
# Apply migrations
pnpm migration:up
# Rollback migrations
pnpm migration:down
# List migrations
pnpm migration:list
# Fix migration issues
pnpm migration:repair
- Start the web application:
cd work-verify
pnpm dev
- Start the Discord bot:
cd work-discord-bot
pnpm dev
- Build and start the web application:
cd work-verify
pnpm build
pnpm start
- Build and start the Discord bot:
cd work-discord-bot
pnpm build
node dist/index.js
- Invite the bot to your Discord server
- Use the
/verify
command in your server - Click the "Connect Wallet" button
- Connect your Solana wallet on the verification page
- Sign the message to prove wallet ownership
- If you have the required token balance, you'll receive the role
The token address and required balance are defined in both applications:
-
In
work-verify/components/VerifyContent.tsx
:const SPECIFIC_TOKEN_MINT = "F7Hwf8ib5DVCoiuyGr618Y3gon429Rnd1r5F9R5upump"; const REQUIRED_BALANCE = 200000;
-
In
work-discord-bot/src/index.ts
:const TOKEN_MINT_ADDRESS = "F7Hwf8ib5DVCoiuyGr618Y3gon429Rnd1r5F9R5upump"; const REQUIRED_BALANCE = 200000;
To change the token or required balance, update these values in both files.
Contributions are welcome! Here's how you can contribute:
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature
- Commit your changes:
git commit -am 'Add new feature'
- Push to the branch:
git push origin feature/my-feature
- Submit a pull request
When making database changes:
- Create a new migration:
pnpm migration:new your_change
- Test the migration locally
- Include migration files in your PR
app/
: Next.js app directorypage.tsx
: Main page componentlayout.tsx
: Root layout componentapi/
: API routes
components/
: React componentsVerifyContent.tsx
: Main verification componentWalletProvider.tsx
: Solana wallet adapter provider
src/
: Source codeindex.ts
: Main bot application
supabase/
: Database migrationsmigrations/
: Migration filesconfig.toml
: Supabase configurationREADME.md
: Migrations documentation
-
Discord Bot Not Responding
- Check if your bot token is correct
- Ensure the bot has the necessary permissions
-
Wallet Connection Issues
- Make sure you're using a supported Solana wallet
- Check if your RPC URL is valid and has sufficient rate limits
-
Role Not Being Assigned
- Verify that the bot has permission to manage roles
- Check if the role ID in the .env file is correct
- Ensure the bot's role is higher than the role it's trying to assign
-
Database Migration Issues
- Check migration logs with
pnpm migration:list
- Use
pnpm migration:repair
for inconsistencies - Ensure you have the latest migrations
- Backup data before running migrations in production
- Check migration logs with