# Binance Alpha Farm Agent Automated trading agent for Binance Alpha Farm with robust state management and task-step architecture. ## πŸ“‹ Table of Contents - [System Architecture](#system-architecture) - [Code Structure & Module Order](#code-structure--module-order) - [Task-Step System](#task-step-system) - [Bot Status Flow](#bot-status-flow) - [State Management](#state-management) - [Navigation State Management](#navigation-state-management) - [Helper Functions](#helper-functions) - [Configuration](#configuration) - [API Endpoints](#api-endpoints) - [Development Notes](#development-notes) ## πŸ—οΈ System Architecture The agent follows a **hybrid architecture** combining centralized task definitions with dedicated step execution: ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ AppState β”‚ β”‚ TaskRunner β”‚ β”‚ StepRunner β”‚ β”‚ (State Mgmt) │◄──►│ (Task Mgmt) │◄──►│ (Step Exec) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β–Ό β–Ό β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ StateWatchers β”‚ β”‚ TASK_DEFINITIONSβ”‚ β”‚ Step Functions β”‚ β”‚ (Observers) β”‚ β”‚ (Task Config) β”‚ β”‚ (Step Logic) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Key Components: - **AppState**: Centralized state management with observer pattern - **TaskRunner**: Handles task polling and coordination - **StepRunner**: Executes individual steps with navigation handling - **StateWatchers**: React to state changes (page, login, bot status) - **TASK_DEFINITIONS**: Centralized task configurations - **Step Functions**: Modular step logic (LoginSteps, OrderHistorySteps, BalanceSteps) ## πŸ“ Code Structure & Module Order The code follows this specific order for maintainability: ### 1. **Configuration & Constants** ```javascript // ====== CONFIGURATION ====== const CONFIG = { ... } // ====== ENUMS & CONSTANTS ====== const BOT_STATUS = { ... } const TASK_TYPES = { ... } const STEP_TYPES = { ... } const LOGIN_METHOD = { ... } const ORDER_TYPE = { ... } const ORDER_STATUS = { ... } const BALANCE_FORMAT = { ... } const GAS_FEE_TYPE = { ... } ``` ### 2. **State Management** ```javascript // ====== STATE MANAGEMENT ====== class AppState { ... } // ====== STORAGE MODULE ====== const STORAGE = { ... } ``` ### 3. **Utility Modules** ```javascript // ====== TL UTILITY MODULE ====== const TL = { ... } // ====== BAF API MODULE ====== const BAF = { ... } // ====== BINANCE PAGE MODULE ====== const BINANCE = { ... } ``` ### 4. **Step Functions (Modular Logic)** ```javascript // ====== STEP FUNCTIONS ====== const LoginSteps = { ... } const OrderHistorySteps = { ... } const BalanceSteps = { ... } ``` ### 5. **Task Definitions** ```javascript // ====== TASK DEFINITIONS ====== const TASK_DEFINITIONS = { ... } ``` ### 6. **Core Execution Engine** ```javascript // ====== STEP RUNNER ====== class StepRunner { ... } // ====== TASK RUNNER ====== const TaskRunner = { ... } // ====== STATE WATCHERS ====== const StateWatchers = { ... } ``` ### 7. **UI & Initialization** ```javascript // ====== UI & MENU ====== async function createGM_Menu() { ... } // ====== MONITORING ====== async function heartbeat_report() { ... } async function monitorPageChanges() { ... } // ====== INITIALIZATION ====== async function initialize() { ... } ``` ## πŸ”„ Task-Step System ### Task Types ```javascript const TASK_TYPES = { LOGIN: 'login', GET_ORDER_HISTORY: 'get_order_history', GET_BALANCE: 'get_balance', SWAP: 'swap', NO_TASK: 'no_task' }; ``` ### Step Types by Task #### **Login Task** ```javascript const STEP_TYPES = { LOGIN: { NAVIGATE_TO_LOGIN: 'NavigateToLogin', SELECT_QR_CODE: 'SelectQRCode', WAIT_FOR_LOGIN: 'WaitForLogin' } }; ``` #### **Order History Task** ```javascript const STEP_TYPES = { GET_ORDER_HISTORY: { NAVIGATE_TO_ORDER_HISTORY: 'NavigateToOrderHistory', EXTRACT_ORDER_DATA: 'ExtractOrderData', SEND_ORDER_DATA: 'SendOrderData' } }; ``` #### **Balance Task** ```javascript const STEP_TYPES = { GET_BALANCE: { NAVIGATE_TO_BALANCE: 'NavigateToBalance', EXTRACT_BALANCE_DATA: 'ExtractBalanceData', SEND_BALANCE_DATA: 'SendBalanceData' } }; ``` ### Task Data Examples #### **Login Task** ```javascript { type: TASK_TYPES.LOGIN, id: "login_123", data: { method: LOGIN_METHOD.QR_CODE, timeout: 300000, // 5 minutes retry_count: 3 } } ``` #### **Order History Task** ```javascript { type: TASK_TYPES.GET_ORDER_HISTORY, id: "order_history_456", data: { limit: 50, date_from: "2024-01-01", date_to: "2024-12-31", status: ORDER_STATUS.COMPLETED } } ``` #### **Balance Task** ```javascript { type: TASK_TYPES.GET_BALANCE, id: "balance_789", data: { currencies: ["USDT", "BTC", "ETH"], format: BALANCE_FORMAT.DECIMAL } } ``` ## πŸ€– Bot Status Flow ### Status Transitions ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ ready-for-new- │────►│ performing- │────►│ ready-for-new- β”‚ β”‚ tasks β”‚ β”‚ tasks β”‚ β”‚ tasks β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β–² β–Ό β–Ό β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ pause- │◄───── Task Complete β”‚β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ automation β”‚ β”‚ or Error β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Flow Description: 1. **ready-for-new-tasks**: Bot polls server for new tasks 2. **performing-tasks**: Bot executes task steps 3. **pause-automation**: Bot stops (manual or error) 4. **Back to ready-for-new-tasks**: After task completion or resume ### Task Polling Logic: ```javascript // Poll only when ready-for-new-tasks if (bot_status === BOT_STATUS.READY_FOR_NEW_TASKS) { const task = await BAF.getTask(); if (task.type === TASK_TYPES.NO_TASK) { // Sleep for interval before next poll await delay(CONFIG.task_poll_interval); } else { // Start task execution bot_status = BOT_STATUS.PERFORMING_TASKS; } } ``` ## 🎯 State Management ### AppState Structure ```javascript class AppState { data = { // Server configuration server_type: 'prod', server_url: null, // Page state current_page: null, is_logged_in: false, // Bot status bot_status: BOT_STATUS.READY_FOR_NEW_TASKS, // Task state current_task: null, task_data: null, current_step: null, step_data: null, // UI state is_loading: false, error_message: null }; } ``` ### Observer Pattern ```javascript // Subscribe to state changes APP_STATE.subscribe('bot_status', StateWatchers.onBotStatusChange); APP_STATE.subscribe('current_page', StateWatchers.onCurrentPageChange); APP_STATE.subscribe('is_logged_in', StateWatchers.onLoginStateChange); // Notify observers on state change await APP_STATE.update({ bot_status: BOT_STATUS.PERFORMING_TASKS }); ``` ## 🧭 Navigation State Management ### Navigation State Structure ```javascript { navigating: true, navigation_start: 1703123456789, navigation_target: "https://accounts.binance.com/login", task_id: "task_123", step_index: 0 } ``` ### Navigation Flow ``` 1. Step executes β†’ ctx.goto('/login') ↓ 2. Mark navigating = true ↓ 3. Save navigation state to storage ↓ 4. window.location.href = '/login' ↓ 5. Page reloads, userscript restarts ↓ 6. resumeTask() β†’ detect navigation state ↓ 7. handleNavigationResume() β†’ check target page ↓ 8. Skip navigation step, continue next step ``` ### guardDoubleRun Helper ```javascript // Prevents double execution during navigation await TL.guardDoubleRun(ctx, async () => { // Step logic here if (!BINANCE.isOnLoginPage()) { BINANCE.navigateToLogin(); } }); ``` ## πŸ› οΈ Helper Functions ### TL Utility Module ```javascript const TL = { // Logging log: (level, message, data) => { ... }, debug: (level, message, data) => { ... }, error: (level, message, error) => { ... }, // Utilities delay: (ms) => new Promise(resolve => setTimeout(resolve, ms)), notification: (title, text, timeout) => { ... }, // Navigation guard guardDoubleRun: async (ctx, stepLogic) => { ... }, // DOM helpers dom: { isVisible: (el) => { ... }, isDisabled: (el) => { ... }, click: (el) => { ... }, scrollToView: (el, behavior) => { ... } }, // Network helpers net: { gmRequest: (url, init) => { ... } } }; ``` ### TaskRunner Helpers ```javascript const TaskRunner = { // Task validation validateEnum: (value, enumObj, defaultValue) => { ... }, validateTaskData: (taskType, taskData) => { ... }, // Task state getCurrentTaskData: () => { ... }, updateTaskData: (newData) => { ... }, isCurrentTaskType: (taskType) => { ... }, // Task execution checkForNewTasks: async () => { ... }, continueCurrentStep: async () => { ... } }; ``` ### StepRunner Context ```javascript // Context passed to step functions { task_id: "task_123", task_type: TASK_TYPES.LOGIN, task_data: { method: LOGIN_METHOD.QR_CODE }, step_data: {}, is_logged_in: false, current_page: BINANCE_PAGES.LOGIN, current_step_name: "NavigateToLogin", // Helper methods done: (result) => this.completeTask(result), goto: (url) => this.navigateTo(url), wait: (ms) => this.wait(ms), retry: (fn, maxAttempts) => this.retry(fn, maxAttempts) } ``` ## βš™οΈ Configuration ### Server Configuration ```javascript const CONFIG = { heartbeat_interval: 10000, // 10 seconds task_poll_interval: 10000, // 10 seconds is_debug: true, servers: { local: { label: '🏠 Local', url: 'http://localhost:3000' }, prod: { label: '🌐 Prod', url: 'https://baf.thuanle.me' } } }; ``` ### Storage Keys ```javascript const STORAGE = { key_token: 'baf-agent-token', key_server_type: 'baf-server-type', key_bot_status: 'baf-bot-status', key_navigation_state: 'baf-navigation-state' }; ``` ## 🌐 API Endpoints ### BAF API Methods ```javascript const BAF = { // Server management getServer: async () => { ... }, getHost: async () => { ... }, // API requests request: async (method, path, options) => { ... }, // Task management getTask: async () => { ... }, submitTaskResult: async (taskId, result) => { ... }, // Heartbeat heartbeat: async (data) => { ... } }; ``` ### Page Detection ```javascript const BINANCE = { // Page detection detectPage: () => { ... }, isOnLoginPage: () => { ... }, isOnAlphaSwapPage: () => { ... }, isOnAlphaOrderHistoryPage: () => { ... }, isLoggedIn: async () => { ... }, // Navigation navigateToLogin: () => { ... }, navigateToAlphaSwap: () => { ... }, navigateToAlphaOrderHistory: () => { ... } }; ``` ## πŸš€ Development Notes ### Adding New Tasks 1. **Define Task Type**: ```javascript const TASK_TYPES = { // ... existing types NEW_TASK: 'new-task' }; ``` 2. **Create Step Functions**: ```javascript const NewTaskSteps = { matchStep1: (url, ctx) => { /* match logic */ }, runStep1: async (ctx) => { await TL.guardDoubleRun(ctx, async () => { // Step logic }); } }; ``` 3. **Add Task Definition**: ```javascript const TASK_DEFINITIONS = { [TASK_TYPES.NEW_TASK]: { id: "new-task", steps: [ { name: "Step1", match: NewTaskSteps.matchStep1, run: NewTaskSteps.runStep1 } ] } }; ``` ### Adding New Steps 1. **Add Step Type**: ```javascript const STEP_TYPES = { NEW_TASK: { // ... existing steps NEW_STEP: 'NewStep' } }; ``` 2. **Implement Step Functions**: ```javascript const NewTaskSteps = { // ... existing steps matchNewStep: (url, ctx) => { return url.includes("/target-page") && ctx?.step_data?.previous_step_completed; }, runNewStep: async (ctx) => { await TL.guardDoubleRun(ctx, async () => { // Step logic here ctx.step_data.new_step_completed = true; }); } }; ``` 3. **Update Task Definition**: ```javascript [TASK_TYPES.NEW_TASK]: { id: "new-task", steps: [ // ... existing steps { name: "NewStep", match: NewTaskSteps.matchNewStep, run: NewTaskSteps.runNewStep } ] } ``` ### Best Practices 1. **Always use `guardDoubleRun`** for step functions to prevent double execution 2. **Use enums** for type safety (TASK_TYPES, LOGIN_METHOD, etc.) 3. **Validate task data** using `TaskRunner.validateTaskData` 4. **Handle navigation** using `ctx.goto()` instead of direct `window.location` 5. **Use context helpers** (`ctx.wait()`, `ctx.retry()`) for robust execution 6. **Log appropriately** using `TL.log()`, `TL.debug()`, `TL.error()` 7. **Update step_data** to track progress and avoid duplicate work 8. **Handle errors gracefully** with try-catch and proper error reporting ### Debugging Tips 1. **Enable debug mode**: Set `CONFIG.is_debug = true` 2. **Check navigation state**: Use `STORAGE.getNavigationState()` 3. **Monitor state changes**: Watch `APP_STATE.getData()` values 4. **Check step execution**: Look for `[STEP]` logs in console 5. **Verify page detection**: Use `BINANCE.detectPage()` to check current page 6. **Test step matching**: Use step `match` functions directly 7. **Check task data**: Use `TaskRunner.getCurrentTaskData()`