mirror of
https://github.com/basicswap/basicswap.git
synced 2025-01-05 18:29:26 +00:00
XMR amounts in http interface.
This commit is contained in:
parent
327394e81b
commit
2d4131d4ee
7 changed files with 72 additions and 18 deletions
|
@ -7,6 +7,7 @@
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from .util import (
|
from .util import (
|
||||||
COIN,
|
COIN,
|
||||||
|
format_amount
|
||||||
)
|
)
|
||||||
|
|
||||||
XMR_COIN = 10 ** 12
|
XMR_COIN = 10 ** 12
|
||||||
|
@ -193,7 +194,7 @@ chainparams = {
|
||||||
|
|
||||||
class CoinInterface:
|
class CoinInterface:
|
||||||
def format_amount(self, amount_int):
|
def format_amount(self, amount_int):
|
||||||
return format_amount(feerate, self.exp())
|
return format_amount(amount_int, self.exp())
|
||||||
|
|
||||||
def coin_name(self):
|
def coin_name(self):
|
||||||
return chainparams[self.coin_type()]['name'].capitalize()
|
return chainparams[self.coin_type()]['name'].capitalize()
|
||||||
|
|
|
@ -17,8 +17,6 @@ from jinja2 import Environment, PackageLoader
|
||||||
|
|
||||||
from . import __version__
|
from . import __version__
|
||||||
from .util import (
|
from .util import (
|
||||||
COIN,
|
|
||||||
format8,
|
|
||||||
make_int,
|
make_int,
|
||||||
dumpj,
|
dumpj,
|
||||||
)
|
)
|
||||||
|
@ -157,6 +155,8 @@ def describeBid(swap_client, bid, offer, edit_bid, show_txns):
|
||||||
|
|
||||||
coin_from = Coins(offer.coin_from)
|
coin_from = Coins(offer.coin_from)
|
||||||
coin_to = Coins(offer.coin_to)
|
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_from = swap_client.getTicker(coin_from)
|
||||||
ticker_to = swap_client.getTicker(coin_to)
|
ticker_to = swap_client.getTicker(coin_to)
|
||||||
|
|
||||||
|
@ -189,8 +189,8 @@ def describeBid(swap_client, bid, offer, edit_bid, show_txns):
|
||||||
state_description = ''
|
state_description = ''
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'amt_from': format8(bid.amount),
|
'amt_from': ci_from.format_amount(bid.amount),
|
||||||
'amt_to': format8((bid.amount * offer.rate) // COIN),
|
'amt_to': ci_to.format_amount((bid.amount * offer.rate) // ci_from.COIN()),
|
||||||
'ticker_from': ticker_from,
|
'ticker_from': ticker_from,
|
||||||
'ticker_to': ticker_to,
|
'ticker_to': ticker_to,
|
||||||
'bid_state': strBidState(bid.state),
|
'bid_state': strBidState(bid.state),
|
||||||
|
@ -374,6 +374,8 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
'error': w['error']
|
'error': w['error']
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
ci = swap_client.ci(k)
|
||||||
fee_rate = swap_client.getFeeRateForCoin(k)
|
fee_rate = swap_client.getFeeRateForCoin(k)
|
||||||
tx_vsize = swap_client.getContractSpendTxVSize(k)
|
tx_vsize = swap_client.getContractSpendTxVSize(k)
|
||||||
est_fee = (fee_rate * tx_vsize) / 1000
|
est_fee = (fee_rate * tx_vsize) / 1000
|
||||||
|
@ -381,8 +383,8 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
'name': w['name'],
|
'name': w['name'],
|
||||||
'version': w['version'],
|
'version': w['version'],
|
||||||
'cid': str(int(k)),
|
'cid': str(int(k)),
|
||||||
'fee_rate': format8(fee_rate * COIN),
|
'fee_rate': ci.format_amount(int(fee_rate * ci.COIN())),
|
||||||
'est_fee': format8(est_fee * COIN),
|
'est_fee': ci.format_amount(int(est_fee * ci.COIN())),
|
||||||
'balance': w['balance'],
|
'balance': w['balance'],
|
||||||
'blocks': w['blocks'],
|
'blocks': w['blocks'],
|
||||||
'synced': w['synced'],
|
'synced': w['synced'],
|
||||||
|
@ -437,6 +439,7 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
raise ValueError('Unknown Coin From')
|
raise ValueError('Unknown Coin From')
|
||||||
try:
|
try:
|
||||||
coin_to = Coins(int(form_data[b'coin_to'][0]))
|
coin_to = Coins(int(form_data[b'coin_to'][0]))
|
||||||
|
ci_to = swap_client.ci(coin_to)
|
||||||
except Exception:
|
except Exception:
|
||||||
raise ValueError('Unknown Coin To')
|
raise ValueError('Unknown Coin To')
|
||||||
|
|
||||||
|
@ -444,7 +447,7 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
value_to = inputAmount(form_data[b'amt_to'][0].decode('utf-8'))
|
value_to = inputAmount(form_data[b'amt_to'][0].decode('utf-8'))
|
||||||
|
|
||||||
min_bid = int(value_from)
|
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
|
autoaccept = True if b'autoaccept' in form_data else False
|
||||||
lock_seconds = int(form_data[b'lockhrs'][0]) * 60 * 60
|
lock_seconds = int(form_data[b'lockhrs'][0]) * 60 * 60
|
||||||
# TODO: More accurate rate
|
# TODO: More accurate rate
|
||||||
|
@ -516,8 +519,8 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
'coin_from': ci_from.coin_name(),
|
'coin_from': ci_from.coin_name(),
|
||||||
'coin_to': ci_to.coin_name(),
|
'coin_to': ci_to.coin_name(),
|
||||||
'amt_from': ci_from.format_amount(offer.amount_from),
|
'amt_from': ci_from.format_amount(offer.amount_from),
|
||||||
'amt_to': ci_to.format_amount((offer.amount_from * offer.rate) // COIN),
|
'amt_to': ci_to.format_amount((offer.amount_from * offer.rate) // ci_from.COIN()),
|
||||||
'rate': format8(offer.rate),
|
'rate': ci_to.format_amount(offer.rate),
|
||||||
'lock_type': getLockName(offer.lock_type),
|
'lock_type': getLockName(offer.lock_type),
|
||||||
'lock_value': offer.lock_value,
|
'lock_value': offer.lock_value,
|
||||||
'addr_from': offer.addr_from,
|
'addr_from': offer.addr_from,
|
||||||
|
@ -540,7 +543,7 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
sent_bid_id=sent_bid_id,
|
sent_bid_id=sent_bid_id,
|
||||||
messages=messages,
|
messages=messages,
|
||||||
data=data,
|
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'),
|
addrs=None if show_bid_form is None else swap_client.listSmsgAddresses('bid'),
|
||||||
form_id=os.urandom(8).hex(),
|
form_id=os.urandom(8).hex(),
|
||||||
), 'UTF-8')
|
), 'UTF-8')
|
||||||
|
@ -583,6 +586,18 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
|
|
||||||
offers = swap_client.listOffers(sent, filters)
|
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')
|
template = env.get_template('offers.html')
|
||||||
return bytes(template.render(
|
return bytes(template.render(
|
||||||
title=self.server.title,
|
title=self.server.title,
|
||||||
|
@ -591,8 +606,7 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
coins=listAvailableCoins(swap_client),
|
coins=listAvailableCoins(swap_client),
|
||||||
messages=messages,
|
messages=messages,
|
||||||
filters=filters,
|
filters=filters,
|
||||||
offers=[(time.strftime('%Y-%m-%d %H:%M', time.localtime(o.created_at)),
|
offers=formatted_offers,
|
||||||
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],
|
|
||||||
form_id=os.urandom(8).hex(),
|
form_id=os.urandom(8).hex(),
|
||||||
), 'UTF-8')
|
), 'UTF-8')
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,10 @@ class BTCInterface(CoinInterface):
|
||||||
def coin_type():
|
def coin_type():
|
||||||
return Coins.BTC
|
return Coins.BTC
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def COIN():
|
||||||
|
return COIN
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def exp():
|
def exp():
|
||||||
return 8
|
return 8
|
||||||
|
@ -118,9 +122,6 @@ class BTCInterface(CoinInterface):
|
||||||
self._network = network
|
self._network = network
|
||||||
self.blocks_confirmed = coin_settings['blocks_confirmed']
|
self.blocks_confirmed = coin_settings['blocks_confirmed']
|
||||||
|
|
||||||
def coin_name(self):
|
|
||||||
return chainparams[self.coin_type()]['name']
|
|
||||||
|
|
||||||
def testDaemonRPC(self):
|
def testDaemonRPC(self):
|
||||||
self.rpc_callback('getwalletinfo', [])
|
self.rpc_callback('getwalletinfo', [])
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,10 @@ class XMRInterface(CoinInterface):
|
||||||
def coin_type():
|
def coin_type():
|
||||||
return Coins.XMR
|
return Coins.XMR
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def COIN():
|
||||||
|
return XMR_COIN
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def exp():
|
def exp():
|
||||||
return 12
|
return 12
|
||||||
|
@ -279,6 +283,7 @@ class XMRInterface(CoinInterface):
|
||||||
rv = self.rpc_wallet_cb('incoming_transfers', params)
|
rv = self.rpc_wallet_cb('incoming_transfers', params)
|
||||||
if 'transfers' in rv:
|
if 'transfers' in rv:
|
||||||
for transfer in rv['transfers']:
|
for transfer in rv['transfers']:
|
||||||
|
print('[rm] transfer', transfer)
|
||||||
if transfer['tx_hash'] == txid \
|
if transfer['tx_hash'] == txid \
|
||||||
and (current_height is None or current_height - transfer['block_height'] > self.blocks_confirmed):
|
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']}
|
return {'txid': transfer['tx_hash'], 'amount': transfer['amount'], 'height': transfer['block_height']}
|
||||||
|
|
|
@ -276,6 +276,8 @@ def validate_amount(amount, scale=8):
|
||||||
|
|
||||||
|
|
||||||
def format_amount(i, display_scale, scale=None):
|
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:
|
if scale is None:
|
||||||
scale = display_scale
|
scale = display_scale
|
||||||
ep = 10 ** scale
|
ep = 10 ** scale
|
||||||
|
@ -284,7 +286,7 @@ def format_amount(i, display_scale, scale=None):
|
||||||
remainder = n % ep
|
remainder = n % ep
|
||||||
if display_scale != scale:
|
if display_scale != scale:
|
||||||
remainder %= (10 ** display_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:
|
if i < 0:
|
||||||
rv = '-' + rv
|
rv = '-' + rv
|
||||||
return rv
|
return rv
|
||||||
|
|
|
@ -200,6 +200,20 @@ class Test(unittest.TestCase):
|
||||||
amount_from = 100 * (10 ** scale_from)
|
amount_from = 100 * (10 ** scale_from)
|
||||||
rate = 0.1 * (10 ** scale_to)
|
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__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -81,6 +81,8 @@ XMR_BASE_ZMQ_PORT = 22792
|
||||||
XMR_BASE_WALLET_RPC_PORT = 23792
|
XMR_BASE_WALLET_RPC_PORT = 23792
|
||||||
|
|
||||||
PREFIX_SECRET_KEY_REGTEST = 0x2e
|
PREFIX_SECRET_KEY_REGTEST = 0x2e
|
||||||
|
|
||||||
|
delay_event = threading.Event()
|
||||||
stop_test = False
|
stop_test = False
|
||||||
|
|
||||||
|
|
||||||
|
@ -263,8 +265,9 @@ def make_rpc_func(node_id, base_rpc_port=BASE_RPC_PORT):
|
||||||
|
|
||||||
def signal_handler(sig, frame):
|
def signal_handler(sig, frame):
|
||||||
global stop_test
|
global stop_test
|
||||||
print('signal {} detected.'.format(sig))
|
logging.info('signal {} detected.'.format(sig))
|
||||||
stop_test = True
|
stop_test = True
|
||||||
|
delay_event.set()
|
||||||
|
|
||||||
|
|
||||||
def waitForXMRNode(rpc_offset, max_tries=7):
|
def waitForXMRNode(rpc_offset, max_tries=7):
|
||||||
|
@ -531,6 +534,11 @@ class Test(unittest.TestCase):
|
||||||
return
|
return
|
||||||
raise ValueError('wait_for_bid timed out.')
|
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):
|
def test_01_part_xmr(self):
|
||||||
logging.info('---------- Test PART to XMR')
|
logging.info('---------- Test PART to XMR')
|
||||||
swap_clients = self.swap_clients
|
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[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180)
|
||||||
self.wait_for_bid(swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True)
|
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):
|
def test_02_leader_recover_a_lock_tx(self):
|
||||||
logging.info('---------- Test PART to XMR leader recovers coin a lock tx')
|
logging.info('---------- Test PART to XMR leader recovers coin a lock tx')
|
||||||
swap_clients = self.swap_clients
|
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[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180)
|
||||||
self.wait_for_bid(swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True)
|
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__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
Loading…
Reference in a new issue