-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdex_manager.py
210 lines (182 loc) · 6.8 KB
/
dex_manager.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
from multiprocessing import Lock
import requests
from erdpy.accounts import Account
from erdpy.proxy import ElrondProxy
from erdpy.transactions import Transaction
from logger import Logger
from utils import *
class DexManager:
def __init__(self, pem_file, gateaway, logger: Logger):
self.mutex = Lock()
self.account = Account(pem_file=pem_file)
self.proxy = ElrondProxy(gateaway)
self.logger = logger
self.logger.info(f"gateway: {gateaway}")
self.pairs = {}
self.tokenIdentifiers = {}
self.fetch_pairs()
self.wrapperContract = self.getWrapperContract()
def getShardAccount(self, address=None):
if address is None:
address = self.account.address.bech32()
response = requests.get(accInfoURL + address)
errorMessage = ''
if response.status_code != 200:
errorMessage = "fail to fetch account infos"
jsonResponse = response.json()
if 'shard' not in jsonResponse:
errorMessage = "no shard id info in account infos"
if errorMessage != '':
self.logger.error(errorMessage)
raise Exception(errorMessage)
return jsonResponse['shard']
def fetch_pairs(self):
with self.mutex:
pairs = query(pairsQuery, None)['pairs']
for pair in pairs:
pairAddress = pair['address']
fee = pair['totalFeePercent']
ftn = pair['firstToken']['name']
fti = pair['firstToken']['identifier']
ftp = float(pair['firstTokenPrice'])
ftpUSD = float(pair['firstTokenPriceUSD'])
stn = pair['secondToken']['name']
sti = pair['secondToken']['identifier']
stp = float(pair['secondTokenPrice'])
stpUSD = float(pair['secondTokenPriceUSD'])
fts = int(pair['info']['reserves0'])
sts = int(pair['info']['reserves1'])
self.pairs[pairAddress] = {
fti: {
'name': ftn,
'supply': fts,
'price': ftp, # in secondToken
'priceUSD': ftpUSD
},
sti: {
'name': stn,
'supply': sts,
'price': stp, # in firstToken
'priceUSD': stpUSD
},
'fee': fee
}
if ftn not in self.tokenIdentifiers:
self.tokenIdentifiers[ftn] = fti
if stn not in self.tokenIdentifiers:
self.tokenIdentifiers[stn] = sti
def getWrapperContract(self):
contracts = query(queryWrappingInfo, None)['wrappingInfo']
for contract in contracts:
if contract['shard'] == self.getShardAccount():
return contract['address']
return None
def getTokenIdentifier(self, tokenName):
tokenID = None
with self.mutex:
if tokenName in self.tokenIdentifiers:
tokenID = self.tokenIdentifiers[tokenName]
return tokenID
def getPairAddress(self, tokenIN, tokenOUT):
for pairAddress in self.pairs:
if tokenIN in self.pairs[pairAddress] and tokenOUT in self.pairs[pairAddress]:
return pairAddress
return None
def generateTx(self, data, gasLimit, value=0, receiver=None):
sender = self.account.address.bech32()
if receiver is None:
receiver = self.account.address.bech32()
nonce = self.proxy.get_account_nonce(self.account.address)
tx = Transaction()
tx.sender = sender
tx.nonce = nonce
tx.version = self.account
tx.value = str(value)
tx.receiver = receiver
tx.chainID = chainID
tx.gasPrice = 1000000000
tx.gasLimit = gasLimit
tx.version = 1
tx.data = data
return tx
def sentTransaction(self, receiver, data, value, gasLimit):
self.account.sync_nonce(self.proxy)
tx = self.generateTx(
receiver=receiver,
data=data,
value=value,
gasLimit=gasLimit
)
tx.sign(self.account)
print(f"trying to send transaction hash: {tx.hash}")
try:
tx = tx.send_wait_result(self.proxy, 700)
if tx['status'] == 'success':
self.logger.debug(f"transaction sent successfully: {tx['hash']}")
elif tx['status'] == 'invalid':
err = tx['receipt']['data']
self.logger.debug(f"failed with reason: {err}")
return tx['hash'], None
except Exception as e:
self.logger.error(e)
return None, e
def wrapEgld(self, value):
value = value
data = 'wrapEgld'
return self.sentTransaction(
receiver=self.wrapperContract,
data=data,
value=value,
gasLimit=4000000
)
def unWrapEgld(self, value):
data = '@'.join([
'ESDTTransfer',
string2hex(wrapEgldTI),
int2hex(value),
'756e7772617045676c64' # unwrapEgld
])
return self.sentTransaction(
receiver=self.wrapperContract,
data=data,
value=0,
gasLimit=4000000
)
def swap(self, tokenIN, tokenOUT, valueIN, valueOUT=None, slippage=0.01):
pairAddress = self.getPairAddress(tokenIN, tokenOUT)
if valueOUT is None:
valueOUT = int(query(queryGetAmountOut, {
"amount": str(valueIN),
'tokenInID': tokenIN,
'pairAddress': pairAddress
})['getAmountOut'])
valueOUT -= int(valueOUT * slippage)
data = '@'.join([
'ESDTTransfer',
string2hex(tokenIN),
int2hex(valueIN),
'73776170546f6b656e734669786564496e707574', # swapTokensFixedInput
string2hex(tokenOUT),
int2hex(valueOUT)
])
self.logger.info(f"amount to pay: {valueIN} {tokenIN} for {valueOUT} {tokenOUT}")
txHash, err = self.sentTransaction(
receiver=pairAddress,
data=data,
value=0,
gasLimit=20000000
)
if err is not None:
self.logger.debug('swap failed')
return txHash, err
if __name__ == '__main__':
logger = Logger(logging_service='DexManager')
logger.info("Starting")
dexManager = DexManager(
pem_file="dexswap.pem",
gateaway=gateaway,
logger=logger,
)
#print(dexManager.unWrapEgld(5 * 10 ** 18))
print(dexManager.wrapEgld(int(1.6 * 10 ** 18)))
#print(dexManager.swap(wrapEgldTI, rideTI, 10 * 10 ** 18))