Implement CLTV_expiries for each hold invoice duration. Invoice expiry matches status time to lock it.

This commit is contained in:
Reckless_Satoshi 2022-01-24 09:54:44 -08:00
parent 4d0c62734c
commit 51d65fd15e
No known key found for this signature in database
GPG Key ID: 9C4585B561315571
9 changed files with 33 additions and 20 deletions

View File

@ -28,7 +28,7 @@ RETRY_TIME = 5
MIN_TRADE = 10000 MIN_TRADE = 10000
MAX_TRADE = 500000 MAX_TRADE = 500000
# Expiration time for HODL invoices and returning collateral in HOURS # Expiration (CLTV_expiry) time for HODL invoices in HOURS // 7 min/block assumed
BOND_EXPIRY = 14 BOND_EXPIRY = 14
ESCROW_EXPIRY = 8 ESCROW_EXPIRY = 8

View File

@ -64,7 +64,7 @@ class LNNode():
return str(response)=="" # True if no response, false otherwise. return str(response)=="" # True if no response, false otherwise.
@classmethod @classmethod
def gen_hold_invoice(cls, num_satoshis, description, expiry): def gen_hold_invoice(cls, num_satoshis, description, invoice_expiry, cltv_expiry_secs):
'''Generates hold invoice''' '''Generates hold invoice'''
hold_payment = {} hold_payment = {}
@ -73,12 +73,16 @@ 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,
hash=r_hash, hash=r_hash,
expiry=expiry) expiry=invoice_expiry,
cltv_expiry=cltv_expiry_blocks,
)
response = cls.invoicesstub.AddHoldInvoice(request, metadata=[('macaroon', MACAROON.hex())]) response = cls.invoicesstub.AddHoldInvoice(request, metadata=[('macaroon', MACAROON.hex())])
hold_payment['invoice'] = response.payment_request hold_payment['invoice'] = response.payment_request

View File

@ -500,7 +500,10 @@ class Logics():
description = f"RoboSats - Publishing '{str(order)}' - This is a maker bond, it will freeze in your wallet temporarily and automatically return. It will be charged if you cheat or cancel." description = f"RoboSats - Publishing '{str(order)}' - This is a maker bond, it will freeze in your wallet temporarily and automatically return. It will be charged if you cheat or cancel."
# Gen hold Invoice # Gen hold Invoice
hold_payment = LNNode.gen_hold_invoice(bond_satoshis, description, BOND_EXPIRY*3600) hold_payment = LNNode.gen_hold_invoice(bond_satoshis,
description,
invoice_expiry=Order.t_to_expire[Order.Status.WFB],
cltv_expiry_secs=BOND_EXPIRY*3600)
order.maker_bond = LNPayment.objects.create( order.maker_bond = LNPayment.objects.create(
concept = LNPayment.Concepts.MAKEBOND, concept = LNPayment.Concepts.MAKEBOND,
@ -577,7 +580,10 @@ class Logics():
+ " - This is a taker bond, it will freeze in your wallet temporarily and automatically return. It will be charged if you cheat or cancel.") + " - This is a taker bond, it will freeze in your wallet temporarily and automatically return. It will be charged if you cheat or cancel.")
# Gen hold Invoice # Gen hold Invoice
hold_payment = LNNode.gen_hold_invoice(bond_satoshis, description, BOND_EXPIRY*3600) hold_payment = LNNode.gen_hold_invoice(bond_satoshis,
description,
invoice_expiry=Order.t_to_expire[Order.Status.TAK],
cltv_expiry_secs=BOND_EXPIRY*3600)
order.taker_bond = LNPayment.objects.create( order.taker_bond = LNPayment.objects.create(
concept = LNPayment.Concepts.TAKEBOND, concept = LNPayment.Concepts.TAKEBOND,
@ -640,7 +646,10 @@ class Logics():
description = f"RoboSats - Escrow amount for '{str(order)}' - The escrow will be released to the buyer once you confirm you received the fiat. It will automatically return if buyer does not confirm the payment." description = f"RoboSats - Escrow amount for '{str(order)}' - The escrow will be released to the buyer once you confirm you received the fiat. It will automatically return if buyer does not confirm the payment."
# Gen hold Invoice # Gen hold Invoice
hold_payment = LNNode.gen_hold_invoice(escrow_satoshis, description, ESCROW_EXPIRY*3600) hold_payment = LNNode.gen_hold_invoice(escrow_satoshis,
description,
invoice_expiry=Order.t_to_expire[Order.Status.WF2],
cltv_expiry_secs=ESCROW_EXPIRY*3600)
order.trade_escrow = LNPayment.objects.create( order.trade_escrow = LNPayment.objects.create(
concept = LNPayment.Concepts.TRESCROW, concept = LNPayment.Concepts.TRESCROW,

View File

@ -62,4 +62,4 @@ class Command(BaseCommand):
if 'database is locked' in str(e): if 'database is locked' in str(e):
self.stdout.write('database is locked') self.stdout.write('database is locked')
self.stdout.write(e) self.stdout.write(str(e))

View File

@ -62,8 +62,8 @@ class Command(BaseCommand):
hold_lnpayment.status = lnd_state_to_lnpayment_status[response.state] hold_lnpayment.status = lnd_state_to_lnpayment_status[response.state]
except Exception as e: except Exception as e:
# If it fails at finding the invoice it has been canceled. # If it fails at finding the invoice: it has been canceled.
# On RoboSats DB we make a distinction between cancelled and returned (LND does not) # In RoboSats DB we make a distinction between cancelled and returned (LND does not)
if 'unable to locate invoice' in str(e): if 'unable to locate invoice' in str(e):
self.stdout.write(str(e)) self.stdout.write(str(e))
hold_lnpayment.status = LNPayment.Status.CANCEL hold_lnpayment.status = LNPayment.Status.CANCEL
@ -140,4 +140,4 @@ class Command(BaseCommand):
if 'database is locked' in str(e): if 'database is locked' in str(e):
self.stdout.write('database is locked') self.stdout.write('database is locked')
self.stdout.write(e) self.stdout.write(str(e))

View File

@ -79,10 +79,10 @@ export default class InfoDialog extends Component {
In addition, disputes are solved by the <i>RoboSats</i> staff. In addition, disputes are solved by the <i>RoboSats</i> staff.
</p> </p>
<p> Trust requirements are minimal, however there is still one way <i>RoboSats</i> <p> To be totally clear. Trust requirements are minimized. However, there is still
could run away with your satoshis: by not releasing one way <i>RoboSats </i> could run away with your satoshis: by not releasing
the satoshis to the buyer. It could be argued that such move is not on <i>RoboSats</i> the satoshis to the buyer. It could be argued that such move is not in <i>RoboSats' </i>
interest as it would damage the reputation for a small payout. as it would damage the reputation for a small payout.
However, you should hesitate and only trade small quantities at a However, you should hesitate and only trade small quantities at a
time. For large amounts use an onchain escrow service such as <i>Bisq</i> time. For large amounts use an onchain escrow service such as <i>Bisq</i>
</p> </p>
@ -98,7 +98,7 @@ export default class InfoDialog extends Component {
forever. This is true for both, locked bonds and trading escrows. However, forever. This is true for both, locked bonds and trading escrows. However,
there is a small window between the seller confirms FIAT RECEIVED and the moment there is a small window between the seller confirms FIAT RECEIVED and the moment
the buyer receives the satoshis when the funds could be permanentely lost if the buyer receives the satoshis when the funds could be permanentely lost if
<i>RoboSats</i> disappears. This window is about 1 second long. Make sure to have enough <i> RoboSats</i> disappears. This window is about 1 second long. Make sure to have enough
inbound liquidity to avoid routing failures. If you have any problem, reach out inbound liquidity to avoid routing failures. If you have any problem, reach out
trough the <i>RoboSats</i> public channels. trough the <i>RoboSats</i> public channels.
</p> </p>

View File

@ -52,7 +52,7 @@ export default class OrderPage extends Component {
// Refresh delays according to Order status // Refresh delays according to Order status
this.statusToDelay = { this.statusToDelay = {
"0": 2000, //'Waiting for maker bond' "0": 2000, //'Waiting for maker bond'
"1": 15000, //'Public' "1": 45000, //'Public'
"2": 9999999, //'Deleted' "2": 9999999, //'Deleted'
"3": 2000, //'Waiting for taker bond' "3": 2000, //'Waiting for taker bond'
"4": 9999999, //'Cancelled' "4": 9999999, //'Cancelled'
@ -87,7 +87,7 @@ export default class OrderPage extends Component {
delay: this.setDelay(newStateVars.status), delay: this.setDelay(newStateVars.status),
currencyCode: this.getCurrencyCode(newStateVars.currency), currencyCode: this.getCurrencyCode(newStateVars.currency),
}; };
var completeStateVars = Object.assign({}, newStateVars, otherStateVars); var completeStateVars = Object.assign({}, newStateVars, otherStateVars);
this.setState(completeStateVars); this.setState(completeStateVars);
} }

View File

@ -147,7 +147,7 @@ export default class TradeBox extends Component {
<Grid container spacing={1}> <Grid container spacing={1}>
<Grid item xs={12} align="center"> <Grid item xs={12} align="center">
<Typography component="body2" variant="body2"> <Typography component="body2" variant="body2">
Robosats show commitment to their peers Robots show commitment to their peers
</Typography> </Typography>
</Grid> </Grid>
<Grid item xs={12} align="center"> <Grid item xs={12} align="center">
@ -665,7 +665,7 @@ handleRatingChange=(e)=>{
showRoutingFailed(){ showRoutingFailed(){
// TODO If it has failed 3 times, ask for a new invoice. // TODO If it has failed 3 times, ask for a new invoice.
return( return(
<Grid container spacing={1}> <Grid container spacing={1}>
<Grid item xs={12} align="center"> <Grid item xs={12} align="center">