mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-25 15:58:08 +00:00
226 lines
7.5 KiB
Python
226 lines
7.5 KiB
Python
# This file is part of the Trezor project.
|
|
#
|
|
# Copyright (C) 2012-2022 SatoshiLabs and contributors
|
|
#
|
|
# This library is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU Lesser General Public License version 3
|
|
# as published by the Free Software Foundation.
|
|
#
|
|
# This library is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Lesser General Public License for more details.
|
|
#
|
|
# You should have received a copy of the License along with this library.
|
|
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
|
|
|
|
import json
|
|
from typing import TYPE_CHECKING
|
|
|
|
from . import exceptions, messages
|
|
from .tools import expect
|
|
|
|
if TYPE_CHECKING:
|
|
from .client import TrezorClient
|
|
from .protobuf import MessageType
|
|
from .tools import Address
|
|
|
|
TYPE_TRANSACTION_TRANSFER = 0x0101
|
|
TYPE_IMPORTANCE_TRANSFER = 0x0801
|
|
TYPE_AGGREGATE_MODIFICATION = 0x1001
|
|
TYPE_MULTISIG_SIGNATURE = 0x1002
|
|
TYPE_MULTISIG = 0x1004
|
|
TYPE_PROVISION_NAMESPACE = 0x2001
|
|
TYPE_MOSAIC_CREATION = 0x4001
|
|
TYPE_MOSAIC_SUPPLY_CHANGE = 0x4002
|
|
|
|
|
|
def create_transaction_common(transaction: dict) -> messages.NEMTransactionCommon:
|
|
msg = messages.NEMTransactionCommon(
|
|
network=(transaction["version"] >> 24) & 0xFF,
|
|
timestamp=transaction["timeStamp"],
|
|
fee=transaction["fee"],
|
|
deadline=transaction["deadline"],
|
|
)
|
|
|
|
if "signer" in transaction:
|
|
msg.signer = bytes.fromhex(transaction["signer"])
|
|
|
|
return msg
|
|
|
|
|
|
def create_transfer(transaction: dict) -> messages.NEMTransfer:
|
|
msg = messages.NEMTransfer(
|
|
recipient=transaction["recipient"], amount=transaction["amount"]
|
|
)
|
|
|
|
if "payload" in transaction["message"]:
|
|
msg.payload = bytes.fromhex(transaction["message"]["payload"])
|
|
|
|
if transaction["message"]["type"] == 0x02:
|
|
msg.public_key = bytes.fromhex(transaction["message"]["publicKey"])
|
|
|
|
if "mosaics" in transaction:
|
|
msg.mosaics = [
|
|
messages.NEMMosaic(
|
|
namespace=mosaic["mosaicId"]["namespaceId"],
|
|
mosaic=mosaic["mosaicId"]["name"],
|
|
quantity=mosaic["quantity"],
|
|
)
|
|
for mosaic in transaction["mosaics"]
|
|
]
|
|
|
|
return msg
|
|
|
|
|
|
def create_aggregate_modification(
|
|
transaction: dict,
|
|
) -> messages.NEMAggregateModification:
|
|
msg = messages.NEMAggregateModification(
|
|
modifications=[
|
|
messages.NEMCosignatoryModification(
|
|
type=modification["modificationType"],
|
|
public_key=bytes.fromhex(modification["cosignatoryAccount"]),
|
|
)
|
|
for modification in transaction["modifications"]
|
|
]
|
|
)
|
|
|
|
if "minCosignatories" in transaction:
|
|
msg.relative_change = transaction["minCosignatories"]["relativeChange"]
|
|
|
|
return msg
|
|
|
|
|
|
def create_provision_namespace(transaction: dict) -> messages.NEMProvisionNamespace:
|
|
msg = messages.NEMProvisionNamespace(
|
|
sink=transaction["rentalFeeSink"],
|
|
fee=transaction["rentalFee"],
|
|
namespace=transaction["newPart"],
|
|
)
|
|
|
|
if transaction["parent"]:
|
|
msg.parent = transaction["parent"]
|
|
|
|
return msg
|
|
|
|
|
|
def create_mosaic_creation(transaction: dict) -> messages.NEMMosaicCreation:
|
|
definition_dict = transaction["mosaicDefinition"]
|
|
|
|
definition = messages.NEMMosaicDefinition(
|
|
namespace=definition_dict["id"]["namespaceId"],
|
|
mosaic=definition_dict["id"]["name"],
|
|
description=definition_dict["description"],
|
|
)
|
|
|
|
if definition_dict["levy"]:
|
|
definition.levy = definition_dict["levy"]["type"]
|
|
definition.fee = definition_dict["levy"]["fee"]
|
|
definition.levy_address = definition_dict["levy"]["recipient"]
|
|
definition.levy_namespace = definition_dict["levy"]["mosaicId"]["namespaceId"]
|
|
definition.levy_mosaic = definition_dict["levy"]["mosaicId"]["name"]
|
|
|
|
for property in definition_dict["properties"]:
|
|
name = property["name"]
|
|
value = json.loads(property["value"])
|
|
|
|
if name == "divisibility":
|
|
definition.divisibility = value
|
|
elif name == "initialSupply":
|
|
definition.supply = value
|
|
elif name == "supplyMutable":
|
|
definition.mutable_supply = value
|
|
elif name == "transferable":
|
|
definition.transferable = value
|
|
|
|
return messages.NEMMosaicCreation(
|
|
definition=definition,
|
|
sink=transaction["creationFeeSink"],
|
|
fee=transaction["creationFee"],
|
|
)
|
|
|
|
|
|
def create_supply_change(transaction: dict) -> messages.NEMMosaicSupplyChange:
|
|
return messages.NEMMosaicSupplyChange(
|
|
namespace=transaction["mosaicId"]["namespaceId"],
|
|
mosaic=transaction["mosaicId"]["name"],
|
|
type=transaction["supplyType"],
|
|
delta=transaction["delta"],
|
|
)
|
|
|
|
|
|
def create_importance_transfer(transaction: dict) -> messages.NEMImportanceTransfer:
|
|
return messages.NEMImportanceTransfer(
|
|
mode=transaction["importanceTransfer"]["mode"],
|
|
public_key=bytes.fromhex(transaction["importanceTransfer"]["publicKey"]),
|
|
)
|
|
|
|
|
|
def fill_transaction_by_type(msg: messages.NEMSignTx, transaction: dict) -> None:
|
|
if transaction["type"] == TYPE_TRANSACTION_TRANSFER:
|
|
msg.transfer = create_transfer(transaction)
|
|
elif transaction["type"] == TYPE_AGGREGATE_MODIFICATION:
|
|
msg.aggregate_modification = create_aggregate_modification(transaction)
|
|
elif transaction["type"] == TYPE_PROVISION_NAMESPACE:
|
|
msg.provision_namespace = create_provision_namespace(transaction)
|
|
elif transaction["type"] == TYPE_MOSAIC_CREATION:
|
|
msg.mosaic_creation = create_mosaic_creation(transaction)
|
|
elif transaction["type"] == TYPE_MOSAIC_SUPPLY_CHANGE:
|
|
msg.supply_change = create_supply_change(transaction)
|
|
elif transaction["type"] == TYPE_IMPORTANCE_TRANSFER:
|
|
msg.importance_transfer = create_importance_transfer(transaction)
|
|
else:
|
|
raise ValueError("Unknown transaction type")
|
|
|
|
|
|
def create_sign_tx(transaction: dict, chunkify: bool = False) -> messages.NEMSignTx:
|
|
msg = messages.NEMSignTx(
|
|
transaction=create_transaction_common(transaction),
|
|
cosigning=transaction["type"] == TYPE_MULTISIG_SIGNATURE,
|
|
chunkify=chunkify,
|
|
)
|
|
|
|
if transaction["type"] in (TYPE_MULTISIG_SIGNATURE, TYPE_MULTISIG):
|
|
other_trans = transaction["otherTrans"]
|
|
msg.multisig = create_transaction_common(other_trans)
|
|
fill_transaction_by_type(msg, other_trans)
|
|
elif "otherTrans" in transaction:
|
|
raise ValueError("Transaction does not support inner transaction")
|
|
else:
|
|
fill_transaction_by_type(msg, transaction)
|
|
|
|
return msg
|
|
|
|
|
|
# ====== Client functions ====== #
|
|
|
|
|
|
@expect(messages.NEMAddress, field="address", ret_type=str)
|
|
def get_address(
|
|
client: "TrezorClient",
|
|
n: "Address",
|
|
network: int,
|
|
show_display: bool = False,
|
|
chunkify: bool = False,
|
|
) -> "MessageType":
|
|
return client.call(
|
|
messages.NEMGetAddress(
|
|
address_n=n, network=network, show_display=show_display, chunkify=chunkify
|
|
)
|
|
)
|
|
|
|
|
|
@expect(messages.NEMSignedTx)
|
|
def sign_tx(
|
|
client: "TrezorClient", n: "Address", transaction: dict, chunkify: bool = False
|
|
) -> "MessageType":
|
|
try:
|
|
msg = create_sign_tx(transaction, chunkify=chunkify)
|
|
except ValueError as e:
|
|
raise exceptions.TrezorException("Failed to encode transaction") from e
|
|
|
|
assert msg.transaction is not None
|
|
msg.transaction.address_n = n
|
|
return client.call(msg)
|