Skip to content

Commit 2b89c69

Browse files
committed
Update futures-v3 general-info documentation
1 parent 9ad46b3 commit 2b89c69

2 files changed

Lines changed: 160 additions & 553 deletions

File tree

docs/futures-v3/general-info.en.md

Lines changed: 80 additions & 281 deletions
Original file line numberDiff line numberDiff line change
@@ -154,315 +154,114 @@ print(nonce)
154154
Instant now = Instant.now();
155155
long 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&timestamp=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&timestamp=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

461261
if __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

Comments
 (0)