ui: Start describing xmr bid states.
This commit is contained in:
parent
b99fc48e89
commit
bf00f80b4d
@ -23,7 +23,6 @@ import sqlalchemy as sa
|
|||||||
import collections
|
import collections
|
||||||
import concurrent.futures
|
import concurrent.futures
|
||||||
|
|
||||||
from enum import IntEnum, auto
|
|
||||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||||
from sqlalchemy.orm.session import close_all_sessions
|
from sqlalchemy.orm.session import close_all_sessions
|
||||||
|
|
||||||
@ -93,314 +92,30 @@ from .explorers import (
|
|||||||
ExplorerBitAps,
|
ExplorerBitAps,
|
||||||
ExplorerChainz,
|
ExplorerChainz,
|
||||||
)
|
)
|
||||||
from .types import (
|
|
||||||
SEQUENCE_LOCK_BLOCKS,
|
|
||||||
SEQUENCE_LOCK_TIME,
|
|
||||||
ABS_LOCK_BLOCKS,
|
|
||||||
ABS_LOCK_TIME)
|
|
||||||
import basicswap.config as cfg
|
import basicswap.config as cfg
|
||||||
import basicswap.network as bsn
|
import basicswap.network as bsn
|
||||||
import basicswap.protocols.atomic_swap_1 as atomic_swap_1
|
import basicswap.protocols.atomic_swap_1 as atomic_swap_1
|
||||||
|
from .basicswap_util import (
|
||||||
|
SEQUENCE_LOCK_TIME,
|
||||||
class MessageTypes(IntEnum):
|
ABS_LOCK_BLOCKS,
|
||||||
OFFER = auto()
|
ABS_LOCK_TIME,
|
||||||
BID = auto()
|
MessageTypes,
|
||||||
BID_ACCEPT = auto()
|
SwapTypes,
|
||||||
|
OfferStates,
|
||||||
XMR_OFFER = auto()
|
BidStates,
|
||||||
XMR_BID_FL = auto()
|
TxStates,
|
||||||
XMR_BID_SPLIT = auto()
|
TxTypes,
|
||||||
XMR_BID_ACCEPT_LF = auto()
|
EventTypes,
|
||||||
XMR_BID_TXN_SIGS_FL = auto()
|
EventLogTypes,
|
||||||
XMR_BID_LOCK_SPEND_TX_LF = auto()
|
XmrSplitMsgTypes,
|
||||||
XMR_BID_LOCK_RELEASE_LF = auto()
|
DebugTypes,
|
||||||
OFFER_REVOKE = auto()
|
strBidState,
|
||||||
|
describeEventEntry,
|
||||||
|
getVoutByAddress,
|
||||||
class SwapTypes(IntEnum):
|
getVoutByP2WSH,
|
||||||
SELLER_FIRST = auto()
|
replaceAddrPrefix,
|
||||||
BUYER_FIRST = auto()
|
getOfferProofOfFundsHash,
|
||||||
SELLER_FIRST_2MSG = auto()
|
getLastBidState)
|
||||||
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()
|
|
||||||
|
|
||||||
|
|
||||||
def threadPollChainState(swap_client, coin_type):
|
def threadPollChainState(swap_client, coin_type):
|
||||||
@ -2213,7 +1928,12 @@ class BasicSwap(BaseApp):
|
|||||||
assert(bid), 'Bid not found: {}.'.format(bid_id.hex())
|
assert(bid), 'Bid not found: {}.'.format(bid_id.hex())
|
||||||
assert(xmr_swap), 'XMR swap 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.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)
|
offer, xmr_offer = self.getXmrOffer(bid.offer_id)
|
||||||
assert(offer), 'Offer not found: {}.'.format(bid.offer_id.hex())
|
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())
|
self.log.info('Received valid bid %s for xmr offer %s', bid.bid_id.hex(), bid.offer_id.hex())
|
||||||
|
|
||||||
bid.setState(BidStates.BID_RECEIVED)
|
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
|
# Auto accept bid if set and no other non-abandoned bid for this order exists
|
||||||
if offer.auto_accept_bids:
|
if offer.auto_accept_bids:
|
||||||
@ -4001,6 +3720,9 @@ class BasicSwap(BaseApp):
|
|||||||
delay = random.randrange(self.min_delay_event, self.max_delay_event)
|
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.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)
|
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):
|
def receiveXmrBidAccept(self, bid, session):
|
||||||
# Follower receiving MSG1F and MSG2F
|
# 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,
|
chainparams,
|
||||||
Coins,
|
Coins,
|
||||||
)
|
)
|
||||||
from .basicswap import (
|
from .basicswap_util import (
|
||||||
SwapTypes,
|
SwapTypes,
|
||||||
strOfferState,
|
strOfferState,
|
||||||
strBidState,
|
strBidState,
|
||||||
|
@ -62,7 +62,7 @@ from .contrib.test_framework.script import (
|
|||||||
SegwitV0SignatureHash,
|
SegwitV0SignatureHash,
|
||||||
hash160)
|
hash160)
|
||||||
|
|
||||||
from .types import (
|
from .basicswap_util import (
|
||||||
SEQUENCE_LOCK_BLOCKS,
|
SEQUENCE_LOCK_BLOCKS,
|
||||||
SEQUENCE_LOCK_TIME)
|
SEQUENCE_LOCK_TIME)
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import urllib.parse
|
|||||||
from .util import (
|
from .util import (
|
||||||
toBool,
|
toBool,
|
||||||
)
|
)
|
||||||
from .basicswap import (
|
from .basicswap_util import (
|
||||||
strBidState,
|
strBidState,
|
||||||
SwapTypes,
|
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>
|
<tr><td>Swap</td><td>{{ data.amt_from }} {{ data.ticker_from }} for {{ data.amt_to }} {{ data.ticker_to }}</td></tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<tr><td>Bid State</td><td>{{ data.bid_state }}</td></tr>
|
<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>ITX State</td><td>{{ data.itx_state }}</td></tr>
|
||||||
<tr><td>PTX State</td><td>{{ data.ptx_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>
|
<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>
|
<tr><td>Swap</td><td>{{ data.amt_from }} {{ data.ticker_from }} for {{ data.amt_to }} {{ data.ticker_to }}</td></tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<tr><td>Bid State</td><td>{{ data.bid_state }}</td></tr>
|
<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>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>Address From</td><td>{{ data.addr_from }}</td></tr>
|
||||||
<tr><td>Created At</td><td>{{ data.created_at }}</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 (
|
from .chainparams import (
|
||||||
Coins,
|
Coins,
|
||||||
)
|
)
|
||||||
from .basicswap import (
|
from .basicswap_util import (
|
||||||
|
SEQUENCE_LOCK_TIME,
|
||||||
SwapTypes,
|
SwapTypes,
|
||||||
BidStates,
|
BidStates,
|
||||||
TxStates,
|
TxStates,
|
||||||
@ -20,9 +21,7 @@ from .basicswap import (
|
|||||||
strTxType,
|
strTxType,
|
||||||
strBidState,
|
strBidState,
|
||||||
strTxState,
|
strTxState,
|
||||||
)
|
getLastBidState,
|
||||||
from .types import (
|
|
||||||
SEQUENCE_LOCK_TIME,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
PAGE_LIMIT = 50
|
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'
|
state_description = 'Bid abandoned'
|
||||||
elif bid.state == BidStates.BID_ERROR:
|
elif bid.state == BidStates.BID_ERROR:
|
||||||
state_description = bid.state_note
|
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 = {
|
data = {
|
||||||
'amt_from': ci_from.format_amount(bid.amount),
|
'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
|
- More swap protocols
|
||||||
- Manual method to set wallet seeds from particl mnemonic
|
- 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
|
- 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.ecc_util import i2b
|
||||||
from basicswap.interface_btc import BTCInterface
|
from basicswap.interface_btc import BTCInterface
|
||||||
from basicswap.interface_xmr import XMRInterface
|
from basicswap.interface_xmr import XMRInterface
|
||||||
|
|
||||||
|
from basicswap.basicswap_util import (
|
||||||
|
SEQUENCE_LOCK_BLOCKS,
|
||||||
|
SEQUENCE_LOCK_TIME)
|
||||||
from basicswap.util import (
|
from basicswap.util import (
|
||||||
SerialiseNum,
|
SerialiseNum,
|
||||||
DeserialiseNum,
|
DeserialiseNum,
|
||||||
make_int,
|
make_int,
|
||||||
format_amount,
|
format_amount,
|
||||||
validate_amount)
|
validate_amount)
|
||||||
from basicswap.types import (
|
|
||||||
SEQUENCE_LOCK_BLOCKS,
|
|
||||||
SEQUENCE_LOCK_TIME)
|
|
||||||
|
|
||||||
|
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
|
@ -32,6 +32,8 @@ from basicswap.basicswap import (
|
|||||||
BidStates,
|
BidStates,
|
||||||
TxStates,
|
TxStates,
|
||||||
DebugTypes,
|
DebugTypes,
|
||||||
|
)
|
||||||
|
from basicswap.basicswap_util import (
|
||||||
SEQUENCE_LOCK_BLOCKS,
|
SEQUENCE_LOCK_BLOCKS,
|
||||||
)
|
)
|
||||||
from basicswap.util import (
|
from basicswap.util import (
|
||||||
|
@ -25,6 +25,8 @@ from basicswap.basicswap import (
|
|||||||
SwapTypes,
|
SwapTypes,
|
||||||
BidStates,
|
BidStates,
|
||||||
DebugTypes,
|
DebugTypes,
|
||||||
|
)
|
||||||
|
from basicswap.basicswap_util import (
|
||||||
SEQUENCE_LOCK_BLOCKS,
|
SEQUENCE_LOCK_BLOCKS,
|
||||||
)
|
)
|
||||||
from basicswap.util import (
|
from basicswap.util import (
|
||||||
|
Loading…
Reference in New Issue
Block a user