You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/src/apps/eos/actions/layout.py

319 lines
11 KiB

from micropython import const
from ubinascii import hexlify
from trezor import ui
from trezor.messages import ButtonRequestType
from trezor.ui.components.tt.scroll import Paginated
from trezor.ui.components.tt.text import Text
from trezor.utils import chunks
from .. import helpers
from ..layout import require_confirm
if False:
from trezor import wire
from trezor.messages.EosAuthorization import EosAuthorization
from trezor.messages.EosActionBuyRam import EosActionBuyRam
from trezor.messages.EosActionBuyRamBytes import EosActionBuyRamBytes
from trezor.messages.EosActionCommon import EosActionCommon
from trezor.messages.EosActionDelegate import EosActionDelegate
from trezor.messages.EosActionDeleteAuth import EosActionDeleteAuth
from trezor.messages.EosActionLinkAuth import EosActionLinkAuth
from trezor.messages.EosActionNewAccount import EosActionNewAccount
from trezor.messages.EosActionRefund import EosActionRefund
from trezor.messages.EosActionSellRam import EosActionSellRam
from trezor.messages.EosActionTransfer import EosActionTransfer
from trezor.messages.EosActionUndelegate import EosActionUndelegate
from trezor.messages.EosActionUnlinkAuth import EosActionUnlinkAuth
from trezor.messages.EosActionUpdateAuth import EosActionUpdateAuth
from trezor.messages.EosActionVoteProducer import EosActionVoteProducer
_LINE_LENGTH = const(17)
_LINE_PLACEHOLDER = "{:<" + str(_LINE_LENGTH) + "}"
_FIRST_PAGE = const(0)
_TWO_FIELDS_PER_PAGE = const(2)
_THREE_FIELDS_PER_PAGE = const(3)
_FOUR_FIELDS_PER_PAGE = const(4)
_FIVE_FIELDS_PER_PAGE = const(5)
async def _require_confirm_paginated(
ctx: wire.Context, header: str, fields: list[str], per_page: int
) -> None:
pages = []
for page in chunks(fields, per_page):
if header == "Arbitrary data":
text = Text(header, ui.ICON_WIPE, ui.RED)
else:
text = Text(header, ui.ICON_CONFIRM, ui.GREEN)
text.mono(*page)
pages.append(text)
await require_confirm(ctx, Paginated(pages), ButtonRequestType.ConfirmOutput)
async def confirm_action_buyram(ctx: wire.Context, msg: EosActionBuyRam) -> None:
text = "Buy RAM"
fields = []
fields.append("Payer:")
fields.append(helpers.eos_name_to_string(msg.payer))
fields.append("Receiver:")
fields.append(helpers.eos_name_to_string(msg.receiver))
fields.append("Amount:")
fields.append(helpers.eos_asset_to_string(msg.quantity))
await _require_confirm_paginated(ctx, text, fields, _FOUR_FIELDS_PER_PAGE)
async def confirm_action_buyrambytes(
ctx: wire.Context, msg: EosActionBuyRamBytes
) -> None:
text = "Buy RAM"
fields = []
fields.append("Payer:")
fields.append(helpers.eos_name_to_string(msg.payer))
fields.append("Receiver:")
fields.append(helpers.eos_name_to_string(msg.receiver))
fields.append("Bytes:")
fields.append(str(msg.bytes))
await _require_confirm_paginated(ctx, text, fields, _FOUR_FIELDS_PER_PAGE)
async def confirm_action_delegate(ctx: wire.Context, msg: EosActionDelegate) -> None:
text = "Delegate"
fields = []
fields.append("Sender:")
fields.append(helpers.eos_name_to_string(msg.sender))
fields.append("Receiver:")
fields.append(helpers.eos_name_to_string(msg.receiver))
fields.append("CPU:")
fields.append(helpers.eos_asset_to_string(msg.cpu_quantity))
fields.append("NET:")
fields.append(helpers.eos_asset_to_string(msg.net_quantity))
if msg.transfer:
fields.append("Transfer: Yes")
fields.append("Receiver:")
fields.append(helpers.eos_name_to_string(msg.receiver))
else:
fields.append("Transfer: No")
await _require_confirm_paginated(ctx, text, fields, _FOUR_FIELDS_PER_PAGE)
async def confirm_action_sellram(ctx: wire.Context, msg: EosActionSellRam) -> None:
text = "Sell RAM"
fields = []
fields.append("Receiver:")
fields.append(helpers.eos_name_to_string(msg.account))
fields.append("Bytes:")
fields.append(str(msg.bytes))
await _require_confirm_paginated(ctx, text, fields, _TWO_FIELDS_PER_PAGE)
async def confirm_action_undelegate(
ctx: wire.Context, msg: EosActionUndelegate
) -> None:
text = "Undelegate"
fields = []
fields.append("Sender:")
fields.append(helpers.eos_name_to_string(msg.sender))
fields.append("Receiver:")
fields.append(helpers.eos_name_to_string(msg.receiver))
fields.append("CPU:")
fields.append(helpers.eos_asset_to_string(msg.cpu_quantity))
fields.append("NET:")
fields.append(helpers.eos_asset_to_string(msg.net_quantity))
await _require_confirm_paginated(ctx, text, fields, _FOUR_FIELDS_PER_PAGE)
async def confirm_action_refund(ctx: wire.Context, msg: EosActionRefund) -> None:
text = Text("Refund", ui.ICON_CONFIRM, icon_color=ui.GREEN)
text.normal("Owner:")
text.normal(helpers.eos_name_to_string(msg.owner))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
async def confirm_action_voteproducer(
ctx: wire.Context, msg: EosActionVoteProducer
) -> None:
if msg.proxy and not msg.producers:
# PROXY
text = Text("Vote for proxy", ui.ICON_CONFIRM, icon_color=ui.GREEN)
text.normal("Voter:")
text.normal(helpers.eos_name_to_string(msg.voter))
text.normal("Proxy:")
text.normal(helpers.eos_name_to_string(msg.proxy))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
elif msg.producers:
# PRODUCERS
text = "Vote for producers"
fields = [
"{:2d}. {}".format(wi + 1, helpers.eos_name_to_string(producer))
for wi, producer in enumerate(msg.producers)
]
await _require_confirm_paginated(ctx, text, fields, _FIVE_FIELDS_PER_PAGE)
else:
# Cancel vote
text = Text("Cancel vote", ui.ICON_CONFIRM, icon_color=ui.GREEN)
text.normal("Voter:")
text.normal(helpers.eos_name_to_string(msg.voter))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
async def confirm_action_transfer(
ctx: wire.Context, msg: EosActionTransfer, account: str
) -> None:
text = "Transfer"
fields = []
fields.append("From:")
fields.append(helpers.eos_name_to_string(msg.sender))
fields.append("To:")
fields.append(helpers.eos_name_to_string(msg.receiver))
fields.append("Amount:")
fields.append(helpers.eos_asset_to_string(msg.quantity))
fields.append("Contract:")
fields.append(account)
if msg.memo is not None:
fields.append("Memo:")
fields.extend(split_data(msg.memo[:512]))
await _require_confirm_paginated(ctx, text, fields, _FOUR_FIELDS_PER_PAGE)
async def confirm_action_updateauth(
ctx: wire.Context, msg: EosActionUpdateAuth
) -> None:
text = "Update Auth"
fields = []
fields.append("Account:")
fields.append(helpers.eos_name_to_string(msg.account))
fields.append("Permission:")
fields.append(helpers.eos_name_to_string(msg.permission))
fields.append("Parent:")
fields.append(helpers.eos_name_to_string(msg.parent))
fields.extend(authorization_fields(msg.auth))
await _require_confirm_paginated(ctx, text, fields, _FOUR_FIELDS_PER_PAGE)
async def confirm_action_deleteauth(
ctx: wire.Context, msg: EosActionDeleteAuth
) -> None:
text = Text("Delete auth", ui.ICON_CONFIRM, icon_color=ui.GREEN)
text.normal("Account:")
text.normal(helpers.eos_name_to_string(msg.account))
text.normal("Permission:")
text.normal(helpers.eos_name_to_string(msg.permission))
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
async def confirm_action_linkauth(ctx: wire.Context, msg: EosActionLinkAuth) -> None:
text = "Link Auth"
fields = []
fields.append("Account:")
fields.append(helpers.eos_name_to_string(msg.account))
fields.append("Code:")
fields.append(helpers.eos_name_to_string(msg.code))
fields.append("Type:")
fields.append(helpers.eos_name_to_string(msg.type))
fields.append("Requirement:")
fields.append(helpers.eos_name_to_string(msg.requirement))
await _require_confirm_paginated(ctx, text, fields, _FOUR_FIELDS_PER_PAGE)
async def confirm_action_unlinkauth(
ctx: wire.Context, msg: EosActionUnlinkAuth
) -> None:
text = "Unlink Auth"
fields = []
fields.append("Account:")
fields.append(helpers.eos_name_to_string(msg.account))
fields.append("Code:")
fields.append(helpers.eos_name_to_string(msg.code))
fields.append("Type:")
fields.append(helpers.eos_name_to_string(msg.type))
await _require_confirm_paginated(ctx, text, fields, _FOUR_FIELDS_PER_PAGE)
async def confirm_action_newaccount(
ctx: wire.Context, msg: EosActionNewAccount
) -> None:
text = "New Account"
fields = []
fields.append("Creator:")
fields.append(helpers.eos_name_to_string(msg.creator))
fields.append("Name:")
fields.append(helpers.eos_name_to_string(msg.name))
fields.extend(authorization_fields(msg.owner))
fields.extend(authorization_fields(msg.active))
await _require_confirm_paginated(ctx, text, fields, _FOUR_FIELDS_PER_PAGE)
async def confirm_action_unknown(
ctx: wire.Context, action: EosActionCommon, checksum: bytes
) -> None:
text = "Arbitrary data"
fields = []
fields.append("Contract:")
fields.append(helpers.eos_name_to_string(action.account))
fields.append("Action Name:")
fields.append(helpers.eos_name_to_string(action.name))
fields.append("Checksum: ")
fields.extend(split_data(hexlify(checksum).decode("ascii")))
await _require_confirm_paginated(ctx, text, fields, _FIVE_FIELDS_PER_PAGE)
def authorization_fields(auth: EosAuthorization) -> list[str]:
fields = []
fields.append("Threshold:")
fields.append(str(auth.threshold))
for i, key in enumerate(auth.keys):
_key = helpers.public_key_to_wif(bytes(key.key))
_weight = str(key.weight)
header = "Key #{}:".format(i + 1)
w_header = "Key #{} Weight:".format(i + 1)
fields.append(header)
fields += split_data(_key)
fields.append(w_header)
fields.append(_weight)
for i, account in enumerate(auth.accounts):
_account = helpers.eos_name_to_string(account.account.actor)
_permission = helpers.eos_name_to_string(account.account.permission)
a_header = "Account #{}:".format(i + 1)
p_header = "Acc Permission #{}:".format(i + 1)
w_header = "Account #{} weight:".format(i + 1)
fields.append(a_header)
fields.append(_account)
fields.append(p_header)
fields.append(_permission)
fields.append(w_header)
fields.append(str(account.weight))
for i, wait in enumerate(auth.waits):
_wait = str(wait.wait_sec)
_weight = str(wait.weight)
header = "Delay #{}".format(i + 1)
w_header = "Delay #{} weight:".format(i + 1)
fields.append(header)
fields.append("{} sec".format(_wait))
fields.append(w_header)
fields.append(_weight)
return fields
def split_data(data: str) -> list[str]:
lines = []
while data:
lines.append("{} ".format(data[:_LINE_LENGTH]))
data = data[_LINE_LENGTH:]
return lines