mirror of
https://github.com/basicswap/basicswap.git
synced 2025-01-22 02:24:31 +00:00
All spend paths implemented, increasing test coverage, still some issues with refund spends and swipes to resolve
This commit is contained in:
parent
52e6e2b586
commit
57513aeb06
7 changed files with 181 additions and 57 deletions
|
@ -47,6 +47,7 @@ from .util import (
|
|||
DeserialiseNum,
|
||||
h2b,
|
||||
i2b,
|
||||
i2h,
|
||||
zeroIfNone,
|
||||
make_int,
|
||||
ensure,
|
||||
|
@ -1220,7 +1221,7 @@ class BasicSwap(BaseApp):
|
|||
coin_from = Coins(offer.coin_from)
|
||||
coin_to = Coins(offer.coin_to)
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
ci_from = self.ci(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
ci_to = self.ci(offer.coin_from if reverse_bid else offer.coin_to)
|
||||
|
||||
|
@ -1296,7 +1297,7 @@ class BasicSwap(BaseApp):
|
|||
query = 'UPDATE actions SET active_ind = 2 WHERE linked_id = x\'{}\' '.format(bid.bid_id.hex())
|
||||
use_session.execute(text(query))
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
# Unlock locked inputs (TODO)
|
||||
if offer.swap_type == SwapTypes.XMR_SWAP:
|
||||
ci_from = self.ci(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
|
@ -1367,7 +1368,9 @@ class BasicSwap(BaseApp):
|
|||
self.log.error('smsgsend failed {}'.format(json.dumps(ro, indent=4)))
|
||||
raise e
|
||||
|
||||
def is_reverse_ads_bid(self, coin_from) -> bool:
|
||||
def is_reverse_ads_bid(self, coin_from, coin_to) -> bool:
|
||||
if coin_to == Coins.BCH:
|
||||
return True
|
||||
return coin_from in self.scriptless_coins + self.coins_without_segwit
|
||||
|
||||
def validateSwapType(self, coin_from, coin_to, swap_type):
|
||||
|
@ -1377,7 +1380,7 @@ class BasicSwap(BaseApp):
|
|||
raise ValueError('Invalid coin: {}'.format(coin.name))
|
||||
|
||||
if swap_type == SwapTypes.XMR_SWAP:
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(coin_from, coin_to)
|
||||
itx_coin = coin_to if reverse_bid else coin_from
|
||||
ptx_coin = coin_from if reverse_bid else coin_to
|
||||
if itx_coin in self.coins_without_segwit + self.scriptless_coins:
|
||||
|
@ -1575,7 +1578,7 @@ class BasicSwap(BaseApp):
|
|||
if lock_type == TxLockTypes.SEQUENCE_LOCK_TIME:
|
||||
ensure(lock_value >= self.min_sequence_lock_seconds and lock_value <= self.max_sequence_lock_seconds, 'Invalid lock_value time')
|
||||
if swap_type == SwapTypes.XMR_SWAP:
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(coin_from, coin_to)
|
||||
itx_coin_has_csv = coin_to_has_csv if reverse_bid else coin_from_has_csv
|
||||
ensure(itx_coin_has_csv, 'ITX coin needs CSV activated.')
|
||||
else:
|
||||
|
@ -1583,7 +1586,7 @@ class BasicSwap(BaseApp):
|
|||
elif lock_type == TxLockTypes.SEQUENCE_LOCK_BLOCKS:
|
||||
ensure(lock_value >= 5 and lock_value <= 1000, 'Invalid lock_value blocks')
|
||||
if swap_type == SwapTypes.XMR_SWAP:
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(coin_from, coin_to)
|
||||
itx_coin_has_csv = coin_to_has_csv if reverse_bid else coin_from_has_csv
|
||||
ensure(itx_coin_has_csv, 'ITX coin needs CSV activated.')
|
||||
else:
|
||||
|
@ -1655,7 +1658,7 @@ class BasicSwap(BaseApp):
|
|||
|
||||
offer_addr_to = self.getOfferAddressTo(extra_options)
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(coin_from, coin_to)
|
||||
|
||||
try:
|
||||
session = self.openSession()
|
||||
|
@ -1736,7 +1739,7 @@ class BasicSwap(BaseApp):
|
|||
if security_token is not None and len(security_token) != 20:
|
||||
raise ValueError('Security token must be 20 bytes long.')
|
||||
|
||||
bid_reversed: bool = msg_buf.swap_type == SwapTypes.XMR_SWAP and self.is_reverse_ads_bid(msg_buf.coin_from)
|
||||
bid_reversed: bool = msg_buf.swap_type == SwapTypes.XMR_SWAP and self.is_reverse_ads_bid(msg_buf.coin_from, msg_buf.coin_to)
|
||||
offer = Offer(
|
||||
offer_id=offer_id,
|
||||
active_ind=1,
|
||||
|
@ -2629,7 +2632,7 @@ class BasicSwap(BaseApp):
|
|||
|
||||
if offer.swap_type == SwapTypes.XMR_SWAP:
|
||||
ensure(bid.protocol_version >= MINPROTO_VERSION_ADAPTOR_SIG, 'Incompatible bid protocol version')
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
if reverse_bid:
|
||||
return self.acceptADSReverseBid(bid_id, use_session)
|
||||
return self.acceptXmrBid(bid_id, use_session)
|
||||
|
@ -2786,7 +2789,7 @@ class BasicSwap(BaseApp):
|
|||
balance_to: int = ci_to.getSpendableBalance()
|
||||
ensure(balance_to > amount_to, '{} spendable balance is too low: {} < {}'.format(ci_to.coin_name(), ci_to.format_amount(balance_to), ci_to.format_amount(amount_to)))
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(coin_from, coin_to)
|
||||
if reverse_bid:
|
||||
reversed_rate: int = ci_to.make_int(amount / amount_to, r=1)
|
||||
|
||||
|
@ -2952,7 +2955,7 @@ class BasicSwap(BaseApp):
|
|||
ensure(xmr_offer, 'Adaptor-sig offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
ensure(offer.expire_at > now, 'Offer has expired')
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
coin_from = Coins(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
coin_to = Coins(offer.coin_from if reverse_bid else offer.coin_to)
|
||||
ci_from = self.ci(coin_from)
|
||||
|
@ -3807,7 +3810,7 @@ class BasicSwap(BaseApp):
|
|||
def checkXmrBidState(self, bid_id: bytes, bid, offer):
|
||||
rv = False
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
ci_from = self.ci(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
ci_to = self.ci(offer.coin_from if reverse_bid else offer.coin_to)
|
||||
|
||||
|
@ -3937,7 +3940,7 @@ class BasicSwap(BaseApp):
|
|||
if lock_tx_chain_info is None:
|
||||
return rv
|
||||
|
||||
if lock_tx_chain_info['txid'] != b2h(xmr_swap.a_lock_tx_id):
|
||||
if 'txid' in lock_tx_chain_info and lock_tx_chain_info['txid'] != b2h(xmr_swap.a_lock_tx_id):
|
||||
# if we find that txid was changed (by funding or otherwise), we need to update it to track correctly
|
||||
xmr_swap.a_lock_tx_id = h2b(lock_tx_chain_info['txid'])
|
||||
xmr_swap.a_lock_tx = h2b(lock_tx_chain_info['txhex'])
|
||||
|
@ -3957,8 +3960,8 @@ class BasicSwap(BaseApp):
|
|||
bid.xmr_a_lock_tx.tx_data = xmr_swap.a_lock_tx
|
||||
bid.xmr_a_lock_tx.spend_txid = xmr_swap.a_lock_spend_tx_id
|
||||
|
||||
coin_from = Coins(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
self.addWatchedOutput(coin_from, bid.bid_id, bid.xmr_a_lock_tx.txid.hex(), bid.xmr_a_lock_tx.vout, TxTypes.XMR_SWAP_A_LOCK, SwapTypes.XMR_SWAP)
|
||||
# update watcher
|
||||
self.watchXmrSwap(bid, offer, xmr_swap, session)
|
||||
bid_changed = True
|
||||
|
||||
if bid.xmr_a_lock_tx.state == TxStates.TX_NONE and lock_tx_chain_info['height'] == 0:
|
||||
|
@ -4394,7 +4397,7 @@ class BasicSwap(BaseApp):
|
|||
ensure(offer, 'Offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
ensure(xmr_offer, 'Adaptor-sig offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
was_received: bool = bid.was_sent if reverse_bid else bid.was_received
|
||||
coin_from = Coins(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
coin_to = Coins(offer.coin_from if reverse_bid else offer.coin_to)
|
||||
|
@ -4402,12 +4405,18 @@ class BasicSwap(BaseApp):
|
|||
state = BidStates(bid.state)
|
||||
spending_txid = bytes.fromhex(spend_txid_hex)
|
||||
|
||||
spend_tx = self.ci(coin_from).loadTx(h2b(spend_txn_hex))
|
||||
ci_from = self.ci(coin_from)
|
||||
spend_tx = ci_from.loadTx(h2b(spend_txn_hex))
|
||||
|
||||
bid.xmr_a_lock_tx.spend_txid = spending_txid
|
||||
if spending_txid == xmr_swap.a_lock_spend_tx_id or i2b(spend_tx.vin[0].prevout.hash) == xmr_swap.a_lock_tx_id:
|
||||
|
||||
is_spending_lock_tx = False
|
||||
if self.isBchXmrSwap(offer):
|
||||
is_spending_lock_tx = self.ci(coin_from).isSpendingLockTx(spend_tx)
|
||||
|
||||
if spending_txid == xmr_swap.a_lock_spend_tx_id or (i2b(spend_tx.vin[0].prevout.hash) == xmr_swap.a_lock_tx_id and is_spending_lock_tx):
|
||||
# bch txids change
|
||||
if xmr_swap.a_lock_spend_tx_id != spending_txid:
|
||||
if self.isBchXmrSwap(offer):
|
||||
xmr_swap.a_lock_spend_tx_id = spending_txid
|
||||
xmr_swap.a_lock_spend_tx = bytes.fromhex(spend_txn_hex)
|
||||
|
||||
|
@ -4424,13 +4433,20 @@ class BasicSwap(BaseApp):
|
|||
# Could already be processed if spend was detected in the mempool
|
||||
self.log.warning('Coin a lock tx spend ignored due to bid state for bid {}'.format(bid_id.hex()))
|
||||
|
||||
elif spending_txid == xmr_swap.a_lock_refund_tx_id or i2b(spend_tx.vin[0].prevout.hash) == xmr_swap.a_lock_refund_tx_id:
|
||||
elif spending_txid == xmr_swap.a_lock_refund_tx_id or (i2b(spend_tx.vin[0].prevout.hash) == xmr_swap.a_lock_tx_id and not is_spending_lock_tx):
|
||||
self.log.debug('Coin a lock tx spent by lock refund tx.')
|
||||
# bch txids change
|
||||
if xmr_swap.a_lock_refund_tx_id != spending_txid:
|
||||
if self.isBchXmrSwap(offer):
|
||||
self.log.debug('Recomputing refund spend transaction and txid after lock tx spend.')
|
||||
|
||||
xmr_swap.a_lock_refund_tx_id = spending_txid
|
||||
xmr_swap.a_lock_refund_tx = bytes.fromhex(spend_txn_hex)
|
||||
|
||||
self.log.debug('Coin a lock tx spent by lock refund tx.')
|
||||
tx = ci_from.loadTx(xmr_swap.a_lock_refund_spend_tx)
|
||||
tx.vin[0].prevout.hash = b2i(xmr_swap.a_lock_refund_tx_id)
|
||||
xmr_swap.a_lock_refund_spend_tx = tx.serialize_without_witness()
|
||||
xmr_swap.a_lock_refund_spend_tx_id = ci_from.getTxid(xmr_swap.a_lock_refund_spend_tx)
|
||||
|
||||
bid.setState(BidStates.XMR_SWAP_SCRIPT_TX_PREREFUND)
|
||||
self.logBidEvent(bid.bid_id, EventLogTypes.LOCK_TX_A_REFUND_TX_SEEN, '', use_session)
|
||||
else:
|
||||
|
@ -4455,7 +4471,7 @@ class BasicSwap(BaseApp):
|
|||
ensure(offer, 'Offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
ensure(xmr_offer, 'Adaptor-sig offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
coin_from = Coins(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
coin_to = Coins(offer.coin_from if reverse_bid else offer.coin_to)
|
||||
was_sent: bool = bid.was_received if reverse_bid else bid.was_sent
|
||||
|
@ -4467,9 +4483,13 @@ class BasicSwap(BaseApp):
|
|||
spend_txn_hex = spend_txn['hex']
|
||||
spend_tx = self.ci(coin_from).loadTx(h2b(spend_txn_hex))
|
||||
|
||||
if spending_txid == xmr_swap.a_lock_refund_spend_tx_id or i2b(spend_tx.vin[0].prevout.hash) == xmr_swap.a_lock_refund_spend_tx_id:
|
||||
is_spending_lock_refund_tx = False
|
||||
if self.isBchXmrSwap(offer):
|
||||
is_spending_lock_refund_tx = self.ci(coin_from).isSpendingLockRefundTx(spend_tx)
|
||||
|
||||
if spending_txid == xmr_swap.a_lock_refund_spend_tx_id or (i2b(spend_tx.vin[0].prevout.hash) == xmr_swap.a_lock_refund_tx_id and is_spending_lock_refund_tx):
|
||||
# bch txids change
|
||||
if xmr_swap.a_lock_refund_spend_tx_id != spending_txid:
|
||||
if self.isBchXmrSwap(offer):
|
||||
xmr_swap.a_lock_refund_spend_tx_id = spending_txid
|
||||
xmr_swap.a_lock_refund_spend_tx = bytes.fromhex(spend_txn_hex)
|
||||
|
||||
|
@ -4911,7 +4931,7 @@ class BasicSwap(BaseApp):
|
|||
ensure(msg['sent'] + offer_data.time_valid >= now, 'Offer expired')
|
||||
|
||||
offer_rate: int = ci_from.make_int(offer_data.amount_to / offer_data.amount_from, r=1)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(coin_from, coin_to)
|
||||
|
||||
if offer_data.swap_type == SwapTypes.SELLER_FIRST:
|
||||
ensure(offer_data.protocol_version >= MINPROTO_VERSION_SECRET_HASH, 'Invalid protocol version')
|
||||
|
@ -4952,7 +4972,7 @@ class BasicSwap(BaseApp):
|
|||
# Check for sent
|
||||
existing_offer = self.getOffer(offer_id, session=session)
|
||||
if existing_offer is None:
|
||||
bid_reversed: bool = offer_data.swap_type == SwapTypes.XMR_SWAP and self.is_reverse_ads_bid(offer_data.coin_from)
|
||||
bid_reversed: bool = offer_data.swap_type == SwapTypes.XMR_SWAP and self.is_reverse_ads_bid(offer_data.coin_from, offer_data.coin_to)
|
||||
offer = Offer(
|
||||
offer_id=offer_id,
|
||||
active_ind=1,
|
||||
|
@ -5337,7 +5357,7 @@ class BasicSwap(BaseApp):
|
|||
xmr_swap = session.query(XmrSwap).filter_by(bid_id=bid.bid_id).first()
|
||||
ensure(xmr_swap, 'Adaptor-sig swap not found: {}.'.format(bid.bid_id.hex()))
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
addr_expect_from: str = ''
|
||||
if reverse_bid:
|
||||
ci_from = self.ci(Coins(offer.coin_to))
|
||||
|
@ -5404,7 +5424,7 @@ class BasicSwap(BaseApp):
|
|||
xmr_swap = session.query(XmrSwap).filter_by(bid_id=bid.bid_id).first()
|
||||
ensure(xmr_swap, 'Adaptor-sig swap not found: {}.'.format(bid.bid_id.hex()))
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
ci_from = self.ci(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
ci_to = self.ci(offer.coin_from if reverse_bid else offer.coin_to)
|
||||
addr_from: str = bid.bid_addr if reverse_bid else offer.addr_from
|
||||
|
@ -5566,7 +5586,7 @@ class BasicSwap(BaseApp):
|
|||
ensure(offer, 'Offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
ensure(xmr_offer, 'Adaptor-sig offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
ci_from = self.ci(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
ci_to = self.ci(offer.coin_from if reverse_bid else offer.coin_to)
|
||||
addr_from: str = bid.bid_addr if reverse_bid else offer.addr_from
|
||||
|
@ -5675,7 +5695,7 @@ class BasicSwap(BaseApp):
|
|||
self.log.debug('Adaptor-sig swap in progress, bid %s', bid.bid_id.hex())
|
||||
self.swaps_in_progress[bid.bid_id] = (bid, offer)
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
coin_from = Coins(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
self.setLastHeightCheckedStart(coin_from, bid.chain_a_height_start, session)
|
||||
self.addWatchedOutput(coin_from, bid.bid_id, bid.xmr_a_lock_tx.txid.hex(), bid.xmr_a_lock_tx.vout, TxTypes.XMR_SWAP_A_LOCK, SwapTypes.XMR_SWAP)
|
||||
|
@ -5696,7 +5716,7 @@ class BasicSwap(BaseApp):
|
|||
ensure(offer, 'Offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
ensure(xmr_offer, 'Adaptor-sig offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
coin_from = Coins(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
coin_to = Coins(offer.coin_from if reverse_bid else offer.coin_to)
|
||||
ci_from = self.ci(coin_from)
|
||||
|
@ -5760,7 +5780,7 @@ class BasicSwap(BaseApp):
|
|||
ensure(offer, 'Offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
ensure(xmr_offer, 'Adaptor-sig offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
coin_from = Coins(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
coin_to = Coins(offer.coin_from if reverse_bid else offer.coin_to)
|
||||
ci_from = self.ci(coin_from)
|
||||
|
@ -5803,6 +5823,7 @@ class BasicSwap(BaseApp):
|
|||
lock_tx_signed = ci_from.signTxWithWallet(xmr_swap.a_lock_tx)
|
||||
txid_hex = ci_from.publishTx(lock_tx_signed)
|
||||
if txid_hex != b2h(xmr_swap.a_lock_tx_id):
|
||||
self.log.info('Recomputing lock refund and lock spend transactions and txids after lock tx publish')
|
||||
xmr_swap.a_lock_tx = lock_tx_signed
|
||||
xmr_swap.a_lock_tx_id = bytes.fromhex(txid_hex)
|
||||
|
||||
|
@ -5816,10 +5837,18 @@ class BasicSwap(BaseApp):
|
|||
xmr_swap.a_lock_spend_tx = tx.serialize_without_witness()
|
||||
xmr_swap.a_lock_spend_tx_id = ci_from.getTxid(xmr_swap.a_lock_spend_tx)
|
||||
|
||||
if bid.xmr_a_lock_tx:
|
||||
bid.xmr_a_lock_tx.txid = xmr_swap.a_lock_tx_id
|
||||
bid.xmr_a_lock_tx.tx_data = lock_tx_signed
|
||||
bid.xmr_a_lock_tx.spend_txid = xmr_swap.a_lock_spend_tx_id
|
||||
vout_pos = ci_from.getTxOutputPos(xmr_swap.a_lock_tx, xmr_swap.a_lock_tx_script)
|
||||
if not bid.xmr_a_lock_tx:
|
||||
bid.xmr_a_lock_tx = SwapTx(
|
||||
bid_id=bid_id,
|
||||
tx_type=TxTypes.XMR_SWAP_A_LOCK,
|
||||
txid=xmr_swap.a_lock_tx_id,
|
||||
vout=vout_pos,
|
||||
)
|
||||
|
||||
bid.xmr_a_lock_tx.txid = xmr_swap.a_lock_tx_id
|
||||
bid.xmr_a_lock_tx.tx_data = lock_tx_signed
|
||||
bid.xmr_a_lock_tx.spend_txid = xmr_swap.a_lock_spend_tx_id
|
||||
|
||||
vout_pos = ci_from.getTxOutputPos(xmr_swap.a_lock_tx, xmr_swap.a_lock_tx_script)
|
||||
self.log.debug('Submitted lock txn %s to %s chain for bid %s', txid_hex, ci_from.coin_name(), bid_id.hex())
|
||||
|
@ -5855,7 +5884,7 @@ class BasicSwap(BaseApp):
|
|||
ensure(offer, 'Offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
ensure(xmr_offer, 'Adaptor-sig offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
ci_from = self.ci(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
ci_to = self.ci(offer.coin_from if reverse_bid else offer.coin_to)
|
||||
b_fee_rate: int = xmr_offer.a_fee_rate if reverse_bid else xmr_offer.b_fee_rate
|
||||
|
@ -5939,7 +5968,7 @@ class BasicSwap(BaseApp):
|
|||
ensure(offer, 'Offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
ensure(xmr_offer, 'Adaptor-sig offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
coin_from = Coins(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
coin_to = Coins(offer.coin_from if reverse_bid else offer.coin_to)
|
||||
|
||||
|
@ -5971,7 +6000,7 @@ class BasicSwap(BaseApp):
|
|||
ensure(offer, 'Offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
ensure(xmr_offer, 'Adaptor-sig offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
coin_from = Coins(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
coin_to = Coins(offer.coin_from if reverse_bid else offer.coin_to)
|
||||
ci_from = self.ci(coin_from)
|
||||
|
@ -6043,7 +6072,7 @@ class BasicSwap(BaseApp):
|
|||
ensure(offer, 'Offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
ensure(xmr_offer, 'Adaptor-sig offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
coin_from = Coins(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
coin_to = Coins(offer.coin_from if reverse_bid else offer.coin_to)
|
||||
ci_from = self.ci(coin_from)
|
||||
|
@ -6115,7 +6144,7 @@ class BasicSwap(BaseApp):
|
|||
ensure(offer, 'Offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
ensure(xmr_offer, 'Adaptor-sig offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
coin_from = Coins(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
coin_to = Coins(offer.coin_from if reverse_bid else offer.coin_to)
|
||||
ci_from = self.ci(coin_from)
|
||||
|
@ -6183,7 +6212,7 @@ class BasicSwap(BaseApp):
|
|||
ensure(offer, 'Offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
ensure(xmr_offer, 'Adaptor-sig offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
ci_from = self.ci(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
addr_send_from: str = bid.bid_addr if reverse_bid else offer.addr_from
|
||||
addr_send_to: str = offer.addr_from if reverse_bid else bid.bid_addr
|
||||
|
@ -6221,7 +6250,7 @@ class BasicSwap(BaseApp):
|
|||
ensure(offer, 'Offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
ensure(xmr_offer, 'Adaptor-sig offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
coin_from = Coins(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
coin_to = Coins(offer.coin_from if reverse_bid else offer.coin_to)
|
||||
addr_sent_from: str = offer.addr_from if reverse_bid else bid.bid_addr
|
||||
|
@ -6276,6 +6305,7 @@ class BasicSwap(BaseApp):
|
|||
ensure(v, 'Invalid signature for lock refund spend txn')
|
||||
|
||||
tx.vin[0].scriptSig = ci_from.getScriptScriptSig(xmr_swap.a_lock_refund_tx_script, out1_sig)
|
||||
tx.vin[0].prevout.hash = b2i(xmr_swap.a_lock_tx_id)
|
||||
xmr_swap.a_lock_refund_spend_tx = tx.serialize_without_witness()
|
||||
xmr_swap.a_lock_refund_spend_tx_id = ci_from.getTxid(xmr_swap.a_lock_refund_spend_tx)
|
||||
|
||||
|
@ -6309,7 +6339,7 @@ class BasicSwap(BaseApp):
|
|||
ensure(offer, 'Offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
ensure(xmr_offer, 'Adaptor-sig offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
ci_from = self.ci(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
ci_to = self.ci(offer.coin_from if reverse_bid else offer.coin_to)
|
||||
addr_sent_from: str = bid.bid_addr if reverse_bid else offer.addr_from
|
||||
|
@ -6404,7 +6434,7 @@ class BasicSwap(BaseApp):
|
|||
ensure(offer, 'Offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
ensure(xmr_offer, 'Adaptor-sig offer not found: {}.'.format(bid.offer_id.hex()))
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
ci_from = self.ci(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
addr_sent_from: str = bid.bid_addr if reverse_bid else offer.addr_from
|
||||
addr_sent_to: str = offer.addr_from if reverse_bid else bid.bid_addr
|
||||
|
@ -7784,7 +7814,7 @@ class BasicSwap(BaseApp):
|
|||
def createCoinALockRefundSwipeTx(self, ci, bid, offer, xmr_swap, xmr_offer):
|
||||
self.log.debug('Creating %s lock refund swipe tx', ci.coin_name())
|
||||
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = self.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
a_fee_rate: int = xmr_offer.b_fee_rate if reverse_bid else xmr_offer.a_fee_rate
|
||||
coin_from = Coins(offer.coin_to if reverse_bid else offer.coin_from)
|
||||
coin_to = Coins(offer.coin_from if reverse_bid else offer.coin_to)
|
||||
|
|
|
@ -367,7 +367,7 @@ class BCHInterface(BTCInterface):
|
|||
if ves is not None:
|
||||
return CScript([ves, script])
|
||||
else:
|
||||
return CScript([0, script])
|
||||
return CScript([script])
|
||||
|
||||
def createSCLockSpendTx(self, tx_lock_bytes, script_lock, pkh_dest, tx_fee_rate, vkbv=None, fee_info={}, **kwargs):
|
||||
# tx_fee_rate in this context is equal to `mining_fee` contract param
|
||||
|
@ -443,6 +443,42 @@ class BCHInterface(BTCInterface):
|
|||
kwargs['ves'] = bytes(73)
|
||||
return self.createSCLockSpendTx(tx_lock_refund_bytes, script_lock_refund, pkh_refund_to, tx_fee_rate, vkbv, **kwargs)
|
||||
|
||||
def createSCLockRefundSpendToFTx(self, tx_lock_refund_bytes, script_lock_refund, pkh_dest, tx_fee_rate, vkbv=None):
|
||||
# lock refund swipe tx
|
||||
# Sends the coinA locked coin to the follower
|
||||
|
||||
tx_lock_refund = self.loadTx(tx_lock_refund_bytes)
|
||||
|
||||
output_script = self.getScriptDest(script_lock_refund)
|
||||
locked_n = findOutput(tx_lock_refund, output_script)
|
||||
ensure(locked_n is not None, 'Output not found in tx')
|
||||
locked_coin = tx_lock_refund.vout[locked_n].nValue
|
||||
|
||||
mining_fee, out_1, out_2, public_key, timelock = self.extractScriptLockScriptValues(script_lock_refund)
|
||||
|
||||
tx_lock_refund.rehash()
|
||||
tx_lock_refund_hash_int = tx_lock_refund.sha256
|
||||
|
||||
tx = CTransaction()
|
||||
tx.nVersion = self.txVersion()
|
||||
tx.vin.append(CTxIn(COutPoint(tx_lock_refund_hash_int, locked_n),
|
||||
nSequence=timelock,
|
||||
scriptSig=self.getScriptScriptSig(script_lock_refund, None)))
|
||||
|
||||
tx.vout.append(self.txoType()(locked_coin, CScript(out_2)))
|
||||
|
||||
size = self.getTxSize(tx)
|
||||
vsize = size
|
||||
|
||||
pay_fee = mining_fee
|
||||
tx.vout[0].nValue = locked_coin - pay_fee
|
||||
|
||||
tx.rehash()
|
||||
self._log.info('createSCLockRefundSpendToFTx %s:\n fee_rate, vsize, fee: %ld, %ld, %ld.',
|
||||
i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
|
||||
|
||||
return tx.serialize()
|
||||
|
||||
def signTx(self, key_bytes: bytes, tx_bytes: bytes, input_n: int, prevout_script: bytes, prevout_value: int) -> bytes:
|
||||
# simply sign the entire tx data, as this is not a preimage signature
|
||||
eck = PrivateKey(key_bytes)
|
||||
|
@ -493,7 +529,11 @@ class BCHInterface(BTCInterface):
|
|||
|
||||
def extractScriptLockScriptValuesFromScriptSig(self, script_bytes):
|
||||
signature, nb = decodePushData(script_bytes, 0)
|
||||
unlock_script, _ = decodePushData(script_bytes, nb)
|
||||
if nb == len(script_bytes):
|
||||
unlock_script = signature[:]
|
||||
signature = None
|
||||
else:
|
||||
unlock_script, _ = decodePushData(script_bytes, nb)
|
||||
mining_fee, out_1, out_2, public_key, timelock = self.extractScriptLockScriptValues(unlock_script)
|
||||
|
||||
return signature, mining_fee, out_1, out_2, public_key, timelock
|
||||
|
@ -782,3 +822,19 @@ class BCHInterface(BTCInterface):
|
|||
tx = self.loadTx(tx_bytes)
|
||||
signature, _, _, _, _, _ = self.extractScriptLockScriptValuesFromScriptSig(tx.vin[0].scriptSig)
|
||||
return signature
|
||||
|
||||
def extractFollowerSig(self, tx_bytes: bytes) -> bytes:
|
||||
tx = self.loadTx(tx_bytes)
|
||||
signature, _, _, _, _, _ = self.extractScriptLockScriptValuesFromScriptSig(tx.vin[0].scriptSig)
|
||||
return signature
|
||||
|
||||
def isSpendingLockTx(self, spend_tx: CTransaction) -> bool:
|
||||
signature, _, _, _, _, _ = self.extractScriptLockScriptValuesFromScriptSig(spend_tx.vin[0].scriptSig)
|
||||
return spend_tx.vin[0].nSequence == 0 and signature is not None
|
||||
|
||||
def isSpendingLockRefundTx(self, spend_tx: CTransaction) -> bool:
|
||||
signature, _, _, _, _, _ = self.extractScriptLockScriptValuesFromScriptSig(spend_tx.vin[0].scriptSig)
|
||||
return spend_tx.vin[0].nSequence == 0 and signature is not None
|
||||
|
||||
def isTxExistsError(self, err_str: str) -> bool:
|
||||
return 'transaction already in block chain' in err_str
|
||||
|
|
|
@ -224,7 +224,7 @@ def parseOfferFormData(swap_client, form_data, page_data, options={}):
|
|||
|
||||
try:
|
||||
if len(errors) == 0 and page_data['swap_style'] == 'xmr':
|
||||
reverse_bid: bool = swap_client.is_reverse_ads_bid(coin_from)
|
||||
reverse_bid: bool = swap_client.is_reverse_ads_bid(coin_from, coin_to)
|
||||
ci_leader = ci_to if reverse_bid else ci_from
|
||||
ci_follower = ci_from if reverse_bid else ci_to
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ def describeBid(swap_client, bid, xmr_swap, offer, xmr_offer, bid_events, edit_b
|
|||
ci_from = swap_client.ci(Coins(offer.coin_from))
|
||||
ci_to = swap_client.ci(Coins(offer.coin_to))
|
||||
|
||||
reverse_bid: bool = swap_client.is_reverse_ads_bid(offer.coin_from)
|
||||
reverse_bid: bool = swap_client.is_reverse_ads_bid(offer.coin_from, offer.coin_to)
|
||||
ci_leader = ci_to if reverse_bid else ci_from
|
||||
ci_follower = ci_from if reverse_bid else ci_to
|
||||
|
||||
|
|
|
@ -2,10 +2,12 @@ import unittest
|
|||
|
||||
from basicswap.contrib.test_framework.script import CScript
|
||||
from basicswap.interface.bch import BCHInterface
|
||||
from basicswap.util import ensure
|
||||
|
||||
bch_lock_spend_tx = '0200000001bfc6bbb47851441c7827059ae337a06aa9064da7f9537eb9243e45766c3dd34c00000000d8473045022100a0161ea14d3b41ed41250c8474fc8ec6ce1cab8df7f401e69ecf77c2ab63d82102207a2a57ddf2ea400e09ea059f3b261da96f5098858b17239931f3cc2fb929bb2a4c8ec3519dc4519d02e80300c600cc949d00ce00d18800cf00d28800d000d39d00cb641976a91481ec21969399d15c26af089d5db437ead066c5ba88ac00cd788821024ffcc0481629866671d89f05f3da813a2aacec1b52e69b8c0c586b665f5d4574ba6752b27523aa20df65a90e9becc316ff5aca44d4e06dfaade56622f32bafa197aba706c5e589758700cd87680000000001251cde06000000001976a91481ec21969399d15c26af089d5db437ead066c5ba88ac00000000'
|
||||
bch_lock_script = 'c3519dc4519d02e80300c600cc949d00ce00d18800cf00d28800d000d39d00cb641976a91481ec21969399d15c26af089d5db437ead066c5ba88ac00cd788821024ffcc0481629866671d89f05f3da813a2aacec1b52e69b8c0c586b665f5d4574ba6752b27523aa20df65a90e9becc316ff5aca44d4e06dfaade56622f32bafa197aba706c5e589758700cd8768'
|
||||
bch_lock_spend_script = '473045022100a0161ea14d3b41ed41250c8474fc8ec6ce1cab8df7f401e69ecf77c2ab63d82102207a2a57ddf2ea400e09ea059f3b261da96f5098858b17239931f3cc2fb929bb2a4c8ec3519dc4519d02e80300c600cc949d00ce00d18800cf00d28800d000d39d00cb641976a91481ec21969399d15c26af089d5db437ead066c5ba88ac00cd788821024ffcc0481629866671d89f05f3da813a2aacec1b52e69b8c0c586b665f5d4574ba6752b27523aa20df65a90e9becc316ff5aca44d4e06dfaade56622f32bafa197aba706c5e589758700cd8768'
|
||||
bch_lock_swipe_script = '4c8fc3519dc4519d02e80300c600cc949d00ce00d18800cf00d28800d000d39d00cb641976a9141ab50aedd2e48297073f0f6eef46f97b37c9354e88ac00cd7888210234fe304a5b129b8265c177c92aa40b7840e8303f8b0fcca2359023163c7c2768ba670120b27523aa20191b09e40d1277fa14fea1e9b41e4fcc4528c9cb77e39e1b7b1a0b3332180cb78700cd8768'
|
||||
|
||||
coin_settings = {'rpcport': 0, 'rpcauth': 'none', 'blocks_confirmed': 1, 'conf_target': 1, 'use_segwit': False, 'connection_type': 'rpc'}
|
||||
|
||||
|
@ -26,4 +28,8 @@ class TestXmrBchSwapInterface(unittest.TestCase):
|
|||
|
||||
script_bytes = CScript(bytes.fromhex(bch_lock_spend_script))
|
||||
signature, mining_fee, out_1, out_2, public_key, timelock = ci.extractScriptLockScriptValuesFromScriptSig(script_bytes)
|
||||
print(timelock)
|
||||
ensure(signature is not None, 'signature not present')
|
||||
|
||||
script_bytes = CScript(bytes.fromhex(bch_lock_swipe_script))
|
||||
signature, mining_fee, out_1, out_2, public_key, timelock = ci.extractScriptLockScriptValuesFromScriptSig(script_bytes)
|
||||
ensure(signature is None, 'signature present')
|
||||
|
|
|
@ -519,4 +519,36 @@ class TestBCH(BasicSwapTest):
|
|||
|
||||
def test_01_b_full_swap_reverse(self):
|
||||
self.prepare_balance(Coins.BCH, 100.0, 1801, 1800)
|
||||
super().test_01_b_full_swap_reverse()
|
||||
super().test_01_b_full_swap_reverse()
|
||||
|
||||
def test_01_c_full_swap_to_part(self):
|
||||
super().test_01_c_full_swap_to_part()
|
||||
|
||||
def test_01_d_full_swap_from_part(self):
|
||||
self.prepare_balance(Coins.BCH, 100.0, 1801, 1800)
|
||||
super().test_01_d_full_swap_from_part()
|
||||
|
||||
def test_02_a_leader_recover_a_lock_tx(self):
|
||||
super().test_02_a_leader_recover_a_lock_tx()
|
||||
|
||||
def test_03_a_follower_recover_a_lock_tx(self):
|
||||
super().test_03_a_follower_recover_a_lock_tx()
|
||||
|
||||
def test_03_b_follower_recover_a_lock_tx_reverse(self):
|
||||
self.prepare_balance(Coins.BCH, 100.0, 1801, 1800)
|
||||
super().test_03_b_follower_recover_a_lock_tx_reverse()
|
||||
|
||||
def test_03_c_follower_recover_a_lock_tx_to_part(self):
|
||||
super().test_03_c_follower_recover_a_lock_tx_to_part()
|
||||
|
||||
def test_03_d_follower_recover_a_lock_tx_from_part(self):
|
||||
self.prepare_balance(Coins.BCH, 100.0, 1801, 1800)
|
||||
super().test_03_d_follower_recover_a_lock_tx_from_part()
|
||||
|
||||
def test_04_a_follower_recover_b_lock_tx(self):
|
||||
super().test_04_a_follower_recover_b_lock_tx()
|
||||
|
||||
# does not work yet
|
||||
# def test_04_b_follower_recover_b_lock_tx_reverse(self):
|
||||
# self.prepare_balance(Coins.BCH, 100.0, 1801, 1800)
|
||||
# super().test_04_b_follower_recover_b_lock_tx_reverse()
|
|
@ -105,7 +105,7 @@ class TestFunctions(BaseTest):
|
|||
id_bidder: int = self.node_b_id
|
||||
|
||||
swap_clients = self.swap_clients
|
||||
reverse_bid: bool = coin_from in swap_clients[id_offerer].scriptless_coins
|
||||
reverse_bid: bool = swap_clients[0].is_reverse_ads_bid(coin_from, coin_to)
|
||||
ci_from = swap_clients[id_offerer].ci(coin_from)
|
||||
ci_to = swap_clients[id_bidder].ci(coin_to)
|
||||
ci_part0 = swap_clients[id_offerer].ci(Coins.PART)
|
||||
|
@ -229,7 +229,7 @@ class TestFunctions(BaseTest):
|
|||
id_bidder: int = self.node_b_id
|
||||
|
||||
swap_clients = self.swap_clients
|
||||
reverse_bid: bool = coin_from in swap_clients[id_offerer].scriptless_coins
|
||||
reverse_bid: bool = swap_clients[0].is_reverse_ads_bid(coin_from, coin_to)
|
||||
ci_from = swap_clients[id_offerer].ci(coin_from)
|
||||
ci_to = swap_clients[id_offerer].ci(coin_to)
|
||||
|
||||
|
@ -274,7 +274,7 @@ class TestFunctions(BaseTest):
|
|||
id_bidder: int = self.node_b_id
|
||||
|
||||
swap_clients = self.swap_clients
|
||||
reverse_bid: bool = coin_from in swap_clients[id_offerer].scriptless_coins
|
||||
reverse_bid: bool = swap_clients[0].is_reverse_ads_bid(coin_from, coin_to)
|
||||
ci_from = swap_clients[id_offerer].ci(coin_from)
|
||||
ci_to = swap_clients[id_offerer].ci(coin_to)
|
||||
|
||||
|
@ -325,7 +325,7 @@ class TestFunctions(BaseTest):
|
|||
id_bidder: int = self.node_b_id
|
||||
|
||||
swap_clients = self.swap_clients
|
||||
reverse_bid: bool = coin_from in swap_clients[id_offerer].scriptless_coins
|
||||
reverse_bid: bool = swap_clients[0].is_reverse_ads_bid(coin_from, coin_to)
|
||||
ci_from = swap_clients[id_offerer].ci(coin_from)
|
||||
ci_to = swap_clients[id_offerer].ci(coin_to)
|
||||
|
||||
|
|
Loading…
Reference in a new issue