From 2d4131d4ee7aeba36b9a02611ad9a48b40854a2a Mon Sep 17 00:00:00 2001 From: tecnovert Date: Sun, 29 Nov 2020 01:04:26 +0200 Subject: [PATCH] XMR amounts in http interface. --- basicswap/chainparams.py | 3 ++- basicswap/http_server.py | 38 ++++++++++++++++++++++++----------- basicswap/interface_btc.py | 7 ++++--- basicswap/interface_xmr.py | 5 +++++ basicswap/util.py | 4 +++- tests/basicswap/test_other.py | 14 +++++++++++++ tests/basicswap/test_xmr.py | 19 +++++++++++++++++- 7 files changed, 72 insertions(+), 18 deletions(-) diff --git a/basicswap/chainparams.py b/basicswap/chainparams.py index 9ddd648..e13a12d 100644 --- a/basicswap/chainparams.py +++ b/basicswap/chainparams.py @@ -7,6 +7,7 @@ from enum import IntEnum from .util import ( COIN, + format_amount ) XMR_COIN = 10 ** 12 @@ -193,7 +194,7 @@ chainparams = { class CoinInterface: def format_amount(self, amount_int): - return format_amount(feerate, self.exp()) + return format_amount(amount_int, self.exp()) def coin_name(self): return chainparams[self.coin_type()]['name'].capitalize() diff --git a/basicswap/http_server.py b/basicswap/http_server.py index 4533435..27cb609 100644 --- a/basicswap/http_server.py +++ b/basicswap/http_server.py @@ -17,8 +17,6 @@ from jinja2 import Environment, PackageLoader from . import __version__ from .util import ( - COIN, - format8, make_int, dumpj, ) @@ -157,6 +155,8 @@ def describeBid(swap_client, bid, offer, edit_bid, show_txns): coin_from = Coins(offer.coin_from) coin_to = Coins(offer.coin_to) + ci_from = swap_client.ci(coin_from) + ci_to = swap_client.ci(coin_to) ticker_from = swap_client.getTicker(coin_from) ticker_to = swap_client.getTicker(coin_to) @@ -189,8 +189,8 @@ def describeBid(swap_client, bid, offer, edit_bid, show_txns): state_description = '' data = { - 'amt_from': format8(bid.amount), - 'amt_to': format8((bid.amount * offer.rate) // COIN), + 'amt_from': ci_from.format_amount(bid.amount), + 'amt_to': ci_to.format_amount((bid.amount * offer.rate) // ci_from.COIN()), 'ticker_from': ticker_from, 'ticker_to': ticker_to, 'bid_state': strBidState(bid.state), @@ -374,6 +374,8 @@ class HttpHandler(BaseHTTPRequestHandler): 'error': w['error'] }) continue + + ci = swap_client.ci(k) fee_rate = swap_client.getFeeRateForCoin(k) tx_vsize = swap_client.getContractSpendTxVSize(k) est_fee = (fee_rate * tx_vsize) / 1000 @@ -381,8 +383,8 @@ class HttpHandler(BaseHTTPRequestHandler): 'name': w['name'], 'version': w['version'], 'cid': str(int(k)), - 'fee_rate': format8(fee_rate * COIN), - 'est_fee': format8(est_fee * COIN), + 'fee_rate': ci.format_amount(int(fee_rate * ci.COIN())), + 'est_fee': ci.format_amount(int(est_fee * ci.COIN())), 'balance': w['balance'], 'blocks': w['blocks'], 'synced': w['synced'], @@ -437,6 +439,7 @@ class HttpHandler(BaseHTTPRequestHandler): raise ValueError('Unknown Coin From') try: coin_to = Coins(int(form_data[b'coin_to'][0])) + ci_to = swap_client.ci(coin_to) except Exception: raise ValueError('Unknown Coin To') @@ -444,7 +447,7 @@ class HttpHandler(BaseHTTPRequestHandler): value_to = inputAmount(form_data[b'amt_to'][0].decode('utf-8')) min_bid = int(value_from) - rate = int((value_to / value_from) * COIN) + rate = int((value_to / value_from) * ci_to.COIN()) autoaccept = True if b'autoaccept' in form_data else False lock_seconds = int(form_data[b'lockhrs'][0]) * 60 * 60 # TODO: More accurate rate @@ -516,8 +519,8 @@ class HttpHandler(BaseHTTPRequestHandler): 'coin_from': ci_from.coin_name(), 'coin_to': ci_to.coin_name(), 'amt_from': ci_from.format_amount(offer.amount_from), - 'amt_to': ci_to.format_amount((offer.amount_from * offer.rate) // COIN), - 'rate': format8(offer.rate), + 'amt_to': ci_to.format_amount((offer.amount_from * offer.rate) // ci_from.COIN()), + 'rate': ci_to.format_amount(offer.rate), 'lock_type': getLockName(offer.lock_type), 'lock_value': offer.lock_value, 'addr_from': offer.addr_from, @@ -540,7 +543,7 @@ class HttpHandler(BaseHTTPRequestHandler): sent_bid_id=sent_bid_id, messages=messages, data=data, - bids=[(b[1].hex(), format8(b[3]), strBidState(b[4]), strTxState(b[6]), strTxState(b[7])) for b in bids], + bids=[(b[1].hex(), ci_from.format_amount(b[3]), strBidState(b[4]), strTxState(b[6]), strTxState(b[7])) for b in bids], addrs=None if show_bid_form is None else swap_client.listSmsgAddresses('bid'), form_id=os.urandom(8).hex(), ), 'UTF-8') @@ -583,6 +586,18 @@ class HttpHandler(BaseHTTPRequestHandler): offers = swap_client.listOffers(sent, filters) + formatted_offers = [] + for o in offers: + ci_from = swap_client.ci(Coins(o.coin_from)) + ci_to = swap_client.ci(Coins(o.coin_to)) + formatted_offers.append(( + time.strftime('%Y-%m-%d %H:%M', time.localtime(o.created_at)), + o.offer_id.hex(), + ci_from.coin_name(), ci_to.coin_name(), + ci_from.format_amount(o.amount_from), + ci_to.format_amount((o.amount_from * o.rate) // ci_from.COIN()), + ci_to.format_amount(o.rate))) + template = env.get_template('offers.html') return bytes(template.render( title=self.server.title, @@ -591,8 +606,7 @@ class HttpHandler(BaseHTTPRequestHandler): coins=listAvailableCoins(swap_client), messages=messages, filters=filters, - offers=[(time.strftime('%Y-%m-%d %H:%M', time.localtime(o.created_at)), - o.offer_id.hex(), getCoinName(Coins(o.coin_from)), getCoinName(Coins(o.coin_to)), format8(o.amount_from), format8((o.amount_from * o.rate) // COIN), format8(o.rate)) for o in offers], + offers=formatted_offers, form_id=os.urandom(8).hex(), ), 'UTF-8') diff --git a/basicswap/interface_btc.py b/basicswap/interface_btc.py index 6a85781..ddbaa79 100644 --- a/basicswap/interface_btc.py +++ b/basicswap/interface_btc.py @@ -81,6 +81,10 @@ class BTCInterface(CoinInterface): def coin_type(): return Coins.BTC + @staticmethod + def COIN(): + return COIN + @staticmethod def exp(): return 8 @@ -118,9 +122,6 @@ class BTCInterface(CoinInterface): self._network = network self.blocks_confirmed = coin_settings['blocks_confirmed'] - def coin_name(self): - return chainparams[self.coin_type()]['name'] - def testDaemonRPC(self): self.rpc_callback('getwalletinfo', []) diff --git a/basicswap/interface_xmr.py b/basicswap/interface_xmr.py index d0fc442..3ab2c3d 100644 --- a/basicswap/interface_xmr.py +++ b/basicswap/interface_xmr.py @@ -37,6 +37,10 @@ class XMRInterface(CoinInterface): def coin_type(): return Coins.XMR + @staticmethod + def COIN(): + return XMR_COIN + @staticmethod def exp(): return 12 @@ -279,6 +283,7 @@ class XMRInterface(CoinInterface): rv = self.rpc_wallet_cb('incoming_transfers', params) if 'transfers' in rv: for transfer in rv['transfers']: + print('[rm] transfer', transfer) if transfer['tx_hash'] == txid \ and (current_height is None or current_height - transfer['block_height'] > self.blocks_confirmed): return {'txid': transfer['tx_hash'], 'amount': transfer['amount'], 'height': transfer['block_height']} diff --git a/basicswap/util.py b/basicswap/util.py index 154397f..283e80b 100644 --- a/basicswap/util.py +++ b/basicswap/util.py @@ -276,6 +276,8 @@ def validate_amount(amount, scale=8): def format_amount(i, display_scale, scale=None): + if not isinstance(i, int): + raise ValueError('Amount must be an integer.') # Raise error instead of converting as amounts should always be integers if scale is None: scale = display_scale ep = 10 ** scale @@ -284,7 +286,7 @@ def format_amount(i, display_scale, scale=None): remainder = n % ep if display_scale != scale: remainder %= (10 ** display_scale) - rv = '{}.{:0>{prec}}'.format(quotient, remainder, prec=display_scale) + rv = '{}.{:0>{scale}}'.format(quotient, remainder, scale=display_scale) if i < 0: rv = '-' + rv return rv diff --git a/tests/basicswap/test_other.py b/tests/basicswap/test_other.py index 1ba6095..52fd565 100644 --- a/tests/basicswap/test_other.py +++ b/tests/basicswap/test_other.py @@ -200,6 +200,20 @@ class Test(unittest.TestCase): amount_from = 100 * (10 ** scale_from) rate = 0.1 * (10 ** scale_to) + amount_to = int((amount_from * rate) // (10 ** scale_from)) + assert('100.00000000' == format_amount(amount_from, scale_from)) + assert('10.000000000000' == format_amount(amount_to, scale_to)) + + scale_from = 12 + scale_to = 8 + amount_from = 1 * (10 ** scale_from) + rate = 12 * (10 ** scale_to) + + amount_to = int((amount_from * rate) // (10 ** scale_from)) + assert('1.000000000000' == format_amount(amount_from, scale_from)) + assert('12.00000000' == format_amount(amount_to, scale_to)) + + if __name__ == '__main__': unittest.main() diff --git a/tests/basicswap/test_xmr.py b/tests/basicswap/test_xmr.py index 9a1df3c..ba53e41 100644 --- a/tests/basicswap/test_xmr.py +++ b/tests/basicswap/test_xmr.py @@ -81,6 +81,8 @@ XMR_BASE_ZMQ_PORT = 22792 XMR_BASE_WALLET_RPC_PORT = 23792 PREFIX_SECRET_KEY_REGTEST = 0x2e + +delay_event = threading.Event() stop_test = False @@ -263,8 +265,9 @@ def make_rpc_func(node_id, base_rpc_port=BASE_RPC_PORT): def signal_handler(sig, frame): global stop_test - print('signal {} detected.'.format(sig)) + logging.info('signal {} detected.'.format(sig)) stop_test = True + delay_event.set() def waitForXMRNode(rpc_offset, max_tries=7): @@ -531,6 +534,11 @@ class Test(unittest.TestCase): return raise ValueError('wait_for_bid timed out.') + def delay_for(self, delay_for=60): + logging.info('Delaying for {} seconds.'.format(delay_for)) + delay_event.clear() + delay_event.wait(delay_for) + def test_01_part_xmr(self): logging.info('---------- Test PART to XMR') swap_clients = self.swap_clients @@ -557,6 +565,12 @@ class Test(unittest.TestCase): self.wait_for_bid(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180) self.wait_for_bid(swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True) + js_0_end = json.loads(urlopen('http://localhost:1800/json/wallets').read()) + end_xmr = float(js_0_end['6']['balance']) + float(js_0_end['6']['unconfirmed']) + assert(end_xmr > 10.9 and end_xmr < 11.0) + + self.delay_for(600) + def test_02_leader_recover_a_lock_tx(self): logging.info('---------- Test PART to XMR leader recovers coin a lock tx') swap_clients = self.swap_clients @@ -658,6 +672,9 @@ class Test(unittest.TestCase): self.wait_for_bid(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180) self.wait_for_bid(swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True) + def pass_06_delay(self): + self.delay_for(60) + if __name__ == '__main__': unittest.main()