X-TaskChecker is an airdrop management system for the Tondi blockchain that integrates with Twitter (X) and Telegram to verify user tasks and distribute token rewards.
- Twitter (X) Integration: OAuth authentication and task verification
- Telegram Integration: User verification and bot integration
- Airdrop Management: Automated token distribution with configurable rewards
- Invitation System: Referral tracking with milestone-based rewards
- Task Verification: Automated checking of likes, retweets, quote tweets, and replies
- Scheduled Processing: Periodic claim approval and airdrop distribution
The system consists of:
- External API (public-facing endpoints)
- Internal API (administrative endpoints)
- Background workers for task fetching and verification
- SQLite database for state management
- Tondi blockchain integration for token transfers
All API endpoints return errors in a standardized JSON format with appropriate HTTP status codes:
{
"error": "Human-readable error message",
"code": "MACHINE_READABLE_ERROR_CODE"
}Common HTTP Status Codes:
400 BAD_REQUEST- Invalid request parameters401 UNAUTHORIZED- Missing or invalid authentication403 FORBIDDEN- Insufficient permissions404 NOT_FOUND- Resource not found409 CONFLICT- Resource conflict (e.g., pool exhausted)429 TOO_MANY_REQUESTS- Rate limit exceeded500 INTERNAL_SERVER_ERROR- Server error
Common Error Codes:
AUTH_FAILED- Authentication failedRATE_LIMITED- Too many requestsVALIDATION_FAILED- Request validation failedRECORD_NOT_FOUND- Requested record not found
Initiates Twitter OAuth flow.
- Response: Redirects to Twitter OAuth URL
- Sets cookie:
pkce_verifierfor OAuth verification
OAuth callback endpoint.
- Query Parameters:
code: Authorization code from Twitter
- Returns: Redirects to
https://tondi.org/airdrop?token={jwt_token}&x_user_id={user_id} - Response: JWT token for authenticated user
- Error Codes:
OAUTH_SESSION_EXPIRED- OAuth session invalidINVALID_OAUTH_CODE- Invalid OAuth codeTOKEN_FAILED- Failed to obtain access tokenOAUTH_FAILED- General OAuth failure
Check X (Twitter) task completion status for a user.
- Path Parameters:
x_user_id: Twitter user ID
- Response:
{
"user_id": "string",
"liking_posts": ["post_id1", "post_id2"],
"retweeted_posts": ["post_id1"],
"quote_tweet_posts": ["post_id1"],
"reply_posts": ["post_id1"]
}- Error Codes:
TASKS_NOT_FOUND- No task results found for userTASKS_CHECK_FAILED- Failed to check task status
Verify if a Telegram user is in the specified channel.
- Headers:
Authorization: Bearer {tg_jwt_token}
- Response:
"true"or"false" - Error Codes:
RATE_LIMITED- Too many requests (max 1 per 2 seconds per user)AUTH_FAILED- Invalid authorization tokenCHECK_FAILED- Failed to verify membership
Submit an airdrop claim request.
- Headers:
Authorization: Bearer {x_jwt_token}X-Real-IP: User's IP address (set by proxy)
- Request Body:
{
"tg_auth": "telegram_jwt_token",
"recv_address": "tondi_testnet_address"
}- Response: 200 OK or error response
- Error Codes:
AUTH_FAILED- Invalid authorization tokenINVALID_ADDRESS- Invalid TON wallet address formatINVALID_NETWORK- Only testnet addresses acceptedPOOL_EXHAUSTED- Airdrop pool exhaustedVALIDATION_FAILED- Request validation failedCLAIM_FAILED- Failed to submit claim
Check the status of a claim.
- Headers:
Authorization: Bearer {x_jwt_token}
- Request Body:
tg_token(string) - Response:
{
"x_user_id": "string",
"x_username": "string",
"tg_user_id": "string",
"tg_username": "string",
"create_timestamp": 1234567890,
"status": "pending_review|waiting_manual_verification|claim_submitted|claim_denied",
"amount": 15000000,
"lock_amount": 85000000,
"recv_address": "tondi_testnet_address",
"airdrop_tx": [...],
"user_ip": "127.0.0.1"
}- Error Codes:
AUTH_FAILED- Invalid authorization tokenRECORD_NOT_FOUND- No claim record foundSTATUS_FAILED- Failed to retrieve status
Get the current status of the airdrop pool.
- Response:
{
"claimed_amount": 1000,
"total_amount": 10000,
"pre_claimed_amount": 0
}- Error Codes:
POOL_STATUS_FAILED- Failed to retrieve pool status
Generate an invitation code for the authenticated user.
- Headers:
Authorization: Bearer {x_jwt_token}
- Request Body:
{
"tg_token": "telegram_jwt_token"
}- Response:
{
"invitation_code": "abc123de"
}- Error Codes:
AUTH_FAILED- Invalid authorization tokenCLAIM_NOT_FOUND- Claim record not foundCLAIM_DENIED- Claim has been deniedGENERATION_FAILED- Failed to generate codeGEN_CODE_FAILED- General generation failure
Bind an invitee to an inviter using invitation code.
- Headers:
Authorization: Bearer {x_jwt_token}
- Request Body:
{
"invitation_code": "abc123de",
"tg_token": "telegram_jwt_token"
}- Response: 200 OK or error response
- Error Codes:
AUTH_FAILED- Invalid authorization tokenCLAIM_NOT_FOUND- Claim record not foundCLAIM_DENIED- Claim has been deniedINVALID_INVITATION_CODE- Invalid invitation codeSELF_INVITATION- Cannot use own invitation codeBIND_FAILED- Failed to bind relationship
Get the inviter address for a specific invitee.
- Path Parameters:
invitee: Invitee's Tondi address
- Response:
{
"inviter": "tondi_testnet_address"
}- Note: Returns
{"inviter": null}if no inviter is found - Error Codes:
INVITER_FAILED- Failed to retrieve inviter
Count total and available invitees for an inviter.
- Path Parameters:
inviter: Inviter's Tondi address
- Response:
{
"total_invitees": 10,
"available_invitees": 8
}- Error Codes:
COUNT_FAILED- Failed to count invitees
Get the configured invitation milestones.
- Response:
[
{"invitees_count": 1, "reward_amount": 10},
{"invitees_count": 5, "reward_amount": 20},
{"invitees_count": 10, "reward_amount": 30}
]Get milestone reward records for an inviter.
- Path Parameters:
inviter: Inviter's Tondi address
- Response:
[
{
"inviter": "tondi_testnet_address",
"amount": 20,
"invitees_count": 5,
"create_timestamp": 1234567890,
"airdrop_tx": [...]
}
]- Error Codes:
RECORDS_FAILED- Failed to retrieve records
Update the task configuration (admin only).
- Headers:
Authorization: Bearer {admin_jwt_token}
- Request Body:
{
"watch_tweets": ["tweet_id1", "tweet_id2", "tweet_id3"]
}- Response: 200 OK or 500 with error message
Required environment variables:
# Twitter OAuth credentials
API_KEY_CODE="your_twitter_api_key"
API_SECRET_CODE="your_twitter_api_secret"
CALLBACK_URL="https://your-domain.com/oauth"
# Database
DATABASE_URL="sqlite://sqlite-db/taskchecker.db"
# Telegram Bot
TG_BOT_TOKEN="your_telegram_bot_token"
TG_CHANNEL="@YOUR_CHANNEL"
# Airdrop configuration
AIRDROP_SENDER_SK="sender_private_key_hex"
# Admin user (for task updates)
ADMIN_X_USERNAME="admin_twitter_username"cargo run --release -- \
--network "testnet" \
--airdrop-total-amount 100000000000 \
--pre-claimed-amount 0 \
--amount-per-claim 100 \
--tondi-node-url "grpc://localhost:16210" \
--lock-time 1764839943070 \
--external-bind-addr "0.0.0.0:80" \
--internal-api-addr "0.0.0.0:8080" \
--task-call-interval-secs 900 \
--approve-claim-interval-mins 10 \
--invite-milestone "[[1, 10], [5, 20], [10, 30]]" \
--set-invite-code-reward-amount 10--network: Network type (mainnet, testnet, devnet)--airdrop-total-amount: Total tokens available for airdrop (in smallest unit)--pre-claimed-amount: Amount already claimed before system start--amount-per-claim: Tokens awarded per successful claim--tondi-node-url: Tondi GRPC node URL--lock-time: Lock time in Unix timestamp or block height for locked tokens--external-bind-addr: Public API bind address (default: 0.0.0.0:80)--internal-api-addr: Internal API bind address (default: 0.0.0.0:8080)--task-call-interval-secs: Interval between task fetching calls (default: 900 seconds / 15 minutes)--approve-claim-interval-mins: Interval between claim approval runs (default: 10 minutes)--invite-milestone: JSON array of [invitee_count, reward_amount] pairs--set-invite-code-reward-amount: Reward amount for setting invitation code
Each claim distributes tokens with a lock mechanism:
- 15% non-locked: Immediately available
- 85% locked: Locked until the configured
lock_time
- Invitee Reward: Fixed amount when an invitee successfully claims (configured via
set-invite-code-reward-amount) - Milestone Rewards: Inviter receives additional rewards upon reaching invitation milestones
- pending_review: Initial state after claim submission
- waiting_manual_verification: Tasks verified, awaiting final approval
- claim_submitted: Approved and tokens distributed
- claim_denied: Claim rejected
For a claim to be approved, users must complete:
- Like at least one tracked tweet
- Perform at least one of:
- Retweet a tracked tweet
- Quote tweet a tracked tweet
- Reply to a tracked tweet
- Join the Telegram channel
Uses SQLite database with tables for:
- User tokens (OAuth credentials)
- Claim records
- Invitation mappings
- Invitation codes
- Invitee rewards
- Milestone claim records
Database file location: sqlite-db/taskchecker.db
# Build release version
cargo build --release
# Run tests
cargo test
# Run with configuration
./xtaskcheck-start.sh # Linux/Mac
./xtaskcheck-start.ps1 # WindowsFour concurrent workers fetch Twitter data:
- Liking users fetcher
- Retweeted by fetcher
- Quote tweets fetcher
- Search recent (replies) fetcher
Data is stored in out/ directory as JSON files.
Periodically checks claims in pending_review status and moves them to waiting_manual_verification when requirements are met.
Automatically approves and processes claims in waiting_manual_verification status based on the configured interval.
- Distributes rewards to invitees who successfully claim
- Processes milestone rewards for inviters
- Runs every 10 minutes
- JWT tokens expire after 7 days for Twitter auth
- Rate limiting on Telegram verification endpoint (2 seconds between requests per user)
- Admin-only access to task update endpoint
- IP address tracking for claim submissions
- PKCE flow for Twitter OAuth
- HTTPS and secure cookies for production use
See repository for license information.