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:
parent
44ce832163
commit
8d75fad50c
@ -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:
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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'
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user