mirror of
https://github.com/basicswap/basicswap.git
synced 2024-12-23 03:49:25 +00:00
ui: Start describing xmr bid states.
This commit is contained in:
parent
b99fc48e89
commit
bf00f80b4d
15 changed files with 542 additions and 373 deletions
|
@ -23,7 +23,6 @@ import sqlalchemy as sa
|
|||
import collections
|
||||
import concurrent.futures
|
||||
|
||||
from enum import IntEnum, auto
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
from sqlalchemy.orm.session import close_all_sessions
|
||||
|
||||
|
@ -93,314 +92,30 @@ from .explorers import (
|
|||
ExplorerBitAps,
|
||||
ExplorerChainz,
|
||||
)
|
||||
from .types import (
|
||||
SEQUENCE_LOCK_BLOCKS,
|
||||
SEQUENCE_LOCK_TIME,
|
||||
ABS_LOCK_BLOCKS,
|
||||
ABS_LOCK_TIME)
|
||||
import basicswap.config as cfg
|
||||
import basicswap.network as bsn
|
||||
import basicswap.protocols.atomic_swap_1 as atomic_swap_1
|
||||
|
||||
|
||||
class MessageTypes(IntEnum):
|
||||
OFFER = auto()
|
||||
BID = auto()
|
||||
BID_ACCEPT = auto()
|
||||
|
||||
XMR_OFFER = auto()
|
||||
XMR_BID_FL = auto()
|
||||
XMR_BID_SPLIT = auto()
|
||||
XMR_BID_ACCEPT_LF = auto()
|
||||
XMR_BID_TXN_SIGS_FL = auto()
|
||||
XMR_BID_LOCK_SPEND_TX_LF = auto()
|
||||
XMR_BID_LOCK_RELEASE_LF = auto()
|
||||
OFFER_REVOKE = auto()
|
||||
|
||||
|
||||
class SwapTypes(IntEnum):
|
||||
SELLER_FIRST = auto()
|
||||
BUYER_FIRST = auto()
|
||||
SELLER_FIRST_2MSG = auto()
|
||||
BUYER_FIRST_2MSG = auto()
|
||||
XMR_SWAP = auto()
|
||||
|
||||
|
||||
class OfferStates(IntEnum):
|
||||
OFFER_SENT = auto()
|
||||
OFFER_RECEIVED = auto()
|
||||
OFFER_ABANDONED = auto()
|
||||
|
||||
|
||||
class BidStates(IntEnum):
|
||||
BID_SENT = auto()
|
||||
BID_RECEIVING = auto() # Partially received
|
||||
BID_RECEIVED = auto()
|
||||
BID_RECEIVING_ACC = auto() # Partially received accept message
|
||||
BID_ACCEPTED = auto() # BidAcceptMessage received/sent
|
||||
SWAP_INITIATED = auto() # Initiate txn validated
|
||||
SWAP_PARTICIPATING = auto() # Participate txn validated
|
||||
SWAP_COMPLETED = auto() # All swap txns spent
|
||||
XMR_SWAP_SCRIPT_COIN_LOCKED = auto()
|
||||
XMR_SWAP_HAVE_SCRIPT_COIN_SPEND_TX = auto()
|
||||
XMR_SWAP_NOSCRIPT_COIN_LOCKED = auto()
|
||||
XMR_SWAP_LOCK_RELEASED = auto()
|
||||
XMR_SWAP_SCRIPT_TX_REDEEMED = auto()
|
||||
XMR_SWAP_NOSCRIPT_TX_REDEEMED = auto()
|
||||
XMR_SWAP_NOSCRIPT_TX_RECOVERED = auto()
|
||||
XMR_SWAP_FAILED_REFUNDED = auto()
|
||||
XMR_SWAP_FAILED_SWIPED = auto()
|
||||
XMR_SWAP_FAILED = auto()
|
||||
SWAP_DELAYING = auto()
|
||||
SWAP_TIMEDOUT = auto()
|
||||
BID_ABANDONED = auto() # Bid will no longer be processed
|
||||
BID_ERROR = auto() # An error occurred
|
||||
BID_STALLED_FOR_TEST = auto()
|
||||
|
||||
|
||||
class TxStates(IntEnum):
|
||||
TX_NONE = auto()
|
||||
TX_SENT = auto()
|
||||
TX_CONFIRMED = auto()
|
||||
TX_REDEEMED = auto()
|
||||
TX_REFUNDED = auto()
|
||||
|
||||
|
||||
class TxTypes(IntEnum):
|
||||
ITX = auto()
|
||||
PTX = auto()
|
||||
ITX_REDEEM = auto()
|
||||
ITX_REFUND = auto()
|
||||
PTX_REDEEM = auto()
|
||||
PTX_REFUND = auto()
|
||||
|
||||
XMR_SWAP_A_LOCK = auto()
|
||||
XMR_SWAP_A_LOCK_SPEND = auto()
|
||||
XMR_SWAP_A_LOCK_REFUND = auto()
|
||||
XMR_SWAP_A_LOCK_REFUND_SPEND = auto()
|
||||
XMR_SWAP_A_LOCK_REFUND_SWIPE = auto()
|
||||
XMR_SWAP_B_LOCK = auto()
|
||||
|
||||
|
||||
class EventTypes(IntEnum):
|
||||
ACCEPT_BID = auto()
|
||||
ACCEPT_XMR_BID = auto()
|
||||
SIGN_XMR_SWAP_LOCK_TX_A = auto()
|
||||
SEND_XMR_SWAP_LOCK_TX_A = auto()
|
||||
SEND_XMR_SWAP_LOCK_TX_B = auto()
|
||||
SEND_XMR_LOCK_RELEASE = auto()
|
||||
REDEEM_XMR_SWAP_LOCK_TX_A = auto() # Follower
|
||||
REDEEM_XMR_SWAP_LOCK_TX_B = auto() # Leader
|
||||
RECOVER_XMR_SWAP_LOCK_TX_B = auto()
|
||||
|
||||
|
||||
class EventLogTypes(IntEnum):
|
||||
FAILED_TX_B_LOCK_PUBLISH = auto()
|
||||
LOCK_TX_A_PUBLISHED = auto()
|
||||
LOCK_TX_B_PUBLISHED = auto()
|
||||
FAILED_TX_B_SPEND = auto()
|
||||
LOCK_TX_A_SEEN = auto()
|
||||
LOCK_TX_A_CONFIRMED = auto()
|
||||
LOCK_TX_B_SEEN = auto()
|
||||
LOCK_TX_B_CONFIRMED = auto()
|
||||
DEBUG_TWEAK_APPLIED = auto()
|
||||
FAILED_TX_B_REFUND = auto()
|
||||
LOCK_TX_B_INVALID = auto()
|
||||
LOCK_TX_A_REFUND_TX_PUBLISHED = auto()
|
||||
LOCK_TX_A_REFUND_SPEND_TX_PUBLISHED = auto()
|
||||
LOCK_TX_A_REFUND_SWIPE_TX_PUBLISHED = auto()
|
||||
LOCK_TX_B_REFUND_TX_PUBLISHED = auto()
|
||||
SYSTEM_WARNING = auto()
|
||||
LOCK_TX_A_SPEND_TX_PUBLISHED = auto()
|
||||
LOCK_TX_B_SPEND_TX_PUBLISHED = auto()
|
||||
|
||||
|
||||
class XmrSplitMsgTypes(IntEnum):
|
||||
BID = auto()
|
||||
BID_ACCEPT = auto()
|
||||
|
||||
|
||||
class DebugTypes(IntEnum):
|
||||
BID_STOP_AFTER_COIN_A_LOCK = auto()
|
||||
BID_DONT_SPEND_COIN_A_LOCK_REFUND = auto()
|
||||
CREATE_INVALID_COIN_B_LOCK = auto()
|
||||
BUYER_STOP_AFTER_ITX = auto()
|
||||
MAKE_INVALID_PTX = auto()
|
||||
|
||||
|
||||
def strOfferState(state):
|
||||
if state == OfferStates.OFFER_SENT:
|
||||
return 'Sent'
|
||||
if state == OfferStates.OFFER_RECEIVED:
|
||||
return 'Received'
|
||||
if state == OfferStates.OFFER_ABANDONED:
|
||||
return 'Abandoned'
|
||||
return 'Unknown'
|
||||
|
||||
|
||||
def strBidState(state):
|
||||
if state == BidStates.BID_SENT:
|
||||
return 'Sent'
|
||||
if state == BidStates.BID_RECEIVING:
|
||||
return 'Receiving'
|
||||
if state == BidStates.BID_RECEIVING_ACC:
|
||||
return 'Receiving accept'
|
||||
if state == BidStates.BID_RECEIVED:
|
||||
return 'Received'
|
||||
if state == BidStates.BID_ACCEPTED:
|
||||
return 'Accepted'
|
||||
if state == BidStates.SWAP_INITIATED:
|
||||
return 'Initiated'
|
||||
if state == BidStates.SWAP_PARTICIPATING:
|
||||
return 'Participating'
|
||||
if state == BidStates.SWAP_COMPLETED:
|
||||
return 'Completed'
|
||||
if state == BidStates.SWAP_TIMEDOUT:
|
||||
return 'Timed-out'
|
||||
if state == BidStates.BID_ABANDONED:
|
||||
return 'Abandoned'
|
||||
if state == BidStates.BID_STALLED_FOR_TEST:
|
||||
return 'Stalled (debug)'
|
||||
if state == BidStates.BID_ERROR:
|
||||
return 'Error'
|
||||
if state == BidStates.XMR_SWAP_SCRIPT_COIN_LOCKED:
|
||||
return 'Script coin locked'
|
||||
if state == BidStates.XMR_SWAP_HAVE_SCRIPT_COIN_SPEND_TX:
|
||||
return 'Script coin spend tx valid'
|
||||
if state == BidStates.XMR_SWAP_NOSCRIPT_COIN_LOCKED:
|
||||
return 'Scriptless coin locked'
|
||||
if state == BidStates.XMR_SWAP_LOCK_RELEASED:
|
||||
return 'Script coin lock released'
|
||||
if state == BidStates.XMR_SWAP_SCRIPT_TX_REDEEMED:
|
||||
return 'Script tx redeemed'
|
||||
if state == BidStates.XMR_SWAP_NOSCRIPT_TX_REDEEMED:
|
||||
return 'Scriptless tx redeemed'
|
||||
if state == BidStates.XMR_SWAP_NOSCRIPT_TX_RECOVERED:
|
||||
return 'Scriptless tx recovered'
|
||||
if state == BidStates.XMR_SWAP_FAILED_REFUNDED:
|
||||
return 'Failed, refunded'
|
||||
if state == BidStates.XMR_SWAP_FAILED_SWIPED:
|
||||
return 'Failed, swiped'
|
||||
if state == BidStates.XMR_SWAP_FAILED:
|
||||
return 'Failed'
|
||||
if state == BidStates.SWAP_DELAYING:
|
||||
return 'Delaying'
|
||||
return 'Unknown'
|
||||
|
||||
|
||||
def strTxState(state):
|
||||
if state == TxStates.TX_NONE:
|
||||
return 'None'
|
||||
if state == TxStates.TX_SENT:
|
||||
return 'Sent'
|
||||
if state == TxStates.TX_CONFIRMED:
|
||||
return 'Confirmed'
|
||||
if state == TxStates.TX_REDEEMED:
|
||||
return 'Redeemed'
|
||||
if state == TxStates.TX_REFUNDED:
|
||||
return 'Refunded'
|
||||
return 'Unknown'
|
||||
|
||||
|
||||
def strTxType(tx_type):
|
||||
if tx_type == TxTypes.XMR_SWAP_A_LOCK:
|
||||
return 'Chain A Lock Tx'
|
||||
if tx_type == TxTypes.XMR_SWAP_A_LOCK_SPEND:
|
||||
return 'Chain A Lock Spend Tx'
|
||||
if tx_type == TxTypes.XMR_SWAP_A_LOCK_REFUND:
|
||||
return 'Chain A Lock Refund Tx'
|
||||
if tx_type == TxTypes.XMR_SWAP_A_LOCK_REFUND_SPEND:
|
||||
return 'Chain A Lock Refund Spend Tx'
|
||||
if tx_type == TxTypes.XMR_SWAP_A_LOCK_REFUND_SWIPE:
|
||||
return 'Chain A Lock Refund Swipe Tx'
|
||||
if tx_type == TxTypes.XMR_SWAP_B_LOCK:
|
||||
return 'Chain B Lock Tx'
|
||||
return 'Unknown'
|
||||
|
||||
|
||||
def getLockName(lock_type):
|
||||
if lock_type == SEQUENCE_LOCK_BLOCKS:
|
||||
return 'Sequence lock, blocks'
|
||||
if lock_type == SEQUENCE_LOCK_TIME:
|
||||
return 'Sequence lock, time'
|
||||
if lock_type == ABS_LOCK_BLOCKS:
|
||||
return 'blocks'
|
||||
if lock_type == ABS_LOCK_TIME:
|
||||
return 'time'
|
||||
|
||||
|
||||
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:
|
||||
return 'Failed to publish lock tx B'
|
||||
if event_type == EventLogTypes.LOCK_TX_A_PUBLISHED:
|
||||
return 'Lock tx A published'
|
||||
if event_type == EventLogTypes.LOCK_TX_B_PUBLISHED:
|
||||
return 'Lock tx B published'
|
||||
if event_type == EventLogTypes.FAILED_TX_B_SPEND:
|
||||
return 'Failed to publish lock tx B spend'
|
||||
if event_type == EventLogTypes.LOCK_TX_A_SEEN:
|
||||
return 'Lock tx A seen in chain'
|
||||
if event_type == EventLogTypes.LOCK_TX_A_CONFIRMED:
|
||||
return 'Lock tx A confirmed in chain'
|
||||
if event_type == EventLogTypes.LOCK_TX_B_SEEN:
|
||||
return 'Lock tx B seen in chain'
|
||||
if event_type == EventLogTypes.LOCK_TX_B_CONFIRMED:
|
||||
return 'Lock tx B confirmed in chain'
|
||||
if event_type == EventLogTypes.DEBUG_TWEAK_APPLIED:
|
||||
return 'Debug tweak applied ' + event_msg
|
||||
if event_type == EventLogTypes.FAILED_TX_B_REFUND:
|
||||
return 'Failed to publish lock tx B refund'
|
||||
if event_type == EventLogTypes.LOCK_TX_B_INVALID:
|
||||
return 'Detected invalid lock Tx B'
|
||||
if event_type == EventLogTypes.LOCK_TX_A_REFUND_TX_PUBLISHED:
|
||||
return 'Lock tx A refund tx published'
|
||||
if event_type == EventLogTypes.LOCK_TX_A_REFUND_SPEND_TX_PUBLISHED:
|
||||
return 'Lock tx A refund spend tx published'
|
||||
if event_type == EventLogTypes.LOCK_TX_A_REFUND_SWIPE_TX_PUBLISHED:
|
||||
return 'Lock tx A refund swipe tx published'
|
||||
if event_type == EventLogTypes.LOCK_TX_B_REFUND_TX_PUBLISHED:
|
||||
return 'Lock tx B refund tx published'
|
||||
if event_type == EventLogTypes.LOCK_TX_A_SPEND_TX_PUBLISHED:
|
||||
return 'Lock tx A spend tx published'
|
||||
if event_type == EventLogTypes.LOCK_TX_B_SPEND_TX_PUBLISHED:
|
||||
return 'Lock tx B spend tx published'
|
||||
if event_type == EventLogTypes.SYSTEM_WARNING:
|
||||
return 'Warning: ' + event_msg
|
||||
|
||||
|
||||
def getVoutByAddress(txjs, p2sh):
|
||||
for o in txjs['vout']:
|
||||
try:
|
||||
if p2sh in o['scriptPubKey']['addresses']:
|
||||
return o['n']
|
||||
except Exception:
|
||||
pass
|
||||
raise ValueError('Address output not found in txn')
|
||||
|
||||
|
||||
def getVoutByP2WSH(txjs, p2wsh_hex):
|
||||
for o in txjs['vout']:
|
||||
try:
|
||||
if p2wsh_hex == o['scriptPubKey']['hex']:
|
||||
return o['n']
|
||||
except Exception:
|
||||
pass
|
||||
raise ValueError('P2WSH output not found in txn')
|
||||
|
||||
|
||||
def replaceAddrPrefix(addr, coin_type, chain_name, addr_type='pubkey_address'):
|
||||
return encodeAddress(bytes((chainparams[coin_type][chain_name][addr_type],)) + decodeAddress(addr)[1:])
|
||||
|
||||
|
||||
def getOfferProofOfFundsHash(offer_msg, offer_addr):
|
||||
# TODO: Hash must not include proof_of_funds sig if it exists in offer_msg
|
||||
h = hashlib.sha256()
|
||||
h.update(offer_addr.encode('utf-8'))
|
||||
offer_bytes = offer_msg.SerializeToString()
|
||||
h.update(offer_bytes)
|
||||
return h.digest()
|
||||
from .basicswap_util import (
|
||||
SEQUENCE_LOCK_TIME,
|
||||
ABS_LOCK_BLOCKS,
|
||||
ABS_LOCK_TIME,
|
||||
MessageTypes,
|
||||
SwapTypes,
|
||||
OfferStates,
|
||||
BidStates,
|
||||
TxStates,
|
||||
TxTypes,
|
||||
EventTypes,
|
||||
EventLogTypes,
|
||||
XmrSplitMsgTypes,
|
||||
DebugTypes,
|
||||
strBidState,
|
||||
describeEventEntry,
|
||||
getVoutByAddress,
|
||||
getVoutByP2WSH,
|
||||
replaceAddrPrefix,
|
||||
getOfferProofOfFundsHash,
|
||||
getLastBidState)
|
||||
|
||||
|
||||
def threadPollChainState(swap_client, coin_type):
|
||||
|
@ -2213,7 +1928,12 @@ class BasicSwap(BaseApp):
|
|||
assert(bid), 'Bid not found: {}.'.format(bid_id.hex())
|
||||
assert(xmr_swap), 'XMR swap not found: {}.'.format(bid_id.hex())
|
||||
assert(bid.expire_at > now), 'Bid expired'
|
||||
assert(bid.state == BidStates.BID_RECEIVED), 'Wrong bid state: {}'.format(str(BidStates(bid.state)))
|
||||
|
||||
last_bid_state = bid.state
|
||||
if last_bid_state == BidStates.SWAP_DELAYING:
|
||||
last_bid_state = getLastBidState(bid.states)
|
||||
|
||||
assert(last_bid_state == BidStates.BID_RECEIVED), 'Wrong bid state: {}'.format(str(BidStates(last_bid_state)))
|
||||
|
||||
offer, xmr_offer = self.getXmrOffer(bid.offer_id)
|
||||
assert(offer), 'Offer not found: {}.'.format(bid.offer_id.hex())
|
||||
|
@ -3989,7 +3709,6 @@ class BasicSwap(BaseApp):
|
|||
self.log.info('Received valid bid %s for xmr offer %s', bid.bid_id.hex(), bid.offer_id.hex())
|
||||
|
||||
bid.setState(BidStates.BID_RECEIVED)
|
||||
self.saveBidInSession(bid.bid_id, bid, session, xmr_swap)
|
||||
|
||||
# Auto accept bid if set and no other non-abandoned bid for this order exists
|
||||
if offer.auto_accept_bids:
|
||||
|
@ -4001,6 +3720,9 @@ class BasicSwap(BaseApp):
|
|||
delay = random.randrange(self.min_delay_event, self.max_delay_event)
|
||||
self.log.info('Auto accepting xmr bid %s in %d seconds', bid.bid_id.hex(), delay)
|
||||
self.createEventInSession(delay, EventTypes.ACCEPT_XMR_BID, bid.bid_id, session)
|
||||
bid.setState(BidStates.SWAP_DELAYING)
|
||||
|
||||
self.saveBidInSession(bid.bid_id, bid, session, xmr_swap)
|
||||
|
||||
def receiveXmrBidAccept(self, bid, session):
|
||||
# Follower receiving MSG1F and MSG2F
|
||||
|
|
338
basicswap/basicswap_util.py
Normal file
338
basicswap/basicswap_util.py
Normal file
|
@ -0,0 +1,338 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2021 tecnovert
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
import struct
|
||||
import hashlib
|
||||
from enum import IntEnum, auto
|
||||
from .util import (
|
||||
encodeAddress,
|
||||
decodeAddress,
|
||||
)
|
||||
from .chainparams import (
|
||||
chainparams,
|
||||
)
|
||||
|
||||
|
||||
SEQUENCE_LOCK_BLOCKS = 1
|
||||
SEQUENCE_LOCK_TIME = 2
|
||||
ABS_LOCK_BLOCKS = 3
|
||||
ABS_LOCK_TIME = 4
|
||||
|
||||
|
||||
class MessageTypes(IntEnum):
|
||||
OFFER = auto()
|
||||
BID = auto()
|
||||
BID_ACCEPT = auto()
|
||||
|
||||
XMR_OFFER = auto()
|
||||
XMR_BID_FL = auto()
|
||||
XMR_BID_SPLIT = auto()
|
||||
XMR_BID_ACCEPT_LF = auto()
|
||||
XMR_BID_TXN_SIGS_FL = auto()
|
||||
XMR_BID_LOCK_SPEND_TX_LF = auto()
|
||||
XMR_BID_LOCK_RELEASE_LF = auto()
|
||||
OFFER_REVOKE = auto()
|
||||
|
||||
|
||||
class SwapTypes(IntEnum):
|
||||
SELLER_FIRST = auto()
|
||||
BUYER_FIRST = auto()
|
||||
SELLER_FIRST_2MSG = auto()
|
||||
BUYER_FIRST_2MSG = auto()
|
||||
XMR_SWAP = auto()
|
||||
|
||||
|
||||
class OfferStates(IntEnum):
|
||||
OFFER_SENT = auto()
|
||||
OFFER_RECEIVED = auto()
|
||||
OFFER_ABANDONED = auto()
|
||||
|
||||
|
||||
class BidStates(IntEnum):
|
||||
BID_SENT = auto()
|
||||
BID_RECEIVING = auto() # Partially received
|
||||
BID_RECEIVED = auto()
|
||||
BID_RECEIVING_ACC = auto() # Partially received accept message
|
||||
BID_ACCEPTED = auto() # BidAcceptMessage received/sent
|
||||
SWAP_INITIATED = auto() # Initiate txn validated
|
||||
SWAP_PARTICIPATING = auto() # Participate txn validated
|
||||
SWAP_COMPLETED = auto() # All swap txns spent
|
||||
XMR_SWAP_SCRIPT_COIN_LOCKED = auto()
|
||||
XMR_SWAP_HAVE_SCRIPT_COIN_SPEND_TX = auto()
|
||||
XMR_SWAP_NOSCRIPT_COIN_LOCKED = auto()
|
||||
XMR_SWAP_LOCK_RELEASED = auto()
|
||||
XMR_SWAP_SCRIPT_TX_REDEEMED = auto()
|
||||
XMR_SWAP_NOSCRIPT_TX_REDEEMED = auto()
|
||||
XMR_SWAP_NOSCRIPT_TX_RECOVERED = auto()
|
||||
XMR_SWAP_FAILED_REFUNDED = auto()
|
||||
XMR_SWAP_FAILED_SWIPED = auto()
|
||||
XMR_SWAP_FAILED = auto()
|
||||
SWAP_DELAYING = auto()
|
||||
SWAP_TIMEDOUT = auto()
|
||||
BID_ABANDONED = auto() # Bid will no longer be processed
|
||||
BID_ERROR = auto() # An error occurred
|
||||
BID_STALLED_FOR_TEST = auto()
|
||||
BID_STATE_UNKNOWN = auto()
|
||||
|
||||
|
||||
class TxStates(IntEnum):
|
||||
TX_NONE = auto()
|
||||
TX_SENT = auto()
|
||||
TX_CONFIRMED = auto()
|
||||
TX_REDEEMED = auto()
|
||||
TX_REFUNDED = auto()
|
||||
|
||||
|
||||
class TxTypes(IntEnum):
|
||||
ITX = auto()
|
||||
PTX = auto()
|
||||
ITX_REDEEM = auto()
|
||||
ITX_REFUND = auto()
|
||||
PTX_REDEEM = auto()
|
||||
PTX_REFUND = auto()
|
||||
|
||||
XMR_SWAP_A_LOCK = auto()
|
||||
XMR_SWAP_A_LOCK_SPEND = auto()
|
||||
XMR_SWAP_A_LOCK_REFUND = auto()
|
||||
XMR_SWAP_A_LOCK_REFUND_SPEND = auto()
|
||||
XMR_SWAP_A_LOCK_REFUND_SWIPE = auto()
|
||||
XMR_SWAP_B_LOCK = auto()
|
||||
|
||||
|
||||
class EventTypes(IntEnum):
|
||||
ACCEPT_BID = auto()
|
||||
ACCEPT_XMR_BID = auto()
|
||||
SIGN_XMR_SWAP_LOCK_TX_A = auto()
|
||||
SEND_XMR_SWAP_LOCK_TX_A = auto()
|
||||
SEND_XMR_SWAP_LOCK_TX_B = auto()
|
||||
SEND_XMR_LOCK_RELEASE = auto()
|
||||
REDEEM_XMR_SWAP_LOCK_TX_A = auto() # Follower
|
||||
REDEEM_XMR_SWAP_LOCK_TX_B = auto() # Leader
|
||||
RECOVER_XMR_SWAP_LOCK_TX_B = auto()
|
||||
|
||||
|
||||
class EventLogTypes(IntEnum):
|
||||
FAILED_TX_B_LOCK_PUBLISH = auto()
|
||||
LOCK_TX_A_PUBLISHED = auto()
|
||||
LOCK_TX_B_PUBLISHED = auto()
|
||||
FAILED_TX_B_SPEND = auto()
|
||||
LOCK_TX_A_SEEN = auto()
|
||||
LOCK_TX_A_CONFIRMED = auto()
|
||||
LOCK_TX_B_SEEN = auto()
|
||||
LOCK_TX_B_CONFIRMED = auto()
|
||||
DEBUG_TWEAK_APPLIED = auto()
|
||||
FAILED_TX_B_REFUND = auto()
|
||||
LOCK_TX_B_INVALID = auto()
|
||||
LOCK_TX_A_REFUND_TX_PUBLISHED = auto()
|
||||
LOCK_TX_A_REFUND_SPEND_TX_PUBLISHED = auto()
|
||||
LOCK_TX_A_REFUND_SWIPE_TX_PUBLISHED = auto()
|
||||
LOCK_TX_B_REFUND_TX_PUBLISHED = auto()
|
||||
SYSTEM_WARNING = auto()
|
||||
LOCK_TX_A_SPEND_TX_PUBLISHED = auto()
|
||||
LOCK_TX_B_SPEND_TX_PUBLISHED = auto()
|
||||
|
||||
|
||||
class XmrSplitMsgTypes(IntEnum):
|
||||
BID = auto()
|
||||
BID_ACCEPT = auto()
|
||||
|
||||
|
||||
class DebugTypes(IntEnum):
|
||||
BID_STOP_AFTER_COIN_A_LOCK = auto()
|
||||
BID_DONT_SPEND_COIN_A_LOCK_REFUND = auto()
|
||||
CREATE_INVALID_COIN_B_LOCK = auto()
|
||||
BUYER_STOP_AFTER_ITX = auto()
|
||||
MAKE_INVALID_PTX = auto()
|
||||
|
||||
|
||||
def strOfferState(state):
|
||||
if state == OfferStates.OFFER_SENT:
|
||||
return 'Sent'
|
||||
if state == OfferStates.OFFER_RECEIVED:
|
||||
return 'Received'
|
||||
if state == OfferStates.OFFER_ABANDONED:
|
||||
return 'Abandoned'
|
||||
return 'Unknown'
|
||||
|
||||
|
||||
def strBidState(state):
|
||||
if state == BidStates.BID_SENT:
|
||||
return 'Sent'
|
||||
if state == BidStates.BID_RECEIVING:
|
||||
return 'Receiving'
|
||||
if state == BidStates.BID_RECEIVING_ACC:
|
||||
return 'Receiving accept'
|
||||
if state == BidStates.BID_RECEIVED:
|
||||
return 'Received'
|
||||
if state == BidStates.BID_ACCEPTED:
|
||||
return 'Accepted'
|
||||
if state == BidStates.SWAP_INITIATED:
|
||||
return 'Initiated'
|
||||
if state == BidStates.SWAP_PARTICIPATING:
|
||||
return 'Participating'
|
||||
if state == BidStates.SWAP_COMPLETED:
|
||||
return 'Completed'
|
||||
if state == BidStates.SWAP_TIMEDOUT:
|
||||
return 'Timed-out'
|
||||
if state == BidStates.BID_ABANDONED:
|
||||
return 'Abandoned'
|
||||
if state == BidStates.BID_STALLED_FOR_TEST:
|
||||
return 'Stalled (debug)'
|
||||
if state == BidStates.BID_ERROR:
|
||||
return 'Error'
|
||||
if state == BidStates.XMR_SWAP_SCRIPT_COIN_LOCKED:
|
||||
return 'Script coin locked'
|
||||
if state == BidStates.XMR_SWAP_HAVE_SCRIPT_COIN_SPEND_TX:
|
||||
return 'Script coin spend tx valid'
|
||||
if state == BidStates.XMR_SWAP_NOSCRIPT_COIN_LOCKED:
|
||||
return 'Scriptless coin locked'
|
||||
if state == BidStates.XMR_SWAP_LOCK_RELEASED:
|
||||
return 'Script coin lock released'
|
||||
if state == BidStates.XMR_SWAP_SCRIPT_TX_REDEEMED:
|
||||
return 'Script tx redeemed'
|
||||
if state == BidStates.XMR_SWAP_NOSCRIPT_TX_REDEEMED:
|
||||
return 'Scriptless tx redeemed'
|
||||
if state == BidStates.XMR_SWAP_NOSCRIPT_TX_RECOVERED:
|
||||
return 'Scriptless tx recovered'
|
||||
if state == BidStates.XMR_SWAP_FAILED_REFUNDED:
|
||||
return 'Failed, refunded'
|
||||
if state == BidStates.XMR_SWAP_FAILED_SWIPED:
|
||||
return 'Failed, swiped'
|
||||
if state == BidStates.XMR_SWAP_FAILED:
|
||||
return 'Failed'
|
||||
if state == BidStates.SWAP_DELAYING:
|
||||
return 'Delaying'
|
||||
return 'Unknown'
|
||||
|
||||
|
||||
def strTxState(state):
|
||||
if state == TxStates.TX_NONE:
|
||||
return 'None'
|
||||
if state == TxStates.TX_SENT:
|
||||
return 'Sent'
|
||||
if state == TxStates.TX_CONFIRMED:
|
||||
return 'Confirmed'
|
||||
if state == TxStates.TX_REDEEMED:
|
||||
return 'Redeemed'
|
||||
if state == TxStates.TX_REFUNDED:
|
||||
return 'Refunded'
|
||||
return 'Unknown'
|
||||
|
||||
|
||||
def strTxType(tx_type):
|
||||
if tx_type == TxTypes.XMR_SWAP_A_LOCK:
|
||||
return 'Chain A Lock Tx'
|
||||
if tx_type == TxTypes.XMR_SWAP_A_LOCK_SPEND:
|
||||
return 'Chain A Lock Spend Tx'
|
||||
if tx_type == TxTypes.XMR_SWAP_A_LOCK_REFUND:
|
||||
return 'Chain A Lock Refund Tx'
|
||||
if tx_type == TxTypes.XMR_SWAP_A_LOCK_REFUND_SPEND:
|
||||
return 'Chain A Lock Refund Spend Tx'
|
||||
if tx_type == TxTypes.XMR_SWAP_A_LOCK_REFUND_SWIPE:
|
||||
return 'Chain A Lock Refund Swipe Tx'
|
||||
if tx_type == TxTypes.XMR_SWAP_B_LOCK:
|
||||
return 'Chain B Lock Tx'
|
||||
return 'Unknown'
|
||||
|
||||
|
||||
def getLockName(lock_type):
|
||||
if lock_type == SEQUENCE_LOCK_BLOCKS:
|
||||
return 'Sequence lock, blocks'
|
||||
if lock_type == SEQUENCE_LOCK_TIME:
|
||||
return 'Sequence lock, time'
|
||||
if lock_type == ABS_LOCK_BLOCKS:
|
||||
return 'blocks'
|
||||
if lock_type == ABS_LOCK_TIME:
|
||||
return 'time'
|
||||
|
||||
|
||||
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:
|
||||
return 'Failed to publish lock tx B'
|
||||
if event_type == EventLogTypes.LOCK_TX_A_PUBLISHED:
|
||||
return 'Lock tx A published'
|
||||
if event_type == EventLogTypes.LOCK_TX_B_PUBLISHED:
|
||||
return 'Lock tx B published'
|
||||
if event_type == EventLogTypes.FAILED_TX_B_SPEND:
|
||||
return 'Failed to publish lock tx B spend'
|
||||
if event_type == EventLogTypes.LOCK_TX_A_SEEN:
|
||||
return 'Lock tx A seen in chain'
|
||||
if event_type == EventLogTypes.LOCK_TX_A_CONFIRMED:
|
||||
return 'Lock tx A confirmed in chain'
|
||||
if event_type == EventLogTypes.LOCK_TX_B_SEEN:
|
||||
return 'Lock tx B seen in chain'
|
||||
if event_type == EventLogTypes.LOCK_TX_B_CONFIRMED:
|
||||
return 'Lock tx B confirmed in chain'
|
||||
if event_type == EventLogTypes.DEBUG_TWEAK_APPLIED:
|
||||
return 'Debug tweak applied ' + event_msg
|
||||
if event_type == EventLogTypes.FAILED_TX_B_REFUND:
|
||||
return 'Failed to publish lock tx B refund'
|
||||
if event_type == EventLogTypes.LOCK_TX_B_INVALID:
|
||||
return 'Detected invalid lock Tx B'
|
||||
if event_type == EventLogTypes.LOCK_TX_A_REFUND_TX_PUBLISHED:
|
||||
return 'Lock tx A refund tx published'
|
||||
if event_type == EventLogTypes.LOCK_TX_A_REFUND_SPEND_TX_PUBLISHED:
|
||||
return 'Lock tx A refund spend tx published'
|
||||
if event_type == EventLogTypes.LOCK_TX_A_REFUND_SWIPE_TX_PUBLISHED:
|
||||
return 'Lock tx A refund swipe tx published'
|
||||
if event_type == EventLogTypes.LOCK_TX_B_REFUND_TX_PUBLISHED:
|
||||
return 'Lock tx B refund tx published'
|
||||
if event_type == EventLogTypes.LOCK_TX_A_SPEND_TX_PUBLISHED:
|
||||
return 'Lock tx A spend tx published'
|
||||
if event_type == EventLogTypes.LOCK_TX_B_SPEND_TX_PUBLISHED:
|
||||
return 'Lock tx B spend tx published'
|
||||
if event_type == EventLogTypes.SYSTEM_WARNING:
|
||||
return 'Warning: ' + event_msg
|
||||
|
||||
|
||||
def getVoutByAddress(txjs, p2sh):
|
||||
for o in txjs['vout']:
|
||||
try:
|
||||
if p2sh in o['scriptPubKey']['addresses']:
|
||||
return o['n']
|
||||
except Exception:
|
||||
pass
|
||||
raise ValueError('Address output not found in txn')
|
||||
|
||||
|
||||
def getVoutByP2WSH(txjs, p2wsh_hex):
|
||||
for o in txjs['vout']:
|
||||
try:
|
||||
if p2wsh_hex == o['scriptPubKey']['hex']:
|
||||
return o['n']
|
||||
except Exception:
|
||||
pass
|
||||
raise ValueError('P2WSH output not found in txn')
|
||||
|
||||
|
||||
def replaceAddrPrefix(addr, coin_type, chain_name, addr_type='pubkey_address'):
|
||||
return encodeAddress(bytes((chainparams[coin_type][chain_name][addr_type],)) + decodeAddress(addr)[1:])
|
||||
|
||||
|
||||
def getOfferProofOfFundsHash(offer_msg, offer_addr):
|
||||
# TODO: Hash must not include proof_of_funds sig if it exists in offer_msg
|
||||
h = hashlib.sha256()
|
||||
h.update(offer_addr.encode('utf-8'))
|
||||
offer_bytes = offer_msg.SerializeToString()
|
||||
h.update(offer_bytes)
|
||||
return h.digest()
|
||||
|
||||
|
||||
def getLastBidState(packed_states):
|
||||
num_states = len(packed_states) // 12
|
||||
if num_states < 2:
|
||||
return BidStates.BID_STATE_UNKNOWN
|
||||
return struct.unpack_from('<i', packed_states[(num_states - 2) * 12:])[0]
|
||||
try:
|
||||
num_states = len(packed_states) // 12
|
||||
if num_states < 2:
|
||||
return BidStates.BID_STATE_UNKNOWN
|
||||
return struct.unpack_from('<i', packed_states[(num_states - 2) * 12:])[0]
|
||||
except Exception:
|
||||
return BidStates.BID_STATE_UNKNOWN
|
|
@ -22,7 +22,7 @@ from .chainparams import (
|
|||
chainparams,
|
||||
Coins,
|
||||
)
|
||||
from .basicswap import (
|
||||
from .basicswap_util import (
|
||||
SwapTypes,
|
||||
strOfferState,
|
||||
strBidState,
|
||||
|
|
|
@ -62,7 +62,7 @@ from .contrib.test_framework.script import (
|
|||
SegwitV0SignatureHash,
|
||||
hash160)
|
||||
|
||||
from .types import (
|
||||
from .basicswap_util import (
|
||||
SEQUENCE_LOCK_BLOCKS,
|
||||
SEQUENCE_LOCK_TIME)
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import urllib.parse
|
|||
from .util import (
|
||||
toBool,
|
||||
)
|
||||
from .basicswap import (
|
||||
from .basicswap_util import (
|
||||
strBidState,
|
||||
SwapTypes,
|
||||
)
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<tr><td>Swap</td><td>{{ data.amt_from }} {{ data.ticker_from }} for {{ data.amt_to }} {{ data.ticker_to }}</td></tr>
|
||||
{% endif %}
|
||||
<tr><td>Bid State</td><td>{{ data.bid_state }}</td></tr>
|
||||
<tr><td>StateDescription </td><td>{{ data.state_description }}</td></tr>
|
||||
<tr><td>State Description </td><td>{{ data.state_description }}</td></tr>
|
||||
<tr><td>ITX State</td><td>{{ data.itx_state }}</td></tr>
|
||||
<tr><td>PTX State</td><td>{{ data.ptx_state }}</td></tr>
|
||||
<tr><td>Offer</td><td><a href="/offer/{{ data.offer_id }}">{{ data.offer_id }}</a></td></tr>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<tr><td>Swap</td><td>{{ data.amt_from }} {{ data.ticker_from }} for {{ data.amt_to }} {{ data.ticker_to }}</td></tr>
|
||||
{% endif %}
|
||||
<tr><td>Bid State</td><td>{{ data.bid_state }}</td></tr>
|
||||
<tr><td>StateDescription </td><td>{{ data.state_description }}</td></tr>
|
||||
<tr><td>State Description </td><td>{{ data.state_description }}</td></tr>
|
||||
<tr><td>Offer</td><td><a href="/offer/{{ data.offer_id }}">{{ data.offer_id }}</a></td></tr>
|
||||
<tr><td>Address From</td><td>{{ data.addr_from }}</td></tr>
|
||||
<tr><td>Created At</td><td>{{ data.created_at }}</td></tr>
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2021 tecnovert
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
SEQUENCE_LOCK_BLOCKS = 1
|
||||
SEQUENCE_LOCK_TIME = 2
|
||||
ABS_LOCK_BLOCKS = 3
|
||||
ABS_LOCK_TIME = 4
|
|
@ -12,7 +12,8 @@ from .util import (
|
|||
from .chainparams import (
|
||||
Coins,
|
||||
)
|
||||
from .basicswap import (
|
||||
from .basicswap_util import (
|
||||
SEQUENCE_LOCK_TIME,
|
||||
SwapTypes,
|
||||
BidStates,
|
||||
TxStates,
|
||||
|
@ -20,9 +21,7 @@ from .basicswap import (
|
|||
strTxType,
|
||||
strBidState,
|
||||
strTxState,
|
||||
)
|
||||
from .types import (
|
||||
SEQUENCE_LOCK_TIME,
|
||||
getLastBidState,
|
||||
)
|
||||
|
||||
PAGE_LIMIT = 50
|
||||
|
@ -164,6 +163,42 @@ def describeBid(swap_client, bid, xmr_swap, offer, xmr_offer, bid_events, edit_b
|
|||
state_description = 'Bid abandoned'
|
||||
elif bid.state == BidStates.BID_ERROR:
|
||||
state_description = bid.state_note
|
||||
elif offer.swap_type == SwapTypes.XMR_SWAP:
|
||||
if bid.state == BidStates.BID_RECEIVING:
|
||||
# Offerer receiving bid from bidder
|
||||
state_description = 'Waiting for bid to be fully received'
|
||||
elif bid.state == BidStates.BID_RECEIVED:
|
||||
# Offerer received bid from bidder
|
||||
# TODO: Manual vs automatic
|
||||
state_description = 'Bid must be accepted'
|
||||
elif bid.state == BidStates.BID_RECEIVING_ACC:
|
||||
state_description = 'Receiving accepted bid message'
|
||||
elif bid.state == BidStates.BID_ACCEPTED:
|
||||
state_description = 'Offerer has accepted bid, waiting for bidder to respond'
|
||||
elif bid.state == BidStates.SWAP_DELAYING:
|
||||
last_state = getLastBidState(bid.states)
|
||||
if last_state == BidStates.BID_RECEIVED:
|
||||
state_description = 'Delaying before accepting bid'
|
||||
elif last_state == BidStates.BID_RECEIVING_ACC:
|
||||
state_description = 'Delaying before responding to accepted bid'
|
||||
elif last_state == BidStates.XMR_SWAP_SCRIPT_TX_REDEEMED:
|
||||
state_description = f'Delaying before spending from {ticker_to} lock tx'
|
||||
elif last_state == BidStates.BID_ACCEPTED:
|
||||
state_description = f'Delaying before sending {ticker_from} lock tx'
|
||||
else:
|
||||
state_description = 'Delaying before automated action'
|
||||
elif bid.state == BidStates.XMR_SWAP_HAVE_SCRIPT_COIN_SPEND_TX:
|
||||
state_description = f'Waiting for {ticker_from} lock tx to confirm in chain'
|
||||
elif bid.state == BidStates.XMR_SWAP_SCRIPT_COIN_LOCKED:
|
||||
state_description = f'Waiting for {ticker_to} lock tx to confirm in chain'
|
||||
elif bid.state == BidStates.XMR_SWAP_NOSCRIPT_COIN_LOCKED:
|
||||
state_description = f'Waiting for offerer to unlock {ticker_from} lock tx'
|
||||
elif bid.state == BidStates.XMR_SWAP_LOCK_RELEASED:
|
||||
state_description = f'Waiting for bidder to spend from {ticker_from} lock tx'
|
||||
elif bid.state == BidStates.XMR_SWAP_SCRIPT_TX_REDEEMED:
|
||||
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'
|
||||
|
||||
data = {
|
||||
'amt_from': ci_from.format_amount(bid.amount),
|
||||
|
|
43
doc/notes.md
43
doc/notes.md
|
@ -13,46 +13,3 @@ Features still required (of many):
|
|||
- More swap protocols
|
||||
- Manual method to set wallet seeds from particl mnemonic
|
||||
- prepare script tries to load seeds automatically, btc versions < 0.21 require a fully synced chain
|
||||
|
||||
|
||||
## Seller first protocol:
|
||||
|
||||
Seller sends the 1st transaction.
|
||||
|
||||
1. Seller posts offer.
|
||||
- smsg from seller to network
|
||||
coin-from
|
||||
coin-to
|
||||
amount-from
|
||||
rate
|
||||
min-amount
|
||||
time-valid
|
||||
|
||||
2. Buyer posts bid:
|
||||
- smsg from buyer to seller
|
||||
offerid
|
||||
amount
|
||||
proof-of-funds
|
||||
address_to_buyer
|
||||
time-valid
|
||||
|
||||
3. Seller accepts bid:
|
||||
- verifies proof-of-funds
|
||||
- generates secret
|
||||
- submits initiate tx to coin-from network
|
||||
- smsg from seller to buyer
|
||||
txid
|
||||
initiatescript (includes pkhash_to_seller as the pkhash_refund)
|
||||
|
||||
4. Buyer participates:
|
||||
- inspects initiate tx in coin-from network
|
||||
- submits participate tx in coin-to network
|
||||
|
||||
5. Seller redeems:
|
||||
- constructs participatescript
|
||||
- inspects participate tx in coin-to network
|
||||
- redeems from participate tx revealing secret
|
||||
|
||||
6. Buyer redeems:
|
||||
- scans coin-to network for seller-redeem tx
|
||||
- redeems from initiate tx with revealed secret
|
||||
|
|
43
doc/protocols/seller_first.md
Normal file
43
doc/protocols/seller_first.md
Normal file
|
@ -0,0 +1,43 @@
|
|||
# Seller first protocol
|
||||
|
||||
Seller sends the first transaction.
|
||||
Both coin types must support scripts.
|
||||
|
||||
|
||||
1. Seller posts offer.
|
||||
- smsg from seller to network
|
||||
coin-from
|
||||
coin-to
|
||||
amount-from
|
||||
rate
|
||||
min-amount
|
||||
time-valid
|
||||
|
||||
2. Buyer posts bid:
|
||||
- smsg from buyer to seller
|
||||
offerid
|
||||
amount
|
||||
proof-of-funds
|
||||
address_to_buyer
|
||||
time-valid
|
||||
|
||||
3. Seller accepts bid:
|
||||
- verifies proof-of-funds
|
||||
- generates secret
|
||||
- submits initiate tx to coin-from network
|
||||
- smsg from seller to buyer
|
||||
txid
|
||||
initiatescript (includes pkhash_to_seller as the pkhash_refund)
|
||||
|
||||
4. Buyer participates:
|
||||
- inspects initiate tx in coin-from network
|
||||
- submits participate tx in coin-to network
|
||||
|
||||
5. Seller redeems:
|
||||
- constructs participatescript
|
||||
- inspects participate tx in coin-to network
|
||||
- redeems from participate tx revealing secret
|
||||
|
||||
6. Buyer redeems:
|
||||
- scans coin-to network for seller-redeem tx
|
||||
- redeems from initiate tx with revealed secret
|
79
doc/protocols/xmr.md
Normal file
79
doc/protocols/xmr.md
Normal file
|
@ -0,0 +1,79 @@
|
|||
# XMR protocol
|
||||
|
||||
|
||||
## WIP
|
||||
|
||||
Relies on a One-Time Verifiably Encrypted Signature (OtVES) to function
|
||||
An OtVES:
|
||||
- Is a valid signature for key (a) encrypted with a public key (B)
|
||||
- Can be decrypted into a valid signature for key (a) with the private key (b) to the encrypting public key (B)
|
||||
- The encrypting private key (b) can be recovered using both the encrypted and decrypted signatures.
|
||||
|
||||
|
||||
Leader - sends the first lock tx.
|
||||
|
||||
|
||||
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 (Leader) | Bidder (Follower) |
|
||||
------------------------------------------------------------------------|-------------------------------------------------------------------------------|
|
||||
o1. Sends offer | |
|
||||
- x SCRIPT_COIN for y NOSCRIPT_COIN | |
|
||||
- sends smsg OfferMessage | |
|
||||
| b1. Receives offer |
|
||||
| - validates offer |
|
||||
| b2. Sends bid |
|
||||
| - sends smsgs XmrBidMessage + 2x XmrSplitMessage |
|
||||
| |
|
||||
o2. Receives bid | |
|
||||
- validates bid | |
|
||||
o3. Accepts bid | |
|
||||
- sends smsgs XmrBidAcceptMessage + 2x XmrSplitMessage | |
|
||||
| |
|
||||
| b3. Receives bid accept |
|
||||
| - 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 | |
|
||||
| |
|
||||
| b4. Receives XmrBidLockSpendTxMessage |
|
||||
| - 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 | |
|
||||
spend tx. | |
|
||||
| |
|
||||
| b6. Receives offerer OtVES for SCRIPT_COIN lock spend tx. |
|
||||
| - 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 | |
|
||||
```
|
||||
|
||||
Offerer sent 6 smsgs (2 extra from split messages)
|
||||
Bidder sent 4 smsgs (2 extra from split messages)
|
||||
|
|
@ -24,15 +24,16 @@ from coincurve.keys import (
|
|||
from basicswap.ecc_util import i2b
|
||||
from basicswap.interface_btc import BTCInterface
|
||||
from basicswap.interface_xmr import XMRInterface
|
||||
|
||||
from basicswap.basicswap_util import (
|
||||
SEQUENCE_LOCK_BLOCKS,
|
||||
SEQUENCE_LOCK_TIME)
|
||||
from basicswap.util import (
|
||||
SerialiseNum,
|
||||
DeserialiseNum,
|
||||
make_int,
|
||||
format_amount,
|
||||
validate_amount)
|
||||
from basicswap.types import (
|
||||
SEQUENCE_LOCK_BLOCKS,
|
||||
SEQUENCE_LOCK_TIME)
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
|
|
|
@ -32,6 +32,8 @@ from basicswap.basicswap import (
|
|||
BidStates,
|
||||
TxStates,
|
||||
DebugTypes,
|
||||
)
|
||||
from basicswap.basicswap_util import (
|
||||
SEQUENCE_LOCK_BLOCKS,
|
||||
)
|
||||
from basicswap.util import (
|
||||
|
|
|
@ -25,6 +25,8 @@ from basicswap.basicswap import (
|
|||
SwapTypes,
|
||||
BidStates,
|
||||
DebugTypes,
|
||||
)
|
||||
from basicswap.basicswap_util import (
|
||||
SEQUENCE_LOCK_BLOCKS,
|
||||
)
|
||||
from basicswap.util import (
|
||||
|
|
Loading…
Reference in a new issue