mirror of
https://github.com/RoboSats/robosats.git
synced 2025-01-31 02:21:35 +00:00
Logics update: escrow settles exactly at buyer payout time.
This commit is contained in:
parent
bfa0cd84d1
commit
7218b9b0d3
@ -514,8 +514,7 @@ class Logics():
|
|||||||
|
|
||||||
# Do not gen and kick out the taker if order is older than expiry time
|
# Do not gen and kick out the taker if order is older than expiry time
|
||||||
if order.expires_at < timezone.now():
|
if order.expires_at < timezone.now():
|
||||||
cls.cancel_bond(order.taker_bond)
|
cls.order_expires(order)
|
||||||
cls.kick_taker(order)
|
|
||||||
return False, {'bad_request':'Invoice expired. You did not confirm taking the order in time.'}
|
return False, {'bad_request':'Invoice expired. You did not confirm taking the order in time.'}
|
||||||
|
|
||||||
# Do not gen if a taker invoice exist. Do not return if it is already locked. Return the old one if still waiting.
|
# Do not gen if a taker invoice exist. Do not return if it is already locked. Return the old one if still waiting.
|
||||||
@ -580,7 +579,7 @@ class Logics():
|
|||||||
|
|
||||||
# Do not generate if escrow deposit time has expired
|
# Do not generate if escrow deposit time has expired
|
||||||
if order.expires_at < timezone.now():
|
if order.expires_at < timezone.now():
|
||||||
cls.cancel_order(order,user)
|
cls.order_expires(order)
|
||||||
return False, {'bad_request':'Invoice expired. You did not send the escrow in time.'}
|
return False, {'bad_request':'Invoice expired. You did not send the escrow in time.'}
|
||||||
|
|
||||||
# Do not gen if an escrow invoice exist. Do not return if it is already locked. Return the old one if still waiting.
|
# Do not gen if an escrow invoice exist. Do not return if it is already locked. Return the old one if still waiting.
|
||||||
@ -690,12 +689,10 @@ class Logics():
|
|||||||
|
|
||||||
# If buyer, settle escrow and mark fiat sent
|
# If buyer, settle escrow and mark fiat sent
|
||||||
if cls.is_buyer(order, user):
|
if cls.is_buyer(order, user):
|
||||||
if cls.settle_escrow(order): ##### !!! KEY LINE - SETTLES THE TRADE ESCROW !!!
|
order.status = Order.Status.FSE
|
||||||
order.trade_escrow.status = LNPayment.Status.SETLED
|
order.is_fiat_sent = True
|
||||||
order.status = Order.Status.FSE
|
|
||||||
order.is_fiat_sent = True
|
|
||||||
|
|
||||||
# If seller and fiat sent, pay buyer invoice
|
# If seller and fiat was sent, SETTLE ESCRO AND PAY BUYER INVOICE
|
||||||
elif cls.is_seller(order, user):
|
elif cls.is_seller(order, user):
|
||||||
if not order.is_fiat_sent:
|
if not order.is_fiat_sent:
|
||||||
return False, {'bad_request':'You cannot confirm to have received the fiat before it is confirmed to be sent by the buyer.'}
|
return False, {'bad_request':'You cannot confirm to have received the fiat before it is confirmed to be sent by the buyer.'}
|
||||||
@ -703,6 +700,9 @@ class Logics():
|
|||||||
# Make sure the trade escrow is at least as big as the buyer invoice
|
# Make sure the trade escrow is at least as big as the buyer invoice
|
||||||
if order.trade_escrow.num_satoshis <= order.buyer_invoice.num_satoshis:
|
if order.trade_escrow.num_satoshis <= order.buyer_invoice.num_satoshis:
|
||||||
return False, {'bad_request':'Woah, something broke badly. Report in the public channels, or open a Github Issue.'}
|
return False, {'bad_request':'Woah, something broke badly. Report in the public channels, or open a Github Issue.'}
|
||||||
|
|
||||||
|
if cls.settle_escrow(order): ##### !!! KEY LINE - SETTLES THE TRADE ESCROW !!!
|
||||||
|
order.trade_escrow.status = LNPayment.Status.SETLED
|
||||||
|
|
||||||
# Double check the escrow is settled.
|
# Double check the escrow is settled.
|
||||||
if LNNode.double_check_htlc_is_settled(order.trade_escrow.payment_hash):
|
if LNNode.double_check_htlc_is_settled(order.trade_escrow.payment_hash):
|
||||||
|
@ -15,6 +15,8 @@ class Command(BaseCommand):
|
|||||||
''' Continuously checks order expiration times for 1 hour. If order
|
''' Continuously checks order expiration times for 1 hour. If order
|
||||||
has expires, it calls the logics module for expiration handling.'''
|
has expires, it calls the logics module for expiration handling.'''
|
||||||
|
|
||||||
|
# TODO handle 'database is locked'
|
||||||
|
|
||||||
do_nothing = [Order.Status.DEL, Order.Status.UCA,
|
do_nothing = [Order.Status.DEL, Order.Status.UCA,
|
||||||
Order.Status.EXP, Order.Status.FSE,
|
Order.Status.EXP, Order.Status.FSE,
|
||||||
Order.Status.DIS, Order.Status.CCA,
|
Order.Status.DIS, Order.Status.CCA,
|
||||||
@ -34,8 +36,17 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
for idx, order in enumerate(queryset):
|
for idx, order in enumerate(queryset):
|
||||||
context = str(order)+ " was "+ Order.Status(order.status).label
|
context = str(order)+ " was "+ Order.Status(order.status).label
|
||||||
if Logics.order_expires(order): # Order send to expire here
|
try:
|
||||||
debug['expired_orders'].append({idx:context})
|
if Logics.order_expires(order): # Order send to expire here
|
||||||
|
debug['expired_orders'].append({idx:context})
|
||||||
|
|
||||||
|
# If it cannot locate the hold invoice, make it expire anywway
|
||||||
|
except Exception as e:
|
||||||
|
if 'unable to locate invoice' in str(e):
|
||||||
|
self.stdout.write(str(e))
|
||||||
|
order.status = Order.Status.EXP
|
||||||
|
debug['expired_orders'].append({idx:context})
|
||||||
|
|
||||||
|
|
||||||
if debug['num_expired_orders'] > 0:
|
if debug['num_expired_orders'] > 0:
|
||||||
self.stdout.write(str(timezone.now()))
|
self.stdout.write(str(timezone.now()))
|
||||||
|
@ -31,6 +31,8 @@ class Command(BaseCommand):
|
|||||||
''' Follows and updates LNpayment objects
|
''' Follows and updates LNpayment objects
|
||||||
until settled or canceled'''
|
until settled or canceled'''
|
||||||
|
|
||||||
|
# TODO handle 'database is locked'
|
||||||
|
|
||||||
lnd_state_to_lnpayment_status = {
|
lnd_state_to_lnpayment_status = {
|
||||||
0: LNPayment.Status.INVGEN, # OPEN
|
0: LNPayment.Status.INVGEN, # OPEN
|
||||||
1: LNPayment.Status.SETLED, # SETTLED
|
1: LNPayment.Status.SETLED, # SETTLED
|
||||||
@ -64,6 +66,7 @@ class Command(BaseCommand):
|
|||||||
# 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)
|
# On 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('unable to locate invoice')
|
||||||
hold_lnpayment.status = LNPayment.Status.CANCEL
|
hold_lnpayment.status = LNPayment.Status.CANCEL
|
||||||
# LND restarted.
|
# LND restarted.
|
||||||
if 'wallet locked, unlock it' in str(e):
|
if 'wallet locked, unlock it' in str(e):
|
||||||
|
@ -70,7 +70,7 @@ def follow_send_payment(lnpayment):
|
|||||||
order.status = Order.Status.FAI
|
order.status = Order.Status.FAI
|
||||||
order.save()
|
order.save()
|
||||||
context = LNNode.payment_failure_context[response.failure_reason]
|
context = LNNode.payment_failure_context[response.failure_reason]
|
||||||
# Call for a retry here
|
# Call a retry here?
|
||||||
return False, context
|
return False, context
|
||||||
|
|
||||||
if response.status == 2 : # Status 2 'SUCCEEDED'
|
if response.status == 2 : # Status 2 'SUCCEEDED'
|
||||||
|
@ -19,7 +19,7 @@ export default class InfoDialog extends Component {
|
|||||||
|
|
||||||
<Typography component="h5" variant="h5">How does it work?</Typography>
|
<Typography component="h5" variant="h5">How does it work?</Typography>
|
||||||
<Typography component="body2" variant="body2">
|
<Typography component="body2" variant="body2">
|
||||||
<p>AdequateAlice01 wants to sell bitcoin. She posts a sell order.
|
<p>Anonymous AdequateAlice01 wants to sell bitcoin. She posts a sell order.
|
||||||
BafflingBob02 wants to buy bitcoin and he takes Alice's order.
|
BafflingBob02 wants to buy bitcoin and he takes Alice's order.
|
||||||
Both have to post a small bond using lightning to prove they are real
|
Both have to post a small bond using lightning to prove they are real
|
||||||
robots. Then, Alice posts the trade collateral also using a lightning
|
robots. Then, Alice posts the trade collateral also using a lightning
|
||||||
@ -51,8 +51,9 @@ export default class InfoDialog extends Component {
|
|||||||
|
|
||||||
<Typography component="h5" variant="h5">Is <i>RoboSats</i> private?</Typography>
|
<Typography component="h5" variant="h5">Is <i>RoboSats</i> private?</Typography>
|
||||||
<Typography component="body2" variant="body2">
|
<Typography component="body2" variant="body2">
|
||||||
<p> RoboSats will never ask you for your name, country or ID. For
|
<p> RoboSats will never ask you for your name, country or ID. RoboSats does
|
||||||
best anonymity use Tor Browser and access the .onion hidden service. </p>
|
not custody your funds, and doesn't care who you are. For best anonymity
|
||||||
|
use Tor Browser and access the .onion hidden service. </p>
|
||||||
|
|
||||||
<p>Your trading peer is the only one who can potentially guess
|
<p>Your trading peer is the only one who can potentially guess
|
||||||
anything about you. Keep your chat short and concise. Avoid
|
anything about you. Keep your chat short and concise. Avoid
|
||||||
@ -73,29 +74,33 @@ export default class InfoDialog extends Component {
|
|||||||
<Typography component="h5" variant="h5">What is the trust model?</Typography>
|
<Typography component="h5" variant="h5">What is the trust model?</Typography>
|
||||||
<Typography component="body2" variant="body2">
|
<Typography component="body2" variant="body2">
|
||||||
<p> The buyer and the seller never have to trust each other.
|
<p> The buyer and the seller never have to trust each other.
|
||||||
Some trust on <i>RoboSats</i> staff is needed since linking
|
Some trust on <i>RoboSats</i> is needed since linking the
|
||||||
the seller's hold invoice and buyer payment is not atomic (yet).
|
seller's hold invoice and buyer payment is not atomic (yet).
|
||||||
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> While trust requirements are minimized, <i>RoboSats</i> could
|
<p> Trust requirements are minimized, however there is still one way
|
||||||
run away with your satoshis. It could be argued that it is not
|
<i>RoboSats</i> could run away with your satoshis, by not releasing
|
||||||
worth it, as it would instantly destroy <i>RoboSats</i> reputation.
|
the satoshis to the buyer. It could be argued that such move is not on
|
||||||
|
<i>RoboSats</i> interest as it would damage thereputation 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>
|
||||||
|
|
||||||
<p> You can build more trust on <i>RoboSats</i> by <a href='https://github.com/reckless-satoshi/robosats'>
|
<p> You can build more trust on <i>RoboSats</i> by <a href='https://github.com/reckless-satoshi/robosats'>
|
||||||
inspecting the source code </a> </p>
|
inspecting the source code. </a> </p>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography component="h5" variant="h5">What happens if <i>RoboSats</i> suddenly disapears?</Typography>
|
<Typography component="h5" variant="h5">What happens if <i>RoboSats</i> suddenly disapears?</Typography>
|
||||||
<Typography component="body2" variant="body2">
|
<Typography component="body2" variant="body2">
|
||||||
<p> Your sats will most likely return to you. Any hold invoice that is not
|
<p> Your sats will return to you. Any hold invoice that is not
|
||||||
settled would be automatically returned even if <i>RoboSats</i> goes down
|
settled would be automatically returned even if <i>RoboSats</i> goes down
|
||||||
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 buyer confirms FIAT SENT and the moment
|
there is a small window between the seller confirms FIAT RECEIVED and the moment
|
||||||
the seller releases the satoshis when the funds could be lost.
|
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
|
||||||
|
inbound liquidity to avoid routing failures. If you have any problem, reach out
|
||||||
|
trough the <i>RoboSats</i> public channels.
|
||||||
</p>
|
</p>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
@ -116,9 +121,7 @@ export default class InfoDialog extends Component {
|
|||||||
RoboSats</i> will definitely never ask for your robot token.
|
RoboSats</i> will definitely never ask for your robot token.
|
||||||
</p>
|
</p>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ export default class TradeBox extends Component {
|
|||||||
size="small"
|
size="small"
|
||||||
defaultValue={this.props.data.bondInvoice}
|
defaultValue={this.props.data.bondInvoice}
|
||||||
disabled="true"
|
disabled="true"
|
||||||
helperText="This is a hold invoice. It will be charged only if you cancel or lose a dispute."
|
helperText="This is a hold invoice, it will freeze in your wallet. It will be charged only if you cancel or lose a dispute."
|
||||||
color = "secondary"
|
color = "secondary"
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -198,7 +198,7 @@ export default class TradeBox extends Component {
|
|||||||
size="small"
|
size="small"
|
||||||
defaultValue={this.props.data.escrowInvoice}
|
defaultValue={this.props.data.escrowInvoice}
|
||||||
disabled="true"
|
disabled="true"
|
||||||
helperText="This is a hold invoice. It will be charged once the buyer confirms he sent the fiat."
|
helperText={"This is a hold invoice, it will freeze in your wallet. It will be released to the buyer once you confirm to have received the "+this.props.data.currencyCode+"."}
|
||||||
color = "secondary"
|
color = "secondary"
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -31,9 +31,9 @@ app.conf.beat_scheduler = 'django_celery_beat.schedulers:DatabaseScheduler'
|
|||||||
|
|
||||||
# Configure the periodic tasks
|
# Configure the periodic tasks
|
||||||
app.conf.beat_schedule = {
|
app.conf.beat_schedule = {
|
||||||
'users-cleansing': { # Cleans abandoned users every hour
|
'users-cleansing': { # Cleans abandoned users every 6 hours
|
||||||
'task': 'users_cleansing',
|
'task': 'users_cleansing',
|
||||||
'schedule': timedelta(hours=1),
|
'schedule': timedelta(hours=6),
|
||||||
},
|
},
|
||||||
'cache-market-prices': { # Cache market prices every minutes for now.
|
'cache-market-prices': { # Cache market prices every minutes for now.
|
||||||
'task': 'cache_external_market_prices',
|
'task': 'cache_external_market_prices',
|
||||||
|
Loading…
Reference in New Issue
Block a user