stellar: refactoring

pull/25/head
Tomas Susanka 6 years ago
parent 2af33a6893
commit 501ea6bb2c

@ -9,3 +9,8 @@ REVIEWER = Jan Pochyla <jan.pochyla@satoshilabs.com>
-----
TODO
# Stellar transactions consist of sha256 of:
# - sha256(network passphrase)
# - 4-byte unsigned big-endian int type constant (2 for tx)
# - public key

@ -34,6 +34,7 @@ op_wire_types = [
wire_types.StellarSetOptionsOp,
]
# https://github.com/stellar/go/blob/e0ffe19f58879d3c31e2976b97a5bf10e13a337b/xdr/xdr_generated.go#L584
ASSET_TYPE_NATIVE = const(0)
ASSET_TYPE_ALPHANUM4 = const(1)
ASSET_TYPE_ALPHANUM12 = const(2)

@ -36,5 +36,5 @@ async def _show(ctx, address: str):
cancel_style=ui.BTN_KEY)
def _split_address(address: str):
def _split_address(address: str): # todo merge with NEM
return chunks(address, 17)

@ -1,4 +1,4 @@
from apps.common.confirm import *
from apps.common.confirm import require_confirm, require_hold_to_confirm
from apps.stellar import consts
from apps.stellar import helpers
from trezor import ui
@ -66,6 +66,7 @@ def format_address(pubkey: bytes) -> str:
return helpers.address_from_public_key(pubkey)
# todo merge with nem
def split(text):
return utils.chunks(text, 17)

@ -1,44 +1,46 @@
from apps.stellar.operations.serialize import *
from apps.stellar.operations.layout import *
from apps.stellar.operations import serialize
from apps.stellar.operations import layout
from apps.stellar import consts
from apps.stellar import writers
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)
await layout.confirm_source_account(ctx, op.source_account)
serialize.serialize_account(w, op.source_account)
writers.write_uint32(w, consts.get_op_code(op))
if isinstance(op, serialize.StellarAccountMergeOp):
await layout.confirm_account_merge_op(ctx, op)
serialize.serialize_account_merge_op(w, op)
elif isinstance(op, serialize.StellarAllowTrustOp):
await layout.confirm_allow_trust_op(ctx, op)
serialize.serialize_allow_trust_op(w, op)
elif isinstance(op, serialize.StellarBumpSequenceOp):
await layout.confirm_bump_sequence_op(ctx, op)
serialize.serialize_bump_sequence_op(w, op)
elif isinstance(op, serialize.StellarChangeTrustOp):
await layout.confirm_change_trust_op(ctx, op)
serialize.serialize_change_trust_op(w, op)
elif isinstance(op, serialize.StellarCreateAccountOp):
await layout.confirm_create_account_op(ctx, op)
serialize.serialize_create_account_op(w, op)
elif isinstance(op, serialize.StellarCreatePassiveOfferOp):
await layout.confirm_create_passive_offer_op(ctx, op)
serialize.serialize_create_passive_offer_op(w, op)
elif isinstance(op, serialize.StellarManageDataOp):
await layout.confirm_manage_data_op(ctx, op)
serialize.serialize_manage_data_op(w, op)
elif isinstance(op, serialize.StellarManageOfferOp):
await layout.confirm_manage_offer_op(ctx, op)
serialize.serialize_manage_offer_op(w, op)
elif isinstance(op, serialize.StellarPathPaymentOp):
await layout.confirm_path_payment_op(ctx, op)
serialize.serialize_path_payment_op(w, op)
elif isinstance(op, serialize.StellarPaymentOp):
await layout.confirm_payment_op(ctx, op)
serialize.serialize_payment_op(w, op)
elif isinstance(op, serialize.StellarSetOptionsOp):
await layout.confirm_set_options_op(ctx, op)
serialize.serialize_set_options_op(w, op)
else:
raise ValueError('Stellar: unknown operation')
raise ValueError('serialize.Stellar: unknown operation')

@ -1,7 +1,7 @@
from apps.stellar.layout import *
from apps.stellar.layout import split, format_address, format_amount, ui, trim_to_rows, require_confirm
from apps.stellar import consts
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
@ -27,12 +27,12 @@ async def confirm_source_account(ctx, source_account: bytes):
async def confirm_allow_trust_op(ctx, op: StellarAllowTrustOp):
if op.is_authorized:
text = 'Allow'
text = 'Allow Trust'
else:
text = 'Revoke'
text = 'Revoke Trust'
content = Text('Confirm operation', ui.ICON_CONFIRM,
ui.BOLD, text + ' Trust',
ui.NORMAL, "of '" + op.asset_code + "' by:",
ui.BOLD, text,
ui.NORMAL, 'of %s by:' % op.asset_code,
ui.MONO, *split(trim_to_rows(format_address(op.trusted_account), 3)),
icon_color=ui.GREEN)
@ -59,13 +59,13 @@ async def confirm_bump_sequence_op(ctx, op: StellarBumpSequenceOp):
async def confirm_change_trust_op(ctx, op: StellarChangeTrustOp):
if op.limit == 0:
text = 'Delete'
text = 'Delete Trust'
else:
text = 'Add'
text = 'Add Trust'
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),
ui.BOLD, text,
ui.NORMAL, 'Asset: %s' % op.asset.code,
ui.NORMAL, 'Amount: %s' % format_amount(op.limit, ticker=False),
icon_color=ui.GREEN)
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
await confirm_asset_issuer(ctx, op.asset)
@ -74,7 +74,7 @@ async def confirm_change_trust_op(ctx, op: StellarChangeTrustOp):
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.NORMAL, 'with %s' % 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)
@ -96,32 +96,30 @@ async def confirm_manage_offer_op(ctx, op: StellarManageOfferOp):
text = 'Delete'
else:
text = 'Update'
text += ' #' + str(op.offer_id)
text += ' #%d' % 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),
ui.NORMAL, 'Sell %s %s' % (format_amount(op.amount, ticker=False), op.selling_asset.code),
ui.NORMAL, 'For %f' % (op.price_n / op.price_d),
ui.NORMAL, 'Per %s' % 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'
title = 'Set'
else:
text = 'Clear'
title = 'Clear'
content = Text('Confirm operation', ui.ICON_CONFIRM,
ui.BOLD, text + ' data value key',
ui.BOLD, '%s data value key' % title,
ui.MONO, *split(op.key),
icon_color=ui.GREEN)
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
@ -129,7 +127,7 @@ async def confirm_manage_data_op(ctx, op: StellarManageDataOp):
digest = sha256(op.value).digest()
digest_str = hexlify(digest).decode()
content = Text('Confirm operation', ui.ICON_CONFIRM,
ui.BOLD, ' Value (SHA-256):',
ui.BOLD, 'Value (SHA-256):',
ui.MONO, *split(digest_str),
icon_color=ui.GREEN)
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
@ -137,8 +135,8 @@ async def confirm_manage_data_op(ctx, op: StellarManageDataOp):
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.BOLD, 'Path Pay %s' % format_amount(op.destination_amount, ticker=False),
ui.BOLD, '%s to:' % format_asset_code(op.destination_asset),
ui.MONO, *split(trim_to_rows(format_address(op.destination_account), 3)),
icon_color=ui.GREEN)
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
@ -157,8 +155,8 @@ async def confirm_path_payment_op(ctx, op: StellarPathPaymentOp):
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.BOLD, 'Pay %s' % format_amount(op.amount, ticker=False),
ui.BOLD, '%s to:' % format_asset_code(op.asset),
ui.MONO, *split(trim_to_rows(format_address(op.destination_account), 3)),
icon_color=ui.GREEN)
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
@ -201,23 +199,22 @@ async def confirm_set_options_op(ctx, op: StellarSetOptionsOp):
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
if op.signer_type is not None:
if op.signer_weight > 0:
text = 'Add Signer'
text = 'Add Signer (%s)'
else:
text = 'Remove Signer'
text = 'Remove Signer (%s)'
if op.signer_type == consts.SIGN_TYPE_ACCOUNT:
text += ' (acc)'
content = Text('Confirm operation', ui.ICON_CONFIRM,
ui.BOLD, text,
ui.BOLD, text % 'acc',
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]:
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)'
signer_type = 'auth'
else:
text += ' (hash)'
signer_type = 'hash'
content = Text('Confirm operation', ui.ICON_CONFIRM,
ui.BOLD, text,
ui.BOLD, text % signer_type,
ui.MONO, *split(hexlify(op.signer_key).decode()),
icon_color=ui.GREEN)
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
@ -225,20 +222,20 @@ async def confirm_set_options_op(ctx, op: StellarSetOptionsOp):
raise ValueError('Stellar: invalid signer type')
def _format_thresholds(op: StellarSetOptionsOp) -> ():
def _format_thresholds(op: StellarSetOptionsOp) -> tuple:
text = ()
if op.master_weight is not None:
text += ('Master Weight: ' + str(op.master_weight), )
text += ('Master Weight: %d' % op.master_weight, )
if op.low_threshold is not None:
text += ('Low: ' + str(op.low_threshold), )
text += ('Low: %d' % op.low_threshold, )
if op.medium_threshold is not None:
text += ('Medium: ' + str(op.medium_threshold), )
text += ('Medium: %d' % op.medium_threshold, )
if op.high_threshold is not None:
text += ('High: ' + str(op.high_threshold), )
text += ('High: %d' % op.high_threshold, )
return text
def _format_flags(flags: int) -> ():
def _format_flags(flags: int) -> tuple:
if flags > consts.FLAGS_MAX_SIZE:
raise ValueError('Stellar: invalid')
text = ()
@ -261,7 +258,7 @@ 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.BOLD, '%s issuer:' % asset.code,
ui.MONO, *split(format_address(asset.issuer)),
icon_color=ui.GREEN)
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)

@ -1,3 +1,5 @@
from apps.stellar import writers
from apps.stellar import consts
from trezor.messages.StellarAccountMergeOp import StellarAccountMergeOp
from trezor.messages.StellarAssetType import StellarAssetType
from trezor.messages.StellarAllowTrustOp import StellarAllowTrustOp
@ -10,156 +12,154 @@ 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 *
def serialize_account_merge_op(w, msg: StellarAccountMergeOp):
write_pubkey(w, msg.destination_account)
writers.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)
writers.write_pubkey(w, msg.trusted_account)
writers.write_uint32(w, msg.asset_type)
_serialize_asset_code(w, msg.asset_type, msg.asset_code)
write_bool(w, msg.is_authorized)
writers.write_bool(w, msg.is_authorized)
def serialize_bump_sequence_op(w, msg: StellarBumpSequenceOp):
write_uint64(w, msg.bump_to)
writers.write_uint64(w, msg.bump_to)
def serialize_change_trust_op(w, msg: StellarChangeTrustOp):
_serialize_asset(w, msg.asset)
write_uint64(w, msg.limit)
writers.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)
writers.write_pubkey(w, msg.new_account)
writers.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)
writers.write_uint64(w, msg.amount)
writers.write_uint32(w, msg.price_n)
writers.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))
writers.write_string(w, msg.key)
writers.write_bool(w, bool(msg.value))
if msg.value:
write_uint32(w, len(msg.value))
write_bytes(w, msg.value)
writers.write_uint32(w, len(msg.value))
writers.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)
writers.write_uint64(w, msg.amount) # amount to sell
writers.write_uint32(w, msg.price_n) # numerator
writers.write_uint32(w, msg.price_d) # denominator
writers.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)
writers.write_uint64(w, msg.send_max)
writers.write_pubkey(w, msg.destination_account)
_serialize_asset(w, msg.destination_asset)
write_uint64(w, msg.destination_amount)
write_uint32(w, len(msg.paths))
writers.write_uint64(w, msg.destination_amount)
writers.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)
writers.write_pubkey(w, msg.destination_account)
_serialize_asset(w, msg.asset)
write_uint64(w, msg.amount)
writers.write_uint64(w, msg.amount)
def serialize_set_options_op(w, msg: StellarSetOptionsOp):
# inflation destination
write_bool(w, bool(msg.inflation_destination_account))
writers.write_bool(w, bool(msg.inflation_destination_account))
if msg.inflation_destination_account:
write_pubkey(w, msg.inflation_destination_account)
writers.write_pubkey(w, msg.inflation_destination_account)
# clear flags
write_bool(w, bool(msg.clear_flags))
writers.write_bool(w, bool(msg.clear_flags))
if msg.clear_flags:
write_uint32(w, msg.clear_flags)
writers.write_uint32(w, msg.clear_flags)
# set flags
write_bool(w, bool(msg.set_flags))
writers.write_bool(w, bool(msg.set_flags))
if msg.set_flags:
write_uint32(w, msg.set_flags)
writers.write_uint32(w, msg.set_flags)
# account thresholds
write_bool(w, bool(msg.master_weight))
writers.write_bool(w, bool(msg.master_weight))
if msg.master_weight:
write_uint32(w, msg.master_weight)
writers.write_uint32(w, msg.master_weight)
write_bool(w, bool(msg.low_threshold))
writers.write_bool(w, bool(msg.low_threshold))
if msg.low_threshold:
write_uint32(w, msg.low_threshold)
writers.write_uint32(w, msg.low_threshold)
write_bool(w, bool(msg.medium_threshold))
writers.write_bool(w, bool(msg.medium_threshold))
if msg.medium_threshold:
write_uint32(w, msg.medium_threshold)
writers.write_uint32(w, msg.medium_threshold)
write_bool(w, bool(msg.high_threshold))
writers.write_bool(w, bool(msg.high_threshold))
if msg.high_threshold:
write_uint32(w, msg.high_threshold)
writers.write_uint32(w, msg.high_threshold)
# home domain
write_bool(w, bool(msg.home_domain))
writers.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)
writers.write_string(w, msg.home_domain)
# signer
write_bool(w, bool(msg.signer_type))
writers.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)
writers.write_uint32(w, msg.signer_type)
writers.write_bytes(w, msg.signer_key)
writers.write_uint32(w, msg.signer_weight)
def serialize_account(w, source_account: bytes):
if source_account is None:
write_bool(w, False)
writers.write_bool(w, False)
return
write_pubkey(w, source_account)
writers.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_NATIVE:
if asset_type == consts.ASSET_TYPE_NATIVE:
return # nothing is needed
elif asset_type == ASSET_TYPE_ALPHANUM4:
elif asset_type == consts.ASSET_TYPE_ALPHANUM4:
# pad with zeros to 4 chars
write_bytes(w, code + bytearray([0] * (4 - len(code))))
elif asset_type == ASSET_TYPE_ALPHANUM12:
writers.write_bytes(w, code + bytearray([0] * (4 - len(code))))
elif asset_type == consts.ASSET_TYPE_ALPHANUM12:
# pad with zeros to 12 chars
write_bytes(w, code + bytearray([0] * (12 - len(code))))
writers.write_bytes(w, code + bytearray([0] * (12 - len(code))))
else:
raise ValueError('Stellar: invalid asset type')
def _serialize_asset(w, asset: StellarAssetType):
if asset is None:
write_uint32(w, 0)
writers.write_uint32(w, 0)
return
write_uint32(w, asset.type)
writers.write_uint32(w, asset.type)
_serialize_asset_code(w, asset.type, asset.code)
write_pubkey(w, asset.issuer)
writers.write_pubkey(w, asset.issuer)

@ -1,9 +1,8 @@
from apps.common import seed
from apps.stellar.writers import *
from apps.stellar import writers
from apps.stellar.operations import operation
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
@ -16,39 +15,66 @@ async def sign_tx(ctx, msg: StellarSignTx):
if msg.num_operations == 0:
raise ValueError('Stellar: At least one operation is required')
network_passphrase_hash = sha256(msg.network_passphrase).digest()
# Stellar transactions consist of sha256 of:
# - sha256(network passphrase)
# - 4-byte unsigned big-endian int type constant (2 for tx)
# - public key
node = await seed.derive_node(ctx, msg.address_n, consts.STELLAR_CURVE)
pubkey = seed.remove_ed25519_public_key_prefix(node.public_key())
w = bytearray()
write_bytes(w, network_passphrase_hash)
write_bytes(w, consts.TX_TYPE)
await _init(ctx, w, pubkey, msg)
_timebounds(w, msg.timebounds_start, msg.timebounds_end)
await _memo(ctx, w, msg)
await _operations(ctx, w, msg.num_operations)
await _final(ctx, w, msg)
node = await seed.derive_node(ctx, msg.address_n, consts.STELLAR_CURVE)
pubkey = seed.remove_ed25519_public_key_prefix(node.public_key())
write_pubkey(w, pubkey)
# sign
digest = sha256(w).digest()
signature = ed25519.sign(node.private_key(), digest)
# Add the public key for verification that the right account was used for signing
return StellarSignedTx(pubkey, signature)
async def _final(ctx, w: bytearray, msg: StellarSignTx):
# 4 null bytes representing a (currently unused) empty union
writers.write_uint32(w, 0)
# final confirm
await layout.require_confirm_final(ctx, msg.fee, msg.num_operations)
async def _init(ctx, w: bytearray, pubkey: bytes, msg: StellarSignTx):
network_passphrase_hash = sha256(msg.network_passphrase).digest()
writers.write_bytes(w, network_passphrase_hash)
writers.write_bytes(w, consts.TX_TYPE)
writers.write_pubkey(w, pubkey)
if msg.source_account != pubkey:
raise ValueError('Stellar: source account does not match address_n')
writers.write_uint32(w, msg.fee)
writers.write_uint64(w, msg.sequence_number)
# confirm init
await layout.require_confirm_init(ctx, pubkey, msg.network_passphrase)
write_uint32(w, msg.fee)
write_uint64(w, msg.sequence_number)
def _timebounds(w: bytearray, start: int, end: int):
# timebounds are only present if timebounds_start or timebounds_end is non-zero
if msg.timebounds_start or msg.timebounds_end:
write_bool(w, True)
if start or end:
writers.write_bool(w, True)
# timebounds are sent as uint32s since that's all we can display, but they must be hashed as 64bit
write_uint64(w, msg.timebounds_start)
write_uint64(w, msg.timebounds_end)
writers.write_uint64(w, start)
writers.write_uint64(w, end)
else:
write_bool(w, False)
writers.write_bool(w, False)
write_uint32(w, msg.memo_type)
async def _operations(ctx, w: bytearray, num_operations: int):
writers.write_uint32(w, num_operations)
for i in range(num_operations):
op = await ctx.call(StellarTxOpRequest(), *consts.op_wire_types)
await operation(ctx, w, op)
async def _memo(ctx, w: bytearray, msg: StellarSignTx):
writers.write_uint32(w, msg.memo_type)
if msg.memo_type == consts.MEMO_TYPE_NONE:
# nothing is serialized
memo_confirm_text = ''
@ -56,39 +82,20 @@ async def sign_tx(ctx, msg: StellarSignTx):
# 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)
writers.write_string(w, msg.memo_text)
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)
writers.write_uint64(w, msg.memo_id)
memo_confirm_text = str(msg.memo_id)
elif msg.memo_type in [consts.MEMO_TYPE_HASH, consts.MEMO_TYPE_RETURN]:
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))
writers.write_bytes(w, bytearray(msg.memo_hash))
memo_confirm_text = hexlify(msg.memo_hash).decode()
else:
raise ValueError('Stellar invalid memo type')
await layout.require_confirm_memo(ctx, msg.memo_type, memo_confirm_text)
write_uint32(w, msg.num_operations)
for i in range(msg.num_operations):
op = await ctx.call(StellarTxOpRequest(), *consts.op_wire_types)
await operation(ctx, w, op)
# 4 null bytes representing a (currently unused) empty union
write_uint32(w, 0)
# final confirm
await layout.require_confirm_final(ctx, msg.fee, msg.num_operations)
# sign
# (note that the signature does not include the 4-byte hint since it can be calculated from the public key)
digest = sha256(w).digest()
signature = ed25519.sign(node.private_key(), digest)
# Add the public key for verification that the right account was used for signing
return StellarSignedTx(pubkey, signature)
def node_derive(root, address_n: list):
node = root.clone()

Loading…
Cancel
Save