mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-17 21:22:10 +00:00
chore(core): decrease nem size by 1550 bytes
This commit is contained in:
parent
32125ef51f
commit
d182ac5b53
@ -1,41 +1,42 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from trezor.messages import NEMAddress
|
|
||||||
from trezor.ui.layouts import show_address
|
|
||||||
|
|
||||||
from apps.common.keychain import with_slip44_keychain
|
from apps.common.keychain import with_slip44_keychain
|
||||||
from apps.common.paths import address_n_to_str, validate_path
|
|
||||||
|
|
||||||
from . import CURVE, PATTERNS, SLIP44_ID
|
from . import CURVE, PATTERNS, SLIP44_ID
|
||||||
from .helpers import check_path, get_network_str
|
|
||||||
from .validators import validate_network
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from apps.common.keychain import Keychain
|
from apps.common.keychain import Keychain
|
||||||
from trezor.wire import Context
|
from trezor.wire import Context
|
||||||
from trezor.messages import NEMGetAddress
|
from trezor.messages import NEMGetAddress, NEMAddress
|
||||||
|
|
||||||
|
|
||||||
@with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE)
|
@with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE)
|
||||||
async def get_address(
|
async def get_address(
|
||||||
ctx: Context, msg: NEMGetAddress, keychain: Keychain
|
ctx: Context, msg: NEMGetAddress, keychain: Keychain
|
||||||
) -> NEMAddress:
|
) -> NEMAddress:
|
||||||
validate_network(msg.network)
|
from trezor.messages import NEMAddress
|
||||||
await validate_path(
|
from trezor.ui.layouts import show_address
|
||||||
ctx, keychain, msg.address_n, check_path(msg.address_n, msg.network)
|
from apps.common.paths import address_n_to_str, validate_path
|
||||||
)
|
from .helpers import check_path, get_network_str
|
||||||
|
from .validators import validate_network
|
||||||
|
|
||||||
node = keychain.derive(msg.address_n)
|
address_n = msg.address_n # local_cache_attribute
|
||||||
address = node.nem_address(msg.network)
|
network = msg.network # local_cache_attribute
|
||||||
|
|
||||||
|
validate_network(network)
|
||||||
|
await validate_path(ctx, keychain, address_n, check_path(address_n, network))
|
||||||
|
|
||||||
|
node = keychain.derive(address_n)
|
||||||
|
address = node.nem_address(network)
|
||||||
|
|
||||||
if msg.show_display:
|
if msg.show_display:
|
||||||
title = address_n_to_str(msg.address_n)
|
title = address_n_to_str(address_n)
|
||||||
await show_address(
|
await show_address(
|
||||||
ctx,
|
ctx,
|
||||||
address=address,
|
address,
|
||||||
case_sensitive=False,
|
case_sensitive=False,
|
||||||
title=title,
|
title=title,
|
||||||
network=get_network_str(msg.network),
|
network=get_network_str(network),
|
||||||
)
|
)
|
||||||
|
|
||||||
return NEMAddress(address=address)
|
return NEMAddress(address=address)
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
from micropython import const
|
from micropython import const
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from apps.common import paths
|
if TYPE_CHECKING:
|
||||||
|
from apps.common import paths
|
||||||
|
|
||||||
from . import SLIP44_ID
|
|
||||||
|
|
||||||
NEM_NETWORK_MAINNET = const(0x68)
|
NEM_NETWORK_MAINNET = const(0x68)
|
||||||
NEM_NETWORK_TESTNET = const(0x98)
|
NEM_NETWORK_TESTNET = const(0x98)
|
||||||
@ -44,6 +45,9 @@ def get_network_str(network: int) -> str:
|
|||||||
|
|
||||||
def check_path(path: paths.Bip32Path, network: int) -> bool:
|
def check_path(path: paths.Bip32Path, network: int) -> bool:
|
||||||
"""Validates that the appropriate coin_type is set for the given network."""
|
"""Validates that the appropriate coin_type is set for the given network."""
|
||||||
|
from apps.common import paths
|
||||||
|
from . import SLIP44_ID
|
||||||
|
|
||||||
if len(path) < 2:
|
if len(path) < 2:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ from typing import TYPE_CHECKING
|
|||||||
|
|
||||||
from trezor.enums import ButtonRequestType
|
from trezor.enums import ButtonRequestType
|
||||||
from trezor.strings import format_amount
|
from trezor.strings import format_amount
|
||||||
from trezor.ui.layouts import confirm_metadata, confirm_properties
|
from trezor.ui.layouts import confirm_metadata
|
||||||
|
|
||||||
from .helpers import NEM_MAX_DIVISIBILITY
|
from .helpers import NEM_MAX_DIVISIBILITY
|
||||||
|
|
||||||
@ -14,8 +14,8 @@ async def require_confirm_text(ctx: Context, action: str) -> None:
|
|||||||
await confirm_metadata(
|
await confirm_metadata(
|
||||||
ctx,
|
ctx,
|
||||||
"confirm_nem",
|
"confirm_nem",
|
||||||
title="Confirm action",
|
"Confirm action",
|
||||||
content=action,
|
action,
|
||||||
hide_continue=True,
|
hide_continue=True,
|
||||||
br_code=ButtonRequestType.ConfirmOutput,
|
br_code=ButtonRequestType.ConfirmOutput,
|
||||||
)
|
)
|
||||||
@ -25,20 +25,22 @@ async def require_confirm_fee(ctx: Context, action: str, fee: int) -> None:
|
|||||||
await confirm_metadata(
|
await confirm_metadata(
|
||||||
ctx,
|
ctx,
|
||||||
"confirm_fee",
|
"confirm_fee",
|
||||||
title="Confirm fee",
|
"Confirm fee",
|
||||||
content=action + "\n{}",
|
action + "\n{}",
|
||||||
param=f"{format_amount(fee, NEM_MAX_DIVISIBILITY)} XEM",
|
f"{format_amount(fee, NEM_MAX_DIVISIBILITY)} XEM",
|
||||||
|
ButtonRequestType.ConfirmOutput,
|
||||||
hide_continue=True,
|
hide_continue=True,
|
||||||
br_code=ButtonRequestType.ConfirmOutput,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def require_confirm_content(ctx: Context, headline: str, content: list) -> None:
|
async def require_confirm_content(ctx: Context, headline: str, content: list) -> None:
|
||||||
|
from trezor.ui.layouts import confirm_properties
|
||||||
|
|
||||||
await confirm_properties(
|
await confirm_properties(
|
||||||
ctx,
|
ctx,
|
||||||
"confirm_content",
|
"confirm_content",
|
||||||
title=headline,
|
headline,
|
||||||
props=content,
|
content,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -47,9 +49,9 @@ async def require_confirm_final(ctx: Context, fee: int) -> None:
|
|||||||
await confirm_metadata(
|
await confirm_metadata(
|
||||||
ctx,
|
ctx,
|
||||||
"confirm_final",
|
"confirm_final",
|
||||||
title="Final confirm",
|
"Final confirm",
|
||||||
content="Sign this transaction\n{}\nfor network fee?",
|
"Sign this transaction\n{}\nfor network fee?",
|
||||||
param=f"and pay {format_amount(fee, NEM_MAX_DIVISIBILITY)} XEM",
|
f"and pay {format_amount(fee, NEM_MAX_DIVISIBILITY)} XEM",
|
||||||
hide_continue=True,
|
hide_continue=True,
|
||||||
hold=True,
|
hold=True,
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from .nem_mosaics import mosaics_iterator
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from trezor.messages import NEMMosaic
|
from trezor.messages import NEMMosaic
|
||||||
|
|
||||||
@ -11,6 +9,8 @@ if TYPE_CHECKING:
|
|||||||
def get_mosaic_definition(
|
def get_mosaic_definition(
|
||||||
namespace_name: str, mosaic_name: str, network: int
|
namespace_name: str, mosaic_name: str, network: int
|
||||||
) -> Mosaic | None:
|
) -> Mosaic | None:
|
||||||
|
from .nem_mosaics import mosaics_iterator
|
||||||
|
|
||||||
for mosaic in mosaics_iterator():
|
for mosaic in mosaics_iterator():
|
||||||
if namespace_name == mosaic.namespace and mosaic_name == mosaic.mosaic:
|
if namespace_name == mosaic.namespace and mosaic_name == mosaic.mosaic:
|
||||||
if (mosaic.networks is None) or (network in mosaic.networks):
|
if (mosaic.networks is None) or (network in mosaic.networks):
|
||||||
|
@ -1,15 +1,6 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from trezor import ui
|
from ..layout import require_confirm_content, require_confirm_final
|
||||||
from trezor.enums import NEMMosaicLevy, NEMSupplyChangeType
|
|
||||||
from trezor.ui.layouts import confirm_properties
|
|
||||||
|
|
||||||
from ..layout import (
|
|
||||||
require_confirm_content,
|
|
||||||
require_confirm_fee,
|
|
||||||
require_confirm_final,
|
|
||||||
require_confirm_text,
|
|
||||||
)
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from trezor.messages import (
|
from trezor.messages import (
|
||||||
@ -24,8 +15,14 @@ if TYPE_CHECKING:
|
|||||||
async def ask_mosaic_creation(
|
async def ask_mosaic_creation(
|
||||||
ctx: Context, common: NEMTransactionCommon, creation: NEMMosaicCreation
|
ctx: Context, common: NEMTransactionCommon, creation: NEMMosaicCreation
|
||||||
) -> None:
|
) -> None:
|
||||||
await require_confirm_content(ctx, "Create mosaic", _creation_message(creation))
|
from ..layout import require_confirm_fee
|
||||||
await require_confirm_properties(ctx, creation.definition)
|
|
||||||
|
creation_message = [
|
||||||
|
("Create mosaic", creation.definition.mosaic),
|
||||||
|
("under namespace", creation.definition.namespace),
|
||||||
|
]
|
||||||
|
await require_confirm_content(ctx, "Create mosaic", creation_message)
|
||||||
|
await _require_confirm_properties(ctx, creation.definition)
|
||||||
await require_confirm_fee(ctx, "Confirm creation fee", creation.fee)
|
await require_confirm_fee(ctx, "Confirm creation fee", creation.fee)
|
||||||
|
|
||||||
await require_confirm_final(ctx, common.fee)
|
await require_confirm_final(ctx, common.fee)
|
||||||
@ -34,57 +31,49 @@ async def ask_mosaic_creation(
|
|||||||
async def ask_supply_change(
|
async def ask_supply_change(
|
||||||
ctx: Context, common: NEMTransactionCommon, change: NEMMosaicSupplyChange
|
ctx: Context, common: NEMTransactionCommon, change: NEMMosaicSupplyChange
|
||||||
) -> None:
|
) -> None:
|
||||||
await require_confirm_content(ctx, "Supply change", _supply_message(change))
|
from trezor.enums import NEMSupplyChangeType
|
||||||
|
from ..layout import require_confirm_text
|
||||||
|
|
||||||
|
supply_message = [
|
||||||
|
("Modify supply for", change.mosaic),
|
||||||
|
("under namespace", change.namespace),
|
||||||
|
]
|
||||||
|
await require_confirm_content(ctx, "Supply change", supply_message)
|
||||||
if change.type == NEMSupplyChangeType.SupplyChange_Decrease:
|
if change.type == NEMSupplyChangeType.SupplyChange_Decrease:
|
||||||
msg = "Decrease supply by " + str(change.delta) + " whole units?"
|
action = "Decrease"
|
||||||
elif change.type == NEMSupplyChangeType.SupplyChange_Increase:
|
elif change.type == NEMSupplyChangeType.SupplyChange_Increase:
|
||||||
msg = "Increase supply by " + str(change.delta) + " whole units?"
|
action = "Increase"
|
||||||
else:
|
else:
|
||||||
raise ValueError("Invalid supply change type")
|
raise ValueError("Invalid supply change type")
|
||||||
await require_confirm_text(ctx, msg)
|
await require_confirm_text(ctx, f"{action} supply by {change.delta} whole units?")
|
||||||
|
|
||||||
await require_confirm_final(ctx, common.fee)
|
await require_confirm_final(ctx, common.fee)
|
||||||
|
|
||||||
|
|
||||||
def _creation_message(mosaic_creation: NEMMosaicCreation) -> list[tuple[str, str]]:
|
async def _require_confirm_properties(
|
||||||
return [
|
|
||||||
("Create mosaic", mosaic_creation.definition.mosaic),
|
|
||||||
("under namespace", mosaic_creation.definition.namespace),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def _supply_message(supply_change: NEMMosaicSupplyChange) -> list[tuple[str, str]]:
|
|
||||||
return [
|
|
||||||
("Modify supply for", supply_change.mosaic),
|
|
||||||
("under namespace", supply_change.namespace),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
async def require_confirm_properties(
|
|
||||||
ctx: Context, definition: NEMMosaicDefinition
|
ctx: Context, definition: NEMMosaicDefinition
|
||||||
) -> None:
|
) -> None:
|
||||||
|
from trezor.enums import NEMMosaicLevy
|
||||||
|
from trezor import ui
|
||||||
|
from trezor.ui.layouts import confirm_properties
|
||||||
|
|
||||||
properties = []
|
properties = []
|
||||||
|
append = properties.append # local_cache_attribute
|
||||||
|
|
||||||
# description
|
# description
|
||||||
if definition.description:
|
if definition.description:
|
||||||
properties.append(("Description:", definition.description))
|
append(("Description:", definition.description))
|
||||||
|
|
||||||
# transferable
|
# transferable
|
||||||
if definition.transferable:
|
transferable = "Yes" if definition.transferable else "No"
|
||||||
transferable = "Yes"
|
append(("Transferable?", transferable))
|
||||||
else:
|
|
||||||
transferable = "No"
|
|
||||||
properties.append(("Transferable?", transferable))
|
|
||||||
|
|
||||||
# mutable_supply
|
# mutable_supply
|
||||||
if definition.mutable_supply:
|
imm = "mutable" if definition.mutable_supply else "immutable"
|
||||||
imm = "mutable"
|
|
||||||
else:
|
|
||||||
imm = "immutable"
|
|
||||||
if definition.supply:
|
if definition.supply:
|
||||||
properties.append(("Initial supply:", str(definition.supply) + "\n" + imm))
|
append(("Initial supply:", str(definition.supply) + "\n" + imm))
|
||||||
else:
|
else:
|
||||||
properties.append(("Initial supply:", imm))
|
append(("Initial supply:", imm))
|
||||||
|
|
||||||
# levy
|
# levy
|
||||||
if definition.levy:
|
if definition.levy:
|
||||||
@ -93,24 +82,25 @@ async def require_confirm_properties(
|
|||||||
assert definition.levy_namespace is not None
|
assert definition.levy_namespace is not None
|
||||||
assert definition.levy_mosaic is not None
|
assert definition.levy_mosaic is not None
|
||||||
|
|
||||||
properties.append(("Levy recipient:", definition.levy_address))
|
append(("Levy recipient:", definition.levy_address))
|
||||||
|
|
||||||
properties.append(("Levy fee:", str(definition.fee)))
|
append(("Levy fee:", str(definition.fee)))
|
||||||
properties.append(("Levy divisibility:", str(definition.divisibility)))
|
append(("Levy divisibility:", str(definition.divisibility)))
|
||||||
|
|
||||||
properties.append(("Levy namespace:", definition.levy_namespace))
|
append(("Levy namespace:", definition.levy_namespace))
|
||||||
properties.append(("Levy mosaic:", definition.levy_mosaic))
|
append(("Levy mosaic:", definition.levy_mosaic))
|
||||||
|
|
||||||
if definition.levy == NEMMosaicLevy.MosaicLevy_Absolute:
|
levy_type = (
|
||||||
levy_type = "absolute"
|
"absolute"
|
||||||
else:
|
if definition.levy == NEMMosaicLevy.MosaicLevy_Absolute
|
||||||
levy_type = "percentile"
|
else "percentile"
|
||||||
properties.append(("Levy type:", levy_type))
|
)
|
||||||
|
append(("Levy type:", levy_type))
|
||||||
|
|
||||||
await confirm_properties(
|
await confirm_properties(
|
||||||
ctx,
|
ctx,
|
||||||
"confirm_properties",
|
"confirm_properties",
|
||||||
title="Confirm properties",
|
"Confirm properties",
|
||||||
props=properties,
|
properties,
|
||||||
icon_color=ui.ORANGE_ICON,
|
icon_color=ui.ORANGE_ICON,
|
||||||
)
|
)
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
# (by running `make templates` in `core`)
|
# (by running `make templates` in `core`)
|
||||||
# do not edit manually!
|
# do not edit manually!
|
||||||
|
|
||||||
|
# NOTE: not supplying the kwargs saves 120 bytes of code size
|
||||||
|
# `networks` needs kwarg as `levy` above is optional
|
||||||
|
|
||||||
from typing import Iterator
|
from typing import Iterator
|
||||||
|
|
||||||
from trezor.enums import NEMMosaicLevy
|
from trezor.enums import NEMMosaicLevy
|
||||||
@ -43,61 +46,65 @@ class Mosaic:
|
|||||||
|
|
||||||
def mosaics_iterator() -> Iterator[Mosaic]:
|
def mosaics_iterator() -> Iterator[Mosaic]:
|
||||||
yield Mosaic(
|
yield Mosaic(
|
||||||
name="NEM",
|
"NEM", # name
|
||||||
ticker=" XEM",
|
" XEM", # ticker
|
||||||
namespace="nem",
|
"nem", # namespace
|
||||||
mosaic="xem",
|
"xem", # mosaic
|
||||||
divisibility=6,
|
6, # divisibility
|
||||||
|
None, # levy
|
||||||
)
|
)
|
||||||
yield Mosaic(
|
yield Mosaic(
|
||||||
name="DIMCOIN",
|
"DIMCOIN", # name
|
||||||
ticker=" DIM",
|
" DIM", # ticker
|
||||||
namespace="dim",
|
"dim", # namespace
|
||||||
mosaic="coin",
|
"coin", # mosaic
|
||||||
divisibility=6,
|
6, # divisibility
|
||||||
levy=MosaicLevy(
|
MosaicLevy( # levy
|
||||||
type=NEMMosaicLevy.MosaicLevy_Percentile,
|
NEMMosaicLevy.MosaicLevy_Percentile, # type
|
||||||
fee=10,
|
10, # fee
|
||||||
namespace="dim",
|
"dim", # namespace
|
||||||
mosaic="coin",
|
"coin", # mosaic
|
||||||
),
|
),
|
||||||
networks=(104,),
|
(104,), # networks
|
||||||
)
|
)
|
||||||
yield Mosaic(
|
yield Mosaic(
|
||||||
name="DIM TOKEN",
|
"DIM TOKEN", # name
|
||||||
ticker=" DIMTOK",
|
" DIMTOK", # ticker
|
||||||
namespace="dim",
|
"dim", # namespace
|
||||||
mosaic="token",
|
"token", # mosaic
|
||||||
divisibility=6,
|
6, # divisibility
|
||||||
networks=(104,),
|
None, # levy
|
||||||
|
(104,), # networks
|
||||||
)
|
)
|
||||||
yield Mosaic(
|
yield Mosaic(
|
||||||
name="Breeze Token",
|
"Breeze Token", # name
|
||||||
ticker=" BREEZE",
|
" BREEZE", # ticker
|
||||||
namespace="breeze",
|
"breeze", # namespace
|
||||||
mosaic="breeze-token",
|
"breeze-token", # mosaic
|
||||||
divisibility=0,
|
0, # divisibility
|
||||||
networks=(104,),
|
None, # levy
|
||||||
|
(104,), # networks
|
||||||
)
|
)
|
||||||
yield Mosaic(
|
yield Mosaic(
|
||||||
name="PacNEM Game Credits",
|
"PacNEM Game Credits", # name
|
||||||
ticker=" PAC:HRT",
|
" PAC:HRT", # ticker
|
||||||
namespace="pacnem",
|
"pacnem", # namespace
|
||||||
mosaic="heart",
|
"heart", # mosaic
|
||||||
divisibility=0,
|
0, # divisibility
|
||||||
networks=(104,),
|
None, # levy
|
||||||
|
(104,), # networks
|
||||||
)
|
)
|
||||||
yield Mosaic(
|
yield Mosaic(
|
||||||
name="PacNEM Score Tokens",
|
"PacNEM Score Tokens", # name
|
||||||
ticker=" PAC:CHS",
|
" PAC:CHS", # ticker
|
||||||
namespace="pacnem",
|
"pacnem", # namespace
|
||||||
mosaic="cheese",
|
"cheese", # mosaic
|
||||||
divisibility=6,
|
6, # divisibility
|
||||||
levy=MosaicLevy(
|
MosaicLevy( # levy
|
||||||
type=NEMMosaicLevy.MosaicLevy_Percentile,
|
NEMMosaicLevy.MosaicLevy_Percentile, # type
|
||||||
fee=100,
|
100, # fee
|
||||||
namespace="nem",
|
"nem", # namespace
|
||||||
mosaic="xem",
|
"xem", # mosaic
|
||||||
),
|
),
|
||||||
networks=(104,),
|
(104,), # networks
|
||||||
)
|
)
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
# (by running `make templates` in `core`)
|
# (by running `make templates` in `core`)
|
||||||
# do not edit manually!
|
# do not edit manually!
|
||||||
|
|
||||||
|
# NOTE: not supplying the kwargs saves 120 bytes of code size
|
||||||
|
# `networks` needs kwarg as `levy` above is optional
|
||||||
|
|
||||||
from typing import Iterator
|
from typing import Iterator
|
||||||
|
|
||||||
from trezor.enums import NEMMosaicLevy
|
from trezor.enums import NEMMosaicLevy
|
||||||
@ -44,21 +47,23 @@ class Mosaic:
|
|||||||
def mosaics_iterator() -> Iterator[Mosaic]:
|
def mosaics_iterator() -> Iterator[Mosaic]:
|
||||||
% for m in supported_on("trezor2", nem):
|
% for m in supported_on("trezor2", nem):
|
||||||
yield Mosaic(
|
yield Mosaic(
|
||||||
name="${m.name}",
|
"${m.name}", # name
|
||||||
ticker=" ${m.ticker}",
|
" ${m.ticker}", # ticker
|
||||||
namespace="${m.namespace}",
|
"${m.namespace}", # namespace
|
||||||
mosaic="${m.mosaic}",
|
"${m.mosaic}", # mosaic
|
||||||
divisibility=${m.divisibility},
|
${m.divisibility}, # divisibility
|
||||||
% if "levy" in m:
|
% if "levy" in m:
|
||||||
levy=MosaicLevy(
|
MosaicLevy( # levy
|
||||||
type=NEMMosaicLevy.${m.levy},
|
NEMMosaicLevy.${m.levy}, # type
|
||||||
fee=${m.fee},
|
${m.fee}, # fee
|
||||||
namespace="${m.levy_namespace}",
|
"${m.levy_namespace}", # namespace
|
||||||
mosaic="${m.levy_mosaic}",
|
"${m.levy_mosaic}", # mosaic
|
||||||
),
|
),
|
||||||
|
% else:
|
||||||
|
None, # levy
|
||||||
% endif
|
% endif
|
||||||
% if "networks" in m:
|
% if "networks" in m:
|
||||||
networks=${tuple(m.networks)},
|
${tuple(m.networks)}, # networks
|
||||||
% endif
|
% endif
|
||||||
)
|
)
|
||||||
% endfor
|
% endfor
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from ..helpers import (
|
|
||||||
NEM_TRANSACTION_TYPE_MOSAIC_CREATION,
|
|
||||||
NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE,
|
|
||||||
)
|
|
||||||
from ..writers import (
|
from ..writers import (
|
||||||
serialize_tx_common,
|
serialize_tx_common,
|
||||||
write_bytes_with_len,
|
write_bytes_with_len,
|
||||||
@ -23,44 +19,43 @@ if TYPE_CHECKING:
|
|||||||
def serialize_mosaic_creation(
|
def serialize_mosaic_creation(
|
||||||
common: NEMTransactionCommon, creation: NEMMosaicCreation, public_key: bytes
|
common: NEMTransactionCommon, creation: NEMMosaicCreation, public_key: bytes
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
|
from ..helpers import NEM_TRANSACTION_TYPE_MOSAIC_CREATION
|
||||||
|
|
||||||
w = serialize_tx_common(common, public_key, NEM_TRANSACTION_TYPE_MOSAIC_CREATION)
|
w = serialize_tx_common(common, public_key, NEM_TRANSACTION_TYPE_MOSAIC_CREATION)
|
||||||
|
|
||||||
mosaics_w = bytearray()
|
mosaics_w = bytearray()
|
||||||
write_bytes_with_len(mosaics_w, public_key)
|
write_bytes_with_len(mosaics_w, public_key)
|
||||||
|
definition = creation.definition # local_cache_attribute
|
||||||
|
|
||||||
identifier_w = bytearray()
|
identifier_w = bytearray()
|
||||||
write_bytes_with_len(identifier_w, creation.definition.namespace.encode())
|
write_bytes_with_len(identifier_w, definition.namespace.encode())
|
||||||
write_bytes_with_len(identifier_w, creation.definition.mosaic.encode())
|
write_bytes_with_len(identifier_w, definition.mosaic.encode())
|
||||||
|
|
||||||
write_bytes_with_len(mosaics_w, identifier_w)
|
write_bytes_with_len(mosaics_w, identifier_w)
|
||||||
write_bytes_with_len(mosaics_w, creation.definition.description.encode())
|
write_bytes_with_len(mosaics_w, definition.description.encode())
|
||||||
write_uint32_le(mosaics_w, 4) # number of properties
|
write_uint32_le(mosaics_w, 4) # number of properties
|
||||||
|
|
||||||
_write_property(mosaics_w, "divisibility", creation.definition.divisibility)
|
_write_property(mosaics_w, "divisibility", definition.divisibility)
|
||||||
_write_property(mosaics_w, "initialSupply", creation.definition.supply)
|
_write_property(mosaics_w, "initialSupply", definition.supply)
|
||||||
_write_property(mosaics_w, "supplyMutable", creation.definition.mutable_supply)
|
_write_property(mosaics_w, "supplyMutable", definition.mutable_supply)
|
||||||
_write_property(mosaics_w, "transferable", creation.definition.transferable)
|
_write_property(mosaics_w, "transferable", definition.transferable)
|
||||||
|
|
||||||
if creation.definition.levy:
|
if definition.levy:
|
||||||
# all below asserts checked by nem.validators._validate_mosaic_creation
|
# all below asserts checked by nem.validators._validate_mosaic_creation
|
||||||
assert creation.definition.levy_namespace is not None
|
assert definition.levy_namespace is not None
|
||||||
assert creation.definition.levy_mosaic is not None
|
assert definition.levy_mosaic is not None
|
||||||
assert creation.definition.levy_address is not None
|
assert definition.levy_address is not None
|
||||||
assert creation.definition.fee is not None
|
assert definition.fee is not None
|
||||||
|
|
||||||
levy_identifier_w = bytearray()
|
levy_identifier_w = bytearray()
|
||||||
write_bytes_with_len(
|
write_bytes_with_len(levy_identifier_w, definition.levy_namespace.encode())
|
||||||
levy_identifier_w, creation.definition.levy_namespace.encode()
|
write_bytes_with_len(levy_identifier_w, definition.levy_mosaic.encode())
|
||||||
)
|
|
||||||
write_bytes_with_len(
|
|
||||||
levy_identifier_w, creation.definition.levy_mosaic.encode()
|
|
||||||
)
|
|
||||||
|
|
||||||
levy_w = bytearray()
|
levy_w = bytearray()
|
||||||
write_uint32_le(levy_w, creation.definition.levy)
|
write_uint32_le(levy_w, definition.levy)
|
||||||
write_bytes_with_len(levy_w, creation.definition.levy_address.encode())
|
write_bytes_with_len(levy_w, definition.levy_address.encode())
|
||||||
write_bytes_with_len(levy_w, levy_identifier_w)
|
write_bytes_with_len(levy_w, levy_identifier_w)
|
||||||
write_uint64_le(levy_w, creation.definition.fee)
|
write_uint64_le(levy_w, definition.fee)
|
||||||
|
|
||||||
write_bytes_with_len(mosaics_w, levy_w)
|
write_bytes_with_len(mosaics_w, levy_w)
|
||||||
else:
|
else:
|
||||||
@ -77,6 +72,8 @@ def serialize_mosaic_creation(
|
|||||||
def serialize_mosaic_supply_change(
|
def serialize_mosaic_supply_change(
|
||||||
common: NEMTransactionCommon, change: NEMMosaicSupplyChange, public_key: bytes
|
common: NEMTransactionCommon, change: NEMMosaicSupplyChange, public_key: bytes
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
|
from ..helpers import NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE
|
||||||
|
|
||||||
w = serialize_tx_common(
|
w = serialize_tx_common(
|
||||||
common, public_key, NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE
|
common, public_key, NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE
|
||||||
)
|
)
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from trezor import ui
|
|
||||||
from trezor.crypto import nem
|
from trezor.crypto import nem
|
||||||
from trezor.enums import ButtonRequestType, NEMModificationType
|
|
||||||
from trezor.ui.layouts import confirm_address
|
|
||||||
|
|
||||||
from ..layout import require_confirm_fee, require_confirm_final, require_confirm_text
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from trezor.messages import (
|
from trezor.messages import (
|
||||||
@ -17,6 +12,8 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
|
|
||||||
async def ask_multisig(ctx: Context, msg: NEMSignTx) -> None:
|
async def ask_multisig(ctx: Context, msg: NEMSignTx) -> None:
|
||||||
|
from ..layout import require_confirm_fee
|
||||||
|
|
||||||
assert msg.multisig is not None # sign_tx
|
assert msg.multisig is not None # sign_tx
|
||||||
assert msg.multisig.signer is not None # sign_tx
|
assert msg.multisig.signer is not None # sign_tx
|
||||||
address = nem.compute_address(msg.multisig.signer, msg.transaction.network)
|
address = nem.compute_address(msg.multisig.signer, msg.transaction.network)
|
||||||
@ -33,6 +30,9 @@ async def ask_aggregate_modification(
|
|||||||
mod: NEMAggregateModification,
|
mod: NEMAggregateModification,
|
||||||
multisig: bool,
|
multisig: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
from trezor.enums import NEMModificationType
|
||||||
|
from ..layout import require_confirm_final, require_confirm_text
|
||||||
|
|
||||||
if not multisig:
|
if not multisig:
|
||||||
await require_confirm_text(ctx, "Convert account to multisig account?")
|
await require_confirm_text(ctx, "Convert account to multisig account?")
|
||||||
|
|
||||||
@ -55,12 +55,14 @@ async def ask_aggregate_modification(
|
|||||||
|
|
||||||
|
|
||||||
async def _require_confirm_address(ctx: Context, action: str, address: str) -> None:
|
async def _require_confirm_address(ctx: Context, action: str, address: str) -> None:
|
||||||
|
from trezor.enums import ButtonRequestType
|
||||||
|
from trezor.ui.layouts import confirm_address
|
||||||
|
|
||||||
await confirm_address(
|
await confirm_address(
|
||||||
ctx,
|
ctx,
|
||||||
br_type="confirm_multisig",
|
"Confirm address",
|
||||||
title="Confirm address",
|
address,
|
||||||
description=action,
|
action,
|
||||||
address=address,
|
"confirm_multisig",
|
||||||
br_code=ButtonRequestType.ConfirmOutput,
|
ButtonRequestType.ConfirmOutput,
|
||||||
icon=ui.ICON_SEND,
|
|
||||||
)
|
)
|
||||||
|
@ -1,12 +1,5 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from trezor.crypto import hashlib, nem
|
|
||||||
|
|
||||||
from ..helpers import (
|
|
||||||
NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION,
|
|
||||||
NEM_TRANSACTION_TYPE_MULTISIG,
|
|
||||||
NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE,
|
|
||||||
)
|
|
||||||
from ..writers import serialize_tx_common, write_bytes_with_len, write_uint32_le
|
from ..writers import serialize_tx_common, write_bytes_with_len, write_uint32_le
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -17,6 +10,8 @@ if TYPE_CHECKING:
|
|||||||
def serialize_multisig(
|
def serialize_multisig(
|
||||||
common: NEMTransactionCommon, public_key: bytes, inner: bytes
|
common: NEMTransactionCommon, public_key: bytes, inner: bytes
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
|
from ..helpers import NEM_TRANSACTION_TYPE_MULTISIG
|
||||||
|
|
||||||
w = serialize_tx_common(common, public_key, NEM_TRANSACTION_TYPE_MULTISIG)
|
w = serialize_tx_common(common, public_key, NEM_TRANSACTION_TYPE_MULTISIG)
|
||||||
write_bytes_with_len(w, inner)
|
write_bytes_with_len(w, inner)
|
||||||
return w
|
return w
|
||||||
@ -28,6 +23,9 @@ def serialize_multisig_signature(
|
|||||||
inner: bytes,
|
inner: bytes,
|
||||||
address_public_key: bytes,
|
address_public_key: bytes,
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
|
from trezor.crypto import hashlib, nem
|
||||||
|
from ..helpers import NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE
|
||||||
|
|
||||||
w = serialize_tx_common(common, public_key, NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE)
|
w = serialize_tx_common(common, public_key, NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE)
|
||||||
digest = hashlib.sha3_256(inner, keccak=True).digest()
|
digest = hashlib.sha3_256(inner, keccak=True).digest()
|
||||||
address = nem.compute_address(address_public_key, common.network)
|
address = nem.compute_address(address_public_key, common.network)
|
||||||
@ -41,6 +39,8 @@ def serialize_multisig_signature(
|
|||||||
def serialize_aggregate_modification(
|
def serialize_aggregate_modification(
|
||||||
common: NEMTransactionCommon, mod: NEMAggregateModification, public_key: bytes
|
common: NEMTransactionCommon, mod: NEMAggregateModification, public_key: bytes
|
||||||
) -> bytearray:
|
) -> bytearray:
|
||||||
|
from ..helpers import NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION
|
||||||
|
|
||||||
version = common.network << 24 | 1
|
version = common.network << 24 | 1
|
||||||
if mod.relative_change:
|
if mod.relative_change:
|
||||||
version = common.network << 24 | 2
|
version = common.network << 24 | 2
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from . import layout, serialize
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from trezor.messages import NEMProvisionNamespace, NEMTransactionCommon
|
from trezor.messages import NEMProvisionNamespace, NEMTransactionCommon
|
||||||
from trezor.wire import Context
|
from trezor.wire import Context
|
||||||
@ -13,5 +11,7 @@ async def namespace(
|
|||||||
common: NEMTransactionCommon,
|
common: NEMTransactionCommon,
|
||||||
namespace: NEMProvisionNamespace,
|
namespace: NEMProvisionNamespace,
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
|
from . import layout, serialize
|
||||||
|
|
||||||
await layout.ask_provision_namespace(ctx, common, namespace)
|
await layout.ask_provision_namespace(ctx, common, namespace)
|
||||||
return serialize.serialize_provision_namespace(common, namespace, public_key)
|
return serialize.serialize_provision_namespace(common, namespace, public_key)
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from ..layout import require_confirm_content, require_confirm_fee, require_confirm_final
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from trezor.messages import NEMProvisionNamespace, NEMTransactionCommon
|
from trezor.messages import NEMProvisionNamespace, NEMTransactionCommon
|
||||||
from trezor.wire import Context
|
from trezor.wire import Context
|
||||||
@ -10,6 +8,12 @@ if TYPE_CHECKING:
|
|||||||
async def ask_provision_namespace(
|
async def ask_provision_namespace(
|
||||||
ctx: Context, common: NEMTransactionCommon, namespace: NEMProvisionNamespace
|
ctx: Context, common: NEMTransactionCommon, namespace: NEMProvisionNamespace
|
||||||
) -> None:
|
) -> None:
|
||||||
|
from ..layout import (
|
||||||
|
require_confirm_content,
|
||||||
|
require_confirm_fee,
|
||||||
|
require_confirm_final,
|
||||||
|
)
|
||||||
|
|
||||||
if namespace.parent:
|
if namespace.parent:
|
||||||
content = [
|
content = [
|
||||||
("Create namespace", namespace.namespace),
|
("Create namespace", namespace.namespace),
|
||||||
|
@ -1,13 +1,5 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from ..helpers import NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE
|
|
||||||
from ..writers import (
|
|
||||||
serialize_tx_common,
|
|
||||||
write_bytes_with_len,
|
|
||||||
write_uint32_le,
|
|
||||||
write_uint64_le,
|
|
||||||
)
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from trezor.messages import NEMProvisionNamespace, NEMTransactionCommon
|
from trezor.messages import NEMProvisionNamespace, NEMTransactionCommon
|
||||||
|
|
||||||
@ -15,6 +7,14 @@ if TYPE_CHECKING:
|
|||||||
def serialize_provision_namespace(
|
def serialize_provision_namespace(
|
||||||
common: NEMTransactionCommon, namespace: NEMProvisionNamespace, public_key: bytes
|
common: NEMTransactionCommon, namespace: NEMProvisionNamespace, public_key: bytes
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
|
from ..helpers import NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE
|
||||||
|
from ..writers import (
|
||||||
|
serialize_tx_common,
|
||||||
|
write_bytes_with_len,
|
||||||
|
write_uint32_le,
|
||||||
|
write_uint64_le,
|
||||||
|
)
|
||||||
|
|
||||||
tx = serialize_tx_common(
|
tx = serialize_tx_common(
|
||||||
common, public_key, NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE
|
common, public_key, NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE
|
||||||
)
|
)
|
||||||
|
@ -1,44 +1,50 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from trezor import wire
|
|
||||||
from trezor.crypto.curve import ed25519
|
|
||||||
from trezor.messages import NEMSignedTx
|
|
||||||
|
|
||||||
from apps.common import seed
|
|
||||||
from apps.common.keychain import with_slip44_keychain
|
from apps.common.keychain import with_slip44_keychain
|
||||||
from apps.common.paths import validate_path
|
|
||||||
|
|
||||||
from . import CURVE, PATTERNS, SLIP44_ID, mosaic, multisig, namespace, transfer
|
from . import CURVE, PATTERNS, SLIP44_ID
|
||||||
from .helpers import NEM_HASH_ALG, check_path
|
|
||||||
from .validators import validate
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from trezor.messages import NEMSignTx
|
from trezor.messages import NEMSignTx, NEMSignedTx
|
||||||
from apps.common.keychain import Keychain
|
from apps.common.keychain import Keychain
|
||||||
|
from trezor.wire import Context
|
||||||
|
|
||||||
|
|
||||||
@with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE)
|
@with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE)
|
||||||
async def sign_tx(ctx: wire.Context, msg: NEMSignTx, keychain: Keychain) -> NEMSignedTx:
|
async def sign_tx(ctx: Context, msg: NEMSignTx, keychain: Keychain) -> NEMSignedTx:
|
||||||
|
from trezor.wire import DataError
|
||||||
|
from trezor.crypto.curve import ed25519
|
||||||
|
from trezor.messages import NEMSignedTx
|
||||||
|
|
||||||
|
from apps.common import seed
|
||||||
|
from apps.common.paths import validate_path
|
||||||
|
|
||||||
|
from . import mosaic, multisig, namespace, transfer
|
||||||
|
from .helpers import NEM_HASH_ALG, check_path
|
||||||
|
from .validators import validate
|
||||||
|
|
||||||
validate(msg)
|
validate(msg)
|
||||||
|
msg_multisig = msg.multisig # local_cache_attribute
|
||||||
|
transaction = msg.transaction # local_cache_attribute
|
||||||
|
|
||||||
await validate_path(
|
await validate_path(
|
||||||
ctx,
|
ctx,
|
||||||
keychain,
|
keychain,
|
||||||
msg.transaction.address_n,
|
transaction.address_n,
|
||||||
check_path(msg.transaction.address_n, msg.transaction.network),
|
check_path(transaction.address_n, transaction.network),
|
||||||
)
|
)
|
||||||
|
|
||||||
node = keychain.derive(msg.transaction.address_n)
|
node = keychain.derive(transaction.address_n)
|
||||||
|
|
||||||
if msg.multisig:
|
if msg_multisig:
|
||||||
if msg.multisig.signer is None:
|
if msg_multisig.signer is None:
|
||||||
raise wire.DataError("No signer provided")
|
raise DataError("No signer provided")
|
||||||
public_key = msg.multisig.signer
|
public_key = msg_multisig.signer
|
||||||
common = msg.multisig
|
common = msg_multisig
|
||||||
await multisig.ask(ctx, msg)
|
await multisig.ask(ctx, msg)
|
||||||
else:
|
else:
|
||||||
public_key = seed.remove_ed25519_prefix(node.public_key())
|
public_key = seed.remove_ed25519_prefix(node.public_key())
|
||||||
common = msg.transaction
|
common = transaction
|
||||||
|
|
||||||
if msg.transfer:
|
if msg.transfer:
|
||||||
tx = await transfer.transfer(ctx, public_key, common, msg.transfer, node)
|
tx = await transfer.transfer(ctx, public_key, common, msg.transfer, node)
|
||||||
@ -54,28 +60,28 @@ async def sign_tx(ctx: wire.Context, msg: NEMSignTx, keychain: Keychain) -> NEMS
|
|||||||
public_key,
|
public_key,
|
||||||
common,
|
common,
|
||||||
msg.aggregate_modification,
|
msg.aggregate_modification,
|
||||||
msg.multisig is not None,
|
msg_multisig is not None,
|
||||||
)
|
)
|
||||||
elif msg.importance_transfer:
|
elif msg.importance_transfer:
|
||||||
tx = await transfer.importance_transfer(
|
tx = await transfer.importance_transfer(
|
||||||
ctx, public_key, common, msg.importance_transfer
|
ctx, public_key, common, msg.importance_transfer
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise wire.DataError("No transaction provided")
|
raise DataError("No transaction provided")
|
||||||
|
|
||||||
if msg.multisig:
|
if msg_multisig:
|
||||||
# wrap transaction in multisig wrapper
|
# wrap transaction in multisig wrapper
|
||||||
if msg.cosigning:
|
if msg.cosigning:
|
||||||
assert msg.multisig.signer is not None
|
assert msg_multisig.signer is not None
|
||||||
tx = multisig.cosign(
|
tx = multisig.cosign(
|
||||||
seed.remove_ed25519_prefix(node.public_key()),
|
seed.remove_ed25519_prefix(node.public_key()),
|
||||||
msg.transaction,
|
transaction,
|
||||||
tx,
|
tx,
|
||||||
msg.multisig.signer,
|
msg_multisig.signer,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
tx = multisig.initiate(
|
tx = multisig.initiate(
|
||||||
seed.remove_ed25519_prefix(node.public_key()), msg.transaction, tx
|
seed.remove_ed25519_prefix(node.public_key()), transaction, tx
|
||||||
)
|
)
|
||||||
|
|
||||||
signature = ed25519.sign(node.private_key(), tx, NEM_HASH_ALG)
|
signature = ed25519.sign(node.private_key(), tx, NEM_HASH_ALG)
|
||||||
|
@ -1,22 +1,12 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from trezor import ui
|
from trezor import ui
|
||||||
from trezor.enums import ButtonRequestType, NEMImportanceTransferMode, NEMMosaicLevy
|
from trezor.enums import ButtonRequestType
|
||||||
from trezor.strings import format_amount
|
from trezor.strings import format_amount
|
||||||
from trezor.ui.layouts import (
|
|
||||||
confirm_action,
|
|
||||||
confirm_output,
|
|
||||||
confirm_properties,
|
|
||||||
confirm_text,
|
|
||||||
)
|
|
||||||
|
|
||||||
from ..helpers import (
|
from ..helpers import NEM_MOSAIC_AMOUNT_DIVISOR
|
||||||
NEM_LEVY_PERCENTILE_DIVISOR_ABSOLUTE,
|
from ..layout import require_confirm_final
|
||||||
NEM_MAX_DIVISIBILITY,
|
from ..mosaic.helpers import is_nem_xem_mosaic
|
||||||
NEM_MOSAIC_AMOUNT_DIVISOR,
|
|
||||||
)
|
|
||||||
from ..layout import require_confirm_final, require_confirm_text
|
|
||||||
from ..mosaic.helpers import get_mosaic_definition, is_nem_xem_mosaic
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from trezor.messages import (
|
from trezor.messages import (
|
||||||
@ -26,7 +16,6 @@ if TYPE_CHECKING:
|
|||||||
NEMTransfer,
|
NEMTransfer,
|
||||||
)
|
)
|
||||||
from trezor.wire import Context
|
from trezor.wire import Context
|
||||||
from ..mosaic.nem_mosaics import MosaicLevy
|
|
||||||
|
|
||||||
|
|
||||||
async def ask_transfer(
|
async def ask_transfer(
|
||||||
@ -35,17 +24,45 @@ async def ask_transfer(
|
|||||||
transfer: NEMTransfer,
|
transfer: NEMTransfer,
|
||||||
encrypted: bool,
|
encrypted: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
from trezor.ui.layouts import confirm_output, confirm_text
|
||||||
|
from ..helpers import NEM_MAX_DIVISIBILITY
|
||||||
|
|
||||||
if transfer.payload:
|
if transfer.payload:
|
||||||
await _require_confirm_payload(ctx, transfer.payload, encrypted)
|
# require_confirm_payload
|
||||||
|
await confirm_text(
|
||||||
|
ctx,
|
||||||
|
"confirm_payload",
|
||||||
|
"Confirm payload",
|
||||||
|
bytes(transfer.payload).decode(),
|
||||||
|
"Encrypted:" if encrypted else "Unencrypted:",
|
||||||
|
ButtonRequestType.ConfirmOutput,
|
||||||
|
icon_color=ui.GREEN if encrypted else ui.RED,
|
||||||
|
)
|
||||||
|
|
||||||
for mosaic in transfer.mosaics:
|
for mosaic in transfer.mosaics:
|
||||||
await ask_transfer_mosaic(ctx, common, transfer, mosaic)
|
await _ask_transfer_mosaic(ctx, common, transfer, mosaic)
|
||||||
await _require_confirm_transfer(ctx, transfer.recipient, _get_xem_amount(transfer))
|
|
||||||
|
# require_confirm_transfer
|
||||||
|
await confirm_output(
|
||||||
|
ctx,
|
||||||
|
transfer.recipient,
|
||||||
|
f"Send {format_amount(_get_xem_amount(transfer), NEM_MAX_DIVISIBILITY)} XEM",
|
||||||
|
ui.BOLD,
|
||||||
|
"Confirm transfer",
|
||||||
|
to_str="\nto\n",
|
||||||
|
)
|
||||||
|
|
||||||
await require_confirm_final(ctx, common.fee)
|
await require_confirm_final(ctx, common.fee)
|
||||||
|
|
||||||
|
|
||||||
async def ask_transfer_mosaic(
|
async def _ask_transfer_mosaic(
|
||||||
ctx: Context, common: NEMTransactionCommon, transfer: NEMTransfer, mosaic: NEMMosaic
|
ctx: Context, common: NEMTransactionCommon, transfer: NEMTransfer, mosaic: NEMMosaic
|
||||||
) -> None:
|
) -> None:
|
||||||
|
from trezor.enums import NEMMosaicLevy
|
||||||
|
from trezor.ui.layouts import confirm_action, confirm_properties
|
||||||
|
from ..mosaic.helpers import get_mosaic_definition
|
||||||
|
from ..helpers import NEM_LEVY_PERCENTILE_DIVISOR_ABSOLUTE
|
||||||
|
|
||||||
if is_nem_xem_mosaic(mosaic):
|
if is_nem_xem_mosaic(mosaic):
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -56,19 +73,26 @@ async def ask_transfer_mosaic(
|
|||||||
await confirm_properties(
|
await confirm_properties(
|
||||||
ctx,
|
ctx,
|
||||||
"confirm_mosaic",
|
"confirm_mosaic",
|
||||||
title="Confirm mosaic",
|
"Confirm mosaic",
|
||||||
props=[
|
(
|
||||||
(
|
(
|
||||||
"Confirm transfer of",
|
"Confirm transfer of",
|
||||||
format_amount(mosaic_quantity, definition.divisibility)
|
format_amount(mosaic_quantity, definition.divisibility)
|
||||||
+ definition.ticker,
|
+ definition.ticker,
|
||||||
),
|
),
|
||||||
("of", definition.name),
|
("of", definition.name),
|
||||||
],
|
),
|
||||||
)
|
)
|
||||||
|
levy = definition.levy # local_cache_attribute
|
||||||
|
|
||||||
|
if levy is not None:
|
||||||
|
if levy == NEMMosaicLevy.MosaicLevy_Absolute:
|
||||||
|
levy_fee = levy.fee
|
||||||
|
else:
|
||||||
|
levy_fee = (
|
||||||
|
mosaic_quantity * levy.fee // NEM_LEVY_PERCENTILE_DIVISOR_ABSOLUTE
|
||||||
|
)
|
||||||
|
|
||||||
if definition.levy is not None:
|
|
||||||
levy_fee = _get_levy_fee(definition.levy, mosaic_quantity)
|
|
||||||
levy_msg = (
|
levy_msg = (
|
||||||
format_amount(levy_fee, definition.divisibility) + definition.ticker
|
format_amount(levy_fee, definition.divisibility) + definition.ticker
|
||||||
)
|
)
|
||||||
@ -76,19 +100,17 @@ async def ask_transfer_mosaic(
|
|||||||
await confirm_properties(
|
await confirm_properties(
|
||||||
ctx,
|
ctx,
|
||||||
"confirm_mosaic_levy",
|
"confirm_mosaic_levy",
|
||||||
title="Confirm mosaic",
|
"Confirm mosaic",
|
||||||
props=[
|
(("Confirm mosaic\nlevy fee of", levy_msg),),
|
||||||
("Confirm mosaic\nlevy fee of", levy_msg),
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
await confirm_action(
|
await confirm_action(
|
||||||
ctx,
|
ctx,
|
||||||
"confirm_mosaic_unknown",
|
"confirm_mosaic_unknown",
|
||||||
title="Confirm mosaic",
|
"Confirm mosaic",
|
||||||
action="Unknown mosaic!",
|
"Unknown mosaic!",
|
||||||
description="Divisibility and levy cannot be shown for unknown mosaics",
|
"Divisibility and levy cannot be shown for unknown mosaics",
|
||||||
icon=ui.ICON_SEND,
|
icon=ui.ICON_SEND,
|
||||||
icon_color=ui.RED,
|
icon_color=ui.RED,
|
||||||
br_code=ButtonRequestType.ConfirmOutput,
|
br_code=ButtonRequestType.ConfirmOutput,
|
||||||
@ -97,11 +119,11 @@ async def ask_transfer_mosaic(
|
|||||||
await confirm_properties(
|
await confirm_properties(
|
||||||
ctx,
|
ctx,
|
||||||
"confirm_mosaic_transfer",
|
"confirm_mosaic_transfer",
|
||||||
title="Confirm mosaic",
|
"Confirm mosaic",
|
||||||
props=[
|
(
|
||||||
("Confirm transfer of", f"{mosaic_quantity} raw units"),
|
("Confirm transfer of", f"{mosaic_quantity} raw units"),
|
||||||
("of", f"{mosaic.namespace}.{mosaic.mosaic}"),
|
("of", f"{mosaic.namespace}.{mosaic.mosaic}"),
|
||||||
],
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -117,44 +139,15 @@ def _get_xem_amount(transfer: NEMTransfer) -> int:
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def _get_levy_fee(levy: MosaicLevy, quantity: int) -> int:
|
|
||||||
if levy.type == NEMMosaicLevy.MosaicLevy_Absolute:
|
|
||||||
return levy.fee
|
|
||||||
else:
|
|
||||||
return quantity * levy.fee // NEM_LEVY_PERCENTILE_DIVISOR_ABSOLUTE
|
|
||||||
|
|
||||||
|
|
||||||
async def ask_importance_transfer(
|
async def ask_importance_transfer(
|
||||||
ctx: Context, common: NEMTransactionCommon, imp: NEMImportanceTransfer
|
ctx: Context, common: NEMTransactionCommon, imp: NEMImportanceTransfer
|
||||||
) -> None:
|
) -> None:
|
||||||
|
from trezor.enums import NEMImportanceTransferMode
|
||||||
|
from ..layout import require_confirm_text
|
||||||
|
|
||||||
if imp.mode == NEMImportanceTransferMode.ImportanceTransfer_Activate:
|
if imp.mode == NEMImportanceTransferMode.ImportanceTransfer_Activate:
|
||||||
m = "Activate"
|
m = "Activate"
|
||||||
else:
|
else:
|
||||||
m = "Deactivate"
|
m = "Deactivate"
|
||||||
await require_confirm_text(ctx, m + " remote harvesting?")
|
await require_confirm_text(ctx, m + " remote harvesting?")
|
||||||
await require_confirm_final(ctx, common.fee)
|
await require_confirm_final(ctx, common.fee)
|
||||||
|
|
||||||
|
|
||||||
async def _require_confirm_transfer(ctx: Context, recipient: str, value: int) -> None:
|
|
||||||
await confirm_output(
|
|
||||||
ctx,
|
|
||||||
recipient,
|
|
||||||
amount=f"Send {format_amount(value, NEM_MAX_DIVISIBILITY)} XEM",
|
|
||||||
font_amount=ui.BOLD,
|
|
||||||
title="Confirm transfer",
|
|
||||||
to_str="\nto\n",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def _require_confirm_payload(
|
|
||||||
ctx: Context, payload: bytes, encrypted: bool = False
|
|
||||||
) -> None:
|
|
||||||
await confirm_text(
|
|
||||||
ctx,
|
|
||||||
"confirm_payload",
|
|
||||||
title="Confirm payload",
|
|
||||||
description="Encrypted:" if encrypted else "Unencrypted:",
|
|
||||||
data=bytes(payload).decode(),
|
|
||||||
icon_color=ui.GREEN if encrypted else ui.RED,
|
|
||||||
br_code=ButtonRequestType.ConfirmOutput,
|
|
||||||
)
|
|
||||||
|
@ -1,19 +1,5 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from trezor.crypto import random
|
|
||||||
from trezor.messages import (
|
|
||||||
NEMImportanceTransfer,
|
|
||||||
NEMMosaic,
|
|
||||||
NEMTransactionCommon,
|
|
||||||
NEMTransfer,
|
|
||||||
)
|
|
||||||
|
|
||||||
from ..helpers import (
|
|
||||||
AES_BLOCK_SIZE,
|
|
||||||
NEM_SALT_SIZE,
|
|
||||||
NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER,
|
|
||||||
NEM_TRANSACTION_TYPE_TRANSFER,
|
|
||||||
)
|
|
||||||
from ..writers import (
|
from ..writers import (
|
||||||
serialize_tx_common,
|
serialize_tx_common,
|
||||||
write_bytes_with_len,
|
write_bytes_with_len,
|
||||||
@ -24,6 +10,12 @@ from ..writers import (
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from trezor.crypto import bip32
|
from trezor.crypto import bip32
|
||||||
from trezor.utils import Writer
|
from trezor.utils import Writer
|
||||||
|
from trezor.messages import (
|
||||||
|
NEMImportanceTransfer,
|
||||||
|
NEMMosaic,
|
||||||
|
NEMTransactionCommon,
|
||||||
|
NEMTransfer,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def serialize_transfer(
|
def serialize_transfer(
|
||||||
@ -33,11 +25,15 @@ def serialize_transfer(
|
|||||||
payload: bytes,
|
payload: bytes,
|
||||||
encrypted: bool,
|
encrypted: bool,
|
||||||
) -> bytearray:
|
) -> bytearray:
|
||||||
|
from ..helpers import NEM_TRANSACTION_TYPE_TRANSFER
|
||||||
|
from ..writers import write_uint32_le
|
||||||
|
|
||||||
|
version = common.network << 24 | 2 if transfer.mosaics else common.network << 24 | 1
|
||||||
tx = serialize_tx_common(
|
tx = serialize_tx_common(
|
||||||
common,
|
common,
|
||||||
public_key,
|
public_key,
|
||||||
NEM_TRANSACTION_TYPE_TRANSFER,
|
NEM_TRANSACTION_TYPE_TRANSFER,
|
||||||
_get_version(common.network, transfer.mosaics),
|
version,
|
||||||
)
|
)
|
||||||
|
|
||||||
write_bytes_with_len(tx, transfer.recipient.encode())
|
write_bytes_with_len(tx, transfer.recipient.encode())
|
||||||
@ -75,6 +71,8 @@ def serialize_mosaic(w: Writer, namespace: str, mosaic: str, quantity: int) -> N
|
|||||||
def serialize_importance_transfer(
|
def serialize_importance_transfer(
|
||||||
common: NEMTransactionCommon, imp: NEMImportanceTransfer, public_key: bytes
|
common: NEMTransactionCommon, imp: NEMImportanceTransfer, public_key: bytes
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
|
from ..helpers import NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER
|
||||||
|
|
||||||
w = serialize_tx_common(
|
w = serialize_tx_common(
|
||||||
common, public_key, NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER
|
common, public_key, NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER
|
||||||
)
|
)
|
||||||
@ -87,55 +85,45 @@ def serialize_importance_transfer(
|
|||||||
def get_transfer_payload(
|
def get_transfer_payload(
|
||||||
transfer: NEMTransfer, node: bip32.HDNode
|
transfer: NEMTransfer, node: bip32.HDNode
|
||||||
) -> tuple[bytes, bool]:
|
) -> tuple[bytes, bool]:
|
||||||
|
from trezor.crypto import random
|
||||||
|
from ..helpers import (
|
||||||
|
AES_BLOCK_SIZE,
|
||||||
|
NEM_SALT_SIZE,
|
||||||
|
)
|
||||||
|
|
||||||
if transfer.public_key is not None:
|
if transfer.public_key is not None:
|
||||||
if not transfer.payload:
|
if not transfer.payload:
|
||||||
raise ValueError("Public key provided but no payload to encrypt")
|
raise ValueError("Public key provided but no payload to encrypt")
|
||||||
encrypted_payload = _encrypt(node, transfer.public_key, transfer.payload)
|
|
||||||
|
# encrypt payload
|
||||||
|
salt = random.bytes(NEM_SALT_SIZE)
|
||||||
|
iv = random.bytes(AES_BLOCK_SIZE)
|
||||||
|
encrypted = node.nem_encrypt(transfer.public_key, iv, salt, transfer.payload)
|
||||||
|
encrypted_payload = iv + salt + encrypted
|
||||||
|
|
||||||
return encrypted_payload, True
|
return encrypted_payload, True
|
||||||
else:
|
else:
|
||||||
return transfer.payload or b"", False
|
return transfer.payload or b"", False
|
||||||
|
|
||||||
|
|
||||||
def _encrypt(node: bip32.HDNode, public_key: bytes, payload: bytes) -> bytes:
|
|
||||||
salt = random.bytes(NEM_SALT_SIZE)
|
|
||||||
iv = random.bytes(AES_BLOCK_SIZE)
|
|
||||||
encrypted = node.nem_encrypt(public_key, iv, salt, payload)
|
|
||||||
return iv + salt + encrypted
|
|
||||||
|
|
||||||
|
|
||||||
def _get_version(network: int, mosaics: list[NEMMosaic] | None = None) -> int:
|
|
||||||
if mosaics:
|
|
||||||
return network << 24 | 2
|
|
||||||
return network << 24 | 1
|
|
||||||
|
|
||||||
|
|
||||||
def canonicalize_mosaics(mosaics: list[NEMMosaic]) -> list[NEMMosaic]:
|
def canonicalize_mosaics(mosaics: list[NEMMosaic]) -> list[NEMMosaic]:
|
||||||
if len(mosaics) <= 1:
|
if len(mosaics) <= 1:
|
||||||
return mosaics
|
return mosaics
|
||||||
mosaics = merge_mosaics(mosaics)
|
mosaics = _merge_mosaics(mosaics)
|
||||||
return sort_mosaics(mosaics)
|
return sorted(mosaics, key=lambda m: (m.namespace, m.mosaic))
|
||||||
|
|
||||||
|
|
||||||
def are_mosaics_equal(a: NEMMosaic, b: NEMMosaic) -> bool:
|
def _merge_mosaics(mosaics: list[NEMMosaic]) -> list[NEMMosaic]:
|
||||||
if a.namespace == b.namespace and a.mosaic == b.mosaic:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def merge_mosaics(mosaics: list[NEMMosaic]) -> list[NEMMosaic]:
|
|
||||||
if not mosaics:
|
if not mosaics:
|
||||||
return []
|
return []
|
||||||
ret: list[NEMMosaic] = []
|
ret: list[NEMMosaic] = []
|
||||||
for i in mosaics:
|
for i in mosaics:
|
||||||
found = False
|
found = False
|
||||||
for k, y in enumerate(ret):
|
for k, y in enumerate(ret):
|
||||||
if are_mosaics_equal(i, y):
|
# are_mosaics_equal
|
||||||
|
if i.namespace == y.namespace and i.mosaic == y.mosaic:
|
||||||
ret[k].quantity += i.quantity
|
ret[k].quantity += i.quantity
|
||||||
found = True
|
found = True
|
||||||
if not found:
|
if not found:
|
||||||
ret.append(i)
|
ret.append(i)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def sort_mosaics(mosaics: list[NEMMosaic]) -> list[NEMMosaic]:
|
|
||||||
return sorted(mosaics, key=lambda m: (m.namespace, m.mosaic))
|
|
||||||
|
@ -1,72 +1,37 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from trezor.crypto import nem
|
|
||||||
from trezor.enums import NEMModificationType
|
|
||||||
from trezor.wire import ProcessError
|
from trezor.wire import ProcessError
|
||||||
|
|
||||||
from .helpers import (
|
|
||||||
NEM_MAX_DIVISIBILITY,
|
|
||||||
NEM_MAX_ENCRYPTED_PAYLOAD_SIZE,
|
|
||||||
NEM_MAX_PLAIN_PAYLOAD_SIZE,
|
|
||||||
NEM_MAX_SUPPLY,
|
|
||||||
NEM_NETWORK_MAINNET,
|
|
||||||
NEM_NETWORK_MIJIN,
|
|
||||||
NEM_NETWORK_TESTNET,
|
|
||||||
NEM_PUBLIC_KEY_SIZE,
|
|
||||||
)
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from trezor.messages import (
|
from trezor.messages import NEMSignTx, NEMTransactionCommon
|
||||||
NEMAggregateModification,
|
|
||||||
NEMImportanceTransfer,
|
|
||||||
NEMMosaicCreation,
|
|
||||||
NEMMosaicSupplyChange,
|
|
||||||
NEMProvisionNamespace,
|
|
||||||
NEMSignTx,
|
|
||||||
NEMTransactionCommon,
|
|
||||||
NEMTransfer,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def validate(msg: NEMSignTx) -> None:
|
def validate(msg: NEMSignTx) -> None:
|
||||||
_validate_single_tx(msg)
|
from trezor.crypto import nem
|
||||||
_validate_common(msg.transaction)
|
from trezor.enums import NEMModificationType
|
||||||
|
from trezor.wire import ProcessError # local_cache_global
|
||||||
|
from .helpers import (
|
||||||
|
NEM_MAX_ENCRYPTED_PAYLOAD_SIZE,
|
||||||
|
NEM_MAX_PLAIN_PAYLOAD_SIZE,
|
||||||
|
NEM_MAX_DIVISIBILITY,
|
||||||
|
NEM_MAX_SUPPLY,
|
||||||
|
)
|
||||||
|
|
||||||
if msg.multisig:
|
validate_address = nem.validate_address # local_cache_attribute
|
||||||
_validate_common(msg.multisig, inner=True)
|
transfer = msg.transfer # local_cache_attribute
|
||||||
_validate_multisig(msg.multisig, msg.transaction.network)
|
aggregate_modification = msg.aggregate_modification # local_cache_attribute
|
||||||
if not msg.multisig and msg.cosigning:
|
multisig = msg.multisig # local_cache_attribute
|
||||||
raise ProcessError("No multisig transaction to cosign")
|
mosaic_creation = msg.mosaic_creation # local_cache_attribute
|
||||||
|
network = msg.transaction.network # local_cache_attribute
|
||||||
|
|
||||||
if msg.transfer:
|
# _validate_single_tx
|
||||||
_validate_transfer(msg.transfer, msg.transaction.network)
|
|
||||||
if msg.provision_namespace:
|
|
||||||
_validate_provision_namespace(msg.provision_namespace, msg.transaction.network)
|
|
||||||
if msg.mosaic_creation:
|
|
||||||
_validate_mosaic_creation(msg.mosaic_creation, msg.transaction.network)
|
|
||||||
if msg.supply_change:
|
|
||||||
_validate_supply_change(msg.supply_change)
|
|
||||||
if msg.aggregate_modification:
|
|
||||||
_validate_aggregate_modification(
|
|
||||||
msg.aggregate_modification, msg.multisig is None
|
|
||||||
)
|
|
||||||
if msg.importance_transfer:
|
|
||||||
_validate_importance_transfer(msg.importance_transfer)
|
|
||||||
|
|
||||||
|
|
||||||
def validate_network(network: int) -> None:
|
|
||||||
if network not in (NEM_NETWORK_MAINNET, NEM_NETWORK_TESTNET, NEM_NETWORK_MIJIN):
|
|
||||||
raise ProcessError("Invalid NEM network")
|
|
||||||
|
|
||||||
|
|
||||||
def _validate_single_tx(msg: NEMSignTx) -> None:
|
|
||||||
# ensure exactly one transaction is provided
|
# ensure exactly one transaction is provided
|
||||||
tx_count = (
|
tx_count = (
|
||||||
bool(msg.transfer)
|
bool(transfer)
|
||||||
+ bool(msg.provision_namespace)
|
+ bool(msg.provision_namespace)
|
||||||
+ bool(msg.mosaic_creation)
|
+ bool(mosaic_creation)
|
||||||
+ bool(msg.supply_change)
|
+ bool(msg.supply_change)
|
||||||
+ bool(msg.aggregate_modification)
|
+ bool(aggregate_modification)
|
||||||
+ bool(msg.importance_transfer)
|
+ bool(msg.importance_transfer)
|
||||||
)
|
)
|
||||||
if tx_count == 0:
|
if tx_count == 0:
|
||||||
@ -74,16 +39,145 @@ def _validate_single_tx(msg: NEMSignTx) -> None:
|
|||||||
if tx_count > 1:
|
if tx_count > 1:
|
||||||
raise ProcessError("More than one transaction provided")
|
raise ProcessError("More than one transaction provided")
|
||||||
|
|
||||||
|
_validate_common(msg.transaction)
|
||||||
|
|
||||||
|
if multisig:
|
||||||
|
_validate_common(multisig, True)
|
||||||
|
# _validate_multisig
|
||||||
|
if multisig.network != network:
|
||||||
|
raise ProcessError("Inner transaction network is different")
|
||||||
|
_validate_public_key(
|
||||||
|
multisig.signer, "Invalid multisig signer public key provided"
|
||||||
|
)
|
||||||
|
# END _validate_multisig
|
||||||
|
if not multisig and msg.cosigning:
|
||||||
|
raise ProcessError("No multisig transaction to cosign")
|
||||||
|
|
||||||
|
if transfer:
|
||||||
|
payload = transfer.payload # local_cache_attribute
|
||||||
|
|
||||||
|
if transfer.public_key is not None:
|
||||||
|
_validate_public_key(transfer.public_key, "Invalid recipient public key")
|
||||||
|
if not payload:
|
||||||
|
raise ProcessError("Public key provided but no payload to encrypt")
|
||||||
|
|
||||||
|
if payload:
|
||||||
|
if len(payload) > NEM_MAX_PLAIN_PAYLOAD_SIZE:
|
||||||
|
raise ProcessError("Payload too large")
|
||||||
|
if transfer.public_key and len(payload) > NEM_MAX_ENCRYPTED_PAYLOAD_SIZE:
|
||||||
|
raise ProcessError("Payload too large")
|
||||||
|
|
||||||
|
if not validate_address(transfer.recipient, network):
|
||||||
|
raise ProcessError("Invalid recipient address")
|
||||||
|
# END _validate_transfer
|
||||||
|
if msg.provision_namespace:
|
||||||
|
# _validate_provision_namespace
|
||||||
|
if not validate_address(msg.provision_namespace.sink, network):
|
||||||
|
raise ProcessError("Invalid rental sink address")
|
||||||
|
# END _validate_provision_namespace
|
||||||
|
if mosaic_creation:
|
||||||
|
# _validate_mosaic_creation
|
||||||
|
if not validate_address(mosaic_creation.sink, network):
|
||||||
|
raise ProcessError("Invalid creation sink address")
|
||||||
|
definition = mosaic_creation.definition # local_cache_attribute
|
||||||
|
supply = definition.supply # local_cache_attribute
|
||||||
|
divisibility = definition.divisibility # local_cache_attribute
|
||||||
|
|
||||||
|
if definition.name is not None:
|
||||||
|
raise ProcessError("Name not allowed in mosaic creation transactions")
|
||||||
|
if definition.ticker is not None:
|
||||||
|
raise ProcessError("Ticker not allowed in mosaic creation transactions")
|
||||||
|
if definition.networks:
|
||||||
|
raise ProcessError("Networks not allowed in mosaic creation transactions")
|
||||||
|
|
||||||
|
if supply is not None and divisibility is None:
|
||||||
|
raise ProcessError(
|
||||||
|
"Definition divisibility needs to be provided when supply is"
|
||||||
|
)
|
||||||
|
if supply is None and divisibility is not None:
|
||||||
|
raise ProcessError(
|
||||||
|
"Definition supply needs to be provided when divisibility is"
|
||||||
|
)
|
||||||
|
|
||||||
|
if definition.levy is not None:
|
||||||
|
if definition.fee is None:
|
||||||
|
raise ProcessError("No levy fee provided")
|
||||||
|
if definition.levy_address is None:
|
||||||
|
raise ProcessError("No levy address provided")
|
||||||
|
if definition.levy_namespace is None:
|
||||||
|
raise ProcessError("No levy namespace provided")
|
||||||
|
if definition.levy_mosaic is None:
|
||||||
|
raise ProcessError("No levy mosaic name provided")
|
||||||
|
|
||||||
|
if divisibility is None:
|
||||||
|
raise ProcessError("No divisibility provided")
|
||||||
|
if supply is None:
|
||||||
|
raise ProcessError("No supply provided")
|
||||||
|
if definition.mutable_supply is None:
|
||||||
|
raise ProcessError("No supply mutability provided")
|
||||||
|
if definition.transferable is None:
|
||||||
|
raise ProcessError("No mosaic transferability provided")
|
||||||
|
if definition.description is None:
|
||||||
|
raise ProcessError("No description provided")
|
||||||
|
|
||||||
|
if divisibility > NEM_MAX_DIVISIBILITY:
|
||||||
|
raise ProcessError("Invalid divisibility provided")
|
||||||
|
if supply > NEM_MAX_SUPPLY:
|
||||||
|
raise ProcessError("Invalid supply provided")
|
||||||
|
|
||||||
|
if not validate_address(definition.levy_address, network):
|
||||||
|
raise ProcessError("Invalid levy address")
|
||||||
|
# END _validate_mosaic_creation
|
||||||
|
if msg.supply_change:
|
||||||
|
# _validate_supply_change
|
||||||
|
pass
|
||||||
|
# END _validate_supply_change
|
||||||
|
if aggregate_modification:
|
||||||
|
# _validate_aggregate_modification
|
||||||
|
creation = multisig is None
|
||||||
|
if creation and not aggregate_modification.modifications:
|
||||||
|
raise ProcessError("No modifications provided")
|
||||||
|
|
||||||
|
for m in aggregate_modification.modifications:
|
||||||
|
if (
|
||||||
|
creation
|
||||||
|
and m.type == NEMModificationType.CosignatoryModification_Delete
|
||||||
|
):
|
||||||
|
raise ProcessError("Cannot remove cosignatory when converting account")
|
||||||
|
_validate_public_key(
|
||||||
|
m.public_key, "Invalid cosignatory public key provided"
|
||||||
|
)
|
||||||
|
# END _validate_aggregate_modification
|
||||||
|
if msg.importance_transfer:
|
||||||
|
# _validate_importance_transfer
|
||||||
|
_validate_public_key(
|
||||||
|
msg.importance_transfer.public_key,
|
||||||
|
"Invalid remote account public key provided",
|
||||||
|
)
|
||||||
|
# END _validate_importance_transfer
|
||||||
|
|
||||||
|
|
||||||
|
def validate_network(network: int) -> None:
|
||||||
|
from .helpers import (
|
||||||
|
NEM_NETWORK_MAINNET,
|
||||||
|
NEM_NETWORK_MIJIN,
|
||||||
|
NEM_NETWORK_TESTNET,
|
||||||
|
)
|
||||||
|
|
||||||
|
if network not in (NEM_NETWORK_MAINNET, NEM_NETWORK_TESTNET, NEM_NETWORK_MIJIN):
|
||||||
|
raise ProcessError("Invalid NEM network")
|
||||||
|
|
||||||
|
|
||||||
def _validate_common(common: NEMTransactionCommon, inner: bool = False) -> None:
|
def _validate_common(common: NEMTransactionCommon, inner: bool = False) -> None:
|
||||||
validate_network(common.network)
|
validate_network(common.network)
|
||||||
|
signer = common.signer # local_cache_attribute
|
||||||
|
|
||||||
err = None
|
err = None
|
||||||
|
|
||||||
if not inner and common.signer:
|
if not inner and signer:
|
||||||
raise ProcessError("Signer not allowed in outer transaction")
|
raise ProcessError("Signer not allowed in outer transaction")
|
||||||
|
|
||||||
if inner and common.signer is None:
|
if inner and signer is None:
|
||||||
err = "signer"
|
err = "signer"
|
||||||
|
|
||||||
if err:
|
if err:
|
||||||
@ -92,125 +186,14 @@ def _validate_common(common: NEMTransactionCommon, inner: bool = False) -> None:
|
|||||||
else:
|
else:
|
||||||
raise ProcessError(f"No {err} provided")
|
raise ProcessError(f"No {err} provided")
|
||||||
|
|
||||||
if common.signer is not None:
|
if signer is not None:
|
||||||
_validate_public_key(
|
_validate_public_key(signer, "Invalid signer public key in inner transaction")
|
||||||
common.signer, "Invalid signer public key in inner transaction"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _validate_public_key(public_key: bytes | None, err_msg: str) -> None:
|
def _validate_public_key(public_key: bytes | None, err_msg: str) -> None:
|
||||||
|
from .helpers import NEM_PUBLIC_KEY_SIZE
|
||||||
|
|
||||||
if not public_key:
|
if not public_key:
|
||||||
raise ProcessError(f"{err_msg} (none provided)")
|
raise ProcessError(f"{err_msg} (none provided)")
|
||||||
if len(public_key) != NEM_PUBLIC_KEY_SIZE:
|
if len(public_key) != NEM_PUBLIC_KEY_SIZE:
|
||||||
raise ProcessError(f"{err_msg} (invalid length)")
|
raise ProcessError(f"{err_msg} (invalid length)")
|
||||||
|
|
||||||
|
|
||||||
def _validate_importance_transfer(importance_transfer: NEMImportanceTransfer) -> None:
|
|
||||||
_validate_public_key(
|
|
||||||
importance_transfer.public_key, "Invalid remote account public key provided"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _validate_multisig(multisig: NEMTransactionCommon, network: int) -> None:
|
|
||||||
if multisig.network != network:
|
|
||||||
raise ProcessError("Inner transaction network is different")
|
|
||||||
_validate_public_key(multisig.signer, "Invalid multisig signer public key provided")
|
|
||||||
|
|
||||||
|
|
||||||
def _validate_aggregate_modification(
|
|
||||||
aggregate_modification: NEMAggregateModification, creation: bool = False
|
|
||||||
) -> None:
|
|
||||||
|
|
||||||
if creation and not aggregate_modification.modifications:
|
|
||||||
raise ProcessError("No modifications provided")
|
|
||||||
|
|
||||||
for m in aggregate_modification.modifications:
|
|
||||||
if creation and m.type == NEMModificationType.CosignatoryModification_Delete:
|
|
||||||
raise ProcessError("Cannot remove cosignatory when converting account")
|
|
||||||
_validate_public_key(m.public_key, "Invalid cosignatory public key provided")
|
|
||||||
|
|
||||||
|
|
||||||
def _validate_supply_change(supply_change: NEMMosaicSupplyChange) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def _validate_mosaic_creation(mosaic_creation: NEMMosaicCreation, network: int) -> None:
|
|
||||||
if not nem.validate_address(mosaic_creation.sink, network):
|
|
||||||
raise ProcessError("Invalid creation sink address")
|
|
||||||
|
|
||||||
if mosaic_creation.definition.name is not None:
|
|
||||||
raise ProcessError("Name not allowed in mosaic creation transactions")
|
|
||||||
if mosaic_creation.definition.ticker is not None:
|
|
||||||
raise ProcessError("Ticker not allowed in mosaic creation transactions")
|
|
||||||
if mosaic_creation.definition.networks:
|
|
||||||
raise ProcessError("Networks not allowed in mosaic creation transactions")
|
|
||||||
|
|
||||||
if (
|
|
||||||
mosaic_creation.definition.supply is not None
|
|
||||||
and mosaic_creation.definition.divisibility is None
|
|
||||||
):
|
|
||||||
raise ProcessError(
|
|
||||||
"Definition divisibility needs to be provided when supply is"
|
|
||||||
)
|
|
||||||
if (
|
|
||||||
mosaic_creation.definition.supply is None
|
|
||||||
and mosaic_creation.definition.divisibility is not None
|
|
||||||
):
|
|
||||||
raise ProcessError(
|
|
||||||
"Definition supply needs to be provided when divisibility is"
|
|
||||||
)
|
|
||||||
|
|
||||||
if mosaic_creation.definition.levy is not None:
|
|
||||||
if mosaic_creation.definition.fee is None:
|
|
||||||
raise ProcessError("No levy fee provided")
|
|
||||||
if mosaic_creation.definition.levy_address is None:
|
|
||||||
raise ProcessError("No levy address provided")
|
|
||||||
if mosaic_creation.definition.levy_namespace is None:
|
|
||||||
raise ProcessError("No levy namespace provided")
|
|
||||||
if mosaic_creation.definition.levy_mosaic is None:
|
|
||||||
raise ProcessError("No levy mosaic name provided")
|
|
||||||
|
|
||||||
if mosaic_creation.definition.divisibility is None:
|
|
||||||
raise ProcessError("No divisibility provided")
|
|
||||||
if mosaic_creation.definition.supply is None:
|
|
||||||
raise ProcessError("No supply provided")
|
|
||||||
if mosaic_creation.definition.mutable_supply is None:
|
|
||||||
raise ProcessError("No supply mutability provided")
|
|
||||||
if mosaic_creation.definition.transferable is None:
|
|
||||||
raise ProcessError("No mosaic transferability provided")
|
|
||||||
if mosaic_creation.definition.description is None:
|
|
||||||
raise ProcessError("No description provided")
|
|
||||||
|
|
||||||
if mosaic_creation.definition.divisibility > NEM_MAX_DIVISIBILITY:
|
|
||||||
raise ProcessError("Invalid divisibility provided")
|
|
||||||
if mosaic_creation.definition.supply > NEM_MAX_SUPPLY:
|
|
||||||
raise ProcessError("Invalid supply provided")
|
|
||||||
|
|
||||||
if not nem.validate_address(mosaic_creation.definition.levy_address, network):
|
|
||||||
raise ProcessError("Invalid levy address")
|
|
||||||
|
|
||||||
|
|
||||||
def _validate_provision_namespace(
|
|
||||||
provision_namespace: NEMProvisionNamespace, network: int
|
|
||||||
) -> None:
|
|
||||||
if not nem.validate_address(provision_namespace.sink, network):
|
|
||||||
raise ProcessError("Invalid rental sink address")
|
|
||||||
|
|
||||||
|
|
||||||
def _validate_transfer(transfer: NEMTransfer, network: int) -> None:
|
|
||||||
if transfer.public_key is not None:
|
|
||||||
_validate_public_key(transfer.public_key, "Invalid recipient public key")
|
|
||||||
if not transfer.payload:
|
|
||||||
raise ProcessError("Public key provided but no payload to encrypt")
|
|
||||||
|
|
||||||
if transfer.payload:
|
|
||||||
if len(transfer.payload) > NEM_MAX_PLAIN_PAYLOAD_SIZE:
|
|
||||||
raise ProcessError("Payload too large")
|
|
||||||
if (
|
|
||||||
transfer.public_key
|
|
||||||
and len(transfer.payload) > NEM_MAX_ENCRYPTED_PAYLOAD_SIZE
|
|
||||||
):
|
|
||||||
raise ProcessError("Payload too large")
|
|
||||||
|
|
||||||
if not nem.validate_address(transfer.recipient, network):
|
|
||||||
raise ProcessError("Invalid recipient address")
|
|
||||||
|
@ -5,6 +5,7 @@ if not utils.BITCOIN_ONLY:
|
|||||||
from apps.nem.mosaic.helpers import get_mosaic_definition
|
from apps.nem.mosaic.helpers import get_mosaic_definition
|
||||||
from apps.nem.transfer import *
|
from apps.nem.transfer import *
|
||||||
from apps.nem.transfer.serialize import *
|
from apps.nem.transfer.serialize import *
|
||||||
|
from apps.nem.transfer.serialize import _merge_mosaics
|
||||||
|
|
||||||
|
|
||||||
def get_mosaic(namespace: str, quantity: int, mosaic: str) -> NEMMosaic:
|
def get_mosaic(namespace: str, quantity: int, mosaic: str) -> NEMMosaic:
|
||||||
@ -15,6 +16,11 @@ def get_mosaic(namespace: str, quantity: int, mosaic: str) -> NEMMosaic:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# NOTE: copy-pasted from apps.nem.transfer.serialize.py
|
||||||
|
def sort_mosaics(mosaics: list[NEMMosaic]) -> list[NEMMosaic]:
|
||||||
|
return sorted(mosaics, key=lambda m: (m.namespace, m.mosaic))
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(not utils.BITCOIN_ONLY, "altcoin")
|
@unittest.skipUnless(not utils.BITCOIN_ONLY, "altcoin")
|
||||||
class TestNemMosaic(unittest.TestCase):
|
class TestNemMosaic(unittest.TestCase):
|
||||||
|
|
||||||
@ -54,20 +60,20 @@ class TestNemMosaic(unittest.TestCase):
|
|||||||
b = get_mosaic("abc", 1, "mosaic")
|
b = get_mosaic("abc", 1, "mosaic")
|
||||||
c = get_mosaic("abc", 2, "xxx")
|
c = get_mosaic("abc", 2, "xxx")
|
||||||
|
|
||||||
merged = merge_mosaics([a, b])
|
merged = _merge_mosaics([a, b])
|
||||||
self.assertEqual(merged[0].quantity, 2)
|
self.assertEqual(merged[0].quantity, 2)
|
||||||
self.assertEqual(len(merged), 1)
|
self.assertEqual(len(merged), 1)
|
||||||
|
|
||||||
a.quantity = 1
|
a.quantity = 1
|
||||||
b.quantity = 10
|
b.quantity = 10
|
||||||
merged = merge_mosaics([a, b])
|
merged = _merge_mosaics([a, b])
|
||||||
self.assertEqual(merged[0].quantity, 11)
|
self.assertEqual(merged[0].quantity, 11)
|
||||||
|
|
||||||
a.namespace = "abcdef"
|
a.namespace = "abcdef"
|
||||||
merged = merge_mosaics([a, b])
|
merged = _merge_mosaics([a, b])
|
||||||
self.assertEqual(len(merged), 2)
|
self.assertEqual(len(merged), 2)
|
||||||
|
|
||||||
merged = merge_mosaics([a, b, c])
|
merged = _merge_mosaics([a, b, c])
|
||||||
self.assertEqual(len(merged), 3)
|
self.assertEqual(len(merged), 3)
|
||||||
|
|
||||||
a.namespace = "abcdef"
|
a.namespace = "abcdef"
|
||||||
@ -79,7 +85,7 @@ class TestNemMosaic(unittest.TestCase):
|
|||||||
c.namespace = "abc"
|
c.namespace = "abc"
|
||||||
c.mosaic = "mosaic"
|
c.mosaic = "mosaic"
|
||||||
c.quantity = 3
|
c.quantity = 3
|
||||||
merged = merge_mosaics([a, b, c])
|
merged = _merge_mosaics([a, b, c])
|
||||||
self.assertEqual(merged[0].quantity, 1)
|
self.assertEqual(merged[0].quantity, 1)
|
||||||
self.assertEqual(merged[1].quantity, 5)
|
self.assertEqual(merged[1].quantity, 5)
|
||||||
self.assertEqual(len(merged), 2)
|
self.assertEqual(len(merged), 2)
|
||||||
@ -93,7 +99,7 @@ class TestNemMosaic(unittest.TestCase):
|
|||||||
c.namespace = "abc"
|
c.namespace = "abc"
|
||||||
c.mosaic = "mosaic"
|
c.mosaic = "mosaic"
|
||||||
c.quantity = 3
|
c.quantity = 3
|
||||||
merged = merge_mosaics([a, b, c])
|
merged = _merge_mosaics([a, b, c])
|
||||||
self.assertEqual(merged[0].quantity, 6)
|
self.assertEqual(merged[0].quantity, 6)
|
||||||
self.assertEqual(len(merged), 1)
|
self.assertEqual(len(merged), 1)
|
||||||
|
|
||||||
|
@ -7,8 +7,7 @@ if not utils.BITCOIN_ONLY:
|
|||||||
from apps.nem.mosaic import *
|
from apps.nem.mosaic import *
|
||||||
from apps.nem.transfer import *
|
from apps.nem.transfer import *
|
||||||
from apps.nem.transfer.serialize import *
|
from apps.nem.transfer.serialize import *
|
||||||
from trezor.messages import NEMTransfer
|
from trezor.messages import NEMTransfer, NEMTransactionCommon, NEMSignTx, NEMMosaic
|
||||||
from trezor.messages import NEMSignTx
|
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(not utils.BITCOIN_ONLY, "altcoin")
|
@unittest.skipUnless(not utils.BITCOIN_ONLY, "altcoin")
|
||||||
|
Loading…
Reference in New Issue
Block a user