mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-18 13:38:12 +00:00
nem: first signed transaction
This commit is contained in:
parent
fb15e993f1
commit
d28a3ca5cf
@ -1,6 +1,6 @@
|
|||||||
from trezor.wire import register, protobuf_workflow
|
from trezor.wire import register, protobuf_workflow
|
||||||
from trezor.utils import unimport
|
from trezor.utils import unimport
|
||||||
from trezor.messages.wire_types import NEMGetAddress
|
from trezor.messages.wire_types import NEMGetAddress, NEMSignTx
|
||||||
|
|
||||||
|
|
||||||
@unimport
|
@unimport
|
||||||
@ -9,5 +9,12 @@ def dispatch_NemGetAddress(*args, **kwargs):
|
|||||||
return nem_get_address(*args, **kwargs)
|
return nem_get_address(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@unimport
|
||||||
|
def dispatch_NemSignTx(*args, **kwargs):
|
||||||
|
from .signing import nem_sign_tx
|
||||||
|
return nem_sign_tx(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def boot():
|
def boot():
|
||||||
register(NEMGetAddress, protobuf_workflow, dispatch_NemGetAddress)
|
register(NEMGetAddress, protobuf_workflow, dispatch_NemGetAddress)
|
||||||
|
register(NEMSignTx, protobuf_workflow, dispatch_NemSignTx)
|
||||||
|
29
src/apps/nem/layout.py
Normal file
29
src/apps/nem/layout.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
from apps.common.confirm import *
|
||||||
|
from trezor import ui
|
||||||
|
from trezor.messages import ButtonRequestType
|
||||||
|
from trezor.ui.text import Text
|
||||||
|
|
||||||
|
# todo wording, ui
|
||||||
|
|
||||||
|
|
||||||
|
async def require_confirm_tx(ctx, recipient, value):
|
||||||
|
content = Text('Confirm sending', ui.ICON_SEND,
|
||||||
|
ui.BOLD, value,
|
||||||
|
ui.NORMAL, 'to',
|
||||||
|
ui.MONO, recipient,
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_hold_to_confirm(ctx, content, ButtonRequestType.SignTx) # we use SignTx, not ConfirmOutput, for compatibility with T1
|
||||||
|
|
||||||
|
|
||||||
|
async def require_confirm_fee(ctx, value, fee):
|
||||||
|
content = Text('Confirm transaction', ui.ICON_SEND,
|
||||||
|
ui.BOLD, value,
|
||||||
|
ui.NORMAL, 'fee:',
|
||||||
|
ui.BOLD, fee,
|
||||||
|
icon_color=ui.GREEN)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
||||||
|
|
||||||
|
|
||||||
|
async def require_confirm_action(ctx):
|
||||||
|
content = Text('Send unencrypted transaction?', ui.ICON_SEND)
|
||||||
|
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
|
@ -1,86 +0,0 @@
|
|||||||
|
|
||||||
from .helpers import *
|
|
||||||
from .writers import *
|
|
||||||
|
|
||||||
|
|
||||||
def nem_transaction_create_transfer(network: int, timestamp: int, signer_public_key: bytes, fee: int, deadline: int,
|
|
||||||
recipient: str, amount: int, payload: bytearray = None, encrypted: bool = False,
|
|
||||||
mosaics: int = 0) -> bytearray:
|
|
||||||
|
|
||||||
tx = _nem_transaction_write_common(NEM_TRANSACTION_TYPE_TRANSFER,
|
|
||||||
_nem_get_version(network, mosaics),
|
|
||||||
timestamp,
|
|
||||||
signer_public_key,
|
|
||||||
fee,
|
|
||||||
deadline)
|
|
||||||
|
|
||||||
write_bytes_with_length(tx, bytearray(recipient))
|
|
||||||
write_uint64(tx, amount)
|
|
||||||
|
|
||||||
if payload:
|
|
||||||
# payload + payload size (u32) + encryption flag (u32)
|
|
||||||
write_uint32(tx, len(payload) + 2 * 4)
|
|
||||||
if encrypted:
|
|
||||||
write_uint32(tx, 0x02)
|
|
||||||
else:
|
|
||||||
write_uint32(tx, 0x01)
|
|
||||||
write_bytes_with_length(tx, payload)
|
|
||||||
else:
|
|
||||||
write_uint32(tx, 0)
|
|
||||||
|
|
||||||
if mosaics:
|
|
||||||
write_uint32(tx, mosaics)
|
|
||||||
|
|
||||||
return tx
|
|
||||||
|
|
||||||
|
|
||||||
def nem_transaction_create_provision_namespace(network: int, timestamp: int, signer_public_key: bytes, fee: int,
|
|
||||||
deadline: int, namespace: str, parent: str, rental_sink: str,
|
|
||||||
rental_fee: int) -> bytearray:
|
|
||||||
|
|
||||||
tx = _nem_transaction_write_common(NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE,
|
|
||||||
_nem_get_version(network),
|
|
||||||
timestamp,
|
|
||||||
signer_public_key,
|
|
||||||
fee,
|
|
||||||
deadline)
|
|
||||||
|
|
||||||
write_bytes_with_length(tx, bytearray(rental_sink))
|
|
||||||
write_uint64(tx, rental_fee)
|
|
||||||
write_bytes_with_length(tx, bytearray(namespace))
|
|
||||||
if parent:
|
|
||||||
write_bytes_with_length(tx, bytearray(parent))
|
|
||||||
else:
|
|
||||||
write_uint32(tx, 0xffffffff)
|
|
||||||
|
|
||||||
return tx
|
|
||||||
|
|
||||||
|
|
||||||
def nem_transaction_write_mosaic(w: bytearray, namespace: str, mosaic: str, quantity: int):
|
|
||||||
identifier_length = 4 + len(namespace) + 4 + len(mosaic)
|
|
||||||
# indentifier length (u32) + quantity (u64) + identifier size
|
|
||||||
write_uint32(w, 4 + 8 + identifier_length)
|
|
||||||
write_uint32(w, identifier_length)
|
|
||||||
write_bytes_with_length(w, bytearray(namespace))
|
|
||||||
write_bytes_with_length(w, bytearray(mosaic))
|
|
||||||
write_uint64(w, quantity)
|
|
||||||
|
|
||||||
|
|
||||||
def _nem_transaction_write_common(tx_type: int, version: int, timestamp: int, signer: bytes, fee: int, deadline: int)\
|
|
||||||
-> bytearray:
|
|
||||||
ret = bytearray()
|
|
||||||
write_uint32(ret, tx_type)
|
|
||||||
write_uint32(ret, version)
|
|
||||||
write_uint32(ret, timestamp)
|
|
||||||
|
|
||||||
write_bytes_with_length(ret, bytearray(signer))
|
|
||||||
write_uint64(ret, fee)
|
|
||||||
write_uint32(ret, deadline)
|
|
||||||
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
def _nem_get_version(network, mosaics=None) -> int:
|
|
||||||
if mosaics:
|
|
||||||
return network << 24 | 2
|
|
||||||
return network << 24 | 1
|
|
43
src/apps/nem/signing.py
Normal file
43
src/apps/nem/signing.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
from apps.nem.transaction import *
|
||||||
|
from apps.nem.layout import *
|
||||||
|
from trezor.messages.NEMSignTx import NEMSignTx
|
||||||
|
from trezor.messages.NEMSignedTx import NEMSignedTx
|
||||||
|
|
||||||
|
|
||||||
|
async def nem_sign_tx(ctx, msg: NEMSignTx):
|
||||||
|
from ..common import seed
|
||||||
|
from trezor.crypto.curve import ed25519
|
||||||
|
|
||||||
|
# if len(msg.transfer.public_key):
|
||||||
|
# todo encrypt
|
||||||
|
|
||||||
|
node = await seed.derive_node(ctx, msg.transaction.address_n, NEM_CURVE)
|
||||||
|
# 0x01 prefix is not part of the actual public key, hence removed
|
||||||
|
public_key = node.public_key()[1:]
|
||||||
|
|
||||||
|
tx = nem_transaction_create_transfer(
|
||||||
|
msg.transaction.network,
|
||||||
|
msg.transaction.timestamp,
|
||||||
|
public_key,
|
||||||
|
msg.transaction.fee,
|
||||||
|
msg.transaction.deadline,
|
||||||
|
msg.transfer.recipient,
|
||||||
|
msg.transfer.amount,
|
||||||
|
msg.transfer.payload, # todo might require encryption
|
||||||
|
msg.transfer.public_key is not None,
|
||||||
|
len(msg.transfer.mosaics)
|
||||||
|
)
|
||||||
|
|
||||||
|
for mosaic in msg.transfer.mosaics:
|
||||||
|
nem_transaction_write_mosaic(tx, mosaic.namespace, mosaic.mosaic, mosaic.quantity)
|
||||||
|
|
||||||
|
await require_confirm_action(ctx)
|
||||||
|
await require_confirm_fee(ctx, msg.transfer.amount, msg.transaction.fee)
|
||||||
|
await require_confirm_tx(ctx, msg.transfer.recipient, msg.transfer.amount)
|
||||||
|
|
||||||
|
signature = ed25519.sign(node.private_key(), tx, 'keccak')
|
||||||
|
|
||||||
|
resp = NEMSignedTx()
|
||||||
|
resp.data = tx
|
||||||
|
resp.signature = signature
|
||||||
|
return resp
|
Loading…
Reference in New Issue
Block a user