gogo2/test_mexc_signature.py
2025-05-28 11:18:07 +03:00

321 lines
10 KiB
Python

"""
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&timestamp=1644489390087
query_string3 = f"symbol={params['symbol']}&side={params['side']}&type={params['type']}&quantity={params['quantity']}&timestamp={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")