diff --git a/basicswap/__init__.py b/basicswap/__init__.py index 70dbfc1..af2ffe5 100644 --- a/basicswap/__init__.py +++ b/basicswap/__init__.py @@ -1,3 +1,3 @@ name = "basicswap" -__version__ = "0.11.63" +__version__ = "0.11.64" diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py index bac529b..2f5952e 100644 --- a/basicswap/basicswap.py +++ b/basicswap/basicswap.py @@ -2515,7 +2515,7 @@ class BasicSwap(BaseApp): session.close() session.remove() - self.log.info('Sent XMR_BID_FL %s', xmr_swap.bid_id.hex()) + self.log.info('Sent ADS_BID_LF %s', xmr_swap.bid_id.hex()) return xmr_swap.bid_id msg_buf = XmrBidMessage() @@ -4100,15 +4100,14 @@ class BasicSwap(BaseApp): try: ci_part = self.ci(Coins.PART) rpc_conn = ci_part.open_rpc() - now: int = self.getTime() - options = {'encoding': 'none'} - ro = ci_part.json_request(rpc_conn, 'smsginbox', ['all', '', options]) - num_messages = 0 - num_removed = 0 - for msg in ro['messages']: + num_messages: int = 0 + num_removed: int = 0 + + def remove_if_expired(msg): + nonlocal num_messages, num_removed try: num_messages += 1 - expire_at = msg['sent'] + msg['ttl'] + expire_at: int = msg['sent'] + msg['ttl'] if expire_at < now: options = {'encoding': 'none', 'delete': True} del_msg = ci_part.json_request(rpc_conn, 'smsg', [msg['msgid'], options]) @@ -4116,7 +4115,15 @@ class BasicSwap(BaseApp): except Exception as e: if self.debug: self.log.error(traceback.format_exc()) - continue + + now: int = self.getTime() + options = {'encoding': 'none'} + inbox_messages = ci_part.json_request(rpc_conn, 'smsginbox', ['all', '', options])['messages'] + for msg in inbox_messages: + remove_if_expired(msg) + outbox_messages = ci_part.json_request(rpc_conn, 'smsgoutbox', ['all', '', options])['messages'] + for msg in outbox_messages: + remove_if_expired(msg) if num_messages + num_removed > 0: self.log.info('Expired {} / {} messages.'.format(num_removed, num_messages)) @@ -4481,15 +4488,23 @@ class BasicSwap(BaseApp): self.log.debug('Evaluating against strategy {}'.format(strategy.record_id)) if not offer.amount_negotiable: - if bid.amount != offer.amount_from: - raise AutomationConstraint('Need exact amount match') + if reverse_bid: + if abs(bid_amount - offer.amount_from) >= 20: # TODO: Tolerance? + raise AutomationConstraint('Need exact amount match') + else: + if bid_amount != offer.amount_from: + raise AutomationConstraint('Need exact amount match') if bid_amount < offer.min_bid_amount: raise AutomationConstraint('Bid amount below offer minimum') if opts.get('exact_rate_only', False) is True: - if bid_rate != offer.rate: - raise AutomationConstraint('Need exact rate match') + if reverse_bid: + if abs(bid_rate - offer.rate) >= 20: # TODO: Tolerance? + raise AutomationConstraint('Need exact rate match') + else: + if bid_rate != offer.rate: + raise AutomationConstraint('Need exact rate match') active_bids, total_bids_value = self.getCompletedAndActiveBidsValue(offer, use_session) diff --git a/basicswap/static/sequence_diagrams/xmr.bidder.alt.xu.min.svg b/basicswap/static/sequence_diagrams/ads.bidder.alt.xu.min.svg similarity index 100% rename from basicswap/static/sequence_diagrams/xmr.bidder.alt.xu.min.svg rename to basicswap/static/sequence_diagrams/ads.bidder.alt.xu.min.svg diff --git a/basicswap/static/sequence_diagrams/xmr.offerer.alt.xu.min.svg b/basicswap/static/sequence_diagrams/ads.offerer.alt.xu.min.svg similarity index 100% rename from basicswap/static/sequence_diagrams/xmr.offerer.alt.xu.min.svg rename to basicswap/static/sequence_diagrams/ads.offerer.alt.xu.min.svg diff --git a/basicswap/static/sequence_diagrams/ads.rev.bidder.xu.min.svg b/basicswap/static/sequence_diagrams/ads.rev.bidder.xu.min.svg new file mode 100644 index 0000000..42b23d2 --- /dev/null +++ b/basicswap/static/sequence_diagrams/ads.rev.bidder.xu.min.svg @@ -0,0 +1,391 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Network + + Offerer + + Bidder + + + + + + + Sends Offer + + + Detects Offer + + + Sends BidIntent message + + + Sends BidIntentAccept message + + + Sends BidAccept message + + + Sends XmrBidLockTxSigsMessage + + + Sends script-coin-lock-tx + + + Sends XmrBidLockSpendTxMessage + + + Wait for + + script-coin-lock-tx to + + confirm + + + Wait for + + script-coin-lock-tx to + + confirm + + + Sends noscript-coin-lock-tx + + + Wait for + + noscript-coin-lock-tx to + + confirm + + + Sends script-coin-lock-tx + + release message + + + Sends script-coin-lock-spend-tx + + + Detects script-coin-lock-spend-tx + + + Sends noscript-coin-lock-spend-tx + + + Wait for + + noscript-coin-lock-spend-tx + + to confirm + + + fail path + + + Wait for + + script-coin-lock-tx + + locktime to expire + + + Sends script-coin-lock-pre-refund-tx + + + script-coin-lock-pre-refund-tx + + + Wait for + + pre-refund tx to confirm + + + Sends script-coin-lock-pre-refund-spend-tx + + + + Bid Request sent + + User accepts bid + + The BidAccept message contains the pubkeys the offerer will use and a + DLEAG proof one key will work across both chains of the swapping coins + + Bid Receiving accept + + Bid Accepted + + The XmrBidLockTxSigsMessage contains the offerer's signatures for the + script-coin-lock-refund and script-coin-lock-refund-spend txns. + + Exchanged script lock tx sigs + msg + + Bid Script coin spend tx valid + + The XmrBidLockSpendTxMessage contains the script-coin-lock-tx and + proof the bidder can sign it. + + Exchanged script lock spend tx + msg + + Bid Script coin locked + + alt: success path + + Bid Scriptless coin locked + + The XmrBidLockReleaseMessage contains the bidder's OTVES for the + script-coin-lock-tx. The offerer decodes the + bidder's signature from the OTVES. When the + bidder has the plaintext signature, they can decode the offerer's key + for the noscript-lock-tx. + + Bid Script coin lock released + + Bid Script tx redeemed + + The bidder extracts the offerer's plaintext signature and derives the + offerer's noscript-lock-tx keyhalf. + + Bid Scriptless tx redeemed + + Bid Completed + + tx can be sent by either party. + + Bid Script pre-refund tx in + chain + + Refunds the script lock tx, with the bidder's cleartext signature the + offerer can refund the noscript lock tx. + + Bid Failed, refunded + + + diff --git a/basicswap/static/sequence_diagrams/ads.rev.offerer.xu.min.svg b/basicswap/static/sequence_diagrams/ads.rev.offerer.xu.min.svg new file mode 100644 index 0000000..f1b4199 --- /dev/null +++ b/basicswap/static/sequence_diagrams/ads.rev.offerer.xu.min.svg @@ -0,0 +1,420 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Network + + Offerer + + Bidder + + + + + + + Sends Offer + + + Detects Offer + + + Sends BidIntent message + + + Sends BidIntentAccept message + + + Sends BidAccept message + + + Sends XmrBidLockTxSigsMessage + + + Sends XmrBidLockSpendTxMessage + + + Sends script-coin-lock-tx + + + Wait for + + script-coin-lock-tx to + + confirm + + + Sends noscript-coin-lock-tx + + + Wait for + + noscript-coin-lock-tx to + + confirm + + + Wait for + + noscript-coin-lock-tx to + + confirm + + + Sends script-coin-lock-tx + + release message + + + Sends script-coin-lock-spend-tx + + + fail path + + + Wait for + + script-coin-lock-tx lock to + + expire + + + Sends script-coin-lock-pre-refund-tx + + + script-coin-lock-pre-refund-tx + + + Wait for + + pre-refund tx to confirm + + + Sends script-coin-lock-pre-refund-spend-tx + + + Detects + + script-coin-lock-pre-refund-spend-tx + + + Sends + + scriptless-coin-lock-recover-tx + + + offerer swipes script coin lock tx + + + Wait for + + pre-refund tx lock to expire + + + Sends + + script-coin-lock-pre-refund-swipe-tx + + + + Bid Received + + User accepts bid + + The BidAccept message contains the pubkeys the offerer will use and + a DLEAG proof one key will work across both chains of the swapping + coins + + The BidAccept message contains the pubkeys the bidder will use and a + DLEAG proof one key will work across both chains of the swapping coins + + Bid Accepted + + The XmrBidLockTxSigsMessage contains the offerer's signatures for + the script-coin-lock-refund and script-coin-lock-refund-spend txns. + + Exchanged script lock tx sigs + msg + + The XmrBidLockSpendTxMessage contains the script-coin-lock-tx and + proof the bidder can sign it. + + Bid Script coin spend tx valid + + Exchanged script lock spend tx + msg + + Bid Script coin locked + + Bid Scriptless coin locked + + alt: success path + + The XmrBidLockReleaseMessage contains the bidder's OTVES for it. + The offerer decodes the bidder's signature + from the OTVES. When the bidder has the + plaintext signature, they can decode the offerer's noscript-coin-lock-tx + signature. + + Script coin lock released + + Script tx redeemed + + Bid Completed + + tx can be sent by either party. + + Bid Script pre-refund tx in + chain + + alt: bidder refunds script coin lock tx + + Refunds the script lock tx, with the bidder's cleartext signature + the offerer can refund the noscript lock tx. + Once the lock expires the pre-refund tx can be spent by the offerer. + + Bid Failed, refunded + + offerer recovers the bidder's scriptless chain key-shard. + + Bid Scriptless tx recovered + + Bid Failed, refunded + + Bid Failed, swiped + + + diff --git a/basicswap/templates/bid_xmr.html b/basicswap/templates/bid_xmr.html index ebe093d..0915263 100644 --- a/basicswap/templates/bid_xmr.html +++ b/basicswap/templates/bid_xmr.html @@ -639,7 +639,11 @@
- + {% if data.reverse_bid %} + + {% else %} + + {% endif %}
@@ -673,7 +677,11 @@
- + {% if data.reverse_bid %} + + {% else %} + + {% endif %}
diff --git a/basicswap/ui/util.py b/basicswap/ui/util.py index 385af83..e109932 100644 --- a/basicswap/ui/util.py +++ b/basicswap/ui/util.py @@ -155,8 +155,8 @@ def describeBid(swap_client, bid, xmr_swap, offer, xmr_offer, bid_events, edit_b ci_leader = ci_to if reverse_bid else ci_from ci_follower = ci_from if reverse_bid else ci_to - bid_amount = bid.amount - bid_rate = offer.rate if bid.rate is None else bid.rate + bid_amount: int = bid.amount + bid_rate: int = offer.rate if bid.rate is None else bid.rate if reverse_bid: bid_amount, bid_rate = reverseBidAmountAndRate(swap_client, bid, offer) @@ -271,6 +271,7 @@ def describeBid(swap_client, bid, xmr_swap, offer, xmr_offer, bid_events, edit_b 'can_abandon': can_abandon, 'events': bid_events, 'debug_ui': swap_client.debug_ui, + 'reverse_bid': reverse_bid, } if edit_bid: diff --git a/doc/protocols/xmr.md b/doc/protocols/adaptor_sig.md similarity index 81% rename from doc/protocols/xmr.md rename to doc/protocols/adaptor_sig.md index c47e494..431afdc 100644 --- a/doc/protocols/xmr.md +++ b/doc/protocols/adaptor_sig.md @@ -1,4 +1,4 @@ -# XMR protocol +# Adaptor Signature Swap protocol ## WIP @@ -10,21 +10,24 @@ An OtVES: - The encrypting private key (b) can be recovered using both the encrypted and decrypted signatures. -Leader - sends the first lock tx. +Offerer - Sends the offer +Bidder - Sends the bid +Leader - Sends the first lock tx (ITX) +Follower - Sends the second lock tx (PTX) NOSCRIPT_COIN lock tx: - - sent second - - is sent to a combined key using a private key from each participant. + - Sent second. + - Is sent to a combined key using a private key from each participant. SCRIPT_COIN lock tx: - Sent first - Requires two signatures to spend from. - Refund to sender txn is presigned for and can only be mined in the future. - - Spending the refund tx reveals the leader's NOSCRIPT_COIN split private key + - Spending the refund tx reveals the leader's NOSCRIPT_COIN split private key. - Sender withholds signature until NOSCRIPT_COIN lock tx is confirmed. - - spending the spend txn reveals the follower's NOSCRIPT_COIN split private key + - spending the spend txn reveals the follower's NOSCRIPT_COIN split private key. ``` @@ -32,48 +35,49 @@ Offerer (Leader) | Bidder ------------------------------------------------------------------------|-------------------------------------------------------------------------------| o1. Sends offer | | - x SCRIPT_COIN for y NOSCRIPT_COIN | | - - sends smsg OfferMessage | | + - Sends smsg OfferMessage | | | b1. Receives offer | - | - validates offer | + | - Validates offer | | b2. Sends bid | - | - sends smsgs XmrBidMessage + 2x XmrSplitMessage | + | - Sends smsgs XmrBidMessage + 2x XmrSplitMessage | | | o2. Receives bid | | - - validates bid | | + - Validates bid | | o3. Accepts bid | | - - sends smsgs XmrBidAcceptMessage + 2x XmrSplitMessage | | + - Sends smsgs XmrBidAcceptMessage + 2x XmrSplitMessage | | | | | b3. Receives bid accept | - | - validates | - | - signs for lock tx refund | - | - sends smsg XmrBidLockTxSigsMessage | + | - Validates | + | - Signs for lock tx refund | + | - Sends smsg XmrBidLockTxSigsMessage | | | o4. Receives bidder lock refund tx signatures | | - - sends smsg XmrBidLockSpendTxMessage | | - - full SCRIPT_COIN lock tx | | - - signature to prove leader can sign for split key | | - - submits SCRIPT_COIN lock tx to network | | + - Sends smsg XmrBidLockSpendTxMessage | | + - Full SCRIPT_COIN lock tx | | + - Signature to prove leader can sign for split key | | + - Submits SCRIPT_COIN lock tx to network | | | | | b4. Receives XmrBidLockSpendTxMessage | - | - validates SCRIPT_COIN lock tx and signature | - | - waits for SCRIPT_COIN lock tx to confirm in chain | + | - Validates SCRIPT_COIN lock tx and signature | + | - Waits for SCRIPT_COIN lock tx to confirm in chain | | b5. Sends NOSCRIPT_COIN lock tx | | | o5. Waits for NOSCRIPT_COIN lock tx to confirm in chain | | o6. Sends SCRIPT_COIN lock release. | | - - sends smsg XmrBidLockReleaseMessage | | - - includes OtVES ciphertext signature for the SCRIPT_COIN lock | | + - Sends smsg XmrBidLockReleaseMessage | | + - Includes OtVES ciphertext signature for the SCRIPT_COIN lock | | spend tx. | | | | | b6. Receives offerer OtVES for SCRIPT_COIN lock spend tx. | - | - submits SCRIPT_COIN lock spend tx to network. | + | - Submits SCRIPT_COIN lock spend tx to network. | | | o7. Waits for SCRIPT_COIN lock spend tx. | | - Extracts the NOSCRIPT_COIN bidders key using the signature | | o8. Combines the keys to spend from the NOSCRIPT_COIN lock tx | | - - submits NOSCRIPT_COIN lock spend tx to network | | + - Submits NOSCRIPT_COIN lock spend tx to network | | ``` +Per swap (including the offer smsg): Offerer sent 6 smsgs (2 extra from split messages) Bidder sent 4 smsgs (2 extra from split messages) diff --git a/doc/protocols/adaptor_sig_reversed.md b/doc/protocols/adaptor_sig_reversed.md new file mode 100644 index 0000000..f323bfb --- /dev/null +++ b/doc/protocols/adaptor_sig_reversed.md @@ -0,0 +1,85 @@ +# Reverse Adaptor Signature Swap protocol + + + +## WIP + +Offerer - Sends the offer +Bidder - Sends the bid +Leader - Sends the first lock tx (ITX) +Follower - Sends the second lock tx (PTX) + + +The ITX must be sent from the script chain (coin A). +The side sending the ITX can be switched and the system can abstract to +users that the protocol is running in the opposite direction. + + +NOSCRIPT_COIN lock tx: + - Sent second. + - Is sent to a combined key using a private key from each participant. + + +SCRIPT_COIN lock tx: + - Sent first. + - Requires two signatures to spend from. + - Refund to sender txn is presigned for and can only be mined in the future. + - Spending the refund tx reveals the leader's NOSCRIPT_COIN split private key. + - Sender withholds signature until NOSCRIPT_COIN lock tx is confirmed. + - spending the spend txn reveals the follower's NOSCRIPT_COIN split private key. + + +``` +Offerer (Follower) | Bidder (Leader) | +------------------------------------------------------------------------|-------------------------------------------------------------------------------| +o1. Sends offer | | + - x NOSCRIPT_COIN for y SCRIPT_COIN | | + - Sends smsg OfferMessage | | + | b1. Receives offer | + | - Validates offer | + | b2. Sends bid intent message | + | - Sends smsg ADSBidIntentMessage | + | | +o2. Receives bid intent message | | + - Validates bid intent | | +o3. Accepts bid intent message | | + - Sends smsgs ADSBidIntentAcceptMessage + 2x XmrSplitMessage | | + | | + | b3. Receives bid intent message | + | - Sends smsgs XmrBidAcceptMessage + 2x XmrSplitMessage | + | | +o4. Receives bid accept | | + - Validates | | + - Signs for lock tx refund | | + - Sends smsg XmrBidLockTxSigsMessage | | + | | + | b4. Receives bidder lock refund tx signatures | + | - Sends smsg XmrBidLockSpendTxMessage | + | - Full SCRIPT_COIN lock tx | + | - Signature to prove leader can sign for split key | + | - Submits SCRIPT_COIN lock tx to network | + | | +o5. Receives XmrBidLockSpendTxMessage | | + - Validates SCRIPT_COIN lock tx and signature | | + - Waits for SCRIPT_COIN lock tx to confirm in chain | | +o6. Sends NOSCRIPT_COIN lock tx | | + | | + | b5. Waits for NOSCRIPT_COIN lock tx to confirm in chain | + | b6. Sends SCRIPT_COIN lock release. | + | - Sends smsg XmrBidLockReleaseMessage | + | - Includes OtVES ciphertext signature for the SCRIPT_COIN lock | + | spend tx. | + | | +o7. Receives leader OtVES for SCRIPT_COIN lock spend tx. | | + - Submits SCRIPT_COIN lock spend tx to network. | | + | | + | b7. Waits for SCRIPT_COIN lock spend tx. | + | - Extracts the NOSCRIPT_COIN follower's key using the signature | + | b8. Combines the keys to spend from the NOSCRIPT_COIN lock tx | + | - Submits NOSCRIPT_COIN lock spend tx to network | +``` + +Per swap (including the offer smsg): +Offerer sent 5 smsgs (2 extra from split messages) +Bidder sent 6 smsgs (2 extra from split messages) + diff --git a/doc/protocols/seller_first.md b/doc/protocols/secret_hash_seller_first.md similarity index 100% rename from doc/protocols/seller_first.md rename to doc/protocols/secret_hash_seller_first.md diff --git a/doc/protocols/sequence_diagrams/xmr.bidder.alt.xu b/doc/protocols/sequence_diagrams/ads.bidder.alt.xu similarity index 100% rename from doc/protocols/sequence_diagrams/xmr.bidder.alt.xu rename to doc/protocols/sequence_diagrams/ads.bidder.alt.xu diff --git a/doc/protocols/sequence_diagrams/xmr.offerer.alt.xu b/doc/protocols/sequence_diagrams/ads.offerer.alt.xu similarity index 100% rename from doc/protocols/sequence_diagrams/xmr.offerer.alt.xu rename to doc/protocols/sequence_diagrams/ads.offerer.alt.xu diff --git a/doc/protocols/sequence_diagrams/ads.rev.bidder.xu b/doc/protocols/sequence_diagrams/ads.rev.bidder.xu new file mode 100644 index 0000000..28189c8 --- /dev/null +++ b/doc/protocols/sequence_diagrams/ads.rev.bidder.xu @@ -0,0 +1,79 @@ +xu { + hscale="1.3", wordwraparcs=on; + + CB [label=" ", linecolor="transparent"], + N [label="Network", linecolor="#008800", textbgcolor="#CCFFCC", arclinecolor="#008800"], + O [label="Offerer", linecolor="#FF0000", textbgcolor="#FFCCCC", arclinecolor="#FF0000"], + B [label="Bidder", linecolor="#0000FF", textbgcolor="#CCCCFF", arclinecolor="#0000FF"], + C [label=" ", linecolor="transparent"], C2 [label=" ", linecolor="transparent"]; + O =>> N [label="Sends Offer"]; + N >> B [label="Detects Offer"]; + B =>> O [label="Sends BidIntent message"]; + B abox B [label="Bid Request sent"]; + O box O [label="User accepts bid"]; + O =>> B [label="Sends BidIntentAccept message"], + C note C2 + [label="The BidAccept message contains the pubkeys the offerer will use and a DLEAG proof one key will work across both chains of the swapping coins", + textbgcolor="#FFFFCC"]; + B abox B [label="Bid Receiving accept"]; + B =>> O [label="Sends BidAccept message"]; + B abox B [label="Bid Accepted"]; + + O =>> B [label="Sends XmrBidLockTxSigsMessage"], + C note C2 + [label="The XmrBidLockTxSigsMessage contains the offerer's signatures for the script-coin-lock-refund and script-coin-lock-refund-spend txns.", + textbgcolor="#FFFFCC"]; + B abox B [label="Exchanged script lock tx sigs msg"]; + B =>> N [label="Sends script-coin-lock-tx"]; + B abox B [label="Bid Script coin spend tx valid"]; + B =>> O [label="Sends XmrBidLockSpendTxMessage"], + C note C2 + [label="The XmrBidLockSpendTxMessage contains the script-coin-lock-tx and proof the bidder can sign it.", + textbgcolor="#FFFFCC"]; + B abox B [label="Exchanged script lock spend tx msg"]; + + |||; + O => O [label="Wait for script-coin-lock-tx to confirm"], B => B [label="Wait for script-coin-lock-tx to confirm"]; + B abox B [label="Bid Script coin locked"]; + CB alt C [label="success path"] { + O =>> N [label="Sends noscript-coin-lock-tx"]; + |||; + B => B [label="Wait for noscript-coin-lock-tx to confirm"]; + B abox B [label="Bid Scriptless coin locked"]; + B => O [label="Sends script-coin-lock-tx release message"], + C note C2 + [label="The XmrBidLockReleaseMessage contains the bidder's OTVES for the script-coin-lock-tx. + The offerer decodes the bidder's signature from the OTVES. + When the bidder has the plaintext signature, they can decode the offerer's key for the noscript-lock-tx.", + textbgcolor="#FFFFCC"]; + B abox B [label="Bid Script coin lock released"]; + O =>> N [label="Sends script-coin-lock-spend-tx"]; + N >> B [label="Detects script-coin-lock-spend-tx"]; + B abox B [label="Bid Script tx redeemed"], + C note C2 + [label="The bidder extracts the offerer's plaintext signature and derives the offerer's noscript-lock-tx keyhalf.", + textbgcolor="#FFFFCC"]; + B =>> N [label="Sends noscript-coin-lock-spend-tx"]; + B abox B [label="Bid Scriptless tx redeemed"]; + |||; + B => B [label="Wait for noscript-coin-lock-spend-tx to confirm"]; + B abox B [label="Bid Completed"]; + --- [label="fail path"]; + |||; + B => B [label="Wait for script-coin-lock-tx locktime to expire"]; + B =>> N [label="Sends script-coin-lock-pre-refund-tx"], + C note C2 + [label="tx can be sent by either party.", + textbgcolor="#FFFFCC"]; + N >> B [label="script-coin-lock-pre-refund-tx"]; + B abox B [label="Bid Script pre-refund tx in chain"]; + |||; + B => B [label="Wait for pre-refund tx to confirm"]; + B =>> N [label="Sends script-coin-lock-pre-refund-spend-tx"], + C note C2 + [label="Refunds the script lock tx, with the bidder's cleartext signature the offerer can refund the noscript lock tx.", + textbgcolor="#FFFFCC"]; + B abox B [label="Bid Failed, refunded"]; + }; +} + diff --git a/doc/protocols/sequence_diagrams/ads.rev.offerer.xu b/doc/protocols/sequence_diagrams/ads.rev.offerer.xu new file mode 100644 index 0000000..7c919de --- /dev/null +++ b/doc/protocols/sequence_diagrams/ads.rev.offerer.xu @@ -0,0 +1,86 @@ +xu { + hscale="1.3", wordwraparcs=on; + + CB [label=" ", linecolor="transparent"], + N [label="Network", linecolor="#008800", textbgcolor="#CCFFCC", arclinecolor="#008800"], + O [label="Offerer", linecolor="#FF0000", textbgcolor="#FFCCCC", arclinecolor="#FF0000"], + B [label="Bidder", linecolor="#0000FF", textbgcolor="#CCCCFF", arclinecolor="#0000FF"], + C [label=" ", linecolor="transparent"], C2 [label=" ", linecolor="transparent"]; + O =>> N [label="Sends Offer"]; + N >> B [label="Detects Offer"]; + B =>> O [label="Sends BidIntent message"]; + O abox O [label="Bid Received"]; + O box O [label="User accepts bid"]; + O =>> B [label="Sends BidIntentAccept message"], + C note C2 + [label="The BidAccept message contains the pubkeys the offerer will use and a DLEAG proof one key will work across both chains of the swapping coins", + textbgcolor="#FFFFCC"]; + B =>> O [label="Sends BidAccept message"], + C note C2 + [label="The BidAccept message contains the pubkeys the bidder will use and a DLEAG proof one key will work across both chains of the swapping coins", + textbgcolor="#FFFFCC"]; + O abox O [label="Bid Accepted"]; + + + O =>> B [label="Sends XmrBidLockTxSigsMessage"], + C note C2 + [label="The XmrBidLockTxSigsMessage contains the offerer's signatures for the script-coin-lock-refund and script-coin-lock-refund-spend txns.", + textbgcolor="#FFFFCC"]; + O abox O [label="Exchanged script lock tx sigs msg"]; + B =>> O [label="Sends XmrBidLockSpendTxMessage"], + C note C2 + [label="The XmrBidLockSpendTxMessage contains the script-coin-lock-tx and proof the bidder can sign it.", + textbgcolor="#FFFFCC"]; + B =>> N [label="Sends script-coin-lock-tx"], + O abox O [label="Bid Script coin spend tx valid"]; + O abox O [label="Exchanged script lock spend tx msg"]; + O => O [label="Wait for script-coin-lock-tx to confirm"]; + O abox O [label="Bid Script coin locked"]; + # offerer would only send noscript-coin-lock-tx if script-coin-lock-tx validates + O =>> N [label="Sends noscript-coin-lock-tx"]; + O => O [label="Wait for noscript-coin-lock-tx to confirm"], B => B [label="Wait for noscript-coin-lock-tx to confirm"]; + O abox O [label="Bid Scriptless coin locked"]; + CB alt C [label="success path"] { + B => O [label="Sends script-coin-lock-tx release message"], + C note C2 + [label="The XmrBidLockReleaseMessage contains the bidder's OTVES for it. + The offerer decodes the bidder's signature from the OTVES. + When the bidder has the plaintext signature, they can decode the offerer's noscript-coin-lock-tx signature.", + textbgcolor="#FFFFCC"]; + O abox O [label="Script coin lock released"]; + O =>> N [label="Sends script-coin-lock-spend-tx"]; + O abox O [label="Script tx redeemed"]; + O abox O [label="Bid Completed"]; + --- [label="fail path"]; + |||; + O => O [label="Wait for script-coin-lock-tx lock to expire"]; + B =>> N [label="Sends script-coin-lock-pre-refund-tx"], + C note C2 + [label="tx can be sent by either party.", + textbgcolor="#FFFFCC"]; + N >> B [label="script-coin-lock-pre-refund-tx"]; + O abox O [label="Bid Script pre-refund tx in chain"]; + CB alt C [label="bidder refunds script coin lock tx"] { + |||; + B => B [label="Wait for pre-refund tx to confirm"]; + B =>> N [label="Sends script-coin-lock-pre-refund-spend-tx"], + C note C2 + [label="Refunds the script lock tx, with the bidder's cleartext signature the offerer can refund the noscript lock tx. + Once the lock expires the pre-refund tx can be spent by the offerer.", + textbgcolor="#FFFFCC"]; + B abox B [label="Bid Failed, refunded"]; + N >> O [label="Detects script-coin-lock-pre-refund-spend-tx"], + C note C2 + [label="offerer recovers the bidder's scriptless chain key-shard.", + textbgcolor="#FFFFCC"]; + O =>> N [label="Sends scriptless-coin-lock-recover-tx"]; + O abox O [label="Bid Scriptless tx recovered"]; + O abox O [label="Bid Failed, refunded"]; + --- [label="offerer swipes script coin lock tx"]; + |||; + O => O [label="Wait for pre-refund tx lock to expire"]; + O =>> N [label="Sends script-coin-lock-pre-refund-swipe-tx"]; + O abox O [label="Bid Failed, swiped"]; + }; + }; +} diff --git a/doc/protocols/sequence_diagrams/notes.txt b/doc/protocols/sequence_diagrams/notes.txt index e8e0c97..04d0c14 100644 --- a/doc/protocols/sequence_diagrams/notes.txt +++ b/doc/protocols/sequence_diagrams/notes.txt @@ -11,13 +11,17 @@ npm install -g mscgenjs-cli mscgenjs -T svg -i bidder.alt.xu -o bidder.alt.xu.svg mscgenjs -T svg -i offerer.alt.xu -o offerer.alt.xu.svg -mscgenjs -T svg -i xmr.bidder.alt.xu -o xmr.bidder.alt.xu.svg -mscgenjs -T svg -i xmr.offerer.alt.xu -o xmr.offerer.alt.xu.svg +mscgenjs -T svg -i ads.bidder.alt.xu -o ads.bidder.alt.xu.svg +mscgenjs -T svg -i ads.offerer.alt.xu -o ads.offerer.alt.xu.svg +mscgenjs -T svg -i ads.rev.bidder.xu -o ads.rev.bidder.xu.svg +mscgenjs -T svg -i ads.rev.offerer.xu -o ads.rev.offerer.xu.svg npm -g install svgo svgo --pretty bidder.alt.xu.svg -o bidder.alt.xu.min.svg svgo --pretty offerer.alt.xu.svg -o offerer.alt.xu.min.svg -svgo --pretty xmr.bidder.alt.xu.svg -o xmr.bidder.alt.xu.min.svg -svgo --pretty xmr.offerer.alt.xu.svg -o xmr.offerer.alt.xu.min.svg +svgo --pretty ads.bidder.alt.xu.svg -o ads.bidder.alt.xu.min.svg +svgo --pretty ads.offerer.alt.xu.svg -o ads.offerer.alt.xu.min.svg +svgo --pretty ads.rev.bidder.xu.svg -o ads.rev.bidder.xu.min.svg +svgo --pretty ads.rev.offerer.xu.svg -o ads.rev.offerer.xu.min.svg diff --git a/doc/release-notes.md b/doc/release-notes.md index a542738..7584adc 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,4 +1,13 @@ +0.0.64 +============== + +- protocol: Added reversed Adaptor sig protocol. + - Runs the adaptor-sig protocol with leader and follower swapped to + enable offers from no-script coins to script coins. +- smsg: Outbox messages are removed when expired. + + 0.0.63 ============== diff --git a/tests/basicswap/test_btc_xmr.py b/tests/basicswap/test_btc_xmr.py index 687dd10..b960615 100644 --- a/tests/basicswap/test_btc_xmr.py +++ b/tests/basicswap/test_btc_xmr.py @@ -279,8 +279,22 @@ class BasicSwapTest(BaseTest): logging.info('---------- Test {} to {}'.format(coin_from.name, coin_to.name)) swap_clients = self.swap_clients + reverse_bid: bool = coin_from in swap_clients[0].scriptless_coins ci_from = swap_clients[0].ci(coin_from) ci_to = swap_clients[1].ci(coin_to) + ci_part0 = swap_clients[0].ci(Coins.PART) + ci_part1 = swap_clients[1].ci(Coins.PART) + + # Offerer sends the offer + # Bidder sends the bid + id_offerer: int = 0 + id_bidder: int = 1 + + # Leader sends the initial (chain a) lock tx. + # Follower sends the participate (chain b) lock tx. + id_leader: int = 1 if reverse_bid else 0 + id_follower: int = 0 if reverse_bid else 1 + logging.info(f'Offerer, bidder, leader, follower: {id_offerer}, {id_bidder}, {id_leader}, {id_follower}') js_0 = read_json_api(1800, 'wallets') node0_from_before = self.getBalance(js_0, coin_from) @@ -291,20 +305,23 @@ class BasicSwapTest(BaseTest): js_0_to = read_json_api(1800, 'wallets/{}'.format(coin_to.name.lower())) js_1_to = read_json_api(1801, 'wallets/{}'.format(coin_to.name.lower())) + node0_sent_messages_before: int = ci_part0.rpc_callback('smsgoutbox', ['count',])['num_messages'] + node1_sent_messages_before: int = ci_part1.rpc_callback('smsgoutbox', ['count',])['num_messages'] + amt_swap = ci_from.make_int(random.uniform(0.1, 2.0), r=1) rate_swap = ci_to.make_int(random.uniform(0.2, 20.0), r=1) - offer_id = swap_clients[0].postOffer(coin_from, coin_to, amt_swap, rate_swap, amt_swap, SwapTypes.XMR_SWAP) - wait_for_offer(test_delay_event, swap_clients[1], offer_id) - offers = swap_clients[0].listOffers(filters={'offer_id': offer_id}) - offer = offers[0] + offer_id = swap_clients[id_offerer].postOffer(coin_from, coin_to, amt_swap, rate_swap, amt_swap, SwapTypes.XMR_SWAP) + wait_for_offer(test_delay_event, swap_clients[id_bidder], offer_id) + offer = swap_clients[id_bidder].listOffers(filters={'offer_id': offer_id})[0] + assert (offer.offer_id == 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[0].acceptBid(bid_id) + wait_for_bid(test_delay_event, swap_clients[id_offerer], bid_id, BidStates.BID_RECEIVED) + swap_clients[id_offerer].acceptBid(bid_id) - wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180) - wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True) + wait_for_bid(test_delay_event, swap_clients[id_offerer], bid_id, BidStates.SWAP_COMPLETED, wait_for=180) + wait_for_bid(test_delay_event, swap_clients[id_bidder], bid_id, BidStates.SWAP_COMPLETED, sent=True) amount_from = float(ci_from.format_amount(amt_swap)) js_1 = read_json_api(1801, 'wallets') @@ -328,6 +345,13 @@ class BasicSwapTest(BaseTest): if False: # TODO: set stakeaddress and xmr rewards to non wallet addresses assert (node1_to_after < node1_to_before - amount_to_float) + node0_sent_messages_after: int = ci_part0.rpc_callback('smsgoutbox', ['count',])['num_messages'] + node1_sent_messages_after: int = ci_part1.rpc_callback('smsgoutbox', ['count',])['num_messages'] + node0_sent_messages: int = node0_sent_messages_after - node0_sent_messages_before + node1_sent_messages: int = node1_sent_messages_after - node1_sent_messages_before + assert (node0_sent_messages == (5 if reverse_bid else 6)) + assert (node1_sent_messages == (6 if reverse_bid else 4)) + def test_01_a_full_swap(self): if not self.has_segwit: return @@ -355,13 +379,8 @@ class BasicSwapTest(BaseTest): ci_from = swap_clients[0].ci(coin_from) ci_to = swap_clients[0].ci(coin_to) - # Offerer sends the offer - # Bidder sends the bid id_offerer: int = 0 id_bidder: int = 1 - - # Leader sends the initial (chain a) lock tx. - # Follower sends the participate (chain b) lock tx. id_leader: int = 1 if reverse_bid else 0 id_follower: int = 0 if reverse_bid else 1 logging.info(f'Offerer, bidder, leader, follower: {id_offerer}, {id_bidder}, {id_leader}, {id_follower}') diff --git a/tests/basicswap/test_xmr.py b/tests/basicswap/test_xmr.py index 9f6ac1a..8f4515e 100644 --- a/tests/basicswap/test_xmr.py +++ b/tests/basicswap/test_xmr.py @@ -347,8 +347,8 @@ class BaseTest(unittest.TestCase): logger.addHandler(stream_stdout) diagrams_dir = 'doc/protocols/sequence_diagrams' - cls.states_bidder = extract_states_from_xu_file(os.path.join(diagrams_dir, 'xmr.bidder.alt.xu'), 'B') - cls.states_offerer = extract_states_from_xu_file(os.path.join(diagrams_dir, 'xmr.offerer.alt.xu'), 'O') + cls.states_bidder = extract_states_from_xu_file(os.path.join(diagrams_dir, 'ads.bidder.alt.xu'), 'B') + cls.states_offerer = extract_states_from_xu_file(os.path.join(diagrams_dir, 'ads.offerer.alt.xu'), 'O') if os.path.isdir(TEST_DIR): if RESET_TEST: