Ejemplo n.º 1
0
async def get_insurance(offer: EscrowOffer) -> Decimal:
    """Get insurance of escrow asset in ``offer`` taking limits into account."""
    offer_sum = offer[f"sum_{offer.type}"].to_decimal()
    asset = offer[offer.type]
    limits = await get_escrow_instance(asset).get_limits(asset)
    if not limits:
        return offer_sum
    insured = min(offer_sum, limits.single)
    cursor = database.escrow.aggregate([{
        "$group": {
            "_id": 0,
            "insured_total": {
                "$sum": "$insured"
            }
        }
    }])
    if await cursor.fetch_next:
        insured_total = cursor.next_object()["insured_total"]
        if insured_total != 0:
            insured_total = insured_total.to_decimal()
        total_difference = limits.total - insured_total - insured
        if total_difference < 0:
            insured += total_difference
    return normalize(insured)
Ejemplo n.º 2
0
async def edit_field(message: types.Message, state: FSMContext):
    """Ask new value of chosen order's field during editing."""
    user = database_user.get()
    edit = user["edit"]
    field = edit["field"]
    invert = user.get("invert_order", False)
    set_dict = {}
    error = None

    if field == "sum_buy":
        try:
            transaction_sum = money.money(message.text)
        except money.MoneyValueError as exception:
            error = str(exception)
        else:
            order = await database.orders.find_one({"_id": edit["order_id"]})
            set_dict["sum_buy"] = Decimal128(transaction_sum)
            if "price_sell" in order:
                set_dict["sum_sell"] = Decimal128(
                    money.normalize(transaction_sum * order["price_sell"].to_decimal())
                )

    elif field == "sum_sell":
        try:
            transaction_sum = money.money(message.text)
        except money.MoneyValueError as exception:
            error = str(exception)
        else:
            order = await database.orders.find_one({"_id": edit["order_id"]})
            set_dict["sum_sell"] = Decimal128(transaction_sum)
            if "price_buy" in order:
                set_dict["sum_buy"] = Decimal128(
                    money.normalize(transaction_sum * order["price_buy"].to_decimal())
                )

    elif field == "price":
        try:
            price = money.money(message.text)
        except money.MoneyValueError as exception:
            error = str(exception)
        else:
            order = await database.orders.find_one({"_id": edit["order_id"]})

            if invert:
                price_sell = money.normalize(Decimal(1) / price)
                set_dict["price_buy"] = Decimal128(price)
                set_dict["price_sell"] = Decimal128(price_sell)

                if order.get("sum_currency") == "buy":
                    set_dict["sum_sell"] = Decimal128(
                        money.normalize(order["sum_buy"].to_decimal() * price_sell)
                    )
                elif "sum_sell" in order:
                    set_dict["sum_buy"] = Decimal128(
                        money.normalize(order["sum_sell"].to_decimal() * price)
                    )
            else:
                price_buy = money.normalize(Decimal(1) / price)
                set_dict["price_buy"] = Decimal128(price_buy)
                set_dict["price_sell"] = Decimal128(price)

                if order.get("sum_currency") == "sell":
                    set_dict["sum_buy"] = Decimal128(
                        money.normalize(order["sum_sell"].to_decimal() * price_buy)
                    )
                elif "sum_buy" in order:
                    set_dict["sum_sell"] = Decimal128(
                        money.normalize(order["sum_buy"].to_decimal() * price)
                    )

    elif field == "payment_system":
        payment_system = message.text.replace("\n", " ")
        if len(payment_system) >= 150:
            await tg.send_message(
                message.chat.id,
                i18n("exceeded_character_limit {limit} {sent}").format(
                    limit=150, sent=len(payment_system)
                ),
            )
            return
        set_dict["payment_system"] = payment_system

    elif field == "duration":
        try:
            duration = int(message.text)
            if duration <= 0:
                raise ValueError
        except ValueError:
            error = i18n("send_natural_number")
        else:
            if duration > config.ORDER_DURATION_LIMIT:
                error = i18n("exceeded_duration_limit {limit}").format(
                    limit=config.ORDER_DURATION_LIMIT
                )
            else:
                order = await database.orders.find_one({"_id": edit["order_id"]})
                set_dict["duration"] = duration
                set_dict["expiration_time"] = time() + duration * 24 * 60 * 60
                set_dict["notify"] = True

    elif field == "comments":
        comments = message.text
        if len(comments) >= 150:
            await tg.send_message(
                message.chat.id,
                i18n("exceeded_character_limit {limit} {sent}").format(
                    limit=150, sent=len(comments)
                ),
            )
            return
        set_dict["comments"] = comments

    if set_dict:
        await finish_edit(user, {"$set": set_dict})
        await message.delete()
        try:
            await tg.delete_message(user["chat"], edit["message_id"])
        except MessageCantBeDeleted:
            return
    elif error:
        await message.delete()
        await tg.edit_message_text(error, message.chat.id, edit["message_id"])
Ejemplo n.º 3
0
async def choose_sum(message: types.Message, state: FSMContext):
    """Set sum.

    If price and sum in another currency were not specified, ask for
    sum in another currency. Otherwise calculate it if price was
    specified, and, finally, ask for cashless payment system.
    """
    order = await database.creation.find_one({"user_id": message.from_user.id})
    if "sum_currency" not in order:
        currency = message.text.upper()
        if currency == order["buy"]:
            sum_currency = "buy"
        elif currency == order["sell"]:
            sum_currency = "sell"
        else:
            await tg.send_message(message.chat.id,
                                  i18n("choose_sum_currency_with_buttons"))
            return
        await database.creation.update_one(
            {"_id": order["_id"]}, {"$set": {
                "sum_currency": sum_currency
            }})
        await tg.send_message(
            message.chat.id,
            i18n("ask_order_sum {currency}").format(currency=currency))
        return

    try:
        transaction_sum = money(message.text)
    except MoneyValueError as exception:
        await tg.send_message(message.chat.id, str(exception))
        return

    update_dict = {"sum_" + order["sum_currency"]: Decimal128(transaction_sum)}

    new_sum_currency = "sell" if order["sum_currency"] == "buy" else "buy"
    sum_field = f"sum_{new_sum_currency}"
    price_field = f"price_{new_sum_currency}"

    if price_field in order:
        update_dict[sum_field] = Decimal128(
            normalize(transaction_sum * order[price_field].to_decimal()))
    elif sum_field not in order:
        update_dict["sum_currency"] = new_sum_currency
        await database.creation.update_one({"_id": order["_id"]},
                                           {"$set": update_dict})
        await tg.send_message(
            message.chat.id,
            i18n("ask_order_sum {currency}").format(
                currency=order[update_dict["sum_currency"]]),
            reply_markup=InlineKeyboardMarkup(
                inline_keyboard=await inline_control_buttons(back=False)),
        )
        return

    await database.creation.update_one({"_id": order["_id"]},
                                       {"$set": update_dict})
    if order["buy"] not in whitelist.FIAT and order[
            "sell"] not in whitelist.FIAT:
        await OrderCreation.location.set()
        await tg.send_message(
            message.chat.id,
            i18n("ask_location"),
            reply_markup=InlineKeyboardMarkup(
                inline_keyboard=await inline_control_buttons()),
        )
        return
    await OrderCreation.payment_system.set()
    await tg.send_message(
        message.chat.id,
        i18n("cashless_payment_system"),
        reply_markup=InlineKeyboardMarkup(
            inline_keyboard=await inline_control_buttons()),
    )
Ejemplo n.º 4
0
async def orders_list(
    cursor: Cursor,
    chat_id: int,
    start: int,
    quantity: int,
    buttons_data: str,
    user_id: typing.Optional[int] = None,
    message_id: typing.Optional[int] = None,
    invert: typing.Optional[bool] = None,
) -> None:
    """Send list of orders.

    :param cursor: Cursor of MongoDB query to orders.
    :param chat_id: Telegram ID of current chat.
    :param start: Start index.
    :param quantity: Quantity of orders in cursor.
    :param buttons_data: Beginning of callback data of left/right buttons.
    :param user_id: Telegram ID of current user if cursor is not user-specific.
    :param message_id: Telegram ID of message to edit.
    :param invert: Invert all prices.
    """
    user = await database.users.find_one({"id": types.User.get_current().id})
    if invert is None:
        invert = user.get("invert_book", False)
    else:
        await database.users.update_one({"_id": user["_id"]},
                                        {"$set": {
                                            "invert_book": invert
                                        }})

    keyboard = types.InlineKeyboardMarkup(
        row_width=min(config.ORDERS_COUNT // 2, 8))

    inline_orders_buttons = (
        types.InlineKeyboardButton(
            emojize(":arrow_left:"),
            callback_data="{} {} {}".format(buttons_data,
                                            start - config.ORDERS_COUNT,
                                            int(invert)),
        ),
        types.InlineKeyboardButton(
            emojize(":arrow_right:"),
            callback_data="{} {} {}".format(buttons_data,
                                            start + config.ORDERS_COUNT,
                                            int(invert)),
        ),
    )

    if quantity == 0:
        keyboard.row(*inline_orders_buttons)
        text = i18n("no_orders")
        if message_id is None:
            await tg.send_message(chat_id, text, reply_markup=keyboard)
        else:
            await tg.edit_message_text(text,
                                       chat_id,
                                       message_id,
                                       reply_markup=keyboard)
        return

    all_orders = await cursor.to_list(length=start + config.ORDERS_COUNT)
    orders = all_orders[start:]

    lines = []
    buttons = []
    current_time = time()
    for i, order in enumerate(orders):
        line = ""

        if user_id is None:
            if not order.get(
                    "archived") and order["expiration_time"] > current_time:
                line += emojize(":arrow_forward: ")
            else:
                line += emojize(":pause_button: ")

        exp = Decimal("1e-5")

        if "sum_sell" in order:
            line += "{:,} ".format(
                normalize(order["sum_sell"].to_decimal(), exp))
        line += "{} → ".format(order["sell"])

        if "sum_buy" in order:
            line += "{:,} ".format(
                normalize(order["sum_buy"].to_decimal(), exp))
        line += order["buy"]

        if "price_sell" in order:
            if invert:
                line += " ({:,} {}/{})".format(
                    normalize(order["price_buy"].to_decimal(), exp),
                    order["buy"],
                    order["sell"],
                )
            else:
                line += " ({:,} {}/{})".format(
                    normalize(order["price_sell"].to_decimal(), exp),
                    order["sell"],
                    order["buy"],
                )

        if user_id is not None and order["user_id"] == user_id:
            line = f"*{line}*"

        lines.append(f"{i + 1}. {line}")
        buttons.append(
            types.InlineKeyboardButton("{}".format(i + 1),
                                       callback_data="get_order {}".format(
                                           order["_id"])))

    keyboard.row(
        types.InlineKeyboardButton(
            i18n("invert"),
            callback_data="{} {} {}".format(buttons_data, start,
                                            int(not invert)),
        ))
    keyboard.add(*buttons)
    keyboard.row(*inline_orders_buttons)

    text = ("\\[" + i18n("page {number} {total}").format(
        number=math.ceil(start / config.ORDERS_COUNT) + 1,
        total=math.ceil(quantity / config.ORDERS_COUNT),
    ) + "]\n" + "\n".join(lines))

    if message_id is None:
        await tg.send_message(
            chat_id,
            text,
            reply_markup=keyboard,
            parse_mode=types.ParseMode.MARKDOWN,
            disable_web_page_preview=True,
        )
    else:
        await tg.edit_message_text(
            text,
            chat_id,
            message_id,
            reply_markup=keyboard,
            parse_mode=types.ParseMode.MARKDOWN,
            disable_web_page_preview=True,
        )