Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 43 additions & 14 deletions bot/modules/orders/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as ordersActions from '../../ordersActions';
import { deletedCommunityMessage } from './messages';
import {
getCommunityInfo,
getCommunityByIdentifier,
isCurrencySupported,
} from '../../../util/communityHelper';
import { takebuy, takesell, takebuyValidation } from './takeOrder';
Expand Down Expand Up @@ -50,18 +51,15 @@ const sell = async (ctx: MainContext) => {
const sellOrderParams = await validateSellOrder(ctx);

if (!sellOrderParams) return;
const { amount, fiatAmount, fiatCode, paymentMethod } = sellOrderParams;
const { amount, fiatAmount, fiatCode, paymentMethod, communityName } =
sellOrderParams;
let priceMargin = sellOrderParams.priceMargin;
priceMargin = isFloat(priceMargin)
? parseFloat(priceMargin.toFixed(2))
: parseInt(priceMargin);

// Optimized community lookup - single database query instead of multiple
const communityInfo = await getCommunityInfo(
user,
ctx.message?.chat.type || 'private',
ctx.message?.chat as Chat.UserNameChat,
);
const communityInfo = await resolveOrderCommunity(ctx, user, communityName);
if (!communityInfo) return;

const { community, communityId, isBanned } = communityInfo;

Expand Down Expand Up @@ -119,18 +117,15 @@ const buy = async (ctx: MainContext) => {
const buyOrderParams = await validateBuyOrder(ctx);
if (!buyOrderParams) return;

const { amount, fiatAmount, fiatCode, paymentMethod } = buyOrderParams;
const { amount, fiatAmount, fiatCode, paymentMethod, communityName } =
buyOrderParams;
let priceMargin = buyOrderParams.priceMargin;
priceMargin = isFloat(priceMargin)
? parseFloat(priceMargin.toFixed(2))
: parseInt(priceMargin);

// Optimized community lookup - single database query instead of multiple
const communityInfo = await getCommunityInfo(
user,
ctx.message?.chat.type || 'private',
ctx.message?.chat as Chat.UserNameChat,
);
const communityInfo = await resolveOrderCommunity(ctx, user, communityName);
if (!communityInfo) return;

const { community, communityId, isBanned } = communityInfo;

Expand Down Expand Up @@ -182,6 +177,40 @@ const buy = async (ctx: MainContext) => {
}
};

// Decides which community an order should be published to.
// When the user passes a community name in a private chat, the order is
// published to that community. Otherwise the default behaviour applies: the
// group's community when the command runs inside a group, or the user's
// default community in private. Returns null when the flow must stop because
// an error was already reported to the user.
async function resolveOrderCommunity(
ctx: MainContext,
user: UserDocument,
communityName?: string,
) {
// An explicit community always wins, in private chats and in groups alike.
// Only when none is passed do we fall back to the group's community (in a
// group) or the user's default community (in private).
if (communityName) {
const communityInfo = await getCommunityByIdentifier(user, communityName);
if (!communityInfo.community) {
if ((ctx.message?.chat.type || 'private') !== 'private') {
await ctx.deleteMessage();
} else {
await ctx.reply(ctx.i18n.t('community_not_found'));
}
return null;
}
return communityInfo;
}

return getCommunityInfo(
user,
ctx.message?.chat.type || 'private',
ctx.message?.chat as Chat.UserNameChat,
);
}

async function enterWizard(
ctx: CommunityContext,
user: UserDocument,
Expand Down
45 changes: 43 additions & 2 deletions bot/validations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,23 @@ const processParameters = (args: string[]) => {
return correctedArgs;
};

// The two optional trailing params of /buy and /sell are, in order, the price
// margin and the community. They are told apart by position, not by type: the
// first optional arg is always the price margin, the second is always the
// community. Positional parsing keeps numeric community identifiers (e.g. a
// Telegram group id) from being mistaken for a price margin, and makes any
// leftover non-numeric token fail the price-margin check instead of being
// silently swallowed as a community.
const parseOptionalOrderParams = (optionalArgs: string[]) => {
// priceMargin is kept loosely typed because downstream callers feed it
// through isFloat/parseInt/isNaN, matching the previous untyped behaviour.
const priceMargin: any = optionalArgs[0] === '' ? undefined : optionalArgs[0];
const communityName: string | undefined =
optionalArgs[1] === '' ? undefined : optionalArgs[1];

return { priceMargin, communityName };
};
Comment thread
coderabbitai[bot] marked this conversation as resolved.

const validateSellOrder = async (ctx: MainContext) => {
try {
let args = ctx.state.command.args;
Expand All @@ -170,7 +187,18 @@ const validateSellOrder = async (ctx: MainContext) => {
}
args = processParameters(args);

let [amount, fiatAmount, fiatCode, paymentMethod, priceMargin] = args;
// Only two optional trailing params exist (price margin and community), so
// a third token means the command is malformed. Rejecting it here keeps a
// typo from being silently dropped and the order published anyway.
if (args.length > 6) {
await messages.sellOrderCorrectFormatMessage(ctx);
return false;
}

let [amount, fiatAmount, fiatCode, paymentMethod] = args;
const { priceMargin, communityName } = parseOptionalOrderParams(
args.slice(4),
);

if (priceMargin && isNaN(priceMargin)) {
await ctx.reply(
Expand Down Expand Up @@ -244,6 +272,7 @@ const validateSellOrder = async (ctx: MainContext) => {
fiatCode: fiatCode.toUpperCase(),
paymentMethod,
priceMargin,
communityName,
};
} catch (error) {
logger.error(error);
Expand All @@ -260,7 +289,18 @@ const validateBuyOrder = async (ctx: MainContext) => {
}
args = processParameters(args);

let [amount, fiatAmount, fiatCode, paymentMethod, priceMargin] = args;
// Only two optional trailing params exist (price margin and community), so
// a third token means the command is malformed. Rejecting it here keeps a
// typo from being silently dropped and the order published anyway.
if (args.length > 6) {
await messages.buyOrderCorrectFormatMessage(ctx);
return false;
}

let [amount, fiatAmount, fiatCode, paymentMethod] = args;
const { priceMargin, communityName } = parseOptionalOrderParams(
args.slice(4),
);

if (priceMargin && isNaN(priceMargin)) {
await ctx.reply(
Expand Down Expand Up @@ -332,6 +372,7 @@ const validateBuyOrder = async (ctx: MainContext) => {
fiatCode: fiatCode.toUpperCase(),
paymentMethod,
priceMargin,
communityName,
};
} catch (error) {
logger.error(error);
Expand Down
12 changes: 8 additions & 4 deletions locales/de.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ must_be_numeric: ${fieldName} muss numerisch sein
sats_amount: sats Wert
fiat_amount: fiat Wert
sell_correct_format: |
/sell \<_Anzahl sats_\> \<_fiat Wert_\> \<_fiat code_\> \<_Zahlungsmethode_\> \[_Zuschlag/Rabatt_\]
/sell \<_Anzahl sats_\> \<_fiat Wert_\> \<_fiat code_\> \<_Zahlungsmethode_\> \[_Zuschlag/Rabatt_\] \[_Community_\]

Du kannst den Namen einer deiner Communities als letzten Parameter hinzufügen, um die Order dort statt in deiner Standard\-Community zu veröffentlichen\. Du musst den Zuschlag/Rabatt davor angeben \(nutze 0, wenn du keinen möchtest\)\.

Um einen Verkaufsauftrag von 1000 Sats für 2 Euro \(EUR\) zu erstellen und anzugeben, dass die Zahlung in FIAT durch Überweisung oder Einzahlung am Geldautomaten erfolgt, musst du \<\> und \[\] weglassen\.

Expand All @@ -85,7 +87,9 @@ sell_correct_format: |

`/sell 0 100\-500 EUR "Zahlungsmethode" 3`
buy_correct_format: |
/buy \<_Anzahl sats_\> \<_fiat Wert_\> \<_fiat code_\> \<_Zahlungsmethode_\> \[_Zuschlag/Rabatt_\]
/buy \<_Anzahl sats_\> \<_fiat Wert_\> \<_fiat code_\> \<_Zahlungsmethode_\> \[_Zuschlag/Rabatt_\] \[_Community_\]

Du kannst den Namen einer deiner Communities als letzten Parameter hinzufügen, um die Order dort statt in deiner Standard\-Community zu veröffentlichen\. Du musst den Zuschlag/Rabatt davor angeben \(nutze 0, wenn du keinen möchtest\)\.

Um einen Auftrag über 1000 Sats für 2 \(EUR\) zu erstellen und anzugeben, dass die Zahlung per Überweisung erfolgt, musst du sowohl \<\> als auch \[\] weglassen\.

Expand Down Expand Up @@ -241,8 +245,8 @@ must_be_number_or_range: 'Fiat_amount muss eine Zahl oder ein numerischer Bereic
invalid_lightning_address: Ungültige Lightning-Adresse
unavailable_lightning_address: Nicht verfügbare Lightning-Adresse ${la}
help: |
/sell <_Anzahl sats_> <_fiat Wert_> <_fiat code_> <_Zahlungsmethode_> \[_Zuschlag/Rabatt_] - Erstellt einen Bitcoin Verkaufsauftrag
/buy <_Anzahl sats_> <_fiat Wert_> <_fiat code_> <_Zahlungsmethode_> \[_Zuschlag/Rabatt_] - Erstellt eine Bitcoin Kaufauftrag
/sell <_Anzahl sats_> <_fiat Wert_> <_fiat code_> <_Zahlungsmethode_> \[_Zuschlag/Rabatt_] \[_Community_] - Erstellt einen Bitcoin Verkaufsauftrag
/buy <_Anzahl sats_> <_fiat Wert_> <_fiat code_> <_Zahlungsmethode_> \[_Zuschlag/Rabatt_] \[_Community_] - Erstellt eine Bitcoin Kaufauftrag
/takeorder <_order id_> - Ermöglicht Ihnen, eine Bestellung aus dem Chat mit dem Bot anzunehmen, ohne zu dem Kanal zu gehen, in dem sie veröffentlicht wurde
/info - Zeigt zusätzliche Informationen über das Bot an
/showusername - Schaltet die Anzeige des Benutzernamens in jedem neu erstellten Auftrag aus. Der Standardwert ist *nein* (false)
Expand Down
12 changes: 8 additions & 4 deletions locales/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ must_be_numeric: ${fieldName} must be numeric
sats_amount: sats amount
fiat_amount: fiat amount
sell_correct_format: |
/sell \<_sats amount_\> \<_fiat amount_\> \<_fiat code_\> \<_payment method_\> \[_premium/discount_\]
/sell \<_sats amount_\> \<_fiat amount_\> \<_fiat code_\> \<_payment method_\> \[_premium/discount_\] \[_community_\]

You can add the name of one of your communities as the last parameter to publish the order there instead of your default community\. You must include the premium/discount before it \(use 0 if you don't want any\)\.

In order to create a sell order of 1000 satoshis for 2 US dollars \(USD\) and indicate that the fiat payment is through transfer or ATM deposit, you must avoid \<\> and \[\]\.

Expand All @@ -87,7 +89,9 @@ sell_correct_format: |

`/sell 0 100\-500 USD "payment method" 3`
buy_correct_format: |
/buy \<_sats amount_\> \<_fiat amount_\> \<_fiat code_\> \<_payment method_\> \[_premium/discount_\]
/buy \<_sats amount_\> \<_fiat amount_\> \<_fiat code_\> \<_payment method_\> \[_premium/discount_\] \[_community_\]

You can add the name of one of your communities as the last parameter to publish the order there instead of your default community\. You must include the premium/discount before it \(use 0 if you don't want any\)\.

In order to create an order for 1000 satoshis for 2 \(USD\) and indicate that fiat payment is through transfer, you must to omit both \<\> and \[\]\.

Expand Down Expand Up @@ -245,8 +249,8 @@ invalid_lightning_address: Invalid lightning address
unavailable_lightning_address: Unavailable lightning address ${la}
ln_address_temporarily_disabled: ⚠️ Lightning Address payouts are temporarily disabled for maintenance. Please send a regular Lightning invoice (BOLT11) for the exact order amount to receive your sats.
help: |
/sell <_sats amount_> <_fiat amount_> <_fiat code_> <_payment method_> [premium/discount] - Creates a Sell order
/buy <_sats amount_> <_fiat amount_> <_Fiat code_> <_payment method_> [premium/discount] - Creates a Purchase Order
/sell <_sats amount_> <_fiat amount_> <_fiat code_> <_payment method_> [premium/discount] [community] - Creates a Sell order
/buy <_sats amount_> <_fiat amount_> <_Fiat code_> <_payment method_> [premium/discount] [community] - Creates a Purchase Order
/takeorder <_order id_> - Allows the user to take an order from the chat with the bot without going to the channel where it was published
/info - Shows additional info about the bot
/showusername - Toggles off the username display in each new order created. Default value is set to false
Expand Down
12 changes: 8 additions & 4 deletions locales/es.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ must_be_numeric: ${fieldName} debe ser numérico
sats_amount: monto en sats
fiat_amount: monto en fiat
sell_correct_format: |
/sell \<_monto en sats_\> \<_monto en fiat_\> \<_código fiat_\> \<_método de pago_\> \[_prima/descuento_\]
/sell \<_monto en sats_\> \<_monto en fiat_\> \<_código fiat_\> \<_método de pago_\> \[_prima/descuento_\] \[_comunidad_\]

Puedes agregar el nombre de una de tus comunidades como último parámetro para publicar la orden ahí en lugar de en tu comunidad por defecto\. Debes incluir la prima/descuento antes \(usa 0 si no quieres ninguno\)\.

Para crear una venta de 1000 satoshis por 2 bolívares \(VES\) e indicar que el método de pago fiat es pago móvil, debes omitir los \<\> y los \[\]\.

Expand All @@ -85,7 +87,9 @@ sell_correct_format: |

`/sell 0 100\-500 ves "pago móvil" 3`
buy_correct_format: |
/buy \<_monto en sats_\> \<_monto en fiat_\> \<_código fiat_\> \<_método de pago_\> \[_prima/descuento_\]
/buy \<_monto en sats_\> \<_monto en fiat_\> \<_código fiat_\> \<_método de pago_\> \[_prima/descuento_\] \[_comunidad_\]

Puedes agregar el nombre de una de tus comunidades como último parámetro para publicar la orden ahí en lugar de en tu comunidad por defecto\. Debes incluir la prima/descuento antes \(usa 0 si no quieres ninguno\)\.

Para crear una compra de 1000 satoshis por 2 bolívares \(VES\) e indicar que el método de pago fiat es pago móvil, debes omitir los \<\> y los \[\]\.

Expand Down Expand Up @@ -242,8 +246,8 @@ invalid_lightning_address: Dirección lightning no válida
unavailable_lightning_address: Dirección lightning ${la} no disponible
ln_address_temporarily_disabled: ⚠️ Los pagos a Lightning Address están temporalmente deshabilitados por mantenimiento. Por favor envía una factura Lightning normal (BOLT11) por el monto exacto de la orden para recibir tus sats.
help: |
/sell <_monto en sats_> <_monto en fiat_> <_código fiat_> <_método de pago_> [prima/descuento] - Crea una orden de venta
/buy <_monto en sats_> <_monto en fiat_> <_código fiat_> <_método de pago_> [prima/descuento] - Crea una orden de compra
/sell <_monto en sats_> <_monto en fiat_> <_código fiat_> <_método de pago_> [prima/descuento] [comunidad] - Crea una orden de venta
/buy <_monto en sats_> <_monto en fiat_> <_código fiat_> <_método de pago_> [prima/descuento] [comunidad] - Crea una orden de compra
/takeorder <_order id_> - Permite tomar una orden desde el chat con el bot sin ir al canal donde fue publicada
/info - Muestra información sobre el bot
/showusername - Permite mostrar u ocultar el username en cada nueva orden creada, el valor predeterminado es no (falso)
Expand Down
12 changes: 8 additions & 4 deletions locales/fa.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ must_be_numeric: '${fieldName} باید عدد باشد.'
sats_amount: تعداد ساتوشی
fiat_amount: مقدار فیات
sell_correct_format: |
/sell \<_sats amount_\> \<_fiat amount_\> \<_fiat code_\> \<_payment method_\> \[_premium/discount_\]
/sell \<_sats amount_\> \<_fiat amount_\> \<_fiat code_\> \<_payment method_\> \[_premium/discount_\] \[_community_\]

می‌توانید نام یکی از اجتماع‌های خود را به عنوان آخرین پارامتر اضافه کنید تا سفارش به جای اجتماع پیش‌فرض شما در آنجا منتشر شود\. باید پیش از آن، حباب/تخفیف را وارد کنید \(اگر نمی‌خواهید 0 بگذارید\)\.

جهت ایجاد سفارش فروش 1000 ساتوشی در ازای 300 هزار تومان \(IRT\) و اعلام «کارت به کارت» به عنوان روش پرداخت، باید از به کار بردن \<\> و \[\]\ اجتناب کنید\.

Expand All @@ -88,7 +90,9 @@ sell_correct_format: |

`/sell 0 300000\-500000 IRT "payment method" 3`
buy_correct_format: |
/buy \<_sats amount_\> \<_fiat amount_\> \<_fiat code_\> \<_payment method_\> \[_premium/discount_\]
/buy \<_sats amount_\> \<_fiat amount_\> \<_fiat code_\> \<_payment method_\> \[_premium/discount_\] \[_community_\]

می‌توانید نام یکی از اجتماع‌های خود را به عنوان آخرین پارامتر اضافه کنید تا سفارش به جای اجتماع پیش‌فرض شما در آنجا منتشر شود\. باید پیش از آن، حباب/تخفیف را وارد کنید \(اگر نمی‌خواهید 0 بگذارید\)\.

جهت ایجاد سفارش خرید 1000 ساتوشی در ازای 300 هزار تومان \(IRT\) و اعلام «کارت به کارت» به عنوان روش پرداخت، باید از به کار بردن \<\> و \[\]\ اجتناب کنید\.

Expand Down Expand Up @@ -254,10 +258,10 @@ must_be_number_or_range: |
invalid_lightning_address: نشانی لایتنینگ نامعتبر است.
unavailable_lightning_address: 'نشانی لایتنینگ ${la} در دسترس نیست.'
help: |
/sell <_sats amount_> <_fiat amount_> <_fiat code_> <_payment method_> [premium/discount]
/sell <_sats amount_> <_fiat amount_> <_fiat code_> <_payment method_> [premium/discount] [community]
سفارش فروش ایجاد می‌کند.

/buy <_sats amount_> <_fiat amount_> <_Fiat code_> <_payment method_> [premium/discount]
/buy <_sats amount_> <_fiat amount_> <_Fiat code_> <_payment method_> [premium/discount] [community]
سفارش خرید ایجاد می‌کند.

/takeorder <_order id_>
Expand Down
Loading
Loading