-
Notifications
You must be signed in to change notification settings - Fork 1
/
swap_functions.py
299 lines (241 loc) · 12.4 KB
/
swap_functions.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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# This is where all the swap-service related functions go.
# We may need different functions for getting the rates, and performing the swap.
import json
import time
import monero_usd_price
import requests
from datetime import datetime, timedelta
from fp.fp import FreeProxy
import wallet_functions as wallet
import config as cfg
# GLOBAL VARIABLES #####################################################################################################
# Sideshift
sideshift_api_endpoint = 'https://sideshift.ai/api/v2/'
sideshift_affiliate_id = 'ql4wc8Y44' # Required, but I set the commission rate to 0, so that I don't make anything.
# Trocador
trocador_api_endpoint = 'https://trocador.app/en/api/'
trocador_api_key = 'j3uhif80j37OpnZoEwD29w1HqR84A0' # if my account gets used too much or banned, get your own api key
trocador_ref = 'z1kEXtwvF'
# Localmonero
# Kraken
# IBKR
# ChangeNow
changenow_api_endpoint = 'https://api.changenow.io/v2/'
changenow_api_key = '58aff9c5d295ff13c885e8fcd3373402c3ab8e5752964d9c3e7ff991da831a2f' # if my account gets used too much or banned, get your own api key
# Supported Coins & Networks
supported_network_names = {
"Ethereum": ["ethereum", "ERC20", "ERC-20", "eth", ],
"Polygon": ["polygon", "MATIC", "matic"],
#"Solana": ["solana", "SOL"],
#"Avalance C-Chain": ["Avalance C-Chain", "avax", "AVAXC", "Avax-c"],
"Arbitrum": ["arbitrum", "Arbitrum"],
#"Optimism": ["optimism", "op"],
#"Binance Smart Chain": ["Binance Smart Chain", "bsc", "BEP20", "BEP-20"],
#"Tron": ["tron", "TRC20", "TRC-20", "trx"],
#"Algorand": ["algorand", "algo"]
}
supported_networks = list(supported_network_names.keys())
supported_coins = ['USDC', 'USDT', 'DAI'] # Add any coin tickers the monero business wallet should support here
# GET COIN FUNCTIONS ###################################################################################################
def get_networks_for_coin_from_sideshift(coin_to_check, proxy=None):
api_link = f'{sideshift_api_endpoint}coins'
response = requests.get(api_link, proxies={"http": proxy, "https": proxy})
response = response.json()
networks = []
for item in response:
# if item['coin'] in coins_supported:
if item['coin'].lower() == coin_to_check.lower():
#print(item)
for i in item['networks']:
networks.append(i)
print(f'Sideshift Networks for {coin_to_check}: {networks}')
return networks
def get_networks_for_coin_from_trocador(coin_to_check, proxy=None):
api_link = f'{trocador_api_endpoint}coins/?api_key={trocador_api_key}&ref={trocador_ref}'
response = requests.get(api_link, proxies={"http": proxy, "https": proxy})
response = response.json()
networks = []
for item in response:
# if item['coin'] in coins_supported:
if item['ticker'].lower() == coin_to_check.lower():
#print(item)
networks.append(item['network'])
print(f'Trocador Networks for {coin_to_check}: {networks}')
return networks
def get_networks_for_coin_from_changenow(coin_to_check, proxy=None):
api_link = f'{changenow_api_endpoint}exchange/currencies?active=&flow=standard&buy=&sell='
headers = {
'x-changenow-api-key': changenow_api_key
}
response = requests.get(api_link, headers=headers, proxies={"http": proxy, "https": proxy})
#print(response)
response = response.json()
#print(response)
networks = []
for item in response:
if item['ticker'].lower() == coin_to_check.lower():
#print(item)
networks.append(item['network'])
print(f'Changenow Networks for {coin_to_check}: {networks}')
return networks
# SWAP FUNCTIONS #######################################################################################################
def with_sideshift(shift_to_coin, to_wallet, on_network, amount_to_convert, proxy=None):
# Documentation: https://sideshift.ai/api/
converting_from = 'xmr'
# Confirm that coin and network are still supported (and get min/max swap amounts)
pass
# Use supported_network_names to convert on_network to the correct "word" for this platform.
# (makes all items in both lists lowercase, and then uses "&" to find the intersection)
on_network = set(n.lower() for n in supported_network_names[on_network]) & set(nn.lower() for nn in get_networks_for_coin_from_sideshift(shift_to_coin))
on_network = on_network.pop()
print(on_network)
# Create variable-rate swap
response = create_shift_with_sideshift(converting_from=converting_from, shift_to_coin=shift_to_coin, to_wallet=to_wallet, on_network=on_network)
print(response)
# Example
"""{'id': '95b520d9ccd01b23c6c5', 'createdAt': '2023-07-27T06:16:24.524Z', 'depositCoin': 'XMR', 'settleCoin': 'USDC',
'depositNetwork': 'monero', 'settleNetwork': 'polygon', 'depositAddress': '4Bh68jCUZGHbVu45zCVvtcMYesHuduwgajoQcdYRjUQcY6MNa8qd67vTfSNWdtrc33dDECzbPCJeQ8HbiopdeM7Ej3qLTv2mWCwMgFHsyQ',
'settleAddress': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D', 'depositMin': '0.018337408314',
'depositMax': '30.56234719', 'type': 'variable', 'expiresAt': '2023-08-03T06:16:24.524Z', 'status': 'waiting',
'averageShiftSeconds': '28.21795'}"""
shift_id = response['id']
created_at = response['createdAt'] #
deposit_coin = response['depositCoin'] #
settle_coin = response['settleCoin'] #
settle_network = response['settleNetwork'] #
send_to_wallet = response['depositAddress']
settle_address = response['settleAddress'] #
send_min = response['depositMin']
send_max = response['depositMax']
swap_type = response['status'] #
expires_at = response['expiresAt']
status = response['status']
average_time_to_complete = response['averageShiftSeconds']
print('Shift ID:', shift_id,
'\nSend To Wallet:', send_to_wallet,
'\nMinumum:', send_min,
'\nMaximum:', send_max,
'\nExpires At:', expires_at,
'\nStatus:', status,
'\nAverage Time To Complete:', average_time_to_complete)
# Confirm that everything in the swap matches what we want.
is_at_least_ten_minutes_before = datetime.utcnow() + timedelta(minutes=10) <= datetime.strptime(expires_at, "%Y-%m-%dT%H:%M:%S.%fZ")
if (
deposit_coin.lower() == converting_from.lower() and
settle_coin.lower() == shift_to_coin.lower() and
settle_network.lower() == on_network.lower() and
settle_address == to_wallet and
is_at_least_ten_minutes_before and
float(average_time_to_complete) <= float(60 * 60 * 24) and # 24hrs
send_min <= amount_to_convert
):
# If we made it here, proceed with the swap
if amount_to_convert >= send_max:
print('This is too much to convert!')
smaller_amount = amount_to_convert
attempt_count = 0
while smaller_amount >= send_max and attempt_count < 20: # arbitrary 20 attempts at cutting it in half.
print('...trying with less')
smaller_amount /= 2 # Halve the smaller_amount
if smaller_amount < send_max:
print(f'Converting! This may take up to: {average_time_to_complete} to complete.')
wallet.send_monero(destination_address=send_to_wallet, amount=smaller_amount)
break # Exit the loop since we found an acceptable amount
attempt_count += 1 # Increment the counter
swap_info = {'sent_xmr_amount': smaller_amount, 'to_wallet': send_to_wallet, 'swap_id': shift_id, 'service': 'sideshift'}
return swap_info
else: # We can convert this amount because it is above min and below max.
print(f'Converting! This may take up to: {average_time_to_complete} to complete.')
wallet.send_monero(destination_address=send_to_wallet, amount=amount_to_convert)
swap_info = {'sent_xmr_amount': amount_to_convert, 'to_wallet': send_to_wallet, 'swap_id': shift_id, 'service': 'sideshift'}
return swap_info
# There is a problem. DO NOT SWAP!
else:
print('DO NOT SWAP')
return dict()
def with_trocador():
# Documentation: https://trocador.app/en/docs/
# (Would be cool to add tor and i2p in the future at some point)
pass
def with_localmonero():
# Documentation: https://agoradesk.com/api-docs/v1#section/Introduction
pass
def with_kraken():
# Documentation: https://docs.kraken.com/rest/
pass
def with_ibkr():
# Documentation: https://www.interactivebrokers.com/api/doc.html
# Not sure if we really want to add this one or not, but it was suggested (I've never heard of them).
pass
def with_changenow():
# Documentation: https://gitlab.com/changenow-s-library-catalogue/changenow-api-python
pass
def at_best_rate():
# A function that should be able to determine the swap service that gives the best rate, and uses it.
# Users should be able to set certain swap services to avoid (if desired). By default, all are used.
# (unless complex setup is required like Kraken)
pass
# SUPPLEMENTAL FUNCTIONS ###############################################################################################
def check_if_ip_address_works_with_sideshift(proxy=None):
sideshift_check_url = "https://sideshift.ai/api/v2/permissions"
response = requests.get(url=sideshift_check_url, proxies={"http": proxy, "https": proxy})
if response.status_code == 200:
data = response.json()
working = data.get("createShift")
return bool(working)
else:
#print("Request failed with status code:", response.status_code)
return False
def find_working_proxy_for_sideshift():
result = False
while not result:
try:
print('No working proxy yet. Getting a random one.')
proxy = FreeProxy(rand=True, timeout=1,).get()
print('Checking: ' + proxy)
result = check_if_ip_address_works_with_sideshift(proxy=proxy)
except:
pass
print(f'\nWe bypassed SideShifts location restrictions with proxy {proxy}')
return proxy
def create_shift_with_sideshift(converting_from, shift_to_coin, to_wallet, on_network):
while True:
try:
# check if we are blocked on the current IP
if not check_if_ip_address_works_with_sideshift():
# we are blocked, the user probably has a VPN on, so use a proxy
print('looking for a proxy that will work')
proxy = find_working_proxy_for_sideshift()
#proxy = 'http://20.44.206.138:80' #'http://52.221.130.124:80'
time.sleep(5)
else:
print('Not using a proxy')
proxy = None
api_link = f'{sideshift_api_endpoint}shifts/variable'
headers = {
'Content-Type': 'application/json'
}
data = {
"settleAddress": to_wallet,
# "refundAddress": refund_address, # leaving this out to stay anonymous
"depositCoin": converting_from,
"settleCoin": shift_to_coin,
"settleNetwork": on_network,
"affiliateId": sideshift_affiliate_id,
"commissionRate": 0.0 # set the commissionRate to 0
}
print('sending request/waiting for response...')
response = requests.post(api_link, headers=headers, data=json.dumps(data), proxies={"http": proxy, "https": proxy})
if response.status_code == 201: # it was successful
print('Created Shift!')
return response.json()
else:
print(response)
except Exception as e:
print(e)
time.sleep(2)
# TESTING ##############################################################################################################
#get_networks_for_coin_from_changenow('DAI')
#get_networks_for_coin_from_sideshift('DAI')
#get_networks_for_coin_from_trocador('DAI')
#with_sideshift(shift_to_coin='USDC', to_wallet='0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D', on_network='Polygon', amount_to_convert=111)