Пример #1
0
async def ask_transfer_mosaic(
    ctx: Context, common: NEMTransactionCommon, transfer: NEMTransfer, mosaic: NEMMosaic
) -> None:
    if is_nem_xem_mosaic(mosaic):
        return

    definition = get_mosaic_definition(mosaic.namespace, mosaic.mosaic, common.network)
    mosaic_quantity = mosaic.quantity * transfer.amount // NEM_MOSAIC_AMOUNT_DIVISOR

    if definition:
        await confirm_properties(
            ctx,
            "confirm_mosaic",
            title="Confirm mosaic",
            props=[
                (
                    "Confirm transfer of",
                    format_amount(mosaic_quantity, definition.divisibility)
                    + definition.ticker,
                ),
                ("of", definition.name),
            ],
        )

        if definition.levy is not None:
            levy_fee = _get_levy_fee(definition.levy, mosaic_quantity)
            levy_msg = (
                format_amount(levy_fee, definition.divisibility) + definition.ticker
            )

            await confirm_properties(
                ctx,
                "confirm_mosaic_levy",
                title="Confirm mosaic",
                props=[
                    ("Confirm mosaic\nlevy fee of", levy_msg),
                ],
            )

    else:
        await confirm_action(
            ctx,
            "confirm_mosaic_unknown",
            title="Confirm mosaic",
            action="Unknown mosaic!",
            description="Divisibility and levy cannot be shown for unknown mosaics",
            icon=ui.ICON_SEND,
            icon_color=ui.RED,
            br_code=ButtonRequestType.ConfirmOutput,
        )

        await confirm_properties(
            ctx,
            "confirm_mosaic_transfer",
            title="Confirm mosaic",
            props=[
                ("Confirm transfer of", f"{mosaic_quantity} raw units"),
                ("of", f"{mosaic.namespace}.{mosaic.mosaic}"),
            ],
        )
Пример #2
0
async def authorize_coinjoin(ctx: wire.Context, msg: AuthorizeCoinJoin) -> Success:
    # We cannot use the @with_keychain decorator here, because we need the keychain
    # to survive the function exit. The ownership of the keychain is transferred to
    # the CoinJoinAuthorization object, which takes care of its destruction.
    keychain, coin = await get_keychain_for_coin(ctx, msg.coin_name)

    try:
        if len(msg.coordinator) > _MAX_COORDINATOR_LEN or not all(
            32 <= ord(x) <= 126 for x in msg.coordinator
        ):
            raise wire.DataError("Invalid coordinator name.")

        if not msg.address_n:
            raise wire.DataError("Empty path not allowed.")

        await validate_path(
            ctx,
            addresses.validate_full_path,
            keychain,
            msg.address_n + [0] * BIP32_WALLET_DEPTH,
            coin.curve_name,
            coin=coin,
            script_type=msg.script_type,
        )

        text = Text("Authorize CoinJoin", ui.ICON_RECOVERY)
        text.normal("Do you really want to")
        text.normal("take part in a CoinJoin")
        text.normal("transaction at:")
        text.mono(msg.coordinator)
        await require_confirm(ctx, text)

        text = Text("Authorize CoinJoin", ui.ICON_RECOVERY)
        if msg.fee_per_anonymity is not None:
            text.normal("Fee per anonymity set:")
            text.bold(
                "{} %".format(
                    format_amount(msg.fee_per_anonymity, FEE_PER_ANONYMITY_DECIMALS)
                )
            )
        text.normal("Maximum total fees:")
        text.bold(
            "{} {}".format(
                format_amount(msg.max_total_fee, coin.decimals), coin.coin_shortcut
            )
        )
        await require_hold_to_confirm(ctx, text)

        set_authorization(CoinJoinAuthorization(msg, keychain, coin))

    except BaseException:
        keychain.__del__()
        raise

    return Success(message="CoinJoin authorized")
Пример #3
0
async def require_confirm_tx(ctx, to, value):

    text = Text("Confirm sending", ui.ICON_SEND, ui.GREEN)
    text.bold(format_amount(value, helpers.DECIMALS) + " XRP")
    text.normal("to")
    text.mono(*split_address(to))
    return await require_hold_to_confirm(ctx, text, ButtonRequestType.SignTx)
Пример #4
0
async def require_confirm_final(ctx, fee: int):
    text = Text("Final confirm", ui.ICON_SEND, ui.GREEN)
    text.normal("Sign this transaction")
    text.bold("and pay %s XEM" % format_amount(fee, NEM_MAX_DIVISIBILITY))
    text.normal("for network fee?")
    # we use SignTx, not ConfirmOutput, for compatibility with T1
    await require_hold_to_confirm(ctx, text, ButtonRequestType.SignTx)
Пример #5
0
async def authorize_coinjoin(ctx: wire.Context, msg: AuthorizeCoinJoin,
                             keychain: Keychain, coin: CoinInfo) -> Success:
    if len(msg.coordinator) > _MAX_COORDINATOR_LEN or not all(
            32 <= ord(x) <= 126 for x in msg.coordinator):
        raise wire.DataError("Invalid coordinator name.")

    if msg.max_rounds > _MAX_ROUNDS and safety_checks.is_strict():
        raise wire.DataError("The number of rounds is unexpectedly large.")

    if (msg.max_coordinator_fee_rate > _MAX_COORDINATOR_FEE_RATE
            and safety_checks.is_strict()):
        raise wire.DataError(
            "The coordination fee rate is unexpectedly large.")

    if msg.max_fee_per_kvbyte > 10 * coin.maxfee_kb and safety_checks.is_strict(
    ):
        raise wire.DataError("The fee per vbyte is unexpectedly large.")

    if not msg.address_n:
        raise wire.DataError("Empty path not allowed.")

    await confirm_action(
        ctx,
        "coinjoin_coordinator",
        title="Authorize CoinJoin",
        description=
        "Do you really want to take part in a CoinJoin transaction at:\n{}",
        description_param=msg.coordinator,
        description_param_font=ui.MONO,
        icon=ui.ICON_RECOVERY,
    )

    max_fee_per_vbyte = format_amount(msg.max_fee_per_kvbyte, 3)
    await confirm_coinjoin(ctx, coin.coin_name, msg.max_rounds,
                           max_fee_per_vbyte)

    validation_path = msg.address_n + [0] * BIP32_WALLET_DEPTH
    await validate_path(
        ctx,
        keychain,
        validation_path,
        validate_path_against_script_type(coin,
                                          address_n=validation_path,
                                          script_type=msg.script_type),
    )

    if msg.max_fee_per_kvbyte > coin.maxfee_kb:
        await confirm_metadata(
            ctx,
            "fee_over_threshold",
            "High mining fee",
            "The mining fee of\n{} sats/vbyte\nis unexpectedly high.",
            max_fee_per_vbyte,
            ButtonRequestType.FeeOverThreshold,
        )

    authorization.set(msg)

    return Success(message="CoinJoin authorized")
Пример #6
0
 def make_input_output_pages(msg: BinanceInputOutput, direction):
     for coin in msg.coins:
         items.append((
             direction,
             format_amount(coin.amount, helpers.DECIMALS) + " " +
             coin.denom,
             msg.address,
         ))
Пример #7
0
async def require_confirm_fee(ctx, action: str, fee: int):
    content = (
        ui.NORMAL,
        action,
        ui.BOLD,
        "%s XEM" % format_amount(fee, NEM_MAX_DIVISIBILITY),
    )
    await require_confirm_content(ctx, "Confirm fee", content)
Пример #8
0
 def test_format_amount(self):
     VECTORS = [
         (123456, 3, "123.456"),
         (4242, 7, "0.0004242"),
         (-123456, 3, "-123.456"),
         (-4242, 7, "-0.0004242"),
     ]
     for v in VECTORS:
         self.assertEqual(strings.format_amount(v[0], v[1]), v[2])
Пример #9
0
async def confirm_sending_token_hex(ctx: wire.Context, token: CardanoTokenType,
                                    token_number: int) -> None:
    page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
    page1.bold("Asset #%s name (hex):" % (token_number))
    page1.mono(hexlify(token.asset_name_bytes).decode())
    page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
    page2.normal("Amount sent:")
    page2.bold(format_amount(token.amount, 0))
    await require_confirm(ctx, Paginated([page1, page2]))
Пример #10
0
async def confirm_sending_token_ascii(ctx: wire.Context,
                                      token: CardanoTokenType,
                                      token_number: int) -> None:
    page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
    page1.normal("Asset #%s name (ASCII):" % (token_number))
    page1.bold(token.asset_name_bytes.decode("ascii"))
    page1.normal("Amount sent:")
    page1.bold(format_amount(token.amount, 0))
    await require_confirm(ctx, page1)
Пример #11
0
async def require_confirm_fee(ctx, fee):
    await confirm_metadata(
        ctx,
        "confirm_fee",
        title="Confirm fee",
        content="Transaction fee:\n{}",
        param=format_amount(fee, helpers.DECIMALS) + " XRP",
        hide_continue=True,
        br_code=ButtonRequestType.ConfirmOutput,
    )
Пример #12
0
def _get_levy_msg(mosaic_definition, quantity: int, network: int) -> str:
    levy_definition = get_mosaic_definition(
        mosaic_definition["levy_namespace"], mosaic_definition["levy_mosaic"],
        network)
    if mosaic_definition["levy"] == NEMMosaicLevy.MosaicLevy_Absolute:
        levy_fee = mosaic_definition["fee"]
    else:
        levy_fee = (quantity * mosaic_definition["fee"] //
                    NEM_LEVY_PERCENTILE_DIVISOR_ABSOLUTE)
    return (format_amount(levy_fee, levy_definition["divisibility"]) +
            levy_definition["ticker"])
Пример #13
0
async def authorize_coinjoin(ctx: wire.Context,
                             msg: AuthorizeCoinJoin) -> Success:
    # We cannot use the @with_keychain decorator here, because we need the keychain
    # to survive the function exit. The ownership of the keychain is transferred to
    # the CoinJoinAuthorization object, which takes care of its destruction.
    keychain, coin = await get_keychain_for_coin(ctx, msg.coin_name)

    try:
        if len(msg.coordinator) > _MAX_COORDINATOR_LEN or not all(
                32 <= ord(x) <= 126 for x in msg.coordinator):
            raise wire.DataError("Invalid coordinator name.")

        if not msg.address_n:
            raise wire.DataError("Empty path not allowed.")

        validation_path = msg.address_n + [0] * BIP32_WALLET_DEPTH
        await validate_path(
            ctx,
            keychain,
            validation_path,
            validate_path_against_script_type(coin,
                                              address_n=validation_path,
                                              script_type=msg.script_type),
        )

        await confirm_action(
            ctx,
            "coinjoin_coordinator",
            title="Authorize CoinJoin",
            description=
            "Do you really want to take part in a CoinJoin transaction at:\n{}",
            description_param=msg.coordinator,
            description_param_font=ui.MONO,
            icon=ui.ICON_RECOVERY,
        )

        fee_per_anonymity = None
        if msg.fee_per_anonymity is not None:
            fee_per_anonymity = format_amount(msg.fee_per_anonymity,
                                              FEE_PER_ANONYMITY_DECIMALS)
        await confirm_coinjoin(
            ctx,
            fee_per_anonymity,
            format_coin_amount(msg.max_total_fee, coin, msg.amount_unit),
        )

        set_authorization(CoinJoinAuthorization(msg, keychain, coin))

    except BaseException:
        keychain.__del__()
        raise

    return Success(message="CoinJoin authorized")
Пример #14
0
async def require_confirm_order(ctx: Context, msg: BinanceOrderMsg) -> None:
    if msg.side == BinanceOrderSide.BUY:
        side = "Buy"
    elif msg.side == BinanceOrderSide.SELL:
        side = "Sell"
    else:
        side = "Unknown"

    await confirm_properties(
        ctx,
        "confirm_order",
        title="Confirm order",
        props=[
            ("Sender address:", str(msg.sender)),
            ("Pair:", str(msg.symbol)),
            ("Side:", side),
            ("Quantity:", format_amount(msg.quantity, helpers.DECIMALS)),
            ("Price:", format_amount(msg.price, helpers.DECIMALS)),
        ],
        hold=True,
        br_code=ButtonRequestType.SignTx,
    )
Пример #15
0
async def require_confirm_order(ctx, msg: BinanceOrderMsg):
    page1 = Text("Confirm order 1/3", ui.ICON_SEND, icon_color=ui.GREEN)
    page1.normal("Sender address:")
    page1.bold(msg.sender)

    page2 = Text("Confirm order 2/3", ui.ICON_SEND, icon_color=ui.GREEN)
    page2.normal("Pair:")
    page2.bold(msg.symbol)
    page2.normal("Side:")
    if msg.side == BinanceOrderSide.BUY:
        page2.bold("Buy")
    elif msg.side == BinanceOrderSide.SELL:
        page2.bold("Sell")

    page3 = Text("Confirm order 3/3", ui.ICON_SEND, icon_color=ui.GREEN)
    page3.normal("Quantity:")
    page3.bold(format_amount(msg.quantity, helpers.DECIMALS))
    page3.normal("Price:")
    page3.bold(format_amount(msg.price, helpers.DECIMALS))

    return await require_hold_to_confirm(ctx, Paginated([page1, page2, page3]),
                                         ButtonRequestType.SignTx)
Пример #16
0
    def make_input_output_pages(msg: BinanceInputOutput, direction):
        pages = []
        for coin in msg.coins:
            coin_page = Text("Confirm " + direction,
                             ui.ICON_SEND,
                             icon_color=ui.GREEN)
            coin_page.bold(
                format_amount(coin.amount, helpers.DECIMALS) + " " +
                coin.denom)
            coin_page.normal("to")
            coin_page.mono(*split_address(msg.address))
            pages.append(coin_page)

        return pages
Пример #17
0
def parse(data: bytes) -> bool:
    if not is_valid(data):
        return None
    tx_version, tx_type = unpack(">HH", data[4:8])
    if tx_version == 0 and tx_type == 0 and len(data) == 20:  # OMNI simple send
        currency, amount = unpack(">IQ", data[8:20])
        suffix, divisible = currencies.get(currency, ("UNKN", False))
        return "Simple send of %s %s" % (
            format_amount(amount, 8 if divisible else 0),
            suffix,
        )
    else:
        # unknown OMNI transaction
        return "Unknown transaction"
Пример #18
0
def format_coin_amount(amount: int, coin: CoinInfo,
                       amount_unit: EnumTypeAmountUnit) -> str:
    decimals, shortcut = coin.decimals, coin.coin_shortcut
    if amount_unit == AmountUnit.SATOSHI:
        decimals = 0
        shortcut = "sat " + shortcut
    elif amount_unit == AmountUnit.MICROBITCOIN and decimals >= 6:
        decimals -= 6
        shortcut = "u" + shortcut
    elif amount_unit == AmountUnit.MILLIBITCOIN and decimals >= 3:
        decimals -= 3
        shortcut = "m" + shortcut
    # we don't need to do anything for AmountUnit.BITCOIN
    return "%s %s" % (format_amount(amount, decimals), shortcut)
Пример #19
0
async def confirm_sending_token_bundle(
        ctx: wire.Context, token_bundle: list[CardanoAssetGroupType]) -> None:
    for token_group in token_bundle:
        for token in token_group.tokens:
            page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
            page1.normal("Asset fingerprint:")
            page1.bold(
                format_asset_fingerprint(
                    policy_id=token_group.policy_id,
                    asset_name_bytes=token.asset_name_bytes,
                ))
            page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
            page2.normal("Amount sent:")
            page2.bold(format_amount(token.amount, 0))
            await require_confirm(ctx, Paginated([page1, page2]))
Пример #20
0
def format_ethereum_amount(value: int, token, chain_id: int, tx_type=None):
    if token:
        if token is tokens.UNKNOWN_TOKEN:
            return "Unknown token value"
        suffix = token[2]
        decimals = token[3]
    else:
        suffix = networks.shortcut_by_chain_id(chain_id, tx_type)
        decimals = 18

    # Don't want to display wei values for tokens with small decimal numbers
    if decimals > 9 and value < 10**(decimals - 9):
        suffix = "Wei " + suffix
        decimals = 0

    return "%s %s" % (format_amount(value, decimals), suffix)
async def authorize_coinjoin(ctx: wire.Context, msg: AuthorizeCoinJoin,
                             keychain: Keychain, coin: CoinInfo) -> Success:
    if len(msg.coordinator) > _MAX_COORDINATOR_LEN or not all(
            32 <= ord(x) <= 126 for x in msg.coordinator):
        raise wire.DataError("Invalid coordinator name.")

    if not msg.address_n:
        raise wire.DataError("Empty path not allowed.")

    validation_path = msg.address_n + [0] * BIP32_WALLET_DEPTH
    await validate_path(
        ctx,
        keychain,
        validation_path,
        validate_path_against_script_type(coin,
                                          address_n=validation_path,
                                          script_type=msg.script_type),
    )

    await confirm_action(
        ctx,
        "coinjoin_coordinator",
        title="Authorize CoinJoin",
        description=
        "Do you really want to take part in a CoinJoin transaction at:\n{}",
        description_param=msg.coordinator,
        description_param_font=ui.MONO,
        icon=ui.ICON_RECOVERY,
    )

    if msg.fee_per_anonymity:
        fee_per_anonymity: str | None = format_amount(
            msg.fee_per_anonymity, FEE_PER_ANONYMITY_DECIMALS)
    else:
        fee_per_anonymity = None

    await confirm_coinjoin(
        ctx,
        fee_per_anonymity,
        format_coin_amount(msg.max_total_fee, coin, msg.amount_unit),
    )

    authorization.set(msg)

    return Success(message="CoinJoin authorized")
Пример #22
0
async def confirm_sending_token(ctx: wire.Context, policy_id: bytes,
                                token: CardanoToken) -> None:
    assert token.amount is not None  # _validate_token

    await confirm_properties(
        ctx,
        "confirm_token",
        title="Confirm transaction",
        props=[
            (
                "Asset fingerprint:",
                format_asset_fingerprint(
                    policy_id=policy_id,
                    asset_name_bytes=token.asset_name_bytes,
                ),
            ),
            ("Amount sent:", format_amount(token.amount, 0)),
        ],
        br_code=ButtonRequestType.Other,
    )
Пример #23
0
async def ask_transfer_mosaic(
    ctx, common: NEMTransactionCommon, transfer: NEMTransfer, mosaic: NEMMosaic
):
    if is_nem_xem_mosaic(mosaic.namespace, mosaic.mosaic):
        return

    definition = get_mosaic_definition(mosaic.namespace, mosaic.mosaic, common.network)
    mosaic_quantity = mosaic.quantity * transfer.amount / NEM_MOSAIC_AMOUNT_DIVISOR

    if definition:
        msg = Text("Confirm mosaic", ui.ICON_SEND, ui.GREEN)
        msg.normal("Confirm transfer of")
        msg.bold(
            format_amount(mosaic_quantity, definition["divisibility"])
            + definition["ticker"]
        )
        msg.normal("of")
        msg.bold(definition["name"])
        await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput)

        if "levy" in definition and "fee" in definition:
            levy_msg = _get_levy_msg(definition, mosaic_quantity, common.network)
            msg = Text("Confirm mosaic", ui.ICON_SEND, ui.GREEN)
            msg.normal("Confirm mosaic", "levy fee of")
            msg.bold(levy_msg)
            await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput)

    else:
        msg = Text("Confirm mosaic", ui.ICON_SEND, ui.RED)
        msg.bold("Unknown mosaic!")
        msg.normal("Divisibility and levy")
        msg.normal("cannot be shown for")
        msg.normal("unknown mosaics")
        await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput)

        msg = Text("Confirm mosaic", ui.ICON_SEND, ui.GREEN)
        msg.normal("Confirm transfer of")
        msg.bold("%s raw units" % mosaic_quantity)
        msg.normal("of")
        msg.bold("%s.%s" % (mosaic.namespace, mosaic.mosaic))
        await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput)
Пример #24
0
def format_coin_amount(amount: int) -> str:
    return "%s %s" % (format_amount(amount, 6), "ADA")
Пример #25
0
def format_coin_amount(amount: int, coin: coininfo.CoinInfo) -> str:
    return "%s %s" % (format_amount(amount, coin.decimals), coin.coin_shortcut)
Пример #26
0
async def _require_confirm_transfer(ctx, recipient, value):
    text = Text("Confirm transfer", ui.ICON_SEND, ui.GREEN)
    text.bold("Send %s XEM" % format_amount(value, NEM_MAX_DIVISIBILITY))
    text.normal("to")
    text.mono(*split_address(recipient))
    await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
Пример #27
0
def format_amount(value):
    return "%s XMR" % strings.format_amount(value, 12)
Пример #28
0
def format_amount(amount: int, ticker=True) -> str:
    t = ""
    if ticker:
        t = " XLM"
    return strings.format_amount(amount, consts.AMOUNT_DECIMALS) + t
Пример #29
0
def format_coin_amount(value):
    return "%s LSK" % format_amount(value, 8)
Пример #30
0
def format_coin_amount(amount):
    return "%s %s" % (format_amount(amount, 6), "ADA")