Tight CLTV expiry dynamically

This commit is contained in:
Reckless_Satoshi 2022-07-21 06:19:47 -07:00
parent 98e2da68d0
commit 8423896285
No known key found for this signature in database
GPG Key ID: 9C4585B561315571
3 changed files with 39 additions and 14 deletions

View File

@ -77,9 +77,11 @@ MIN_TRADE = 20000
MAX_TRADE = 3000000 MAX_TRADE = 3000000
MAX_TRADE_BONDLESS_TAKER = 50000 MAX_TRADE_BONDLESS_TAKER = 50000
# Expiration (CLTV_expiry) time for HODL invoices in HOURS // 7 min/block assumed # For CLTV_expiry calculation
BOND_EXPIRY = 54 # Assume 8 min/block assumed
ESCROW_EXPIRY = 48 BLOCK_TIME = 8
# Safety multiplier in case of mining speed up (CLTV expiry will be times X larger than real time needs for locked bonds/escrow)
MAX_MINING_NETWORK_SPEEDUP_EXPECTED = 1.7
# Expiration time for locking collateral in SECONDS # Expiration time for locking collateral in SECONDS
EXP_MAKER_BOND_INVOICE = 300 EXP_MAKER_BOND_INVOICE = 300
@ -123,7 +125,7 @@ MAX_SWAP_FEE = 0.1
# Liquidity split point (LN/onchain) at which we use MAX_SWAP_FEE # Liquidity split point (LN/onchain) at which we use MAX_SWAP_FEE
MAX_SWAP_POINT = 0 MAX_SWAP_POINT = 0
# Min amount allowed for Swap # Min amount allowed for Swap
MIN_SWAP_AMOUNT = 50000 MIN_SWAP_AMOUNT = 10000
# Reward tip. Reward for every finished trade in the referral program (Satoshis) # Reward tip. Reward for every finished trade in the referral program (Satoshis)
REWARD_TIP = 100 REWARD_TIP = 100

View File

@ -160,7 +160,7 @@ class LNNode:
@classmethod @classmethod
def gen_hold_invoice(cls, num_satoshis, description, invoice_expiry, def gen_hold_invoice(cls, num_satoshis, description, invoice_expiry,
cltv_expiry_secs): cltv_expiry_blocks):
"""Generates hold invoice""" """Generates hold invoice"""
hold_payment = {} hold_payment = {}
@ -170,8 +170,6 @@ class LNNode:
# Its hash is used to generate the hold invoice # Its hash is used to generate the hold invoice
r_hash = hashlib.sha256(preimage).digest() r_hash = hashlib.sha256(preimage).digest()
# timelock expiry for the last hop, computed based on a 10 minutes block with 30% padding (~7 min block)
cltv_expiry_blocks = int(cltv_expiry_secs / (7 * 60))
request = invoicesrpc.AddHoldInvoiceRequest( request = invoicesrpc.AddHoldInvoiceRequest(
memo=description, memo=description,
value=num_satoshis, value=num_satoshis,

View File

@ -27,13 +27,12 @@ MAX_TRADE = int(config("MAX_TRADE"))
EXP_MAKER_BOND_INVOICE = int(config("EXP_MAKER_BOND_INVOICE")) EXP_MAKER_BOND_INVOICE = int(config("EXP_MAKER_BOND_INVOICE"))
EXP_TAKER_BOND_INVOICE = int(config("EXP_TAKER_BOND_INVOICE")) EXP_TAKER_BOND_INVOICE = int(config("EXP_TAKER_BOND_INVOICE"))
BOND_EXPIRY = int(config("BOND_EXPIRY")) BLOCK_TIME = float(config("BLOCK_TIME"))
ESCROW_EXPIRY = int(config("ESCROW_EXPIRY")) MAX_MINING_NETWORK_SPEEDUP_EXPECTED = float(config("MAX_MINING_NETWORK_SPEEDUP_EXPECTED"))
INVOICE_AND_ESCROW_DURATION = int(config("INVOICE_AND_ESCROW_DURATION")) INVOICE_AND_ESCROW_DURATION = int(config("INVOICE_AND_ESCROW_DURATION"))
FIAT_EXCHANGE_DURATION = int(config("FIAT_EXCHANGE_DURATION")) FIAT_EXCHANGE_DURATION = int(config("FIAT_EXCHANGE_DURATION"))
class Logics: class Logics:
@classmethod @classmethod
@ -987,6 +986,31 @@ class Logics:
# send_message.delay(order.id,'order_published') # too spammy # send_message.delay(order.id,'order_published') # too spammy
return return
def compute_cltv_expiry_blocks(order, invoice_concept):
''' Computes timelock CLTV expiry of the last hop in blocks for hodl invoices
invoice_concepts (str): maker_bond, taker_bond, trade_escrow
'''
# Every invoice_concept must be locked by at least the fiat exchange duration
cltv_expiry_secs = order.t_to_expire(Order.Status.CHA)
# Both fidelity bonds must also be locked for deposit_time (escrow duration or WFE status)
if invoice_concept in ["taker_bond", "maker_bond"]:
cltv_expiry_secs += order.t_to_expire(Order.Status.WFE)
# Maker bond must also be locked for the full public duration plus the taker bond locking time
if invoice_concept == "maker_bond":
cltv_expiry_secs += order.t_to_expire(Order.Status.PUB)
cltv_expiry_secs += order.t_to_expire(Order.Status.TAK)
# Add a safety marging by multiplying by the maxium expected mining network speed up
safe_cltv_expiry_secs = cltv_expiry_secs * MAX_MINING_NETWORK_SPEEDUP_EXPECTED
# Convert to blocks using assummed average block time (~8 mins/block)
cltv_expiry_blocks = int(safe_cltv_expiry_secs / (BLOCK_TIME * 60))
print(invoice_concept," cltv_expiry_hours:",cltv_expiry_secs/3600," cltv_expiry_blocks:",cltv_expiry_blocks)
return cltv_expiry_blocks
@classmethod @classmethod
def is_maker_bond_locked(cls, order): def is_maker_bond_locked(cls, order):
if order.maker_bond.status == LNPayment.Status.LOCKED: if order.maker_bond.status == LNPayment.Status.LOCKED:
@ -1031,7 +1055,7 @@ class Logics:
bond_satoshis, bond_satoshis,
description, description,
invoice_expiry=order.t_to_expire(Order.Status.WFB), invoice_expiry=order.t_to_expire(Order.Status.WFB),
cltv_expiry_secs=BOND_EXPIRY * 3600, cltv_expiry_blocks=cls.compute_cltv_expiry_blocks(order, "maker_bond")
) )
except Exception as e: except Exception as e:
print(str(e)) print(str(e))
@ -1040,7 +1064,7 @@ class Logics:
"bad_request": "bad_request":
"The Lightning Network Daemon (LND) is down. Write in the Telegram group to make sure the staff is aware." "The Lightning Network Daemon (LND) is down. Write in the Telegram group to make sure the staff is aware."
} }
if "wallet locked" in str(e): elif "wallet locked" in str(e):
return False, { return False, {
"bad_request": "bad_request":
"This is weird, RoboSats' lightning wallet is locked. Check in the Telegram group, maybe the staff has died." "This is weird, RoboSats' lightning wallet is locked. Check in the Telegram group, maybe the staff has died."
@ -1147,7 +1171,7 @@ class Logics:
bond_satoshis, bond_satoshis,
description, description,
invoice_expiry=order.t_to_expire(Order.Status.TAK), invoice_expiry=order.t_to_expire(Order.Status.TAK),
cltv_expiry_secs=BOND_EXPIRY * 3600, cltv_expiry_blocks=cls.compute_cltv_expiry_blocks(order, "taker_bond")
) )
except Exception as e: except Exception as e:
@ -1235,7 +1259,7 @@ class Logics:
escrow_satoshis, escrow_satoshis,
description, description,
invoice_expiry=order.t_to_expire(Order.Status.WF2), invoice_expiry=order.t_to_expire(Order.Status.WF2),
cltv_expiry_secs=ESCROW_EXPIRY * 3600, cltv_expiry_blocks=cls.compute_cltv_expiry_blocks(order, "trade_escrow")
) )
except Exception as e: except Exception as e:
@ -1610,6 +1634,7 @@ class Logics:
summary['mining_fee_sats'] = order.payout_tx.mining_fee_sats summary['mining_fee_sats'] = order.payout_tx.mining_fee_sats
summary['swap_fee_sats'] = round(order.payout_tx.num_satoshis - order.payout_tx.mining_fee_sats - order.payout_tx.sent_satoshis) summary['swap_fee_sats'] = round(order.payout_tx.num_satoshis - order.payout_tx.mining_fee_sats - order.payout_tx.sent_satoshis)
summary['swap_fee_percent'] = order.payout_tx.swap_fee_rate summary['swap_fee_percent'] = order.payout_tx.swap_fee_rate
summary['trade_fee_sats'] = round(order.last_satoshis - summary['received_sats'] - summary['mining_fee_sats'] - summary['swap_fee_sats'])
else: else:
summary['sent_sats'] = order.trade_escrow.num_satoshis summary['sent_sats'] = order.trade_escrow.num_satoshis
summary['received_fiat'] = order.amount summary['received_fiat'] = order.amount