This commit is contained in:
koalasat
2025-06-21 16:33:09 +02:00
parent ef5257ef33
commit 9000fffc48
24 changed files with 340 additions and 231 deletions

View File

@ -241,13 +241,7 @@ class OrderView(viewsets.ViewSet):
data["is_maker"] = order.maker == request.user
data["is_taker"] = order.taker == request.user or take_order.exists()
data["is_participant"] = data["is_maker"] or data["is_taker"]
# 1) If order has a password
if not data["is_participant"] and order.password is not None:
return Response(
{"bad_request": "This order is password protected"},
status.HTTP_403_FORBIDDEN,
)
data["has_password"] = order.password is not None
# 2) If order has been cancelled
if order.status == Order.Status.UCA:
@ -268,6 +262,10 @@ class OrderView(viewsets.ViewSet):
if is_penalized:
data["penalty"] = request.user.robot.penalty_expiration
# 1) If order has a password
if not data["is_participant"] and order.password is not None:
return Response(data, status.HTTP_200_OK)
# 3.a) If not a participant and order is not public, forbid.
if (
order.maker != request.user

View File

@ -80,6 +80,7 @@ const OrderPage = (): React.JSX.Element => {
<OrderDetails
shortAlias={String(currentOrder.shortAlias)}
currentOrder={currentOrder}
setCurrentOrder={setCurrentOrder}
onClickCoordinator={onClickCoordinator}
/>
) : (
@ -118,11 +119,27 @@ const OrderPage = (): React.JSX.Element => {
});
}}
/>
{!currentOrder?.maker_hash_id && <CircularProgress />}
{!currentOrder?.maker_hash_id && !currentOrder?.bad_request && <CircularProgress />}
{currentOrder?.bad_request && currentOrder.status !== 5 ? (
<Typography align='center' variant='subtitle2' color='secondary'>
{t(currentOrder.bad_request)}
</Typography>
<>
<Typography align='center' variant='subtitle2' color='secondary'>
{t(currentOrder.bad_request)}
</Typography>
{currentOrder?.bad_request?.includes('password') && (
<Grid item xs={6} style={{ width: '21em' }}>
<Paper
elevation={12}
style={{
width: '21em',
maxHeight: `${maxHeight}em`,
overflow: 'auto',
}}
>
{orderDetailsSpace}
</Paper>
</Grid>
)}
</>
) : null}
{currentOrder?.maker_hash_id && (!currentOrder.bad_request || currentOrder.status === 5) ? (
currentOrder.is_participant ? (

View File

@ -41,6 +41,7 @@ import SelectCoordinator from './SelectCoordinator';
import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext';
import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext';
import { useNavigate } from 'react-router-dom';
import { sha256 } from 'js-sha256';
interface MakerFormProps {
disableRequest?: boolean;
@ -252,6 +253,7 @@ const MakerForm = ({
latitude: maker.latitude,
longitude: maker.longitude,
shortAlias: maker.coordinator,
password: maker.password ? sha256(maker.password) : null,
};
void slot
@ -286,6 +288,13 @@ const MakerForm = ({
});
};
const handlePasswordChange = function (event: React.ChangeEvent<HTMLInputElement>): void {
setMaker({
...maker,
password: event.target.value,
});
};
const handleChangeEscrowDuration = function (date: Date): void {
const d = new Date(date);
const hours: number = d.getHours();
@ -821,6 +830,24 @@ const MakerForm = ({
/>
</Grid>
<Collapse in={maker.advancedOptions} sx={{ width: '100%' }}>
<Grid item sx={{ width: '100%' }}>
<TextField
fullWidth
label={`${t('Password')}`}
type='password'
value={maker.password}
style={{ marginBottom: 8 }}
inputProps={{
style: {
textAlign: 'center',
backgroundColor: theme.palette.background.paper,
borderRadius: 4,
},
}}
onChange={handlePasswordChange}
/>
</Grid>
<Grid item sx={{ width: '100%' }}>
<LocalizationProvider dateAdapter={AdapterDateFns}>
<MobileTimePicker

View File

@ -27,10 +27,13 @@ import { computeSats } from '../../utils';
import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext';
import { type UseFederationStoreType, FederationContext } from '../../contexts/FederationContext';
import { useNavigate } from 'react-router-dom';
import { sha256 } from 'js-sha256';
interface TakeButtonProps {
currentOrder: Order;
password?: string;
info?: Info;
setCurrentOrder: (currentOrder: Order) => void;
onClickGenerateRobot?: () => void;
}
@ -41,7 +44,9 @@ interface OpenDialogsProps {
const closeAll = { inactiveMaker: false, confirmation: false };
const TakeButton = ({
password,
currentOrder,
setCurrentOrder,
info,
onClickGenerateRobot = () => null,
}: TakeButtonProps): React.JSX.Element => {
@ -317,6 +322,8 @@ const TakeButton = ({
if (currentOrder === null || slot === null) return;
if (password) currentOrder.password = sha256(password);
setLoadingTake(true);
slot
@ -326,8 +333,10 @@ const TakeButton = ({
setBadRequest(order.bad_request);
} else {
setBadRequest('');
setCurrentOrder(order);
navigate(`/order/${order.shortAlias}/${order.id}`);
}
setLoadingTake(false);
})
.catch(() => {
setBadRequest('Request error');

View File

@ -16,6 +16,7 @@ import {
IconButton,
Tooltip,
ListItemButton,
TextField,
} from '@mui/material';
import Countdown, { type CountdownRenderProps, zeroPad } from 'react-countdown';
@ -46,6 +47,7 @@ import { type Order } from '../../models';
interface OrderDetailsProps {
shortAlias: string;
currentOrder: Order;
setCurrentOrder: (currentOrder: Order) => void;
onClickCoordinator?: () => void;
onClickGenerateRobot?: () => void;
}
@ -53,6 +55,7 @@ interface OrderDetailsProps {
const OrderDetails = ({
shortAlias,
currentOrder,
setCurrentOrder,
onClickCoordinator = () => null,
onClickGenerateRobot = () => null,
}: OrderDetailsProps): React.JSX.Element => {
@ -65,6 +68,7 @@ const OrderDetails = ({
const [currencyCode, setCurrencyCode] = useState<string | null>();
const [showSatsDetails, setShowSatsDetails] = useState<boolean>(false);
const [openWorldmap, setOpenWorldmap] = useState<boolean>(false);
const [password, setPassword] = useState<string>();
useEffect(() => {
setCoordinator(federation.getCoordinator(shortAlias));
@ -142,6 +146,10 @@ const OrderDetails = ({
);
};
const onPasswordChange = (password: string) => {
setPassword(password);
};
// Countdown Renderer callback with condition
const countdownPenaltyRenderer = ({
minutes,
@ -294,234 +302,239 @@ const OrderDetails = ({
)}
<Divider />
<ListItem>
<ListItemAvatar sx={{ width: '4em', height: '4em' }}>
<RobotAvatar
statusColor={statusBadgeColor(currentOrder?.maker_status ?? '')}
hashId={currentOrder?.maker_hash_id}
tooltip={t(currentOrder?.maker_status ?? '')}
orderType={currentOrder?.type}
small={true}
/>
</ListItemAvatar>
<ListItemText
primary={`${String(currentOrder?.maker_nick)} (${
currentOrder?.type === 1
? t(currentOrder?.currency === 1000 ? 'Swapping Out' : 'Seller')
: t(currentOrder?.currency === 1000 ? 'Swapping In' : 'Buyer')
})`}
secondary={t('Order maker')}
/>
</ListItem>
<Collapse in={currentOrder?.is_participant && currentOrder?.taker_nick !== 'None'}>
<Divider />
<ListItem>
<ListItemText
primary={`${String(currentOrder?.taker_nick)} (${
currentOrder?.type === 1
? t(currentOrder?.currency === 1000 ? 'Swapping In' : 'Buyer')
: t(currentOrder?.currency === 1000 ? 'Swapping Out' : 'Seller')
})`}
secondary={t('Order taker')}
/>
<ListItemAvatar>
<RobotAvatar
avatarClass='smallAvatar'
statusColor={statusBadgeColor(currentOrder?.taker_status ?? '')}
hashId={
currentOrder?.taker_hash_id === 'None' ? undefined : currentOrder?.taker_hash_id
}
tooltip={t(currentOrder?.taker_status ?? '')}
orderType={currentOrder?.type === 0 ? 1 : 0}
small={true}
/>
</ListItemAvatar>
</ListItem>
</Collapse>
<Divider>
<Chip label={t('Order Details')} />
</Divider>
<Collapse in={currentOrder?.is_participant}>
<ListItem>
<ListItemIcon>
<Article />
</ListItemIcon>
<ListItemText
primary={t(currentOrder?.status_message ?? '')}
secondary={t('Order status')}
/>
</ListItem>
<Divider />
</Collapse>
<ListItem>
<ListItemIcon>
<div
style={{
zoom: 1.25,
opacity: 0.7,
msZoom: 1.25,
WebkitZoom: 1.25,
MozTransform: 'scale(1.25,1.25)',
MozTransformOrigin: 'left center',
}}
>
<FlagWithProps code={currencyCode} width='1.2em' height='1.2em' />
</div>
</ListItemIcon>
<ListItemText
primary={amountString}
secondary={(currentOrder?.amount ?? 0) > 0 ? 'Amount' : 'Amount Range'}
/>
<ListItemIcon>
<IconButton
onClick={() => {
setShowSatsDetails(!showSatsDetails);
}}
>
{showSatsDetails ? <ExpandLess /> : <ExpandMore color='primary' />}
</IconButton>
</ListItemIcon>
</ListItem>
<Collapse in={showSatsDetails}>
<List dense={true} sx={{ position: 'relative', bottom: '0.5em' }}>
{!currentOrder.bad_request && (
<>
<ListItem>
<ListItemIcon sx={{ position: 'relative', left: '0.3em' }}>
<SendReceiveIcon
sx={{ transform: 'scaleX(-1)', width: '0.9em', opacity: 0.9 }}
color='secondary'
<ListItemAvatar sx={{ width: '4em', height: '4em' }}>
<RobotAvatar
statusColor={statusBadgeColor(currentOrder?.maker_status ?? '')}
hashId={currentOrder?.maker_hash_id}
tooltip={t(currentOrder?.maker_status ?? '')}
orderType={currentOrder?.type}
small={true}
/>
</ListItemIcon>
<Typography variant='body2'>{satsSummary.send}</Typography>
</ListItemAvatar>
<ListItemText
primary={`${String(currentOrder?.maker_nick)} (${
currentOrder?.type === 1
? t(currentOrder?.currency === 1000 ? 'Swapping Out' : 'Seller')
: t(currentOrder?.currency === 1000 ? 'Swapping In' : 'Buyer')
})`}
secondary={t('Order maker')}
/>
</ListItem>
<ListItem>
<ListItemIcon sx={{ position: 'relative', left: '0.3em' }}>
<SendReceiveIcon
sx={{ left: '0.1em', width: '0.9em', opacity: 0.9 }}
color='primary'
<Collapse in={currentOrder?.is_participant && currentOrder?.taker_nick !== 'None'}>
<Divider />
<ListItem>
<ListItemText
primary={`${String(currentOrder?.taker_nick)} (${
currentOrder?.type === 1
? t(currentOrder?.currency === 1000 ? 'Swapping In' : 'Buyer')
: t(currentOrder?.currency === 1000 ? 'Swapping Out' : 'Seller')
})`}
secondary={t('Order taker')}
/>
</ListItemIcon>
<Typography variant='body2'>{satsSummary.receive}</Typography>
</ListItem>
</List>
</Collapse>
<ListItemAvatar>
<RobotAvatar
avatarClass='smallAvatar'
statusColor={statusBadgeColor(currentOrder?.taker_status ?? '')}
hashId={
currentOrder?.taker_hash_id === 'None'
? undefined
: currentOrder?.taker_hash_id
}
tooltip={t(currentOrder?.taker_status ?? '')}
orderType={currentOrder?.type === 0 ? 1 : 0}
small={true}
/>
</ListItemAvatar>
</ListItem>
</Collapse>
<Divider>
<Chip label={t('Order Details')} />
</Divider>
<Divider />
<Collapse in={currentOrder?.is_participant}>
<ListItem>
<ListItemIcon>
<Article />
</ListItemIcon>
<ListItemText
primary={t(currentOrder?.status_message ?? '')}
secondary={t('Order status')}
/>
</ListItem>
<Divider />
</Collapse>
<ListItem>
<ListItemIcon>
<Payments />
</ListItemIcon>
<ListItemText
primary={
<PaymentStringAsIcons
size={1.42 * theme.typography.fontSize}
othersText={t('Others')}
verbose={true}
text={currentOrder?.payment_method}
/>
}
secondary={
currentOrder?.currency === 1000
? t('Swap destination')
: t('Accepted payment methods')
}
/>
{currentOrder?.payment_method.includes('Cash F2F') && (
<ListItemIcon>
<Tooltip enterTouchDelay={0} title={t('F2F location')}>
<div>
<IconButton
onClick={() => {
setOpenWorldmap(true);
}}
>
<Map />
</IconButton>
<ListItem>
<ListItemIcon>
<div
style={{
zoom: 1.25,
opacity: 0.7,
msZoom: 1.25,
WebkitZoom: 1.25,
MozTransform: 'scale(1.25,1.25)',
MozTransformOrigin: 'left center',
}}
>
<FlagWithProps code={currencyCode} width='1.2em' height='1.2em' />
</div>
</Tooltip>
</ListItemIcon>
)}
</ListItem>
<Divider />
{/* If there is live Price and Premium data, show it. Otherwise show the order maker settings */}
<ListItem>
<ListItemIcon>
<PriceChange />
</ListItemIcon>
{currentOrder?.price_now !== undefined ? (
<ListItemText
primary={t('{{price}} {{currencyCode}}/BTC - Premium: {{premium}}%', {
price: pn(currentOrder?.price_now),
currencyCode,
premium: currentOrder?.premium_now,
})}
secondary={t('Price and Premium')}
/>
) : null}
{currentOrder?.price_now === undefined && currentOrder?.is_explicit ? (
<ListItemText
primary={pn(currentOrder?.satoshis)}
secondary={t('Amount of Satoshis')}
/>
) : null}
{currentOrder?.price_now === undefined && !currentOrder?.is_explicit ? (
<ListItemText
primary={`${parseFloat(Number(currentOrder?.premium).toFixed(2))}%`}
secondary={t('Premium over market price')}
/>
) : null}
</ListItem>
<Divider />
<Grid container direction='row' justifyContent='center' alignItems='center'>
<ListItem style={{ width: '50%' }}>
<ListItemIcon>
<Numbers />
</ListItemIcon>
<ListItemText primary={currentOrder?.id} secondary={t('Order ID')} />
</ListItem>
<ListItem style={{ width: '50%' }}>
<ListItemIcon>
<HourglassTop />
</ListItemIcon>
<ListItemText
primary={timerRenderer(currentOrder?.escrow_duration)}
secondary={t('Deposit')}
/>
</ListItem>
</Grid>
{/* if order is in a status that does not expire, do not show countdown */}
<Collapse in={![4, 5, 12, 13, 14, 15, 16, 17, 18].includes(currentOrder?.status ?? 0)}>
<Divider />
<ListItem>
<ListItemIcon>
<AccessTime />
</ListItemIcon>
<ListItemText secondary={t('Expires in')}>
<Countdown
date={new Date(currentOrder?.expires_at ?? '')}
renderer={countdownRenderer}
</ListItemIcon>
<ListItemText
primary={amountString}
secondary={(currentOrder?.amount ?? 0) > 0 ? 'Amount' : 'Amount Range'}
/>
</ListItemText>
</ListItem>
<LinearDeterminate
totalSecsExp={currentOrder?.total_secs_exp ?? 0}
expiresAt={currentOrder?.expires_at ?? ''}
/>
</Collapse>
<ListItemIcon>
<IconButton
onClick={() => {
setShowSatsDetails(!showSatsDetails);
}}
>
{showSatsDetails ? <ExpandLess /> : <ExpandMore color='primary' />}
</IconButton>
</ListItemIcon>
</ListItem>
<Collapse in={showSatsDetails}>
<List dense={true} sx={{ position: 'relative', bottom: '0.5em' }}>
<ListItem>
<ListItemIcon sx={{ position: 'relative', left: '0.3em' }}>
<SendReceiveIcon
sx={{ transform: 'scaleX(-1)', width: '0.9em', opacity: 0.9 }}
color='secondary'
/>
</ListItemIcon>
<Typography variant='body2'>{satsSummary.send}</Typography>
</ListItem>
<ListItem>
<ListItemIcon sx={{ position: 'relative', left: '0.3em' }}>
<SendReceiveIcon
sx={{ left: '0.1em', width: '0.9em', opacity: 0.9 }}
color='primary'
/>
</ListItemIcon>
<Typography variant='body2'>{satsSummary.receive}</Typography>
</ListItem>
</List>
</Collapse>
<Divider />
<ListItem>
<ListItemIcon>
<Payments />
</ListItemIcon>
<ListItemText
primary={
<PaymentStringAsIcons
size={1.42 * theme.typography.fontSize}
othersText={t('Others')}
verbose={true}
text={currentOrder?.payment_method}
/>
}
secondary={
currentOrder?.currency === 1000
? t('Swap destination')
: t('Accepted payment methods')
}
/>
{currentOrder?.payment_method.includes('Cash F2F') && (
<ListItemIcon>
<Tooltip enterTouchDelay={0} title={t('F2F location')}>
<div>
<IconButton
onClick={() => {
setOpenWorldmap(true);
}}
>
<Map />
</IconButton>
</div>
</Tooltip>
</ListItemIcon>
)}
</ListItem>
<Divider />
{/* If there is live Price and Premium data, show it. Otherwise show the order maker settings */}
<ListItem>
<ListItemIcon>
<PriceChange />
</ListItemIcon>
{currentOrder?.price_now !== undefined ? (
<ListItemText
primary={t('{{price}} {{currencyCode}}/BTC - Premium: {{premium}}%', {
price: pn(currentOrder?.price_now),
currencyCode,
premium: currentOrder?.premium_now,
})}
secondary={t('Price and Premium')}
/>
) : null}
{currentOrder?.price_now === undefined && currentOrder?.is_explicit ? (
<ListItemText
primary={pn(currentOrder?.satoshis)}
secondary={t('Amount of Satoshis')}
/>
) : null}
{currentOrder?.price_now === undefined && !currentOrder?.is_explicit ? (
<ListItemText
primary={`${parseFloat(Number(currentOrder?.premium).toFixed(2))}%`}
secondary={t('Premium over market price')}
/>
) : null}
</ListItem>
<Divider />
<Grid container direction='row' justifyContent='center' alignItems='center'>
<ListItem style={{ width: '50%' }}>
<ListItemIcon>
<Numbers />
</ListItemIcon>
<ListItemText primary={currentOrder?.id} secondary={t('Order ID')} />
</ListItem>
<ListItem style={{ width: '50%' }}>
<ListItemIcon>
<HourglassTop />
</ListItemIcon>
<ListItemText
primary={timerRenderer(currentOrder?.escrow_duration)}
secondary={t('Deposit')}
/>
</ListItem>
</Grid>
{/* if order is in a status that does not expire, do not show countdown */}
<Collapse in={![4, 5, 12, 13, 14, 15, 16, 17, 18].includes(currentOrder?.status ?? 0)}>
<Divider />
<ListItem>
<ListItemIcon>
<AccessTime />
</ListItemIcon>
<ListItemText secondary={t('Expires in')}>
<Countdown
date={new Date(currentOrder?.expires_at ?? '')}
renderer={countdownRenderer}
/>
</ListItemText>
</ListItem>
<LinearDeterminate
totalSecsExp={currentOrder?.total_secs_exp ?? 0}
expiresAt={currentOrder?.expires_at ?? ''}
/>
</Collapse>
</>
)}
</List>
{/* If the user has a penalty/limit */}
@ -538,10 +551,32 @@ const OrderDetails = ({
<></>
)}
{!currentOrder?.is_participant ? (
{currentOrder.bad_request?.includes('password') && (
<Grid item style={{ width: '100%', padding: '16px' }}>
<TextField
fullWidth
label={`${t('Password')}`}
type='password'
value={password}
style={{ marginBottom: 8 }}
inputProps={{
style: {
textAlign: 'center',
backgroundColor: theme.palette.background.paper,
borderRadius: 4,
},
}}
onChange={(e) => onPasswordChange(e.target.value)}
/>
</Grid>
)}
{!currentOrder?.is_participant || currentOrder.bad_request?.includes('password') ? (
<Grid item style={{ width: '100%', padding: '8px' }}>
<TakeButton
password={password}
currentOrder={currentOrder}
setCurrentOrder={setCurrentOrder}
info={coordinator.info}
onClickGenerateRobot={onClickGenerateRobot}
/>

View File

@ -21,6 +21,7 @@ export interface Maker {
badPremiumText: string;
latitude: number;
longitude: number;
password: string | null;
}
export const defaultMaker: Maker = {
@ -47,6 +48,7 @@ export const defaultMaker: Maker = {
badSatoshisText: '',
latitude: 0,
longitude: 0,
password: null,
};
export default Maker;

View File

@ -22,6 +22,7 @@ export interface SubmitActionProps {
rating?: number;
amount?: number;
cancel_status?: number;
password?: string;
}
export interface TradeRobotSummary {
@ -83,6 +84,7 @@ class Order {
satoshis_now: number = 0;
latitude: number = 0;
longitude: number = 0;
password: string | undefined = undefined;
premium_now: number | undefined = undefined;
premium_percentile: number = 0;
num_similar_orders: number = 0;
@ -199,6 +201,7 @@ class Order {
bond_size: this.bond_size,
latitude: this.latitude,
longitude: this.longitude,
password: this.password,
};
if (slot) {
@ -223,6 +226,7 @@ class Order {
) => {
return await this.submitAction(federation, slot, {
action: 'take',
password: this?.password,
amount: this?.currency === 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount),
});
};

View File

@ -385,6 +385,7 @@
"Onchain amount to send (BTC)": "Quantitat a enviar Onchain (BTC)",
"Order current rate:": "Preu actual:",
"Order for ": "Ordre per ",
"Password": "Password",
"Premium over Market (%)": "Prima sobre el mercat (%)",
"Public Duration (HH:mm)": "Duració pública (HH:mm)",
"Public order length": "Duració de l'ordre pública",

View File

@ -385,6 +385,7 @@
"Onchain amount to send (BTC)": "Onchain amount to send (BTC)",
"Order current rate:": "Aktuální kurz nabídky:",
"Order for ": "Order for ",
"Password": "Password",
"Premium over Market (%)": "Prémium vůči tržní ceně (%)",
"Public Duration (HH:mm)": "Doba zveřejnění (HH:mm)",
"Public order length": "Public order length",

View File

@ -385,6 +385,7 @@
"Onchain amount to send (BTC)": "Onchain amount to send (BTC)",
"Order current rate:": "Aktueller Order-Kurs:",
"Order for ": "Order for ",
"Password": "Password",
"Premium over Market (%)": "Marktpreis Aufschlag (%)",
"Public Duration (HH:mm)": "Angebotslaufzeit (HH:mm)",
"Public order length": "Public order length",

View File

@ -385,6 +385,7 @@
"Onchain amount to send (BTC)": "Onchain amount to send (BTC)",
"Order current rate:": "Order current rate:",
"Order for ": "Order for ",
"Password": "Password",
"Premium over Market (%)": "Premium over Market (%)",
"Public Duration (HH:mm)": "Public Duration (HH:mm)",
"Public order length": "Public order length",

View File

@ -385,6 +385,7 @@
"Onchain amount to send (BTC)": "Cantidad onchain a enviar (BTC)",
"Order current rate:": "Precio actual:",
"Order for ": "Orden por ",
"Password": "Password",
"Premium over Market (%)": "Prima sobre el mercado (%)",
"Public Duration (HH:mm)": "Duración pública (HH:mm)",
"Public order length": "Public order length",

View File

@ -385,6 +385,7 @@
"Onchain amount to send (BTC)": "Onchain amount to send (BTC)",
"Order current rate:": "Uneko Prezioa:",
"Order for ": "Order for ",
"Password": "Password",
"Premium over Market (%)": "Merkatuarekiko Prima (%)",
"Public Duration (HH:mm)": "Iraupen publikoa (HH:mm)",
"Public order length": "Public order length",

View File

@ -385,6 +385,7 @@
"Onchain amount to send (BTC)": "Onchain montant à envoyer (BTC)",
"Order current rate:": "Commander le taux actuel:",
"Order for ": "Ordre pour ",
"Password": "Password",
"Premium over Market (%)": "Prime sur le marché (%)",
"Public Duration (HH:mm)": "Durée publique (HH:mm)",
"Public order length": "Durée de l'ordre public",

View File

@ -385,6 +385,7 @@
"Onchain amount to send (BTC)": "Importo da inviare onchain (BTC)",
"Order current rate:": "Ordina al prezzo corrente:",
"Order for ": "Ordina per ",
"Password": "Password",
"Premium over Market (%)": "Premio sul prezzo di mercato (%)",
"Public Duration (HH:mm)": "Durata pubblica (HH:mm)",
"Public order length": "Durata dell'ordine pubblico",

View File

@ -385,6 +385,7 @@
"Onchain amount to send (BTC)": "送信するオンチェーン量BTC",
"Order current rate:": "現在のレート:",
"Order for ": "Order for ",
"Password": "Password",
"Premium over Market (%)": "マーケットに対するプレミアム(%)",
"Public Duration (HH:mm)": "公開期間(HH:mm)",
"Public order length": "公開注文の期間",

View File

@ -385,6 +385,7 @@
"Onchain amount to send (BTC)": "Onchain amount to send (BTC)",
"Order current rate:": "Order current rate:",
"Order for ": "Order for ",
"Password": "Password",
"Premium over Market (%)": "Premia nad rynkiem (%)",
"Public Duration (HH:mm)": "Czas trwania publicznego (HH:mm)",
"Public order length": "Public order length",

View File

@ -385,6 +385,7 @@
"Onchain amount to send (BTC)": "Valor onchain a enviar (BTC)",
"Order current rate:": "Taxa atual do pedido:",
"Order for ": "Ordem para ",
"Password": "Password",
"Premium over Market (%)": "Prêmio sobre o mercado (%)",
"Public Duration (HH:mm)": "Duração Pública (HH:mm)",
"Public order length": "Tempo da ordem pública",

View File

@ -385,6 +385,7 @@
"Onchain amount to send (BTC)": "Сумма для отправки на ончейн (BTC)",
"Order current rate:": "Текущий курс ордера:",
"Order for ": "Ордер на ",
"Password": "Password",
"Premium over Market (%)": "Наценка по сравнению с рынком (%)",
"Public Duration (HH:mm)": "Публичная продолжительность (ЧЧ: мм)",
"Public order length": "Длина общественного ордера",

View File

@ -385,6 +385,7 @@
"Onchain amount to send (BTC)": "Onchain amount to send (BTC)",
"Order current rate:": "Aktuell kurs: ",
"Order for ": "Order for ",
"Password": "Password",
"Premium over Market (%)": "Premium över marknaden (%)",
"Public Duration (HH:mm)": "Publikt tidsspann (HH:mm)",
"Public order length": "Public order length",

View File

@ -385,6 +385,7 @@
"Onchain amount to send (BTC)": "Kiasi cha onchain cha kutuma (BTC)",
"Order current rate:": "Kiwango cha sasa cha amri:",
"Order for ": "Amri kwa ",
"Password": "Password",
"Premium over Market (%)": "Faida juu ya Soko (%)",
"Public Duration (HH:mm)": "Muda wa Umma (HH:mm)",
"Public order length": "Urefu wa amri ya umma",

View File

@ -385,6 +385,7 @@
"Onchain amount to send (BTC)": "Onchain amount to send (BTC)",
"Order current rate:": "ราคาที่คุณกำหนด:",
"Order for ": "Order for ",
"Password": "Password",
"Premium over Market (%)": "ค่าพรีเมี่ยมจากท้องตลาด (%)",
"Public Duration (HH:mm)": "ประกาศรายการซื้อขายมีอายุ (ชม:นาที)",
"Public order length": "Public order length",

View File

@ -385,6 +385,7 @@
"Onchain amount to send (BTC)": "链上发送金额BTC",
"Order current rate:": "订单当前价格:",
"Order for ": "Order for ",
"Password": "Password",
"Premium over Market (%)": "市场溢价(%",
"Public Duration (HH:mm)": "公开时间 (HH:mm)",
"Public order length": "订单公开长度",

View File

@ -385,6 +385,7 @@
"Onchain amount to send (BTC)": "鏈上發送金額BTC",
"Order current rate:": "訂單當前價格:",
"Order for ": "Order for ",
"Password": "Password",
"Premium over Market (%)": "市場溢價 (%)",
"Public Duration (HH:mm)": "公開時間 (HH:mm)",
"Public order length": "訂單公開長度",