mirror of
https://github.com/RoboSats/robosats.git
synced 2024-12-25 13:22:38 +03:00
Add stealth invoices (#210)
* Add stealth invoice switch to profile * Add stealth invoice including only order uuid * Add explanatory tooltip for stealth invoices and fix code smells
This commit is contained in:
parent
6090e21f6a
commit
eff58dc91d
@ -1043,7 +1043,10 @@ class Logics:
|
||||
order.last_satoshis_time = timezone.now()
|
||||
bond_satoshis = int(order.last_satoshis * order.bond_size/100)
|
||||
|
||||
description = f"RoboSats - Publishing '{str(order)}' - Maker bond - This payment WILL FREEZE IN YOUR WALLET, check on the website if it was successful. It will automatically return unless you cheat or cancel unilaterally."
|
||||
if user.profile.wants_stealth:
|
||||
description = f"This payment WILL FREEZE IN YOUR WALLET, check on the website if it was successful. It will automatically return unless you cheat or cancel unilaterally. Payment reference: {order.reference}"
|
||||
else:
|
||||
description = f"RoboSats - Publishing '{str(order)}' - Maker bond - This payment WILL FREEZE IN YOUR WALLET, check on the website if it was successful. It will automatically return unless you cheat or cancel unilaterally."
|
||||
|
||||
# Gen hold Invoice
|
||||
try:
|
||||
@ -1155,11 +1158,14 @@ class Logics:
|
||||
order.last_satoshis_time = timezone.now()
|
||||
bond_satoshis = int(order.last_satoshis * order.bond_size/100)
|
||||
pos_text = "Buying" if cls.is_buyer(order, user) else "Selling"
|
||||
description = (
|
||||
f"RoboSats - Taking 'Order {order.id}' {pos_text} BTC for {str(float(order.amount)) + Currency.currency_dict[str(order.currency.currency)]}"
|
||||
+
|
||||
" - Taker bond - This payment WILL FREEZE IN YOUR WALLET, check on the website if it was successful. It will automatically return unless you cheat or cancel unilaterally."
|
||||
)
|
||||
if user.profile.wants_stealth:
|
||||
description = f"This payment WILL FREEZE IN YOUR WALLET, check on the website if it was successful. It will automatically return unless you cheat or cancel unilaterally. Payment reference: {order.reference}"
|
||||
else:
|
||||
description = (
|
||||
f"RoboSats - Taking 'Order {order.id}' {pos_text} BTC for {str(float(order.amount)) + Currency.currency_dict[str(order.currency.currency)]}"
|
||||
+
|
||||
" - Taker bond - This payment WILL FREEZE IN YOUR WALLET, check on the website if it was successful. It will automatically return unless you cheat or cancel unilaterally."
|
||||
)
|
||||
|
||||
# Gen hold Invoice
|
||||
try:
|
||||
@ -1247,7 +1253,10 @@ class Logics:
|
||||
|
||||
# If there was no taker_bond object yet, generate one
|
||||
escrow_satoshis = cls.escrow_amount(order, user)[1]["escrow_amount"] # Amount was fixed when taker bond was locked, fee applied here
|
||||
description = f"RoboSats - Escrow amount for '{str(order)}' - It WILL FREEZE IN YOUR WALLET. It will be released to the buyer once you confirm you received the fiat. It will automatically return if buyer does not confirm the payment."
|
||||
if user.profile.wants_stealth:
|
||||
description = f"This payment WILL FREEZE IN YOUR WALLET, check on the website if it was successful. It will automatically return unless you cheat or cancel unilaterally. Payment reference: {order.reference}"
|
||||
else:
|
||||
description = f"RoboSats - Escrow amount for '{str(order)}' - It WILL FREEZE IN YOUR WALLET. It 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
|
||||
try:
|
||||
|
@ -297,6 +297,7 @@ class Order(models.Model):
|
||||
NESINV = 4, "Neither escrow locked or invoice submitted"
|
||||
|
||||
# order info
|
||||
reference = models.UUIDField(default = uuid.uuid4, editable = False)
|
||||
status = models.PositiveSmallIntegerField(choices=Status.choices,
|
||||
null=False,
|
||||
default=Status.WFB)
|
||||
@ -652,6 +653,10 @@ class Profile(models.Model):
|
||||
default=None,
|
||||
blank=True)
|
||||
|
||||
# Stealth invoices
|
||||
wants_stealth = models.BooleanField(default=False,
|
||||
null=False)
|
||||
|
||||
@receiver(post_save, sender=User)
|
||||
def create_user_profile(sender, instance, created, **kwargs):
|
||||
if created:
|
||||
|
@ -146,4 +146,7 @@ class TickSerializer(serializers.ModelSerializer):
|
||||
"premium",
|
||||
"fee",
|
||||
)
|
||||
depth = 1
|
||||
depth = 1
|
||||
|
||||
class StealthSerializer(serializers.Serializer):
|
||||
wantsStealth = serializers.BooleanField()
|
||||
|
@ -1,5 +1,5 @@
|
||||
from django.urls import path
|
||||
from .views import MakerView, OrderView, UserView, BookView, InfoView, RewardView, PriceView, LimitView, HistoricalView, TickView
|
||||
from .views import MakerView, OrderView, UserView, BookView, InfoView, RewardView, PriceView, LimitView, HistoricalView, TickView, StealthView
|
||||
|
||||
urlpatterns = [
|
||||
path("make/", MakerView.as_view()),
|
||||
@ -16,4 +16,5 @@ urlpatterns = [
|
||||
path("reward/", RewardView.as_view()),
|
||||
path("historical/", HistoricalView.as_view()),
|
||||
path("ticks/", TickView.as_view()),
|
||||
path("stealth/", StealthView.as_view()),
|
||||
]
|
||||
|
34
api/views.py
34
api/views.py
@ -2,7 +2,7 @@ import os
|
||||
from re import T
|
||||
from django.db.models import Sum, Q
|
||||
from rest_framework import status, viewsets
|
||||
from rest_framework.generics import CreateAPIView, ListAPIView
|
||||
from rest_framework.generics import CreateAPIView, ListAPIView, UpdateAPIView
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.response import Response
|
||||
|
||||
@ -11,7 +11,7 @@ from django.utils.decorators import method_decorator
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from api.serializers import ListOrderSerializer, MakeOrderSerializer, UpdateOrderSerializer, ClaimRewardSerializer, PriceSerializer, UserGenSerializer, TickSerializer
|
||||
from api.serializers import ListOrderSerializer, MakeOrderSerializer, UpdateOrderSerializer, ClaimRewardSerializer, PriceSerializer, UserGenSerializer, TickSerializer, StealthSerializer
|
||||
from api.models import LNPayment, MarketTick, OnchainPayment, Order, Currency, Profile
|
||||
from control.models import AccountingDay, BalanceLog
|
||||
from api.logics import Logics
|
||||
@ -740,10 +740,13 @@ class UserView(APIView):
|
||||
user.profile.is_referred = True
|
||||
user.profile.referred_by = queryset[0]
|
||||
|
||||
user.profile.wants_stealth = False
|
||||
|
||||
user.profile.save()
|
||||
|
||||
context["public_key"] = user.profile.public_key
|
||||
context["encrypted_private_key"] = user.profile.encrypted_private_key
|
||||
context["wants_stealth"] = user.profile.wants_stealth
|
||||
return Response(context, status=status.HTTP_201_CREATED)
|
||||
|
||||
# log in user and return pub/priv keys if existing
|
||||
@ -755,6 +758,7 @@ class UserView(APIView):
|
||||
context["encrypted_private_key"] = user.profile.encrypted_private_key
|
||||
context["earned_rewards"] = user.profile.earned_rewards
|
||||
context["referral_code"] = str(user.profile.referral_code)
|
||||
context["wants_stealth"] = user.profile.wants_stealth
|
||||
|
||||
# return active order or last made order if any
|
||||
has_no_active_order, _, order = Logics.validate_already_maker_or_taker(request.user)
|
||||
@ -1026,3 +1030,29 @@ class HistoricalView(ListAPIView):
|
||||
}
|
||||
|
||||
return Response(payload, status.HTTP_200_OK)
|
||||
|
||||
class StealthView(UpdateAPIView):
|
||||
|
||||
serializer_class = StealthSerializer
|
||||
|
||||
def put(self, request):
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
|
||||
if not request.user.is_authenticated:
|
||||
return Response(
|
||||
{
|
||||
"bad_request":
|
||||
"Woops! It seems you do not have a robot avatar"
|
||||
},
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
if not serializer.is_valid():
|
||||
return Response(status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
stealth = serializer.data.get("wantsStealth")
|
||||
|
||||
request.user.profile.wants_stealth = stealth
|
||||
request.user.profile.save()
|
||||
|
||||
return Response({"wantsStealth": stealth})
|
||||
|
@ -124,6 +124,17 @@ class BottomBar extends Component {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
handleSetStealthInvoice = (wantsStealth) => {
|
||||
const requestOptions = {
|
||||
method: 'PUT',
|
||||
headers: {'Content-Type':'application/json', 'X-CSRFToken': getCookie('csrftoken')},
|
||||
body: JSON.stringify({wantsStealth: wantsStealth}),
|
||||
};
|
||||
fetch('/api/stealth/', requestOptions)
|
||||
.then((response) => response.json())
|
||||
.then((data) => this.props.setAppState({stealthInvoices: data.wantsStealth}));
|
||||
}
|
||||
|
||||
getHost(){
|
||||
var url = (window.location != window.parent.location) ? this.getHost(document.referrer) : document.location.href;
|
||||
return url.split('/')[2]
|
||||
@ -488,6 +499,8 @@ bottomBarPhone =()=>{
|
||||
badInvoice={this.state.badInvoice}
|
||||
earnedRewards={this.props.earnedRewards}
|
||||
setAppState={this.props.setAppState}
|
||||
stealthInvoices={this.props.stealthInvoices}
|
||||
handleSetStealthInvoice={this.handleSetStealthInvoice}
|
||||
/>
|
||||
|
||||
<StatsDialog
|
||||
|
@ -48,6 +48,8 @@ type Props = {
|
||||
withdrawn: boolean;
|
||||
badInvoice: boolean | string;
|
||||
earnedRewards: number;
|
||||
stealthInvoices: boolean;
|
||||
handleSetStealthInvoice: (stealth: boolean) => void;
|
||||
setAppState: (state: any) => void; // TODO: move to a ContextProvider
|
||||
}
|
||||
|
||||
@ -65,6 +67,8 @@ const ProfileDialog = ({
|
||||
badInvoice,
|
||||
earnedRewards,
|
||||
setAppState,
|
||||
stealthInvoices,
|
||||
handleSetStealthInvoice,
|
||||
}: Props): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@ -206,6 +210,24 @@ const ProfileDialog = ({
|
||||
|
||||
<Divider/>
|
||||
|
||||
<Grid container>
|
||||
<Tooltip placement="top" enterTouchDelay={0} title={t("stealth_invoice_explaination")}>
|
||||
<Grid item>
|
||||
<FormControlLabel
|
||||
labelPlacement="start"
|
||||
label={`${t("Use stealth invoices")}`}
|
||||
control={
|
||||
<Switch
|
||||
checked={stealthInvoices}
|
||||
onChange={() => handleSetStealthInvoice(!stealthInvoices)
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
|
||||
<Grid container>
|
||||
<Grid item>
|
||||
<FormControlLabel
|
||||
|
@ -86,6 +86,7 @@ class UserGenPage extends Component {
|
||||
bad_request: data.bad_request,
|
||||
found: data.found,
|
||||
loadingRobot:false,
|
||||
stealthInvoices: data.wants_stealth,
|
||||
})
|
||||
&
|
||||
// Add nick and token to App state (token only if not a bad request)
|
||||
@ -96,6 +97,7 @@ class UserGenPage extends Component {
|
||||
referralCode: data.referral_code,
|
||||
earnedRewards: data.earned_rewards,
|
||||
lastOrderId: data.last_order_id ? data.last_order_id : null,
|
||||
stealthInvoices: data.wants_stealth,
|
||||
})
|
||||
:
|
||||
(this.props.setAppState({
|
||||
@ -106,6 +108,7 @@ class UserGenPage extends Component {
|
||||
lastOrderId: data.last_order_id ? data.last_order_id : null,
|
||||
referralCode: data.referral_code,
|
||||
earnedRewards: data.earned_rewards,
|
||||
stealthInvoices: data.wants_stealth,
|
||||
})) & writeCookie("robot_token",token)
|
||||
& writeCookie("pub_key",data.public_key.split('\n').join('\\'))
|
||||
& writeCookie("enc_priv_key",data.encrypted_private_key.split('\n').join('\\')))
|
||||
|
@ -227,6 +227,8 @@
|
||||
"Join RoboSats' Subreddit":"Join RoboSats' Subreddit",
|
||||
"RoboSats in Reddit":"RoboSats in Reddit",
|
||||
"Current onchain payout fee":"Current onchain payout fee",
|
||||
"Use stealth invoices":"Use stealth invoices",
|
||||
"stealth_invoice_explaination":"Stealth invoices do not contain details about the trade except a payment reference. Enable this setting if you don't want to disclose details to a custodial lightning wallet.",
|
||||
|
||||
"ORDER PAGE - OrderPage.js": "Order details page",
|
||||
"Order Box":"Order Box",
|
||||
|
Loading…
Reference in New Issue
Block a user