mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-26 17:38:39 +00:00
nem: refactored to directories
This commit is contained in:
parent
32681972f1
commit
8de3cd7cac
@ -1,7 +1,4 @@
|
|||||||
|
|
||||||
from micropython import const
|
from micropython import const
|
||||||
from trezor.messages.NEMSignTx import NEMSignTx
|
|
||||||
|
|
||||||
|
|
||||||
NEM_NETWORK_MAINNET = const(0x68)
|
NEM_NETWORK_MAINNET = const(0x68)
|
||||||
NEM_NETWORK_TESTNET = const(0x98)
|
NEM_NETWORK_TESTNET = const(0x98)
|
||||||
|
12
src/apps/nem/mosaic/__init__.py
Normal file
12
src/apps/nem/mosaic/__init__.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
from .layout import *
|
||||||
|
from .serialize import *
|
||||||
|
|
||||||
|
|
||||||
|
async def mosaic_creation(ctx, public_key: bytes, msg: NEMSignTx) -> bytearray:
|
||||||
|
await ask_mosaic_creation(ctx, msg)
|
||||||
|
return serialize_mosaic_creation(msg, public_key)
|
||||||
|
|
||||||
|
|
||||||
|
async def supply_change(ctx, public_key: bytes, msg: NEMSignTx):
|
||||||
|
await ask_mosaic_supply_change(ctx, msg)
|
||||||
|
return serialize_mosaic_supply_change(msg, public_key)
|
26
src/apps/nem/mosaic/layout.py
Normal file
26
src/apps/nem/mosaic/layout.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
from apps.nem.layout import *
|
||||||
|
from trezor.messages import NEMSignTx
|
||||||
|
from trezor.messages import NEMSupplyChangeType
|
||||||
|
|
||||||
|
|
||||||
|
async def ask_mosaic_creation(ctx, msg: NEMSignTx):
|
||||||
|
await require_confirm_action(ctx, 'Create mosaic "' + msg.mosaic_creation.definition.mosaic + '" under namespace "'
|
||||||
|
+ msg.mosaic_creation.definition.namespace + '"?')
|
||||||
|
await require_confirm_properties(ctx, msg.mosaic_creation.definition)
|
||||||
|
await require_confirm_fee(ctx, 'Confirm creation fee', msg.mosaic_creation.fee)
|
||||||
|
|
||||||
|
await require_confirm_final(ctx, msg.transaction.fee)
|
||||||
|
|
||||||
|
|
||||||
|
async def ask_mosaic_supply_change(ctx, msg: NEMSignTx):
|
||||||
|
await require_confirm_action(ctx, 'Modify supply for "' + msg.supply_change.mosaic + '" under namespace "'
|
||||||
|
+ msg.supply_change.namespace + '"?')
|
||||||
|
if msg.supply_change.type == NEMSupplyChangeType.SupplyChange_Decrease:
|
||||||
|
ask_msg = 'Decrease supply by ' + str(msg.supply_change.delta) + ' whole units?'
|
||||||
|
elif msg.supply_change.type == NEMSupplyChangeType.SupplyChange_Increase:
|
||||||
|
ask_msg = 'Increase supply by ' + str(msg.supply_change.delta) + ' whole units?'
|
||||||
|
else:
|
||||||
|
raise ValueError('Invalid supply change type')
|
||||||
|
await require_confirm_action(ctx, ask_msg)
|
||||||
|
|
||||||
|
await require_confirm_final(ctx, msg.transaction.fee)
|
@ -1,30 +1,6 @@
|
|||||||
from .writers import *
|
from apps.nem.writers import *
|
||||||
from trezor.messages.NEMMosaic import NEMMosaic
|
from apps.nem.helpers import *
|
||||||
from trezor.messages import NEMSupplyChangeType
|
from trezor.messages.NEMSignTx import NEMSignTx
|
||||||
from apps.nem.layout import *
|
|
||||||
|
|
||||||
|
|
||||||
async def ask_mosaic_creation(ctx, msg: NEMSignTx):
|
|
||||||
await require_confirm_action(ctx, 'Create mosaic "' + msg.mosaic_creation.definition.mosaic + '" under namespace "'
|
|
||||||
+ msg.mosaic_creation.definition.namespace + '"?')
|
|
||||||
await require_confirm_properties(ctx, msg.mosaic_creation.definition)
|
|
||||||
await require_confirm_fee(ctx, 'Confirm creation fee', msg.mosaic_creation.fee)
|
|
||||||
|
|
||||||
await require_confirm_final(ctx, msg.transaction.fee)
|
|
||||||
|
|
||||||
|
|
||||||
async def ask_mosaic_supply_change(ctx, msg: NEMSignTx):
|
|
||||||
await require_confirm_action(ctx, 'Modify supply for "' + msg.supply_change.mosaic + '" under namespace "'
|
|
||||||
+ msg.supply_change.namespace + '"?')
|
|
||||||
if msg.supply_change.type == NEMSupplyChangeType.SupplyChange_Decrease:
|
|
||||||
ask_msg = 'Decrease supply by ' + str(msg.supply_change.delta) + ' whole units?'
|
|
||||||
elif msg.supply_change.type == NEMSupplyChangeType.SupplyChange_Increase:
|
|
||||||
ask_msg = 'Increase supply by ' + str(msg.supply_change.delta) + ' whole units?'
|
|
||||||
else:
|
|
||||||
raise ValueError('Invalid supply change type')
|
|
||||||
await require_confirm_action(ctx, ask_msg)
|
|
||||||
|
|
||||||
await require_confirm_final(ctx, msg.transaction.fee)
|
|
||||||
|
|
||||||
|
|
||||||
def serialize_mosaic_creation(msg: NEMSignTx, public_key: bytes):
|
def serialize_mosaic_creation(msg: NEMSignTx, public_key: bytes):
|
||||||
@ -96,45 +72,3 @@ def _write_property(w: bytearray, name: str, value):
|
|||||||
write_uint32(w, 4 + len(name) + 4 + len(value))
|
write_uint32(w, 4 + len(name) + 4 + len(value))
|
||||||
write_bytes_with_length(w, bytearray(name))
|
write_bytes_with_length(w, bytearray(name))
|
||||||
write_bytes_with_length(w, bytearray(value))
|
write_bytes_with_length(w, bytearray(value))
|
||||||
|
|
||||||
|
|
||||||
def serialize_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 canonicalize_mosaics(mosaics: list):
|
|
||||||
if len(mosaics) <= 1:
|
|
||||||
return mosaics
|
|
||||||
mosaics = merge_mosaics(mosaics)
|
|
||||||
return sort_mosaics(mosaics)
|
|
||||||
|
|
||||||
|
|
||||||
def are_mosaics_equal(a: NEMMosaic, b: NEMMosaic) -> bool:
|
|
||||||
if a.namespace == b.namespace and a.mosaic == b.mosaic:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def merge_mosaics(mosaics: list) -> list:
|
|
||||||
if not len(mosaics):
|
|
||||||
return list()
|
|
||||||
ret = list()
|
|
||||||
for i in mosaics:
|
|
||||||
found = False
|
|
||||||
for k, y in enumerate(ret):
|
|
||||||
if are_mosaics_equal(i, y):
|
|
||||||
ret[k].quantity += i.quantity
|
|
||||||
found = True
|
|
||||||
if not found:
|
|
||||||
ret.append(i)
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
def sort_mosaics(mosaics: list) -> list:
|
|
||||||
return sorted(mosaics, key=lambda m: (m.namespace, m.mosaic))
|
|
29
src/apps/nem/multisig/__init__.py
Normal file
29
src/apps/nem/multisig/__init__.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
from .serialize import *
|
||||||
|
from .layout import *
|
||||||
|
|
||||||
|
|
||||||
|
async def ask(ctx, msg: NEMSignTx):
|
||||||
|
await ask_multisig(ctx, msg)
|
||||||
|
|
||||||
|
|
||||||
|
def initiate(public_key, msg: NEMSignTx, inner_tx: bytes) -> bytes:
|
||||||
|
return serialize_multisig(msg.multisig, public_key, inner_tx)
|
||||||
|
|
||||||
|
|
||||||
|
def cosign(public_key, msg: NEMSignTx, inner_tx: bytes) -> bytes:
|
||||||
|
return serialize_multisig_signature(msg.multisig,
|
||||||
|
public_key,
|
||||||
|
inner_tx,
|
||||||
|
msg.multisig.signer)
|
||||||
|
|
||||||
|
|
||||||
|
async def aggregate_modification(ctx, public_key: bytes, msg: NEMSignTx):
|
||||||
|
await ask_aggregate_modification(ctx, msg)
|
||||||
|
w = serialize_aggregate_modification(msg, public_key)
|
||||||
|
|
||||||
|
for m in msg.aggregate_modification.modifications:
|
||||||
|
serialize_cosignatory_modification(w, m.type, m.public_key)
|
||||||
|
|
||||||
|
if msg.aggregate_modification.relative_change:
|
||||||
|
serialize_minimum_cosignatories(w, msg.aggregate_modification.relative_change)
|
||||||
|
return w
|
36
src/apps/nem/multisig/layout.py
Normal file
36
src/apps/nem/multisig/layout.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
from apps.nem.layout import *
|
||||||
|
from trezor.messages import NEMModificationType
|
||||||
|
from trezor.messages import NEMSignTx
|
||||||
|
from trezor.crypto import nem
|
||||||
|
|
||||||
|
|
||||||
|
async def ask_multisig(ctx, msg: NEMSignTx):
|
||||||
|
address = nem.compute_address(msg.multisig.signer, msg.transaction.network)
|
||||||
|
if msg.cosigning:
|
||||||
|
await require_confirm_address(ctx, 'Cosign transaction for', address)
|
||||||
|
else:
|
||||||
|
await require_confirm_address(ctx, 'Initiate transaction for', address)
|
||||||
|
await require_confirm_fee(ctx, 'Confirm multisig fee', msg.multisig.fee)
|
||||||
|
|
||||||
|
|
||||||
|
async def ask_aggregate_modification(ctx, msg: NEMSignTx):
|
||||||
|
if not msg.multisig:
|
||||||
|
await require_confirm_action(ctx, 'Convert account to multisig account?')
|
||||||
|
|
||||||
|
for m in msg.aggregate_modification.modifications:
|
||||||
|
if m.type == NEMModificationType.CosignatoryModification_Add:
|
||||||
|
action = 'Add'
|
||||||
|
else:
|
||||||
|
action = 'Remove'
|
||||||
|
address = nem.compute_address(m.public_key, msg.transaction.network)
|
||||||
|
await require_confirm_address(ctx, action + ' cosignatory?', address)
|
||||||
|
|
||||||
|
if msg.aggregate_modification.relative_change:
|
||||||
|
if not msg.multisig:
|
||||||
|
action = 'Set minimum cosignatories to '
|
||||||
|
else:
|
||||||
|
action = 'Modify the number of cosignatories by '
|
||||||
|
await require_confirm_action(ctx, action + str(msg.aggregate_modification.relative_change) + '?')
|
||||||
|
|
||||||
|
await require_confirm_final(ctx, msg.transaction.fee)
|
||||||
|
|
@ -1,41 +1,10 @@
|
|||||||
from .writers import *
|
from apps.nem.writers import *
|
||||||
from apps.nem.layout import *
|
from apps.nem.helpers import *
|
||||||
|
from trezor.messages.NEMSignTx import NEMSignTx
|
||||||
from trezor.crypto import hashlib
|
from trezor.crypto import hashlib
|
||||||
from trezor.messages import NEMModificationType
|
|
||||||
from trezor.crypto import nem
|
from trezor.crypto import nem
|
||||||
|
|
||||||
|
|
||||||
async def ask_multisig(ctx, msg: NEMSignTx):
|
|
||||||
address = nem.compute_address(msg.multisig.signer, msg.transaction.network)
|
|
||||||
if msg.cosigning:
|
|
||||||
await require_confirm_address(ctx, 'Cosign transaction for', address)
|
|
||||||
else:
|
|
||||||
await require_confirm_address(ctx, 'Initiate transaction for', address)
|
|
||||||
await require_confirm_fee(ctx, 'Confirm multisig fee', msg.multisig.fee)
|
|
||||||
|
|
||||||
|
|
||||||
async def ask_aggregate_modification(ctx, msg: NEMSignTx):
|
|
||||||
if not msg.multisig:
|
|
||||||
await require_confirm_action(ctx, 'Convert account to multisig account?')
|
|
||||||
|
|
||||||
for m in msg.aggregate_modification.modifications:
|
|
||||||
if m.type == NEMModificationType.CosignatoryModification_Add:
|
|
||||||
action = 'Add'
|
|
||||||
else:
|
|
||||||
action = 'Remove'
|
|
||||||
address = nem.compute_address(m.public_key, msg.transaction.network)
|
|
||||||
await require_confirm_address(ctx, action + ' cosignatory?', address)
|
|
||||||
|
|
||||||
if msg.aggregate_modification.relative_change:
|
|
||||||
if not msg.multisig:
|
|
||||||
action = 'Set minimum cosignatories to '
|
|
||||||
else:
|
|
||||||
action = 'Modify the number of cosignatories by '
|
|
||||||
await require_confirm_action(ctx, action + str(msg.aggregate_modification.relative_change) + '?')
|
|
||||||
|
|
||||||
await require_confirm_final(ctx, msg.transaction.fee)
|
|
||||||
|
|
||||||
|
|
||||||
def serialize_multisig(msg: NEMTransactionCommon, public_key: bytes, inner: bytes):
|
def serialize_multisig(msg: NEMTransactionCommon, public_key: bytes, inner: bytes):
|
||||||
w = write_common(msg, bytearray(public_key), NEM_TRANSACTION_TYPE_MULTISIG)
|
w = write_common(msg, bytearray(public_key), NEM_TRANSACTION_TYPE_MULTISIG)
|
||||||
write_bytes_with_length(w, bytearray(inner))
|
write_bytes_with_length(w, bytearray(inner))
|
@ -1,29 +0,0 @@
|
|||||||
from .writers import *
|
|
||||||
from apps.nem.layout import *
|
|
||||||
|
|
||||||
|
|
||||||
async def ask_provision_namespace(ctx, msg: NEMSignTx):
|
|
||||||
if msg.provision_namespace.parent:
|
|
||||||
await require_confirm_action(ctx, 'Create namespace "' + msg.provision_namespace.namespace + '"' +
|
|
||||||
'under namespace "' + msg.provision_namespace.parent + '"?')
|
|
||||||
else:
|
|
||||||
await require_confirm_action(ctx, 'Create namespace "' + msg.provision_namespace.namespace + '"?')
|
|
||||||
await require_confirm_fee(ctx, 'Confirm rental fee', msg.provision_namespace.fee)
|
|
||||||
|
|
||||||
await require_confirm_final(ctx, msg.transaction.fee)
|
|
||||||
|
|
||||||
|
|
||||||
def serialize_provision_namespace(msg: NEMSignTx, public_key: bytes) -> bytearray:
|
|
||||||
tx = write_common(msg.transaction,
|
|
||||||
bytearray(public_key),
|
|
||||||
NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE)
|
|
||||||
|
|
||||||
write_bytes_with_length(tx, bytearray(msg.provision_namespace.sink))
|
|
||||||
write_uint64(tx, msg.provision_namespace.fee)
|
|
||||||
write_bytes_with_length(tx, bytearray(msg.provision_namespace.namespace))
|
|
||||||
if msg.provision_namespace.parent:
|
|
||||||
write_bytes_with_length(tx, bytearray(msg.provision_namespace.parent))
|
|
||||||
else:
|
|
||||||
write_uint32(tx, 0xffffffff)
|
|
||||||
|
|
||||||
return tx
|
|
7
src/apps/nem/namespace/__init__.py
Normal file
7
src/apps/nem/namespace/__init__.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from .layout import *
|
||||||
|
from .serialize import *
|
||||||
|
|
||||||
|
|
||||||
|
async def namespace(ctx, public_key: bytes, msg: NEMSignTx) -> bytearray:
|
||||||
|
await ask_provision_namespace(ctx, msg)
|
||||||
|
return serialize_provision_namespace(msg, public_key)
|
13
src/apps/nem/namespace/layout.py
Normal file
13
src/apps/nem/namespace/layout.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from apps.nem.layout import *
|
||||||
|
from trezor.messages import NEMSignTx
|
||||||
|
|
||||||
|
|
||||||
|
async def ask_provision_namespace(ctx, msg: NEMSignTx):
|
||||||
|
if msg.provision_namespace.parent:
|
||||||
|
await require_confirm_action(ctx, 'Create namespace "' + msg.provision_namespace.namespace + '"' +
|
||||||
|
'under namespace "' + msg.provision_namespace.parent + '"?')
|
||||||
|
else:
|
||||||
|
await require_confirm_action(ctx, 'Create namespace "' + msg.provision_namespace.namespace + '"?')
|
||||||
|
await require_confirm_fee(ctx, 'Confirm rental fee', msg.provision_namespace.fee)
|
||||||
|
|
||||||
|
await require_confirm_final(ctx, msg.transaction.fee)
|
19
src/apps/nem/namespace/serialize.py
Normal file
19
src/apps/nem/namespace/serialize.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
from apps.nem.helpers import *
|
||||||
|
from apps.nem.writers import *
|
||||||
|
from trezor.messages.NEMSignTx import NEMSignTx
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_provision_namespace(msg: NEMSignTx, public_key: bytes) -> bytearray:
|
||||||
|
tx = write_common(msg.transaction,
|
||||||
|
bytearray(public_key),
|
||||||
|
NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE)
|
||||||
|
|
||||||
|
write_bytes_with_length(tx, bytearray(msg.provision_namespace.sink))
|
||||||
|
write_uint64(tx, msg.provision_namespace.fee)
|
||||||
|
write_bytes_with_length(tx, bytearray(msg.provision_namespace.namespace))
|
||||||
|
if msg.provision_namespace.parent:
|
||||||
|
write_bytes_with_length(tx, bytearray(msg.provision_namespace.parent))
|
||||||
|
else:
|
||||||
|
write_uint32(tx, 0xffffffff)
|
||||||
|
|
||||||
|
return tx
|
@ -1,9 +1,9 @@
|
|||||||
from apps.nem.transfer import *
|
from apps.nem import namespace
|
||||||
from apps.nem.multisig import *
|
from apps.nem import transfer
|
||||||
from apps.nem.namespace import *
|
from apps.nem import mosaic
|
||||||
from apps.nem.mosaic import *
|
from apps.nem import multisig
|
||||||
from apps.nem.validators import validate
|
from apps.nem.validators import validate
|
||||||
from apps.nem import helpers
|
from apps.nem.helpers import *
|
||||||
from apps.common import seed
|
from apps.common import seed
|
||||||
from trezor.messages.NEMSignTx import NEMSignTx
|
from trezor.messages.NEMSignTx import NEMSignTx
|
||||||
from trezor.messages.NEMSignedTx import NEMSignedTx
|
from trezor.messages.NEMSignedTx import NEMSignedTx
|
||||||
@ -16,31 +16,33 @@ async def sign_tx(ctx, msg: NEMSignTx):
|
|||||||
|
|
||||||
if msg.multisig:
|
if msg.multisig:
|
||||||
public_key = msg.multisig.signer
|
public_key = msg.multisig.signer
|
||||||
await ask_multisig(ctx, msg)
|
await multisig.ask(ctx, msg)
|
||||||
else:
|
else:
|
||||||
public_key = _get_public_key(node)
|
public_key = _get_public_key(node)
|
||||||
|
|
||||||
if msg.transfer:
|
if msg.transfer:
|
||||||
msg.transfer.mosaics = canonicalize_mosaics(msg.transfer.mosaics)
|
tx = await transfer.transfer(ctx, public_key, msg, node)
|
||||||
tx = await _transfer(ctx, public_key, msg, node)
|
|
||||||
elif msg.provision_namespace:
|
elif msg.provision_namespace:
|
||||||
tx = await _provision_namespace(ctx, public_key, msg)
|
tx = await namespace.namespace(ctx, public_key, msg)
|
||||||
elif msg.mosaic_creation:
|
elif msg.mosaic_creation:
|
||||||
tx = await _mosaic_creation(ctx, public_key, msg)
|
tx = await mosaic.mosaic_creation(ctx, public_key, msg)
|
||||||
elif msg.supply_change:
|
elif msg.supply_change:
|
||||||
tx = await _supply_change(ctx, public_key, msg)
|
tx = await mosaic.supply_change(ctx, public_key, msg)
|
||||||
elif msg.aggregate_modification:
|
elif msg.aggregate_modification:
|
||||||
tx = await _aggregate_modification(ctx, public_key, msg)
|
tx = await multisig.aggregate_modification(ctx, public_key, msg)
|
||||||
elif msg.importance_transfer:
|
elif msg.importance_transfer:
|
||||||
tx = await _importance_transfer(ctx, public_key, msg)
|
tx = await transfer.importance_transfer(ctx, public_key, msg)
|
||||||
else:
|
else:
|
||||||
raise ValueError('No transaction provided')
|
raise ValueError('No transaction provided')
|
||||||
|
|
||||||
if msg.multisig:
|
if msg.multisig:
|
||||||
# wrap transaction in multisig wrapper
|
# wrap transaction in multisig wrapper
|
||||||
tx = _multisig(node, msg, tx)
|
if msg.cosigning:
|
||||||
|
tx = multisig.cosign(_get_public_key(node), msg, tx)
|
||||||
|
else:
|
||||||
|
tx = multisig.initiate(_get_public_key(node), msg, tx)
|
||||||
|
|
||||||
signature = ed25519.sign(node.private_key(), tx, helpers.NEM_HASH_ALG)
|
signature = ed25519.sign(node.private_key(), tx, NEM_HASH_ALG)
|
||||||
|
|
||||||
resp = NEMSignedTx()
|
resp = NEMSignedTx()
|
||||||
resp.data = tx
|
resp.data = tx
|
||||||
@ -48,58 +50,6 @@ async def sign_tx(ctx, msg: NEMSignTx):
|
|||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
def _multisig(node, msg: NEMSignTx, inner_tx: bytes) -> bytes:
|
|
||||||
if msg.cosigning:
|
|
||||||
return serialize_multisig_signature(msg.multisig,
|
|
||||||
_get_public_key(node),
|
|
||||||
inner_tx,
|
|
||||||
msg.multisig.signer)
|
|
||||||
else:
|
|
||||||
return serialize_multisig(msg.multisig, _get_public_key(node), inner_tx)
|
|
||||||
|
|
||||||
|
|
||||||
def _get_public_key(node) -> bytes:
|
def _get_public_key(node) -> bytes:
|
||||||
# 0x01 prefix is not part of the actual public key, hence removed
|
# 0x01 prefix is not part of the actual public key, hence removed
|
||||||
return node.public_key()[1:]
|
return node.public_key()[1:]
|
||||||
|
|
||||||
|
|
||||||
async def _transfer(ctx, public_key: bytes, msg: NEMSignTx, node) -> bytes:
|
|
||||||
payload, encrypted = get_transfer_payload(msg, node)
|
|
||||||
await ask_transfer(ctx, msg, payload, encrypted)
|
|
||||||
|
|
||||||
w = serialize_transfer(msg, public_key, payload, encrypted)
|
|
||||||
for mosaic in msg.transfer.mosaics:
|
|
||||||
serialize_mosaic(w, mosaic.namespace, mosaic.mosaic, mosaic.quantity)
|
|
||||||
return w
|
|
||||||
|
|
||||||
|
|
||||||
async def _provision_namespace(ctx, public_key: bytes, msg: NEMSignTx) -> bytearray:
|
|
||||||
await ask_provision_namespace(ctx, msg)
|
|
||||||
return serialize_provision_namespace(msg, public_key)
|
|
||||||
|
|
||||||
|
|
||||||
async def _mosaic_creation(ctx, public_key: bytes, msg: NEMSignTx) -> bytearray:
|
|
||||||
await ask_mosaic_creation(ctx, msg)
|
|
||||||
return serialize_mosaic_creation(msg, public_key)
|
|
||||||
|
|
||||||
|
|
||||||
async def _supply_change(ctx, public_key: bytes, msg: NEMSignTx):
|
|
||||||
await ask_mosaic_supply_change(ctx, msg)
|
|
||||||
return serialize_mosaic_supply_change(msg, public_key)
|
|
||||||
|
|
||||||
|
|
||||||
async def _aggregate_modification(ctx, public_key: bytes, msg: NEMSignTx):
|
|
||||||
await ask_aggregate_modification(ctx, msg)
|
|
||||||
w = serialize_aggregate_modification(msg, public_key)
|
|
||||||
|
|
||||||
for m in msg.aggregate_modification.modifications:
|
|
||||||
serialize_cosignatory_modification(w, m.type, m.public_key)
|
|
||||||
|
|
||||||
if msg.aggregate_modification.relative_change:
|
|
||||||
serialize_minimum_cosignatories(w, msg.aggregate_modification.relative_change)
|
|
||||||
return w
|
|
||||||
|
|
||||||
|
|
||||||
async def _importance_transfer(ctx, public_key: bytes, msg: NEMSignTx):
|
|
||||||
await ask_importance_transfer(ctx, msg)
|
|
||||||
return serialize_importance_transfer(msg, public_key)
|
|
||||||
|
19
src/apps/nem/transfer/__init__.py
Normal file
19
src/apps/nem/transfer/__init__.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
from .layout import *
|
||||||
|
from .serialize import *
|
||||||
|
|
||||||
|
|
||||||
|
async def transfer(ctx, public_key: bytes, msg: NEMSignTx, node):
|
||||||
|
msg.transfer.mosaics = canonicalize_mosaics(msg.transfer.mosaics)
|
||||||
|
|
||||||
|
payload, encrypted = get_transfer_payload(msg, node)
|
||||||
|
await ask_transfer(ctx, msg, payload, encrypted)
|
||||||
|
|
||||||
|
w = serialize_transfer(msg, public_key, payload, encrypted)
|
||||||
|
for mosaic in msg.transfer.mosaics:
|
||||||
|
serialize_mosaic(w, mosaic.namespace, mosaic.mosaic, mosaic.quantity)
|
||||||
|
return w
|
||||||
|
|
||||||
|
|
||||||
|
async def importance_transfer(ctx, public_key: bytes, msg: NEMSignTx):
|
||||||
|
await ask_importance_transfer(ctx, msg)
|
||||||
|
return serialize_importance_transfer(msg, public_key)
|
25
src/apps/nem/transfer/layout.py
Normal file
25
src/apps/nem/transfer/layout.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
from apps.nem.layout import *
|
||||||
|
from trezor.messages import NEMImportanceTransferMode
|
||||||
|
from trezor.messages import NEMSignTx
|
||||||
|
|
||||||
|
|
||||||
|
async def ask_transfer(ctx, msg: NEMSignTx, payload, encrypted):
|
||||||
|
if payload:
|
||||||
|
await require_confirm_payload(ctx, msg.transfer.payload, encrypted)
|
||||||
|
|
||||||
|
for mosaic in msg.transfer.mosaics:
|
||||||
|
await require_confirm_action(ctx, 'Confirm transfer of ' + str(mosaic.quantity) +
|
||||||
|
' raw units of ' + mosaic.namespace + '.' + mosaic.mosaic)
|
||||||
|
|
||||||
|
await require_confirm_transfer(ctx, msg.transfer.recipient, msg.transfer.amount)
|
||||||
|
|
||||||
|
await require_confirm_final(ctx, msg.transaction.fee)
|
||||||
|
|
||||||
|
|
||||||
|
async def ask_importance_transfer(ctx, msg: NEMSignTx):
|
||||||
|
if msg.importance_transfer.mode == NEMImportanceTransferMode.ImportanceTransfer_Activate:
|
||||||
|
m = 'Activate'
|
||||||
|
else:
|
||||||
|
m = 'Deactivate'
|
||||||
|
await require_confirm_action(ctx, m + ' remote harvesting?')
|
||||||
|
await require_confirm_final(ctx, msg.transaction.fee)
|
@ -1,31 +1,10 @@
|
|||||||
from .writers import *
|
from apps.nem.writers import *
|
||||||
from apps.nem.layout import *
|
from apps.nem.helpers import *
|
||||||
from trezor.messages import NEMImportanceTransferMode
|
from trezor.messages.NEMMosaic import NEMMosaic
|
||||||
|
from trezor.messages.NEMSignTx import NEMSignTx
|
||||||
from trezor.crypto import random
|
from trezor.crypto import random
|
||||||
|
|
||||||
|
|
||||||
async def ask_transfer(ctx, msg: NEMSignTx, payload, encrypted):
|
|
||||||
if payload:
|
|
||||||
await require_confirm_payload(ctx, msg.transfer.payload, encrypted)
|
|
||||||
|
|
||||||
for mosaic in msg.transfer.mosaics:
|
|
||||||
await require_confirm_action(ctx, 'Confirm transfer of ' + str(mosaic.quantity) +
|
|
||||||
' raw units of ' + mosaic.namespace + '.' + mosaic.mosaic)
|
|
||||||
|
|
||||||
await require_confirm_transfer(ctx, msg.transfer.recipient, msg.transfer.amount)
|
|
||||||
|
|
||||||
await require_confirm_final(ctx, msg.transaction.fee)
|
|
||||||
|
|
||||||
|
|
||||||
async def ask_importance_transfer(ctx, msg: NEMSignTx):
|
|
||||||
if msg.importance_transfer.mode == NEMImportanceTransferMode.ImportanceTransfer_Activate:
|
|
||||||
m = 'Activate'
|
|
||||||
else:
|
|
||||||
m = 'Deactivate'
|
|
||||||
await require_confirm_action(ctx, m + ' remote harvesting?')
|
|
||||||
await require_confirm_final(ctx, msg.transaction.fee)
|
|
||||||
|
|
||||||
|
|
||||||
def serialize_transfer(msg: NEMSignTx, public_key: bytes, payload: bytes=None, encrypted: bool=False) -> bytearray:
|
def serialize_transfer(msg: NEMSignTx, public_key: bytes, payload: bytes=None, encrypted: bool=False) -> bytearray:
|
||||||
tx = write_common(msg.transaction,
|
tx = write_common(msg.transaction,
|
||||||
bytearray(public_key),
|
bytearray(public_key),
|
||||||
@ -52,6 +31,16 @@ def serialize_transfer(msg: NEMSignTx, public_key: bytes, payload: bytes=None, e
|
|||||||
return tx
|
return tx
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_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 serialize_importance_transfer(msg: NEMSignTx, public_key: bytes) -> bytearray:
|
def serialize_importance_transfer(msg: NEMSignTx, public_key: bytes) -> bytearray:
|
||||||
w = write_common(msg.transaction, bytearray(public_key), NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER)
|
w = write_common(msg.transaction, bytearray(public_key), NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER)
|
||||||
|
|
||||||
@ -83,3 +72,35 @@ def _get_version(network, mosaics=None) -> int:
|
|||||||
if mosaics:
|
if mosaics:
|
||||||
return network << 24 | 2
|
return network << 24 | 2
|
||||||
return network << 24 | 1
|
return network << 24 | 1
|
||||||
|
|
||||||
|
|
||||||
|
def canonicalize_mosaics(mosaics: list):
|
||||||
|
if len(mosaics) <= 1:
|
||||||
|
return mosaics
|
||||||
|
mosaics = merge_mosaics(mosaics)
|
||||||
|
return sort_mosaics(mosaics)
|
||||||
|
|
||||||
|
|
||||||
|
def are_mosaics_equal(a: NEMMosaic, b: NEMMosaic) -> bool:
|
||||||
|
if a.namespace == b.namespace and a.mosaic == b.mosaic:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def merge_mosaics(mosaics: list) -> list:
|
||||||
|
if not len(mosaics):
|
||||||
|
return list()
|
||||||
|
ret = list()
|
||||||
|
for i in mosaics:
|
||||||
|
found = False
|
||||||
|
for k, y in enumerate(ret):
|
||||||
|
if are_mosaics_equal(i, y):
|
||||||
|
ret[k].quantity += i.quantity
|
||||||
|
found = True
|
||||||
|
if not found:
|
||||||
|
ret.append(i)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def sort_mosaics(mosaics: list) -> list:
|
||||||
|
return sorted(mosaics, key=lambda m: (m.namespace, m.mosaic))
|
@ -1,5 +1,5 @@
|
|||||||
from common import *
|
from common import *
|
||||||
from apps.nem.mosaic import *
|
from apps.nem.transfer import *
|
||||||
|
|
||||||
|
|
||||||
class TestNemMosaicCanonicalization(unittest.TestCase):
|
class TestNemMosaicCanonicalization(unittest.TestCase):
|
||||||
|
Loading…
Reference in New Issue
Block a user