Add address submission and validation checks

This commit is contained in:
Reckless_Satoshi 2022-06-13 15:27:09 -07:00
parent c4396f504a
commit 8f93c8f7b6
No known key found for this signature in database
GPG Key ID: 9C4585B561315571
4 changed files with 86 additions and 12 deletions

View File

@ -1,5 +1,5 @@
from datetime import timedelta from datetime import timedelta
from tkinter import N from tkinter import N, ON
from django.utils import timezone from django.utils import timezone
from api.lightning.node import LNNode from api.lightning.node import LNNode
from django.db.models import Q, Sum from django.db.models import Q, Sum
@ -7,6 +7,7 @@ from django.db.models import Q, Sum
from api.models import OnchainPayment, Order, LNPayment, MarketTick, User, Currency from api.models import OnchainPayment, Order, LNPayment, MarketTick, User, Currency
from api.tasks import send_message from api.tasks import send_message
from decouple import config from decouple import config
from api.utils import validate_onchain_address
import gnupg import gnupg
@ -550,7 +551,7 @@ class Logics:
if suggested_mining_fee_rate > 50: if suggested_mining_fee_rate > 50:
suggested_mining_fee_rate = 50 suggested_mining_fee_rate = 50
onchain_payment.suggested_mining_fee_rate = LNNode.estimate_fee(amount_sats=preliminary_amount)["mining_fee_rate"] onchain_payment.suggested_mining_fee_rate = max(1.05, LNNode.estimate_fee(amount_sats=preliminary_amount)["mining_fee_rate"])
onchain_payment.swap_fee_rate = cls.compute_swap_fee_rate(onchain_payment.balance) onchain_payment.swap_fee_rate = cls.compute_swap_fee_rate(onchain_payment.balance)
onchain_payment.save() onchain_payment.save()
@ -621,6 +622,67 @@ class Logics:
return True, {"escrow_amount": escrow_amount} return True, {"escrow_amount": escrow_amount}
@classmethod
def update_address(cls, order, user, address, mining_fee_rate):
# Empty address?
if not address:
return False, {
"bad_address":
"You submitted an empty invoice"
}
# only the buyer can post a buyer address
if not cls.is_buyer(order, user):
return False, {
"bad_request":
"Only the buyer of this order can provide a payout address."
}
# not the right time to submit
if (not (order.taker_bond.status == order.maker_bond.status ==
LNPayment.Status.LOCKED)
and not order.status == Order.Status.FAI):
return False, {
"bad_request":
"You cannot submit an adress are not locked."
}
# not a valid address (does not accept Taproot as of now)
if not validate_onchain_address(address):
return False, {
"bad_address":
"Does not look like a valid address"
}
if mining_fee_rate:
# not a valid mining fee
if float(mining_fee_rate) <= 1:
return False, {
"bad_address":
"The mining fee is too low."
}
elif float(mining_fee_rate) > 50:
return False, {
"bad_address":
"The mining fee is too high."
}
order.payout_tx.mining_fee_rate = float(mining_fee_rate)
# If not mining ee provider use backend's suggested fee rate
else:
order.payout_tx.mining_fee_rate = order.payout_tx.suggested_mining_fee_rate
tx = order.payout_tx
tx.address = address
tx.mining_fee_sats = int(tx.mining_fee_rate * 141)
tx.num_satoshis = cls.payout_amount(order, user)[1]["invoice_amount"]
tx.sent_satoshis = int(float(tx.num_satoshis) - float(tx.num_satoshis) * float(tx.swap_fee_rate)/100 - float(tx.mining_fee_sats))
tx.status = OnchainPayment.Status.VALID
tx.save()
order.is_swap = True
order.save()
cls.move_state_updated_payout_method(order)
return True, None
@classmethod @classmethod
def update_invoice(cls, order, user, invoice): def update_invoice(cls, order, user, invoice):
@ -677,6 +739,15 @@ class Logics:
}, },
) )
order.is_swap = False
order.save()
cls.move_state_updated_payout_method(order)
return True, None
@classmethod
def move_state_updated_payout_method(cls,order):
# If the order status is 'Waiting for invoice'. Move forward to 'chat' # If the order status is 'Waiting for invoice'. Move forward to 'chat'
if order.status == Order.Status.WFI: if order.status == Order.Status.WFI:
order.status = Order.Status.CHA order.status = Order.Status.CHA
@ -706,10 +777,9 @@ class Logics:
order.payout.status = LNPayment.Status.FLIGHT order.payout.status = LNPayment.Status.FLIGHT
order.payout.routing_attempts = 0 order.payout.routing_attempts = 0
order.payout.save() order.payout.save()
order.save()
order.save() order.save()
return True, None return True
def add_profile_rating(profile, rating): def add_profile_rating(profile, rating):
"""adds a new rating to a user profile""" """adds a new rating to a user profile"""

View File

@ -205,10 +205,14 @@ class OnchainPayment(models.Model):
num_satoshis = models.PositiveBigIntegerField(null=True, num_satoshis = models.PositiveBigIntegerField(null=True,
validators=[ validators=[
MinValueValidator(0.7 * MIN_SWAP_AMOUNT), MinValueValidator(0.5 * MIN_SWAP_AMOUNT),
MaxValueValidator(1.5 * MAX_TRADE),
])
sent_satoshis = models.PositiveBigIntegerField(null=True,
validators=[
MinValueValidator(0.5 * MIN_SWAP_AMOUNT),
MaxValueValidator(1.5 * MAX_TRADE), MaxValueValidator(1.5 * MAX_TRADE),
]) ])
# fee in sats/vbyte with mSats decimals fee_msat # fee in sats/vbyte with mSats decimals fee_msat
suggested_mining_fee_rate = models.DecimalField(max_digits=6, suggested_mining_fee_rate = models.DecimalField(max_digits=6,
decimal_places=3, decimal_places=3,

View File

@ -337,7 +337,7 @@ class OrderView(viewsets.ViewSet):
elif data["is_buyer"] and (order.status == Order.Status.WF2 elif data["is_buyer"] and (order.status == Order.Status.WF2
or order.status == Order.Status.WFI): or order.status == Order.Status.WFI):
# If the two bonds are locked, reply with an AMOUNT and onchain swap cost so he can send the buyer invoice/address # If the two bonds are locked, reply with an AMOUNT and onchain swap cost so he can send the buyer invoice/address.
if (order.maker_bond.status == order.taker_bond.status == if (order.maker_bond.status == order.taker_bond.status ==
LNPayment.Status.LOCKED): LNPayment.Status.LOCKED):
valid, context = Logics.payout_amount(order, request.user) valid, context = Logics.payout_amount(order, request.user)
@ -467,7 +467,7 @@ class OrderView(viewsets.ViewSet):
if not valid: if not valid:
return Response(context, status.HTTP_400_BAD_REQUEST) return Response(context, status.HTTP_400_BAD_REQUEST)
# 2.b) If action is 'update invoice' # 2.b) If action is 'update address'
if action == "update_address": if action == "update_address":
valid, context = Logics.update_address(order, request.user, valid, context = Logics.update_address(order, request.user,
address, mining_fee_rate) address, mining_fee_rate)

View File

@ -578,7 +578,7 @@ class TradeBox extends Component {
}; };
fetch('/api/order/' + '?order_id=' + this.props.data.id, requestOptions) fetch('/api/order/' + '?order_id=' + this.props.data.id, requestOptions)
.then((response) => response.json()) .then((response) => response.json())
.then((data) => this.setState({badAddress:data_address}) .then((data) => this.setState({badAddress:data.bad_address})
& this.props.completeSetState(data)); & this.props.completeSetState(data));
} }
@ -659,7 +659,7 @@ class TradeBox extends Component {
<Paper elevation={2}> <Paper elevation={2}>
<Tabs value={this.state.receiveTab} variant="fullWidth" sx={{width:290}}> <Tabs value={this.state.receiveTab} variant="fullWidth" sx={{width:290}}>
<Tab disableRipple={true} label={<div style={{display:'flex', alignItems:'center', justifyContent:'center', flexWrap:'wrap'}}><BoltIcon/> Lightning</div>} onClick={() => this.setState({receiveTab:0})}/> <Tab disableRipple={true} label={<div style={{display:'flex', alignItems:'center', justifyContent:'center', flexWrap:'wrap'}}><BoltIcon/> Lightning</div>} onClick={() => this.setState({receiveTab:0})}/>
<Tab label={<div style={{display:'flex', alignItems:'center', justifyContent:'center', flexWrap:'wrap'}}><LinkIcon/> Onchain</div>} disabled={!this.props.data.swap_allowed} onClick={() => this.setState({receiveTab:1, miningFee: this.props.data.suggested_mining_fee_rate})} /> <Tab label={<div style={{display:'flex', alignItems:'center', justifyContent:'center', flexWrap:'wrap'}}><LinkIcon/> Onchain</div>} disabled={!this.props.data.swap_allowed} onClick={() => this.setState({receiveTab:1, miningFee: parseFloat(this.props.data.suggested_mining_fee_rate)})} />
</Tabs> </Tabs>
</Paper> </Paper>
</ListItem> </ListItem>
@ -777,7 +777,7 @@ class TradeBox extends Component {
<div style={{height:10}}/> <div style={{height:10}}/>
<Grid item xs={12} align="center"> <Grid item xs={12} align="center">
<Button onClick={null} variant='contained' color='primary'>{t("Submit")}</Button> <Button onClick={this.handleClickSubmitAddressButton} variant='contained' color='primary'>{t("Submit")}</Button>
</Grid> </Grid>
</div> </div>
<List> <List>