Raise version, transmit amount to instead of rate.

This commit is contained in:
tecnovert
2024-04-14 14:45:13 +02:00
parent 463c51c822
commit 8a279dc71f
12 changed files with 288 additions and 170 deletions

View File

@@ -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: