From 8de3cd7cacf57dd40fd6b82559c559c55e3b9687 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Thu, 12 Apr 2018 14:53:10 +0200 Subject: [PATCH] nem: refactored to directories --- src/apps/nem/helpers.py | 3 - src/apps/nem/mosaic/__init__.py | 12 +++ src/apps/nem/mosaic/layout.py | 26 ++++++ .../nem/{mosaic.py => mosaic/serialize.py} | 72 +--------------- src/apps/nem/multisig/__init__.py | 29 +++++++ src/apps/nem/multisig/layout.py | 36 ++++++++ .../{multisig.py => multisig/serialize.py} | 37 +------- src/apps/nem/namespace.py | 29 ------- src/apps/nem/namespace/__init__.py | 7 ++ src/apps/nem/namespace/layout.py | 13 +++ src/apps/nem/namespace/serialize.py | 19 +++++ src/apps/nem/signing.py | 84 ++++--------------- src/apps/nem/transfer/__init__.py | 19 +++++ src/apps/nem/transfer/layout.py | 25 ++++++ .../{transfer.py => transfer/serialize.py} | 71 ++++++++++------ .../test_apps.nem.mosaic.canonicalization.py | 2 +- 16 files changed, 256 insertions(+), 228 deletions(-) create mode 100644 src/apps/nem/mosaic/__init__.py create mode 100644 src/apps/nem/mosaic/layout.py rename src/apps/nem/{mosaic.py => mosaic/serialize.py} (56%) create mode 100644 src/apps/nem/multisig/__init__.py create mode 100644 src/apps/nem/multisig/layout.py rename src/apps/nem/{multisig.py => multisig/serialize.py} (54%) delete mode 100644 src/apps/nem/namespace.py create mode 100644 src/apps/nem/namespace/__init__.py create mode 100644 src/apps/nem/namespace/layout.py create mode 100644 src/apps/nem/namespace/serialize.py create mode 100644 src/apps/nem/transfer/__init__.py create mode 100644 src/apps/nem/transfer/layout.py rename src/apps/nem/{transfer.py => transfer/serialize.py} (59%) diff --git a/src/apps/nem/helpers.py b/src/apps/nem/helpers.py index 9e619d00e8..c7f9f65a17 100644 --- a/src/apps/nem/helpers.py +++ b/src/apps/nem/helpers.py @@ -1,7 +1,4 @@ - from micropython import const -from trezor.messages.NEMSignTx import NEMSignTx - NEM_NETWORK_MAINNET = const(0x68) NEM_NETWORK_TESTNET = const(0x98) diff --git a/src/apps/nem/mosaic/__init__.py b/src/apps/nem/mosaic/__init__.py new file mode 100644 index 0000000000..ed5c5c9b42 --- /dev/null +++ b/src/apps/nem/mosaic/__init__.py @@ -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) diff --git a/src/apps/nem/mosaic/layout.py b/src/apps/nem/mosaic/layout.py new file mode 100644 index 0000000000..55a02f39a8 --- /dev/null +++ b/src/apps/nem/mosaic/layout.py @@ -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) diff --git a/src/apps/nem/mosaic.py b/src/apps/nem/mosaic/serialize.py similarity index 56% rename from src/apps/nem/mosaic.py rename to src/apps/nem/mosaic/serialize.py index 77b370c90d..2300923a0d 100644 --- a/src/apps/nem/mosaic.py +++ b/src/apps/nem/mosaic/serialize.py @@ -1,30 +1,6 @@ -from .writers import * -from trezor.messages.NEMMosaic import NEMMosaic -from trezor.messages import NEMSupplyChangeType -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) +from apps.nem.writers import * +from apps.nem.helpers import * +from trezor.messages.NEMSignTx import NEMSignTx 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_bytes_with_length(w, bytearray(name)) 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)) diff --git a/src/apps/nem/multisig/__init__.py b/src/apps/nem/multisig/__init__.py new file mode 100644 index 0000000000..d31fd25a54 --- /dev/null +++ b/src/apps/nem/multisig/__init__.py @@ -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 diff --git a/src/apps/nem/multisig/layout.py b/src/apps/nem/multisig/layout.py new file mode 100644 index 0000000000..199eca4e76 --- /dev/null +++ b/src/apps/nem/multisig/layout.py @@ -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) + diff --git a/src/apps/nem/multisig.py b/src/apps/nem/multisig/serialize.py similarity index 54% rename from src/apps/nem/multisig.py rename to src/apps/nem/multisig/serialize.py index c3e51383f1..6ba49336dd 100644 --- a/src/apps/nem/multisig.py +++ b/src/apps/nem/multisig/serialize.py @@ -1,41 +1,10 @@ -from .writers import * -from apps.nem.layout import * +from apps.nem.writers import * +from apps.nem.helpers import * +from trezor.messages.NEMSignTx import NEMSignTx from trezor.crypto import hashlib -from trezor.messages import NEMModificationType 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): w = write_common(msg, bytearray(public_key), NEM_TRANSACTION_TYPE_MULTISIG) write_bytes_with_length(w, bytearray(inner)) diff --git a/src/apps/nem/namespace.py b/src/apps/nem/namespace.py deleted file mode 100644 index cc720ad904..0000000000 --- a/src/apps/nem/namespace.py +++ /dev/null @@ -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 diff --git a/src/apps/nem/namespace/__init__.py b/src/apps/nem/namespace/__init__.py new file mode 100644 index 0000000000..f6ae3cc708 --- /dev/null +++ b/src/apps/nem/namespace/__init__.py @@ -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) diff --git a/src/apps/nem/namespace/layout.py b/src/apps/nem/namespace/layout.py new file mode 100644 index 0000000000..dcaa3d2fed --- /dev/null +++ b/src/apps/nem/namespace/layout.py @@ -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) diff --git a/src/apps/nem/namespace/serialize.py b/src/apps/nem/namespace/serialize.py new file mode 100644 index 0000000000..9deeddf330 --- /dev/null +++ b/src/apps/nem/namespace/serialize.py @@ -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 diff --git a/src/apps/nem/signing.py b/src/apps/nem/signing.py index 7ff52a5968..d96b49456c 100644 --- a/src/apps/nem/signing.py +++ b/src/apps/nem/signing.py @@ -1,9 +1,9 @@ -from apps.nem.transfer import * -from apps.nem.multisig import * -from apps.nem.namespace import * -from apps.nem.mosaic import * +from apps.nem import namespace +from apps.nem import transfer +from apps.nem import mosaic +from apps.nem import multisig from apps.nem.validators import validate -from apps.nem import helpers +from apps.nem.helpers import * from apps.common import seed from trezor.messages.NEMSignTx import NEMSignTx from trezor.messages.NEMSignedTx import NEMSignedTx @@ -16,31 +16,33 @@ async def sign_tx(ctx, msg: NEMSignTx): if msg.multisig: public_key = msg.multisig.signer - await ask_multisig(ctx, msg) + await multisig.ask(ctx, msg) else: public_key = _get_public_key(node) if msg.transfer: - msg.transfer.mosaics = canonicalize_mosaics(msg.transfer.mosaics) - tx = await _transfer(ctx, public_key, msg, node) + tx = await transfer.transfer(ctx, public_key, msg, node) elif msg.provision_namespace: - tx = await _provision_namespace(ctx, public_key, msg) + tx = await namespace.namespace(ctx, public_key, msg) 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: - tx = await _supply_change(ctx, public_key, msg) + tx = await mosaic.supply_change(ctx, public_key, msg) 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: - tx = await _importance_transfer(ctx, public_key, msg) + tx = await transfer.importance_transfer(ctx, public_key, msg) else: raise ValueError('No transaction provided') if msg.multisig: # 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.data = tx @@ -48,58 +50,6 @@ async def sign_tx(ctx, msg: NEMSignTx): 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: # 0x01 prefix is not part of the actual public key, hence removed 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) diff --git a/src/apps/nem/transfer/__init__.py b/src/apps/nem/transfer/__init__.py new file mode 100644 index 0000000000..7c9cb0d919 --- /dev/null +++ b/src/apps/nem/transfer/__init__.py @@ -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) diff --git a/src/apps/nem/transfer/layout.py b/src/apps/nem/transfer/layout.py new file mode 100644 index 0000000000..bf95c50d26 --- /dev/null +++ b/src/apps/nem/transfer/layout.py @@ -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) diff --git a/src/apps/nem/transfer.py b/src/apps/nem/transfer/serialize.py similarity index 59% rename from src/apps/nem/transfer.py rename to src/apps/nem/transfer/serialize.py index 81b87a399e..6bc7986cf1 100644 --- a/src/apps/nem/transfer.py +++ b/src/apps/nem/transfer/serialize.py @@ -1,31 +1,10 @@ -from .writers import * -from apps.nem.layout import * -from trezor.messages import NEMImportanceTransferMode +from apps.nem.writers import * +from apps.nem.helpers import * +from trezor.messages.NEMMosaic import NEMMosaic +from trezor.messages.NEMSignTx import NEMSignTx 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: tx = write_common(msg.transaction, bytearray(public_key), @@ -52,6 +31,16 @@ def serialize_transfer(msg: NEMSignTx, public_key: bytes, payload: bytes=None, e 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: 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: return network << 24 | 2 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)) diff --git a/tests/test_apps.nem.mosaic.canonicalization.py b/tests/test_apps.nem.mosaic.canonicalization.py index 3de8ab89f3..01c95f1c41 100644 --- a/tests/test_apps.nem.mosaic.canonicalization.py +++ b/tests/test_apps.nem.mosaic.canonicalization.py @@ -1,5 +1,5 @@ from common import * -from apps.nem.mosaic import * +from apps.nem.transfer import * class TestNemMosaicCanonicalization(unittest.TestCase):