diff --git a/basicswap/__init__.py b/basicswap/__init__.py index 9822e3a..1eb8ad0 100644 --- a/basicswap/__init__.py +++ b/basicswap/__init__.py @@ -1,3 +1,3 @@ name = "basicswap" -__version__ = "0.11.48" +__version__ = "0.11.49" diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py index 73b0ad4..2e4901f 100644 --- a/basicswap/basicswap.py +++ b/basicswap/basicswap.py @@ -6035,6 +6035,8 @@ class BasicSwap(BaseApp): ci_to = self.ci(int(coin_to)) name_from = ci_from.chainparams()['name'] name_to = ci_to.chainparams()['name'] + exchange_name_from = ci_from.getExchangeName('coingecko.com') + exchange_name_to = ci_to.getExchangeName('coingecko.com') ticker_from = ci_from.chainparams()['ticker'] ticker_to = ci_to.chainparams()['ticker'] headers = {'Connection': 'close'} @@ -6044,23 +6046,42 @@ class BasicSwap(BaseApp): if rate_sources.get('coingecko.com', True): try: - url = 'https://api.coingecko.com/api/v3/simple/price?ids={},{}&vs_currencies=usd,btc'.format(name_from, name_to) + url = 'https://api.coingecko.com/api/v3/simple/price?ids={},{}&vs_currencies=usd,btc'.format(exchange_name_from, exchange_name_to) self.log.debug(f'lookupRates: {url}') start = time.time() req = urllib.request.Request(url, headers=headers) js = json.loads(urllib.request.urlopen(req, timeout=10).read()) js['time_taken'] = time.time() - start - rate = float(js[name_from]['usd']) / float(js[name_to]['usd']) + rate = float(js[exchange_name_from]['usd']) / float(js[exchange_name_to]['usd']) js['rate_inferred'] = ci_to.format_amount(rate, conv_int=True, r=1) rv['coingecko'] = js except Exception as e: rv['coingecko_error'] = str(e) + if self.debug: + self.log.error(traceback.format_exc()) + + if exchange_name_from != name_from: + js[name_from] = js[exchange_name_from] + js.pop(exchange_name_from) + if exchange_name_to != name_to: + js[name_to] = js[exchange_name_to] + js.pop(exchange_name_to) if rate_sources.get('bittrex.com', True): bittrex_api_v3 = 'https://api.bittrex.com/v3' try: + exchange_ticker_to = ci_to.getExchangeTicker('bittrex.com') + exchange_ticker_from = ci_from.getExchangeTicker('bittrex.com') + + USDT_coins = (Coins.FIRO,) + # TODO: How to compare USDT pairs with BTC pairs + if ci_from.coin_type() in USDT_coins: + raise ValueError('No BTC pair') + if ci_to.coin_type() in USDT_coins: + raise ValueError('No BTC pair') + if ci_from.coin_type() == Coins.BTC: - pair = f'{ticker_to}-{ticker_from}' + pair = f'{exchange_ticker_to}-{exchange_ticker_from}' url = f'{bittrex_api_v3}/markets/{pair}/ticker' self.log.debug(f'lookupRates: {url}') start = time.time() @@ -6078,7 +6099,7 @@ class BasicSwap(BaseApp): js['to_btc'] = js['lastTradeRate'] rv['bittrex'] = js elif ci_to.coin_type() == Coins.BTC: - pair = f'{ticker_from}-{ticker_to}' + pair = f'{exchange_ticker_from}-{exchange_ticker_to}' url = f'{bittrex_api_v3}/markets/{pair}/ticker' self.log.debug(f'lookupRates: {url}') start = time.time() @@ -6091,7 +6112,7 @@ class BasicSwap(BaseApp): js['to_btc'] = 1.0 rv['bittrex'] = js else: - pair = f'{ticker_from}-BTC' + pair = f'{exchange_ticker_from}-BTC' url = f'{bittrex_api_v3}/markets/{pair}/ticker' self.log.debug(f'lookupRates: {url}') start = time.time() @@ -6100,7 +6121,7 @@ class BasicSwap(BaseApp): js_from['time_taken'] = time.time() - start js_from['pair'] = pair - pair = f'{ticker_to}-BTC' + pair = f'{exchange_ticker_to}-BTC' url = f'{bittrex_api_v3}/markets/{pair}/ticker' self.log.debug(f'lookupRates: {url}') start = time.time() @@ -6124,6 +6145,8 @@ class BasicSwap(BaseApp): } except Exception as e: rv['bittrex_error'] = str(e) + if self.debug: + self.log.error(traceback.format_exc()) if output_array: diff --git a/basicswap/chainparams.py b/basicswap/chainparams.py index f4e6959..101187e 100644 --- a/basicswap/chainparams.py +++ b/basicswap/chainparams.py @@ -374,6 +374,12 @@ class CoinInterface: ticker = 'rt' + ticker return ticker + def getExchangeTicker(self, exchange_name): + return self.ticker() + + def getExchangeName(self, exchange_name): + return chainparams[self.coin_type()]['name'] + def ticker_mainnet(self): ticker = chainparams[self.coin_type()]['ticker'] return ticker diff --git a/basicswap/interface/dash.py b/basicswap/interface/dash.py index 0bed2ec..48d1df7 100644 --- a/basicswap/interface/dash.py +++ b/basicswap/interface/dash.py @@ -39,3 +39,6 @@ class DASHInterface(BTCInterface): def withdrawCoin(self, value, addr_to, subfee): params = [addr_to, value, '', '', subfee] return self.rpc_callback('sendtoaddress', params) + + def getSpendableBalance(self): + return self.make_int(self.rpc_callback('getwalletinfo')['balance']) diff --git a/basicswap/interface/firo.py b/basicswap/interface/firo.py index c5af17d..0738853 100644 --- a/basicswap/interface/firo.py +++ b/basicswap/interface/firo.py @@ -30,6 +30,9 @@ class FIROInterface(BTCInterface): def coin_type(): return Coins.FIRO + def getExchangeName(self, exchange_name): + return 'zcoin' + def initialiseWallet(self, key): # load with -hdseed= parameter pass @@ -171,3 +174,6 @@ class FIROInterface(BTCInterface): def getWalletSeedID(self): return self.rpc_callback('getwalletinfo')['hdmasterkeyid'] + + def getSpendableBalance(self): + return self.make_int(self.rpc_callback('getwalletinfo')['balance']) diff --git a/basicswap/interface/pivx.py b/basicswap/interface/pivx.py index b41e6e5..62d9598 100644 --- a/basicswap/interface/pivx.py +++ b/basicswap/interface/pivx.py @@ -62,3 +62,6 @@ class PIVXInterface(BTCInterface): def withdrawCoin(self, value, addr_to, subfee): params = [addr_to, value, '', '', subfee] return self.rpc_callback('sendtoaddress', params) + + def getSpendableBalance(self): + return self.make_int(self.rpc_callback('getwalletinfo')['balance']) diff --git a/basicswap/js_server.py b/basicswap/js_server.py index 9eb4558..0285241 100644 --- a/basicswap/js_server.py +++ b/basicswap/js_server.py @@ -37,17 +37,24 @@ from .ui.page_offers import postNewOffer from .protocols.xmr_swap_1 import recoverNoScriptTxnWithKey, getChainBSplitKey +def getFormData(post_string, is_json): + if post_string == '': + raise ValueError('No post data') + if is_json: + form_data = json.loads(post_string) + form_data['is_json'] = True + else: + form_data = urllib.parse.parse_qs(post_string) + return form_data + + def js_error(self, error_str): error_str_json = json.dumps({'error': error_str}) return bytes(error_str_json, 'UTF-8') def withdraw_coin(swap_client, coin_type, post_string, is_json): - if is_json: - post_data = json.loads(post_string) - post_data['is_json'] = True - else: - post_data = urllib.parse.parse_qs(post_string) + post_data = getFormData(post_string, is_json) value = get_data_entry(post_data, 'value') address = get_data_entry(post_data, 'address') @@ -99,6 +106,13 @@ def js_wallets(self, url_split, post_string, is_json): return bytes(json.dumps(withdraw_coin(swap_client, coin_type, post_string, is_json)), 'UTF-8') if cmd == 'nextdepositaddr': return bytes(json.dumps(swap_client.cacheNewAddressForCoin(coin_type)), 'UTF-8') + if cmd == 'createutxo': + post_data = getFormData(post_string, is_json) + ci = swap_client.ci(coin_type) + value = ci.make_int(get_data_entry(post_data, 'value')) + txid_hex, new_addr = ci.createUTXO(value) + return bytes(json.dumps({'txid': txid_hex, 'address': new_addr}), 'UTF-8') + raise ValueError('Unknown command') rv = swap_client.getWalletInfo(coin_type) @@ -113,13 +127,7 @@ def js_offers(self, url_split, post_string, is_json, sent=False): offer_id = None if len(url_split) > 3: if url_split[3] == 'new': - if post_string == '': - raise ValueError('No post data') - if is_json: - form_data = json.loads(post_string) - form_data['is_json'] = True - else: - form_data = urllib.parse.parse_qs(post_string) + form_data = getFormData(post_string, is_json) offer_id = postNewOffer(swap_client, form_data) rv = {'offer_id': offer_id.hex()} return bytes(json.dumps(rv), 'UTF-8') @@ -138,11 +146,7 @@ def js_offers(self, url_split, post_string, is_json, sent=False): filters['offer_id'] = offer_id if post_string != '': - if is_json: - post_data = json.loads(post_string) - post_data['is_json'] = True - else: - post_data = urllib.parse.parse_qs(post_string) + post_data = getFormData(post_string, is_json) filters['coin_from'] = setCoinFilter(post_data, 'coin_from') filters['coin_to'] = setCoinFilter(post_data, 'coin_to') @@ -191,13 +195,7 @@ def js_bids(self, url_split, post_string, is_json): swap_client.checkSystemStatus() if len(url_split) > 3: if url_split[3] == 'new': - if post_string == '': - raise ValueError('No post data') - if is_json: - post_data = json.loads(post_string) - post_data['is_json'] = True - else: - post_data = urllib.parse.parse_qs(post_string) + post_data = getFormData(post_string, is_json) offer_id = bytes.fromhex(get_data_entry(post_data, 'offer_id')) assert (len(offer_id) == 28) @@ -246,11 +244,7 @@ def js_bids(self, url_split, post_string, is_json): show_txns = False if post_string != '': - if is_json: - post_data = json.loads(post_string) - post_data['is_json'] = True - else: - post_data = urllib.parse.parse_qs(post_string) + post_data = getFormData(post_string, is_json) if have_data_entry(post_data, 'accept'): swap_client.acceptBid(bid_id) elif have_data_entry(post_data, 'debugind'): @@ -314,13 +308,7 @@ def js_smsgaddresses(self, url_split, post_string, is_json): swap_client = self.server.swap_client swap_client.checkSystemStatus() if len(url_split) > 3: - if post_string == '': - raise ValueError('No post data') - if is_json: - post_data = json.loads(post_string) - post_data['is_json'] = True - else: - post_data = urllib.parse.parse_qs(post_string) + post_data = getFormData(post_string, is_json) if url_split[3] == 'new': addressnote = get_data_entry_or(post_data, 'addressnote', '') new_addr, pubkey = swap_client.newSMSGAddress(addressnote=addressnote) @@ -341,13 +329,7 @@ def js_smsgaddresses(self, url_split, post_string, is_json): def js_rates(self, url_split, post_string, is_json): - if post_string == '': - raise ValueError('No post data') - if is_json: - post_data = json.loads(post_string) - post_data['is_json'] = True - else: - post_data = urllib.parse.parse_qs(post_string) + post_data = getFormData(post_string, is_json) sc = self.server.swap_client coin_from = get_data_entry(post_data, 'coin_from') @@ -365,13 +347,7 @@ def js_rates_list(self, url_split, query_string, is_json): def js_rate(self, url_split, post_string, is_json): - if post_string == '': - raise ValueError('No post data') - if is_json: - post_data = json.loads(post_string) - post_data['is_json'] = True - else: - post_data = urllib.parse.parse_qs(post_string) + post_data = getFormData(post_string, is_json) sc = self.server.swap_client coin_from = getCoinType(get_data_entry(post_data, 'coin_from')) @@ -447,13 +423,7 @@ def js_vacuumdb(self, url_split, post_string, is_json): def js_getcoinseed(self, url_split, post_string, is_json): swap_client = self.server.swap_client swap_client.checkSystemStatus() - if post_string == '': - raise ValueError('No post data') - if is_json: - post_data = json.loads(post_string) - post_data['is_json'] = True - else: - post_data = urllib.parse.parse_qs(post_string) + post_data = getFormData(post_string, is_json) coin = getCoinType(get_data_entry(post_data, 'coin')) if coin in (Coins.PART, Coins.PART_ANON, Coins.PART_BLIND): @@ -471,13 +441,7 @@ def js_setpassword(self, url_split, post_string, is_json): # Only works with currently enabled coins # Will fail if any coin does not unlock on the old password swap_client = self.server.swap_client - if post_string == '': - raise ValueError('No post data') - if is_json: - post_data = json.loads(post_string) - post_data['is_json'] = True - else: - post_data = urllib.parse.parse_qs(post_string) + post_data = getFormData(post_string, is_json) old_password = get_data_entry(post_data, 'oldpassword') new_password = get_data_entry(post_data, 'newpassword') @@ -497,13 +461,7 @@ def js_setpassword(self, url_split, post_string, is_json): def js_unlock(self, url_split, post_string, is_json): swap_client = self.server.swap_client - if post_string == '': - raise ValueError('No post data') - if is_json: - post_data = json.loads(post_string) - post_data['is_json'] = True - else: - post_data = urllib.parse.parse_qs(post_string) + post_data = getFormData(post_string, is_json) password = get_data_entry(post_data, 'password') @@ -520,13 +478,7 @@ def js_unlock(self, url_split, post_string, is_json): def js_lock(self, url_split, post_string, is_json): swap_client = self.server.swap_client - if post_string == '': - raise ValueError('No post data') - if is_json: - post_data = json.loads(post_string) - post_data['is_json'] = True - else: - post_data = urllib.parse.parse_qs(post_string) + post_data = getFormData(post_string, is_json) if have_data_entry(post_data, 'coin'): coin = getCoinType(get_data_entry(post_data, 'coin')) diff --git a/basicswap/templates/bid.html b/basicswap/templates/bid.html index 190630f..d076783 100644 --- a/basicswap/templates/bid.html +++ b/basicswap/templates/bid.html @@ -37,7 +37,7 @@
Bid ID: {{ bid_id }}
-