1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-23 14:58:09 +00:00

refactor(core): convert apps.stellar to layouts

This commit is contained in:
Martin Milata 2021-03-02 23:55:56 +01:00 committed by matejcik
parent 6aeaadfe16
commit 12478b1716
4 changed files with 449 additions and 207 deletions

View File

@ -1,8 +1,12 @@
from trezor import strings, ui, utils
from trezor import strings, ui
from trezor.enums import ButtonRequestType
from trezor.ui.components.tt.text import Text
from apps.common.confirm import require_confirm, require_hold_to_confirm
from trezor.ui.constants import MONO_ADDR_PER_LINE
from trezor.ui.layouts import (
confirm_action,
confirm_hex,
confirm_metadata,
confirm_timebounds_stellar,
)
from . import consts
@ -10,68 +14,107 @@ from . import consts
async def require_confirm_init(
ctx, address: str, network_passphrase: str, accounts_match: bool
):
text = Text("Confirm Stellar", ui.ICON_SEND, ui.GREEN)
text.normal("Initialize signing with")
if accounts_match:
text.normal("your account")
text.mono(*split(trim_to_rows(address, 3)))
description = "Initialize signing with\nyour account"
else:
text.mono(*split(address))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
description = "Initialize signing with"
await require_confirm_op(
ctx,
"confirm_init",
title="Confirm Stellar",
subtitle=None,
description=description,
data=address,
icon=ui.ICON_SEND,
is_account=True,
)
network = get_network_warning(network_passphrase)
if network:
text = Text("Confirm network", ui.ICON_CONFIRM, ui.GREEN)
text.normal("Transaction is on")
text.bold(network)
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await confirm_metadata(
ctx,
"confirm_init_network",
title="Confirm network",
content="Transaction is on {}",
param=network,
icon=ui.ICON_CONFIRM,
br_code=ButtonRequestType.ConfirmOutput,
hide_continue=True,
)
async def require_confirm_timebounds(ctx, start: int, end: int):
text = Text("Confirm timebounds", ui.ICON_SEND, ui.GREEN)
text.bold("Valid from (UTC):")
if start:
text.normal(str(start))
else:
text.mono("[no restriction]")
text.bold("Valid to (UTC):")
if end:
text.normal(str(end))
else:
text.mono("[no restriction]")
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await confirm_timebounds_stellar(ctx, start, end)
async def require_confirm_memo(ctx, memo_type: int, memo_text: str):
text = Text("Confirm memo", ui.ICON_CONFIRM, ui.GREEN)
if memo_type == consts.MEMO_TYPE_TEXT:
text.bold("Memo (TEXT)")
description = "Memo (TEXT)"
elif memo_type == consts.MEMO_TYPE_ID:
text.bold("Memo (ID)")
description = "Memo (ID)"
elif memo_type == consts.MEMO_TYPE_HASH:
text.bold("Memo (HASH)")
description = "Memo (HASH)"
elif memo_type == consts.MEMO_TYPE_RETURN:
text.bold("Memo (RETURN)")
else: # MEMO_TYPE_NONE
text.bold("No memo set!")
text.normal("Important: Many exchanges require a memo when depositing")
if memo_type != consts.MEMO_TYPE_NONE:
text.mono(*split(memo_text))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
description = "Memo (RETURN)"
else:
return await confirm_action(
ctx,
"confirm_memo",
title="Confirm memo",
action="No memo set!",
description="Important: Many exchanges require a memo when depositing",
icon=ui.ICON_CONFIRM,
icon_color=ui.GREEN,
br_code=ButtonRequestType.ConfirmOutput,
)
await require_confirm_op(
ctx,
"confirm_memo",
title="Confirm memo",
subtitle=description,
data=memo_text,
split=False,
)
async def require_confirm_final(ctx, fee: int, num_operations: int):
op_str = str(num_operations) + " operation"
if num_operations > 1:
op_str += "s"
text = Text("Final confirm", ui.ICON_SEND, ui.GREEN)
text.normal("Sign this transaction")
text.normal("made up of " + op_str)
text.bold("and pay " + format_amount(fee))
text.normal("for fee?")
# we use SignTx, not ConfirmOutput, for compatibility with T1
await require_hold_to_confirm(ctx, text, ButtonRequestType.SignTx)
op_str = strings.format_plural("{count} {plural}", num_operations, "operation")
await confirm_metadata(
ctx,
"confirm_final",
title="Final confirm",
content="Sign this transaction made up of " + op_str + " and pay {}\nfor fee?",
param=format_amount(fee),
hide_continue=True,
hold=True,
)
async def require_confirm_op(
ctx,
br_type: str,
subtitle: str | None,
data: str,
title: str = "Confirm operation",
description: str = None,
icon=ui.ICON_CONFIRM,
split: bool = True,
is_account: bool = False,
):
await confirm_hex(
ctx,
br_type,
title=title,
subtitle=subtitle,
description=description,
data=data,
width=MONO_ADDR_PER_LINE if split else None,
icon=icon,
truncate=True,
truncate_ellipsis=".." if is_account else "",
br_code=ButtonRequestType.ConfirmOutput,
)
def format_amount(amount: int, ticker=True) -> str:
@ -81,22 +124,6 @@ def format_amount(amount: int, ticker=True) -> str:
return strings.format_amount(amount, consts.AMOUNT_DECIMALS) + t
def split(text):
return utils.chunks(text, 17)
def trim(payload: str, length: int, dots=True) -> str:
if len(payload) > length:
if dots:
return payload[: length - 2] + ".."
return payload[: length - 2]
return payload
def trim_to_rows(payload: str, rows: int = 1) -> str:
return trim(payload, rows * 17)
def get_network_warning(network_passphrase: str):
if network_passphrase == consts.NETWORK_PASSPHRASE_PUBLIC:
return None

View File

@ -15,68 +15,72 @@ from trezor.messages import (
StellarPaymentOp,
StellarSetOptionsOp,
)
from trezor.ui.components.tt.text import Text
from trezor.ui.layouts import confirm_metadata
from trezor.wire import ProcessError
from .. import consts, helpers
from ..layout import format_amount, require_confirm, split, trim_to_rows, ui
from ..layout import format_amount, require_confirm_op, ui
async def confirm_source_account(ctx, source_account: bytes):
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.bold("Source account:")
text.mono(*split(source_account))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
async def confirm_source_account(ctx, source_account: str):
await require_confirm_op(ctx, "confirm_source", "Source account:", source_account)
async def confirm_allow_trust_op(ctx, op: StellarAllowTrustOp):
if op.is_authorized:
t = "Allow Trust"
else:
t = "Revoke Trust"
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.bold(t)
text.normal("of %s by:" % op.asset_code)
text.mono(*split(trim_to_rows(op.trusted_account, 3)))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm_op(
ctx,
"op_allow_trust",
subtitle="Allow Trust" if op.is_authorized else "Revoke Trust",
description="of %s by:" % op.asset_code,
data=op.trusted_account,
is_account=True,
)
async def confirm_account_merge_op(ctx, op: StellarAccountMergeOp):
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.bold("Account Merge")
text.normal("All XLM will be sent to:")
text.mono(*split(trim_to_rows(op.destination_account, 3)))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm_op(
ctx,
"op_merge",
"Account Merge",
description="All XLM will be sent to:",
data=op.destination_account,
is_account=True,
)
async def confirm_bump_sequence_op(ctx, op: StellarBumpSequenceOp):
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.bold("Bump Sequence")
text.normal("Set sequence to")
text.mono(str(op.bump_to))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm_op(
ctx,
"op_bump",
"Bump Sequence",
description="Set sequence to",
data=str(op.bump_to),
split=False,
)
async def confirm_change_trust_op(ctx, op: StellarChangeTrustOp):
if op.limit == 0:
t = "Delete Trust"
else:
t = "Add Trust"
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.bold(t)
text.normal("Asset: %s" % op.asset.code)
text.normal("Amount: %s" % format_amount(op.limit, ticker=False))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm_op(
ctx,
"op_change_trust",
subtitle="Delete Trust" if op.limit == 0 else "Add Trust",
description="Asset: %s\nAmount: %s"
% (op.asset.code, format_amount(op.limit, ticker=False)),
data="",
split=False,
)
await confirm_asset_issuer(ctx, op.asset)
async def confirm_create_account_op(ctx, op: StellarCreateAccountOp):
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.bold("Create Account")
text.normal("with %s" % format_amount(op.starting_balance))
text.mono(*split(trim_to_rows(op.new_account, 3)))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm_op(
ctx,
"op_account",
subtitle="Create Account",
description="with %s" % format_amount(op.starting_balance),
data=op.new_account,
is_account=True,
)
async def confirm_create_passive_offer_op(ctx, op: StellarCreatePassiveOfferOp):
@ -100,14 +104,20 @@ async def confirm_manage_offer_op(ctx, op: StellarManageOfferOp):
async def _confirm_offer(ctx, title, op):
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.bold(title)
text.normal(
"Sell %s %s" % (format_amount(op.amount, ticker=False), op.selling_asset.code)
await require_confirm_op(
ctx,
"op_offer",
subtitle=title,
description="Sell %s %s\nFor %f\nPer %s"
% (
format_amount(op.amount, ticker=False),
op.selling_asset.code,
op.price_n / op.price_d,
format_asset_code(op.buying_asset),
),
data="",
split=False,
)
text.normal("For %f" % (op.price_n / op.price_d))
text.normal("Per %s" % format_asset_code(op.buying_asset))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await confirm_asset_issuer(ctx, op.selling_asset)
await confirm_asset_issuer(ctx, op.buying_asset)
@ -119,121 +129,128 @@ async def confirm_manage_data_op(ctx, op: StellarManageDataOp):
title = "Set"
else:
title = "Clear"
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.bold("%s data value key" % title)
text.mono(*split(op.key))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm_op(ctx, "op_data", "%s data value key" % title, op.key)
if op.value:
digest = sha256(op.value).digest()
digest_str = hexlify(digest).decode()
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.bold("Value (SHA-256):")
text.mono(*split(digest_str))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm_op(ctx, "op_data_value", "Value (SHA-256):", digest_str)
async def confirm_path_payment_op(ctx, op: StellarPathPaymentOp):
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.bold("Path Pay %s" % format_amount(op.destination_amount, ticker=False))
text.bold("%s to:" % format_asset_code(op.destination_asset))
text.mono(*split(trim_to_rows(op.destination_account, 3)))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm_op(
ctx,
"op_path_payment",
subtitle="Path Pay %s\n%s to:"
% (
format_amount(op.destination_amount, ticker=False),
format_asset_code(op.destination_asset),
),
data=op.destination_account,
is_account=True,
)
await confirm_asset_issuer(ctx, op.destination_asset)
# confirm what the sender is using to pay
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.normal("Pay using")
text.bold(format_amount(op.send_max, ticker=False))
text.bold(format_asset_code(op.send_asset))
text.normal("This amount is debited")
text.normal("from your account.")
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await confirm_metadata(
ctx,
"op_path_payment",
"Confirm operation",
content="Pay using\n{}\nThis amount is debited from your account.",
param="{}\n{}".format(
format_amount(op.send_max, ticker=False),
format_asset_code(op.send_asset),
),
icon=ui.ICON_CONFIRM,
hide_continue=True,
br_code=ButtonRequestType.ConfirmOutput,
)
await confirm_asset_issuer(ctx, op.send_asset)
async def confirm_payment_op(ctx, op: StellarPaymentOp):
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.bold("Pay %s" % format_amount(op.amount, ticker=False))
text.bold("%s to:" % format_asset_code(op.asset))
text.mono(*split(trim_to_rows(op.destination_account, 3)))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
description = "Pay {}\n{} to:".format(
format_amount(op.amount, ticker=False), format_asset_code(op.asset)
)
await require_confirm_op(
ctx, "op_payment", description, op.destination_account, is_account=True
)
await confirm_asset_issuer(ctx, op.asset)
async def confirm_set_options_op(ctx, op: StellarSetOptionsOp):
if op.inflation_destination_account:
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.bold("Set Inflation Destination")
text.mono(*split(op.inflation_destination_account))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm_op(
ctx,
"op_inflation",
"Set Inflation Destination",
op.inflation_destination_account,
)
if op.clear_flags:
t = _format_flags(op.clear_flags)
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.bold("Clear Flags")
text.mono(*t)
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm_op(ctx, "op_clear_flags", "Clear Flags", t, split=False)
if op.set_flags:
t = _format_flags(op.set_flags)
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.bold("Set Flags")
text.mono(*t)
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm_op(ctx, "op_set_flags", "Set Flags", t, split=False)
thresholds = _format_thresholds(op)
if thresholds:
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.bold("Account Thresholds")
text.mono(*thresholds)
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm_op(
ctx,
"op_thresholds",
"Account Thresholds",
thresholds,
split=False,
)
if op.home_domain:
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.bold("Home Domain")
text.mono(*split(op.home_domain))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm_op(ctx, "op_home_domain", "Home Domain", op.home_domain)
if op.signer_type is not None:
if op.signer_weight > 0:
t = "Add Signer (%s)"
else:
t = "Remove Signer (%s)"
if op.signer_type == consts.SIGN_TYPE_ACCOUNT:
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.bold(t % "acc")
text.mono(*split(helpers.address_from_public_key(op.signer_key)))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm_op(
ctx,
"op_signer",
t % "acc",
helpers.address_from_public_key(op.signer_key),
)
elif op.signer_type in (consts.SIGN_TYPE_PRE_AUTH, consts.SIGN_TYPE_HASH):
if op.signer_type == consts.SIGN_TYPE_PRE_AUTH:
signer_type = "auth"
else:
signer_type = "hash"
text = Text("Confirm operation", ui.ICON_CONFIRM, ui.GREEN)
text.bold(t % signer_type)
text.mono(*split(hexlify(op.signer_key).decode()))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm_op(
ctx,
"op_signer",
t % signer_type,
hexlify(op.signer_key).decode(),
)
else:
raise ProcessError("Stellar: invalid signer type")
def _format_thresholds(op: StellarSetOptionsOp) -> tuple:
text = ()
text = ""
if op.master_weight is not None:
text += ("Master Weight: %d" % op.master_weight,)
text += "Master Weight: %d\n" % op.master_weight
if op.low_threshold is not None:
text += ("Low: %d" % op.low_threshold,)
text += "Low: %d\n" % op.low_threshold
if op.medium_threshold is not None:
text += ("Medium: %d" % op.medium_threshold,)
text += "Medium: %d\n" % op.medium_threshold
if op.high_threshold is not None:
text += ("High: %d" % op.high_threshold,)
text += "High: %d\n" % op.high_threshold
return text
def _format_flags(flags: int) -> tuple:
if flags > consts.FLAGS_MAX_SIZE:
raise ProcessError("Stellar: invalid flags")
text = ()
if flags & consts.FLAG_AUTH_REQUIRED:
text += ("AUTH_REQUIRED",)
if flags & consts.FLAG_AUTH_REVOCABLE:
text += ("AUTH_REVOCABLE",)
if flags & consts.FLAG_AUTH_IMMUTABLE:
text += ("AUTH_IMMUTABLE",)
text = "{}{}{}".format(
"AUTH_REQUIRED\n" if flags & consts.FLAG_AUTH_REQUIRED else "",
"AUTH_REVOCABLE\n" if flags & consts.FLAG_AUTH_REVOCABLE else "",
"AUTH_IMMUTABLE\n" if flags & consts.FLAG_AUTH_IMMUTABLE else "",
)
return text
@ -246,7 +263,10 @@ def format_asset_code(asset: StellarAssetType) -> str:
async def confirm_asset_issuer(ctx, asset: StellarAssetType):
if asset is None or asset.type == consts.ASSET_TYPE_NATIVE:
return
text = Text("Confirm issuer", ui.ICON_CONFIRM, ui.GREEN)
text.bold("%s issuer:" % asset.code)
text.mono(*split(asset.issuer))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm_op(
ctx,
"confirm_issuer",
title="Confirm issuer",
subtitle="%s issuer:" % asset.code,
data=asset.issuer,
)

View File

@ -61,6 +61,7 @@ __all__ = (
"confirm_modify_output",
"confirm_modify_fee",
"confirm_coinjoin",
"confirm_timebounds_stellar",
)
@ -216,16 +217,18 @@ def _truncate_hex(
lines: int = TEXT_MAX_LINES,
width: int = MONO_HEX_PER_LINE,
middle: bool = False,
ellipsis: str = "...", # TODO: cleanup @ redesign
) -> Iterator[str]:
ell_len = len(ellipsis)
if len(hex_data) > width * lines:
if middle:
hex_data = (
hex_data[: lines * width // 2 - 1]
+ "..."
+ hex_data[-lines * width // 2 + 2 :]
hex_data[: lines * width // 2 - (ell_len // 2)]
+ ellipsis
+ hex_data[-lines * width // 2 + (ell_len - ell_len // 2) :]
)
else:
hex_data = hex_data[: (width * lines - 3)] + "..."
hex_data = hex_data[: (width * lines - ell_len)] + ellipsis
return chunks_intersperse(hex_data, width)
@ -490,40 +493,55 @@ async def confirm_hex(
br_type: str,
title: str,
data: str,
subtitle: str | None = None,
description: str | None = None,
br_code: ButtonRequestType = ButtonRequestType.Other,
icon: str = ui.ICON_SEND, # TODO cleanup @ redesign
icon_color: int = ui.GREEN, # TODO cleanup @ redesign
font_description: int = ui.NORMAL, # TODO cleanup @ redesign
color_description: int = ui.FG, # TODO cleanup @ redesign
width: int = MONO_HEX_PER_LINE,
width: int | None = MONO_HEX_PER_LINE,
width_paginated: int = MONO_HEX_PER_LINE - 2,
truncate: bool = False,
truncate_middle: bool = False,
truncate_ellipsis: str = "...",
) -> None:
if truncate:
text = Text(title, icon, icon_color, new_lines=False)
description_lines = 0
if description is not None:
description_lines = Span(description, 0, font_description).count_lines()
text.content.extend(
(font_description, color_description, description, ui.FG)
)
if subtitle is not None:
description_lines += Span(subtitle, 0, ui.BOLD).count_lines()
text.bold(subtitle)
text.br()
if description is not None:
description_lines += Span(description, 0, ui.NORMAL).count_lines()
text.content.extend((ui.NORMAL, color_description, description, ui.FG))
text.br()
if width is not None:
text.mono(
*_truncate_hex(
data,
lines=TEXT_MAX_LINES - description_lines,
width=width,
middle=truncate_middle,
ellipsis=truncate_ellipsis,
)
)
else:
text.mono(data)
content: ui.Layout = Confirm(text)
else:
width_paginated = min(width, MONO_HEX_PER_LINE - 2)
assert color_description == ui.FG # only ethereum uses this and it truncates
para = [(font_description, description)] if description is not None else []
para = []
if subtitle is not None:
para.append((ui.BOLD, subtitle))
if description is not None:
assert (
color_description == ui.FG
) # only ethereum uses this and it truncates
para.append((ui.NORMAL, description))
if width is not None:
para.extend((ui.MONO, line) for line in chunks(data, width_paginated))
else:
para.append((ui.MONO, data))
content = paginate_paragraphs(para, title, icon, icon_color)
await raise_if_cancelled(interact(ctx, content, br_type, br_code))
@ -597,8 +615,9 @@ async def confirm_metadata(
br_code: ButtonRequestType = ButtonRequestType.SignTx,
hide_continue: bool = False,
hold: bool = False,
icon: str = ui.ICON_SEND, # TODO cleanup @ redesign
) -> None:
text = Text(title, ui.ICON_SEND, ui.GREEN, new_lines=False)
text = Text(title, icon, ui.GREEN, new_lines=False)
text.format_parametrized(content, param if param is not None else "")
if not hide_continue:
@ -732,3 +751,27 @@ async def confirm_signverify(
ButtonRequestType.Other,
)
)
# TODO cleanup @ redesign
async def confirm_timebounds_stellar(
ctx: wire.GenericContext, start: int, end: int
) -> None:
text = Text("Confirm timebounds", ui.ICON_SEND, ui.GREEN)
text.bold("Valid from (UTC):")
if start:
text.normal(str(start))
else:
text.mono("[no restriction]")
text.bold("Valid to (UTC):")
if end:
text.normal(str(end))
else:
text.mono("[no restriction]")
await raise_if_cancelled(
interact(
ctx, Confirm(text), "confirm_timebounds", ButtonRequestType.ConfirmOutput
)
)

View File

@ -67,12 +67,15 @@ ADDRESS_N = parse_path(stellar.DEFAULT_BIP32_PATH)
NETWORK_PASSPHRASE = "Test SDF Network ; September 2015"
def _create_msg() -> messages.StellarSignTx:
def _create_msg(memo=False) -> messages.StellarSignTx:
kwargs = {"memo_type": 0}
if memo:
kwargs = {"memo_type": 1, "memo_text": "hi"}
return messages.StellarSignTx(
source_account="GAK5MSF74TJW6GLM7NLTL76YZJKM2S4CGP3UH4REJHPHZ4YBZW2GSBPW",
fee=100,
sequence_number=0x100000000,
memo_type=0,
**kwargs,
)
@ -209,6 +212,131 @@ def test_sign_tx_payment_op_custom_asset12(client):
)
# testcase added for UI code coverage, may not normally make sense
def test_sign_tx_allow_trust_op(client):
op = messages.StellarAllowTrustOp()
op.is_authorized = True
op.trusted_account = "GBOVKZBEM2YYLOCDCUXJ4IMRKHN4LCJAE7WEAEA2KF562XFAGDBOB64V"
op.asset_type = 1
op.asset_code = "X"
tx = _create_msg(memo=True)
response = stellar.sign_tx(client, tx, [op], ADDRESS_N, NETWORK_PASSPHRASE)
assert (
b64encode(response.signature)
== b"JLLwaDvPAomcDnljhlM3LF6WQvlQzI+V/afI95X41HGRYgwbYrxXOplzzdBhbRxd09VxDkb3nQ271l6MEqn/CQ=="
)
# testcase added for UI code coverage, may not normally make sense
def test_sign_tx_change_trust_op(client):
op = messages.StellarChangeTrustOp()
op.limit = 500111000
op.source_account = "GBOVKZBEM2YYLOCDCUXJ4IMRKHN4LCJAE7WEAEA2KF562XFAGDBOB64V"
op.asset = messages.StellarAssetType(
type=2,
code="ABCDEFGHIJKL",
issuer="GAUYJFQCYIHFQNS7CI6BFWD2DSSFKDIQZUQ3BLQODDKE4PSW7VVBKENC",
)
tx = _create_msg()
response = stellar.sign_tx(client, tx, [op], ADDRESS_N, NETWORK_PASSPHRASE)
assert (
b64encode(response.signature)
== b"OZdDO/qW8o/xbV6nZaDM/D7z9/fqbrk+P4lSzzCqeD3C8nGOg+Jl33JqHek0zNNOW9Pn+tPpfdoQnuZWJzocCw=="
)
# testcase added for UI code coverage, may not normally make sense
def test_sign_tx_passive_offer_op(client):
op = messages.StellarCreatePassiveOfferOp()
op.selling_asset = messages.StellarAssetType(
type=2,
code="ABCDEFGHIJKL",
issuer="GAUYJFQCYIHFQNS7CI6BFWD2DSSFKDIQZUQ3BLQODDKE4PSW7VVBKENC",
)
op.buing_asset = messages.StellarAssetType(
type=1,
code="X",
issuer="GAUYJFQCYIHFQNS7CI6BFWD2DSSFKDIQZUQ3BLQODDKE4PSW7VVBKENC",
)
op.amount = 4
op.price_n = 5
op.price_d = 6
tx = _create_msg()
response = stellar.sign_tx(client, tx, [op], ADDRESS_N, NETWORK_PASSPHRASE)
assert (
b64encode(response.signature)
== b"78/YNz3U4PZmKubPgl+PIm/Jr8omISshJtwJuqXp4rSo9bAxxYRvMSa2IGFIy9PfIe2kDxnqSajTwiUFGOOtAw=="
)
# testcase added for UI code coverage, may not normally make sense
def test_sign_tx_manage_offer_op(client):
op = messages.StellarManageOfferOp()
op.selling_asset = messages.StellarAssetType(
type=2,
code="ABCDEFGHIJKL",
issuer="GAUYJFQCYIHFQNS7CI6BFWD2DSSFKDIQZUQ3BLQODDKE4PSW7VVBKENC",
)
op.buing_asset = messages.StellarAssetType(
type=1,
code="X",
issuer="GAUYJFQCYIHFQNS7CI6BFWD2DSSFKDIQZUQ3BLQODDKE4PSW7VVBKENC",
)
op.amount = 4
op.price_n = 5
op.price_d = 6
op.offer_id = 1337
tx = _create_msg()
response = stellar.sign_tx(client, tx, [op], ADDRESS_N, NETWORK_PASSPHRASE)
assert (
b64encode(response.signature)
== b"tkCta8G5dmxOVYJ+/mGve1lzNyIKZB83DwWdZH2A6zGI7KF2VYGG8RNHmlMpMqeBFcit9o+/Ss+IAQ86CZBTAw=="
)
# testcase added for UI code coverage, may not normally make sense
def test_sign_tx_path_payment_op(client):
op = messages.StellarPathPaymentOp()
op.send = messages.StellarAssetType(
type=1,
code="X",
issuer="GAUYJFQCYIHFQNS7CI6BFWD2DSSFKDIQZUQ3BLQODDKE4PSW7VVBKENC",
)
op.send_max = 50000
op.destination_account = "GAUYJFQCYIHFQNS7CI6BFWD2DSSFKDIQZUQ3BLQODDKE4PSW7VVBKENC"
op.destination_asset = messages.StellarAssetType(
type=1,
code="X",
issuer="GAUYJFQCYIHFQNS7CI6BFWD2DSSFKDIQZUQ3BLQODDKE4PSW7VVBKENC",
)
op.destination_amount = 6667
tx = _create_msg()
response = stellar.sign_tx(client, tx, [op], ADDRESS_N, NETWORK_PASSPHRASE)
assert (
b64encode(response.signature)
== b"KMUKub6SRXS4R86ux74bSSJXtMMQ1tEWhxc71jcAozKRX/db5dJC7oBVSeijSCT+hJOG/wTw6Jd1UBkJC0JgCw=="
)
def test_sign_tx_set_options(client):
"""Set inflation destination"""
@ -278,6 +406,30 @@ def test_sign_tx_set_options(client):
# db6adf70eaf10621396a4a4db27597f323e000ea5c95b6a356a5d469730d78bd34d29d4e845862d39d2dd7e18d469a123727d5b0918dbed948086a47e24b0301
)
op = messages.StellarSetOptionsOp()
op.signer_type = 1
op.signer_key = bytes.fromhex(
"72187adb879c414346d77c71af8cce7b6eaa57b528e999fd91feae6b6418628e"
)
op.signer_weight = 0
tx = _create_msg()
response = stellar.sign_tx(client, tx, [op], ADDRESS_N, NETWORK_PASSPHRASE)
assert (
b64encode(response.signature)
== b"fvZ8rzZPkJwa1lsr4/z/wXZLT6cBwFmwY861nmEnhy57Stw1dxCipo5PJeXk/EhyLxlAwL99+m7qWtdW38EZBg=="
)
op = messages.StellarSetOptionsOp()
op.clear_flags = 4
tx = _create_msg()
response = stellar.sign_tx(client, tx, [op], ADDRESS_N, NETWORK_PASSPHRASE)
assert (
b64encode(response.signature)
== b"ZObGPxqyavv1fjXnlVQJM35FZu8zkJBAWkuOaI+KqyHTB8rOI4oXb27tohAnxiAzMn7e/tiNfqZwzQQS6RqmBg=="
)
def test_sign_tx_timebounds(client):
op = messages.StellarSetOptionsOp()