diff --git a/demo/aster-code.py b/demo/aster-code.py index a367a0a..edfe030 100644 --- a/demo/aster-code.py +++ b/demo/aster-code.py @@ -1,8 +1,9 @@ import time +import threading import requests from eth_account import Account -from eth_account.messages import encode_structured_data +from eth_account.messages import encode_typed_data from copy import deepcopy import json @@ -113,7 +114,7 @@ def sign_v3_eip712(private_key, message, primary_type) -> str: print(data) print(sign_data) - msg = encode_structured_data(sign_data) + msg = encode_typed_data(full_message=sign_data) signed = Account.sign_message(msg, private_key=private_key) return signed.signature.hex() @@ -151,26 +152,25 @@ def sign_v3(private_key, message) -> str: # print(typed_data_sign) # print(message) - msg = encode_structured_data(typed_data_sign) + msg = encode_typed_data(full_message=typed_data_sign) signed = Account.sign_message(msg, private_key=private_key) print(signed.signature.hex()) return signed.signature.hex() -_last_ms = 0 -_i = 0 +_last_nonce = 0 +_nonce_lock = threading.Lock() def get_nonce(): - global _last_ms, _i - now_ms = int(time.time()) - - if now_ms == _last_ms: - _i += 1 - else: - _last_ms = now_ms - _i = 0 - - return now_ms * 1_000_000 + _i + # Microsecond timestamp; the server requires microsecond precision within 10s. + # Locked and strictly monotonic so concurrent callers never reuse a nonce. + global _last_nonce + with _nonce_lock: + n = time.time_ns() // 1000 + if n <= _last_nonce: + n = _last_nonce + 1 + _last_nonce = n + return n def send_by_url(method_config): param = method_config['params'] diff --git a/demo/consolidation.js b/demo/consolidation.js index aaf5136..5b43fbe 100644 --- a/demo/consolidation.js +++ b/demo/consolidation.js @@ -195,7 +195,7 @@ async function main() { sendToMainAddressRes = await send(spot_send_toAddress, { 'asset': config.asset, "amount": config.amount, "toAddress": main_address }) console.log('sendToMainAddressRes:', sendToMainAddressRes) use_new_apikey = false - if(sendToMainAddressRes['status'] = 'SUCCESS'){ + if(sendToMainAddressRes && sendToMainAddressRes['status'] === 'SUCCESS'){ console.log('归集成功:', config.address); }else{ console.log('归集失败:', config.address); @@ -221,7 +221,7 @@ async function main() { 'userSignature': withdraw_ignature, 'receiver': main_address, 'asset': withdraw_asset, 'amount': withdraw_amount }) - if(spotWithdraw['hash'] != ''){ + if(spotWithdraw && spotWithdraw['hash']){ console.log('提现成功:', spotWithdraw['hash']); }else{ console.log('提现失败:', spotWithdraw); diff --git a/demo/package.json b/demo/package.json new file mode 100644 index 0000000..6b728b6 --- /dev/null +++ b/demo/package.json @@ -0,0 +1,10 @@ +{ + "name": "aster-api-demo", + "version": "1.0.0", + "private": true, + "description": "Aster API demo scripts (consolidation, api-key creation, withdrawal).", + "dependencies": { + "axios": "^1.7.0", + "ethers": "^6.13.0" + } +} diff --git a/demo/requirements.txt b/demo/requirements.txt new file mode 100644 index 0000000..8797312 --- /dev/null +++ b/demo/requirements.txt @@ -0,0 +1,7 @@ +# Pinned dependencies for the Python demos (aster-code.py, sol_agent.py). +# eth-account >= 0.13 is required: encode_typed_data() replaced the older +# encode_structured_data() API that earlier examples imported. +eth-account>=0.13.0 +requests>=2.31.0 +base58>=2.1.1 +PyNaCl>=1.5.0 diff --git a/demo/sol_agent.py b/demo/sol_agent.py index 201db78..7fba218 100644 --- a/demo/sol_agent.py +++ b/demo/sol_agent.py @@ -3,7 +3,7 @@ import base58 from eth_account import Account -from eth_account.messages import encode_structured_data +from eth_account.messages import encode_typed_data from nacl.signing import SigningKey import time import requests @@ -92,22 +92,19 @@ def sign(message, all_bytes=None) : print("signature hex:", signature.hex()) return base58.b58encode(signature).decode() -_last_ms = 0 -_i = 0 +_last_nonce = 0 _nonce_lock = threading.Lock() def get_nonce(): - global _last_ms, _i + # Microsecond timestamp; the server requires microsecond precision within 10s. + # Locked and strictly monotonic so concurrent callers never reuse a nonce. + global _last_nonce with _nonce_lock: - now_ms = int(time.time()) - - if now_ms == _last_ms: - _i += 1 - else: - _last_ms = now_ms - _i = 0 - - return now_ms * 1_000_000 + _i + n = time.time_ns() // 1000 + if n <= _last_nonce: + n = _last_nonce + 1 + _last_nonce = n + return n def send_by_url(api) : my_dict = api['params'] @@ -117,7 +114,7 @@ def send_by_url(api) : my_dict['nonce'] = str(get_nonce()) my_dict['user'] = user - print(str(get_nonce())) + print(my_dict['nonce']) signature = '' param = '' @@ -130,7 +127,7 @@ def send_by_url(api) : param = urllib.parse.urlencode(my_dict) print(param) typed_data['message']['msg'] = param - message = encode_structured_data(typed_data) + message = encode_typed_data(full_message=typed_data) signature = Account.sign_message(message, private_key=signer_pri_key).signature.hex() url = url + '?' + param + '&signature=' + signature