Browse Source

Handle lost noscript lock transaction.

pull/22/head
tecnovert 2 years ago
parent
commit
2a9e423eaa
No known key found for this signature in database GPG Key ID: 8ED6D8750C4E3F93
  1. 2
      basicswap/__init__.py
  2. 77
      basicswap/basicswap.py
  3. 5
      basicswap/basicswap_util.py
  4. 2
      basicswap/interface/btc.py
  5. 17
      basicswap/interface/dash.py
  6. 46
      basicswap/interface/xmr.py
  7. 12
      basicswap/js_server.py
  8. 18
      basicswap/protocols/xmr_swap_1.py
  9. 22
      basicswap/templates/bid.html
  10. 20
      basicswap/templates/bid_xmr.html
  11. 11
      basicswap/ui/page_offers.py
  12. 8
      basicswap/ui/util.py
  13. 18
      doc/release-notes.md
  14. 20
      tests/basicswap/test_xmr.py

2
basicswap/__init__.py

@ -1,3 +1,3 @@
name = "basicswap" name = "basicswap"
__version__ = "0.11.53" __version__ = "0.11.54"

77
basicswap/basicswap.py

@ -3065,6 +3065,33 @@ class BasicSwap(BaseApp):
return sum_unspent return sum_unspent
return None return None
def findTxB(self, ci_to, xmr_swap, bid, session) -> bool:
bid_changed = False
# Have to use findTxB instead of relying on the first seen height to detect chain reorgs
found_tx = ci_to.findTxB(xmr_swap.vkbv, xmr_swap.pkbs, bid.amount_to, ci_to.blocks_confirmed, bid.chain_b_height_start, bid.was_sent)
if isinstance(found_tx, int) and found_tx == -1:
if self.countBidEvents(bid, EventLogTypes.LOCK_TX_B_INVALID, session) < 1:
self.logBidEvent(bid.bid_id, EventLogTypes.LOCK_TX_B_INVALID, 'Detected invalid lock tx B', session)
bid_changed = True
elif found_tx is not None:
if bid.xmr_b_lock_tx is None or not bid.xmr_b_lock_tx.chain_height:
self.logBidEvent(bid.bid_id, EventLogTypes.LOCK_TX_B_SEEN, '', session)
if bid.xmr_b_lock_tx is None:
self.log.debug('Found {} lock tx in chain'.format(ci_to.coin_name()))
xmr_swap.b_lock_tx_id = bytes.fromhex(found_tx['txid'])
bid.xmr_b_lock_tx = SwapTx(
bid_id=bid.bid_id,
tx_type=TxTypes.XMR_SWAP_B_LOCK,
txid=xmr_swap.b_lock_tx_id,
chain_height=found_tx['height'],
)
bid_changed = True
else:
bid.xmr_b_lock_tx.chain_height = found_tx['height']
bid_changed = True
return bid_changed
def checkXmrBidState(self, bid_id, bid, offer): def checkXmrBidState(self, bid_id, bid, offer):
rv = False rv = False
@ -3176,6 +3203,13 @@ class BasicSwap(BaseApp):
rv = True # Remove from swaps_in_progress rv = True # Remove from swaps_in_progress
elif state == BidStates.XMR_SWAP_FAILED_SWIPED: elif state == BidStates.XMR_SWAP_FAILED_SWIPED:
rv = True # Remove from swaps_in_progress rv = True # Remove from swaps_in_progress
elif state == BidStates.XMR_SWAP_FAILED:
if bid.was_sent and bid.xmr_b_lock_tx:
if self.countQueuedActions(session, bid_id, ActionTypes.RECOVER_XMR_SWAP_LOCK_TX_B) < 1:
delay = random.randrange(self.min_delay_event, self.max_delay_event)
self.log.info('Recovering xmr swap chain B lock tx for bid %s in %d seconds', bid_id.hex(), delay)
self.createActionInSession(delay, ActionTypes.RECOVER_XMR_SWAP_LOCK_TX_B, bid_id, session)
session.commit()
elif state == BidStates.XMR_SWAP_MSG_SCRIPT_LOCK_SPEND_TX: elif state == BidStates.XMR_SWAP_MSG_SCRIPT_LOCK_SPEND_TX:
if bid.xmr_a_lock_tx is None: if bid.xmr_a_lock_tx is None:
return rv return rv
@ -3217,33 +3251,7 @@ class BasicSwap(BaseApp):
session.commit() session.commit()
elif state == BidStates.XMR_SWAP_SCRIPT_COIN_LOCKED: elif state == BidStates.XMR_SWAP_SCRIPT_COIN_LOCKED:
if bid.was_sent and bid.xmr_b_lock_tx is None: bid_changed = self.findTxB(ci_to, xmr_swap, bid, session)
return rv
bid_changed = False
# Have to use findTxB instead of relying on the first seen height to detect chain reorgs
found_tx = ci_to.findTxB(xmr_swap.vkbv, xmr_swap.pkbs, bid.amount_to, ci_to.blocks_confirmed, bid.chain_b_height_start, bid.was_sent)
if isinstance(found_tx, int) and found_tx == -1:
if self.countBidEvents(bid, EventLogTypes.LOCK_TX_B_INVALID, session) < 1:
self.logBidEvent(bid.bid_id, EventLogTypes.LOCK_TX_B_INVALID, 'Detected invalid lock tx B', session)
bid_changed = True
elif found_tx is not None:
if bid.xmr_b_lock_tx is None or not bid.xmr_b_lock_tx.chain_height:
self.logBidEvent(bid.bid_id, EventLogTypes.LOCK_TX_B_SEEN, '', session)
if bid.xmr_b_lock_tx is None:
self.log.debug('Found {} lock tx in chain'.format(ci_to.coin_name()))
xmr_swap.b_lock_tx_id = bytes.fromhex(found_tx['txid'])
bid.xmr_b_lock_tx = SwapTx(
bid_id=bid_id,
tx_type=TxTypes.XMR_SWAP_B_LOCK,
txid=xmr_swap.b_lock_tx_id,
chain_height=found_tx['height'],
)
bid_changed = True
else:
bid.xmr_b_lock_tx.chain_height = found_tx['height']
bid_changed = True
if bid.xmr_b_lock_tx and bid.xmr_b_lock_tx.chain_height is not None and bid.xmr_b_lock_tx.chain_height > 0: if bid.xmr_b_lock_tx and bid.xmr_b_lock_tx.chain_height is not None and bid.xmr_b_lock_tx.chain_height > 0:
chain_height = ci_to.getChainHeight() chain_height = ci_to.getChainHeight()
@ -4715,6 +4723,14 @@ class BasicSwap(BaseApp):
ci_from = self.ci(Coins(offer.coin_from)) ci_from = self.ci(Coins(offer.coin_from))
ci_to = self.ci(Coins(offer.coin_to)) ci_to = self.ci(Coins(offer.coin_to))
if self.findTxB(ci_to, xmr_swap, bid, session) is True:
self.saveBidInSession(bid_id, bid, session, xmr_swap, save_in_progress=offer)
return
if bid.xmr_b_lock_tx:
self.log.warning('Coin B lock tx {} exists for xmr bid {}'.format(bid.xmr_b_lock_tx.b_lock_tx_id, bid_id.hex()))
return
if bid.debug_ind == DebugTypes.BID_STOP_AFTER_COIN_A_LOCK: if bid.debug_ind == DebugTypes.BID_STOP_AFTER_COIN_A_LOCK:
self.log.debug('XMR bid %s: Stalling bid for testing: %d.', bid_id.hex(), bid.debug_ind) self.log.debug('XMR bid %s: Stalling bid for testing: %d.', bid_id.hex(), bid.debug_ind)
bid.setState(BidStates.BID_STALLED_FOR_TEST) bid.setState(BidStates.BID_STALLED_FOR_TEST)
@ -4723,7 +4739,7 @@ class BasicSwap(BaseApp):
return return
unlock_time = 0 unlock_time = 0
if bid.debug_ind == DebugTypes.CREATE_INVALID_COIN_B_LOCK: if bid.debug_ind in (DebugTypes.CREATE_INVALID_COIN_B_LOCK, DebugTypes.B_LOCK_TX_MISSED_SEND):
bid.amount_to -= int(bid.amount_to * 0.1) bid.amount_to -= int(bid.amount_to * 0.1)
self.log.debug('XMR bid %s: Debug %d - Reducing lock b txn amount by 10%% to %s.', bid_id.hex(), bid.debug_ind, ci_to.format_amount(bid.amount_to)) self.log.debug('XMR bid %s: Debug %d - Reducing lock b txn amount by 10%% to %s.', bid_id.hex(), bid.debug_ind, ci_to.format_amount(bid.amount_to))
self.logBidEvent(bid.bid_id, EventLogTypes.DEBUG_TWEAK_APPLIED, 'ind {}'.format(bid.debug_ind), session) self.logBidEvent(bid.bid_id, EventLogTypes.DEBUG_TWEAK_APPLIED, 'ind {}'.format(bid.debug_ind), session)
@ -4731,8 +4747,13 @@ class BasicSwap(BaseApp):
unlock_time = 10000 unlock_time = 10000
self.log.debug('XMR bid %s: Debug %d - Sending locked XMR.', bid_id.hex(), bid.debug_ind) self.log.debug('XMR bid %s: Debug %d - Sending locked XMR.', bid_id.hex(), bid.debug_ind)
self.logBidEvent(bid.bid_id, EventLogTypes.DEBUG_TWEAK_APPLIED, 'ind {}'.format(bid.debug_ind), session) self.logBidEvent(bid.bid_id, EventLogTypes.DEBUG_TWEAK_APPLIED, 'ind {}'.format(bid.debug_ind), session)
try: try:
b_lock_tx_id = ci_to.publishBLockTx(xmr_swap.pkbv, xmr_swap.pkbs, bid.amount_to, xmr_offer.b_fee_rate, unlock_time=unlock_time) b_lock_tx_id = ci_to.publishBLockTx(xmr_swap.pkbv, xmr_swap.pkbs, bid.amount_to, xmr_offer.b_fee_rate, unlock_time=unlock_time)
if bid.debug_ind == DebugTypes.B_LOCK_TX_MISSED_SEND:
self.log.debug('XMR bid %s: Debug %d - Losing xmr lock tx %s.', bid_id.hex(), bid.debug_ind, b_lock_tx_id.hex())
self.logBidEvent(bid.bid_id, EventLogTypes.DEBUG_TWEAK_APPLIED, 'ind {}'.format(bid.debug_ind), session)
raise TemporaryError('Fail for debug event')
except Exception as ex: except Exception as ex:
if self.debug: if self.debug:
self.log.error(traceback.format_exc()) self.log.error(traceback.format_exc())

5
basicswap/basicswap_util.py

@ -189,6 +189,7 @@ class DebugTypes(IntEnum):
DONT_SPEND_ITX = auto() DONT_SPEND_ITX = auto()
SKIP_LOCK_TX_REFUND = auto() SKIP_LOCK_TX_REFUND = auto()
SEND_LOCKED_XMR = auto() SEND_LOCKED_XMR = auto()
B_LOCK_TX_MISSED_SEND = auto()
def strOfferState(state): def strOfferState(state):
@ -322,8 +323,6 @@ def getLockName(lock_type):
def describeEventEntry(event_type, event_msg): def describeEventEntry(event_type, event_msg):
if event_type == EventLogTypes.FAILED_TX_B_LOCK_PUBLISH:
return 'Failed to publish lock tx B'
if event_type == EventLogTypes.FAILED_TX_B_LOCK_PUBLISH: if event_type == EventLogTypes.FAILED_TX_B_LOCK_PUBLISH:
return 'Failed to publish lock tx B' return 'Failed to publish lock tx B'
if event_type == EventLogTypes.LOCK_TX_A_PUBLISHED: if event_type == EventLogTypes.LOCK_TX_A_PUBLISHED:
@ -456,4 +455,6 @@ def isActiveBidState(state):
return True return True
if state == BidStates.XMR_SWAP_MSG_SCRIPT_LOCK_SPEND_TX: if state == BidStates.XMR_SWAP_MSG_SCRIPT_LOCK_SPEND_TX:
return True return True
if state == BidStates.XMR_SWAP_FAILED:
return True
return False return False

2
basicswap/interface/btc.py

@ -1186,7 +1186,7 @@ class BTCInterface(CoinInterface):
return True if address_hash == pubkey_hash else False return True if address_hash == pubkey_hash else False
def showLockTransfers(self, Kbv, Kbs): def showLockTransfers(self, kbv, Kbs, restore_height):
raise ValueError('Unimplemented') raise ValueError('Unimplemented')
def getLockTxSwapOutputValue(self, bid, xmr_swap): def getLockTxSwapOutputValue(self, bid, xmr_swap):

17
basicswap/interface/dash.py

@ -20,12 +20,18 @@ class DASHInterface(BTCInterface):
def coin_type(): def coin_type():
return Coins.DASH return Coins.DASH
def __init__(self, coin_settings, network, swap_client=None):
super().__init__(coin_settings, network, swap_client)
self._wallet_passphrase = ''
def seedToMnemonic(self, key): def seedToMnemonic(self, key):
return Mnemonic('english').to_mnemonic(key) return Mnemonic('english').to_mnemonic(key)
def initialiseWallet(self, key): def initialiseWallet(self, key):
words = self.seedToMnemonic(key) words = self.seedToMnemonic(key)
self.rpc_callback('upgradetohd', [words, ])
mnemonic_passphrase = ''
self.rpc_callback('upgradetohd', [words, mnemonic_passphrase, self._wallet_passphrase])
def decodeAddress(self, address): def decodeAddress(self, address):
return decodeAddress(address)[1:] return decodeAddress(address)[1:]
@ -70,3 +76,12 @@ class DASHInterface(BTCInterface):
return {'txid': txid_hex, 'amount': 0, 'height': block_height} return {'txid': txid_hex, 'amount': 0, 'height': block_height}
return None return None
def unlockWallet(self, password: str):
super().unlockWallet(password)
# Store password for initialiseWallet
self._wallet_passphrase = password
def lockWallet(self):
super().lockWallet()
self._wallet_passphrase = ''

46
basicswap/interface/xmr.py

@ -5,7 +5,6 @@
# Distributed under the MIT software license, see the accompanying # Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php. # file LICENSE or http://www.opensource.org/licenses/mit-license.php.
import os
import json import json
import logging import logging
@ -100,8 +99,7 @@ class XMRInterface(CoinInterface):
try: try:
# Can't reopen the same wallet in windows, !is_keys_file_locked() # Can't reopen the same wallet in windows, !is_keys_file_locked()
if os.name == 'nt': self.rpc_wallet_cb('close_wallet')
self.rpc_wallet_cb('close_wallet')
except Exception: except Exception:
pass pass
self.rpc_wallet_cb('open_wallet', params) self.rpc_wallet_cb('open_wallet', params)
@ -263,6 +261,7 @@ class XMRInterface(CoinInterface):
def publishBLockTx(self, Kbv, Kbs, output_amount, feerate, delay_for: int = 10, unlock_time: int = 0) -> bytes: def publishBLockTx(self, Kbv, Kbs, output_amount, feerate, delay_for: int = 10, unlock_time: int = 0) -> bytes:
with self._mx_wallet: with self._mx_wallet:
self.openWallet(self._wallet_filename) self.openWallet(self._wallet_filename)
self.rpc_wallet_cb('refresh')
shared_addr = xmr_util.encode_address(Kbv, Kbs) shared_addr = xmr_util.encode_address(Kbv, Kbs)
@ -276,8 +275,8 @@ class XMRInterface(CoinInterface):
if self._sc.debug: if self._sc.debug:
i = 0 i = 0
while not self._sc.delay_event.is_set(): while not self._sc.delay_event.is_set():
params = {'out': True, 'pending': True, 'failed': True, 'pool': True, } gt_params = {'out': True, 'pending': True, 'failed': True, 'pool': True, }
rv = self.rpc_wallet_cb('get_transfers', params) rv = self.rpc_wallet_cb('get_transfers', gt_params)
self._log.debug('get_transfers {}'.format(dumpj(rv))) self._log.debug('get_transfers {}'.format(dumpj(rv)))
if 'pending' not in rv: if 'pending' not in rv:
break break
@ -292,11 +291,6 @@ class XMRInterface(CoinInterface):
Kbv = self.getPubkey(kbv) Kbv = self.getPubkey(kbv)
address_b58 = xmr_util.encode_address(Kbv, Kbs) address_b58 = xmr_util.encode_address(Kbv, Kbs)
try:
self.rpc_wallet_cb('close_wallet')
except Exception as e:
self._log.warning('close_wallet failed %s', str(e))
kbv_le = kbv[::-1] kbv_le = kbv[::-1]
params = { params = {
'restore_height': restore_height, 'restore_height': restore_height,
@ -328,10 +322,14 @@ class XMRInterface(CoinInterface):
rv = None rv = None
if 'transfers' in transfers: if 'transfers' in transfers:
for transfer in transfers['transfers']: for transfer in transfers['transfers']:
# unlocked <- wallet->is_transfer_unlocked() checks unlock_time and CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE
if not transfer['unlocked']: if not transfer['unlocked']:
self._log.warning('Coin b lock txn is locked: {}'.format(transfer['tx_hash'])) full_tx = self.rpc_wallet_cb('get_transfer_by_txid', {'txid': transfer['tx_hash']})
rv = -1 unlock_time = full_tx['transfer']['unlock_time']
continue if unlock_time != 0:
self._log.warning('Coin b lock txn is locked: {}, unlock_time {}'.format(transfer['tx_hash'], unlock_time))
rv = -1
continue
if transfer['amount'] == cb_swap_value: if transfer['amount'] == cb_swap_value:
return {'txid': transfer['tx_hash'], 'amount': transfer['amount'], 'height': 0 if 'block_height' not in transfer else transfer['block_height']} return {'txid': transfer['tx_hash'], 'amount': transfer['amount'], 'height': 0 if 'block_height' not in transfer else transfer['block_height']}
else: else:
@ -367,11 +365,6 @@ class XMRInterface(CoinInterface):
Kbs = self.getPubkey(kbs) Kbs = self.getPubkey(kbs)
address_b58 = xmr_util.encode_address(Kbv, Kbs) address_b58 = xmr_util.encode_address(Kbv, Kbs)
try:
self.rpc_wallet_cb('close_wallet')
except Exception as e:
self._log.warning('close_wallet failed %s', str(e))
wallet_filename = address_b58 + '_spend' wallet_filename = address_b58 + '_spend'
params = { params = {
@ -446,16 +439,29 @@ class XMRInterface(CoinInterface):
rv = self.rpc_wallet_cb('transfer', params) rv = self.rpc_wallet_cb('transfer', params)
return rv['tx_hash'] return rv['tx_hash']
def showLockTransfers(self, Kbv, Kbs): def showLockTransfers(self, kbv, Kbs, restore_height):
with self._mx_wallet: with self._mx_wallet:
try: try:
Kbv = self.getPubkey(kbv)
address_b58 = xmr_util.encode_address(Kbv, Kbs) address_b58 = xmr_util.encode_address(Kbv, Kbs)
wallet_file = address_b58 + '_spend' wallet_file = address_b58 + '_spend'
try: try:
self.openWallet(wallet_file) self.openWallet(wallet_file)
except Exception: except Exception:
wallet_file = address_b58 wallet_file = address_b58
self.openWallet(wallet_file) try:
self.openWallet(wallet_file)
except Exception:
self._log.info(f'showLockTransfers trying to create wallet for address {address_b58}.')
kbv_le = kbv[::-1]
params = {
'restore_height': restore_height,
'filename': address_b58,
'address': address_b58,
'viewkey': b2h(kbv_le),
}
self.createWallet(params)
self.openWallet(address_b58)
self.rpc_wallet_cb('refresh') self.rpc_wallet_cb('refresh')

12
basicswap/js_server.py

@ -168,11 +168,11 @@ def js_offers(self, url_split, post_string, is_json, sent=False):
filters['limit'] = int(get_data_entry(post_data, 'limit')) filters['limit'] = int(get_data_entry(post_data, 'limit'))
assert (filters['limit'] > 0 and filters['limit'] <= PAGE_LIMIT), 'Invalid limit' assert (filters['limit'] > 0 and filters['limit'] <= PAGE_LIMIT), 'Invalid limit'
offers = self.server.swap_client.listOffers(sent, filters) offers = swap_client.listOffers(sent, filters)
rv = [] rv = []
for o in offers: for o in offers:
ci_from = self.server.swap_client.ci(o.coin_from) ci_from = swap_client.ci(o.coin_from)
ci_to = self.server.swap_client.ci(o.coin_to) ci_to = swap_client.ci(o.coin_to)
rv.append({ rv.append({
'addr_from': o.addr_from, 'addr_from': o.addr_from,
'addr_to': o.addr_to, 'addr_to': o.addr_to,
@ -494,6 +494,10 @@ def js_lock(self, url_split, post_string, is_json):
return bytes(json.dumps({'success': True}), 'UTF-8') return bytes(json.dumps({'success': True}), 'UTF-8')
def js_404(self, url_split, post_string, is_json):
return bytes(json.dumps({'Error': 'path unknown'}), 'UTF-8')
def js_help(self, url_split, post_string, is_json): def js_help(self, url_split, post_string, is_json):
# TODO: Add details and examples # TODO: Add details and examples
commands = [] commands = []
@ -528,5 +532,5 @@ pages = {
def js_url_to_function(url_split): def js_url_to_function(url_split):
if len(url_split) > 2: if len(url_split) > 2:
return pages.get(url_split[2], js_index) return pages.get(url_split[2], js_404)
return js_index return js_index

18
basicswap/protocols/xmr_swap_1.py

@ -91,6 +91,24 @@ def getChainBSplitKey(swap_client, bid, xmr_swap, offer):
return ci_to.encodeKey(swap_client.getPathKey(offer.coin_from, offer.coin_to, bid.created_at, xmr_swap.contract_count, key_type, True if offer.coin_to == Coins.XMR else False)) return ci_to.encodeKey(swap_client.getPathKey(offer.coin_from, offer.coin_to, bid.created_at, xmr_swap.contract_count, key_type, True if offer.coin_to == Coins.XMR else False))
def getChainBRemoteSplitKey(swap_client, bid, xmr_swap, offer):
ci_from = swap_client.ci(offer.coin_from)
ci_to = swap_client.ci(offer.coin_to)
if bid.was_sent:
if xmr_swap.a_lock_refund_spend_tx:
af_lock_refund_spend_tx_sig = ci_from.extractFollowerSig(xmr_swap.a_lock_refund_spend_tx)
kbsl = ci_from.recoverEncKey(xmr_swap.af_lock_refund_spend_tx_esig, af_lock_refund_spend_tx_sig, xmr_swap.pkasl)
return ci_to.encodeKey(kbsl)
else:
if xmr_swap.a_lock_spend_tx:
al_lock_spend_tx_sig = ci_from.extractLeaderSig(xmr_swap.a_lock_spend_tx)
kbsf = ci_from.recoverEncKey(xmr_swap.al_lock_spend_tx_esig, al_lock_spend_tx_sig, xmr_swap.pkasf)
return ci_to.encodeKey(kbsf)
return None
class XmrSwapInterface(ProtocolInterface): class XmrSwapInterface(ProtocolInterface):
swap_type = SwapTypes.XMR_SWAP swap_type = SwapTypes.XMR_SWAP

22
basicswap/templates/bid.html

@ -83,7 +83,7 @@
<td class="py-4 px-6 bold">Swap</td> <td class="py-4 px-6 bold">Swap</td>
<td> <td>
<div class="content flex py-2"> <div class="content flex py-2">
<span class="bold">{{ data.amt_to }} {{ data.ticker_to }}</span> <span class="bold">{{ data.amt_to }} {{ data.ticker_to }}</span>
<svg aria-hidden="true " class="w-5 h-5 ml-3 mr-3" fill="currentColor " viewBox="0 0 20 20 " xmlns="http://www.w3.org/2000/svg "> <svg aria-hidden="true " class="w-5 h-5 ml-3 mr-3" fill="currentColor " viewBox="0 0 20 20 " xmlns="http://www.w3.org/2000/svg ">
<path fill-rule="evenodd " d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z " clip-rule="evenodd "></path></svg> <path fill-rule="evenodd " d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z " clip-rule="evenodd "></path></svg>
<span class="bold">{{ data.amt_from }} {{ data.ticker_from }}</span> <span class="bold">{{ data.amt_from }} {{ data.ticker_from }}</span>
@ -95,7 +95,7 @@
<td class="py-4 px-6 bold">Swap</td> <td class="py-4 px-6 bold">Swap</td>
<td> <td>
<div class="content flex py-2"> <div class="content flex py-2">
<span class="bold">{{ data.amt_from }} {{ data.ticker_from }}</span> <span class="bold">{{ data.amt_from }} {{ data.ticker_from }}</span>
<svg aria-hidden="true " class="w-5 h-5 ml-3 mr-3" fill="currentColor " viewBox="0 0 20 20 " xmlns="http://www.w3.org/2000/svg "> <svg aria-hidden="true " class="w-5 h-5 ml-3 mr-3" fill="currentColor " viewBox="0 0 20 20 " xmlns="http://www.w3.org/2000/svg ">
<path fill-rule="evenodd " d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z " clip-rule="evenodd "></path></svg> <path fill-rule="evenodd " d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z " clip-rule="evenodd "></path></svg>
<span class="bold">{{ data.amt_to }} {{ data.ticker_to }}</span> <span class="bold">{{ data.amt_to }} {{ data.ticker_to }}</span>
@ -264,7 +264,7 @@
<div>{{ s[0] | formatts }}</div> <div>{{ s[0] | formatts }}</div>
</div> </div>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
</div> </div>
@ -306,7 +306,7 @@
<form method="post"> <form method="post">
<div class="p-6 pt-10 bg-white bg-opacity-60 rounded-b-md"> <div class="p-6 pt-10 bg-white bg-opacity-60 rounded-b-md">
<div class="w-full md:w-0/12"> <div class="w-full md:w-0/12">
<div class="flex flex-wrap justify-end -m-1.5"> <div class="flex flex-wrap justify-end -m-1.5">
{% if edit_bid %} {% if edit_bid %}
<table class="mt-1"> <table class="mt-1">
<tr> <tr>
@ -319,11 +319,11 @@
<select class="appearance-none bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" name="new_state"> <select class="appearance-none bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" name="new_state">
{% for s in data.bid_states %} {% for s in data.bid_states %}
<option value="{{ s[0] }}" {% if data.bid_state_ind==s[0] %} selected{% endif %}>{{ s[1] }}</option> <option value="{{ s[0] }}" {% if data.bid_state_ind==s[0] %} selected{% endif %}>{{ s[1] }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
</td> </td>
</tr> </tr>
{% if data.debug_ui == true %} {% if data.debug_ui == true %}
<tr> <tr>
<td class="py-6 pr-2 bold">Debug Option:</td> <td class="py-6 pr-2 bold">Debug Option:</td>
@ -331,7 +331,7 @@
<div class="relative"> <div class="relative">
<svg class="absolute right-4 top-1/2 transform -translate-y-1/2" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg class="absolute right-4 top-1/2 transform -translate-y-1/2" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.3333 6.1133C11.2084 5.98913 11.0395 5.91943 10.8633 5.91943C10.6872 5.91943 10.5182 5.98913 10.3933 6.1133L8.00001 8.47329L5.64001 6.1133C5.5151 5.98913 5.34613 5.91943 5.17001 5.91943C4.99388 5.91943 4.82491 5.98913 4.70001 6.1133C4.63752 6.17527 4.58792 6.249 4.55408 6.33024C4.52023 6.41148 4.50281 6.49862 4.50281 6.58663C4.50281 6.67464 4.52023 6.76177 4.55408 6.84301C4.58792 6.92425 4.63752 6.99799 4.70001 7.05996L7.52667 9.88663C7.58865 9.94911 7.66238 9.99871 7.74362 10.0326C7.82486 10.0664 7.912 10.0838 8.00001 10.0838C8.08801 10.0838 8.17515 10.0664 8.25639 10.0326C8.33763 9.99871 8.41136 9.94911 8.47334 9.88663L11.3333 7.05996C11.3958 6.99799 11.4454 6.92425 11.4793 6.84301C11.5131 6.76177 11.5305 6.67464 11.5305 6.58663C11.5305 6.49862 11.5131 6.41148 11.4793 6.33024C11.4454 6.249 11.3958 6.17527 11.3333 6.1133Z" fill="#8896AB"></path> <path d="M11.3333 6.1133C11.2084 5.98913 11.0395 5.91943 10.8633 5.91943C10.6872 5.91943 10.5182 5.98913 10.3933 6.1133L8.00001 8.47329L5.64001 6.1133C5.5151 5.98913 5.34613 5.91943 5.17001 5.91943C4.99388 5.91943 4.82491 5.98913 4.70001 6.1133C4.63752 6.17527 4.58792 6.249 4.55408 6.33024C4.52023 6.41148 4.50281 6.49862 4.50281 6.58663C4.50281 6.67464 4.52023 6.76177 4.55408 6.84301C4.58792 6.92425 4.63752 6.99799 4.70001 7.05996L7.52667 9.88663C7.58865 9.94911 7.66238 9.99871 7.74362 10.0326C7.82486 10.0664 7.912 10.0838 8.00001 10.0838C8.08801 10.0838 8.17515 10.0664 8.25639 10.0326C8.33763 9.99871 8.41136 9.94911 8.47334 9.88663L11.3333 7.05996C11.3958 6.99799 11.4454 6.92425 11.4793 6.84301C11.5131 6.76177 11.5305 6.67464 11.5305 6.58663C11.5305 6.49862 11.5131 6.41148 11.4793 6.33024C11.4454 6.249 11.3958 6.17527 11.3333 6.1133Z" fill="#8896AB"></path>
</svg> </svg>
<select class="appearance-none bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" name="debugind"> <select class="appearance-none bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" name="debugind">
<option{% if data.debug_ind=="-1" %} selected{% endif %} value="-1">None</option> <option{% if data.debug_ind=="-1" %} selected{% endif %} value="-1">None</option>
{% for a in data.debug_options %} {% for a in data.debug_options %}
@ -349,7 +349,7 @@
</div> </div>
<div class="w-full md:w-auto p-1.5"> <div class="w-full md:w-auto p-1.5">
<button name="edit_bid_submit" value="Submit" type="submit" class="flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-coolGray-500 hover:text-coolGray-600 border border-coolGray-200 hover:border-coolGray-300 bg-white rounded-md shadow-button focus:ring-0 focus:outline-none"> <button name="edit_bid_submit" value="Submit" type="submit" class="flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-coolGray-500 hover:text-coolGray-600 border border-coolGray-200 hover:border-coolGray-300 bg-white rounded-md shadow-button focus:ring-0 focus:outline-none">
<svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="round" ><line x1="2" y1="23" x2="22" y2="23" stroke="#556987"></line> <line data-cap="butt" x1="13" y1="5" x2="17" y2="9"></line> <polygon points="8 18 3 19 4 14 16 2 20 6 8 18"></polygon></g></svg> Submit Edit Bid </button> <svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="round" ><line x1="2" y1="23" x2="22" y2="23" stroke="#556987"></line> <line data-cap="butt" x1="13" y1="5" x2="17" y2="9"></line> <polygon points="8 18 3 19 4 14 16 2 20 6 8 18"></polygon></g></svg> Submit Edit </button>
</div> </div>
{% else %} {% else %}
{% if data.show_bidder_seq_diagram %} {% if data.show_bidder_seq_diagram %}
@ -393,14 +393,14 @@
{% endif %} {% endif %}
<div class="w-full md:w-auto p-1.5"> <div class="w-full md:w-auto p-1.5">
<button name="edit_bid" type="submit" value="Edit Bid" class="flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-coolGray-500 hover:text-coolGray-600 border border-coolGray-200 hover:border-coolGray-300 bg-white rounded-md shadow-button focus:ring-0 focus:outline-none"> <button name="edit_bid" type="submit" value="Edit Bid" class="flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-coolGray-500 hover:text-coolGray-600 border border-coolGray-200 hover:border-coolGray-300 bg-white rounded-md shadow-button focus:ring-0 focus:outline-none">
<svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="round" ><line x1="2" y1="23" x2="22" y2="23" stroke="#556987"></line> <line data-cap="butt" x1="13" y1="5" x2="17" y2="9"></line> <polygon points="8 18 3 19 4 14 16 2 20 6 8 18"></polygon></g></svg> Edit bit </button> <svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="round" ><line x1="2" y1="23" x2="22" y2="23" stroke="#556987"></line> <line data-cap="butt" x1="13" y1="5" x2="17" y2="9"></line> <polygon points="8 18 3 19 4 14 16 2 20 6 8 18"></polygon></g></svg> Edit bid </button>
</div> </div>
{% endif %} {% endif %}
{% if data.was_received == 'True' %} {% if data.was_received == 'True' %}
<div class="w-full md:w-auto p-1.5"> <div class="w-full md:w-auto p-1.5">
<button name="accept_bid" value="Accept Bid" type="submit" onclick='return confirmPopup("Accept");' class="flex flex-wrap justify-center w-full px-4 py-2.5 bg-blue-500 hover:bg-blue-600 font-medium text-sm text-white border border-blue-500 rounded-md shadow-button focus:ring-0 focus:outline-none"> <button name="accept_bid" value="Accept Bid" type="submit" onclick='return confirmPopup("Accept");' class="flex flex-wrap justify-center w-full px-4 py-2.5 bg-blue-500 hover:bg-blue-600 font-medium text-sm text-white border border-blue-500 rounded-md shadow-button focus:ring-0 focus:outline-none">
<svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#ffffff" stroke-linejoin="round" ><polyline points=" 6,12 10,16 18,8 " stroke="#ffffff"></polyline> <circle cx="12" cy="12" r="11"></circle></g></svg> Accept Bid </button> <svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#ffffff" stroke-linejoin="round" ><polyline points=" 6,12 10,16 18,8 " stroke="#ffffff"></polyline> <circle cx="12" cy="12" r="11"></circle></g></svg> Accept Bid </button>
</div> </div>
{% endif %} {% endif %}
</div> </div>
</div> </div>
@ -451,4 +451,4 @@
</div> </div>
{% include 'footer.html' %} {% include 'footer.html' %}
</body> </body>
</html> </html>

20
basicswap/templates/bid_xmr.html

@ -82,7 +82,7 @@
<td class="py-4 px-6 bold">Swap</td> <td class="py-4 px-6 bold">Swap</td>
<td> <td>
<div class="content flex py-2"> <div class="content flex py-2">
<span class="bold">{{ data.amt_to }} {{ data.ticker_to }}</span> <span class="bold">{{ data.amt_to }} {{ data.ticker_to }}</span>
<svg aria-hidden="true " class="w-5 h-5 ml-3 mr-3" fill="currentColor " viewBox="0 0 20 20 " xmlns="http://www.w3.org/2000/svg "> <svg aria-hidden="true " class="w-5 h-5 ml-3 mr-3" fill="currentColor " viewBox="0 0 20 20 " xmlns="http://www.w3.org/2000/svg ">
<path fill-rule="evenodd " d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z " clip-rule="evenodd "></path></svg> <path fill-rule="evenodd " d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z " clip-rule="evenodd "></path></svg>
<span class="bold">{{ data.amt_from }} {{ data.ticker_from }}</span> <span class="bold">{{ data.amt_from }} {{ data.ticker_from }}</span>
@ -305,10 +305,16 @@
{% endif %} {% endif %}
{% if data.xmr_b_half_privatekey %} {% if data.xmr_b_half_privatekey %}
<tr class="bg-white border-t hover:bg-gray-50"> <tr class="bg-white border-t hover:bg-gray-50">
<td class="py-4 px-6 bold">Key Half:</td> <td class="py-4 px-6 bold">Key Half (WARNING key data!):</td>
<td class="py-4 monospace">{{ data.xmr_b_half_privatekey }}</td> <td class="py-4 monospace">{{ data.xmr_b_half_privatekey }}</td>
</tr> </tr>
{% endif %} {% endif %}
{% if data.xmr_b_half_privatekey_remote %}
<tr class="bg-white border-t hover:bg-gray-50">
<td class="py-4 px-6 bold">Remote Key Half:</td>
<td class="py-4 monospace">{{ data.xmr_b_half_privatekey_remote }}</td>
</tr>
{% endif %}
</table> </table>
</div> </div>
</div> </div>
@ -475,7 +481,7 @@
{% if data.debug_ui == true %} {% if data.debug_ui == true %}
<tr> <tr>
<td class="py-6 pr-2 bold"">Debug Option</td> <td class="py-6 pr-2 bold"">Debug Option</td>
<td> <td>
<div class="relative"> <div class="relative">
<svg class="absolute right-4 top-1/2 transform -translate-y-1/2" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg class="absolute right-4 top-1/2 transform -translate-y-1/2" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.3333 6.1133C11.2084 5.98913 11.0395 5.91943 10.8633 5.91943C10.6872 5.91943 10.5182 5.98913 10.3933 6.1133L8.00001 8.47329L5.64001 6.1133C5.5151 5.98913 5.34613 5.91943 5.17001 5.91943C4.99388 5.91943 4.82491 5.98913 4.70001 6.1133C4.63752 6.17527 4.58792 6.249 4.55408 6.33024C4.52023 6.41148 4.50281 6.49862 4.50281 6.58663C4.50281 6.67464 4.52023 6.76177 4.55408 6.84301C4.58792 6.92425 4.63752 6.99799 4.70001 7.05996L7.52667 9.88663C7.58865 9.94911 7.66238 9.99871 7.74362 10.0326C7.82486 10.0664 7.912 10.0838 8.00001 10.0838C8.08801 10.0838 8.17515 10.0664 8.25639 10.0326C8.33763 9.99871 8.41136 9.94911 8.47334 9.88663L11.3333 7.05996C11.3958 6.99799 11.4454 6.92425 11.4793 6.84301C11.5131 6.76177 11.5305 6.67464 11.5305 6.58663C11.5305 6.49862 11.5131 6.41148 11.4793 6.33024C11.4454 6.249 11.3958 6.17527 11.3333 6.1133Z" fill="#8896AB"></path> <path d="M11.3333 6.1133C11.2084 5.98913 11.0395 5.91943 10.8633 5.91943C10.6872 5.91943 10.5182 5.98913 10.3933 6.1133L8.00001 8.47329L5.64001 6.1133C5.5151 5.98913 5.34613 5.91943 5.17001 5.91943C4.99388 5.91943 4.82491 5.98913 4.70001 6.1133C4.63752 6.17527 4.58792 6.249 4.55408 6.33024C4.52023 6.41148 4.50281 6.49862 4.50281 6.58663C4.50281 6.67464 4.52023 6.76177 4.55408 6.84301C4.58792 6.92425 4.63752 6.99799 4.70001 7.05996L7.52667 9.88663C7.58865 9.94911 7.66238 9.99871 7.74362 10.0326C7.82486 10.0664 7.912 10.0838 8.00001 10.0838C8.08801 10.0838 8.17515 10.0664 8.25639 10.0326C8.33763 9.99871 8.41136 9.94911 8.47334 9.88663L11.3333 7.05996C11.3958 6.99799 11.4454 6.92425 11.4793 6.84301C11.5131 6.76177 11.5305 6.67464 11.5305 6.58663C11.5305 6.49862 11.5131 6.41148 11.4793 6.33024C11.4454 6.249 11.3958 6.17527 11.3333 6.1133Z" fill="#8896AB"></path>
@ -503,7 +509,7 @@
</div> </div>
<div class="w-full md:w-auto p-1.5"> <div class="w-full md:w-auto p-1.5">
<button name="edit_bid_submit" value="Submit" type="submit" class="flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-coolGray-500 hover:text-coolGray-600 border border-coolGray-200 hover:border-coolGray-300 bg-white rounded-md shadow-button focus:ring-0 focus:outline-none"> <button name="edit_bid_submit" value="Submit" type="submit" class="flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-coolGray-500 hover:text-coolGray-600 border border-coolGray-200 hover:border-coolGray-300 bg-white rounded-md shadow-button focus:ring-0 focus:outline-none">
<svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="round" ><line x1="2" y1="23" x2="22" y2="23" stroke="#556987"></line> <line data-cap="butt" x1="13" y1="5" x2="17" y2="9"></line> <polygon points="8 18 3 19 4 14 16 2 20 6 8 18"></polygon></g></svg> Submit Edit Bid </button> <svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="round" ><line x1="2" y1="23" x2="22" y2="23" stroke="#556987"></line> <line data-cap="butt" x1="13" y1="5" x2="17" y2="9"></line> <polygon points="8 18 3 19 4 14 16 2 20 6 8 18"></polygon></g></svg> Submit Edit </button>
</div> </div>
{% else %} {% else %}
{% if data.show_bidder_seq_diagram %} {% if data.show_bidder_seq_diagram %}
@ -547,7 +553,7 @@
{% endif %} {% endif %}
<div class="w-full md:w-auto p-1.5"> <div class="w-full md:w-auto p-1.5">
<button name="edit_bid" type="submit" value="Edit Bid" class="flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-coolGray-500 hover:text-coolGray-600 border border-coolGray-200 hover:border-coolGray-300 bg-white rounded-md shadow-button focus:ring-0 focus:outline-none"> <button name="edit_bid" type="submit" value="Edit Bid" class="flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-coolGray-500 hover:text-coolGray-600 border border-coolGray-200 hover:border-coolGray-300 bg-white rounded-md shadow-button focus:ring-0 focus:outline-none">
<svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="round" ><line x1="2" y1="23" x2="22" y2="23" stroke="#556987"></line> <line data-cap="butt" x1="13" y1="5" x2="17" y2="9"></line> <polygon points="8 18 3 19 4 14 16 2 20 6 8 18"></polygon></g></svg> Edit bit </button> <svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="round" ><line x1="2" y1="23" x2="22" y2="23" stroke="#556987"></line> <line data-cap="butt" x1="13" y1="5" x2="17" y2="9"></line> <polygon points="8 18 3 19 4 14 16 2 20 6 8 18"></polygon></g></svg> Edit bid </button>
</div> </div>
{% endif %} {% endif %}
{% if data.was_received == 'True' %} {% if data.was_received == 'True' %}
@ -572,4 +578,4 @@
</div> </div>
{% include 'footer.html' %} {% include 'footer.html' %}
</body> </body>
</html> </html>

11
basicswap/ui/page_offers.py

@ -213,7 +213,16 @@ def parseOfferFormData(swap_client, form_data, page_data, options={}):
def postNewOfferFromParsed(swap_client, parsed_data): def postNewOfferFromParsed(swap_client, parsed_data):
swap_type = SwapTypes.SELLER_FIRST swap_type = SwapTypes.SELLER_FIRST
if parsed_data['coin_to'] in (Coins.XMR, Coins.PART_ANON):
if swap_type in parsed_data:
str_swap_type = parsed_data['swap_type'].lower()
if str_swap_type == 'seller_first':
swap_type = SwapTypes.SELLER_FIRST
elif str_swap_type == 'xmr_swap':
swap_type = SwapTypes.XMR_SWAP
else:
raise ValueError('Unknown swap type')
elif parsed_data['coin_to'] in (Coins.XMR, Coins.PART_ANON):
swap_type = SwapTypes.XMR_SWAP swap_type = SwapTypes.XMR_SWAP
if swap_client.coin_clients[parsed_data['coin_from']]['use_csv'] and swap_client.coin_clients[parsed_data['coin_to']]['use_csv']: if swap_client.coin_clients[parsed_data['coin_from']]['use_csv'] and swap_client.coin_clients[parsed_data['coin_to']]['use_csv']:

8
basicswap/ui/util.py

@ -28,7 +28,7 @@ from basicswap.basicswap_util import (
getLastBidState, getLastBidState,
) )
from basicswap.protocols.xmr_swap_1 import getChainBSplitKey from basicswap.protocols.xmr_swap_1 import getChainBSplitKey, getChainBRemoteSplitKey
PAGE_LIMIT = 50 PAGE_LIMIT = 50
invalid_coins_from = (Coins.XMR, Coins.PART_ANON) invalid_coins_from = (Coins.XMR, Coins.PART_ANON)
@ -302,12 +302,16 @@ def describeBid(swap_client, bid, xmr_swap, offer, xmr_offer, bid_events, edit_b
if swap_client.debug_ui: if swap_client.debug_ui:
try: try:
data['xmr_b_half_privatekey'] = getChainBSplitKey(swap_client, bid, xmr_swap, offer) data['xmr_b_half_privatekey'] = getChainBSplitKey(swap_client, bid, xmr_swap, offer)
remote_split_key = getChainBRemoteSplitKey(swap_client, bid, xmr_swap, offer)
if remote_split_key:
data['xmr_b_half_privatekey_remote'] = remote_split_key
except Exception as e: except Exception as e:
swap_client.log.error(traceback.format_exc()) swap_client.log.error(traceback.format_exc())
if show_lock_transfers: if show_lock_transfers:
if xmr_swap.pkbs: if xmr_swap.pkbs:
data['lock_transfers'] = json.dumps(ci_to.showLockTransfers(xmr_swap.pkbv, xmr_swap.pkbs), indent=4) data['lock_transfers'] = json.dumps(ci_to.showLockTransfers(xmr_swap.vkbv, xmr_swap.pkbs, bid.chain_b_height_start), indent=4)
else: else:
data['lock_transfers'] = 'Shared address not yet known.' data['lock_transfers'] = 'Shared address not yet known.'
else: else:

18
doc/release-notes.md

@ -3,6 +3,24 @@
============== ==============
0.0.54
==============
- If the XMR daemon is busy the wallet can fail a transfer, later sending the tx unknown to bsx.
- Check for existing transfers before trying to send the chain b lock tx.
- Check for transfers in XMR_SWAP_SCRIPT_COIN_LOCKED state when bid is sent.
- Continually try refund noscript lock tx in XMR_SWAP_FAILED state.
- showLockTransfers will attempt to create a wallet if none exists.
- tests:
- Add B_LOCK_TX_MISSED_SEND debug event and test.
- Store the Dash wallet password in memory for use in upgradetohd
- Remove false positive warning. Check for unlock_time transfer is not unlocked.
- ui:
- Add 'Remote Key Half' to Show More Info section (with debug_ui on)
- api:
- An unknown path will return an error instead of the default/index data.
0.0.32 0.0.32
============== ==============

20
tests/basicswap/test_xmr.py

@ -1318,6 +1318,26 @@ class Test(BaseTest):
assert (txin['txid'] == itx_after['vin'][i]['txid']) assert (txin['txid'] == itx_after['vin'][i]['txid'])
assert (txin['vout'] == itx_after['vin'][i]['vout']) assert (txin['vout'] == itx_after['vin'][i]['vout'])
def test_15_missed_xmr_send(self):
logging.info('---------- Test PART to XMR B lock tx is lost')
swap_clients = self.swap_clients
amt_swap = make_int(random.uniform(0.1, 10.0), scale=8, r=1)
rate_swap = make_int(random.uniform(2.0, 20.0), scale=12, r=1)
offer_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, amt_swap, rate_swap, amt_swap, SwapTypes.XMR_SWAP,
lock_type=TxLockTypes.SEQUENCE_LOCK_BLOCKS, lock_value=28)
wait_for_offer(test_delay_event, swap_clients[1], offer_id)
offer = swap_clients[1].getOffer(offer_id)
bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from)
wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED)
swap_clients[1].setBidDebugInd(bid_id, DebugTypes.B_LOCK_TX_MISSED_SEND)
swap_clients[0].acceptXmrBid(bid_id)
wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, wait_for=1800)
wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, wait_for=1800, sent=True)
def test_98_withdraw_all(self): def test_98_withdraw_all(self):
logging.info('---------- Test XMR withdrawal all') logging.info('---------- Test XMR withdrawal all')
try: try:

Loading…
Cancel
Save