mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-21 23:18:13 +00:00
add EOS support
Squashed commit of the following: commit 060563458fbc3b4a17f4d77ba5cd62d0c265c806 Author: matejcik <ja@matejcik.cz> Date: Fri May 10 16:16:19 2019 +0200 skip t1 in eos test commit f759089fef29501467b62bf1540715132a72c4cf Author: matejcik <ja@matejcik.cz> Date: Fri May 10 15:55:20 2019 +0200 make style commit 3ecdd5f77b331d7a6e5a46a10c79d80f214f31bd Author: Andriy Tkachyshyn <atkachyshyn@gmail.com> Date: Thu May 9 22:05:41 2019 +0300 Refinements in asset to to string conversion function according to code review and test cases for amounts less than 1 commit 72e44a35bada76abdd94ab866c2113a6d9d85191 Author: Andriy Tkachyshyn <atkachyshyn@gmail.com> Date: Wed May 8 00:27:45 2019 +0300 Moved to input_flow rest of the tests, cleanup and styling commit 92f9acbabcbef44a6912b074a309393450f0c8de Author: Andriy Tkachyshyn <atkachyshyn@gmail.com> Date: Tue May 7 21:47:12 2019 +0300 Fix for amounts less then 1 commit 8a0154f7432ab78e69a123202a97194d34c2a3cb Author: Andriy Tkachyshyn <atkachyshyn@gmail.com> Date: Mon May 6 23:26:24 2019 +0300 removed unnecessary peace of code commit b25c15de3eb1df863760e81ca69f09094349c26e Author: Andriy Tkachyshyn <atkachyshyn@gmail.com> Date: Mon May 6 23:16:57 2019 +0300 Fixed validate path parameters commit f0f6e7036a8b88d9c5c6b702a8d851e9a9bd3378 Author: Andriy Tkachyshyn <atkachyshyn@gmail.com> Date: Mon May 6 23:04:58 2019 +0300 Fixes commit 0c64d3814300df86d452975b2bd46fea13f512d2 Author: Andriy Tkachyshyn <atkachyshyn@gmail.com> Date: Mon May 6 22:19:51 2019 +0300 Fixed styling commit 41d1e77231e7da78fade9b2efa1b7d1980f0d3a8 Author: Andriy Tkachyshyn <atkachyshyn@gmail.com> Date: Mon May 6 22:13:58 2019 +0300 Changes to core, added CURVE to path validation commit c045b4554ee8e058dbfe35f715b003d0d85ab1d4 Author: Andriy Tkachyshyn <atkachyshyn@gmail.com> Date: Mon May 6 22:07:37 2019 +0300 Changes according to review commit 3f0e6cfd40e7d87dc3287bc3a0b2b9db5dea5377 Author: Andriy Tkachyshyn <atkachyshyn@gmail.com> Date: Mon Apr 29 21:37:16 2019 +0300 Added change to make expiration date timezone agnostic commit efdf44c326cc3f3137c447e798db5439b57c91fa Author: Andriy Tkachyshyn <atkachyshyn@gmail.com> Date: Thu Apr 18 00:14:30 2019 +0300 changes according to code review commit 3b3723da8f8f536c7c370a14236ea81aac25080a Author: Andriy Tkachyshyn <atkachyshyn@gmail.com> Date: Tue Apr 16 23:44:50 2019 +0300 Merged python to monorepo commit da6b0c683c29388e15c889ecea6e7f7471961a19 Author: Andriy Tkachyshyn <atkachyshyn@gmail.com> Date: Tue Apr 16 23:13:42 2019 +0300 Merged core to monorepo
This commit is contained in:
parent
23306d2a0d
commit
2e578572dd
@ -35,6 +35,7 @@ CPPDEFINES_MOD += [
|
||||
('USE_MONERO', '1'),
|
||||
('USE_CARDANO', '1'),
|
||||
('USE_NEM', '1'),
|
||||
('USE_EOS', '1'),
|
||||
]
|
||||
SOURCE_MOD += [
|
||||
'embed/extmod/modtrezorcrypto/modtrezorcrypto.c',
|
||||
|
@ -34,6 +34,7 @@ CPPDEFINES_MOD += [
|
||||
('USE_MONERO', '1'),
|
||||
('USE_CARDANO', '1'),
|
||||
('USE_NEM', '1'),
|
||||
('USE_EOS', '1'),
|
||||
]
|
||||
SOURCE_MOD += [
|
||||
'embed/extmod/modtrezorcrypto/modtrezorcrypto.c',
|
||||
|
@ -85,8 +85,17 @@ static int ethereum_is_canonical(uint8_t v, uint8_t signature[64]) {
|
||||
return (v & 2) == 0;
|
||||
}
|
||||
|
||||
static int eos_is_canonical(uint8_t v, uint8_t signature[64]) {
|
||||
(void)v;
|
||||
return !(signature[0] & 0x80) &&
|
||||
!(signature[0] == 0 && !(signature[1] & 0x80)) &&
|
||||
!(signature[32] & 0x80) &&
|
||||
!(signature[32] == 0 && !(signature[33] & 0x80));
|
||||
}
|
||||
|
||||
enum {
|
||||
CANONICAL_SIG_ETHEREUM = 1,
|
||||
CANONICAL_SIG_EOS = 2,
|
||||
};
|
||||
|
||||
/// def sign(secret_key: bytes, digest: bytes, compressed: bool = True,
|
||||
@ -106,6 +115,9 @@ STATIC mp_obj_t mod_trezorcrypto_secp256k1_sign(size_t n_args,
|
||||
case CANONICAL_SIG_ETHEREUM:
|
||||
is_canonical = ethereum_is_canonical;
|
||||
break;
|
||||
case CANONICAL_SIG_EOS:
|
||||
is_canonical = eos_is_canonical;
|
||||
break;
|
||||
}
|
||||
if (sk.len != 32) {
|
||||
mp_raise_ValueError("Invalid length of secret key");
|
||||
@ -236,6 +248,8 @@ STATIC const mp_rom_map_elem_t mod_trezorcrypto_secp256k1_globals_table[] = {
|
||||
MP_ROM_PTR(&mod_trezorcrypto_secp256k1_multiply_obj)},
|
||||
{MP_ROM_QSTR(MP_QSTR_CANONICAL_SIG_ETHEREUM),
|
||||
MP_OBJ_NEW_SMALL_INT(CANONICAL_SIG_ETHEREUM)},
|
||||
{MP_ROM_QSTR(MP_QSTR_CANONICAL_SIG_EOS),
|
||||
MP_OBJ_NEW_SMALL_INT(CANONICAL_SIG_EOS)},
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_secp256k1_globals,
|
||||
mod_trezorcrypto_secp256k1_globals_table);
|
||||
|
@ -20,8 +20,8 @@
|
||||
#ifndef __DISPLAY_H__
|
||||
#define __DISPLAY_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if TREZOR_MODEL == T
|
||||
|
||||
|
13
core/src/apps/eos/__init__.py
Executable file
13
core/src/apps/eos/__init__.py
Executable file
@ -0,0 +1,13 @@
|
||||
from trezor import wire
|
||||
from trezor.messages import MessageType
|
||||
|
||||
from apps.common import HARDENED
|
||||
|
||||
CURVE = "secp256k1"
|
||||
|
||||
|
||||
def boot():
|
||||
ns = [[CURVE, HARDENED | 44, HARDENED | 194]]
|
||||
|
||||
wire.add(MessageType.EosGetPublicKey, __name__, "get_public_key", ns)
|
||||
wire.add(MessageType.EosSignTx, __name__, "sign_tx", ns)
|
120
core/src/apps/eos/actions/__init__.py
Normal file
120
core/src/apps/eos/actions/__init__.py
Normal file
@ -0,0 +1,120 @@
|
||||
from trezor.crypto.hashlib import sha256
|
||||
from trezor.messages.EosTxActionRequest import EosTxActionRequest
|
||||
from trezor.messages.MessageType import EosTxActionAck
|
||||
from trezor.utils import HashWriter
|
||||
|
||||
from apps.eos import helpers, writers
|
||||
from apps.eos.actions import layout
|
||||
|
||||
|
||||
async def process_action(ctx, sha, action):
|
||||
name = helpers.eos_name_to_string(action.common.name)
|
||||
account = helpers.eos_name_to_string(action.common.account)
|
||||
|
||||
if not check_action(action, name, account):
|
||||
raise ValueError("Invalid action")
|
||||
|
||||
w = bytearray()
|
||||
if account == "eosio":
|
||||
if name == "buyram":
|
||||
await layout.confirm_action_buyram(ctx, action.buy_ram)
|
||||
writers.write_action_buyram(w, action.buy_ram)
|
||||
elif name == "buyrambytes":
|
||||
await layout.confirm_action_buyrambytes(ctx, action.buy_ram_bytes)
|
||||
writers.write_action_buyrambytes(w, action.buy_ram_bytes)
|
||||
elif name == "sellram":
|
||||
await layout.confirm_action_sellram(ctx, action.sell_ram)
|
||||
writers.write_action_sellram(w, action.sell_ram)
|
||||
elif name == "delegatebw":
|
||||
await layout.confirm_action_delegate(ctx, action.delegate)
|
||||
writers.write_action_delegate(w, action.delegate)
|
||||
elif name == "undelegatebw":
|
||||
await layout.confirm_action_undelegate(ctx, action.undelegate)
|
||||
writers.write_action_undelegate(w, action.undelegate)
|
||||
elif name == "refund":
|
||||
await layout.confirm_action_refund(ctx, action.refund)
|
||||
writers.write_action_refund(w, action.refund)
|
||||
elif name == "voteproducer":
|
||||
await layout.confirm_action_voteproducer(ctx, action.vote_producer)
|
||||
writers.write_action_voteproducer(w, action.vote_producer)
|
||||
elif name == "updateauth":
|
||||
await layout.confirm_action_updateauth(ctx, action.update_auth)
|
||||
writers.write_action_updateauth(w, action.update_auth)
|
||||
elif name == "deleteauth":
|
||||
await layout.confirm_action_deleteauth(ctx, action.delete_auth)
|
||||
writers.write_action_deleteauth(w, action.delete_auth)
|
||||
elif name == "linkauth":
|
||||
await layout.confirm_action_linkauth(ctx, action.link_auth)
|
||||
writers.write_action_linkauth(w, action.link_auth)
|
||||
elif name == "unlinkauth":
|
||||
await layout.confirm_action_unlinkauth(ctx, action.unlink_auth)
|
||||
writers.write_action_unlinkauth(w, action.unlink_auth)
|
||||
elif name == "newaccount":
|
||||
await layout.confirm_action_newaccount(ctx, action.new_account)
|
||||
writers.write_action_newaccount(w, action.new_account)
|
||||
else:
|
||||
raise ValueError("Unrecognized action type for eosio")
|
||||
elif name == "transfer":
|
||||
await layout.confirm_action_transfer(ctx, action.transfer, account)
|
||||
writers.write_action_transfer(w, action.transfer)
|
||||
else:
|
||||
await process_unknown_action(ctx, w, action)
|
||||
|
||||
writers.write_action_common(sha, action.common)
|
||||
writers.write_variant32(sha, len(w))
|
||||
writers.write_bytes(sha, w)
|
||||
|
||||
|
||||
async def process_unknown_action(ctx, w, action):
|
||||
checksum = HashWriter(sha256())
|
||||
writers.write_variant32(checksum, action.unknown.data_size)
|
||||
checksum.extend(action.unknown.data_chunk)
|
||||
|
||||
writers.write_bytes(w, action.unknown.data_chunk)
|
||||
bytes_left = action.unknown.data_size - len(action.unknown.data_chunk)
|
||||
|
||||
while bytes_left != 0:
|
||||
action = await ctx.call(
|
||||
EosTxActionRequest(data_size=bytes_left), EosTxActionAck
|
||||
)
|
||||
|
||||
if action.unknown is None:
|
||||
raise ValueError("Bad response. Unknown struct expected.")
|
||||
|
||||
checksum.extend(action.unknown.data_chunk)
|
||||
writers.write_bytes(w, action.unknown.data_chunk)
|
||||
|
||||
bytes_left -= len(action.unknown.data_chunk)
|
||||
if bytes_left < 0:
|
||||
raise ValueError("Bad response. Buffer overflow.")
|
||||
|
||||
await layout.confirm_action_unknown(ctx, action.common, checksum.get_digest())
|
||||
|
||||
|
||||
def check_action(action, name, account):
|
||||
if account == "eosio":
|
||||
if (
|
||||
(name == "buyram" and action.buy_ram is not None)
|
||||
or (name == "buyrambytes" and action.buy_ram_bytes is not None)
|
||||
or (name == "sellram" and action.sell_ram is not None)
|
||||
or (name == "delegatebw" and action.delegate is not None)
|
||||
or (name == "undelegatebw" and action.undelegate is not None)
|
||||
or (name == "refund" and action.refund is not None)
|
||||
or (name == "voteproducer" and action.vote_producer is not None)
|
||||
or (name == "updateauth" and action.update_auth is not None)
|
||||
or (name == "deleteauth" and action.delete_auth is not None)
|
||||
or (name == "linkauth" and action.link_auth is not None)
|
||||
or (name == "unlinkauth" and action.unlink_auth is not None)
|
||||
or (name == "newaccount" and action.new_account is not None)
|
||||
):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
elif name == "transfer":
|
||||
return action.transfer is not None
|
||||
|
||||
elif action.unknown is not None:
|
||||
return True
|
||||
|
||||
return False
|
411
core/src/apps/eos/actions/layout.py
Normal file
411
core/src/apps/eos/actions/layout.py
Normal file
@ -0,0 +1,411 @@
|
||||
from micropython import const
|
||||
from ubinascii import hexlify
|
||||
|
||||
from trezor import ui, wire
|
||||
from trezor.messages import (
|
||||
ButtonRequestType,
|
||||
EosActionBuyRam,
|
||||
EosActionBuyRamBytes,
|
||||
EosActionDelegate,
|
||||
EosActionDeleteAuth,
|
||||
EosActionLinkAuth,
|
||||
EosActionNewAccount,
|
||||
EosActionRefund,
|
||||
EosActionSellRam,
|
||||
EosActionTransfer,
|
||||
EosActionUndelegate,
|
||||
EosActionUnlinkAuth,
|
||||
EosActionUpdateAuth,
|
||||
EosActionVoteProducer,
|
||||
MessageType,
|
||||
)
|
||||
from trezor.messages.ButtonRequest import ButtonRequest
|
||||
from trezor.ui.confirm import CONFIRMED, ConfirmDialog
|
||||
from trezor.ui.scroll import Scrollpage, animate_swipe, paginate
|
||||
from trezor.ui.text import Text
|
||||
from trezor.utils import chunks
|
||||
|
||||
from apps.eos import helpers
|
||||
from apps.eos.get_public_key import _public_key_to_wif
|
||||
from apps.eos.layout import require_confirm
|
||||
|
||||
_LINE_LENGTH = const(17)
|
||||
_LINE_PLACEHOLDER = "{:<" + str(_LINE_LENGTH) + "}"
|
||||
_FIRST_PAGE = const(0)
|
||||
_TWO_FIELDS_PER_PAGE = const(2)
|
||||
_THREE_FIELDS_PER_PAGE = const(3)
|
||||
_FOUR_FIELDS_PER_PAGE = const(4)
|
||||
_FIVE_FIELDS_PER_PAGE = const(5)
|
||||
|
||||
|
||||
async def confirm_action_buyram(ctx, msg: EosActionBuyRam):
|
||||
await ctx.call(
|
||||
ButtonRequest(code=ButtonRequestType.ConfirmOutput), MessageType.ButtonAck
|
||||
)
|
||||
|
||||
text = "Buy RAM"
|
||||
fields = []
|
||||
fields.append("Payer:")
|
||||
fields.append(helpers.eos_name_to_string(msg.payer))
|
||||
fields.append("Receiver:")
|
||||
fields.append(helpers.eos_name_to_string(msg.receiver))
|
||||
fields.append("Amount:")
|
||||
fields.append(helpers.eos_asset_to_string(msg.quantity))
|
||||
|
||||
pages = list(chunks(fields, _FOUR_FIELDS_PER_PAGE))
|
||||
|
||||
paginator = paginate(show_lines_page, len(pages), _FIRST_PAGE, pages, text)
|
||||
await ctx.wait(paginator)
|
||||
|
||||
|
||||
async def confirm_action_buyrambytes(ctx, msg: EosActionBuyRamBytes):
|
||||
await ctx.call(
|
||||
ButtonRequest(code=ButtonRequestType.ConfirmOutput), MessageType.ButtonAck
|
||||
)
|
||||
|
||||
text = "Buy RAM"
|
||||
fields = []
|
||||
fields.append("Payer:")
|
||||
fields.append(helpers.eos_name_to_string(msg.payer))
|
||||
fields.append("Receiver:")
|
||||
fields.append(helpers.eos_name_to_string(msg.receiver))
|
||||
fields.append("Bytes:")
|
||||
fields.append(str(msg.bytes))
|
||||
|
||||
pages = list(chunks(fields, _FOUR_FIELDS_PER_PAGE))
|
||||
paginator = paginate(show_lines_page, len(pages), _FIRST_PAGE, pages, text)
|
||||
|
||||
await ctx.wait(paginator)
|
||||
|
||||
|
||||
async def confirm_action_delegate(ctx, msg: EosActionDelegate):
|
||||
await ctx.call(
|
||||
ButtonRequest(code=ButtonRequestType.ConfirmOutput), MessageType.ButtonAck
|
||||
)
|
||||
|
||||
text = "Delegate"
|
||||
fields = []
|
||||
fields.append("Sender:")
|
||||
fields.append(helpers.eos_name_to_string(msg.sender))
|
||||
fields.append("Receiver:")
|
||||
fields.append(helpers.eos_name_to_string(msg.receiver))
|
||||
fields.append("CPU:")
|
||||
fields.append(helpers.eos_asset_to_string(msg.cpu_quantity))
|
||||
fields.append("NET:")
|
||||
fields.append(helpers.eos_asset_to_string(msg.net_quantity))
|
||||
|
||||
if msg.transfer:
|
||||
fields.append("Transfer: Yes")
|
||||
fields.append("Receiver:")
|
||||
fields.append(helpers.eos_name_to_string(msg.receiver))
|
||||
else:
|
||||
fields.append("Transfer: No")
|
||||
|
||||
pages = list(chunks(fields, _FOUR_FIELDS_PER_PAGE))
|
||||
paginator = paginate(show_lines_page, len(pages), _FIRST_PAGE, pages, text)
|
||||
|
||||
await ctx.wait(paginator)
|
||||
|
||||
|
||||
async def confirm_action_sellram(ctx, msg: EosActionSellRam):
|
||||
await ctx.call(
|
||||
ButtonRequest(code=ButtonRequestType.ConfirmOutput), MessageType.ButtonAck
|
||||
)
|
||||
|
||||
text = "Sell RAM"
|
||||
fields = []
|
||||
fields.append("Receiver:")
|
||||
fields.append(helpers.eos_name_to_string(msg.account))
|
||||
fields.append("Bytes:")
|
||||
fields.append(str(msg.bytes))
|
||||
|
||||
pages = list(chunks(fields, _TWO_FIELDS_PER_PAGE))
|
||||
paginator = paginate(show_lines_page, len(pages), _FIRST_PAGE, pages, text)
|
||||
|
||||
await ctx.wait(paginator)
|
||||
|
||||
|
||||
async def confirm_action_undelegate(ctx, msg: EosActionUndelegate):
|
||||
await ctx.call(
|
||||
ButtonRequest(code=ButtonRequestType.ConfirmOutput), MessageType.ButtonAck
|
||||
)
|
||||
|
||||
text = "Undelegate"
|
||||
fields = []
|
||||
fields.append("Sender:")
|
||||
fields.append(helpers.eos_name_to_string(msg.sender))
|
||||
fields.append("Receiver:")
|
||||
fields.append(helpers.eos_name_to_string(msg.receiver))
|
||||
fields.append("CPU:")
|
||||
fields.append(helpers.eos_asset_to_string(msg.cpu_quantity))
|
||||
fields.append("NET:")
|
||||
fields.append(helpers.eos_asset_to_string(msg.net_quantity))
|
||||
|
||||
pages = list(chunks(fields, _FOUR_FIELDS_PER_PAGE))
|
||||
paginator = paginate(show_lines_page, len(pages), _FIRST_PAGE, pages, text)
|
||||
|
||||
await ctx.wait(paginator)
|
||||
|
||||
|
||||
async def confirm_action_refund(ctx, msg: EosActionRefund):
|
||||
text = Text("Refund", ui.ICON_CONFIRM, icon_color=ui.GREEN)
|
||||
text.normal("Owner:")
|
||||
text.normal(helpers.eos_name_to_string(msg.owner))
|
||||
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
|
||||
|
||||
|
||||
async def confirm_action_voteproducer(ctx, msg: EosActionVoteProducer):
|
||||
if msg.proxy and not msg.producers:
|
||||
# PROXY
|
||||
text = Text("Vote for proxy", ui.ICON_CONFIRM, icon_color=ui.GREEN)
|
||||
text.normal("Voter:")
|
||||
text.normal(helpers.eos_name_to_string(msg.voter))
|
||||
text.normal("Proxy:")
|
||||
text.normal(helpers.eos_name_to_string(msg.proxy))
|
||||
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
|
||||
|
||||
elif msg.producers:
|
||||
# PRODUCERS
|
||||
await ctx.call(
|
||||
ButtonRequest(code=ButtonRequestType.ConfirmOutput), MessageType.ButtonAck
|
||||
)
|
||||
producers = list(enumerate(msg.producers))
|
||||
pages = list(chunks(producers, _FIVE_FIELDS_PER_PAGE))
|
||||
paginator = paginate(show_voter_page, len(pages), _FIRST_PAGE, pages)
|
||||
await ctx.wait(paginator)
|
||||
|
||||
else:
|
||||
# Cancel vote
|
||||
text = Text("Cancel vote", ui.ICON_CONFIRM, icon_color=ui.GREEN)
|
||||
text.normal("Voter:")
|
||||
text.normal(helpers.eos_name_to_string(msg.voter))
|
||||
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
|
||||
|
||||
|
||||
async def confirm_action_transfer(ctx, msg: EosActionTransfer, account: str):
|
||||
await ctx.call(
|
||||
ButtonRequest(code=ButtonRequestType.ConfirmOutput), MessageType.ButtonAck
|
||||
)
|
||||
|
||||
text = "Transfer"
|
||||
fields = []
|
||||
fields.append("From:")
|
||||
fields.append(helpers.eos_name_to_string(msg.sender))
|
||||
fields.append("To:")
|
||||
fields.append(helpers.eos_name_to_string(msg.receiver))
|
||||
fields.append("Amount:")
|
||||
fields.append(helpers.eos_asset_to_string(msg.quantity))
|
||||
fields.append("Contract:")
|
||||
fields.append(account)
|
||||
|
||||
if msg.memo is not None:
|
||||
fields.append("Memo:")
|
||||
fields += split_data(msg.memo[:512])
|
||||
|
||||
pages = list(chunks(fields, _FOUR_FIELDS_PER_PAGE))
|
||||
|
||||
paginator = paginate(show_lines_page, len(pages), _FIRST_PAGE, pages, text)
|
||||
await ctx.wait(paginator)
|
||||
|
||||
|
||||
async def confirm_action_updateauth(ctx, msg: EosActionUpdateAuth):
|
||||
await ctx.call(
|
||||
ButtonRequest(code=ButtonRequestType.ConfirmOutput), MessageType.ButtonAck
|
||||
)
|
||||
|
||||
text = "Update Auth"
|
||||
fields = []
|
||||
fields.append("Account:")
|
||||
fields.append(helpers.eos_name_to_string(msg.account))
|
||||
fields.append("Permission:")
|
||||
fields.append(helpers.eos_name_to_string(msg.permission))
|
||||
fields.append("Parent:")
|
||||
fields.append(helpers.eos_name_to_string(msg.parent))
|
||||
fields += authorization_fields(msg.auth)
|
||||
|
||||
pages = list(chunks(fields, _FOUR_FIELDS_PER_PAGE))
|
||||
|
||||
paginator = paginate(show_lines_page, len(pages), _FIRST_PAGE, pages, text)
|
||||
await ctx.wait(paginator)
|
||||
|
||||
|
||||
async def confirm_action_deleteauth(ctx, msg: EosActionDeleteAuth):
|
||||
text = Text("Delete auth", ui.ICON_CONFIRM, icon_color=ui.GREEN)
|
||||
text.normal("Account:")
|
||||
text.normal(helpers.eos_name_to_string(msg.account))
|
||||
text.normal("Permission:")
|
||||
text.normal(helpers.eos_name_to_string(msg.permission))
|
||||
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
|
||||
|
||||
|
||||
async def confirm_action_linkauth(ctx, msg: EosActionLinkAuth):
|
||||
await ctx.call(
|
||||
ButtonRequest(code=ButtonRequestType.ConfirmOutput), MessageType.ButtonAck
|
||||
)
|
||||
|
||||
text = "Link Auth"
|
||||
fields = []
|
||||
fields.append("Account:")
|
||||
fields.append(helpers.eos_name_to_string(msg.account))
|
||||
fields.append("Code:")
|
||||
fields.append(helpers.eos_name_to_string(msg.code))
|
||||
fields.append("Type:")
|
||||
fields.append(helpers.eos_name_to_string(msg.type))
|
||||
fields.append("Requirement:")
|
||||
fields.append(helpers.eos_name_to_string(msg.requirement))
|
||||
|
||||
pages = list(chunks(fields, _FOUR_FIELDS_PER_PAGE))
|
||||
paginator = paginate(show_lines_page, len(pages), _FIRST_PAGE, pages, text)
|
||||
|
||||
await ctx.wait(paginator)
|
||||
|
||||
|
||||
async def confirm_action_unlinkauth(ctx, msg: EosActionUnlinkAuth):
|
||||
await ctx.call(
|
||||
ButtonRequest(code=ButtonRequestType.ConfirmOutput), MessageType.ButtonAck
|
||||
)
|
||||
|
||||
text = "Unlink Auth"
|
||||
fields = []
|
||||
fields.append("Account:")
|
||||
fields.append(helpers.eos_name_to_string(msg.account))
|
||||
fields.append("Code:")
|
||||
fields.append(helpers.eos_name_to_string(msg.code))
|
||||
fields.append("Type:")
|
||||
fields.append(helpers.eos_name_to_string(msg.type))
|
||||
|
||||
pages = list(chunks(fields, _FOUR_FIELDS_PER_PAGE))
|
||||
paginator = paginate(show_lines_page, len(pages), _FIRST_PAGE, pages, text)
|
||||
|
||||
await ctx.wait(paginator)
|
||||
|
||||
|
||||
async def confirm_action_newaccount(ctx, msg: EosActionNewAccount):
|
||||
await ctx.call(
|
||||
ButtonRequest(code=ButtonRequestType.ConfirmOutput), MessageType.ButtonAck
|
||||
)
|
||||
|
||||
text = "New Account"
|
||||
fields = []
|
||||
fields.append("Creator:")
|
||||
fields.append(helpers.eos_name_to_string(msg.creator))
|
||||
fields.append("Name:")
|
||||
fields.append(helpers.eos_name_to_string(msg.name))
|
||||
fields += authorization_fields(msg.owner)
|
||||
fields += authorization_fields(msg.active)
|
||||
|
||||
pages = list(chunks(fields, _FOUR_FIELDS_PER_PAGE))
|
||||
paginator = paginate(show_lines_page, len(pages), _FIRST_PAGE, pages, text)
|
||||
|
||||
await ctx.wait(paginator)
|
||||
|
||||
|
||||
async def confirm_action_unknown(ctx, action, checksum):
|
||||
await ctx.call(
|
||||
ButtonRequest(code=ButtonRequestType.ConfirmOutput), MessageType.ButtonAck
|
||||
)
|
||||
text = "Arbitrary data"
|
||||
fields = []
|
||||
fields.append("Contract:")
|
||||
fields.append(helpers.eos_name_to_string(action.account))
|
||||
fields.append("Action Name:")
|
||||
fields.append(helpers.eos_name_to_string(action.name))
|
||||
|
||||
fields.append("Checksum: ")
|
||||
fields += split_data(hexlify(checksum).decode("ascii"))
|
||||
|
||||
pages = list(chunks(fields, _FIVE_FIELDS_PER_PAGE))
|
||||
paginator = paginate(show_lines_page, len(pages), _FIRST_PAGE, pages, text)
|
||||
|
||||
await ctx.wait(paginator)
|
||||
|
||||
|
||||
@ui.layout
|
||||
async def show_lines_page(page: int, page_count: int, pages: list, header: str):
|
||||
if header == "Arbitrary data":
|
||||
text = Text(header, ui.ICON_WIPE, icon_color=ui.RED)
|
||||
else:
|
||||
text = Text(header, ui.ICON_CONFIRM, icon_color=ui.GREEN)
|
||||
text.mono(*pages[page])
|
||||
|
||||
content = Scrollpage(text, page, page_count)
|
||||
if page + 1 == page_count:
|
||||
if await ConfirmDialog(content) != CONFIRMED:
|
||||
raise wire.ActionCancelled("Action cancelled")
|
||||
else:
|
||||
content.render()
|
||||
await animate_swipe()
|
||||
|
||||
|
||||
@ui.layout
|
||||
async def show_voter_page(page: int, page_count: int, pages: list):
|
||||
lines = [
|
||||
"{:2d}. {}".format(wi + 1, helpers.eos_name_to_string(producer))
|
||||
for wi, producer in pages[page]
|
||||
]
|
||||
text = Text("Vote for producers", ui.ICON_CONFIRM, icon_color=ui.GREEN)
|
||||
text.mono(*lines)
|
||||
content = Scrollpage(text, page, page_count)
|
||||
|
||||
if page + 1 == page_count:
|
||||
if await ConfirmDialog(content) != CONFIRMED:
|
||||
raise wire.ActionCancelled("Action cancelled")
|
||||
else:
|
||||
content.render()
|
||||
await animate_swipe()
|
||||
|
||||
|
||||
def authorization_fields(auth):
|
||||
fields = []
|
||||
|
||||
fields.append("Threshold:")
|
||||
fields.append(str(auth.threshold))
|
||||
|
||||
for i, key in enumerate(auth.keys):
|
||||
_key = _public_key_to_wif(bytes(key.key))
|
||||
_weight = str(key.weight)
|
||||
|
||||
header = "Key #{}:".format(i + 1)
|
||||
w_header = "Key #{} Weight:".format(i + 1)
|
||||
fields.append(header)
|
||||
fields += split_data(_key)
|
||||
fields.append(w_header)
|
||||
fields.append(_weight)
|
||||
|
||||
for i, account in enumerate(auth.accounts):
|
||||
_account = helpers.eos_name_to_string(account.account.actor)
|
||||
_permission = helpers.eos_name_to_string(account.account.permission)
|
||||
|
||||
a_header = "Account #{}:".format(i + 1)
|
||||
p_header = "Acc Permission #{}:".format(i + 1)
|
||||
w_header = "Account #{} weight:".format(i + 1)
|
||||
|
||||
fields.append(a_header)
|
||||
fields.append(_account)
|
||||
fields.append(p_header)
|
||||
fields.append(_permission)
|
||||
fields.append(w_header)
|
||||
fields.append(str(account.weight))
|
||||
|
||||
for i, wait in enumerate(auth.waits):
|
||||
_wait = str(wait.wait_sec)
|
||||
_weight = str(wait.weight)
|
||||
|
||||
header = "Delay #{}".format(i + 1)
|
||||
w_header = "Delay #{} weight:".format(i + 1)
|
||||
fields.append(header)
|
||||
fields.append("{} sec".format(_wait))
|
||||
fields.append(w_header)
|
||||
fields.append(_weight)
|
||||
|
||||
return fields
|
||||
|
||||
|
||||
def split_data(data):
|
||||
temp_list = []
|
||||
len_left = len(data)
|
||||
while len_left > 0:
|
||||
temp_list.append("{} ".format(data[:_LINE_LENGTH]))
|
||||
data = data[_LINE_LENGTH:]
|
||||
len_left = len(data)
|
||||
return temp_list
|
43
core/src/apps/eos/get_public_key.py
Executable file
43
core/src/apps/eos/get_public_key.py
Executable file
@ -0,0 +1,43 @@
|
||||
from trezor import wire
|
||||
from trezor.crypto import base58
|
||||
from trezor.crypto.curve import secp256k1
|
||||
from trezor.crypto.hashlib import ripemd160
|
||||
from trezor.messages.EosGetPublicKey import EosGetPublicKey
|
||||
from trezor.messages.EosPublicKey import EosPublicKey
|
||||
|
||||
from apps.common import paths
|
||||
from apps.eos import CURVE
|
||||
from apps.eos.helpers import validate_full_path
|
||||
from apps.eos.layout import require_get_public_key
|
||||
|
||||
|
||||
def _ripemd160_32(data: bytes) -> bytes:
|
||||
return ripemd160(data).digest()[:4]
|
||||
|
||||
|
||||
def _public_key_to_wif(pub_key: bytes) -> str:
|
||||
if len(pub_key) == 65:
|
||||
head = 0x03 if pub_key[64] & 0x01 else 0x02
|
||||
compresed_pub_key = bytes([head]) + pub_key[1:33]
|
||||
elif len(pub_key) == 33:
|
||||
compresed_pub_key = pub_key
|
||||
else:
|
||||
raise wire.DataError("invalid public key length")
|
||||
return "EOS" + base58.encode_check(compresed_pub_key, _ripemd160_32)
|
||||
|
||||
|
||||
def _get_public_key(node):
|
||||
seckey = node.private_key()
|
||||
public_key = secp256k1.publickey(seckey, True)
|
||||
wif = _public_key_to_wif(public_key)
|
||||
return wif, public_key
|
||||
|
||||
|
||||
async def get_public_key(ctx, msg: EosGetPublicKey, keychain):
|
||||
await paths.validate_path(ctx, validate_full_path, keychain, msg.address_n, CURVE)
|
||||
|
||||
node = keychain.derive(msg.address_n)
|
||||
wif, public_key = _get_public_key(node)
|
||||
if msg.show_display:
|
||||
await require_get_public_key(ctx, wif)
|
||||
return EosPublicKey(wif, public_key)
|
54
core/src/apps/eos/helpers.py
Normal file
54
core/src/apps/eos/helpers.py
Normal file
@ -0,0 +1,54 @@
|
||||
from trezor.messages import EosAsset
|
||||
|
||||
from apps.common import HARDENED
|
||||
|
||||
|
||||
def eos_name_to_string(value) -> str:
|
||||
charmap = ".12345abcdefghijklmnopqrstuvwxyz"
|
||||
tmp = value
|
||||
string = ""
|
||||
for i in range(0, 13):
|
||||
c = charmap[tmp & (0x0F if i == 0 else 0x1F)]
|
||||
string = c + string
|
||||
tmp >>= 4 if i == 0 else 5
|
||||
|
||||
return string.rstrip(".")
|
||||
|
||||
|
||||
def eos_asset_to_string(asset: EosAsset) -> str:
|
||||
symbol_bytes = int.to_bytes(asset.symbol, 8, "big")
|
||||
precision = symbol_bytes[7]
|
||||
symbol = bytes(reversed(symbol_bytes[:7])).rstrip(b"\x00").decode("ascii")
|
||||
|
||||
amount_digits = "{:0{precision}d}".format(asset.amount, precision=precision)
|
||||
if precision > 0:
|
||||
integer = amount_digits[:-precision]
|
||||
if integer == "":
|
||||
integer = "0"
|
||||
fraction = amount_digits[-precision:]
|
||||
|
||||
return "{}.{} {}".format(integer, fraction, symbol)
|
||||
else:
|
||||
return "{} {}".format(amount_digits, symbol)
|
||||
|
||||
|
||||
def validate_full_path(path: list) -> bool:
|
||||
"""
|
||||
Validates derivation path to equal 44'/194'/a'/0/0,
|
||||
where `a` is an account index from 0 to 1 000 000.
|
||||
Similar to Ethereum this should be 44'/194'/a', but for
|
||||
compatibility with other HW vendors we use 44'/194'/a'/0/0.
|
||||
"""
|
||||
if len(path) != 5:
|
||||
return False
|
||||
if path[0] != 44 | HARDENED:
|
||||
return False
|
||||
if path[1] != 194 | HARDENED:
|
||||
return False
|
||||
if path[2] < HARDENED or path[2] > 1000000 | HARDENED:
|
||||
return False
|
||||
if path[3] != 0:
|
||||
return False
|
||||
if path[4] != 0:
|
||||
return False
|
||||
return True
|
19
core/src/apps/eos/layout.py
Normal file
19
core/src/apps/eos/layout.py
Normal file
@ -0,0 +1,19 @@
|
||||
from trezor import ui
|
||||
from trezor.messages import ButtonRequestType
|
||||
from trezor.ui.text import Text
|
||||
|
||||
from apps.common.confirm import require_confirm
|
||||
|
||||
|
||||
async def require_get_public_key(ctx, public_key):
|
||||
text = Text("Confirm public key", ui.ICON_RECEIVE, icon_color=ui.GREEN)
|
||||
text.normal(public_key)
|
||||
return await require_confirm(ctx, text, code=ButtonRequestType.PublicKey)
|
||||
|
||||
|
||||
async def require_sign_tx(ctx, num_actions):
|
||||
text = Text("Sign transaction", ui.ICON_SEND, icon_color=ui.GREEN)
|
||||
text.normal("You are about")
|
||||
text.normal("to sign {}".format(num_actions))
|
||||
text.normal("action(s).")
|
||||
return await require_confirm(ctx, text, code=ButtonRequestType.SignTx)
|
54
core/src/apps/eos/sign_tx.py
Normal file
54
core/src/apps/eos/sign_tx.py
Normal file
@ -0,0 +1,54 @@
|
||||
from trezor import wire
|
||||
from trezor.crypto.curve import secp256k1
|
||||
from trezor.crypto.hashlib import sha256
|
||||
from trezor.messages.EosSignedTx import EosSignedTx
|
||||
from trezor.messages.EosSignTx import EosSignTx
|
||||
from trezor.messages.EosTxActionRequest import EosTxActionRequest
|
||||
from trezor.messages.MessageType import EosTxActionAck
|
||||
from trezor.utils import HashWriter
|
||||
|
||||
from apps.common import paths
|
||||
from apps.eos import CURVE, writers
|
||||
from apps.eos.actions import process_action
|
||||
from apps.eos.helpers import validate_full_path
|
||||
from apps.eos.layout import require_sign_tx
|
||||
|
||||
|
||||
async def sign_tx(ctx, msg: EosSignTx, keychain):
|
||||
if msg.chain_id is None:
|
||||
raise wire.DataError("No chain id")
|
||||
if msg.header is None:
|
||||
raise wire.DataError("No header")
|
||||
if msg.num_actions is None or msg.num_actions == 0:
|
||||
raise wire.DataError("No actions")
|
||||
|
||||
await paths.validate_path(ctx, validate_full_path, keychain, msg.address_n, CURVE)
|
||||
|
||||
node = keychain.derive(msg.address_n)
|
||||
sha = HashWriter(sha256())
|
||||
await _init(ctx, sha, msg)
|
||||
await _actions(ctx, sha, msg.num_actions)
|
||||
writers.write_variant32(sha, 0)
|
||||
writers.write_bytes(sha, bytearray(32))
|
||||
|
||||
digest = sha.get_digest()
|
||||
signature = secp256k1.sign(
|
||||
node.private_key(), digest, True, secp256k1.CANONICAL_SIG_EOS
|
||||
)
|
||||
|
||||
return EosSignedTx(signature[0], signature[1:33], signature[33:])
|
||||
|
||||
|
||||
async def _init(ctx, sha, msg):
|
||||
writers.write_bytes(sha, msg.chain_id)
|
||||
writers.write_header(sha, msg.header)
|
||||
writers.write_variant32(sha, 0)
|
||||
writers.write_variant32(sha, msg.num_actions)
|
||||
|
||||
await require_sign_tx(ctx, msg.num_actions)
|
||||
|
||||
|
||||
async def _actions(ctx, sha, num_actions: int):
|
||||
for i in range(num_actions):
|
||||
action = await ctx.call(EosTxActionRequest(), EosTxActionAck)
|
||||
await process_action(ctx, sha, action)
|
168
core/src/apps/eos/writers.py
Normal file
168
core/src/apps/eos/writers.py
Normal file
@ -0,0 +1,168 @@
|
||||
from trezor.messages import (
|
||||
EosActionBuyRam,
|
||||
EosActionBuyRamBytes,
|
||||
EosActionCommon,
|
||||
EosActionDelegate,
|
||||
EosActionDeleteAuth,
|
||||
EosActionLinkAuth,
|
||||
EosActionNewAccount,
|
||||
EosActionRefund,
|
||||
EosActionSellRam,
|
||||
EosActionTransfer,
|
||||
EosActionUndelegate,
|
||||
EosActionUpdateAuth,
|
||||
EosActionVoteProducer,
|
||||
EosAsset,
|
||||
EosAuthorization,
|
||||
EosTxHeader,
|
||||
)
|
||||
from trezor.utils import HashWriter
|
||||
|
||||
from apps.common.writers import (
|
||||
write_bytes,
|
||||
write_uint8,
|
||||
write_uint16_le,
|
||||
write_uint32_le,
|
||||
write_uint64_le,
|
||||
)
|
||||
|
||||
|
||||
def write_auth(w: bytearray, auth: EosAuthorization) -> int:
|
||||
write_uint32_le(w, auth.threshold)
|
||||
write_variant32(w, len(auth.keys))
|
||||
for key in auth.keys:
|
||||
write_variant32(w, key.type)
|
||||
write_bytes(w, key.key)
|
||||
write_uint16_le(w, key.weight)
|
||||
|
||||
write_variant32(w, len(auth.accounts))
|
||||
for account in auth.accounts:
|
||||
write_uint64_le(w, account.account.actor)
|
||||
write_uint64_le(w, account.account.permission)
|
||||
write_uint16_le(w, account.weight)
|
||||
|
||||
write_variant32(w, len(auth.waits))
|
||||
for wait in auth.waits:
|
||||
write_uint32_le(w, wait.wait_sec)
|
||||
write_uint16_le(w, wait.weight)
|
||||
|
||||
|
||||
def write_header(hasher: HashWriter, header: EosTxHeader):
|
||||
write_uint32_le(hasher, header.expiration)
|
||||
write_uint16_le(hasher, header.ref_block_num)
|
||||
write_uint32_le(hasher, header.ref_block_prefix)
|
||||
write_variant32(hasher, header.max_net_usage_words)
|
||||
write_uint8(hasher, header.max_cpu_usage_ms)
|
||||
write_variant32(hasher, header.delay_sec)
|
||||
|
||||
|
||||
def write_action_transfer(w: bytearray, msg: EosActionTransfer):
|
||||
write_uint64_le(w, msg.sender)
|
||||
write_uint64_le(w, msg.receiver)
|
||||
write_asset(w, msg.quantity)
|
||||
write_variant32(w, len(msg.memo))
|
||||
write_bytes(w, msg.memo)
|
||||
|
||||
|
||||
def write_action_buyram(w: bytearray, msg: EosActionBuyRam):
|
||||
write_uint64_le(w, msg.payer)
|
||||
write_uint64_le(w, msg.receiver)
|
||||
write_asset(w, msg.quantity)
|
||||
|
||||
|
||||
def write_action_buyrambytes(w: bytearray, msg: EosActionBuyRamBytes):
|
||||
write_uint64_le(w, msg.payer)
|
||||
write_uint64_le(w, msg.receiver)
|
||||
write_uint32_le(w, msg.bytes)
|
||||
|
||||
|
||||
def write_action_sellram(w: bytearray, msg: EosActionSellRam):
|
||||
write_uint64_le(w, msg.account)
|
||||
write_uint64_le(w, msg.bytes)
|
||||
|
||||
|
||||
def write_action_delegate(w: bytearray, msg: EosActionDelegate):
|
||||
write_uint64_le(w, msg.sender)
|
||||
write_uint64_le(w, msg.receiver)
|
||||
write_asset(w, msg.net_quantity)
|
||||
write_asset(w, msg.cpu_quantity)
|
||||
write_uint8(w, 1 if msg.transfer else 0)
|
||||
|
||||
|
||||
def write_action_undelegate(w: bytearray, msg: EosActionUndelegate):
|
||||
write_uint64_le(w, msg.sender)
|
||||
write_uint64_le(w, msg.receiver)
|
||||
write_asset(w, msg.net_quantity)
|
||||
write_asset(w, msg.cpu_quantity)
|
||||
|
||||
|
||||
def write_action_refund(w: bytearray, msg: EosActionRefund):
|
||||
write_uint64_le(w, msg.owner)
|
||||
|
||||
|
||||
def write_action_voteproducer(w: bytearray, msg: EosActionVoteProducer):
|
||||
write_uint64_le(w, msg.voter)
|
||||
write_uint64_le(w, msg.proxy)
|
||||
write_variant32(w, len(msg.producers))
|
||||
for producer in msg.producers:
|
||||
write_uint64_le(w, producer)
|
||||
|
||||
|
||||
def write_action_updateauth(w: bytearray, msg: EosActionUpdateAuth):
|
||||
write_uint64_le(w, msg.account)
|
||||
write_uint64_le(w, msg.permission)
|
||||
write_uint64_le(w, msg.parent)
|
||||
write_auth(w, msg.auth)
|
||||
|
||||
|
||||
def write_action_deleteauth(w: bytearray, msg: EosActionDeleteAuth):
|
||||
write_uint64_le(w, msg.account)
|
||||
write_uint64_le(w, msg.permission)
|
||||
|
||||
|
||||
def write_action_linkauth(w: bytearray, msg: EosActionLinkAuth):
|
||||
write_uint64_le(w, msg.account)
|
||||
write_uint64_le(w, msg.code)
|
||||
write_uint64_le(w, msg.type)
|
||||
write_uint64_le(w, msg.requirement)
|
||||
|
||||
|
||||
def write_action_unlinkauth(w: bytearray, msg: EosActionLinkAuth):
|
||||
write_uint64_le(w, msg.account)
|
||||
write_uint64_le(w, msg.code)
|
||||
write_uint64_le(w, msg.type)
|
||||
|
||||
|
||||
def write_action_newaccount(w: bytearray, msg: EosActionNewAccount):
|
||||
write_uint64_le(w, msg.creator)
|
||||
write_uint64_le(w, msg.name)
|
||||
write_auth(w, msg.owner)
|
||||
write_auth(w, msg.active)
|
||||
|
||||
|
||||
def write_action_common(hasher: HashWriter, msg: EosActionCommon):
|
||||
write_uint64_le(hasher, msg.account)
|
||||
write_uint64_le(hasher, msg.name)
|
||||
write_variant32(hasher, len(msg.authorization))
|
||||
for authorization in msg.authorization:
|
||||
write_uint64_le(hasher, authorization.actor)
|
||||
write_uint64_le(hasher, authorization.permission)
|
||||
|
||||
|
||||
def write_asset(w: bytearray, asset: EosAsset) -> int:
|
||||
write_uint64_le(w, asset.amount)
|
||||
write_uint64_le(w, asset.symbol)
|
||||
|
||||
|
||||
def write_variant32(w: bytearray, value: int) -> int:
|
||||
variant = bytearray()
|
||||
while True:
|
||||
b = value & 0x7F
|
||||
value >>= 7
|
||||
b |= (value > 0) << 7
|
||||
variant.append(b)
|
||||
|
||||
if value == 0:
|
||||
break
|
||||
|
||||
write_bytes(w, bytes(variant))
|
@ -20,6 +20,7 @@ import apps.stellar
|
||||
import apps.ripple
|
||||
import apps.cardano
|
||||
import apps.tezos
|
||||
import apps.eos
|
||||
|
||||
if __debug__:
|
||||
import apps.debug
|
||||
@ -38,6 +39,7 @@ apps.stellar.boot()
|
||||
apps.ripple.boot()
|
||||
apps.cardano.boot()
|
||||
apps.tezos.boot()
|
||||
apps.eos.boot()
|
||||
if __debug__:
|
||||
apps.debug.boot()
|
||||
else:
|
||||
|
26
core/src/trezor/messages/EosActionBuyRam.py
Normal file
26
core/src/trezor/messages/EosActionBuyRam.py
Normal file
@ -0,0 +1,26 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
from .EosAsset import EosAsset
|
||||
|
||||
|
||||
class EosActionBuyRam(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
payer: int = None,
|
||||
receiver: int = None,
|
||||
quantity: EosAsset = None,
|
||||
) -> None:
|
||||
self.payer = payer
|
||||
self.receiver = receiver
|
||||
self.quantity = quantity
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('payer', p.UVarintType, 0),
|
||||
2: ('receiver', p.UVarintType, 0),
|
||||
3: ('quantity', EosAsset, 0),
|
||||
}
|
24
core/src/trezor/messages/EosActionBuyRamBytes.py
Normal file
24
core/src/trezor/messages/EosActionBuyRamBytes.py
Normal file
@ -0,0 +1,24 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
|
||||
class EosActionBuyRamBytes(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
payer: int = None,
|
||||
receiver: int = None,
|
||||
bytes: int = None,
|
||||
) -> None:
|
||||
self.payer = payer
|
||||
self.receiver = receiver
|
||||
self.bytes = bytes
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('payer', p.UVarintType, 0),
|
||||
2: ('receiver', p.UVarintType, 0),
|
||||
3: ('bytes', p.UVarintType, 0),
|
||||
}
|
32
core/src/trezor/messages/EosActionCommon.py
Normal file
32
core/src/trezor/messages/EosActionCommon.py
Normal file
@ -0,0 +1,32 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
from .EosPermissionLevel import EosPermissionLevel
|
||||
|
||||
if __debug__:
|
||||
try:
|
||||
from typing import List
|
||||
except ImportError:
|
||||
List = None # type: ignore
|
||||
|
||||
|
||||
class EosActionCommon(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
account: int = None,
|
||||
name: int = None,
|
||||
authorization: List[EosPermissionLevel] = None,
|
||||
) -> None:
|
||||
self.account = account
|
||||
self.name = name
|
||||
self.authorization = authorization if authorization is not None else []
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('account', p.UVarintType, 0),
|
||||
2: ('name', p.UVarintType, 0),
|
||||
3: ('authorization', EosPermissionLevel, p.FLAG_REPEATED),
|
||||
}
|
32
core/src/trezor/messages/EosActionDelegate.py
Normal file
32
core/src/trezor/messages/EosActionDelegate.py
Normal file
@ -0,0 +1,32 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
from .EosAsset import EosAsset
|
||||
|
||||
|
||||
class EosActionDelegate(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
sender: int = None,
|
||||
receiver: int = None,
|
||||
net_quantity: EosAsset = None,
|
||||
cpu_quantity: EosAsset = None,
|
||||
transfer: bool = None,
|
||||
) -> None:
|
||||
self.sender = sender
|
||||
self.receiver = receiver
|
||||
self.net_quantity = net_quantity
|
||||
self.cpu_quantity = cpu_quantity
|
||||
self.transfer = transfer
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('sender', p.UVarintType, 0),
|
||||
2: ('receiver', p.UVarintType, 0),
|
||||
3: ('net_quantity', EosAsset, 0),
|
||||
4: ('cpu_quantity', EosAsset, 0),
|
||||
5: ('transfer', p.BoolType, 0),
|
||||
}
|
21
core/src/trezor/messages/EosActionDeleteAuth.py
Normal file
21
core/src/trezor/messages/EosActionDeleteAuth.py
Normal file
@ -0,0 +1,21 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
|
||||
class EosActionDeleteAuth(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
account: int = None,
|
||||
permission: int = None,
|
||||
) -> None:
|
||||
self.account = account
|
||||
self.permission = permission
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('account', p.UVarintType, 0),
|
||||
2: ('permission', p.UVarintType, 0),
|
||||
}
|
27
core/src/trezor/messages/EosActionLinkAuth.py
Normal file
27
core/src/trezor/messages/EosActionLinkAuth.py
Normal file
@ -0,0 +1,27 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
|
||||
class EosActionLinkAuth(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
account: int = None,
|
||||
code: int = None,
|
||||
type: int = None,
|
||||
requirement: int = None,
|
||||
) -> None:
|
||||
self.account = account
|
||||
self.code = code
|
||||
self.type = type
|
||||
self.requirement = requirement
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('account', p.UVarintType, 0),
|
||||
2: ('code', p.UVarintType, 0),
|
||||
3: ('type', p.UVarintType, 0),
|
||||
4: ('requirement', p.UVarintType, 0),
|
||||
}
|
29
core/src/trezor/messages/EosActionNewAccount.py
Normal file
29
core/src/trezor/messages/EosActionNewAccount.py
Normal file
@ -0,0 +1,29 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
from .EosAuthorization import EosAuthorization
|
||||
|
||||
|
||||
class EosActionNewAccount(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
creator: int = None,
|
||||
name: int = None,
|
||||
owner: EosAuthorization = None,
|
||||
active: EosAuthorization = None,
|
||||
) -> None:
|
||||
self.creator = creator
|
||||
self.name = name
|
||||
self.owner = owner
|
||||
self.active = active
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('creator', p.UVarintType, 0),
|
||||
2: ('name', p.UVarintType, 0),
|
||||
3: ('owner', EosAuthorization, 0),
|
||||
4: ('active', EosAuthorization, 0),
|
||||
}
|
18
core/src/trezor/messages/EosActionRefund.py
Normal file
18
core/src/trezor/messages/EosActionRefund.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
|
||||
class EosActionRefund(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
owner: int = None,
|
||||
) -> None:
|
||||
self.owner = owner
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('owner', p.UVarintType, 0),
|
||||
}
|
21
core/src/trezor/messages/EosActionSellRam.py
Normal file
21
core/src/trezor/messages/EosActionSellRam.py
Normal file
@ -0,0 +1,21 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
|
||||
class EosActionSellRam(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
account: int = None,
|
||||
bytes: int = None,
|
||||
) -> None:
|
||||
self.account = account
|
||||
self.bytes = bytes
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('account', p.UVarintType, 0),
|
||||
2: ('bytes', p.UVarintType, 0),
|
||||
}
|
29
core/src/trezor/messages/EosActionTransfer.py
Normal file
29
core/src/trezor/messages/EosActionTransfer.py
Normal file
@ -0,0 +1,29 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
from .EosAsset import EosAsset
|
||||
|
||||
|
||||
class EosActionTransfer(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
sender: int = None,
|
||||
receiver: int = None,
|
||||
quantity: EosAsset = None,
|
||||
memo: str = None,
|
||||
) -> None:
|
||||
self.sender = sender
|
||||
self.receiver = receiver
|
||||
self.quantity = quantity
|
||||
self.memo = memo
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('sender', p.UVarintType, 0),
|
||||
2: ('receiver', p.UVarintType, 0),
|
||||
3: ('quantity', EosAsset, 0),
|
||||
4: ('memo', p.UnicodeType, 0),
|
||||
}
|
29
core/src/trezor/messages/EosActionUndelegate.py
Normal file
29
core/src/trezor/messages/EosActionUndelegate.py
Normal file
@ -0,0 +1,29 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
from .EosAsset import EosAsset
|
||||
|
||||
|
||||
class EosActionUndelegate(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
sender: int = None,
|
||||
receiver: int = None,
|
||||
net_quantity: EosAsset = None,
|
||||
cpu_quantity: EosAsset = None,
|
||||
) -> None:
|
||||
self.sender = sender
|
||||
self.receiver = receiver
|
||||
self.net_quantity = net_quantity
|
||||
self.cpu_quantity = cpu_quantity
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('sender', p.UVarintType, 0),
|
||||
2: ('receiver', p.UVarintType, 0),
|
||||
3: ('net_quantity', EosAsset, 0),
|
||||
4: ('cpu_quantity', EosAsset, 0),
|
||||
}
|
21
core/src/trezor/messages/EosActionUnknown.py
Normal file
21
core/src/trezor/messages/EosActionUnknown.py
Normal file
@ -0,0 +1,21 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
|
||||
class EosActionUnknown(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data_size: int = None,
|
||||
data_chunk: bytes = None,
|
||||
) -> None:
|
||||
self.data_size = data_size
|
||||
self.data_chunk = data_chunk
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('data_size', p.UVarintType, 0),
|
||||
2: ('data_chunk', p.BytesType, 0),
|
||||
}
|
24
core/src/trezor/messages/EosActionUnlinkAuth.py
Normal file
24
core/src/trezor/messages/EosActionUnlinkAuth.py
Normal file
@ -0,0 +1,24 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
|
||||
class EosActionUnlinkAuth(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
account: int = None,
|
||||
code: int = None,
|
||||
type: int = None,
|
||||
) -> None:
|
||||
self.account = account
|
||||
self.code = code
|
||||
self.type = type
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('account', p.UVarintType, 0),
|
||||
2: ('code', p.UVarintType, 0),
|
||||
3: ('type', p.UVarintType, 0),
|
||||
}
|
29
core/src/trezor/messages/EosActionUpdateAuth.py
Normal file
29
core/src/trezor/messages/EosActionUpdateAuth.py
Normal file
@ -0,0 +1,29 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
from .EosAuthorization import EosAuthorization
|
||||
|
||||
|
||||
class EosActionUpdateAuth(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
account: int = None,
|
||||
permission: int = None,
|
||||
parent: int = None,
|
||||
auth: EosAuthorization = None,
|
||||
) -> None:
|
||||
self.account = account
|
||||
self.permission = permission
|
||||
self.parent = parent
|
||||
self.auth = auth
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('account', p.UVarintType, 0),
|
||||
2: ('permission', p.UVarintType, 0),
|
||||
3: ('parent', p.UVarintType, 0),
|
||||
4: ('auth', EosAuthorization, 0),
|
||||
}
|
30
core/src/trezor/messages/EosActionVoteProducer.py
Normal file
30
core/src/trezor/messages/EosActionVoteProducer.py
Normal file
@ -0,0 +1,30 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
if __debug__:
|
||||
try:
|
||||
from typing import List
|
||||
except ImportError:
|
||||
List = None # type: ignore
|
||||
|
||||
|
||||
class EosActionVoteProducer(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
voter: int = None,
|
||||
proxy: int = None,
|
||||
producers: List[int] = None,
|
||||
) -> None:
|
||||
self.voter = voter
|
||||
self.proxy = proxy
|
||||
self.producers = producers if producers is not None else []
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('voter', p.UVarintType, 0),
|
||||
2: ('proxy', p.UVarintType, 0),
|
||||
3: ('producers', p.UVarintType, p.FLAG_REPEATED),
|
||||
}
|
21
core/src/trezor/messages/EosAsset.py
Normal file
21
core/src/trezor/messages/EosAsset.py
Normal file
@ -0,0 +1,21 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
|
||||
class EosAsset(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
amount: int = None,
|
||||
symbol: int = None,
|
||||
) -> None:
|
||||
self.amount = amount
|
||||
self.symbol = symbol
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('amount', p.SVarintType, 0),
|
||||
2: ('symbol', p.UVarintType, 0),
|
||||
}
|
37
core/src/trezor/messages/EosAuthorization.py
Normal file
37
core/src/trezor/messages/EosAuthorization.py
Normal file
@ -0,0 +1,37 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
from .EosAuthorizationAccount import EosAuthorizationAccount
|
||||
from .EosAuthorizationKey import EosAuthorizationKey
|
||||
from .EosAuthorizationWait import EosAuthorizationWait
|
||||
|
||||
if __debug__:
|
||||
try:
|
||||
from typing import List
|
||||
except ImportError:
|
||||
List = None # type: ignore
|
||||
|
||||
|
||||
class EosAuthorization(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
threshold: int = None,
|
||||
keys: List[EosAuthorizationKey] = None,
|
||||
accounts: List[EosAuthorizationAccount] = None,
|
||||
waits: List[EosAuthorizationWait] = None,
|
||||
) -> None:
|
||||
self.threshold = threshold
|
||||
self.keys = keys if keys is not None else []
|
||||
self.accounts = accounts if accounts is not None else []
|
||||
self.waits = waits if waits is not None else []
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('threshold', p.UVarintType, 0),
|
||||
2: ('keys', EosAuthorizationKey, p.FLAG_REPEATED),
|
||||
3: ('accounts', EosAuthorizationAccount, p.FLAG_REPEATED),
|
||||
4: ('waits', EosAuthorizationWait, p.FLAG_REPEATED),
|
||||
}
|
23
core/src/trezor/messages/EosAuthorizationAccount.py
Normal file
23
core/src/trezor/messages/EosAuthorizationAccount.py
Normal file
@ -0,0 +1,23 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
from .EosPermissionLevel import EosPermissionLevel
|
||||
|
||||
|
||||
class EosAuthorizationAccount(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
account: EosPermissionLevel = None,
|
||||
weight: int = None,
|
||||
) -> None:
|
||||
self.account = account
|
||||
self.weight = weight
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('account', EosPermissionLevel, 0),
|
||||
2: ('weight', p.UVarintType, 0),
|
||||
}
|
33
core/src/trezor/messages/EosAuthorizationKey.py
Normal file
33
core/src/trezor/messages/EosAuthorizationKey.py
Normal file
@ -0,0 +1,33 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
if __debug__:
|
||||
try:
|
||||
from typing import List
|
||||
except ImportError:
|
||||
List = None # type: ignore
|
||||
|
||||
|
||||
class EosAuthorizationKey(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
type: int = None,
|
||||
key: bytes = None,
|
||||
address_n: List[int] = None,
|
||||
weight: int = None,
|
||||
) -> None:
|
||||
self.type = type
|
||||
self.key = key
|
||||
self.address_n = address_n if address_n is not None else []
|
||||
self.weight = weight
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('type', p.UVarintType, 0),
|
||||
2: ('key', p.BytesType, 0),
|
||||
3: ('address_n', p.UVarintType, p.FLAG_REPEATED),
|
||||
4: ('weight', p.UVarintType, 0),
|
||||
}
|
21
core/src/trezor/messages/EosAuthorizationWait.py
Normal file
21
core/src/trezor/messages/EosAuthorizationWait.py
Normal file
@ -0,0 +1,21 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
|
||||
class EosAuthorizationWait(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
wait_sec: int = None,
|
||||
weight: int = None,
|
||||
) -> None:
|
||||
self.wait_sec = wait_sec
|
||||
self.weight = weight
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('wait_sec', p.UVarintType, 0),
|
||||
2: ('weight', p.UVarintType, 0),
|
||||
}
|
28
core/src/trezor/messages/EosGetPublicKey.py
Normal file
28
core/src/trezor/messages/EosGetPublicKey.py
Normal file
@ -0,0 +1,28 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
if __debug__:
|
||||
try:
|
||||
from typing import List
|
||||
except ImportError:
|
||||
List = None # type: ignore
|
||||
|
||||
|
||||
class EosGetPublicKey(p.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 600
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address_n: List[int] = None,
|
||||
show_display: bool = None,
|
||||
) -> None:
|
||||
self.address_n = address_n if address_n is not None else []
|
||||
self.show_display = show_display
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('address_n', p.UVarintType, p.FLAG_REPEATED),
|
||||
2: ('show_display', p.BoolType, 0),
|
||||
}
|
21
core/src/trezor/messages/EosPermissionLevel.py
Normal file
21
core/src/trezor/messages/EosPermissionLevel.py
Normal file
@ -0,0 +1,21 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
|
||||
class EosPermissionLevel(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
actor: int = None,
|
||||
permission: int = None,
|
||||
) -> None:
|
||||
self.actor = actor
|
||||
self.permission = permission
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('actor', p.UVarintType, 0),
|
||||
2: ('permission', p.UVarintType, 0),
|
||||
}
|
22
core/src/trezor/messages/EosPublicKey.py
Normal file
22
core/src/trezor/messages/EosPublicKey.py
Normal file
@ -0,0 +1,22 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
|
||||
class EosPublicKey(p.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 601
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
wif_public_key: str = None,
|
||||
raw_public_key: bytes = None,
|
||||
) -> None:
|
||||
self.wif_public_key = wif_public_key
|
||||
self.raw_public_key = raw_public_key
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('wif_public_key', p.UnicodeType, 0),
|
||||
2: ('raw_public_key', p.BytesType, 0),
|
||||
}
|
36
core/src/trezor/messages/EosSignTx.py
Normal file
36
core/src/trezor/messages/EosSignTx.py
Normal file
@ -0,0 +1,36 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
from .EosTxHeader import EosTxHeader
|
||||
|
||||
if __debug__:
|
||||
try:
|
||||
from typing import List
|
||||
except ImportError:
|
||||
List = None # type: ignore
|
||||
|
||||
|
||||
class EosSignTx(p.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 602
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address_n: List[int] = None,
|
||||
chain_id: bytes = None,
|
||||
header: EosTxHeader = None,
|
||||
num_actions: int = None,
|
||||
) -> None:
|
||||
self.address_n = address_n if address_n is not None else []
|
||||
self.chain_id = chain_id
|
||||
self.header = header
|
||||
self.num_actions = num_actions
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('address_n', p.UVarintType, p.FLAG_REPEATED),
|
||||
2: ('chain_id', p.BytesType, 0),
|
||||
3: ('header', EosTxHeader, 0),
|
||||
4: ('num_actions', p.UVarintType, 0),
|
||||
}
|
25
core/src/trezor/messages/EosSignedTx.py
Normal file
25
core/src/trezor/messages/EosSignedTx.py
Normal file
@ -0,0 +1,25 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
|
||||
class EosSignedTx(p.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 605
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
signature_v: int = None,
|
||||
signature_r: bytes = None,
|
||||
signature_s: bytes = None,
|
||||
) -> None:
|
||||
self.signature_v = signature_v
|
||||
self.signature_r = signature_r
|
||||
self.signature_s = signature_s
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('signature_v', p.UVarintType, 0),
|
||||
2: ('signature_r', p.BytesType, 0),
|
||||
3: ('signature_s', p.BytesType, 0),
|
||||
}
|
77
core/src/trezor/messages/EosTxActionAck.py
Normal file
77
core/src/trezor/messages/EosTxActionAck.py
Normal file
@ -0,0 +1,77 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
from .EosActionBuyRam import EosActionBuyRam
|
||||
from .EosActionBuyRamBytes import EosActionBuyRamBytes
|
||||
from .EosActionCommon import EosActionCommon
|
||||
from .EosActionDelegate import EosActionDelegate
|
||||
from .EosActionDeleteAuth import EosActionDeleteAuth
|
||||
from .EosActionLinkAuth import EosActionLinkAuth
|
||||
from .EosActionNewAccount import EosActionNewAccount
|
||||
from .EosActionRefund import EosActionRefund
|
||||
from .EosActionSellRam import EosActionSellRam
|
||||
from .EosActionTransfer import EosActionTransfer
|
||||
from .EosActionUndelegate import EosActionUndelegate
|
||||
from .EosActionUnknown import EosActionUnknown
|
||||
from .EosActionUnlinkAuth import EosActionUnlinkAuth
|
||||
from .EosActionUpdateAuth import EosActionUpdateAuth
|
||||
from .EosActionVoteProducer import EosActionVoteProducer
|
||||
|
||||
|
||||
class EosTxActionAck(p.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 604
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
common: EosActionCommon = None,
|
||||
transfer: EosActionTransfer = None,
|
||||
delegate: EosActionDelegate = None,
|
||||
undelegate: EosActionUndelegate = None,
|
||||
refund: EosActionRefund = None,
|
||||
buy_ram: EosActionBuyRam = None,
|
||||
buy_ram_bytes: EosActionBuyRamBytes = None,
|
||||
sell_ram: EosActionSellRam = None,
|
||||
vote_producer: EosActionVoteProducer = None,
|
||||
update_auth: EosActionUpdateAuth = None,
|
||||
delete_auth: EosActionDeleteAuth = None,
|
||||
link_auth: EosActionLinkAuth = None,
|
||||
unlink_auth: EosActionUnlinkAuth = None,
|
||||
new_account: EosActionNewAccount = None,
|
||||
unknown: EosActionUnknown = None,
|
||||
) -> None:
|
||||
self.common = common
|
||||
self.transfer = transfer
|
||||
self.delegate = delegate
|
||||
self.undelegate = undelegate
|
||||
self.refund = refund
|
||||
self.buy_ram = buy_ram
|
||||
self.buy_ram_bytes = buy_ram_bytes
|
||||
self.sell_ram = sell_ram
|
||||
self.vote_producer = vote_producer
|
||||
self.update_auth = update_auth
|
||||
self.delete_auth = delete_auth
|
||||
self.link_auth = link_auth
|
||||
self.unlink_auth = unlink_auth
|
||||
self.new_account = new_account
|
||||
self.unknown = unknown
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('common', EosActionCommon, 0),
|
||||
2: ('transfer', EosActionTransfer, 0),
|
||||
3: ('delegate', EosActionDelegate, 0),
|
||||
4: ('undelegate', EosActionUndelegate, 0),
|
||||
5: ('refund', EosActionRefund, 0),
|
||||
6: ('buy_ram', EosActionBuyRam, 0),
|
||||
7: ('buy_ram_bytes', EosActionBuyRamBytes, 0),
|
||||
8: ('sell_ram', EosActionSellRam, 0),
|
||||
9: ('vote_producer', EosActionVoteProducer, 0),
|
||||
10: ('update_auth', EosActionUpdateAuth, 0),
|
||||
11: ('delete_auth', EosActionDeleteAuth, 0),
|
||||
12: ('link_auth', EosActionLinkAuth, 0),
|
||||
13: ('unlink_auth', EosActionUnlinkAuth, 0),
|
||||
14: ('new_account', EosActionNewAccount, 0),
|
||||
15: ('unknown', EosActionUnknown, 0),
|
||||
}
|
19
core/src/trezor/messages/EosTxActionRequest.py
Normal file
19
core/src/trezor/messages/EosTxActionRequest.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
|
||||
class EosTxActionRequest(p.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 603
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data_size: int = None,
|
||||
) -> None:
|
||||
self.data_size = data_size
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('data_size', p.UVarintType, 0),
|
||||
}
|
33
core/src/trezor/messages/EosTxHeader.py
Normal file
33
core/src/trezor/messages/EosTxHeader.py
Normal file
@ -0,0 +1,33 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
|
||||
class EosTxHeader(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
expiration: int = None,
|
||||
ref_block_num: int = None,
|
||||
ref_block_prefix: int = None,
|
||||
max_net_usage_words: int = None,
|
||||
max_cpu_usage_ms: int = None,
|
||||
delay_sec: int = None,
|
||||
) -> None:
|
||||
self.expiration = expiration
|
||||
self.ref_block_num = ref_block_num
|
||||
self.ref_block_prefix = ref_block_prefix
|
||||
self.max_net_usage_words = max_net_usage_words
|
||||
self.max_cpu_usage_ms = max_cpu_usage_ms
|
||||
self.delay_sec = delay_sec
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('expiration', p.UVarintType, 0), # required
|
||||
2: ('ref_block_num', p.UVarintType, 0), # required
|
||||
3: ('ref_block_prefix', p.UVarintType, 0), # required
|
||||
4: ('max_net_usage_words', p.UVarintType, 0), # required
|
||||
5: ('max_cpu_usage_ms', p.UVarintType, 0), # required
|
||||
6: ('delay_sec', p.UVarintType, 0), # required
|
||||
}
|
64
core/tests/test_apps.eos.check_action.py
Normal file
64
core/tests/test_apps.eos.check_action.py
Normal file
@ -0,0 +1,64 @@
|
||||
from common import *
|
||||
|
||||
from apps.eos.actions import check_action
|
||||
from trezor.messages.EosTxActionAck import EosTxActionAck
|
||||
from trezor.messages.EosActionBuyRam import EosActionBuyRam
|
||||
from trezor.messages.EosActionBuyRamBytes import EosActionBuyRamBytes
|
||||
from trezor.messages.EosActionDelegate import EosActionDelegate
|
||||
from trezor.messages.EosActionDeleteAuth import EosActionDeleteAuth
|
||||
from trezor.messages.EosActionLinkAuth import EosActionLinkAuth
|
||||
from trezor.messages.EosActionNewAccount import EosActionNewAccount
|
||||
from trezor.messages.EosActionRefund import EosActionRefund
|
||||
from trezor.messages.EosActionSellRam import EosActionSellRam
|
||||
from trezor.messages.EosActionTransfer import EosActionTransfer
|
||||
from trezor.messages.EosActionUndelegate import EosActionUndelegate
|
||||
from trezor.messages.EosActionUnlinkAuth import EosActionUnlinkAuth
|
||||
from trezor.messages.EosActionUpdateAuth import EosActionUpdateAuth
|
||||
from trezor.messages.EosActionVoteProducer import EosActionVoteProducer
|
||||
|
||||
|
||||
class TestEosActions(unittest.TestCase):
|
||||
def test_check_action(self):
|
||||
# return True
|
||||
self.assertEqual(check_action(EosTxActionAck(buy_ram=EosActionBuyRam()), 'buyram', 'eosio'), True)
|
||||
self.assertEqual(check_action(EosTxActionAck(buy_ram_bytes=EosActionBuyRamBytes()), 'buyrambytes', 'eosio'), True)
|
||||
self.assertEqual(check_action(EosTxActionAck(sell_ram=EosActionSellRam()), 'sellram', 'eosio'), True)
|
||||
self.assertEqual(check_action(EosTxActionAck(delegate=EosActionDelegate()), 'delegatebw', 'eosio'), True)
|
||||
self.assertEqual(check_action(EosTxActionAck(undelegate=EosActionDeleteAuth()), 'undelegatebw', 'eosio'), True)
|
||||
self.assertEqual(check_action(EosTxActionAck(refund=EosActionRefund()), 'refund', 'eosio'), True)
|
||||
self.assertEqual(check_action(EosTxActionAck(vote_producer=EosActionVoteProducer()), 'voteproducer', 'eosio'), True)
|
||||
self.assertEqual(check_action(EosTxActionAck(update_auth=EosActionUpdateAuth()), 'updateauth', 'eosio'), True)
|
||||
self.assertEqual(check_action(EosTxActionAck(delete_auth=EosActionDeleteAuth()), 'deleteauth', 'eosio'), True)
|
||||
self.assertEqual(check_action(EosTxActionAck(link_auth=EosActionLinkAuth()), 'linkauth', 'eosio'), True)
|
||||
self.assertEqual(check_action(EosTxActionAck(unlink_auth=EosActionUnlinkAuth()), 'unlinkauth', 'eosio'), True)
|
||||
self.assertEqual(check_action(EosTxActionAck(new_account=EosActionNewAccount()), 'newaccount', 'eosio'), True)
|
||||
self.assertEqual(check_action(EosTxActionAck(transfer=EosActionTransfer()), 'transfer', 'not_eosio'), True)
|
||||
self.assertEqual(check_action(EosTxActionAck(unknown=[]), 'unknown', 'not_eosio'), True)
|
||||
self.assertEqual(check_action(EosTxActionAck(unknown=[]), 'buyram', 'buygoods'), True)
|
||||
|
||||
|
||||
# returns False
|
||||
self.assertEqual(check_action(EosTxActionAck(buy_ram=EosActionBuyRam()), 'buyram', 'not_eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(), 'buyram', 'eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(buy_ram_bytes=EosActionBuyRamBytes()), 'buyrambytes', 'not_eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(sell_ram=EosActionSellRam()), 'sellram', 'not_eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(delegate=EosActionDelegate()), 'delegatebw', 'not_eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(undelegate=EosActionDeleteAuth()), 'undelegatebw', 'not_eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(refund=EosActionRefund()), 'refund', 'not_eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(), 'refund', 'eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(vote_producer=EosActionVoteProducer()), 'voteproducer', 'not_eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(update_auth=EosActionUpdateAuth()), 'updateauth', 'not_eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(delete_auth=EosActionDeleteAuth()), 'deleteauth', 'not_eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(link_auth=EosActionLinkAuth()), 'linkauth', 'not_eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(unlink_auth=EosActionUnlinkAuth()), 'unlinkauth', 'not_eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(), 'unlinkauth', 'eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(new_account=EosActionNewAccount()), 'newaccount', 'not_eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(transfer=EosActionTransfer()), 'transfer', 'eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(), 'unknown', 'not_eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(buy_ram=EosActionBuyRam()), 'test', 'eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(unknown=[]), 'buyram', 'eosio'), False)
|
||||
self.assertEqual(check_action(EosTxActionAck(unknown=[]), 'transfer', 'loveme'), False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
66
core/tests/test_apps.eos.conversions.py
Normal file
66
core/tests/test_apps.eos.conversions.py
Normal file
@ -0,0 +1,66 @@
|
||||
from common import *
|
||||
|
||||
from apps.eos import helpers
|
||||
from trezor.messages.EosAsset import EosAsset
|
||||
|
||||
class TestEosConversions(unittest.TestCase):
|
||||
def test_eos_name_to_string(self):
|
||||
names_in = [
|
||||
10639447606881920736,
|
||||
614251623682315968,
|
||||
614251535012020768,
|
||||
7754926748989239168,
|
||||
14895601873759291472,
|
||||
595056260442243600,
|
||||
]
|
||||
names_out = [
|
||||
'miniminimini',
|
||||
'12345abcdefg',
|
||||
'123451234512',
|
||||
'hijklmnopqrs',
|
||||
'tuvwxyz12345',
|
||||
'111111111111',
|
||||
]
|
||||
for i, o in zip(names_in, names_out):
|
||||
self.assertEqual(helpers.eos_name_to_string(i), o)
|
||||
|
||||
def test_eos_asset_to_string(self):
|
||||
asset_in = [
|
||||
EosAsset(
|
||||
amount=10000,
|
||||
symbol=1397703940,
|
||||
),
|
||||
EosAsset(
|
||||
amount=200000,
|
||||
symbol=1397703940,
|
||||
),
|
||||
EosAsset(
|
||||
amount=255000,
|
||||
symbol=1397703940,
|
||||
),
|
||||
EosAsset(
|
||||
amount=999999,
|
||||
symbol=1397703939,
|
||||
),
|
||||
EosAsset(
|
||||
amount=1,
|
||||
symbol=1397703940,
|
||||
),
|
||||
EosAsset(
|
||||
amount=999,
|
||||
symbol=1397703939,
|
||||
),
|
||||
]
|
||||
asset_out = [
|
||||
'1.0000 EOS',
|
||||
'20.0000 EOS',
|
||||
'25.5000 EOS',
|
||||
'999.999 EOS',
|
||||
'0.0001 EOS',
|
||||
'0.999 EOS',
|
||||
]
|
||||
for i, o in zip(asset_in, asset_out):
|
||||
self.assertEqual(helpers.eos_asset_to_string(i), o)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
72
core/tests/test_apps.eos.get_public_key.py
Executable file
72
core/tests/test_apps.eos.get_public_key.py
Executable file
@ -0,0 +1,72 @@
|
||||
from common import *
|
||||
|
||||
from apps.eos.get_public_key import _get_public_key, _public_key_to_wif
|
||||
from trezor.crypto import bip32, bip39
|
||||
from ubinascii import hexlify, unhexlify
|
||||
from apps.common.paths import HARDENED
|
||||
from apps.eos.helpers import validate_full_path
|
||||
|
||||
|
||||
class TestEosGetPublicKey(unittest.TestCase):
|
||||
def test_get_public_key_scheme(self):
|
||||
mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
|
||||
seed = bip39.seed(mnemonic, '')
|
||||
|
||||
derivation_paths = [
|
||||
[0x80000000 | 44, 0x80000000 | 194, 0x80000000, 0, 0],
|
||||
[0x80000000 | 44, 0x80000000 | 194, 0x80000000, 0, 1],
|
||||
[0x80000000 | 44, 0x80000000 | 194],
|
||||
[0x80000000 | 44, 0x80000000 | 194, 0x80000000, 0, 0x80000000],
|
||||
]
|
||||
|
||||
public_keys = [
|
||||
b'0315c358024ce46767102578947584c4342a6982b922d454f63588effa34597197',
|
||||
b'029622eff7248c4d298fe28f2df19ee0d5f7674f678844e05c31d1a5632412869e',
|
||||
b'02625f33c10399703e95e41bd5054beef3ab893dcc7df2bb9bdcee48359b29069d',
|
||||
b'037c9b7d24d42589941cca3f4debc75b37c0e7b881e6eb00d2e674958debe3bbc3',
|
||||
]
|
||||
|
||||
wif_keys = [
|
||||
'EOS6zpSNY1YoLxNt2VsvJjoDfBueU6xC1M1ERJw1UoekL1NHn8KNA',
|
||||
'EOS62cPUiWnLqbUjiBMxbEU4pm4Hp5X3RGk4KMTadvZNygjX72yHW',
|
||||
'EOS5dp8aCFoFwrKo6KuUfos1hwMfZGkiZUbaF2CyuD4chyBEN2wQK',
|
||||
'EOS7n7TXwR4Y3DtPt2ji6akhQi5uw4SruuPArvoNJso84vhwPQt1G',
|
||||
]
|
||||
|
||||
for index, path in enumerate(derivation_paths):
|
||||
node = bip32.from_seed(seed, 'secp256k1')
|
||||
node.derive_path(path)
|
||||
wif, public_key = _get_public_key(node)
|
||||
|
||||
self.assertEqual(hexlify(public_key), public_keys[index])
|
||||
self.assertEqual(wif, wif_keys[index])
|
||||
self.assertEqual(_public_key_to_wif(public_key), wif_keys[index])
|
||||
|
||||
def test_paths(self):
|
||||
# 44'/194'/a'/0/0 is correct
|
||||
incorrect_paths = [
|
||||
[44 | HARDENED],
|
||||
[44 | HARDENED, 194 | HARDENED],
|
||||
[44 | HARDENED, 194 | HARDENED, 0 | HARDENED, 0, 0, 0],
|
||||
[44 | HARDENED, 194 | HARDENED, 0 | HARDENED, 0 | HARDENED],
|
||||
[44 | HARDENED, 194 | HARDENED, 0 | HARDENED, 0 | HARDENED, 0 | HARDENED],
|
||||
[44 | HARDENED, 194 | HARDENED, 0 | HARDENED, 1, 0],
|
||||
[44 | HARDENED, 194 | HARDENED, 0 | HARDENED, 0, 1],
|
||||
[44 | HARDENED, 160 | HARDENED, 0 | HARDENED, 0, 0],
|
||||
[44 | HARDENED, 199 | HARDENED, 0 | HARDENED, 0, 9999],
|
||||
]
|
||||
correct_paths = [
|
||||
[44 | HARDENED, 194 | HARDENED, 0 | HARDENED, 0, 0],
|
||||
[44 | HARDENED, 194 | HARDENED, 9 | HARDENED, 0, 0],
|
||||
[44 | HARDENED, 194 | HARDENED, 9999 | HARDENED, 0, 0],
|
||||
]
|
||||
|
||||
for path in incorrect_paths:
|
||||
self.assertFalse(validate_full_path(path))
|
||||
|
||||
for path in correct_paths:
|
||||
self.assertTrue(validate_full_path(path))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -12,6 +12,7 @@ rm -f ../src/trezor/messages/[A-Z]*.py
|
||||
../vendor/trezor-common/protob/messages-common.proto \
|
||||
../vendor/trezor-common/protob/messages-crypto.proto \
|
||||
../vendor/trezor-common/protob/messages-debug.proto \
|
||||
../vendor/trezor-common/protob/messages-eos.proto \
|
||||
../vendor/trezor-common/protob/messages-ethereum.proto \
|
||||
../vendor/trezor-common/protob/messages-lisk.proto \
|
||||
../vendor/trezor-common/protob/messages-management.proto \
|
||||
|
@ -32,6 +32,8 @@ Use the following command to see all options:
|
||||
disable-passphrase Disable passphrase.
|
||||
enable-passphrase Enable passphrase.
|
||||
encrypt-keyvalue Encrypt value by given key and path.
|
||||
eos_get_public_key Get EOS public key in base58 encoding.
|
||||
eos_sign_transaction Sign EOS transaction...
|
||||
ethereum-get-address Get Ethereum address in hex encoding.
|
||||
ethereum-sign-message Sign message with Ethereum address.
|
||||
ethereum-sign-tx Sign (and optionally publish) Ethereum transaction.
|
||||
|
@ -37,6 +37,7 @@ from trezorlib import (
|
||||
cosi,
|
||||
debuglink,
|
||||
device,
|
||||
eos,
|
||||
ethereum,
|
||||
exceptions,
|
||||
firmware,
|
||||
@ -1414,6 +1415,48 @@ def ethereum_sign_tx(
|
||||
return "Signed raw transaction:\n%s" % tx_hex
|
||||
|
||||
|
||||
#
|
||||
# EOS functions
|
||||
#
|
||||
|
||||
|
||||
@cli.command(help="Get Eos public key in base58 encoding.")
|
||||
@click.option(
|
||||
"-n", "--address", required=True, help="BIP-32 path, e.g. m/44'/194'/0'/0/0"
|
||||
)
|
||||
@click.option("-d", "--show-display", is_flag=True)
|
||||
@click.pass_obj
|
||||
def eos_get_public_key(connect, address, show_display):
|
||||
client = connect()
|
||||
address_n = tools.parse_path(address)
|
||||
res = eos.get_public_key(client, address_n, show_display)
|
||||
return "WIF: {}\nRaw: {}".format(res.wif_public_key, res.raw_public_key.hex())
|
||||
|
||||
|
||||
@cli.command(help="Init sign (and optionally publish) EOS transaction. ")
|
||||
@click.option(
|
||||
"-n",
|
||||
"--address",
|
||||
required=True,
|
||||
help="BIP-32 path to source address, e.g., m/44'/194'/0'/0/0",
|
||||
)
|
||||
@click.option(
|
||||
"-f",
|
||||
"--file",
|
||||
type=click.File("r"),
|
||||
required=True,
|
||||
help="Transaction in JSON format",
|
||||
)
|
||||
@click.pass_obj
|
||||
def eos_sign_transaction(connect, address, file):
|
||||
client = connect()
|
||||
|
||||
tx_json = json.load(file)
|
||||
|
||||
address_n = tools.parse_path(address)
|
||||
return eos.sign_tx(client, address_n, tx_json["transaction"], tx_json["chain_id"])
|
||||
|
||||
|
||||
#
|
||||
# ADA functions
|
||||
#
|
||||
|
332
python/trezorlib/eos.py
Normal file
332
python/trezorlib/eos.py
Normal file
@ -0,0 +1,332 @@
|
||||
from datetime import datetime
|
||||
|
||||
from . import messages
|
||||
from .tools import CallException, b58decode, expect, session
|
||||
|
||||
|
||||
def name_to_number(name):
|
||||
length = len(name)
|
||||
value = 0
|
||||
|
||||
for i in range(0, 13):
|
||||
c = 0
|
||||
if i < length and i < 13:
|
||||
c = char_to_symbol(name[i])
|
||||
|
||||
if i < 12:
|
||||
c &= 0x1F
|
||||
c <<= 64 - 5 * (i + 1)
|
||||
else:
|
||||
c &= 0x0F
|
||||
|
||||
value |= c
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def char_to_symbol(c):
|
||||
if c >= "a" and c <= "z":
|
||||
return ord(c) - ord("a") + 6
|
||||
elif c >= "1" and c <= "5":
|
||||
return ord(c) - ord("1") + 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
def parse_asset(asset):
|
||||
amount_str, symbol_str = asset.split(" ")
|
||||
|
||||
# "-1.0000" => ["-1", "0000"] => -10000
|
||||
amount_parts = amount_str.split(".", maxsplit=1)
|
||||
amount = int("".join(amount_parts))
|
||||
|
||||
precision = 0
|
||||
if len(amount_parts) > 1:
|
||||
precision = len(amount_parts[1])
|
||||
|
||||
# 4, "EOS" => b"\x04EOS" => little-endian uint32
|
||||
symbol_bytes = bytes([precision]) + symbol_str.encode()
|
||||
symbol = int.from_bytes(symbol_bytes, "little")
|
||||
|
||||
return messages.EosAsset(amount=amount, symbol=symbol)
|
||||
|
||||
|
||||
def public_key_to_buffer(pub_key):
|
||||
_t = 0
|
||||
if pub_key[:3] == "EOS":
|
||||
pub_key = pub_key[3:]
|
||||
_t = 0
|
||||
elif pub_key[:7] == "PUB_K1_":
|
||||
pub_key = pub_key[7:]
|
||||
_t = 0
|
||||
elif pub_key[:7] == "PUB_R1_":
|
||||
pub_key = pub_key[7:]
|
||||
_t = 1
|
||||
|
||||
return _t, b58decode(pub_key, None)[:-4]
|
||||
|
||||
|
||||
def parse_common(action):
|
||||
authorization = []
|
||||
for auth in action["authorization"]:
|
||||
authorization.append(
|
||||
messages.EosPermissionLevel(
|
||||
actor=name_to_number(auth["actor"]),
|
||||
permission=name_to_number(auth["permission"]),
|
||||
)
|
||||
)
|
||||
|
||||
return messages.EosActionCommon(
|
||||
account=name_to_number(action["account"]),
|
||||
name=name_to_number(action["name"]),
|
||||
authorization=authorization,
|
||||
)
|
||||
|
||||
|
||||
def parse_transfer(data):
|
||||
return messages.EosActionTransfer(
|
||||
sender=name_to_number(data["from"]),
|
||||
receiver=name_to_number(data["to"]),
|
||||
memo=data["memo"],
|
||||
quantity=parse_asset(data["quantity"]),
|
||||
)
|
||||
|
||||
|
||||
def parse_vote_producer(data):
|
||||
producers = []
|
||||
for producer in data["producers"]:
|
||||
producers.append(name_to_number(producer))
|
||||
|
||||
return messages.EosActionVoteProducer(
|
||||
voter=name_to_number(data["account"]),
|
||||
proxy=name_to_number(data["proxy"]),
|
||||
producers=producers,
|
||||
)
|
||||
|
||||
|
||||
def parse_buy_ram(data):
|
||||
return messages.EosActionBuyRam(
|
||||
payer=name_to_number(data["payer"]),
|
||||
receiver=name_to_number(data["receiver"]),
|
||||
quantity=parse_asset(data["quant"]),
|
||||
)
|
||||
|
||||
|
||||
def parse_buy_rambytes(data):
|
||||
return messages.EosActionBuyRamBytes(
|
||||
payer=name_to_number(data["payer"]),
|
||||
receiver=name_to_number(data["receiver"]),
|
||||
bytes=int(data["bytes"]),
|
||||
)
|
||||
|
||||
|
||||
def parse_sell_ram(data):
|
||||
return messages.EosActionSellRam(
|
||||
account=name_to_number(data["account"]), bytes=int(data["bytes"])
|
||||
)
|
||||
|
||||
|
||||
def parse_delegate(data):
|
||||
return messages.EosActionDelegate(
|
||||
sender=name_to_number(data["sender"]),
|
||||
receiver=name_to_number(data["receiver"]),
|
||||
net_quantity=parse_asset(data["stake_net_quantity"]),
|
||||
cpu_quantity=parse_asset(data["stake_cpu_quantity"]),
|
||||
transfer=bool(data["transfer"]),
|
||||
)
|
||||
|
||||
|
||||
def parse_undelegate(data):
|
||||
return messages.EosActionUndelegate(
|
||||
sender=name_to_number(data["sender"]),
|
||||
receiver=name_to_number(data["receiver"]),
|
||||
net_quantity=parse_asset(data["unstake_net_quantity"]),
|
||||
cpu_quantity=parse_asset(data["unstake_cpu_quantity"]),
|
||||
)
|
||||
|
||||
|
||||
def parse_refund(data):
|
||||
return messages.EosActionRefund(owner=name_to_number(data["owner"]))
|
||||
|
||||
|
||||
def parse_updateauth(data):
|
||||
auth = parse_authorization(data["auth"])
|
||||
|
||||
return messages.EosActionUpdateAuth(
|
||||
account=name_to_number(data["account"]),
|
||||
permission=name_to_number(data["permission"]),
|
||||
parent=name_to_number(data["parent"]),
|
||||
auth=auth,
|
||||
)
|
||||
|
||||
|
||||
def parse_deleteauth(data):
|
||||
return messages.EosActionDeleteAuth(
|
||||
account=name_to_number(data["account"]),
|
||||
permission=name_to_number(data["permission"]),
|
||||
)
|
||||
|
||||
|
||||
def parse_linkauth(data):
|
||||
return messages.EosActionLinkAuth(
|
||||
account=name_to_number(data["account"]),
|
||||
code=name_to_number(data["code"]),
|
||||
type=name_to_number(data["type"]),
|
||||
requirement=name_to_number(data["requirement"]),
|
||||
)
|
||||
|
||||
|
||||
def parse_unlinkauth(data):
|
||||
return messages.EosActionUnlinkAuth(
|
||||
account=name_to_number(data["account"]),
|
||||
code=name_to_number(data["code"]),
|
||||
type=name_to_number(data["type"]),
|
||||
)
|
||||
|
||||
|
||||
def parse_authorization(data):
|
||||
keys = []
|
||||
for key in data["keys"]:
|
||||
_t, _k = public_key_to_buffer(key["key"])
|
||||
|
||||
keys.append(
|
||||
messages.EosAuthorizationKey(type=_t, key=_k, weight=int(key["weight"]))
|
||||
)
|
||||
|
||||
accounts = []
|
||||
for account in data["accounts"]:
|
||||
accounts.append(
|
||||
messages.EosAuthorizationAccount(
|
||||
account=messages.EosPermissionLevel(
|
||||
actor=name_to_number(account["permission"]["actor"]),
|
||||
permission=name_to_number(account["permission"]["permission"]),
|
||||
),
|
||||
weight=int(account["weight"]),
|
||||
)
|
||||
)
|
||||
|
||||
waits = []
|
||||
for wait in data["waits"]:
|
||||
waits.append(
|
||||
messages.EosAuthorizationWait(
|
||||
wait_sec=int(wait["wait_sec"]), weight=int(wait["weight"])
|
||||
)
|
||||
)
|
||||
|
||||
return messages.EosAuthorization(
|
||||
threshold=int(data["threshold"]), keys=keys, accounts=accounts, waits=waits
|
||||
)
|
||||
|
||||
|
||||
def parse_new_account(data):
|
||||
owner = parse_authorization(data["owner"])
|
||||
active = parse_authorization(data["active"])
|
||||
|
||||
return messages.EosActionNewAccount(
|
||||
creator=name_to_number(data["creator"]),
|
||||
name=name_to_number(data["name"]),
|
||||
owner=owner,
|
||||
active=active,
|
||||
)
|
||||
|
||||
|
||||
def parse_unknown(data):
|
||||
data_bytes = bytes.fromhex(data)
|
||||
return messages.EosActionUnknown(data_size=len(data_bytes), data_chunk=data_bytes)
|
||||
|
||||
|
||||
def parse_action(action):
|
||||
tx_action = messages.EosTxActionAck()
|
||||
data = action["data"]
|
||||
|
||||
tx_action.common = parse_common(action)
|
||||
|
||||
if action["account"] == "eosio":
|
||||
if action["name"] == "voteproducer":
|
||||
tx_action.vote_producer = parse_vote_producer(data)
|
||||
elif action["name"] == "buyram":
|
||||
tx_action.buy_ram = parse_buy_ram(data)
|
||||
elif action["name"] == "buyrambytes":
|
||||
tx_action.buy_ram_bytes = parse_buy_rambytes(data)
|
||||
elif action["name"] == "sellram":
|
||||
tx_action.sell_ram = parse_sell_ram(data)
|
||||
elif action["name"] == "delegatebw":
|
||||
tx_action.delegate = parse_delegate(data)
|
||||
elif action["name"] == "undelegatebw":
|
||||
tx_action.undelegate = parse_undelegate(data)
|
||||
elif action["name"] == "refund":
|
||||
tx_action.refund = parse_refund(data)
|
||||
elif action["name"] == "updateauth":
|
||||
tx_action.update_auth = parse_updateauth(data)
|
||||
elif action["name"] == "deleteauth":
|
||||
tx_action.delete_auth = parse_deleteauth(data)
|
||||
elif action["name"] == "linkauth":
|
||||
tx_action.link_auth = parse_linkauth(data)
|
||||
elif action["name"] == "unlinkauth":
|
||||
tx_action.unlink_auth = parse_unlinkauth(data)
|
||||
elif action["name"] == "newaccount":
|
||||
tx_action.new_account = parse_new_account(data)
|
||||
elif action["name"] == "transfer":
|
||||
tx_action.transfer = parse_transfer(data)
|
||||
else:
|
||||
tx_action.unknown = parse_unknown(data)
|
||||
|
||||
return tx_action
|
||||
|
||||
|
||||
def parse_transaction_json(transaction):
|
||||
header = messages.EosTxHeader()
|
||||
header.expiration = int(
|
||||
(
|
||||
datetime.strptime(transaction["expiration"], "%Y-%m-%dT%H:%M:%S")
|
||||
- datetime(1970, 1, 1)
|
||||
).total_seconds()
|
||||
)
|
||||
header.ref_block_num = int(transaction["ref_block_num"])
|
||||
header.ref_block_prefix = int(transaction["ref_block_prefix"])
|
||||
header.max_net_usage_words = int(transaction["net_usage_words"])
|
||||
header.max_cpu_usage_ms = int(transaction["max_cpu_usage_ms"])
|
||||
header.delay_sec = int(transaction["delay_sec"])
|
||||
|
||||
actions = [parse_action(a) for a in transaction["actions"]]
|
||||
|
||||
return header, actions
|
||||
|
||||
|
||||
# ====== Client functions ====== #
|
||||
|
||||
|
||||
@expect(messages.EosPublicKey)
|
||||
def get_public_key(client, n, show_display=False, multisig=None):
|
||||
response = client.call(
|
||||
messages.EosGetPublicKey(address_n=n, show_display=show_display)
|
||||
)
|
||||
return response
|
||||
|
||||
|
||||
@session
|
||||
def sign_tx(client, address, transaction, chain_id):
|
||||
header, actions = parse_transaction_json(transaction)
|
||||
|
||||
msg = messages.EosSignTx()
|
||||
msg.address_n = address
|
||||
msg.chain_id = bytes.fromhex(chain_id)
|
||||
msg.header = header
|
||||
msg.num_actions = len(actions)
|
||||
|
||||
response = client.call(msg)
|
||||
|
||||
try:
|
||||
while isinstance(response, messages.EosTxActionRequest):
|
||||
response = client.call(actions.pop(0))
|
||||
except IndexError:
|
||||
# pop from empty list
|
||||
raise CallException(
|
||||
"Eos.UnexpectedEndOfOperations",
|
||||
"Reached end of operations without a signature.",
|
||||
) from None
|
||||
|
||||
if not isinstance(response, messages.EosSignedTx):
|
||||
raise CallException(messages.FailureType.UnexpectedMessage, response)
|
||||
|
||||
return response
|
@ -0,0 +1,40 @@
|
||||
import pytest
|
||||
|
||||
from trezorlib.eos import get_public_key
|
||||
from trezorlib.tools import parse_path
|
||||
|
||||
from .common import TrezorTest
|
||||
|
||||
|
||||
@pytest.mark.skip_t1
|
||||
@pytest.mark.eos
|
||||
class TestMsgEosGetpublickey(TrezorTest):
|
||||
def test_eos_get_public_key(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
public_key = get_public_key(self.client, parse_path("m/44'/194'/0'/0/0"))
|
||||
assert (
|
||||
public_key.wif_public_key
|
||||
== "EOS4u6Sfnzj4Sh2pEQnkXyZQJqH3PkKjGByDCbsqqmyq6PttM9KyB"
|
||||
)
|
||||
assert (
|
||||
public_key.raw_public_key.hex()
|
||||
== "02015fabe197c955036bab25f4e7c16558f9f672f9f625314ab1ec8f64f7b1198e"
|
||||
)
|
||||
public_key = get_public_key(self.client, parse_path("m/44'/194'/0'/0/1"))
|
||||
assert (
|
||||
public_key.wif_public_key
|
||||
== "EOS5d1VP15RKxT4dSakWu2TFuEgnmaGC2ckfSvQwND7pZC1tXkfLP"
|
||||
)
|
||||
assert (
|
||||
public_key.raw_public_key.hex()
|
||||
== "02608bc2c431521dee0b9d5f2fe34053e15fc3b20d2895e0abda857b9ed8e77a78"
|
||||
)
|
||||
public_key = get_public_key(self.client, parse_path("m/44'/194'/1'/0/0"))
|
||||
assert (
|
||||
public_key.wif_public_key
|
||||
== "EOS7UuNeTf13nfcG85rDB7AHGugZi4C4wJ4ft12QRotqNfxdV2NvP"
|
||||
)
|
||||
assert (
|
||||
public_key.raw_public_key.hex()
|
||||
== "035588a197bd5a7356e8a702361b2d535c6372f843874bed6617cd1afe1dfcb502"
|
||||
)
|
860
python/trezorlib/tests/device_tests/test_msg_eos_signtx.py
Normal file
860
python/trezorlib/tests/device_tests/test_msg_eos_signtx.py
Normal file
@ -0,0 +1,860 @@
|
||||
# This file is part of the Trezor project.
|
||||
#
|
||||
# Copyright (C) 2012-2018 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 time
|
||||
|
||||
import pytest
|
||||
|
||||
from trezorlib import eos
|
||||
from trezorlib.messages import EosSignedTx
|
||||
from trezorlib.tools import parse_path
|
||||
|
||||
from .common import TrezorTest
|
||||
|
||||
CHAIN_ID = "cf057bbfb72640471fd910bcb67639c22df9f92470936cddc1ade0e2f2e7dc4f"
|
||||
ADDRESS_N = parse_path("m/44'/194'/0'/0/0")
|
||||
|
||||
|
||||
@pytest.mark.skip_t1
|
||||
@pytest.mark.eos
|
||||
class TestMsgEosSignTx(TrezorTest):
|
||||
def input_flow(self, pages):
|
||||
# confirm number of actions
|
||||
yield
|
||||
self.client.debug.press_yes()
|
||||
|
||||
# swipe through pages
|
||||
yield
|
||||
for _ in range(pages - 1):
|
||||
self.client.debug.swipe_down()
|
||||
time.sleep(1)
|
||||
|
||||
# confirm last page
|
||||
self.client.debug.press_yes()
|
||||
|
||||
def test_eos_signtx_transfer_token(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
transaction = {
|
||||
"expiration": "2018-07-14T10:43:28",
|
||||
"ref_block_num": 6439,
|
||||
"ref_block_prefix": 2995713264,
|
||||
"net_usage_words": 0,
|
||||
"max_cpu_usage_ms": 0,
|
||||
"delay_sec": 0,
|
||||
"context_free_actions": [],
|
||||
"actions": [
|
||||
{
|
||||
"account": "eosio.token",
|
||||
"name": "transfer",
|
||||
"authorization": [
|
||||
{"actor": "miniminimini", "permission": "active"}
|
||||
],
|
||||
"data": {
|
||||
"from": "miniminimini",
|
||||
"to": "maximaximaxi",
|
||||
"quantity": "1.0000 EOS",
|
||||
"memo": "testtest",
|
||||
},
|
||||
}
|
||||
],
|
||||
"transaction_extensions": [],
|
||||
}
|
||||
|
||||
with self.client:
|
||||
self.client.set_input_flow(self.input_flow(pages=3))
|
||||
resp = eos.sign_tx(self.client, ADDRESS_N, transaction, CHAIN_ID)
|
||||
|
||||
assert isinstance(resp, EosSignedTx)
|
||||
assert (
|
||||
resp.signature_r.hex()
|
||||
== "0a9a0f467697010b743ffd02eae6698464c8b5c84b696245397287c225f85e01"
|
||||
)
|
||||
assert (
|
||||
resp.signature_s.hex()
|
||||
== "3ec6a0175e5209be6789587a9d6b5f61593b841a751112faa05d9efdd9239d40"
|
||||
)
|
||||
assert resp.signature_v == 31
|
||||
|
||||
def test_eos_signtx_buyram(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
transaction = {
|
||||
"expiration": "2018-07-14T10:43:28",
|
||||
"ref_block_num": 6439,
|
||||
"ref_block_prefix": 2995713264,
|
||||
"net_usage_words": 0,
|
||||
"max_cpu_usage_ms": 0,
|
||||
"delay_sec": 0,
|
||||
"context_free_actions": [],
|
||||
"actions": [
|
||||
{
|
||||
"account": "eosio",
|
||||
"name": "buyram",
|
||||
"authorization": [
|
||||
{"actor": "miniminimini", "permission": "active"}
|
||||
],
|
||||
"data": {
|
||||
"payer": "miniminimini",
|
||||
"receiver": "miniminimini",
|
||||
"quant": "1000000000.0000 EOS",
|
||||
},
|
||||
}
|
||||
],
|
||||
"transaction_extensions": [],
|
||||
}
|
||||
|
||||
with self.client:
|
||||
self.client.set_input_flow(self.input_flow(pages=2))
|
||||
resp = eos.sign_tx(self.client, ADDRESS_N, transaction, CHAIN_ID)
|
||||
|
||||
assert isinstance(resp, EosSignedTx)
|
||||
assert (
|
||||
resp.signature_r.hex()
|
||||
== "480bdc505ba196d445d92ea12bda9d39f986d01620efcffe98bcf645ddcbb4ec"
|
||||
)
|
||||
assert (
|
||||
resp.signature_s.hex()
|
||||
== "35c8e2105f0228c9e1e511682ae79eac1b7b90bc84c1a0dae13245b7f0f96abf"
|
||||
)
|
||||
assert resp.signature_v == 31
|
||||
|
||||
def test_eos_signtx_buyrambytes(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
transaction = {
|
||||
"expiration": "2018-07-14T10:43:28",
|
||||
"ref_block_num": 6439,
|
||||
"ref_block_prefix": 2995713264,
|
||||
"net_usage_words": 0,
|
||||
"max_cpu_usage_ms": 0,
|
||||
"delay_sec": 0,
|
||||
"context_free_actions": [],
|
||||
"actions": [
|
||||
{
|
||||
"account": "eosio",
|
||||
"name": "buyrambytes",
|
||||
"authorization": [
|
||||
{"actor": "miniminimini", "permission": "active"}
|
||||
],
|
||||
"data": {
|
||||
"payer": "miniminimini",
|
||||
"receiver": "miniminimini",
|
||||
"bytes": 1023,
|
||||
},
|
||||
}
|
||||
],
|
||||
"transaction_extensions": [],
|
||||
}
|
||||
|
||||
with self.client:
|
||||
self.client.set_input_flow(self.input_flow(pages=2))
|
||||
resp = eos.sign_tx(self.client, ADDRESS_N, transaction, CHAIN_ID)
|
||||
|
||||
assert isinstance(resp, EosSignedTx)
|
||||
assert (
|
||||
resp.signature_r.hex()
|
||||
== "52267ee5f3ff73939af5ccdaa3406e0783deaf76accf5ce4ceb9714cdbdf7d6b"
|
||||
)
|
||||
assert (
|
||||
resp.signature_s.hex()
|
||||
== "53aa9a9ecf044396441a559b51d3b97e239321c895823aad6888b0de2063a078"
|
||||
)
|
||||
assert resp.signature_v == 31
|
||||
|
||||
def test_eos_signtx_sellram(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
transaction = {
|
||||
"expiration": "2018-07-14T10:43:28",
|
||||
"ref_block_num": 6439,
|
||||
"ref_block_prefix": 2995713264,
|
||||
"net_usage_words": 0,
|
||||
"max_cpu_usage_ms": 0,
|
||||
"delay_sec": 0,
|
||||
"context_free_actions": [],
|
||||
"actions": [
|
||||
{
|
||||
"account": "eosio",
|
||||
"name": "sellram",
|
||||
"authorization": [
|
||||
{"actor": "miniminimini", "permission": "active"}
|
||||
],
|
||||
"data": {"account": "miniminimini", "bytes": 1024},
|
||||
}
|
||||
],
|
||||
"transaction_extensions": [],
|
||||
}
|
||||
|
||||
with self.client:
|
||||
self.client.set_input_flow(self.input_flow(pages=2))
|
||||
resp = eos.sign_tx(self.client, ADDRESS_N, transaction, CHAIN_ID)
|
||||
|
||||
assert isinstance(resp, EosSignedTx)
|
||||
assert (
|
||||
resp.signature_r.hex()
|
||||
== "04c0fdf1d2e0ea21af292173eacc2c7db90f7764abe69b79a8c2b24201af27c4"
|
||||
)
|
||||
assert (
|
||||
resp.signature_s.hex()
|
||||
== "7bb29f12eaaabbebdb5190d30367012a80128138b5024b30e93e3afb3d24734e"
|
||||
)
|
||||
assert resp.signature_v == 31
|
||||
|
||||
def test_eos_signtx_delegate(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
transaction = {
|
||||
"expiration": "2018-07-14T10:43:28",
|
||||
"ref_block_num": 6439,
|
||||
"ref_block_prefix": 2995713264,
|
||||
"net_usage_words": 0,
|
||||
"max_cpu_usage_ms": 0,
|
||||
"delay_sec": 0,
|
||||
"context_free_actions": [],
|
||||
"actions": [
|
||||
{
|
||||
"account": "eosio",
|
||||
"name": "delegatebw",
|
||||
"authorization": [
|
||||
{"actor": "miniminimini", "permission": "active"}
|
||||
],
|
||||
"data": {
|
||||
"sender": "miniminimini",
|
||||
"receiver": "maximaximaxi",
|
||||
"stake_net_quantity": "1.0000 EOS",
|
||||
"stake_cpu_quantity": "1.0000 EOS",
|
||||
"transfer": True,
|
||||
},
|
||||
}
|
||||
],
|
||||
"transaction_extensions": [],
|
||||
}
|
||||
|
||||
with self.client:
|
||||
self.client.set_input_flow(self.input_flow(pages=3))
|
||||
resp = eos.sign_tx(self.client, ADDRESS_N, transaction, CHAIN_ID)
|
||||
|
||||
assert isinstance(resp, EosSignedTx)
|
||||
assert (
|
||||
resp.signature_r.hex()
|
||||
== "03b4ccb74b7ad54f28fdeda244facb3038cf70424fd6aa4b171a3bb02a591504"
|
||||
)
|
||||
assert (
|
||||
resp.signature_s.hex()
|
||||
== "4e24e08d1789421e17ba47e0e4635a3721400a795e40a8896dc5e5af4a95343d"
|
||||
)
|
||||
assert resp.signature_v == 31
|
||||
|
||||
def test_eos_signtx_undelegate(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
transaction = {
|
||||
"expiration": "2018-07-14T10:43:28",
|
||||
"ref_block_num": 6439,
|
||||
"ref_block_prefix": 2995713264,
|
||||
"net_usage_words": 0,
|
||||
"max_cpu_usage_ms": 0,
|
||||
"delay_sec": 0,
|
||||
"context_free_actions": [],
|
||||
"actions": [
|
||||
{
|
||||
"account": "eosio",
|
||||
"name": "undelegatebw",
|
||||
"authorization": [
|
||||
{"actor": "miniminimini", "permission": "active"}
|
||||
],
|
||||
"data": {
|
||||
"sender": "miniminimini",
|
||||
"receiver": "maximaximaxi",
|
||||
"unstake_net_quantity": "1.0000 EOS",
|
||||
"unstake_cpu_quantity": "1.0000 EOS",
|
||||
},
|
||||
}
|
||||
],
|
||||
"transaction_extensions": [],
|
||||
}
|
||||
|
||||
with self.client:
|
||||
self.client.set_input_flow(self.input_flow(pages=2))
|
||||
resp = eos.sign_tx(self.client, ADDRESS_N, transaction, CHAIN_ID)
|
||||
|
||||
assert isinstance(resp, EosSignedTx)
|
||||
assert (
|
||||
resp.signature_r.hex()
|
||||
== "3f39722a88f12395f3cfcdbe218c185f02295ec07a5da8f4b953d5ec3c9ec36b"
|
||||
)
|
||||
assert (
|
||||
resp.signature_s.hex()
|
||||
== "7acbae47d60cd538ca28fcc8f3dae8f03b3812e7719dd4e9c069a66dbac5ebf3"
|
||||
)
|
||||
assert resp.signature_v == 31
|
||||
|
||||
def test_eos_signtx_refund(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
transaction = {
|
||||
"expiration": "2018-07-14T10:43:28",
|
||||
"ref_block_num": 6439,
|
||||
"ref_block_prefix": 2995713264,
|
||||
"net_usage_words": 0,
|
||||
"max_cpu_usage_ms": 0,
|
||||
"delay_sec": 0,
|
||||
"context_free_actions": [],
|
||||
"actions": [
|
||||
{
|
||||
"account": "eosio",
|
||||
"name": "refund",
|
||||
"authorization": [
|
||||
{"actor": "miniminimini", "permission": "active"}
|
||||
],
|
||||
"data": {"owner": "miniminimini"},
|
||||
}
|
||||
],
|
||||
"transaction_extensions": [],
|
||||
}
|
||||
|
||||
with self.client:
|
||||
self.client.set_input_flow(self.input_flow(pages=2))
|
||||
resp = eos.sign_tx(self.client, ADDRESS_N, transaction, CHAIN_ID)
|
||||
|
||||
assert isinstance(resp, EosSignedTx)
|
||||
assert (
|
||||
resp.signature_r.hex()
|
||||
== "113c4867f77c371ff4701beb794ff0a0a6a1137a0115d0f4b5245c391e9f596f"
|
||||
)
|
||||
assert (
|
||||
resp.signature_s.hex()
|
||||
== "27203aaaeb8cdbc92c0af32f840c385ac6202e3b4e927bda59d397ebef513381"
|
||||
)
|
||||
assert resp.signature_v == 31
|
||||
|
||||
def test_eos_signtx_linkauth(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
transaction = {
|
||||
"expiration": "2018-07-14T10:43:28",
|
||||
"ref_block_num": 6439,
|
||||
"ref_block_prefix": 2995713264,
|
||||
"net_usage_words": 0,
|
||||
"max_cpu_usage_ms": 0,
|
||||
"delay_sec": 0,
|
||||
"context_free_actions": [],
|
||||
"actions": [
|
||||
{
|
||||
"account": "eosio",
|
||||
"name": "linkauth",
|
||||
"authorization": [
|
||||
{"actor": "miniminimini", "permission": "active"}
|
||||
],
|
||||
"data": {
|
||||
"account": "maximaximaxi",
|
||||
"code": "eosbet",
|
||||
"type": "whatever",
|
||||
"requirement": "active",
|
||||
},
|
||||
}
|
||||
],
|
||||
"transaction_extensions": [],
|
||||
}
|
||||
|
||||
with self.client:
|
||||
self.client.set_input_flow(self.input_flow(pages=2))
|
||||
resp = eos.sign_tx(self.client, ADDRESS_N, transaction, CHAIN_ID)
|
||||
|
||||
assert isinstance(resp, EosSignedTx)
|
||||
assert (
|
||||
resp.signature_r.hex()
|
||||
== "5c9bf154dc77649ccf5a997441fcd4041e9da79149078df27a1c6268cf237c75"
|
||||
)
|
||||
assert (
|
||||
resp.signature_s.hex()
|
||||
== "3e432ddcd17feb2997145d11240b0ca4344a01e2d96e9886533bca7ffceb10cd"
|
||||
)
|
||||
assert resp.signature_v == 32
|
||||
|
||||
def test_eos_signtx_unlinkauth(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
transaction = {
|
||||
"expiration": "2018-07-14T10:43:28",
|
||||
"ref_block_num": 6439,
|
||||
"ref_block_prefix": 2995713264,
|
||||
"net_usage_words": 0,
|
||||
"max_cpu_usage_ms": 0,
|
||||
"delay_sec": 0,
|
||||
"context_free_actions": [],
|
||||
"actions": [
|
||||
{
|
||||
"account": "eosio",
|
||||
"name": "unlinkauth",
|
||||
"authorization": [
|
||||
{"actor": "miniminimini", "permission": "active"}
|
||||
],
|
||||
"data": {
|
||||
"account": "miniminimini",
|
||||
"code": "eosbet",
|
||||
"type": "whatever",
|
||||
},
|
||||
}
|
||||
],
|
||||
"transaction_extensions": [],
|
||||
}
|
||||
|
||||
with self.client:
|
||||
self.client.set_input_flow(self.input_flow(pages=2))
|
||||
resp = eos.sign_tx(self.client, ADDRESS_N, transaction, CHAIN_ID)
|
||||
|
||||
assert isinstance(resp, EosSignedTx)
|
||||
assert (
|
||||
resp.signature_r.hex()
|
||||
== "316c296594fd7a4dd3b615d80c630fda256e9a3460b00d4f16eede1fb2af9574"
|
||||
)
|
||||
assert (
|
||||
resp.signature_s.hex()
|
||||
== "76d023913b4f323cfa857d144bf78a4d561954bb23c5df9a31649c9503c3a3b7"
|
||||
)
|
||||
assert resp.signature_v == 31
|
||||
|
||||
def test_eos_signtx_updateauth(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
transaction = {
|
||||
"expiration": "2018-07-14T10:43:28",
|
||||
"ref_block_num": 6439,
|
||||
"ref_block_prefix": 2995713264,
|
||||
"net_usage_words": 0,
|
||||
"max_cpu_usage_ms": 0,
|
||||
"delay_sec": 0,
|
||||
"context_free_actions": [],
|
||||
"actions": [
|
||||
{
|
||||
"account": "eosio",
|
||||
"name": "updateauth",
|
||||
"authorization": [
|
||||
{"actor": "miniminimini", "permission": "active"}
|
||||
],
|
||||
"data": {
|
||||
"account": "miniminimini",
|
||||
"permission": "active",
|
||||
"parent": "owner",
|
||||
"auth": {
|
||||
"threshold": 1,
|
||||
"keys": [
|
||||
{
|
||||
"key": "EOS8Dkj827FpinZBGmhTM28B85H9eXiFH5XzvLoeukCJV5sKfLc6K",
|
||||
"weight": 1,
|
||||
},
|
||||
{
|
||||
"key": "EOS8Dkj827FpinZBGmhTM28B85H9eXiFH5XzvLoeukCJV5sKfLc6K",
|
||||
"weight": 2,
|
||||
},
|
||||
],
|
||||
"accounts": [
|
||||
{
|
||||
"permission": {
|
||||
"actor": "miniminimini",
|
||||
"permission": "active",
|
||||
},
|
||||
"weight": 3,
|
||||
}
|
||||
],
|
||||
"waits": [{"wait_sec": 55, "weight": 4}],
|
||||
},
|
||||
},
|
||||
}
|
||||
],
|
||||
"transaction_extensions": [],
|
||||
}
|
||||
|
||||
with self.client:
|
||||
self.client.set_input_flow(self.input_flow(pages=8))
|
||||
resp = eos.sign_tx(self.client, ADDRESS_N, transaction, CHAIN_ID)
|
||||
|
||||
assert isinstance(resp, EosSignedTx)
|
||||
assert (
|
||||
resp.signature_r.hex()
|
||||
== "00f0ca8ffa8208e72df509a3b356e77056b234d4db167b58d485f30cb9c61841"
|
||||
)
|
||||
assert (
|
||||
resp.signature_s.hex()
|
||||
== "3f6fb40ffa4e1cf6f3bcb0d8fa3873a2b5a05384ca9251159968558688a4e43d"
|
||||
)
|
||||
assert resp.signature_v == 31
|
||||
|
||||
def test_eos_signtx_deleteauth(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
transaction = {
|
||||
"expiration": "2018-07-14T10:43:28",
|
||||
"ref_block_num": 6439,
|
||||
"ref_block_prefix": 2995713264,
|
||||
"net_usage_words": 0,
|
||||
"max_cpu_usage_ms": 0,
|
||||
"delay_sec": 0,
|
||||
"context_free_actions": [],
|
||||
"actions": [
|
||||
{
|
||||
"account": "eosio",
|
||||
"name": "deleteauth",
|
||||
"authorization": [
|
||||
{"actor": "miniminimini", "permission": "active"}
|
||||
],
|
||||
"data": {"account": "maximaximaxi", "permission": "active"},
|
||||
}
|
||||
],
|
||||
"transaction_extensions": [],
|
||||
}
|
||||
|
||||
with self.client:
|
||||
self.client.set_input_flow(self.input_flow(pages=2))
|
||||
resp = eos.sign_tx(self.client, ADDRESS_N, transaction, CHAIN_ID)
|
||||
|
||||
assert isinstance(resp, EosSignedTx)
|
||||
assert (
|
||||
resp.signature_r.hex()
|
||||
== "6fe7d66f8be2fe3de23c48561e8a17113d1a0aabcf0d4160e9bd8af90f5a608f"
|
||||
)
|
||||
assert (
|
||||
resp.signature_s.hex()
|
||||
== "3cec8db96be2f6aa7bb00302cec6ad3c8655b492f9a2b84b3c61df6bc81f0d83"
|
||||
)
|
||||
assert resp.signature_v == 32
|
||||
|
||||
def test_eos_signtx_vote(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
transaction = {
|
||||
"expiration": "2018-07-14T10:43:28",
|
||||
"ref_block_num": 6439,
|
||||
"ref_block_prefix": 2995713264,
|
||||
"net_usage_words": 0,
|
||||
"max_cpu_usage_ms": 0,
|
||||
"delay_sec": 0,
|
||||
"context_free_actions": [],
|
||||
"actions": [
|
||||
{
|
||||
"account": "eosio",
|
||||
"name": "voteproducer",
|
||||
"authorization": [
|
||||
{"actor": "miniminimini", "permission": "active"}
|
||||
],
|
||||
"data": {
|
||||
"account": "miniminimini",
|
||||
"proxy": "",
|
||||
"producers": [
|
||||
"argentinaeos",
|
||||
"bitfinexeos1",
|
||||
"cryptolions1",
|
||||
"eos42freedom",
|
||||
"eosamsterdam",
|
||||
"eosasia11111",
|
||||
"eosauthority",
|
||||
"eosbeijingbp",
|
||||
"eosbixinboot",
|
||||
"eoscafeblock",
|
||||
"eoscanadacom",
|
||||
"eoscannonchn",
|
||||
"eoscleanerbp",
|
||||
"eosdacserver",
|
||||
"eosfishrocks",
|
||||
"eosflytomars",
|
||||
"eoshuobipool",
|
||||
"eosisgravity",
|
||||
"eoslaomaocom",
|
||||
"eosliquideos",
|
||||
"eosnewyorkio",
|
||||
"eosriobrazil",
|
||||
"eosswedenorg",
|
||||
"eostribeprod",
|
||||
"helloeoscnbp",
|
||||
"jedaaaaaaaaa",
|
||||
"libertyblock",
|
||||
"starteosiobp",
|
||||
"teamgreymass",
|
||||
],
|
||||
},
|
||||
}
|
||||
],
|
||||
"transaction_extensions": [],
|
||||
}
|
||||
|
||||
with self.client:
|
||||
self.client.set_input_flow(self.input_flow(pages=6))
|
||||
resp = eos.sign_tx(self.client, ADDRESS_N, transaction, CHAIN_ID)
|
||||
|
||||
assert isinstance(resp, EosSignedTx)
|
||||
assert (
|
||||
resp.signature_r.hex()
|
||||
== "1a303dcb27d2d17bc9efc89b10c41d9d78f7e3d671e3475bb1115b988f918770"
|
||||
)
|
||||
assert (
|
||||
resp.signature_s.hex()
|
||||
== "07869385bf3af8cf0a4ee9daf4f8dd122650c7d59da48d6d9ce1e26b59753324"
|
||||
)
|
||||
assert resp.signature_v == 31
|
||||
|
||||
def test_eos_signtx_vote_proxy(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
transaction = {
|
||||
"expiration": "2018-07-14T10:43:28",
|
||||
"ref_block_num": 6439,
|
||||
"ref_block_prefix": 2995713264,
|
||||
"net_usage_words": 0,
|
||||
"max_cpu_usage_ms": 0,
|
||||
"delay_sec": 0,
|
||||
"context_free_actions": [],
|
||||
"actions": [
|
||||
{
|
||||
"account": "eosio",
|
||||
"name": "voteproducer",
|
||||
"authorization": [
|
||||
{"actor": "miniminimini", "permission": "active"}
|
||||
],
|
||||
"data": {"account": "miniminimini", "proxy": "", "producers": []},
|
||||
}
|
||||
],
|
||||
"transaction_extensions": [],
|
||||
}
|
||||
|
||||
with self.client:
|
||||
self.client.set_input_flow(self.input_flow(pages=2))
|
||||
resp = eos.sign_tx(self.client, ADDRESS_N, transaction, CHAIN_ID)
|
||||
|
||||
assert isinstance(resp, EosSignedTx)
|
||||
assert (
|
||||
resp.signature_r.hex()
|
||||
== "6f511059a910d256ac20483bfedef2ada3b2d04f3261c97c0fce9455ca8b7ef4"
|
||||
)
|
||||
assert (
|
||||
resp.signature_s.hex()
|
||||
== "58d795deaf5c9b686e5bcaeabee801ad78e6675f051c24972d8c47abd33585f0"
|
||||
)
|
||||
assert resp.signature_v == 32
|
||||
|
||||
def test_eos_signtx_unknown(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
transaction = {
|
||||
"expiration": "2018-07-14T10:43:28",
|
||||
"ref_block_num": 6439,
|
||||
"ref_block_prefix": 2995713264,
|
||||
"net_usage_words": 0,
|
||||
"max_cpu_usage_ms": 0,
|
||||
"delay_sec": 0,
|
||||
"context_free_actions": [],
|
||||
"actions": [
|
||||
{
|
||||
"account": "foocontract",
|
||||
"name": "baraction",
|
||||
"authorization": [
|
||||
{"actor": "miniminimini", "permission": "active"}
|
||||
],
|
||||
"data": "deadbeef",
|
||||
}
|
||||
],
|
||||
"transaction_extensions": [],
|
||||
}
|
||||
|
||||
with self.client:
|
||||
self.client.set_input_flow(self.input_flow(pages=2))
|
||||
resp = eos.sign_tx(self.client, ADDRESS_N, transaction, CHAIN_ID)
|
||||
|
||||
assert isinstance(resp, EosSignedTx)
|
||||
assert (
|
||||
resp.signature_r.hex()
|
||||
== "0bcc986299cf4eb1d5e5bc73620972b2b6683cd4230953a6f1725017927fd9ba"
|
||||
)
|
||||
assert (
|
||||
resp.signature_s.hex()
|
||||
== "488f7830e30eea5c7b4a96156bf7ffb0983c45a96211ca070b9db3bc6ba4db02"
|
||||
)
|
||||
assert resp.signature_v == 31
|
||||
|
||||
def test_eos_signtx_newaccount(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
transaction = {
|
||||
"expiration": "2018-07-14T10:43:28",
|
||||
"ref_block_num": 6439,
|
||||
"ref_block_prefix": 2995713264,
|
||||
"net_usage_words": 0,
|
||||
"max_cpu_usage_ms": 0,
|
||||
"delay_sec": 0,
|
||||
"context_free_actions": [],
|
||||
"actions": [
|
||||
{
|
||||
"account": "eosio",
|
||||
"name": "newaccount",
|
||||
"authorization": [
|
||||
{"actor": "miniminimini", "permission": "active"}
|
||||
],
|
||||
"data": {
|
||||
"creator": "miniminimini",
|
||||
"name": "maximaximaxi",
|
||||
"owner": {
|
||||
"threshold": 1,
|
||||
"keys": [
|
||||
{
|
||||
"key": "EOS8Dkj827FpinZBGmhTM28B85H9eXiFH5XzvLoeukCJV5sKfLc6K",
|
||||
"weight": 1,
|
||||
}
|
||||
],
|
||||
"accounts": [],
|
||||
"waits": [],
|
||||
},
|
||||
"active": {
|
||||
"threshold": 1,
|
||||
"keys": [
|
||||
{
|
||||
"key": "EOS8Dkj827FpinZBGmhTM28B85H9eXiFH5XzvLoeukCJV5sKfLc6K",
|
||||
"weight": 1,
|
||||
}
|
||||
],
|
||||
"accounts": [],
|
||||
"waits": [],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"account": "eosio",
|
||||
"name": "buyrambytes",
|
||||
"authorization": [
|
||||
{"actor": "miniminimini", "permission": "active"}
|
||||
],
|
||||
"data": {
|
||||
"payer": "miniminimini",
|
||||
"receiver": "maximaximaxi",
|
||||
"bytes": 4096,
|
||||
},
|
||||
},
|
||||
{
|
||||
"account": "eosio",
|
||||
"name": "delegatebw",
|
||||
"authorization": [
|
||||
{"actor": "miniminimini", "permission": "active"}
|
||||
],
|
||||
"data": {
|
||||
"sender": "miniminimini",
|
||||
"receiver": "maximaximaxi",
|
||||
"stake_net_quantity": "1.0000 EOS",
|
||||
"stake_cpu_quantity": "1.0000 EOS",
|
||||
"transfer": True,
|
||||
},
|
||||
},
|
||||
],
|
||||
"transaction_extensions": [],
|
||||
}
|
||||
|
||||
def input_flow():
|
||||
# confirm number of actions
|
||||
yield
|
||||
self.client.debug.press_yes()
|
||||
|
||||
# swipe through new account
|
||||
yield
|
||||
for _ in range(5):
|
||||
self.client.debug.swipe_down()
|
||||
time.sleep(1)
|
||||
|
||||
# confirm new account
|
||||
self.client.debug.press_yes()
|
||||
|
||||
# swipe through buyrambytes
|
||||
yield
|
||||
self.client.debug.swipe_down()
|
||||
time.sleep(1)
|
||||
|
||||
# confirm buyrambytes
|
||||
self.client.debug.press_yes()
|
||||
|
||||
# swipe through delegatebw
|
||||
yield
|
||||
for _ in range(2):
|
||||
self.client.debug.swipe_down()
|
||||
time.sleep(1)
|
||||
|
||||
# confirm delegatebw
|
||||
self.client.debug.press_yes()
|
||||
|
||||
with self.client:
|
||||
self.client.set_input_flow(input_flow)
|
||||
resp = eos.sign_tx(self.client, ADDRESS_N, transaction, CHAIN_ID)
|
||||
|
||||
assert isinstance(resp, EosSignedTx)
|
||||
assert (
|
||||
resp.signature_r.hex()
|
||||
== "6346a807eef0257a34269b034df7470e134261833d0da5fe0bd91aedf5a47f86"
|
||||
)
|
||||
assert (
|
||||
resp.signature_s.hex()
|
||||
== "676a1fcd0d8faff63ec206c8596de9cb5d35037d05f337afdc22c7b9e0863e77"
|
||||
)
|
||||
assert resp.signature_v == 32
|
||||
|
||||
def test_eos_signtx_setcontract(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
transaction = {
|
||||
"expiration": "2018-06-19T13:29:53",
|
||||
"ref_block_num": 30587,
|
||||
"ref_block_prefix": 338239089,
|
||||
"net_usage_words": 0,
|
||||
"max_cpu_usage_ms": 0,
|
||||
"delay_sec": 0,
|
||||
"context_free_actions": [],
|
||||
"actions": [
|
||||
{
|
||||
"account": "eosio1",
|
||||
"name": "setcode",
|
||||
"authorization": [
|
||||
{"actor": "ednazztokens", "permission": "active"}
|
||||
],
|
||||
"data": "00" * 1024,
|
||||
},
|
||||
{
|
||||
"account": "eosio1",
|
||||
"name": "setabi",
|
||||
"authorization": [
|
||||
{"actor": "ednazztokens", "permission": "active"}
|
||||
],
|
||||
"data": "00" * 1024,
|
||||
},
|
||||
],
|
||||
"transaction_extensions": [],
|
||||
"context_free_data": [],
|
||||
}
|
||||
|
||||
def input_flow():
|
||||
# confirm number of actions
|
||||
yield
|
||||
self.client.debug.press_yes()
|
||||
|
||||
# swipe through setcode
|
||||
yield
|
||||
self.client.debug.swipe_down()
|
||||
time.sleep(1)
|
||||
|
||||
# confirm setcode
|
||||
self.client.debug.press_yes()
|
||||
|
||||
# swipe through setabi
|
||||
yield
|
||||
self.client.debug.swipe_down()
|
||||
time.sleep(1)
|
||||
|
||||
# confirm setabi
|
||||
self.client.debug.press_yes()
|
||||
|
||||
with self.client:
|
||||
self.client.set_input_flow(input_flow)
|
||||
resp = eos.sign_tx(self.client, ADDRESS_N, transaction, CHAIN_ID)
|
||||
|
||||
assert isinstance(resp, EosSignedTx)
|
||||
assert (
|
||||
resp.signature_r.hex()
|
||||
== "674bbe7c8c7b9abf03ab38851cb53411e794afff04737895962643b1ed94b7d1"
|
||||
)
|
||||
assert (
|
||||
resp.signature_s.hex()
|
||||
== "1e47559db68d435494e832a16cc08ae7a67b533013ab3407f7a89d5e28de98b7"
|
||||
)
|
||||
assert resp.signature_v == 32
|
Loading…
Reference in New Issue
Block a user