1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-15 20:19:23 +00:00

stellar: memo confirms

This commit is contained in:
Tomas Susanka 2018-05-29 15:29:22 +02:00
parent 44ce832163
commit 8d75fad50c
4 changed files with 67 additions and 18 deletions

View File

@ -41,6 +41,12 @@ AMOUNT_DIVISIBILITY = const(7)
NETWORK_PASSPHRASE_PUBLIC = 'Public Global Stellar Network ; September 2015'
NETWORK_PASSPHRASE_TESTNET = 'Test SDF Network ; September 2015'
MEMO_TYPE_NONE = 0
MEMO_TYPE_TEXT = 1
MEMO_TYPE_ID = 2
MEMO_TYPE_HASH = 3
MEMO_TYPE_RETURN = 4
def get_op_code(msg) -> int:
if msg.__qualname__ not in op_codes:

View File

@ -9,6 +9,13 @@ class UiConfirmInit:
self.network = network
class UiConfirmMemo:
def __init__(self, memo_type: int, memo_text: str):
self.memo_type = memo_type
self.memo_text = memo_text
class UiConfirmFinal:
def __init__(self, fee: int, num_operations: int):
@ -20,6 +27,10 @@ def confirm_init(pubkey: bytes, network: str):
return (yield UiConfirmInit(pubkey, network))
def confirm_memo(memo_type: int, memo_text: str):
return (yield UiConfirmMemo(memo_type, memo_text))
def confirm_final(fee: int, num_operations: int):
return (yield UiConfirmFinal(fee, num_operations))

View File

@ -1,7 +1,5 @@
from apps.common.confirm import *
from apps.stellar.consts import AMOUNT_DIVISIBILITY
from apps.stellar.consts import NETWORK_PASSPHRASE_PUBLIC
from apps.stellar.consts import NETWORK_PASSPHRASE_TESTNET
from apps.stellar import consts
from apps.stellar import helpers
from trezor import ui
from trezor.messages import ButtonRequestType
@ -24,6 +22,26 @@ async def require_confirm_init(ctx, pubkey: bytes, network_passphrase: str):
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
async def require_confirm_memo(ctx, memo_type: int, memo_text: str):
if memo_type == consts.MEMO_TYPE_TEXT:
title = 'Memo (TEXT)'
elif memo_type == consts.MEMO_TYPE_ID:
title = 'Memo (ID)'
elif memo_type == consts.MEMO_TYPE_HASH:
title = 'Memo (HASH)'
elif memo_type == consts.MEMO_TYPE_RETURN:
title = 'Memo (RETURN)'
else: # MEMO_TYPE_NONE
title = 'No memo set!'
# todo ugly
memo_text = 'Important: Many exchanges require a memo when depositing'
content = Text('Confirm memo', ui.ICON_CONFIRM,
ui.BOLD, title,
ui.MONO, *split(memo_text),
icon_color=ui.GREEN)
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
async def require_confirm_final(ctx, fee: int, num_operations: int):
op_str = str(num_operations) + ' operation'
if num_operations > 1:
@ -31,7 +49,7 @@ async def require_confirm_final(ctx, fee: int, num_operations: int):
content = Text('Final confirm', ui.ICON_SEND,
ui.NORMAL, 'Sign this transaction',
ui.NORMAL, 'made up of ' + op_str,
ui.BOLD, 'and pay ' + format_amount(fee, AMOUNT_DIVISIBILITY) + ' XLM',
ui.BOLD, 'and pay ' + format_amount(fee, consts.AMOUNT_DIVISIBILITY) + ' XLM',
ui.NORMAL, 'for fee?',
icon_color=ui.GREEN)
# we use SignTx, not ConfirmOutput, for compatibility with T1
@ -40,16 +58,16 @@ async def require_confirm_final(ctx, fee: int, num_operations: int):
def format_address(pubkey: bytes) -> str:
address = helpers.address_from_public_key(pubkey)
return split_address(address)
return split(address)
def split_address(address):
return chunks(address, 17)
def split(text):
return chunks(text, 17)
def get_network_warning(network_passphrase: str):
if network_passphrase == NETWORK_PASSPHRASE_PUBLIC:
if network_passphrase == consts.NETWORK_PASSPHRASE_PUBLIC:
return None
if network_passphrase == NETWORK_PASSPHRASE_TESTNET:
if network_passphrase == consts.NETWORK_PASSPHRASE_TESTNET:
return 'testnet network'
return 'private network'

View File

@ -1,14 +1,15 @@
from apps.common import seed
from apps.stellar.writers import *
from apps.stellar.operations import serialize_op
from apps.stellar.consts import op_wire_types
from apps.stellar.layout import require_confirm_init, require_confirm_final
from apps.stellar import layout
from apps.stellar import consts
from apps.stellar import helpers
from trezor.messages.StellarSignTx import StellarSignTx
from trezor.messages.StellarTxOpRequest import StellarTxOpRequest
from trezor.messages.StellarSignedTx import StellarSignedTx
from trezor.crypto.curve import ed25519
from trezor.crypto.hashlib import sha256
from ubinascii import hexlify
STELLAR_CURVE = 'ed25519'
TX_TYPE = bytearray('\x00\x00\x00\x02')
@ -20,13 +21,15 @@ async def sign_tx_loop(ctx, msg: StellarSignTx):
while True:
req = signer.send(res)
if isinstance(req, StellarTxOpRequest):
res = await ctx.call(req, *op_wire_types)
res = await ctx.call(req, *consts.op_wire_types)
elif isinstance(req, StellarSignedTx):
break
elif isinstance(req, helpers.UiConfirmInit):
res = await require_confirm_init(ctx, req.pubkey, req.network)
res = await layout.require_confirm_init(ctx, req.pubkey, req.network)
elif isinstance(req, helpers.UiConfirmMemo):
res = await layout.require_confirm_memo(ctx, req.memo_type, req.memo_text)
elif isinstance(req, helpers.UiConfirmFinal):
res = await require_confirm_final(ctx, req.fee, req.num_operations)
res = await layout.require_confirm_final(ctx, req.fee, req.num_operations)
else:
raise TypeError('Stellar: Invalid signing instruction')
return req
@ -53,6 +56,9 @@ async def sign_tx(ctx, msg):
if msg.source_account != pubkey:
raise ValueError('Stellar: source account does not match address_n')
# confirm init
await helpers.confirm_init(pubkey, msg.network_passphrase)
write_uint32(w, msg.fee)
write_uint64(w, msg.sequence_number)
@ -66,17 +72,26 @@ async def sign_tx(ctx, msg):
write_bool(w, False)
write_uint32(w, msg.memo_type)
if msg.memo_type == 1: # nothing is needed for memo_type = 0
if msg.memo_type == consts.MEMO_TYPE_NONE:
# nothing is serialized
memo_confirm_text = ''
elif msg.memo_type == consts.MEMO_TYPE_TEXT:
# Text: 4 bytes (size) + up to 28 bytes
if len(msg.memo_text) > 28:
raise ValueError('Stellar: max length of a memo text is 28 bytes')
write_string(w, msg.memo_text)
elif msg.memo_type == 2:
memo_confirm_text = msg.memo_text
elif msg.memo_type == consts.MEMO_TYPE_ID:
# ID: 64 bit unsigned integer
write_uint64(w, msg.memo_id)
elif msg.memo_type in [3, 4]:
memo_confirm_text = str(msg.memo_id)
elif msg.memo_type in [consts.MEMO_TYPE_HASH, consts.MEMO_TYPE_RETURN]:
# Hash/Return: 32 byte hash
write_bytes(w, bytearray(msg.memo_hash))
memo_confirm_text = hexlify(msg.memo_hash).decode()
else:
raise ValueError('Stellar invalid memo type')
await helpers.confirm_memo(msg.memo_type, memo_confirm_text)
write_uint32(w, msg.num_operations)
for i in range(msg.num_operations):
@ -87,7 +102,6 @@ async def sign_tx(ctx, msg):
write_uint32(w, 0)
# confirms
await helpers.confirm_init(pubkey, msg.network_passphrase)
await helpers.confirm_final(msg.fee, msg.num_operations)
# sign