diff --git a/api/lightning/node.py b/api/lightning/node.py
index 400de766..51c3ef1f 100644
--- a/api/lightning/node.py
+++ b/api/lightning/node.py
@@ -16,6 +16,8 @@ from . import lightning_pb2_grpc as lightningstub
from . import router_pb2 as routerrpc
from . import router_pb2_grpc as routerstub
+import time, random
+
#######
# Should work with LND (c-lightning in the future if there are features that deserve the work)
#######
@@ -127,7 +129,7 @@ class LNNode:
}
@classmethod
- def pay_onchain(cls, onchainpayment):
+ def pay_onchain(cls, onchainpayment, valid_code=1, on_mempool_code=2):
"""Send onchain transaction for buyer payouts"""
if config("DISABLE_ONCHAIN", cast=bool):
@@ -141,14 +143,24 @@ class LNNode:
spend_unconfirmed=True,
)
- response = cls.lightningstub.SendCoins(
- request, metadata=[("macaroon", MACAROON.hex())]
- )
+ # Cheap security measure to ensure there has been some non-deterministic time between request and DB check
+ time.sleep(random.uniform(0.5, 10))
- onchainpayment.txid = response.txid
- onchainpayment.save()
+ if onchainpayment.status == valid_code:
+ # Changing the state to "MEMPO" should be atomic with SendCoins.
+ onchainpayment.status = on_mempool_code
+ onchainpayment.save()
+ response = cls.lightningstub.SendCoins(
+ request, metadata=[("macaroon", MACAROON.hex())]
+ )
- return True
+ onchainpayment.txid = response.txid
+ onchainpayment.save()
+ return True
+
+ elif onchainpayment.status == on_mempool_code:
+ # Bug, double payment attempted
+ return True
@classmethod
def cancel_return_hold_invoice(cls, payment_hash):
diff --git a/api/logics.py b/api/logics.py
index 2f2a84fd..d718bd04 100644
--- a/api/logics.py
+++ b/api/logics.py
@@ -734,7 +734,11 @@ class Logics:
if not order.taker_bond:
return False, {"bad_request": "Wait for your order to be taken."}
if (
- not ( order.taker_bond.status == order.maker_bond.status == LNPayment.Status.LOCKED)
+ not (
+ order.taker_bond.status
+ == order.maker_bond.status
+ == LNPayment.Status.LOCKED
+ )
and not order.status == Order.Status.FAI
):
return False, {
@@ -753,7 +757,7 @@ class Logics:
payout = LNNode.validate_ln_invoice(invoice, num_satoshis)
if not payout["valid"]:
- return False, payout['context']
+ return False, payout["context"]
order.payout, _ = LNPayment.objects.update_or_create(
concept=LNPayment.Concepts.PAYBUYER,
@@ -763,10 +767,10 @@ class Logics:
receiver=user,
# if there is a LNPayment matching these above, it updates that one with defaults below.
defaults={
- "invoice":invoice,
- "status":LNPayment.Status.VALIDI,
- "num_satoshis":num_satoshis,
- "description": payout['description'],
+ "invoice": invoice,
+ "status": LNPayment.Status.VALIDI,
+ "num_satoshis": num_satoshis,
+ "description": payout["description"],
"payment_hash": payout["payment_hash"],
"created_at": payout["created_at"],
"expires_at": payout["expires_at"],
@@ -1429,10 +1433,12 @@ class Logics:
if not order.payout_tx.status == OnchainPayment.Status.VALID:
return False
- valid = LNNode.pay_onchain(order.payout_tx)
+ valid = LNNode.pay_onchain(
+ order.payout_tx,
+ valid_code=OnchainPayment.Status.VALID,
+ on_mempool_code=OnchainPayment.Status.MEMPO,
+ )
if valid:
- order.payout_tx.status = OnchainPayment.Status.MEMPO
- order.payout_tx.save()
order.status = Order.Status.SUC
order.save()
send_message.delay(order.id, "trade_successful")
diff --git a/frontend/src/components/TradeBox/index.js b/frontend/src/components/TradeBox/index.js
index b28e9b36..c40acd5f 100644
--- a/frontend/src/components/TradeBox/index.js
+++ b/frontend/src/components/TradeBox/index.js
@@ -6,7 +6,6 @@ import {
ToggleButtonGroup,
ToggleButton,
IconButton,
- Box,
Link,
Paper,
Rating,
@@ -27,6 +26,7 @@ import {
DialogContentText,
DialogTitle,
} from '@mui/material';
+import { LoadingButton } from '@mui/lab';
import QRCode from 'react-qr-code';
import Countdown, { zeroPad } from 'react-countdown';
import Chat from './EncryptedChat';
@@ -61,6 +61,10 @@ class TradeBox extends Component {
super(props);
this.state = {
openConfirmFiatReceived: false,
+ loadingButtonFiatSent: false,
+ loadingButtonFiatReceived: false,
+ loadingSubmitInvoice: false,
+ loadingSubmitAddress: false,
openConfirmDispute: false,
receiveTab: 0,
address: '',
@@ -232,7 +236,15 @@ class TradeBox extends Component {
-
+