mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-16 19:38:09 +00:00
stellar: operations layout
This commit is contained in:
parent
a26aaec953
commit
2af33a6893
@ -1,7 +1,11 @@
|
|||||||
from trezor.messages import wire_types
|
from trezor.messages import wire_types
|
||||||
from micropython import const
|
from micropython import const
|
||||||
|
|
||||||
# source: https://github.com/stellar/go/blob/master/xdr/Stellar-transaction.x
|
STELLAR_CURVE = 'ed25519'
|
||||||
|
TX_TYPE = bytearray('\x00\x00\x00\x02')
|
||||||
|
|
||||||
|
# source: https://github.com/stellar/go/blob/3d2c1defe73dbfed00146ebe0e8d7e07ce4bb1b6/xdr/Stellar-transaction.x#L16
|
||||||
|
# Inflation not supported see https://github.com/trezor/trezor-core/issues/202#issuecomment-393342089
|
||||||
op_codes = {
|
op_codes = {
|
||||||
'StellarAccountMergeOp': const(8),
|
'StellarAccountMergeOp': const(8),
|
||||||
'StellarAllowTrustOp': const(7),
|
'StellarAllowTrustOp': const(7),
|
||||||
@ -30,23 +34,36 @@ op_wire_types = [
|
|||||||
wire_types.StellarSetOptionsOp,
|
wire_types.StellarSetOptionsOp,
|
||||||
]
|
]
|
||||||
|
|
||||||
ASSET_TYPE_CREDIT_ALPHANUM4 = const(1)
|
ASSET_TYPE_NATIVE = const(0)
|
||||||
ASSET_TYPE_CREDIT_ALPHANUM12 = const(2)
|
ASSET_TYPE_ALPHANUM4 = const(1)
|
||||||
|
ASSET_TYPE_ALPHANUM12 = const(2)
|
||||||
|
|
||||||
# https://www.stellar.org/developers/guides/concepts/accounts.html#balance
|
# https://www.stellar.org/developers/guides/concepts/accounts.html#balance
|
||||||
# https://github.com/stellar/go/blob/master/amount/main.go
|
# https://github.com/stellar/go/blob/3d2c1defe73dbfed00146ebe0e8d7e07ce4bb1b6/amount/main.go#L23
|
||||||
AMOUNT_DIVISIBILITY = const(7)
|
AMOUNT_DIVISIBILITY = const(7)
|
||||||
|
|
||||||
# https://github.com/stellar/go/blob/master/network/main.go
|
# https://github.com/stellar/go/blob/master/network/main.go
|
||||||
NETWORK_PASSPHRASE_PUBLIC = 'Public Global Stellar Network ; September 2015'
|
NETWORK_PASSPHRASE_PUBLIC = 'Public Global Stellar Network ; September 2015'
|
||||||
NETWORK_PASSPHRASE_TESTNET = 'Test SDF Network ; September 2015'
|
NETWORK_PASSPHRASE_TESTNET = 'Test SDF Network ; September 2015'
|
||||||
|
|
||||||
|
# https://www.stellar.org/developers/guides/concepts/accounts.html#flags
|
||||||
|
FLAG_AUTH_REQUIRED = const(1)
|
||||||
|
FLAG_AUTH_REVOCABLE = const(2)
|
||||||
|
FLAG_AUTH_IMMUTABLE = const(4)
|
||||||
|
FLAGS_MAX_SIZE = 7
|
||||||
|
|
||||||
|
# https://github.com/stellar/go/blob/e0ffe19f58879d3c31e2976b97a5bf10e13a337b/xdr/Stellar-transaction.x#L275
|
||||||
MEMO_TYPE_NONE = 0
|
MEMO_TYPE_NONE = 0
|
||||||
MEMO_TYPE_TEXT = 1
|
MEMO_TYPE_TEXT = 1
|
||||||
MEMO_TYPE_ID = 2
|
MEMO_TYPE_ID = 2
|
||||||
MEMO_TYPE_HASH = 3
|
MEMO_TYPE_HASH = 3
|
||||||
MEMO_TYPE_RETURN = 4
|
MEMO_TYPE_RETURN = 4
|
||||||
|
|
||||||
|
# https://github.com/stellar/go/blob/3d2c1defe73dbfed00146ebe0e8d7e07ce4bb1b6/xdr/xdr_generated.go#L156
|
||||||
|
SIGN_TYPE_ACCOUNT = const(0)
|
||||||
|
SIGN_TYPE_PRE_AUTH = const(1)
|
||||||
|
SIGN_TYPE_HASH = const(2)
|
||||||
|
|
||||||
|
|
||||||
def get_op_code(msg) -> int:
|
def get_op_code(msg) -> int:
|
||||||
if msg.__qualname__ not in op_codes:
|
if msg.__qualname__ not in op_codes:
|
||||||
|
@ -4,13 +4,13 @@ from apps.stellar import helpers
|
|||||||
from trezor import ui
|
from trezor import ui
|
||||||
from trezor.messages import ButtonRequestType
|
from trezor.messages import ButtonRequestType
|
||||||
from trezor.ui.text import Text
|
from trezor.ui.text import Text
|
||||||
from trezor.utils import chunks, format_amount
|
from trezor import utils
|
||||||
|
|
||||||
|
|
||||||
async def require_confirm_init(ctx, pubkey: bytes, network_passphrase: str):
|
async def require_confirm_init(ctx, pubkey: bytes, network_passphrase: str):
|
||||||
content = Text('Confirm Stellar', ui.ICON_SEND,
|
content = Text('Confirm Stellar', ui.ICON_SEND,
|
||||||
ui.NORMAL, 'Initialize singing with',
|
ui.NORMAL, 'Initialize singing with',
|
||||||
ui.MONO, *format_address(pubkey),
|
ui.MONO, *split(format_address(pubkey)),
|
||||||
icon_color=ui.GREEN)
|
icon_color=ui.GREEN)
|
||||||
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
network = get_network_warning(network_passphrase)
|
network = get_network_warning(network_passphrase)
|
||||||
@ -32,8 +32,7 @@ async def require_confirm_memo(ctx, memo_type: int, memo_text: str):
|
|||||||
elif memo_type == consts.MEMO_TYPE_RETURN:
|
elif memo_type == consts.MEMO_TYPE_RETURN:
|
||||||
title = 'Memo (RETURN)'
|
title = 'Memo (RETURN)'
|
||||||
else: # MEMO_TYPE_NONE
|
else: # MEMO_TYPE_NONE
|
||||||
title = 'No memo set!'
|
title = 'No memo set!' # todo format this as ui.NORMAL not MONO
|
||||||
# todo ugly
|
|
||||||
memo_text = 'Important: Many exchanges require a memo when depositing'
|
memo_text = 'Important: Many exchanges require a memo when depositing'
|
||||||
content = Text('Confirm memo', ui.ICON_CONFIRM,
|
content = Text('Confirm memo', ui.ICON_CONFIRM,
|
||||||
ui.BOLD, title,
|
ui.BOLD, title,
|
||||||
@ -49,20 +48,40 @@ async def require_confirm_final(ctx, fee: int, num_operations: int):
|
|||||||
content = Text('Final confirm', ui.ICON_SEND,
|
content = Text('Final confirm', ui.ICON_SEND,
|
||||||
ui.NORMAL, 'Sign this transaction',
|
ui.NORMAL, 'Sign this transaction',
|
||||||
ui.NORMAL, 'made up of ' + op_str,
|
ui.NORMAL, 'made up of ' + op_str,
|
||||||
ui.BOLD, 'and pay ' + format_amount(fee, consts.AMOUNT_DIVISIBILITY) + ' XLM',
|
ui.BOLD, 'and pay ' + format_amount(fee),
|
||||||
ui.NORMAL, 'for fee?',
|
ui.NORMAL, 'for fee?',
|
||||||
icon_color=ui.GREEN)
|
icon_color=ui.GREEN)
|
||||||
# we use SignTx, not ConfirmOutput, for compatibility with T1
|
# we use SignTx, not ConfirmOutput, for compatibility with T1
|
||||||
await require_hold_to_confirm(ctx, content, ButtonRequestType.SignTx)
|
await require_hold_to_confirm(ctx, content, ButtonRequestType.SignTx)
|
||||||
|
|
||||||
|
|
||||||
|
def format_amount(amount: int, ticker=True) -> str:
|
||||||
|
t = ''
|
||||||
|
if ticker:
|
||||||
|
t = ' XLM'
|
||||||
|
return utils.format_amount(amount, consts.AMOUNT_DIVISIBILITY) + t
|
||||||
|
|
||||||
|
|
||||||
def format_address(pubkey: bytes) -> str:
|
def format_address(pubkey: bytes) -> str:
|
||||||
address = helpers.address_from_public_key(pubkey)
|
return helpers.address_from_public_key(pubkey)
|
||||||
return split(address)
|
|
||||||
|
|
||||||
|
|
||||||
def split(text):
|
def split(text):
|
||||||
return chunks(text, 17)
|
return utils.chunks(text, 17)
|
||||||
|
|
||||||
|
|
||||||
|
# todo merge with nem
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
# todo merge with nem
|
||||||
|
def trim_to_rows(payload: str, rows: int=1) -> str:
|
||||||
|
return trim(payload, rows * 17)
|
||||||
|
|
||||||
|
|
||||||
def get_network_warning(network_passphrase: str):
|
def get_network_warning(network_passphrase: str):
|
||||||
|
@ -1,192 +0,0 @@
|
|||||||
from trezor.messages.StellarAccountMergeOp import StellarAccountMergeOp
|
|
||||||
from trezor.messages.StellarAssetType import StellarAssetType
|
|
||||||
from trezor.messages.StellarAllowTrustOp import StellarAllowTrustOp
|
|
||||||
from trezor.messages.StellarBumpSequenceOp import StellarBumpSequenceOp
|
|
||||||
from trezor.messages.StellarChangeTrustOp import StellarChangeTrustOp
|
|
||||||
from trezor.messages.StellarCreateAccountOp import StellarCreateAccountOp
|
|
||||||
from trezor.messages.StellarCreatePassiveOfferOp import StellarCreatePassiveOfferOp
|
|
||||||
from trezor.messages.StellarManageDataOp import StellarManageDataOp
|
|
||||||
from trezor.messages.StellarManageOfferOp import StellarManageOfferOp
|
|
||||||
from trezor.messages.StellarPathPaymentOp import StellarPathPaymentOp
|
|
||||||
from trezor.messages.StellarPaymentOp import StellarPaymentOp
|
|
||||||
from trezor.messages.StellarSetOptionsOp import StellarSetOptionsOp
|
|
||||||
from apps.stellar.consts import *
|
|
||||||
from apps.stellar.writers import *
|
|
||||||
|
|
||||||
# todo layout
|
|
||||||
|
|
||||||
|
|
||||||
def serialize_op(w, op):
|
|
||||||
_serialize_account(w, op.source_account)
|
|
||||||
write_uint32(w, get_op_code(op))
|
|
||||||
if isinstance(op, StellarAccountMergeOp):
|
|
||||||
serialize_account_merge_op(w, op)
|
|
||||||
elif isinstance(op, StellarAllowTrustOp):
|
|
||||||
serialize_allow_trust_op(w, op)
|
|
||||||
elif isinstance(op, StellarBumpSequenceOp):
|
|
||||||
serialize_bump_sequence_op(w, op)
|
|
||||||
elif isinstance(op, StellarChangeTrustOp):
|
|
||||||
serialize_change_trust_op(w, op)
|
|
||||||
elif isinstance(op, StellarCreateAccountOp):
|
|
||||||
serialize_create_account_op(w, op)
|
|
||||||
elif isinstance(op, StellarCreatePassiveOfferOp):
|
|
||||||
serialize_create_passive_offer_op(w, op)
|
|
||||||
elif isinstance(op, StellarManageDataOp):
|
|
||||||
serialize_manage_data_op(w, op)
|
|
||||||
elif isinstance(op, StellarManageOfferOp):
|
|
||||||
serialize_manage_offer_op(w, op)
|
|
||||||
elif isinstance(op, StellarPathPaymentOp):
|
|
||||||
serialize_path_payment_op(w, op)
|
|
||||||
elif isinstance(op, StellarPaymentOp):
|
|
||||||
serialize_payment_op(w, op)
|
|
||||||
elif isinstance(op, StellarSetOptionsOp):
|
|
||||||
serialize_set_options_op(w, op)
|
|
||||||
else:
|
|
||||||
raise ValueError('Stellar: unknown operation')
|
|
||||||
|
|
||||||
|
|
||||||
def serialize_account_merge_op(w, msg: StellarAccountMergeOp):
|
|
||||||
write_pubkey(w, msg.destination_account)
|
|
||||||
|
|
||||||
|
|
||||||
def serialize_allow_trust_op(w, msg: StellarAllowTrustOp):
|
|
||||||
# trustor account (the account being allowed to access the asset)
|
|
||||||
write_pubkey(w, msg.trusted_account)
|
|
||||||
write_uint32(w, msg.asset_type)
|
|
||||||
_serialize_asset_code(w, msg.asset_type, msg.asset_code)
|
|
||||||
|
|
||||||
write_bool(w, msg.is_authorized)
|
|
||||||
|
|
||||||
|
|
||||||
def serialize_bump_sequence_op(w, msg: StellarBumpSequenceOp):
|
|
||||||
write_uint64(w, msg.bump_to)
|
|
||||||
|
|
||||||
|
|
||||||
def serialize_change_trust_op(w, msg: StellarChangeTrustOp):
|
|
||||||
_serialize_asset(w, msg.asset)
|
|
||||||
write_uint64(w, msg.limit)
|
|
||||||
|
|
||||||
|
|
||||||
def serialize_create_account_op(w, msg: StellarCreateAccountOp):
|
|
||||||
write_pubkey(w, msg.new_account)
|
|
||||||
write_uint64(w, msg.starting_balance)
|
|
||||||
|
|
||||||
|
|
||||||
def serialize_create_passive_offer_op(w, msg: StellarCreatePassiveOfferOp):
|
|
||||||
_serialize_asset(w, msg.selling_asset)
|
|
||||||
_serialize_asset(w, msg.buying_asset)
|
|
||||||
write_uint64(w, msg.amount)
|
|
||||||
write_uint32(w, msg.price_n)
|
|
||||||
write_uint32(w, msg.price_d)
|
|
||||||
|
|
||||||
|
|
||||||
def serialize_manage_data_op(w, msg: StellarManageDataOp):
|
|
||||||
if len(msg.key) > 64:
|
|
||||||
raise ValueError('Stellar: max length of a key is 64 bytes')
|
|
||||||
write_string(w, msg.key)
|
|
||||||
write_bool(w, bool(msg.value))
|
|
||||||
if msg.value:
|
|
||||||
write_uint32(w, len(msg.value))
|
|
||||||
write_bytes(w, msg.value)
|
|
||||||
|
|
||||||
|
|
||||||
def serialize_manage_offer_op(w, msg: StellarManageOfferOp):
|
|
||||||
_serialize_asset(w, msg.selling_asset)
|
|
||||||
_serialize_asset(w, msg.buying_asset)
|
|
||||||
write_uint64(w, msg.amount) # amount to sell
|
|
||||||
write_uint32(w, msg.price_n) # numerator
|
|
||||||
write_uint32(w, msg.price_d) # denominator
|
|
||||||
write_uint64(w, msg.offer_id)
|
|
||||||
|
|
||||||
|
|
||||||
def serialize_path_payment_op(w, msg: StellarPathPaymentOp):
|
|
||||||
_serialize_asset(w, msg.send_asset)
|
|
||||||
write_uint64(w, msg.send_max)
|
|
||||||
write_pubkey(w, msg.destination_account)
|
|
||||||
|
|
||||||
_serialize_asset(w, msg.destination_asset)
|
|
||||||
write_uint64(w, msg.destination_amount)
|
|
||||||
write_uint32(w, len(msg.paths))
|
|
||||||
for p in msg.paths:
|
|
||||||
_serialize_asset(w, p)
|
|
||||||
|
|
||||||
|
|
||||||
def serialize_payment_op(w, msg: StellarPaymentOp):
|
|
||||||
write_pubkey(w, msg.destination_account)
|
|
||||||
_serialize_asset(w, msg.asset)
|
|
||||||
write_uint64(w, msg.amount)
|
|
||||||
|
|
||||||
|
|
||||||
def serialize_set_options_op(w, msg: StellarSetOptionsOp):
|
|
||||||
# inflation destination
|
|
||||||
write_bool(w, bool(msg.inflation_destination_account))
|
|
||||||
if msg.inflation_destination_account:
|
|
||||||
write_pubkey(w, msg.inflation_destination_account)
|
|
||||||
|
|
||||||
# clear flags
|
|
||||||
write_bool(w, bool(msg.clear_flags))
|
|
||||||
if msg.clear_flags:
|
|
||||||
write_uint32(w, msg.clear_flags)
|
|
||||||
|
|
||||||
# set flags
|
|
||||||
write_bool(w, bool(msg.set_flags))
|
|
||||||
if msg.set_flags:
|
|
||||||
write_uint32(w, msg.set_flags)
|
|
||||||
|
|
||||||
# account thresholds
|
|
||||||
write_bool(w, bool(msg.master_weight))
|
|
||||||
if msg.master_weight:
|
|
||||||
write_uint32(w, msg.master_weight)
|
|
||||||
|
|
||||||
write_bool(w, bool(msg.low_threshold))
|
|
||||||
if msg.low_threshold:
|
|
||||||
write_uint32(w, msg.low_threshold)
|
|
||||||
|
|
||||||
write_bool(w, bool(msg.medium_threshold))
|
|
||||||
if msg.medium_threshold:
|
|
||||||
write_uint32(w, msg.medium_threshold)
|
|
||||||
|
|
||||||
write_bool(w, bool(msg.high_threshold))
|
|
||||||
if msg.high_threshold:
|
|
||||||
write_uint32(w, msg.high_threshold)
|
|
||||||
|
|
||||||
# home domain
|
|
||||||
write_bool(w, bool(msg.home_domain))
|
|
||||||
if msg.home_domain:
|
|
||||||
if len(msg.home_domain) > 32:
|
|
||||||
raise ValueError('Stellar: max length of a home domain is 32 bytes')
|
|
||||||
write_string(w, msg.home_domain)
|
|
||||||
|
|
||||||
# signer
|
|
||||||
write_bool(w, bool(msg.signer_type))
|
|
||||||
if msg.signer_type:
|
|
||||||
# signer type
|
|
||||||
write_uint32(w, msg.signer_type)
|
|
||||||
write_bytes(w, msg.signer_key)
|
|
||||||
write_uint32(w, msg.signer_weight)
|
|
||||||
|
|
||||||
|
|
||||||
def _serialize_account(w, source_account: bytes):
|
|
||||||
if source_account is None:
|
|
||||||
write_bool(w, False)
|
|
||||||
return
|
|
||||||
|
|
||||||
write_pubkey(w, source_account)
|
|
||||||
|
|
||||||
|
|
||||||
def _serialize_asset_code(w, asset_type: int, asset_code: str):
|
|
||||||
code = bytearray(asset_code)
|
|
||||||
if asset_type == ASSET_TYPE_CREDIT_ALPHANUM4:
|
|
||||||
# pad with zeros to 4 chars
|
|
||||||
write_bytes(w, code + bytearray([0] * (4 - len(code))))
|
|
||||||
elif asset_type == ASSET_TYPE_CREDIT_ALPHANUM12:
|
|
||||||
# pad with zeros to 12 chars
|
|
||||||
write_bytes(w, code + bytearray([0] * (12 - len(code))))
|
|
||||||
else:
|
|
||||||
raise ValueError('Stellar: invalid asset type')
|
|
||||||
|
|
||||||
|
|
||||||
def _serialize_asset(w, asset: StellarAssetType):
|
|
||||||
write_uint32(w, asset.type)
|
|
||||||
_serialize_asset_code(w, asset.type, asset.code)
|
|
||||||
write_pubkey(w, asset.issuer)
|
|
44
src/apps/stellar/operations/__init__.py
Normal file
44
src/apps/stellar/operations/__init__.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
from apps.stellar.operations.serialize import *
|
||||||
|
from apps.stellar.operations.layout import *
|
||||||
|
|
||||||
|
|
||||||
|
async def operation(ctx, w, op):
|
||||||
|
if op.source_account:
|
||||||
|
await confirm_source_account(ctx, op.source_account)
|
||||||
|
serialize_account(w, op.source_account)
|
||||||
|
write_uint32(w, get_op_code(op))
|
||||||
|
if isinstance(op, StellarAccountMergeOp):
|
||||||
|
await confirm_account_merge_op(ctx, op)
|
||||||
|
serialize_account_merge_op(w, op)
|
||||||
|
elif isinstance(op, StellarAllowTrustOp):
|
||||||
|
await confirm_allow_trust_op(ctx, op)
|
||||||
|
serialize_allow_trust_op(w, op)
|
||||||
|
elif isinstance(op, StellarBumpSequenceOp):
|
||||||
|
await confirm_bump_sequence_op(ctx, op)
|
||||||
|
serialize_bump_sequence_op(w, op)
|
||||||
|
elif isinstance(op, StellarChangeTrustOp):
|
||||||
|
await confirm_change_trust_op(ctx, op)
|
||||||
|
serialize_change_trust_op(w, op)
|
||||||
|
elif isinstance(op, StellarCreateAccountOp):
|
||||||
|
await confirm_create_account_op(ctx, op)
|
||||||
|
serialize_create_account_op(w, op)
|
||||||
|
elif isinstance(op, StellarCreatePassiveOfferOp):
|
||||||
|
await confirm_create_passive_offer_op(ctx, op)
|
||||||
|
serialize_create_passive_offer_op(w, op)
|
||||||
|
elif isinstance(op, StellarManageDataOp):
|
||||||
|
await confirm_manage_data_op(ctx, op)
|
||||||
|
serialize_manage_data_op(w, op)
|
||||||
|
elif isinstance(op, StellarManageOfferOp):
|
||||||
|
await confirm_manage_offer_op(ctx, op)
|
||||||
|
serialize_manage_offer_op(w, op)
|
||||||
|
elif isinstance(op, StellarPathPaymentOp):
|
||||||
|
await confirm_path_payment_op(ctx, op)
|
||||||
|
serialize_path_payment_op(w, op)
|
||||||
|
elif isinstance(op, StellarPaymentOp):
|
||||||
|
await confirm_payment_op(ctx, op)
|
||||||
|
serialize_payment_op(w, op)
|
||||||
|
elif isinstance(op, StellarSetOptionsOp):
|
||||||
|
await confirm_set_options_op(ctx, op)
|
||||||
|
serialize_set_options_op(w, op)
|
||||||
|
else:
|
||||||
|
raise ValueError('Stellar: unknown operation')
|
267
src/apps/stellar/operations/layout.py
Normal file
267
src/apps/stellar/operations/layout.py
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
from apps.stellar.layout import *
|
||||||
|
from trezor.messages import ButtonRequestType
|
||||||
|
from trezor.ui.text import Text
|
||||||
|
|
||||||
|
from trezor.messages.StellarAccountMergeOp import StellarAccountMergeOp
|
||||||
|
from trezor.messages.StellarAssetType import StellarAssetType
|
||||||
|
from trezor.messages.StellarAllowTrustOp import StellarAllowTrustOp
|
||||||
|
from trezor.messages.StellarBumpSequenceOp import StellarBumpSequenceOp
|
||||||
|
from trezor.messages.StellarChangeTrustOp import StellarChangeTrustOp
|
||||||
|
from trezor.messages.StellarCreateAccountOp import StellarCreateAccountOp
|
||||||
|
from trezor.messages.StellarCreatePassiveOfferOp import StellarCreatePassiveOfferOp
|
||||||
|
from trezor.messages.StellarManageDataOp import StellarManageDataOp
|
||||||
|
from trezor.messages.StellarManageOfferOp import StellarManageOfferOp
|
||||||
|
from trezor.messages.StellarPathPaymentOp import StellarPathPaymentOp
|
||||||
|
from trezor.messages.StellarPaymentOp import StellarPaymentOp
|
||||||
|
from trezor.messages.StellarSetOptionsOp import StellarSetOptionsOp
|
||||||
|
from ubinascii import hexlify
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_source_account(ctx, source_account: bytes):
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, 'Source account:',
|
||||||
|
ui.MONO, *split(format_address(source_account)),
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_allow_trust_op(ctx, op: StellarAllowTrustOp):
|
||||||
|
if op.is_authorized:
|
||||||
|
text = 'Allow'
|
||||||
|
else:
|
||||||
|
text = 'Revoke'
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, text + ' Trust',
|
||||||
|
ui.NORMAL, "of '" + op.asset_code + "' by:",
|
||||||
|
ui.MONO, *split(trim_to_rows(format_address(op.trusted_account), 3)),
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_account_merge_op(ctx, op: StellarAccountMergeOp):
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, 'Account Merge',
|
||||||
|
ui.NORMAL, 'All XLM will be sent to:',
|
||||||
|
ui.MONO, *split(trim_to_rows(format_address(op.destination_account), 3)),
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_bump_sequence_op(ctx, op: StellarBumpSequenceOp):
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, 'Bump Sequence',
|
||||||
|
ui.NORMAL, 'Set sequence to',
|
||||||
|
ui.MONO, str(op.bump_to),
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_change_trust_op(ctx, op: StellarChangeTrustOp):
|
||||||
|
if op.limit == 0:
|
||||||
|
text = 'Delete'
|
||||||
|
else:
|
||||||
|
text = 'Add'
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, text + ' Trust',
|
||||||
|
ui.NORMAL, 'Asset: ' + op.asset.code,
|
||||||
|
ui.NORMAL, 'Amount: ' + format_amount(op.limit, ticker=False),
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
await confirm_asset_issuer(ctx, op.asset)
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_create_account_op(ctx, op: StellarCreateAccountOp):
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, 'Create Account',
|
||||||
|
ui.NORMAL, 'with ' + format_amount(op.starting_balance),
|
||||||
|
ui.MONO, *split(trim_to_rows(format_address(op.new_account), 3)),
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_create_passive_offer_op(ctx, op: StellarCreatePassiveOfferOp):
|
||||||
|
if op.amount == 0:
|
||||||
|
text = 'Delete Passive Offer'
|
||||||
|
else:
|
||||||
|
text = 'New Passive Offer'
|
||||||
|
await _confirm_offer(ctx, text, op)
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_manage_offer_op(ctx, op: StellarManageOfferOp):
|
||||||
|
if op.offer_id == 0:
|
||||||
|
text = 'New Offer'
|
||||||
|
else:
|
||||||
|
if op.amount == 0:
|
||||||
|
text = 'Delete'
|
||||||
|
else:
|
||||||
|
text = 'Update'
|
||||||
|
text += ' #' + str(op.offer_id)
|
||||||
|
await _confirm_offer(ctx, text, op)
|
||||||
|
|
||||||
|
|
||||||
|
# todo scale? this is inconsistent with T1 (op.amount should? use divisibility)
|
||||||
|
async def _confirm_offer(ctx, text, op):
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, text,
|
||||||
|
ui.NORMAL, 'Sell ' + str(op.amount) + ' ' + op.selling_asset.code,
|
||||||
|
ui.NORMAL, 'For ' + str(op.price_n / op.price_d),
|
||||||
|
ui.NORMAL, 'Per ' + format_asset_code(op.buying_asset),
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
await confirm_asset_issuer(ctx, op.selling_asset)
|
||||||
|
await confirm_asset_issuer(ctx, op.buying_asset)
|
||||||
|
|
||||||
|
|
||||||
|
# todo done
|
||||||
|
async def confirm_manage_data_op(ctx, op: StellarManageDataOp):
|
||||||
|
from trezor.crypto.hashlib import sha256
|
||||||
|
if op.value:
|
||||||
|
text = 'Set'
|
||||||
|
else:
|
||||||
|
text = 'Clear'
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, text + ' data value key',
|
||||||
|
ui.MONO, *split(op.key),
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
if op.value:
|
||||||
|
digest = sha256(op.value).digest()
|
||||||
|
digest_str = hexlify(digest).decode()
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, ' Value (SHA-256):',
|
||||||
|
ui.MONO, *split(digest_str),
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_path_payment_op(ctx, op: StellarPathPaymentOp):
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, 'Path Pay ' + format_amount(op.destination_amount, ticker=False),
|
||||||
|
ui.BOLD, format_asset_code(op.destination_asset) + ' to:',
|
||||||
|
ui.MONO, *split(trim_to_rows(format_address(op.destination_account), 3)),
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
await confirm_asset_issuer(ctx, op.destination_asset)
|
||||||
|
# confirm what the sender is using to pay
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.NORMAL, 'Pay using',
|
||||||
|
ui.BOLD, format_amount(op.send_max, ticker=False),
|
||||||
|
ui.BOLD, format_asset_code(op.send_asset),
|
||||||
|
ui.NORMAL, 'This amount is debited',
|
||||||
|
ui.NORMAL, 'from your account.',
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
await confirm_asset_issuer(ctx, op.send_asset)
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_payment_op(ctx, op: StellarPaymentOp):
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, 'Pay ' + format_amount(op.amount, ticker=False),
|
||||||
|
ui.BOLD, format_asset_code(op.asset) + ' to:',
|
||||||
|
ui.MONO, *split(trim_to_rows(format_address(op.destination_account), 3)),
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
await confirm_asset_issuer(ctx, op.asset)
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_set_options_op(ctx, op: StellarSetOptionsOp):
|
||||||
|
if op.inflation_destination_account:
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, 'Set Inflation Destination',
|
||||||
|
ui.MONO, *split(format_address(op.inflation_destination_account)),
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
if op.clear_flags:
|
||||||
|
text = _format_flags(op.clear_flags)
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, 'Clear Flags',
|
||||||
|
ui.MONO, *text,
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
if op.set_flags:
|
||||||
|
text = _format_flags(op.set_flags)
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, 'Set Flags',
|
||||||
|
ui.MONO, *text,
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
thresholds = _format_thresholds(op)
|
||||||
|
if thresholds:
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, 'Account Thresholds',
|
||||||
|
ui.MONO, *thresholds,
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
if op.home_domain:
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, 'Home Domain',
|
||||||
|
ui.MONO, *split(op.home_domain),
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
if op.signer_type is not None:
|
||||||
|
if op.signer_weight > 0:
|
||||||
|
text = 'Add Signer'
|
||||||
|
else:
|
||||||
|
text = 'Remove Signer'
|
||||||
|
if op.signer_type == consts.SIGN_TYPE_ACCOUNT:
|
||||||
|
text += ' (acc)'
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, text,
|
||||||
|
ui.MONO, *split(format_address(op.signer_key)),
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
elif op.signer_type in [consts.SIGN_TYPE_PRE_AUTH, consts.SIGN_TYPE_HASH]:
|
||||||
|
if op.signer_type == consts.SIGN_TYPE_PRE_AUTH:
|
||||||
|
text += ' (auth)'
|
||||||
|
else:
|
||||||
|
text += ' (hash)'
|
||||||
|
content = Text('Confirm operation', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, text,
|
||||||
|
ui.MONO, *split(hexlify(op.signer_key).decode()),
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
else:
|
||||||
|
raise ValueError('Stellar: invalid signer type')
|
||||||
|
|
||||||
|
|
||||||
|
def _format_thresholds(op: StellarSetOptionsOp) -> ():
|
||||||
|
text = ()
|
||||||
|
if op.master_weight is not None:
|
||||||
|
text += ('Master Weight: ' + str(op.master_weight), )
|
||||||
|
if op.low_threshold is not None:
|
||||||
|
text += ('Low: ' + str(op.low_threshold), )
|
||||||
|
if op.medium_threshold is not None:
|
||||||
|
text += ('Medium: ' + str(op.medium_threshold), )
|
||||||
|
if op.high_threshold is not None:
|
||||||
|
text += ('High: ' + str(op.high_threshold), )
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def _format_flags(flags: int) -> ():
|
||||||
|
if flags > consts.FLAGS_MAX_SIZE:
|
||||||
|
raise ValueError('Stellar: invalid')
|
||||||
|
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', )
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def format_asset_code(asset: StellarAssetType) -> str:
|
||||||
|
if asset is None or asset.type == consts.ASSET_TYPE_NATIVE:
|
||||||
|
return 'XLM (native)'
|
||||||
|
return asset.code
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_asset_issuer(ctx, asset: StellarAssetType):
|
||||||
|
if asset is None or asset.type == consts.ASSET_TYPE_NATIVE:
|
||||||
|
return
|
||||||
|
content = Text('Confirm issuer', ui.ICON_CONFIRM,
|
||||||
|
ui.BOLD, asset.code + ' issuer:',
|
||||||
|
ui.MONO, *split(format_address(asset.issuer)),
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
Loading…
Reference in New Issue
Block a user