""" Test MEXC Signature Generation This script tests the MEXC signature generation to ensure it's correct according to the MEXC API documentation. """ import os import sys import hashlib import hmac from urllib.parse import urlencode import time import requests # Add paths for imports sys.path.append(os.path.join(os.path.dirname(__file__), 'NN')) from NN.exchanges.mexc_interface import MEXCInterface def test_signature_generation(): """Test MEXC signature generation with known examples""" print("="*60) print("MEXC SIGNATURE GENERATION TEST") print("="*60) api_key = os.getenv('MEXC_API_KEY') api_secret = os.getenv('MEXC_SECRET_KEY') if not api_key or not api_secret: print("❌ Missing API credentials") return False print(f"API Key: {api_key[:8]}...{api_key[-4:]}") print(f"API Secret: {api_secret[:8]}...{api_secret[-4:]}") # Test 1: Simple signature generation print("\n1. Testing basic signature generation...") test_params = { 'symbol': 'ETHUSDT', 'side': 'BUY', 'type': 'MARKET', 'quantity': '0.001', 'timestamp': 1640995200000, 'recvWindow': 5000 } # Generate signature manually sorted_params = sorted(test_params.items()) query_string = urlencode(sorted_params) expected_signature = hmac.new( api_secret.encode('utf-8'), query_string.encode('utf-8'), hashlib.sha256 ).hexdigest() print(f"Query string: {query_string}") print(f"Expected signature: {expected_signature}") # Generate signature using MEXC interface mexc = MEXCInterface(api_key=api_key, api_secret=api_secret, test_mode=True) actual_signature = mexc._generate_signature(test_params) print(f"Actual signature: {actual_signature}") if expected_signature == actual_signature: print("✅ Signature generation matches expected") else: print("❌ Signature generation mismatch") return False # Test 2: Real order parameters print("\n2. Testing with real order parameters...") current_timestamp = int(time.time() * 1000) real_params = { 'symbol': 'ETHUSDT', 'side': 'BUY', 'type': 'MARKET', 'quantity': '0.001', 'timestamp': current_timestamp, 'recvWindow': 5000 } real_signature = mexc._generate_signature(real_params) sorted_real_params = sorted(real_params.items()) real_query_string = urlencode(sorted_real_params) print(f"Real timestamp: {current_timestamp}") print(f"Real query string: {real_query_string}") print(f"Real signature: {real_signature}") # Test 3: Verify parameter ordering print("\n3. Testing parameter ordering sensitivity...") # Test with parameters in different order unordered_params = { 'timestamp': current_timestamp, 'symbol': 'ETHUSDT', 'recvWindow': 5000, 'type': 'MARKET', 'side': 'BUY', 'quantity': '0.001' } unordered_signature = mexc._generate_signature(unordered_params) if real_signature == unordered_signature: print("✅ Parameter ordering handled correctly") else: print("❌ Parameter ordering issue") return False # Test 4: Check for common issues print("\n4. Checking for common signature issues...") # Check if any parameters need special encoding special_params = { 'symbol': 'ETHUSDT', 'side': 'BUY', 'type': 'MARKET', 'quantity': '0.0028417810009889397', # Full precision from error log 'timestamp': current_timestamp, 'recvWindow': 5000 } special_signature = mexc._generate_signature(special_params) special_sorted = sorted(special_params.items()) special_query = urlencode(special_sorted) print(f"Special quantity: {special_params['quantity']}") print(f"Special query: {special_query}") print(f"Special signature: {special_signature}") # Test 5: Compare with error log signature print("\n5. Comparing with error log...") # From the error log, we have this signature: error_log_signature = "2a52436039e24b593ab0ab20ac1a67e2323654dc14190ee2c2cde341930d27d4" error_timestamp = 1748349875981 error_params = { 'symbol': 'ETHUSDT', 'side': 'BUY', 'type': 'MARKET', 'quantity': '0.0028417810009889397', 'recvWindow': 5000, 'timestamp': error_timestamp } recreated_signature = mexc._generate_signature(error_params) print(f"Error log signature: {error_log_signature}") print(f"Recreated signature: {recreated_signature}") if error_log_signature == recreated_signature: print("✅ Signature recreation matches error log") else: print("❌ Signature recreation doesn't match - potential algorithm issue") # Debug the query string debug_sorted = sorted(error_params.items()) debug_query = urlencode(debug_sorted) print(f"Debug query string: {debug_query}") # Try manual HMAC manual_sig = hmac.new( api_secret.encode('utf-8'), debug_query.encode('utf-8'), hashlib.sha256 ).hexdigest() print(f"Manual signature: {manual_sig}") print("\n" + "="*60) print("SIGNATURE TEST COMPLETED") print("="*60) return True def test_mexc_api_call(): """Test a simple authenticated API call to verify signature works""" print("\n6. Testing authenticated API call...") try: api_key = os.getenv('MEXC_API_KEY') api_secret = os.getenv('MEXC_SECRET_KEY') mexc = MEXCInterface(api_key=api_key, api_secret=api_secret, test_mode=True) # Test account info (this should work if signature is correct) account_info = mexc.get_account_info() print("✅ Account info call successful - signature is working") print(f" Account type: {account_info.get('accountType', 'Unknown')}") print(f" Can trade: {account_info.get('canTrade', 'Unknown')}") return True except Exception as e: print(f"❌ Account info call failed: {e}") return False # Test exact signature generation for MEXC order placement def test_mexc_order_signature(): api_key = os.getenv('MEXC_API_KEY') api_secret = os.getenv('MEXC_SECRET_KEY') if not api_key or not api_secret: print("❌ MEXC API keys not found") return print("=== MEXC ORDER SIGNATURE DEBUG ===") print(f"API Key: {api_key[:8]}...{api_key[-4:]}") print(f"Secret Key: {api_secret[:8]}...{api_secret[-4:]}") print() # Get server time first try: time_resp = requests.get('https://api.mexc.com/api/v3/time') server_time = time_resp.json()['serverTime'] print(f"✅ Server time: {server_time}") except Exception as e: print(f"❌ Failed to get server time: {e}") server_time = int(time.time() * 1000) print(f"Using local time: {server_time}") # Test order parameters (from MEXC documentation example) params = { 'symbol': 'MXUSDT', # Changed to API-supported symbol 'side': 'BUY', 'type': 'MARKET', 'quantity': '1', # Small test quantity (1 MX token) 'timestamp': server_time } print("\n=== Testing Different Signature Methods ===") # Method 1: Sorted parameters with & separator (current approach) print("\n1. Current approach (sorted with &):") sorted_params = sorted(params.items()) query_string1 = '&'.join([f"{key}={value}" for key, value in sorted_params]) signature1 = hmac.new( api_secret.encode('utf-8'), query_string1.encode('utf-8'), hashlib.sha256 ).hexdigest() print(f"Query: {query_string1}") print(f"Signature: {signature1}") # Method 2: URL encoded (like account info that works) print("\n2. URL encoded approach:") sorted_params = sorted(params.items()) query_string2 = urlencode(sorted_params) signature2 = hmac.new( api_secret.encode('utf-8'), query_string2.encode('utf-8'), hashlib.sha256 ).hexdigest() print(f"Query: {query_string2}") print(f"Signature: {signature2}") # Method 3: MEXC documentation example format print("\n3. MEXC docs example format:") # From MEXC docs: symbol=BTCUSDT&side=BUY&type=LIMIT&quantity=1&price=11&recvWindow=5000×tamp=1644489390087 query_string3 = f"symbol={params['symbol']}&side={params['side']}&type={params['type']}&quantity={params['quantity']}×tamp={params['timestamp']}" signature3 = hmac.new( api_secret.encode('utf-8'), query_string3.encode('utf-8'), hashlib.sha256 ).hexdigest() print(f"Query: {query_string3}") print(f"Signature: {signature3}") # Test all methods by making actual requests print("\n=== Testing Actual Requests ===") methods = [ ("Current approach", signature1, params), ("URL encoded", signature2, params), ("MEXC docs format", signature3, params) ] for method_name, signature, test_params in methods: print(f"\n{method_name}:") test_params_copy = test_params.copy() test_params_copy['signature'] = signature headers = {'X-MEXC-APIKEY': api_key} try: response = requests.post( 'https://api.mexc.com/api/v3/order', params=test_params_copy, headers=headers, timeout=10 ) print(f"Status: {response.status_code}") print(f"Response: {response.text[:200]}...") if response.status_code == 200: print("✅ SUCCESS!") break elif "Signature for this request is not valid" in response.text: print("❌ Invalid signature") else: print(f"❌ Other error: {response.status_code}") except Exception as e: print(f"❌ Request failed: {e}") if __name__ == "__main__": success = test_signature_generation() if success: success = test_mexc_api_call() if success: test_mexc_order_signature() print("\n🎉 All signature tests passed!") else: print("\n🚨 Signature tests failed - check the output above")