mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-26 09:28:13 +00:00
trezorlib: factor out NEM to a separate module
This commit is contained in:
parent
a5e3d50fb0
commit
f87d931ce7
@ -25,7 +25,6 @@ import time
|
|||||||
import binascii
|
import binascii
|
||||||
import hashlib
|
import hashlib
|
||||||
import unicodedata
|
import unicodedata
|
||||||
import json
|
|
||||||
import getpass
|
import getpass
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
@ -34,6 +33,7 @@ from mnemonic import Mnemonic
|
|||||||
from . import messages as proto
|
from . import messages as proto
|
||||||
from . import tools
|
from . import tools
|
||||||
from . import mapping
|
from . import mapping
|
||||||
|
from . import nem
|
||||||
from .coins import coins_slip44
|
from .coins import coins_slip44
|
||||||
from .debuglink import DebugLink
|
from .debuglink import DebugLink
|
||||||
from .protobuf import MessageType
|
from .protobuf import MessageType
|
||||||
@ -718,120 +718,12 @@ class ProtocolMixin(object):
|
|||||||
@expect(proto.NEMSignedTx)
|
@expect(proto.NEMSignedTx)
|
||||||
def nem_sign_tx(self, n, transaction):
|
def nem_sign_tx(self, n, transaction):
|
||||||
n = self._convert_prime(n)
|
n = self._convert_prime(n)
|
||||||
|
try:
|
||||||
|
msg = nem.create_sign_tx(transaction)
|
||||||
|
except ValueError as e:
|
||||||
|
raise CallException(e.message)
|
||||||
|
|
||||||
def common_to_proto(common):
|
msg.address_n = n
|
||||||
msg = proto.NEMTransactionCommon()
|
|
||||||
msg.network = (common["version"] >> 24) & 0xFF
|
|
||||||
msg.timestamp = common["timeStamp"]
|
|
||||||
msg.fee = common["fee"]
|
|
||||||
msg.deadline = common["deadline"]
|
|
||||||
|
|
||||||
if "signed" in common:
|
|
||||||
msg.signer = binascii.unhexlify(common["signer"])
|
|
||||||
|
|
||||||
return msg
|
|
||||||
|
|
||||||
def transfer_to_proto(transfer):
|
|
||||||
msg = proto.NEMTransfer()
|
|
||||||
msg.recipient = transfer["recipient"]
|
|
||||||
msg.amount = transfer["amount"]
|
|
||||||
|
|
||||||
if "payload" in transfer["message"]:
|
|
||||||
msg.payload = binascii.unhexlify(transfer["message"]["payload"])
|
|
||||||
|
|
||||||
if transfer["message"]["type"] == 0x02:
|
|
||||||
msg.public_key = binascii.unhexlify(transfer["message"]["publicKey"])
|
|
||||||
|
|
||||||
if "mosaics" in transfer:
|
|
||||||
msg._extend_mosaics(proto.NEMMosaic(
|
|
||||||
namespace=mosaic["mosaicId"]["namespaceId"],
|
|
||||||
mosaic=mosaic["mosaicId"]["name"],
|
|
||||||
quantity=mosaic["quantity"],
|
|
||||||
) for mosaic in transfer["mosaics"])
|
|
||||||
return msg
|
|
||||||
|
|
||||||
def aggregate_modification_to_proto(aggregate_modification, msg):
|
|
||||||
msg._extend_modifications(proto.NEMCosignatoryModification(
|
|
||||||
type=modification["modificationType"],
|
|
||||||
public_key=binascii.unhexlify(modification["cosignatoryAccount"]),
|
|
||||||
) for modification in aggregate_modification["modifications"])
|
|
||||||
|
|
||||||
if "minCosignatories" in aggregate_modification:
|
|
||||||
msg.relative_change = aggregate_modification["minCosignatories"]["relativeChange"]
|
|
||||||
|
|
||||||
def provision_namespace_to_proto(provision_namespace, msg):
|
|
||||||
msg.namespace = provision_namespace["newPart"]
|
|
||||||
|
|
||||||
if provision_namespace["parent"]:
|
|
||||||
msg.parent = provision_namespace["parent"]
|
|
||||||
|
|
||||||
msg.sink = provision_namespace["rentalFeeSink"]
|
|
||||||
msg.fee = provision_namespace["rentalFee"]
|
|
||||||
|
|
||||||
def mosaic_creation_to_proto(mosaic_creation):
|
|
||||||
msg = proto.NEMMosaicCreation()
|
|
||||||
msg.definition.namespace = mosaic_creation["mosaicDefinition"]["id"]["namespaceId"]
|
|
||||||
msg.definition.mosaic = mosaic_creation["mosaicDefinition"]["id"]["name"]
|
|
||||||
|
|
||||||
if mosaic_creation["mosaicDefinition"]["levy"]:
|
|
||||||
msg.definition.levy = mosaic_creation["mosaicDefinition"]["levy"]["type"]
|
|
||||||
msg.definition.fee = mosaic_creation["mosaicDefinition"]["levy"]["fee"]
|
|
||||||
msg.definition.levy_address = mosaic_creation["mosaicDefinition"]["levy"]["recipient"]
|
|
||||||
msg.definition.levy_namespace = mosaic_creation["mosaicDefinition"]["levy"]["mosaicId"]["namespaceId"]
|
|
||||||
msg.definition.levy_mosaic = mosaic_creation["mosaicDefinition"]["levy"]["mosaicId"]["name"]
|
|
||||||
|
|
||||||
msg.definition.description = mosaic_creation["mosaicDefinition"]["description"]
|
|
||||||
|
|
||||||
for property in mosaic_creation["mosaicDefinition"]["properties"]:
|
|
||||||
name = property["name"]
|
|
||||||
value = json.loads(property["value"])
|
|
||||||
|
|
||||||
if name == "divisibility":
|
|
||||||
msg.definition.divisibility = value
|
|
||||||
elif name == "initialSupply":
|
|
||||||
msg.definition.supply = value
|
|
||||||
elif name == "supplyMutable":
|
|
||||||
msg.definition.mutable_supply = value
|
|
||||||
elif name == "transferable":
|
|
||||||
msg.definition.transferable = value
|
|
||||||
|
|
||||||
msg.sink = mosaic_creation["creationFeeSink"]
|
|
||||||
msg.fee = mosaic_creation["creationFee"]
|
|
||||||
return msg
|
|
||||||
|
|
||||||
def mosaic_supply_change_to_proto(mosaic_supply_change):
|
|
||||||
msg = proto.NEMMosaicSupplyChange()
|
|
||||||
msg.namespace = mosaic_supply_change["mosaicId"]["namespaceId"]
|
|
||||||
msg.mosaic = mosaic_supply_change["mosaicId"]["name"]
|
|
||||||
msg.type = mosaic_supply_change["supplyType"]
|
|
||||||
msg.delta = mosaic_supply_change["delta"]
|
|
||||||
return msg
|
|
||||||
|
|
||||||
msg = proto.NEMSignTx()
|
|
||||||
|
|
||||||
msg.transaction = common_to_proto(transaction)
|
|
||||||
msg.transaction._extend_address_n(n)
|
|
||||||
msg.cosigning = (transaction["type"] == 0x1002)
|
|
||||||
|
|
||||||
if msg.cosigning or transaction["type"] == 0x1004:
|
|
||||||
transaction = transaction["otherTrans"]
|
|
||||||
msg.multisig = common_to_proto(transaction)
|
|
||||||
elif "otherTrans" in transaction:
|
|
||||||
raise CallException("Transaction does not support inner transaction")
|
|
||||||
|
|
||||||
if transaction["type"] == 0x0101:
|
|
||||||
msg.transfer = transfer_to_proto(transaction)
|
|
||||||
elif transaction["type"] == 0x1001:
|
|
||||||
aggregate_modification_to_proto(transaction, msg.aggregate_modification)
|
|
||||||
elif transaction["type"] == 0x2001:
|
|
||||||
provision_namespace_to_proto(transaction, msg.provision_namespace)
|
|
||||||
elif transaction["type"] == 0x4001:
|
|
||||||
msg = mosaic_creation_to_proto(transaction)
|
|
||||||
elif transaction["type"] == 0x4002:
|
|
||||||
msg.mosaic_supply_change = mosaic_supply_change_to_proto(transaction)
|
|
||||||
else:
|
|
||||||
raise CallException("Unknown transaction type")
|
|
||||||
|
|
||||||
return self.call(msg)
|
return self.call(msg)
|
||||||
|
|
||||||
def verify_message(self, coin_name, address, signature, message):
|
def verify_message(self, coin_name, address, signature, message):
|
||||||
|
140
trezorlib/nem.py
Normal file
140
trezorlib/nem.py
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
import binascii
|
||||||
|
import json
|
||||||
|
from . import messages as proto
|
||||||
|
|
||||||
|
TYPE_MOSAIC_TRANSFER = 0x0101
|
||||||
|
TYPE_IMPORTANCE_TRANSFER = 0x0801
|
||||||
|
TYPE_MULTISIG_CHANGE = 0x1001
|
||||||
|
TYPE_MULTISIG_SIGN = 0x1002
|
||||||
|
TYPE_MULTISIG_TX = 0x1004
|
||||||
|
TYPE_PROVISION_NAMESPACE = 0x2001
|
||||||
|
TYPE_MOSAIC_DEFINITION_CREATION = 0x4001
|
||||||
|
TYPE_MOSAIC_SUPPLY_CHANGE = 0x4002
|
||||||
|
|
||||||
|
|
||||||
|
def create_transaction_common(transaction):
|
||||||
|
msg = proto.NEMTransactionCommon()
|
||||||
|
msg.network = (transaction["version"] >> 24) & 0xFF
|
||||||
|
msg.timestamp = transaction["timeStamp"]
|
||||||
|
msg.fee = transaction["fee"]
|
||||||
|
msg.deadline = transaction["deadline"]
|
||||||
|
|
||||||
|
if "signed" in transaction:
|
||||||
|
msg.signer = binascii.unhexlify(transaction["signer"])
|
||||||
|
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def create_transfer(transaction):
|
||||||
|
msg = proto.NEMTransfer()
|
||||||
|
msg.recipient = transaction["recipient"]
|
||||||
|
msg.amount = transaction["amount"]
|
||||||
|
|
||||||
|
if "payload" in transaction["message"]:
|
||||||
|
msg.payload = binascii.unhexlify(transaction["message"]["payload"])
|
||||||
|
|
||||||
|
if transaction["message"]["type"] == 0x02:
|
||||||
|
msg.public_key = binascii.unhexlify(transaction["message"]["publicKey"])
|
||||||
|
|
||||||
|
if "mosaics" in transaction:
|
||||||
|
msg.mosaics = [proto.NEMMosaic(
|
||||||
|
namespace=mosaic["mosaicId"]["namespaceId"],
|
||||||
|
mosaic=mosaic["mosaicId"]["name"],
|
||||||
|
quantity=mosaic["quantity"],
|
||||||
|
) for mosaic in transaction["mosaics"]]
|
||||||
|
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def create_aggregate_modification(transactions):
|
||||||
|
msg = proto.NEMAggregateModification()
|
||||||
|
msg.modifications = [proto.NEMCosignatoryModification(
|
||||||
|
type=modification["modificationType"],
|
||||||
|
public_key=binascii.unhexlify(modification["cosignatoryAccount"]),
|
||||||
|
) for modification in transactions["modifications"]]
|
||||||
|
|
||||||
|
if "minCosignatories" in transactions:
|
||||||
|
msg.relative_change = transactions["minCosignatories"]["relativeChange"]
|
||||||
|
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def create_provision_namespace(transaction):
|
||||||
|
msg = proto.NEMProvisionNamespace()
|
||||||
|
msg.namespace = transaction["newPart"]
|
||||||
|
|
||||||
|
if transaction["parent"]:
|
||||||
|
msg.parent = transaction["parent"]
|
||||||
|
|
||||||
|
msg.sink = transaction["rentalFeeSink"]
|
||||||
|
msg.fee = transaction["rentalFee"]
|
||||||
|
|
||||||
|
|
||||||
|
def create_mosaic_creation(transaction):
|
||||||
|
definition = transaction["mosaicDefinition"]
|
||||||
|
msg = proto.NEMMosaicCreation()
|
||||||
|
msg.definition = proto.NEMMosaicDefinition()
|
||||||
|
msg.definition.namespace = definition["id"]["namespaceId"]
|
||||||
|
msg.definition.mosaic = definition["id"]["name"]
|
||||||
|
|
||||||
|
if definition["levy"]:
|
||||||
|
msg.definition.levy = definition["levy"]["type"]
|
||||||
|
msg.definition.fee = definition["levy"]["fee"]
|
||||||
|
msg.definition.levy_address = definition["levy"]["recipient"]
|
||||||
|
msg.definition.levy_namespace = definition["levy"]["mosaicId"]["namespaceId"]
|
||||||
|
msg.definition.levy_mosaic = definition["levy"]["mosaicId"]["name"]
|
||||||
|
|
||||||
|
msg.definition.description = definition["description"]
|
||||||
|
|
||||||
|
for property in definition["properties"]:
|
||||||
|
name = property["name"]
|
||||||
|
value = json.loads(property["value"])
|
||||||
|
|
||||||
|
if name == "divisibility":
|
||||||
|
msg.definition.divisibility = value
|
||||||
|
elif name == "initialSupply":
|
||||||
|
msg.definition.supply = value
|
||||||
|
elif name == "supplyMutable":
|
||||||
|
msg.definition.mutable_supply = value
|
||||||
|
elif name == "transferable":
|
||||||
|
msg.definition.transferable = value
|
||||||
|
|
||||||
|
msg.sink = transaction["creationFeeSink"]
|
||||||
|
msg.fee = transaction["creationFee"]
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def create_supply_change(transaction):
|
||||||
|
msg = proto.NEMMosaicSupplyChange()
|
||||||
|
msg.namespace = transaction["mosaicId"]["namespaceId"]
|
||||||
|
msg.mosaic = transaction["mosaicId"]["name"]
|
||||||
|
msg.type = transaction["supplyType"]
|
||||||
|
msg.delta = transaction["delta"]
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def create_sign_tx(transaction):
|
||||||
|
msg = proto.NEMSignTx()
|
||||||
|
msg.transaction = create_transaction_common(transaction)
|
||||||
|
msg.cosigning = (transaction["type"] == TYPE_MULTISIG_SIGN)
|
||||||
|
|
||||||
|
if transaction["type"] in (TYPE_MULTISIG_SIGN, TYPE_MULTISIG_TX):
|
||||||
|
transaction = transaction["otherTrans"]
|
||||||
|
msg.multisig = create_transaction_common(transaction)
|
||||||
|
elif "otherTrans" in transaction:
|
||||||
|
raise ValueError("Transaction does not support inner transaction")
|
||||||
|
|
||||||
|
if transaction["type"] == TYPE_MOSAIC_TRANSFER:
|
||||||
|
msg.transfer = create_transfer(transaction)
|
||||||
|
elif transaction["type"] == TYPE_MULTISIG_CHANGE:
|
||||||
|
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_DEFINITION_CREATION:
|
||||||
|
msg.mosaic_creation = create_mosaic_creation(transaction)
|
||||||
|
elif transaction["type"] == TYPE_MOSAIC_SUPPLY_CHANGE:
|
||||||
|
msg.mosaic_supply_change = create_supply_change(transaction)
|
||||||
|
else:
|
||||||
|
raise ValueError("Unknown transaction type")
|
||||||
|
|
||||||
|
return msg
|
38
trezorlib/tests/unit_tests/test_nem.py
Normal file
38
trezorlib/tests/unit_tests/test_nem.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import binascii
|
||||||
|
from trezorlib import nem
|
||||||
|
|
||||||
|
|
||||||
|
def test_nem_basic():
|
||||||
|
transaction = {
|
||||||
|
"timeStamp": 76809215,
|
||||||
|
"amount": 1000000,
|
||||||
|
"fee": 1000000,
|
||||||
|
"recipient": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
|
||||||
|
"type": nem.TYPE_MOSAIC_TRANSFER,
|
||||||
|
"deadline": 76895615,
|
||||||
|
"version": (0x98 << 24),
|
||||||
|
"message": {
|
||||||
|
"payload": binascii.hexlify(b'hello world'),
|
||||||
|
"type": 1,
|
||||||
|
},
|
||||||
|
"mosaics": [
|
||||||
|
{
|
||||||
|
"mosaicId": {
|
||||||
|
"namespaceId": "nem",
|
||||||
|
"name": "xem",
|
||||||
|
},
|
||||||
|
"quantity": 1000000,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = nem.create_sign_tx(transaction)
|
||||||
|
|
||||||
|
# this is basically just a random sampling of expected properties
|
||||||
|
assert msg.transaction is not None
|
||||||
|
assert msg.transfer is not None
|
||||||
|
assert len(msg.transfer.mosaics) == 1
|
||||||
|
assert msg.transfer.mosaics[0].namespace == "nem"
|
||||||
|
|
||||||
|
assert msg.aggregate_modification is None
|
||||||
|
assert msg.provision_namespace is None
|
Loading…
Reference in New Issue
Block a user