diff --git a/basicswap/__init__.py b/basicswap/__init__.py index e10d01d..f48cb4b 100644 --- a/basicswap/__init__.py +++ b/basicswap/__init__.py @@ -1,3 +1,3 @@ name = "basicswap" -__version__ = "0.12.7" +__version__ = "0.13.0" diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py index c48508a..3b1da83 100644 --- a/basicswap/basicswap.py +++ b/basicswap/basicswap.py @@ -147,11 +147,11 @@ from basicswap.db_util import ( remove_expired_data, ) -PROTOCOL_VERSION_SECRET_HASH = 3 -MINPROTO_VERSION_SECRET_HASH = 2 +PROTOCOL_VERSION_SECRET_HASH = 4 +MINPROTO_VERSION_SECRET_HASH = 4 -PROTOCOL_VERSION_ADAPTOR_SIG = 3 -MINPROTO_VERSION_ADAPTOR_SIG = 3 +PROTOCOL_VERSION_ADAPTOR_SIG = 4 +MINPROTO_VERSION_ADAPTOR_SIG = 4 def validOfferStateToReceiveBid(offer_state): @@ -1455,14 +1455,13 @@ class BasicSwap(BaseApp): finally: self.closeSession(session) - def validateOfferAmounts(self, coin_from, coin_to, amount: int, rate: int, min_bid_amount: int) -> None: + def validateOfferAmounts(self, coin_from, coin_to, amount: int, amount_to: int, min_bid_amount: int) -> None: ci_from = self.ci(coin_from) ci_to = self.ci(coin_to) ensure(amount >= min_bid_amount, 'amount < min_bid_amount') ensure(amount > ci_from.min_amount(), 'From amount below min value for chain') ensure(amount < ci_from.max_amount(), 'From amount above max value for chain') - amount_to = int((amount * rate) // ci_from.COIN()) ensure(amount_to > ci_to.min_amount(), 'To amount below min value for chain') ensure(amount_to < ci_to.max_amount(), 'To amount above max value for chain') @@ -1524,7 +1523,7 @@ class BasicSwap(BaseApp): return extra_options['addr_send_to'] return self.network_addr - def postOffer(self, coin_from, coin_to, amount: int, rate, min_bid_amount: int, swap_type, + def postOffer(self, coin_from, coin_to, amount: int, rate: int, min_bid_amount: int, swap_type, lock_type=TxLockTypes.SEQUENCE_LOCK_TIME, lock_value: int = 48 * 60 * 60, auto_accept_bids: bool = False, addr_send_from: str = None, extra_options={}) -> bytes: # Offer to send offer.amount_from of coin_from in exchange for offer.amount_from * offer.rate of coin_to @@ -1540,10 +1539,14 @@ class BasicSwap(BaseApp): except Exception: raise ValueError('Unknown coin to type') - valid_for_seconds = extra_options.get('valid_for_seconds', 60 * 60) + valid_for_seconds: int = extra_options.get('valid_for_seconds', 60 * 60) + amount_to: int = extra_options.get('amount_to', int((amount * rate) // ci_from.COIN())) + + # Recalculate the rate so it will match the bid rate + rate = ci_from.make_int(amount_to / amount, r=1) self.validateSwapType(coin_from_t, coin_to_t, swap_type) - self.validateOfferAmounts(coin_from_t, coin_to_t, amount, rate, min_bid_amount) + self.validateOfferAmounts(coin_from_t, coin_to_t, amount, amount_to, min_bid_amount) self.validateOfferLockValue(swap_type, coin_from_t, coin_to_t, lock_type, lock_value) self.validateOfferValidTime(swap_type, coin_from_t, coin_to_t, valid_for_seconds) @@ -1564,7 +1567,7 @@ class BasicSwap(BaseApp): msg_buf.coin_from = int(coin_from) msg_buf.coin_to = int(coin_to) msg_buf.amount_from = int(amount) - msg_buf.rate = int(rate) + msg_buf.amount_to = int(amount_to) msg_buf.min_bid_amount = int(min_bid_amount) msg_buf.time_valid = valid_for_seconds @@ -1644,7 +1647,8 @@ class BasicSwap(BaseApp): coin_from=msg_buf.coin_from, coin_to=msg_buf.coin_to, amount_from=msg_buf.amount_from, - rate=msg_buf.rate, + amount_to=msg_buf.amount_to, + rate=rate, min_bid_amount=msg_buf.min_bid_amount, time_valid=msg_buf.time_valid, lock_type=int(msg_buf.lock_type), @@ -2264,24 +2268,34 @@ class BasicSwap(BaseApp): valid_for_seconds = extra_options.get('valid_for_seconds', 60 * 10) self.validateBidValidTime(offer.swap_type, offer.coin_from, offer.coin_to, valid_for_seconds) - bid_rate = extra_options.get('bid_rate', offer.rate) + if not isinstance(amount, int): + amount = int(amount) + self.log.warning('postBid amount should be an integer type.') + + coin_from = Coins(offer.coin_from) + coin_to = Coins(offer.coin_to) + ci_from = self.ci(coin_from) + ci_to = self.ci(coin_to) + + if 'amount_to' in extra_options: + amount_to: int = extra_options['amount_to'] + bid_rate: int = ci_from.make_int(amount_to / amount, r=1) + else: + bid_rate = extra_options.get('bid_rate', offer.rate) + amount_to: int = int((amount * bid_rate) // ci_from.COIN()) + self.validateBidAmount(offer, amount, bid_rate) self.mxDB.acquire() try: + self.checkCoinsReady(coin_from, coin_to) + msg_buf = BidMessage() msg_buf.protocol_version = PROTOCOL_VERSION_SECRET_HASH msg_buf.offer_msg_id = offer_id msg_buf.time_valid = valid_for_seconds - msg_buf.amount = int(amount) # amount of coin_from - msg_buf.rate = bid_rate - - coin_from = Coins(offer.coin_from) - coin_to = Coins(offer.coin_to) - ci_from = self.ci(coin_from) - ci_to = self.ci(coin_to) - - self.checkCoinsReady(coin_from, coin_to) + msg_buf.amount = amount # amount of coin_from + msg_buf.amount_to = amount_to amount_to = int((msg_buf.amount * bid_rate) // ci_from.COIN()) @@ -2314,14 +2328,14 @@ class BasicSwap(BaseApp): bid_id=bid_id, offer_id=offer_id, amount=msg_buf.amount, - rate=msg_buf.rate, + amount_to=msg_buf.amount_to, + rate=bid_rate, pkhash_buyer=msg_buf.pkhash_buyer, proof_address=msg_buf.proof_address, proof_utxos=msg_buf.proof_utxos, created_at=now, contract_count=contract_count, - amount_to=amount_to, expire_at=now + msg_buf.time_valid, bid_addr=bid_addr, was_sent=True, @@ -2627,8 +2641,16 @@ class BasicSwap(BaseApp): ci_to = self.ci(coin_to) valid_for_seconds: int = extra_options.get('valid_for_seconds', 60 * 10) - bid_rate: int = extra_options.get('bid_rate', offer.rate) - amount_to: int = int((int(amount) * bid_rate) // ci_from.COIN()) + + if 'amount_to' in extra_options: + amount_to: int = extra_options['amount_to'] + bid_rate: int = ci_from.make_int(amount_to / amount, r=1) + elif 'bid_rate' in extra_options: + bid_rate: int = extra_options.get('bid_rate', offer.rate) + amount_to: int = int((int(amount) * bid_rate) // ci_from.COIN()) + else: + amount_to: int = offer.amount_to + bid_rate: int = ci_from.make_int(amount_to / amount, r=1) bid_created_at: int = self.getTime() if offer.swap_type != SwapTypes.XMR_SWAP: @@ -2646,8 +2668,6 @@ class BasicSwap(BaseApp): reverse_bid: bool = self.is_reverse_ads_bid(coin_from) if reverse_bid: reversed_rate: int = ci_to.make_int(amount / amount_to, r=1) - amount_from: int = int((int(amount_to) * reversed_rate) // ci_to.COIN()) - ensure(abs(amount_from - amount) < 20, 'invalid bid amount') # TODO: Tolerance? msg_buf = ADSBidIntentMessage() msg_buf.protocol_version = PROTOCOL_VERSION_ADAPTOR_SIG @@ -2655,7 +2675,6 @@ class BasicSwap(BaseApp): msg_buf.time_valid = valid_for_seconds msg_buf.amount_from = amount msg_buf.amount_to = amount_to - msg_buf.rate = bid_rate bid_bytes = msg_buf.SerializeToString() payload_hex = str.format('{:02x}', MessageTypes.ADS_BID_LF) + bid_bytes.hex() @@ -2673,10 +2692,10 @@ class BasicSwap(BaseApp): bid_id=xmr_swap.bid_id, offer_id=offer_id, amount=msg_buf.amount_to, + amount_to=msg_buf.amount_from, rate=reversed_rate, created_at=bid_created_at, contract_count=xmr_swap.contract_count, - amount_to=msg_buf.amount_from, expire_at=bid_created_at + msg_buf.time_valid, bid_addr=bid_addr, was_sent=True, @@ -2700,7 +2719,7 @@ class BasicSwap(BaseApp): msg_buf.offer_msg_id = offer_id msg_buf.time_valid = valid_for_seconds msg_buf.amount = int(amount) # Amount of coin_from - msg_buf.rate = bid_rate + msg_buf.amount_to = amount_to address_out = self.getReceiveAddressFromPool(coin_from, offer_id, TxTypes.XMR_SWAP_A_LOCK) if coin_from == Coins.PART_BLIND: @@ -2763,10 +2782,10 @@ class BasicSwap(BaseApp): bid_id=xmr_swap.bid_id, offer_id=offer_id, amount=msg_buf.amount, - rate=msg_buf.rate, + amount_to=msg_buf.amount_to, + rate=bid_rate, created_at=bid_created_at, contract_count=xmr_swap.contract_count, - amount_to=(msg_buf.amount * msg_buf.rate) // ci_from.COIN(), expire_at=bid_created_at + msg_buf.time_valid, bid_addr=bid_addr, was_sent=True, @@ -4537,12 +4556,13 @@ class BasicSwap(BaseApp): ensure(offer_data.coin_from != offer_data.coin_to, 'coin_from == coin_to') self.validateSwapType(coin_from, coin_to, offer_data.swap_type) - self.validateOfferAmounts(coin_from, coin_to, offer_data.amount_from, offer_data.rate, offer_data.min_bid_amount) + self.validateOfferAmounts(coin_from, coin_to, offer_data.amount_from, offer_data.amount_to, offer_data.min_bid_amount) self.validateOfferLockValue(offer_data.swap_type, coin_from, coin_to, offer_data.lock_type, offer_data.lock_value) self.validateOfferValidTime(offer_data.swap_type, coin_from, coin_to, offer_data.time_valid) ensure(msg['sent'] + offer_data.time_valid >= now, 'Offer expired') + offer_rate: int = ci_from.make_int(offer_data.amount_to / offer_data.amount_from, r=1) reverse_bid: bool = self.is_reverse_ads_bid(coin_from) if offer_data.swap_type == SwapTypes.SELLER_FIRST: @@ -4593,7 +4613,8 @@ class BasicSwap(BaseApp): coin_from=offer_data.coin_from, coin_to=offer_data.coin_to, amount_from=offer_data.amount_from, - rate=offer_data.rate, + amount_to=offer_data.amount_to, + rate=offer_rate, min_bid_amount=offer_data.min_bid_amount, time_valid=offer_data.time_valid, lock_type=int(offer_data.lock_type), @@ -4806,16 +4827,16 @@ class BasicSwap(BaseApp): ensure(now <= offer.expire_at, 'Offer expired') self.validateBidValidTime(offer.swap_type, offer.coin_from, offer.coin_to, bid_data.time_valid) ensure(now <= msg['sent'] + bid_data.time_valid, 'Bid expired') - self.validateBidAmount(offer, bid_data.amount, bid_data.rate) - - # TODO: Allow higher bids - # assert (bid_data.rate != offer['data'].rate), 'Bid rate mismatch' coin_to = Coins(offer.coin_to) ci_from = self.ci(offer.coin_from) ci_to = self.ci(coin_to) + bid_rate: int = ci_from.make_int(bid_data.amount_to / bid_data.amount, r=1) + self.validateBidAmount(offer, bid_data.amount, bid_rate) + + # TODO: Allow higher bids + # assert (bid_data.rate != offer['data'].rate), 'Bid rate mismatch' - amount_to = int((bid_data.amount * bid_data.rate) // ci_from.COIN()) swap_type = offer.swap_type if swap_type == SwapTypes.SELLER_FIRST: ensure(len(bid_data.pkhash_buyer) == 20, 'Bad pkhash_buyer length') @@ -4823,7 +4844,7 @@ class BasicSwap(BaseApp): proof_utxos = ci_to.decodeProofUtxos(bid_data.proof_utxos) sum_unspent = ci_to.verifyProofOfFunds(bid_data.proof_address, bid_data.proof_signature, proof_utxos, offer_id) self.log.debug('Proof of funds %s %s', bid_data.proof_address, self.ci(coin_to).format_amount(sum_unspent)) - ensure(sum_unspent >= amount_to, 'Proof of funds failed') + ensure(sum_unspent >= bid_data.amount_to, 'Proof of funds failed') elif swap_type == SwapTypes.BUYER_FIRST: raise ValueError('TODO') @@ -4840,13 +4861,13 @@ class BasicSwap(BaseApp): offer_id=offer_id, protocol_version=bid_data.protocol_version, amount=bid_data.amount, - rate=bid_data.rate, + amount_to=bid_data.amount_to, + rate=bid_rate, pkhash_buyer=bid_data.pkhash_buyer, proof_address=bid_data.proof_address, proof_utxos=bid_data.proof_utxos, created_at=msg['sent'], - amount_to=amount_to, expire_at=msg['sent'] + bid_data.time_valid, bid_addr=msg['from'], was_received=True, @@ -5116,7 +5137,8 @@ class BasicSwap(BaseApp): self.validateBidValidTime(offer.swap_type, offer.coin_from, offer.coin_to, bid_data.time_valid) ensure(now <= msg['sent'] + bid_data.time_valid, 'Bid expired') - self.validateBidAmount(offer, bid_data.amount, bid_data.rate) + bid_rate: int = ci_from.make_int(bid_data.amount_to / bid_data.amount, r=1) + self.validateBidAmount(offer, bid_data.amount, bid_rate) ensure(ci_to.verifyKey(bid_data.kbvf), 'Invalid chain B follower view key') ensure(ci_from.verifyPubkey(bid_data.pkaf), 'Invalid chain A follower public key') @@ -5135,9 +5157,9 @@ class BasicSwap(BaseApp): offer_id=offer_id, protocol_version=bid_data.protocol_version, amount=bid_data.amount, - rate=bid_data.rate, + amount_to=bid_data.amount_to, + rate=bid_rate, created_at=msg['sent'], - amount_to=(bid_data.amount * bid_data.rate) // ci_from.COIN(), expire_at=msg['sent'] + bid_data.time_valid, bid_addr=msg['from'], was_received=True, @@ -5992,14 +6014,10 @@ class BasicSwap(BaseApp): self.validateBidValidTime(offer.swap_type, offer.coin_from, offer.coin_to, bid_data.time_valid) ensure(now <= msg['sent'] + bid_data.time_valid, 'Bid expired') - amount_from: int = bid_data.amount_from - amount_to: int = (bid_data.amount_from * bid_data.rate) // ci_to.COIN() - ensure(abs(amount_to - bid_data.amount_to) < 20, 'invalid bid amount_to') # TODO: Tolerance? - reversed_rate: int = ci_from.make_int(amount_from / bid_data.amount_to, r=1) - amount_from_recovered: int = int((amount_to * reversed_rate) // ci_from.COIN()) - ensure(abs(amount_from - amount_from_recovered) < 20, 'invalid bid amount_from') # TODO: Tolerance? - - self.validateBidAmount(offer, amount_from, bid_data.rate) + # ci_from/to are reversed + bid_rate: int = ci_to.make_int(bid_data.amount_to / bid_data.amount_from, r=1) + reversed_rate: int = ci_from.make_int(bid_data.amount_from / bid_data.amount_to, r=1) + self.validateBidAmount(offer, bid_data.amount_from, bid_rate) bid_id = bytes.fromhex(msg['msgid']) @@ -6010,10 +6028,10 @@ class BasicSwap(BaseApp): bid_id=bid_id, offer_id=offer_id, protocol_version=bid_data.protocol_version, - amount=amount_to, + amount=bid_data.amount_to, + amount_to=bid_data.amount_from, rate=reversed_rate, created_at=msg['sent'], - amount_to=amount_from, expire_at=msg['sent'] + bid_data.time_valid, bid_addr=msg['from'], was_sent=False, @@ -6044,7 +6062,7 @@ class BasicSwap(BaseApp): session = self.openSession() self.notify(NT.BID_RECEIVED, {'type': 'ads_reversed', 'bid_id': bid.bid_id.hex(), 'offer_id': bid.offer_id.hex()}, session) - options = {'reverse_bid': True, 'bid_rate': bid_data.rate} + options = {'reverse_bid': True, 'bid_rate': bid_rate} if self.shouldAutoAcceptBid(offer, bid, session, options=options): delay = self.get_delay_event_seconds() self.log.info('Auto accepting reverse adaptor-sig bid %s in %d seconds', bid.bid_id.hex(), delay) @@ -6998,6 +7016,7 @@ class BasicSwap(BaseApp): result[13] = amount_to ci_from = self.ci(coin_from) result[10] = ci_from.make_int(amount_to / amount_from, r=1) + rv.append(result) return rv finally: diff --git a/basicswap/db.py b/basicswap/db.py index 8e7f6ce..b8dce4f 100644 --- a/basicswap/db.py +++ b/basicswap/db.py @@ -11,7 +11,7 @@ from enum import IntEnum, auto from sqlalchemy.ext.declarative import declarative_base -CURRENT_DB_VERSION = 22 +CURRENT_DB_VERSION = 23 CURRENT_DB_DATA_VERSION = 4 Base = declarative_base() @@ -61,6 +61,7 @@ class Offer(Base): coin_from = sa.Column(sa.Integer) coin_to = sa.Column(sa.Integer) amount_from = sa.Column(sa.BigInteger) + amount_to = sa.Column(sa.BigInteger) rate = sa.Column(sa.BigInteger) min_bid_amount = sa.Column(sa.BigInteger) time_valid = sa.Column(sa.BigInteger) diff --git a/basicswap/db_upgrades.py b/basicswap/db_upgrades.py index a53032a..ae3f3cd 100644 --- a/basicswap/db_upgrades.py +++ b/basicswap/db_upgrades.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2022-2023 tecnovert +# Copyright (c) 2022-2024 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. @@ -297,7 +297,9 @@ def upgradeDatabase(self, db_version): db_version += 1 session.execute('ALTER TABLE offers ADD COLUMN proof_utxos BLOB') session.execute('ALTER TABLE bids ADD COLUMN proof_utxos BLOB') - + elif current_version == 22: + db_version += 1 + session.execute('ALTER TABLE offers ADD COLUMN amount_to INTEGER') if current_version != db_version: self.db_version = db_version self.setIntKVInSession('db_version', db_version, session) diff --git a/basicswap/js_server.py b/basicswap/js_server.py index aeb8b43..27fcebf 100644 --- a/basicswap/js_server.py +++ b/basicswap/js_server.py @@ -339,7 +339,10 @@ def js_bids(self, url_split, post_string: str, is_json: bool) -> bytes: extra_options = { 'valid_for_seconds': valid_for_seconds, } - if have_data_entry(post_data, 'bid_rate'): + + if have_data_entry(post_data, 'amount_to'): + extra_options['amount_to'] = inputAmount(get_data_entry(post_data, 'amount_to'), ci_to) + elif have_data_entry(post_data, 'bid_rate'): extra_options['bid_rate'] = ci_to.make_int(get_data_entry(post_data, 'bid_rate'), r=1) if have_data_entry(post_data, 'bid_amount'): amount_from = inputAmount(get_data_entry(post_data, 'bid_amount'), ci_from) @@ -493,10 +496,10 @@ def js_rate(self, url_split, post_string, is_json) -> bytes: amount_from = ci_from.format_amount(int((amt_to * rate) // ci_to.COIN()), r=1) return bytes(json.dumps({'amount_from': amount_from}), 'UTF-8') - amt_from = inputAmount(get_data_entry(post_data, 'amt_from'), ci_from) - amt_to = inputAmount(get_data_entry(post_data, 'amt_to'), ci_to) + amt_from: int = inputAmount(get_data_entry(post_data, 'amt_from'), ci_from) + amt_to: int = inputAmount(get_data_entry(post_data, 'amt_to'), ci_to) - rate = ci_to.format_amount(ci_from.make_int(amt_to / amt_from, r=1)) + rate: int = ci_to.format_amount(ci_from.make_int(amt_to / amt_from, r=1)) return bytes(json.dumps({'rate': rate}), 'UTF-8') diff --git a/basicswap/messages.proto b/basicswap/messages.proto index 87cf273..fb5815d 100644 --- a/basicswap/messages.proto +++ b/basicswap/messages.proto @@ -4,12 +4,13 @@ package basicswap; /* Step 1, seller -> network */ message OfferMessage { - uint32 coin_from = 1; - uint32 coin_to = 2; - uint64 amount_from = 3; - uint64 rate = 4; - uint64 min_bid_amount = 5; - uint64 time_valid = 6; + uint32 protocol_version = 1; + uint32 coin_from = 2; + uint32 coin_to = 3; + uint64 amount_from = 4; + uint64 amount_to = 5; + uint64 min_bid_amount = 6; + uint64 time_valid = 7; enum LockType { NOT_SET = 0; SEQUENCE_LOCK_BLOCKS = 1; @@ -17,20 +18,19 @@ message OfferMessage { ABS_LOCK_BLOCKS = 3; ABS_LOCK_TIME = 4; } - LockType lock_type = 7; - uint32 lock_value = 8; - uint32 swap_type = 9; + LockType lock_type = 8; + uint32 lock_value = 9; + uint32 swap_type = 10; /* optional */ - string proof_address = 10; - string proof_signature = 11; - bytes pkhash_seller = 12; - bytes secret_hash = 13; + string proof_address = 11; + string proof_signature = 12; + bytes pkhash_seller = 13; + bytes secret_hash = 14; - uint64 fee_rate_from = 14; - uint64 fee_rate_to = 15; + uint64 fee_rate_from = 15; + uint64 fee_rate_to = 16; - uint32 protocol_version = 16; bool amount_negotiable = 17; bool rate_negotiable = 18; @@ -39,34 +39,27 @@ message OfferMessage { /* Step 2, buyer -> seller */ message BidMessage { - bytes offer_msg_id = 1; - uint64 time_valid = 2; /* seconds bid is valid for */ - uint64 amount = 3; /* amount of amount_from bid is for */ - uint64 rate = 4; - bytes pkhash_buyer = 5; /* buyer's address to receive amount_from */ - string proof_address = 6; - string proof_signature = 7; - - uint32 protocol_version = 8; + uint32 protocol_version = 1; + bytes offer_msg_id = 2; + uint64 time_valid = 3; /* seconds bid is valid for */ + uint64 amount = 4; /* amount of amount_from bid is for */ + uint64 amount_to = 5; + bytes pkhash_buyer = 6; /* buyer's address to receive amount_from */ + string proof_address = 7; + string proof_signature = 8; bytes proof_utxos = 9; /* 32 byte txid 2 byte vout, repeated */ } /* For tests */ -message BidMessage_v1Deprecated { - bytes offer_msg_id = 1; - uint64 time_valid = 2; /* seconds bid is valid for */ - uint64 amount = 3; /* amount of amount_from bid is for */ - uint64 rate = 4; - bytes pkhash_buyer = 5; /* buyer's address to receive amount_from */ - string proof_address = 6; - string proof_signature = 7; - - uint32 protocol_version = 8; +message BidMessage_test { + uint32 protocol_version = 1; + bytes offer_msg_id = 2; + uint64 time_valid = 3; + uint64 amount = 4; + uint64 rate = 5; } - - /* Step 3, seller -> buyer */ message BidAcceptMessage { bytes bid_msg_id = 1; @@ -81,25 +74,23 @@ message OfferRevokeMessage { message BidRejectMessage { bytes bid_msg_id = 1; - uint32 reject_code = 2; } message XmrBidMessage { /* MSG1L, F -> L */ - bytes offer_msg_id = 1; - uint64 time_valid = 2; /* seconds bid is valid for */ - uint64 amount = 3; /* amount of amount_from bid is for */ - uint64 rate = 4; + uint32 protocol_version = 1; + bytes offer_msg_id = 2; + uint64 time_valid = 3; /* seconds bid is valid for */ + uint64 amount = 4; /* amount of amount_from bid is for */ + uint64 amount_to = 5; - bytes pkaf = 5; + bytes pkaf = 6; - bytes kbvf = 6; - bytes kbsf_dleag = 7; + bytes kbvf = 7; + bytes kbsf_dleag = 8; - bytes dest_af = 8; - - uint32 protocol_version = 9; + bytes dest_af = 9; } message XmrSplitMessage { @@ -112,24 +103,22 @@ message XmrSplitMessage { message XmrBidAcceptMessage { bytes bid_msg_id = 1; - bytes pkal = 3; - - bytes kbvl = 4; - bytes kbsl_dleag = 5; + bytes pkal = 2; + bytes kbvl = 3; + bytes kbsl_dleag = 4; /* MSG2F */ - bytes a_lock_tx = 6; - bytes a_lock_tx_script = 7; - bytes a_lock_refund_tx = 8; - bytes a_lock_refund_tx_script = 9; - bytes a_lock_refund_spend_tx = 10; - bytes al_lock_refund_tx_sig = 11; + bytes a_lock_tx = 5; + bytes a_lock_tx_script = 6; + bytes a_lock_refund_tx = 7; + bytes a_lock_refund_tx_script = 8; + bytes a_lock_refund_spend_tx = 9; + bytes al_lock_refund_tx_sig = 10; } message XmrBidLockTxSigsMessage { /* MSG3L */ bytes bid_msg_id = 1; - bytes af_lock_refund_spend_tx_esig = 2; bytes af_lock_refund_tx_sig = 3; } @@ -137,7 +126,6 @@ message XmrBidLockTxSigsMessage { message XmrBidLockSpendTxMessage { /* MSG4F */ bytes bid_msg_id = 1; - bytes a_lock_spend_tx = 2; bytes kal_sig = 3; } @@ -145,19 +133,16 @@ message XmrBidLockSpendTxMessage { message XmrBidLockReleaseMessage { /* MSG5F */ bytes bid_msg_id = 1; - bytes al_lock_spend_tx_esig = 2; } message ADSBidIntentMessage { /* L -> F Sent from bidder, construct a reverse bid */ - bytes offer_msg_id = 1; - uint64 time_valid = 2; /* seconds bid is valid for */ - uint64 amount_from = 3; /* amount of offer.coin_from bid is for */ - uint64 amount_to = 4; /* amount of offer.coin_to bid is for, equivalent to bid.amount */ - uint64 rate = 5; /* amount of offer.coin_from bid is for */ - - uint32 protocol_version = 6; + uint32 protocol_version = 1; + bytes offer_msg_id = 2; + uint64 time_valid = 3; /* seconds bid is valid for */ + uint64 amount_from = 4; /* amount of offer.coin_from bid is for */ + uint64 amount_to = 5; /* amount of offer.coin_to bid is for, equivalent to bid.amount */ } message ADSBidIntentAcceptMessage { diff --git a/basicswap/messages_pb2.py b/basicswap/messages_pb2.py index 7f889e4..74f08a2 100644 --- a/basicswap/messages_pb2.py +++ b/basicswap/messages_pb2.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: messages.proto +# Protobuf Python Version: 4.25.3 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +14,7 @@ _sym_db = _symbol_database.Default() -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0emessages.proto\x12\tbasicswap\"\xa6\x04\n\x0cOfferMessage\x12\x11\n\tcoin_from\x18\x01 \x01(\r\x12\x0f\n\x07\x63oin_to\x18\x02 \x01(\r\x12\x13\n\x0b\x61mount_from\x18\x03 \x01(\x04\x12\x0c\n\x04rate\x18\x04 \x01(\x04\x12\x16\n\x0emin_bid_amount\x18\x05 \x01(\x04\x12\x12\n\ntime_valid\x18\x06 \x01(\x04\x12\x33\n\tlock_type\x18\x07 \x01(\x0e\x32 .basicswap.OfferMessage.LockType\x12\x12\n\nlock_value\x18\x08 \x01(\r\x12\x11\n\tswap_type\x18\t \x01(\r\x12\x15\n\rproof_address\x18\n \x01(\t\x12\x17\n\x0fproof_signature\x18\x0b \x01(\t\x12\x15\n\rpkhash_seller\x18\x0c \x01(\x0c\x12\x13\n\x0bsecret_hash\x18\r \x01(\x0c\x12\x15\n\rfee_rate_from\x18\x0e \x01(\x04\x12\x13\n\x0b\x66\x65\x65_rate_to\x18\x0f \x01(\x04\x12\x18\n\x10protocol_version\x18\x10 \x01(\r\x12\x19\n\x11\x61mount_negotiable\x18\x11 \x01(\x08\x12\x17\n\x0frate_negotiable\x18\x12 \x01(\x08\"q\n\x08LockType\x12\x0b\n\x07NOT_SET\x10\x00\x12\x18\n\x14SEQUENCE_LOCK_BLOCKS\x10\x01\x12\x16\n\x12SEQUENCE_LOCK_TIME\x10\x02\x12\x13\n\x0f\x41\x42S_LOCK_BLOCKS\x10\x03\x12\x11\n\rABS_LOCK_TIME\x10\x04\"\xc9\x01\n\nBidMessage\x12\x14\n\x0coffer_msg_id\x18\x01 \x01(\x0c\x12\x12\n\ntime_valid\x18\x02 \x01(\x04\x12\x0e\n\x06\x61mount\x18\x03 \x01(\x04\x12\x0c\n\x04rate\x18\x04 \x01(\x04\x12\x14\n\x0cpkhash_buyer\x18\x05 \x01(\x0c\x12\x15\n\rproof_address\x18\x06 \x01(\t\x12\x17\n\x0fproof_signature\x18\x07 \x01(\t\x12\x18\n\x10protocol_version\x18\x08 \x01(\r\x12\x13\n\x0bproof_utxos\x18\t \x01(\x0c\"\xc1\x01\n\x17\x42idMessage_v1Deprecated\x12\x14\n\x0coffer_msg_id\x18\x01 \x01(\x0c\x12\x12\n\ntime_valid\x18\x02 \x01(\x04\x12\x0e\n\x06\x61mount\x18\x03 \x01(\x04\x12\x0c\n\x04rate\x18\x04 \x01(\x04\x12\x14\n\x0cpkhash_buyer\x18\x05 \x01(\x0c\x12\x15\n\rproof_address\x18\x06 \x01(\t\x12\x17\n\x0fproof_signature\x18\x07 \x01(\t\x12\x18\n\x10protocol_version\x18\x08 \x01(\r\"V\n\x10\x42idAcceptMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x15\n\rinitiate_txid\x18\x02 \x01(\x0c\x12\x17\n\x0f\x63ontract_script\x18\x03 \x01(\x0c\"=\n\x12OfferRevokeMessage\x12\x14\n\x0coffer_msg_id\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\";\n\x10\x42idRejectMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x13\n\x0breject_code\x18\x02 \x01(\r\"\xb2\x01\n\rXmrBidMessage\x12\x14\n\x0coffer_msg_id\x18\x01 \x01(\x0c\x12\x12\n\ntime_valid\x18\x02 \x01(\x04\x12\x0e\n\x06\x61mount\x18\x03 \x01(\x04\x12\x0c\n\x04rate\x18\x04 \x01(\x04\x12\x0c\n\x04pkaf\x18\x05 \x01(\x0c\x12\x0c\n\x04kbvf\x18\x06 \x01(\x0c\x12\x12\n\nkbsf_dleag\x18\x07 \x01(\x0c\x12\x0f\n\x07\x64\x65st_af\x18\x08 \x01(\x0c\x12\x18\n\x10protocol_version\x18\t \x01(\r\"T\n\x0fXmrSplitMessage\x12\x0e\n\x06msg_id\x18\x01 \x01(\x0c\x12\x10\n\x08msg_type\x18\x02 \x01(\r\x12\x10\n\x08sequence\x18\x03 \x01(\r\x12\r\n\x05\x64leag\x18\x04 \x01(\x0c\"\x80\x02\n\x13XmrBidAcceptMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x0c\n\x04pkal\x18\x03 \x01(\x0c\x12\x0c\n\x04kbvl\x18\x04 \x01(\x0c\x12\x12\n\nkbsl_dleag\x18\x05 \x01(\x0c\x12\x11\n\ta_lock_tx\x18\x06 \x01(\x0c\x12\x18\n\x10\x61_lock_tx_script\x18\x07 \x01(\x0c\x12\x18\n\x10\x61_lock_refund_tx\x18\x08 \x01(\x0c\x12\x1f\n\x17\x61_lock_refund_tx_script\x18\t \x01(\x0c\x12\x1e\n\x16\x61_lock_refund_spend_tx\x18\n \x01(\x0c\x12\x1d\n\x15\x61l_lock_refund_tx_sig\x18\x0b \x01(\x0c\"r\n\x17XmrBidLockTxSigsMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12$\n\x1c\x61\x66_lock_refund_spend_tx_esig\x18\x02 \x01(\x0c\x12\x1d\n\x15\x61\x66_lock_refund_tx_sig\x18\x03 \x01(\x0c\"X\n\x18XmrBidLockSpendTxMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x17\n\x0f\x61_lock_spend_tx\x18\x02 \x01(\x0c\x12\x0f\n\x07kal_sig\x18\x03 \x01(\x0c\"M\n\x18XmrBidLockReleaseMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x1d\n\x15\x61l_lock_spend_tx_esig\x18\x02 \x01(\x0c\"\x8f\x01\n\x13\x41\x44SBidIntentMessage\x12\x14\n\x0coffer_msg_id\x18\x01 \x01(\x0c\x12\x12\n\ntime_valid\x18\x02 \x01(\x04\x12\x13\n\x0b\x61mount_from\x18\x03 \x01(\x04\x12\x11\n\tamount_to\x18\x04 \x01(\x04\x12\x0c\n\x04rate\x18\x05 \x01(\x04\x12\x18\n\x10protocol_version\x18\x06 \x01(\r\"p\n\x19\x41\x44SBidIntentAcceptMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x0c\n\x04pkaf\x18\x02 \x01(\x0c\x12\x0c\n\x04kbvf\x18\x03 \x01(\x0c\x12\x12\n\nkbsf_dleag\x18\x04 \x01(\x0c\x12\x0f\n\x07\x64\x65st_af\x18\x05 \x01(\x0c\x62\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0emessages.proto\x12\tbasicswap\"\xc0\x04\n\x0cOfferMessage\x12\x18\n\x10protocol_version\x18\x01 \x01(\r\x12\x11\n\tcoin_from\x18\x02 \x01(\r\x12\x0f\n\x07\x63oin_to\x18\x03 \x01(\r\x12\x13\n\x0b\x61mount_from\x18\x04 \x01(\x04\x12\x11\n\tamount_to\x18\x05 \x01(\x04\x12\x16\n\x0emin_bid_amount\x18\x06 \x01(\x04\x12\x12\n\ntime_valid\x18\x07 \x01(\x04\x12\x33\n\tlock_type\x18\x08 \x01(\x0e\x32 .basicswap.OfferMessage.LockType\x12\x12\n\nlock_value\x18\t \x01(\r\x12\x11\n\tswap_type\x18\n \x01(\r\x12\x15\n\rproof_address\x18\x0b \x01(\t\x12\x17\n\x0fproof_signature\x18\x0c \x01(\t\x12\x15\n\rpkhash_seller\x18\r \x01(\x0c\x12\x13\n\x0bsecret_hash\x18\x0e \x01(\x0c\x12\x15\n\rfee_rate_from\x18\x0f \x01(\x04\x12\x13\n\x0b\x66\x65\x65_rate_to\x18\x10 \x01(\x04\x12\x19\n\x11\x61mount_negotiable\x18\x11 \x01(\x08\x12\x17\n\x0frate_negotiable\x18\x12 \x01(\x08\x12\x13\n\x0bproof_utxos\x18\x13 \x01(\x0c\"q\n\x08LockType\x12\x0b\n\x07NOT_SET\x10\x00\x12\x18\n\x14SEQUENCE_LOCK_BLOCKS\x10\x01\x12\x16\n\x12SEQUENCE_LOCK_TIME\x10\x02\x12\x13\n\x0f\x41\x42S_LOCK_BLOCKS\x10\x03\x12\x11\n\rABS_LOCK_TIME\x10\x04\"\xce\x01\n\nBidMessage\x12\x18\n\x10protocol_version\x18\x01 \x01(\r\x12\x14\n\x0coffer_msg_id\x18\x02 \x01(\x0c\x12\x12\n\ntime_valid\x18\x03 \x01(\x04\x12\x0e\n\x06\x61mount\x18\x04 \x01(\x04\x12\x11\n\tamount_to\x18\x05 \x01(\x04\x12\x14\n\x0cpkhash_buyer\x18\x06 \x01(\x0c\x12\x15\n\rproof_address\x18\x07 \x01(\t\x12\x17\n\x0fproof_signature\x18\x08 \x01(\t\x12\x13\n\x0bproof_utxos\x18\t \x01(\x0c\"s\n\x0f\x42idMessage_test\x12\x18\n\x10protocol_version\x18\x01 \x01(\r\x12\x14\n\x0coffer_msg_id\x18\x02 \x01(\x0c\x12\x12\n\ntime_valid\x18\x03 \x01(\x04\x12\x0e\n\x06\x61mount\x18\x04 \x01(\x04\x12\x0c\n\x04rate\x18\x05 \x01(\x04\"V\n\x10\x42idAcceptMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x15\n\rinitiate_txid\x18\x02 \x01(\x0c\x12\x17\n\x0f\x63ontract_script\x18\x03 \x01(\x0c\"=\n\x12OfferRevokeMessage\x12\x14\n\x0coffer_msg_id\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\";\n\x10\x42idRejectMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x13\n\x0breject_code\x18\x02 \x01(\r\"\xb7\x01\n\rXmrBidMessage\x12\x18\n\x10protocol_version\x18\x01 \x01(\r\x12\x14\n\x0coffer_msg_id\x18\x02 \x01(\x0c\x12\x12\n\ntime_valid\x18\x03 \x01(\x04\x12\x0e\n\x06\x61mount\x18\x04 \x01(\x04\x12\x11\n\tamount_to\x18\x05 \x01(\x04\x12\x0c\n\x04pkaf\x18\x06 \x01(\x0c\x12\x0c\n\x04kbvf\x18\x07 \x01(\x0c\x12\x12\n\nkbsf_dleag\x18\x08 \x01(\x0c\x12\x0f\n\x07\x64\x65st_af\x18\t \x01(\x0c\"T\n\x0fXmrSplitMessage\x12\x0e\n\x06msg_id\x18\x01 \x01(\x0c\x12\x10\n\x08msg_type\x18\x02 \x01(\r\x12\x10\n\x08sequence\x18\x03 \x01(\r\x12\r\n\x05\x64leag\x18\x04 \x01(\x0c\"\x80\x02\n\x13XmrBidAcceptMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x0c\n\x04pkal\x18\x02 \x01(\x0c\x12\x0c\n\x04kbvl\x18\x03 \x01(\x0c\x12\x12\n\nkbsl_dleag\x18\x04 \x01(\x0c\x12\x11\n\ta_lock_tx\x18\x05 \x01(\x0c\x12\x18\n\x10\x61_lock_tx_script\x18\x06 \x01(\x0c\x12\x18\n\x10\x61_lock_refund_tx\x18\x07 \x01(\x0c\x12\x1f\n\x17\x61_lock_refund_tx_script\x18\x08 \x01(\x0c\x12\x1e\n\x16\x61_lock_refund_spend_tx\x18\t \x01(\x0c\x12\x1d\n\x15\x61l_lock_refund_tx_sig\x18\n \x01(\x0c\"r\n\x17XmrBidLockTxSigsMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12$\n\x1c\x61\x66_lock_refund_spend_tx_esig\x18\x02 \x01(\x0c\x12\x1d\n\x15\x61\x66_lock_refund_tx_sig\x18\x03 \x01(\x0c\"X\n\x18XmrBidLockSpendTxMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x17\n\x0f\x61_lock_spend_tx\x18\x02 \x01(\x0c\x12\x0f\n\x07kal_sig\x18\x03 \x01(\x0c\"M\n\x18XmrBidLockReleaseMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x1d\n\x15\x61l_lock_spend_tx_esig\x18\x02 \x01(\x0c\"\x81\x01\n\x13\x41\x44SBidIntentMessage\x12\x18\n\x10protocol_version\x18\x01 \x01(\r\x12\x14\n\x0coffer_msg_id\x18\x02 \x01(\x0c\x12\x12\n\ntime_valid\x18\x03 \x01(\x04\x12\x13\n\x0b\x61mount_from\x18\x04 \x01(\x04\x12\x11\n\tamount_to\x18\x05 \x01(\x04\"p\n\x19\x41\x44SBidIntentAcceptMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x0c\n\x04pkaf\x18\x02 \x01(\x0c\x12\x0c\n\x04kbvf\x18\x03 \x01(\x0c\x12\x12\n\nkbsf_dleag\x18\x04 \x01(\x0c\x12\x0f\n\x07\x64\x65st_af\x18\x05 \x01(\x0c\x62\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -21,33 +22,33 @@ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'messages_pb2', _globals) if _descriptor._USE_C_DESCRIPTORS == False: DESCRIPTOR._options = None _globals['_OFFERMESSAGE']._serialized_start=30 - _globals['_OFFERMESSAGE']._serialized_end=580 - _globals['_OFFERMESSAGE_LOCKTYPE']._serialized_start=467 - _globals['_OFFERMESSAGE_LOCKTYPE']._serialized_end=580 - _globals['_BIDMESSAGE']._serialized_start=583 - _globals['_BIDMESSAGE']._serialized_end=784 - _globals['_BIDMESSAGE_V1DEPRECATED']._serialized_start=787 - _globals['_BIDMESSAGE_V1DEPRECATED']._serialized_end=980 - _globals['_BIDACCEPTMESSAGE']._serialized_start=982 - _globals['_BIDACCEPTMESSAGE']._serialized_end=1068 - _globals['_OFFERREVOKEMESSAGE']._serialized_start=1070 - _globals['_OFFERREVOKEMESSAGE']._serialized_end=1131 - _globals['_BIDREJECTMESSAGE']._serialized_start=1133 - _globals['_BIDREJECTMESSAGE']._serialized_end=1192 - _globals['_XMRBIDMESSAGE']._serialized_start=1195 - _globals['_XMRBIDMESSAGE']._serialized_end=1373 - _globals['_XMRSPLITMESSAGE']._serialized_start=1375 - _globals['_XMRSPLITMESSAGE']._serialized_end=1459 - _globals['_XMRBIDACCEPTMESSAGE']._serialized_start=1462 - _globals['_XMRBIDACCEPTMESSAGE']._serialized_end=1718 - _globals['_XMRBIDLOCKTXSIGSMESSAGE']._serialized_start=1720 - _globals['_XMRBIDLOCKTXSIGSMESSAGE']._serialized_end=1834 - _globals['_XMRBIDLOCKSPENDTXMESSAGE']._serialized_start=1836 - _globals['_XMRBIDLOCKSPENDTXMESSAGE']._serialized_end=1924 - _globals['_XMRBIDLOCKRELEASEMESSAGE']._serialized_start=1926 - _globals['_XMRBIDLOCKRELEASEMESSAGE']._serialized_end=2003 - _globals['_ADSBIDINTENTMESSAGE']._serialized_start=2006 - _globals['_ADSBIDINTENTMESSAGE']._serialized_end=2149 - _globals['_ADSBIDINTENTACCEPTMESSAGE']._serialized_start=2151 - _globals['_ADSBIDINTENTACCEPTMESSAGE']._serialized_end=2263 + _globals['_OFFERMESSAGE']._serialized_end=606 + _globals['_OFFERMESSAGE_LOCKTYPE']._serialized_start=493 + _globals['_OFFERMESSAGE_LOCKTYPE']._serialized_end=606 + _globals['_BIDMESSAGE']._serialized_start=609 + _globals['_BIDMESSAGE']._serialized_end=815 + _globals['_BIDMESSAGE_TEST']._serialized_start=817 + _globals['_BIDMESSAGE_TEST']._serialized_end=932 + _globals['_BIDACCEPTMESSAGE']._serialized_start=934 + _globals['_BIDACCEPTMESSAGE']._serialized_end=1020 + _globals['_OFFERREVOKEMESSAGE']._serialized_start=1022 + _globals['_OFFERREVOKEMESSAGE']._serialized_end=1083 + _globals['_BIDREJECTMESSAGE']._serialized_start=1085 + _globals['_BIDREJECTMESSAGE']._serialized_end=1144 + _globals['_XMRBIDMESSAGE']._serialized_start=1147 + _globals['_XMRBIDMESSAGE']._serialized_end=1330 + _globals['_XMRSPLITMESSAGE']._serialized_start=1332 + _globals['_XMRSPLITMESSAGE']._serialized_end=1416 + _globals['_XMRBIDACCEPTMESSAGE']._serialized_start=1419 + _globals['_XMRBIDACCEPTMESSAGE']._serialized_end=1675 + _globals['_XMRBIDLOCKTXSIGSMESSAGE']._serialized_start=1677 + _globals['_XMRBIDLOCKTXSIGSMESSAGE']._serialized_end=1791 + _globals['_XMRBIDLOCKSPENDTXMESSAGE']._serialized_start=1793 + _globals['_XMRBIDLOCKSPENDTXMESSAGE']._serialized_end=1881 + _globals['_XMRBIDLOCKRELEASEMESSAGE']._serialized_start=1883 + _globals['_XMRBIDLOCKRELEASEMESSAGE']._serialized_end=1960 + _globals['_ADSBIDINTENTMESSAGE']._serialized_start=1963 + _globals['_ADSBIDINTENTMESSAGE']._serialized_end=2092 + _globals['_ADSBIDINTENTACCEPTMESSAGE']._serialized_start=2094 + _globals['_ADSBIDINTENTACCEPTMESSAGE']._serialized_end=2206 # @@protoc_insertion_point(module_scope) diff --git a/basicswap/ui/page_offers.py b/basicswap/ui/page_offers.py index 1d38bd4..7c05b26 100644 --- a/basicswap/ui/page_offers.py +++ b/basicswap/ui/page_offers.py @@ -142,6 +142,9 @@ def parseOfferFormData(swap_client, form_data, page_data, options={}): parsed_data['rate'] = ci_from.make_int(parsed_data['amt_to'] / parsed_data['amt_from'], r=1) page_data['rate'] = ci_to.format_amount(parsed_data['rate']) + if 'amt_to' not in parsed_data and 'rate' in parsed_data and 'amt_from' in parsed_data: + parsed_data['amt_to'] = int((parsed_data['amt_from'] * parsed_data['rate']) // ci_from.COIN()) + page_data['amt_var'] = True if have_data_entry(form_data, 'amt_var') else False parsed_data['amt_var'] = page_data['amt_var'] page_data['rate_var'] = True if have_data_entry(form_data, 'rate_var') else False @@ -308,6 +311,8 @@ def postNewOfferFromParsed(swap_client, parsed_data): extra_options['automation_id'] = parsed_data['automation_strat_id'] swap_value = parsed_data['amt_from'] + if parsed_data.get('amt_to', None) is not None: + extra_options['amount_to'] = parsed_data['amt_to'] if parsed_data.get('subfee', False): ci_from = swap_client.ci(parsed_data['coin_from']) pi = swap_client.pi(swap_type) @@ -358,7 +363,7 @@ def offer_to_post_string(self, swap_client, offer_id): 'amt_from': ci_from.format_amount(offer.amount_from), 'amt_bid_min': ci_from.format_amount(offer.min_bid_amount), 'rate': ci_to.format_amount(offer.rate), - 'amt_to': ci_to.format_amount((offer.amount_from * offer.rate) // ci_from.COIN()), + 'amt_to': ci_to.format_amount(offer.amount_to), 'validhrs': offer.time_valid // (60 * 60), 'swap_type': strSwapType(offer.swap_type), } @@ -579,7 +584,7 @@ def page_offer(self, url_split, post_string): 'coin_from_ind': int(ci_from.coin_type()), 'coin_to_ind': int(ci_to.coin_type()), 'amt_from': ci_from.format_amount(offer.amount_from), - 'amt_to': ci_to.format_amount((offer.amount_from * offer.rate) // ci_from.COIN()), + 'amt_to': ci_to.format_amount(offer.amount_to), 'amt_bid_min': ci_from.format_amount(offer.min_bid_amount), 'rate': ci_to.format_amount(offer.rate), 'lock_type': getLockName(offer.lock_type), @@ -781,7 +786,7 @@ def page_offers(self, url_split, post_string, sent=False): ci_from.coin_name(), ci_to.coin_name(), ci_from.format_amount(o.amount_from), - ci_to.format_amount((o.amount_from * o.rate) // ci_from.COIN()), + ci_to.format_amount(o.amount_to), ci_to.format_amount(o.rate), 'Public' if o.addr_to == swap_client.network_addr else o.addr_to, o.addr_from, diff --git a/basicswap/ui/util.py b/basicswap/ui/util.py index beea7c7..39f2fe6 100644 --- a/basicswap/ui/util.py +++ b/basicswap/ui/util.py @@ -162,12 +162,14 @@ def describeBid(swap_client, bid, xmr_swap, offer, xmr_offer, bid_events, edit_b ci_follower = ci_from if reverse_bid else ci_to bid_amount: int = bid.amount + bid_amount_to: int = bid.amount_to bid_rate: int = offer.rate if bid.rate is None else bid.rate initiator_role: str = 'offerer' # Leader participant_role: str = 'bidder' # Follower if reverse_bid: bid_amount = bid.amount_to + bid_amount_to = bid.amount bid_rate = ci_from.make_int(bid.amount / bid.amount_to, r=1) initiator_role = 'bidder' participant_role = 'offerer' @@ -259,7 +261,7 @@ def describeBid(swap_client, bid, xmr_swap, offer, xmr_offer, bid_events, edit_b 'coin_from': ci_from.coin_name(), 'coin_to': ci_to.coin_name(), 'amt_from': ci_from.format_amount(bid_amount), - 'amt_to': ci_to.format_amount((bid_amount * bid_rate) // ci_from.COIN()), + 'amt_to': ci_to.format_amount(bid_amount_to), 'bid_rate': ci_to.format_amount(bid_rate), 'ticker_from': ci_from.ticker(), 'ticker_to': ci_to.ticker(), diff --git a/doc/release-notes.md b/doc/release-notes.md index 6d463de..9c009e4 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,3 +1,13 @@ + +0.13.0 +============== + +- GUI v3.0 +- Bid and offer states change when expired. +- bid amounts are specified directly and not constructed from rate. +- Breaks compatibility with prior versions. + + 0.12.7 ============== diff --git a/tests/basicswap/test_btc_xmr.py b/tests/basicswap/test_btc_xmr.py index e548dad..9c093e7 100644 --- a/tests/basicswap/test_btc_xmr.py +++ b/tests/basicswap/test_btc_xmr.py @@ -185,7 +185,7 @@ class TestFunctions(BaseTest): bid0 = read_json_api(1800 + id_offerer, f'bids/{bid_id.hex()}') bid1 = read_json_api(1800 + id_bidder, f'bids/{bid_id.hex()}') - tolerance = 20 if reverse_bid else 0 + tolerance = 1 assert (bid0['ticker_from'] == ci_from.ticker()) assert (bid1['ticker_from'] == ci_from.ticker()) assert (bid0['ticker_to'] == ci_to.ticker()) diff --git a/tests/basicswap/test_other.py b/tests/basicswap/test_other.py index a0ccdeb..98adce3 100644 --- a/tests/basicswap/test_other.py +++ b/tests/basicswap/test_other.py @@ -6,6 +6,7 @@ # file LICENSE or http://www.opensource.org/licenses/mit-license.php. import hashlib +import random import secrets import unittest @@ -41,7 +42,7 @@ from basicswap.util import ( from basicswap.messages_pb2 import ( BidMessage, - BidMessage_v1Deprecated, + BidMessage_test, ) from basicswap.contrib.test_framework.script import hash160 as hash160_btc @@ -310,6 +311,89 @@ class Test(unittest.TestCase): amount_to_recreate = int((amount_from * rate) // (10 ** scale_from)) assert ('10.00000000' == format_amount(amount_to_recreate, scale_to)) + coin_settings = {'rpcport': 0, 'rpcauth': 'none', 'walletrpcport': 0, 'walletrpcauth': 'none'} + coin_settings.update(self.REQUIRED_SETTINGS) + ci_xmr = XMRInterface(coin_settings, 'regtest') + ci_btc = BTCInterface(coin_settings, 'regtest') + + for i in range(10000): + + test_pairs = random.randint(0, 3) + if test_pairs == 0: + ci_from = ci_btc + ci_to = ci_xmr + elif test_pairs == 1: + ci_from = ci_xmr + ci_to = ci_btc + elif test_pairs == 2: + ci_from = ci_xmr + ci_to = ci_xmr + else: + ci_from = ci_btc + ci_to = ci_btc + + test_range = random.randint(0, 5) + if test_range == 0: + amount_from = random.randint(10000, 1 * ci_from.COIN()) + elif test_range == 1: + amount_from = random.randint(10000, 1000 * ci_from.COIN()) + elif test_range == 2: + amount_from = random.randint(10000, 2100 * ci_from.COIN()) + elif test_range == 3: + amount_from = random.randint(10000, 210000 * ci_from.COIN()) + elif test_range == 4: + amount_from = random.randint(10000, 21000000 * ci_from.COIN()) + else: + amount_from = random.randint(10000, 2100000000 * ci_from.COIN()) + + test_range = random.randint(0, 5) + if test_range == 0: + amount_to = random.randint(10000, 1 * ci_to.COIN()) + elif test_range == 1: + amount_to = random.randint(10000, 1000 * ci_to.COIN()) + elif test_range == 2: + amount_to = random.randint(10000, 2100 * ci_to.COIN()) + elif test_range == 3: + amount_to = random.randint(10000, 210000 * ci_to.COIN()) + elif test_range == 4: + amount_to = random.randint(10000, 21000000 * ci_to.COIN()) + else: + amount_to = random.randint(10000, 2100000000 * ci_to.COIN()) + + offer_rate = ci_from.make_int(amount_to / amount_from, r=1) + amount_to_from_rate: int = int((int(amount_from) * offer_rate) // (10 ** scale_from)) + + scale_from = 24 + offer_rate = make_int(amount_to, scale_from) // amount_from + amount_to_from_rate: int = int((int(amount_from) * offer_rate) // (10 ** scale_from)) + + if abs(amount_to - amount_to_from_rate) == 1: + offer_rate += 1 + + offer_rate_human_read: int = int(offer_rate // (10 ** (scale_from - ci_from.exp()))) + amount_to_from_rate: int = int((int(amount_from) * offer_rate) // (10 ** scale_from)) + + if amount_to != amount_to_from_rate: + print('from exp, amount', ci_from.exp(), amount_from) + print('to exp, amount', ci_to.exp(), amount_to) + print('amount_to_from_rate', amount_to_from_rate) + raise ValueError('Bad amount_to') + + scale_to = 24 + reversed_rate = make_int(amount_from, scale_to) // amount_to + + amount_from_from_rate: int = int((int(amount_to) * reversed_rate) // (10 ** scale_to)) + if abs(amount_from - amount_from_from_rate) == 1: + reversed_rate += 1 + + amount_from_from_rate: int = int((int(amount_to) * reversed_rate) // (10 ** scale_to)) + + if amount_from != amount_from_from_rate: + print('from exp, amount', ci_from.exp(), amount_from) + print('to exp, amount', ci_to.exp(), amount_to) + print('amount_from_from_rate', amount_from_from_rate) + raise ValueError('Bad amount_from') + def test_rfc2440(self): password = 'test' salt = bytes.fromhex('B7A94A7E4988630E') @@ -330,14 +414,20 @@ class Test(unittest.TestCase): def test_protobuf(self): # Ensure old protobuf templates can be read - msg_buf = BidMessage_v1Deprecated() + msg_buf = BidMessage_test() msg_buf.protocol_version = 2 + msg_buf.time_valid = 1024 serialised_msg = msg_buf.SerializeToString() msg_buf_v2 = BidMessage() msg_buf_v2.ParseFromString(serialised_msg) - assert (msg_buf_v2.protocol_version == 2) + assert (msg_buf_v2.time_valid == 1024) + + # Decode only the first field + msg_buf_v2.ParseFromString(serialised_msg[:2]) + assert (msg_buf_v2.protocol_version == 2) + assert (msg_buf_v2.time_valid == 0) def test_is_private_ip_address(self): assert (is_private_ip_address('localhost'))