@@ -154,315 +154,114 @@ print(nonce)
154154Instant now = Instant . now();
155155long microsecond = now. getEpochSecond() * 1000000 + now. getNano() / 1000 ;
156156```
157- #### Example: The following parameters are business request parameters.
158157
159- ``` python
160- my_dict = {' symbol' : ' SANDUSDT' , ' positionSide' : ' BOTH' , ' type' : ' LIMIT' , ' side' : ' BUY' ,
161- ' timeInForce' : ' GTC' , ' quantity' : " 190" , ' price' : 0.28694 }
162- ```
163-
164- #### Example: All parameters are sent via form body (using Python as an example).
165-
166- > ** Step 1: Convert all business parameters to strings, then sort them in ASCII order to generate a string.**
167-
168- ``` python
169- # Define all element values as strings.
170- def _trim_dict (my_dict ) :
171- for key in my_dict:
172- value = my_dict[key]
173- if isinstance (value, list ):
174- new_value = []
175- for item in value:
176- if isinstance (item, dict ):
177- new_value.append(json.dumps(_trim_dict(item)))
178- else :
179- new_value.append(str (item))
180- my_dict[key] = json.dumps(new_value)
181- continue
182- if isinstance (value, dict ):
183- my_dict[key] = json.dumps(_trim_dict(value))
184- continue
185- my_dict[key] = str (value)
186-
187- return my_dict
188-
189- # Remove elements with null (empty) values.
190- my_dict = {key: value for key, value in my_dict.items() if value is not None }
191- my_dict[' recvWindow' ] = 50000
192- my_dict[' timestamp' ] = int (round (time.time()* 1000 ))
193- # my_dict['timestamp'] = 1749545309665
194- # Convert elements to strings.
195- _trim_dict(my_dict)
196- # Generate a string sorted by ASCII values and remove special characters.
197- json_str = json.dumps(my_dict, sort_keys = True ).replace(' ' , ' ' ).replace(' \' ' ,' \" ' )
198- print (json_str)
199- # {"positionSide":"BOTH","price":"0.28694","quantity":"190","recvWindow":"50000","side":"BUY","symbol":"SANDUSDT","timeInForce":"GTC","timestamp":"1749545309665","type":"LIMIT"}
200- ```
158+ #### Example: Post an order (using Python as an example).
201159
202- > ** Step 2: Take the string generated in Step 1 and encode it together with the account information and nonce using ABI encoding to generate a hash string.**
203160
204161``` python
205- from eth_abi import encode
206- from web3 import Web3
207- # Use Web3 ABI to encode the generated string along with user, signer, and nonce.
208- encoded = encode([' string' , ' address' , ' address' , ' uint256' ], [json_str, user, signer, nonce])
209- print (encoded.hex())
210- # 000000000000000000000000000000000000000000000000000000000000008000000000000000000000000063dd5acc6b1aa0f563956c0e534dd30b6dcf7c4e00000000000000000000000021cf8ae13bb72632562c6fff438652ba1a151bb00000000000000000000000000000000000000000000000000006361457bcec8300000000000000000000000000000000000000000000000000000000000000af7b22706f736974696f6e53696465223a22424f5448222c227072696365223a22302e3238363934222c227175616e74697479223a22313930222c227265637657696e646f77223a223530303030222c2273696465223a22425559222c2273796d626f6c223a2253414e4455534454222c2274696d65496e466f726365223a22475443222c2274696d657374616d70223a2231373439353435333039363635222c2274797065223a224c494d4954227d0000000000000000000000000000000000
211- # keccak hex
212- keccak_hex = Web3.keccak(encoded).hex()
213- print (keccak_hex)
214- # 9e0273fc91323f5cdbcb00c358be3dee2854afb2d3e4c68497364a2f27a377fc
215- ```
216-
217- > ** Step 3: Sign the hash generated in Step 2 using the privateKey.**
218-
219- ``` python
220- from eth_account import Account
221- from eth_abi import encode
222- from web3 import Web3, EthereumTesterProvider
223- from eth_account.messages import encode_defunct
224-
225- signable_msg = encode_defunct(hexstr = keccak_hex)
226- signed_message = Account.sign_message(signable_message = signable_msg, private_key = priKey)
227- signature = ' 0x' + signed_message.signature.hex()
228- print (signature)
229- # 0x0337dd720a21543b80ff861cd3c26646b75b3a6a4b5d45805d4c1d6ad6fc33e65f0722778dd97525466560c69fbddbe6874eb4ed6f5fa7e576e486d9b5da67f31b
230- ```
231-
232- > ** Step 4: Combine all parameters along with the signature generated in Step 3 into the request body.**
233-
234- ``` python
235- my_dict[' nonce' ] = nonce
236- my_dict[' user' ] = user
237- my_dict[' signer' ] = signer
238- my_dict[' signature' ] = ' 0x' + signed_message.signature.hex()
239- url = ' https://fapi.asterdex.com/fapi/v3/order'
240- headers = {
241- ' Content-Type' : ' application/x-www-form-urlencoded' ,
242- ' User-Agent' : ' PythonApp/1.0'
243- }
244- res = requests.post(url,data = my_dict,headers = headers)
245- print (url)
246- # curl -X POST 'https://fapi.asterdex.com/fapi/v3/order' -d 'symbol=SANDUSDT&positionSide=BOTH&type=LIMIT&side=BUY&timeInForce=GTC&quantity=190&price=0.28694&recvWindow=50000×tamp=1749545309665&nonce=1748310859508867&user=0x63DD5aCC6b1aa0f563956C0e534DD30B6dcF7C4e&signer=0x21cF8Ae13Bb72632562c6Fff438652Ba1a151bb0&signature=0x0337dd720a21543b80ff861cd3c26646b75b3a6a4b5d45805d4c1d6ad6fc33e65f0722778dd97525466560c69fbddbe6874eb4ed6f5fa7e576e486d9b5da67f31b'
247- ```
248-
249- ## ** Example of GET /fapi/v3/order**
162+ import time
163+ import requests
164+ from eth_account.messages import encode_structured_data
165+ from eth_account import Account
250166
251- #### Example: All parameters are sent through the query string (Python 3.9.6).
167+ typed_data = {
168+ " types" : {
169+ " EIP712Domain" : [
170+ {" name" : " name" , " type" : " string" },
171+ {" name" : " version" , " type" : " string" },
172+ {" name" : " chainId" , " type" : " uint256" },
173+ {" name" : " verifyingContract" , " type" : " address" }
174+ ],
175+ " Message" : [
176+ { " name" : " msg" , " type" : " string" }
177+ ]
178+ },
179+ " primaryType" : " Message" ,
180+ " domain" : {
181+ " name" : " AsterSignTransaction" ,
182+ " version" : " 1" ,
183+ " chainId" : 1666 ,
184+ " verifyingContract" : " 0x0000000000000000000000000000000000000000"
185+ },
186+ " message" : {
187+ " msg" : " $msg"
188+ }
189+ }
252190
253- #### Example: The following parameters are API registration information. user, signer, and privateKey are for demonstration purposes only (where privateKey is the private key of the agent).
191+ headers = {
192+ ' Content-Type' : ' application/x-www-form-urlencoded' ,
193+ ' User-Agent' : ' PythonApp/1.0'
194+ }
195+ order_url = ' https://fapi.asterdex-testnet.com/fapi/v3/order'
254196
255- | Key | Value |
256- | ---------- | ------------------------------------------------------------------ |
257- | user | 0x63DD5aCC6b1aa0f563956C0e534DD30B6dcF7C4e |
258- | signer | 0x21cF8Ae13Bb72632562c6Fff438652Ba1a151bb0 |
259- | privateKey | 0x4fd0a42218f3eae43a6ce26d22544e986139a01e5b34a62db53757ffca81bae1 |
197+ # config your user and agent info here
198+ user = ' *'
199+ signer = ' *'
200+ private_key = " *"
260201
261- #### Example: The nonce parameter should be the current system timestamp in microseconds. If it exceeds the current time or lags behind the system time by more than 5 seconds, it will be considered an invalid request.
202+ def get_url (my_dict ) -> str :
203+ return ' &' .join(f ' { key} = { str (value)} ' for key, value in my_dict.items())
262204
263- ``` python
264- # python
265- nonce = math.trunc(time.time()* 1000000 )
266- print (nonce)
267- # 1748310859508867
268- ```
205+ _last_ms = 0
206+ _i = 0
269207
270- ``` java
271- // java
272- Instant now = Instant . now();
273- long microsecond = now. getEpochSecond() * 1000000 + now. getNano() / 1000 ;
274- ```
208+ def get_nonce ():
209+ global _last_ms, _i
210+ now_ms = int (time.time())
275211
276- #### Example: The following parameters are business request parameters.
212+ if now_ms == _last_ms:
213+ _i += 1
214+ else :
215+ _last_ms = now_ms
216+ _i = 0
277217
278- ``` python
279- my_dict = {' symbol' :' SANDUSDT' ,' side' :" SELL" ," type" :' LIMIT' ,' orderId' :2194215 }
280- ```
218+ return now_ms * 1_000_000 + _i
281219
282- > ** Step 1: Convert all business parameters to strings and generate a sorted string based on ASCII order.**
220+ def send_by_url () :
221+ param = ' symbol=ASTERUSDT&side=BUY&type=LIMIT&quantity=10&price=0.6&timeInForce=GTC'
283222
284- ``` python
285- # Define all element values as strings.
286- def _trim_dict (my_dict ) :
287- # 假设待删除的字典为d
288- for key in my_dict:
289- value = my_dict[key]
290- if isinstance (value, list ):
291- new_value = []
292- for item in value:
293- if isinstance (item, dict ):
294- new_value.append(json.dumps(_trim_dict(item)))
295- else :
296- new_value.append(str (item))
297- my_dict[key] = json.dumps(new_value)
298- continue
299- if isinstance (value, dict ):
300- my_dict[key] = json.dumps(_trim_dict(value))
301- continue
302- my_dict[key] = str (value)
303-
304- return my_dict
305-
306-
307- # Remove elements with empty values.
308- my_dict = {key: value for key, value in my_dict.items() if value is not None }
309- my_dict[' recvWindow' ] = 50000
310- my_dict[' timestamp' ] = int (round (time.time()* 1000 ))
311- # my_dict['timestamp'] = 1749545309665
312- # Convert all elements to strings.
313- _trim_dict(my_dict)
314- # Generate a string sorted by ASCII values and remove special characters.
315- json_str = json.dumps(my_dict, sort_keys = True ).replace(' ' , ' ' ).replace(' \' ' ,' \" ' )
316- print (json_str)
317- # {"orderId":"2194215","recvWindow":"50000","side":"BUY","symbol":"SANDUSDT","timestamp":"1749545309665","type":"LIMIT"}
318- ```
223+ param += ' &nonce=' + str (get_nonce())
224+ param += ' &user=' + user
225+ param += ' &signer=' + signer
319226
320- > ** Step 2: Use ABI encoding to combine the string from step 1 with the account information (user, signer) and nonce, then generate a hash string from the encoded result.**
227+ typed_data[' message' ][' msg' ] = param
228+ message = encode_structured_data(typed_data)
229+ signed = Account.sign_message(message, private_key = private_key)
230+ print (signed.signature.hex())
321231
322- ``` python
323- from eth_abi import encode
324- from web3 import Web3
325-
326- # Use WEB3 ABI to encode the generated string together with user, signer, and nonce.
327- encoded = encode([' string' , ' address' , ' address' , ' uint256' ], [json_str, user, signer, nonce])
328- print (encoded.hex())
329- # 000000000000000000000000000000000000000000000000000000000000008000000000000000000000000063dd5acc6b1aa0f563956c0e534dd30b6dcf7c4e00000000000000000000000021cf8ae13bb72632562c6fff438652ba1a151bb00000000000000000000000000000000000000000000000000006361457bcec8300000000000000000000000000000000000000000000000000000000000000767b226f726465724964223a2232313934323135222c227265637657696e646f77223a223530303030222c2273696465223a22425559222c2273796d626f6c223a2253414e4455534454222c2274696d657374616d70223a2231373439353435333039363635222c2274797065223a224c494d4954227d00000000000000000000
330- keccak_hex = Web3.keccak(encoded).hex()
331- print (keccak_hex)
332- # 6ad9569ea1355bf62de1b09b33b267a9404239af6d9227fa59e3633edae19e2a
333- ```
232+ url = order_url + ' ?' + param + ' &signature=' + signed.signature.hex()
334233
335- > ** Step 3: Sign the hash generated in Step 2 using the privateKey.**
234+ print (url)
235+ res = requests.post(url, headers = headers)
336236
337- ``` python
338- from eth_account import Account
339- from eth_abi import encode
340- from web3 import Web3, EthereumTesterProvider
341- from eth_account.messages import encode_defunct
342-
343- signable_msg = encode_defunct(hexstr = keccak_hex)
344- signed_message = Account.sign_message(signable_message = signable_msg, private_key = priKey)
345- signature = ' 0x' + signed_message.signature.hex()
346- print (signature)
347- # 0x4f5e36e91f0d4cf5b29b6559ebc2c808d3c808ebb13b2bcaaa478b98fb4195642c7473f0d1aa101359aaf278126af1a53bcb482fb05003bfb6bdc03de03c63151b
348- ```
237+ print (res.text)
349238
350- > ** Step 4: Combine all parameters and the signature from Step 3 into the request body.**
239+ def send_by_body () :
240+ my_dict = {" symbol" : " ASTERUSDT" , " type" : " LIMIT" , " side" : " BUY" ,
241+ " timeInForce" : " GTC" , " quantity" : " 10" , " price" : " 0.6" }
351242
352- ``` python
353- my_dict[' nonce' ] = nonce
354- my_dict[' user' ] = user
355- my_dict[' signer' ] = signer
356- my_dict[' signature' ] = ' 0x' + signed_message.signature.hex()
243+ my_dict[' nonce' ] = str (get_nonce())
244+ my_dict[' user' ] = user
245+ my_dict[' signer' ] = signer
357246
358- url = ' https://fapi.asterdex.com/fapi/v3/order'
247+ content = get_url(my_dict)
248+ typed_data[' message' ][' msg' ] = content
249+ message = encode_structured_data(typed_data)
359250
360- res = requests.get(url, params = my_dict)
361- print (url)
362- # curl -X GET 'https://fapi.asterdex.com/fapi/v3/order?symbol=SANDUSDT&side=BUY&type=LIMIT&orderId=2194215&recvWindow=50000×tamp=1749545309665&nonce=1748310859508867&user=0x63DD5aCC6b1aa0f563956C0e534DD30B6dcF7C4e&signer=0x21cF8Ae13Bb72632562c6Fff438652Ba1a151bb0&signature=0x4f5e36e91f0d4cf5b29b6559ebc2c808d3c808ebb13b2bcaaa478b98fb4195642c7473f0d1aa101359aaf278126af1a53bcb482fb05003bfb6bdc03de03c63151b'
363- ```
251+ signed = Account.sign_message(message, private_key = private_key)
252+ print (signed.signature.hex())
364253
365- ## ** python script **
254+ my_dict[ ' signature ' ] = signed.signature.hex()
366255
367- ``` python
368- # Python 3.9.6
369- # Python 3.9.6
370- # eth-account~=0.13.7
371- # eth-abi~=5.2.0
372- # web3~=7.11.0
373- # requests~=2.32.3
374-
375- import json
376- import math
377- import time
378- import requests
256+ print (my_dict)
257+ res = requests.post(order_url, data = my_dict, headers = headers)
379258
380- from eth_abi import encode
381- from eth_account import Account
382- from eth_account.messages import encode_defunct
383- from web3 import Web3
384-
385- user = ' 0x63DD5aCC6b1aa0f563956C0e534DD30B6dcF7C4e'
386- signer= ' 0x21cF8Ae13Bb72632562c6Fff438652Ba1a151bb0'
387- priKey = " 0x4fd0a42218f3eae43a6ce26d22544e986139a01e5b34a62db53757ffca81bae1"
388- host = ' https://fapi.asterdex.com'
389- placeOrder = {' url' : ' /fapi/v3/order' , ' method' : ' POST' ,
390- ' params' :{' symbol' : ' SANDUSDT' , ' positionSide' : ' BOTH' , ' type' : ' LIMIT' , ' side' : ' BUY' ,
391- ' timeInForce' : ' GTC' , ' quantity' : " 30" , ' price' : 0.325 ,' reduceOnly' : True }}
392- getOrder = {' url' :' /fapi/v3/order' ,' method' :' GET' ,' params' :{' symbol' :' SANDUSDT' ,' side' :" BUY" ," type" :' LIMIT' ,' orderId' :2194215 }}
393-
394- def call (api ):
395- nonce = math.trunc(time.time() * 1000000 )
396- my_dict = api[' params' ]
397- send(api[' url' ],api[' method' ],sign(my_dict,nonce))
398-
399- def sign (my_dict ,nonce ):
400- my_dict = {key: value for key, value in my_dict.items() if value is not None }
401- my_dict[' recvWindow' ] = 50000
402- my_dict[' timestamp' ] = int (round (time.time()* 1000 ))
403- msg = trim_param(my_dict,nonce)
404- signable_msg = encode_defunct(hexstr = msg)
405- signed_message = Account.sign_message(signable_message = signable_msg, private_key = priKey)
406- my_dict[' nonce' ] = nonce
407- my_dict[' user' ] = user
408- my_dict[' signer' ] = signer
409- my_dict[' signature' ] = ' 0x' + signed_message.signature.hex()
410-
411- print (my_dict[' signature' ])
412- return my_dict
413-
414- def trim_param (my_dict ,nonce ) -> str :
415- _trim_dict(my_dict)
416- json_str = json.dumps(my_dict, sort_keys = True ).replace(' ' , ' ' ).replace(' \' ' ,' \" ' )
417- print (json_str)
418- encoded = encode([' string' , ' address' , ' address' , ' uint256' ], [json_str, user, signer, nonce])
419- print (encoded.hex())
420- keccak_hex = Web3.keccak(encoded).hex()
421- print (keccak_hex)
422- return keccak_hex
423-
424- def _trim_dict (my_dict ) :
425- for key in my_dict:
426- value = my_dict[key]
427- if isinstance (value, list ):
428- new_value = []
429- for item in value:
430- if isinstance (item, dict ):
431- new_value.append(json.dumps(_trim_dict(item)))
432- else :
433- new_value.append(str (item))
434- my_dict[key] = json.dumps(new_value)
435- continue
436- if isinstance (value, dict ):
437- my_dict[key] = json.dumps(_trim_dict(value))
438- continue
439- my_dict[key] = str (value)
440-
441- return my_dict
442-
443- def send (url , method , my_dict ):
444- url = host + url
445- print (url)
446- print (my_dict)
447- if method == ' POST' :
448- headers = {
449- ' Content-Type' : ' application/x-www-form-urlencoded' ,
450- ' User-Agent' : ' PythonApp/1.0'
451- }
452- res = requests.post(url, data = my_dict, headers = headers)
453- print (res.text)
454- if method == ' GET' :
455- res = requests.get(url, params = my_dict)
456- print (res.text)
457- if method == ' DELETE' :
458- res = requests.delete(url, data = my_dict)
459- print (res.text)
259+ print (res.text)
460260
461261if __name__ == ' __main__' :
462- call(placeOrder )
463- # call(getOrder )
262+ send_by_url( )
263+ # send_by_body( )
464264```
465-
466265## ** Public Endpoints Info**
467266
468267### Terminology
0 commit comments