diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py index 30fe42b..491269c 100644 --- a/basicswap/basicswap.py +++ b/basicswap/basicswap.py @@ -4926,6 +4926,40 @@ class BasicSwap(BaseApp): finally: self.mxDB.release() + def recoverNoScriptTxnWithKey(self, bid_id, encoded_key): + # Manually recover txn if other key is known + session = scoped_session(self.session_factory) + try: + bid, xmr_swap = self.getXmrBidFromSession(session, bid_id) + ensure(bid, 'Bid not found: {}.'.format(bid_id.hex())) + ensure(xmr_swap, 'XMR swap not found: {}.'.format(bid_id.hex())) + offer, xmr_offer = self.getXmrOfferFromSession(session, bid.offer_id, sent=False) + ensure(offer, 'Offer not found: {}.'.format(bid.offer_id.hex())) + ensure(xmr_offer, 'XMR offer not found: {}.'.format(bid.offer_id.hex())) + ci_to = self.ci(offer.coin_to) + + for_ed25519 = True if Coins(offer.coin_to) == Coins.XMR else False + if bid.was_sent: + kbsl = ci_to.decodeKey(encoded_key) + kbsf = self.getPathKey(offer.coin_from, offer.coin_to, bid.created_at, xmr_swap.contract_count, 2, for_ed25519) + else: + kbsl = self.getPathKey(offer.coin_from, offer.coin_to, bid.created_at, xmr_swap.contract_count, 2, for_ed25519) + kbsf = ci_to.decodeKey(encoded_key) + ensure(ci_to.verifyKey(kbsl), 'Invalid kbsl') + ensure(ci_to.verifyKey(kbsf), 'Invalid kbsf') + vkbs = ci_to.sumKeys(kbsl, kbsf) + + address_to = self.getCachedMainWalletAddress(ci_to) + txid = ci_to.spendBLockTx(xmr_swap.b_lock_tx_id, address_to, xmr_swap.vkbv, vkbs, bid.amount_to, xmr_offer.b_fee_rate, bid.chain_b_height_start) + self.log.debug('Submitted lock B spend txn %s to %s chain for bid %s', txid.hex(), ci_to.coin_name(), bid_id.hex()) + self.logBidEvent(bid.bid_id, EventLogTypes.LOCK_TX_B_SPEND_TX_PUBLISHED, txid.hex(), session) + session.commit() + + return txid.hex() + finally: + session.close() + session.remove() + def manualBidUpdate(self, bid_id, data): self.log.info('Manually updating bid %s', bid_id.hex()) self.mxDB.acquire() @@ -4948,6 +4982,9 @@ class BasicSwap(BaseApp): bid.debug_ind = data['debug_ind'] has_changed = True + if data['kbs_other'] is not None: + return self.recoverNoScriptTxnWithKey(bid_id, data['kbs_other']) + if has_changed: session = scoped_session(self.session_factory) try: diff --git a/basicswap/http_server.py b/basicswap/http_server.py index 197a0d4..cdfe373 100644 --- a/basicswap/http_server.py +++ b/basicswap/http_server.py @@ -1007,7 +1007,8 @@ class HttpHandler(BaseHTTPRequestHandler): elif b'edit_bid_submit' in form_data: data = { 'bid_state': int(form_data[b'new_state'][0]), - 'debug_ind': int(get_data_entry_or(form_data, 'debugind', -1)) + 'debug_ind': int(get_data_entry_or(form_data, 'debugind', -1)), + 'kbs_other': get_data_entry_or(form_data, 'kbs_other', None), } try: swap_client.manualBidUpdate(bid_id, data) diff --git a/basicswap/interface_btc.py b/basicswap/interface_btc.py index 7e8482f..a0bcc48 100644 --- a/basicswap/interface_btc.py +++ b/basicswap/interface_btc.py @@ -18,6 +18,7 @@ from .util import ( ensure, make_int, b58encode, + decodeWif, decodeAddress, decodeScriptNum, pubkeyToAddress, @@ -201,8 +202,7 @@ class BTCInterface(CoinInterface): return self.rpc_callback('getblockheader', [block_hash]) def initialiseWallet(self, key_bytes): - wif_prefix = self.chainparams_network()['key_prefix'] - key_wif = toWIF(wif_prefix, key_bytes) + key_wif = self.encodeKey(key_bytes) try: self.rpc_callback('sethdseed', [True, key_wif]) @@ -306,6 +306,10 @@ class BTCInterface(CoinInterface): def verifyPubkey(self, pubkey_bytes): return verify_secp256k1_point(pubkey_bytes) + def encodeKey(self, key_bytes): + wif_prefix = self.chainparams_network()['key_prefix'] + return toWIF(wif_prefix, key_bytes) + def encodePubkey(self, pk): return pointToCPK(pk) @@ -313,9 +317,7 @@ class BTCInterface(CoinInterface): return CPKToPoint(pke) def decodeKey(self, k): - i = b2i(k) - assert(i < ep.o) - return i + return decodeWif(k) def sumKeys(self, ka, kb): # TODO: Add to coincurve diff --git a/basicswap/interface_xmr.py b/basicswap/interface_xmr.py index aaab5a5..8c92027 100644 --- a/basicswap/interface_xmr.py +++ b/basicswap/interface_xmr.py @@ -170,6 +170,9 @@ class XMRInterface(CoinInterface): def pubkey(self, key): return edf.scalarmult_B(key) + def encodeKey(self, vk): + return vk.hex() + def encodePubkey(self, pk): return edu.encodepoint(pk) @@ -203,10 +206,8 @@ class XMRInterface(CoinInterface): def lengthDLEAG(self): return dleag_proof_len() - def decodeKey(self, k): - i = b2i(k) - assert(i < edf.l and i > 8) - return i + def decodeKey(self, k_hex): + return bytes.fromhex(k_hex) def sumKeys(self, ka, kb): return ed25519_scalar_add(ka, kb) diff --git a/basicswap/templates/bid_xmr.html b/basicswap/templates/bid_xmr.html index 5aadff0..6cc55d8 100644 --- a/basicswap/templates/bid_xmr.html +++ b/basicswap/templates/bid_xmr.html @@ -50,6 +50,7 @@ {{ a[1] }} {% endfor %} +Sweep No-Script TX {% endif %} @@ -74,6 +75,9 @@ {% if data.xmr_b_shared_address %}

Shared Address: {{ data.xmr_b_shared_address }}

{% endif %} +{% if data.xmr_b_half_privatekey %} +

Key Half: {{ data.xmr_b_half_privatekey }}

+{% endif %}

Transactions

diff --git a/basicswap/ui.py b/basicswap/ui.py index 57a2601..55cbefa 100644 --- a/basicswap/ui.py +++ b/basicswap/ui.py @@ -166,7 +166,7 @@ def describeBid(swap_client, bid, xmr_swap, offer, xmr_offer, bid_events, edit_b state_description = bid.state_note elif offer.swap_type == SwapTypes.XMR_SWAP: if bid.state == BidStates.BID_SENT: - tate_description = 'Waiting for offerer to accept' + state_description = 'Waiting for offerer to accept' if bid.state == BidStates.BID_RECEIVING: # Offerer receiving bid from bidder state_description = 'Waiting for bid to be fully received' @@ -205,6 +205,12 @@ def describeBid(swap_client, bid, xmr_swap, offer, xmr_offer, bid_events, edit_b state_description = f'Waiting for offerer to spend from {ticker_to} lock tx' elif bid.state == BidStates.XMR_SWAP_NOSCRIPT_TX_REDEEMED: state_description = f'Waiting for {ticker_to} lock tx spend tx to confirm in chain' + elif bid.state == BidStates.XMR_SWAP_SCRIPT_TX_PREREFUND: + if bid.was_sent: + state_description = f'Waiting for offerer to redeem or locktime to expire' + else: + state_description = f'Redeeming output' + addr_label = swap_client.getAddressLabel([bid.bid_addr, ])[0] bid_rate = offer.rate if bid.rate is None else bid.rate @@ -276,6 +282,9 @@ def describeBid(swap_client, bid, xmr_swap, offer, xmr_offer, bid_events, edit_b data['xmr_b_shared_address'] = ci_to.encodeSharedAddress(xmr_swap.pkbv, xmr_swap.pkbs) if xmr_swap.pkbs else None + if swap_client.debug_ui: + data['xmr_b_half_privatekey'] = ci_to.encodeKey(swap_client.getPathKey(offer.coin_from, offer.coin_to, bid.created_at, xmr_swap.contract_count, 2, True if offer.coin_to == Coins.XMR else False)) + if show_lock_transfers: if xmr_swap.pkbs: data['lock_transfers'] = json.dumps(ci_to.showLockTransfers(xmr_swap.pkbv, xmr_swap.pkbs), indent=4) diff --git a/basicswap/util.py b/basicswap/util.py index 27320da..03ed30a 100644 --- a/basicswap/util.py +++ b/basicswap/util.py @@ -100,8 +100,8 @@ def b58encode(v): return (__b58chars[0] * nPad) + result -def decodeWif(network_key): - key = b58decode(network_key)[1:-4] +def decodeWif(encoded_key): + key = b58decode(encoded_key)[1:-4] if len(key) == 33: return key[:-1] return key
Tx TypeTx IDBlocks Deep