async def sign_tx(ctx, msg): address_n = msg.address_n or () node = await seed.derive_node(ctx, address_n, TEZOS_CURVE) if msg.transaction is not None: to = _get_address_from_contract(msg.transaction.destination) await require_confirm_tx(ctx, to, msg.transaction.amount) await require_confirm_fee(ctx, msg.transaction.amount, msg.transaction.fee) elif msg.origination is not None: source = _get_address_from_contract(msg.origination.source) await require_confirm_origination(ctx, source) # if we are immediately delegating contract if msg.origination.delegate is not None: delegate = _get_address_by_tag(msg.origination.delegate) await require_confirm_delegation_baker(ctx, delegate) await require_confirm_origination_fee( ctx, msg.origination.balance, msg.origination.fee ) elif msg.delegation is not None: source = _get_address_from_contract(msg.delegation.source) delegate = None if msg.delegation.delegate is not None: delegate = _get_address_by_tag(msg.delegation.delegate) if delegate is not None and source != delegate: await require_confirm_delegation_baker(ctx, delegate) await require_confirm_set_delegate(ctx, msg.delegation.fee) # if account registers itself as a delegate else: await require_confirm_register_delegate(ctx, source, msg.delegation.fee) else: raise wire.DataError("Invalid operation") w = bytearray() _get_operation_bytes(w, msg) opbytes = bytes(w) # watermark 0x03 is prefix for transactions, delegations, originations, reveals... watermark = bytes([3]) wm_opbytes = watermark + opbytes wm_opbytes_hash = hashlib.blake2b(wm_opbytes, outlen=32).digest() signature = ed25519.sign(node.private_key(), wm_opbytes_hash) sig_op_contents = opbytes + signature sig_op_contents_hash = hashlib.blake2b(sig_op_contents, outlen=32).digest() ophash = base58_encode_check(sig_op_contents_hash, prefix="o") sig_prefixed = base58_encode_check(signature, prefix=TEZOS_SIGNATURE_PREFIX) return TezosSignedTx( signature=sig_prefixed, sig_op_contents=sig_op_contents, operation_hash=ophash )
def _get_address_by_tag(address_hash): prefixes = ["tz1", "tz2", "tz3"] tag = int(address_hash[0]) if 0 <= tag < len(prefixes): return base58_encode_check(address_hash[1:], prefix=prefixes[tag]) raise wire.DataError("Invalid tag in address hash")
def test_tezos_base58_encode_check(self): pkh = unhexlify("101368afffeb1dc3c089facbbe23f5c30b787ce9") self.assertEqual( base58_encode_check(pkh, prefix="tz1"), "tz1M72kkAJrntPtayM4yU4CCwQPLSdpEgRrn", ) self.assertEqual( base58_encode_check(pkh, prefix="tz2"), "tz29nEixktH9p9XTFX7p8hATUyeLxXEz96KR", ) self.assertEqual( base58_encode_check(pkh, prefix="tz3"), "tz3Mo3gHekQhCmykfnC58ecqJLXrjMKzkF2Q", ) self.assertEqual(base58_encode_check(pkh), "2U14dJ6ED97bBHDZTQWA6umVL8SAVefXj")
def _get_address_from_contract(address): if address.tag == TezosContractType.Implicit: return _get_address_by_tag(address.hash) elif address.tag == TezosContractType.Originated: return helpers.base58_encode_check( address.hash[:-1], prefix=helpers.TEZOS_ORIGINATED_ADDRESS_PREFIX) raise wire.DataError("Invalid contract type")
async def get_public_key(ctx, msg): node = await seed.derive_node(ctx, msg.address_n, TEZOS_CURVE) pk = seed.remove_ed25519_prefix(node.public_key()) pk_prefixed = base58_encode_check(pk, prefix=TEZOS_PUBLICKEY_PREFIX) if msg.show_display: await _show_tezos_pubkey(ctx, pk_prefixed) return TezosPublicKey(public_key=pk_prefixed)
async def get_public_key(ctx, msg, keychain): await paths.validate_path(ctx, helpers.validate_full_path, keychain, msg.address_n) node = keychain.derive(msg.address_n, helpers.TEZOS_CURVE) pk = seed.remove_ed25519_prefix(node.public_key()) pk_prefixed = helpers.base58_encode_check(pk, prefix=helpers.TEZOS_PUBLICKEY_PREFIX) if msg.show_display: await _show_tezos_pubkey(ctx, pk_prefixed) return TezosPublicKey(public_key=pk_prefixed)
async def get_address(ctx, msg): address_n = msg.address_n or () node = await seed.derive_node(ctx, address_n, TEZOS_CURVE) pk = seed.remove_ed25519_prefix(node.public_key()) pkh = hashlib.blake2b(pk, outlen=20).digest() address = base58_encode_check(pkh, prefix=TEZOS_ED25519_ADDRESS_PREFIX) if msg.show_display: while True: if await show_address(ctx, address): break if await show_qr(ctx, address): break return TezosAddress(address=address)
async def get_address(ctx, msg, keychain): await paths.validate_path(ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE) node = keychain.derive(msg.address_n, CURVE) pk = seed.remove_ed25519_prefix(node.public_key()) pkh = hashlib.blake2b(pk, outlen=20).digest() address = helpers.base58_encode_check( pkh, prefix=helpers.TEZOS_ED25519_ADDRESS_PREFIX) if msg.show_display: desc = address_n_to_str(msg.address_n) while True: if await show_address(ctx, address, desc=desc): break if await show_qr(ctx, address, desc=desc): break return TezosAddress(address=address)
async def sign_tx(ctx, msg, keychain): await paths.validate_path( ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE ) node = keychain.derive(msg.address_n, CURVE) if msg.transaction is not None: # if the tranasction oprtation is used to execute code on a smart contract if msg.transaction.parameters_manager is not None: parameters_manager = msg.transaction.parameters_manager # operation to delegate from a smart contract with manager.tz if parameters_manager.set_delegate is not None: delegate = _get_address_by_tag(parameters_manager.set_delegate) await layout.require_confirm_delegation_baker(ctx, delegate) await layout.require_confirm_set_delegate(ctx, msg.transaction.fee) # operation to remove delegate from the smart contract with manager.tz elif parameters_manager.cancel_delegate is not None: address = _get_address_from_contract(msg.transaction.destination) await layout.require_confirm_delegation_manager_withdraw(ctx, address) await layout.require_confirm_manager_remove_delegate( ctx, msg.transaction.fee ) # operation to transfer tokens from a smart contract to an implicit account or a smart contract elif parameters_manager.transfer is not None: to = _get_address_from_contract(parameters_manager.transfer.destination) await layout.require_confirm_tx( ctx, to, parameters_manager.transfer.amount ) await layout.require_confirm_fee( ctx, parameters_manager.transfer.amount, msg.transaction.fee ) else: # transactions from an implicit account to = _get_address_from_contract(msg.transaction.destination) await layout.require_confirm_tx(ctx, to, msg.transaction.amount) await layout.require_confirm_fee( ctx, msg.transaction.amount, msg.transaction.fee ) elif msg.origination is not None: source = _get_address_by_tag(msg.origination.source) await layout.require_confirm_origination(ctx, source) # if we are immediately delegating contract if msg.origination.delegate is not None: delegate = _get_address_by_tag(msg.origination.delegate) await layout.require_confirm_delegation_baker(ctx, delegate) await layout.require_confirm_origination_fee( ctx, msg.origination.balance, msg.origination.fee ) elif msg.delegation is not None: source = _get_address_by_tag(msg.delegation.source) delegate = None if msg.delegation.delegate is not None: delegate = _get_address_by_tag(msg.delegation.delegate) if delegate is not None and source != delegate: await layout.require_confirm_delegation_baker(ctx, delegate) await layout.require_confirm_set_delegate(ctx, msg.delegation.fee) # if account registers itself as a delegate else: await layout.require_confirm_register_delegate( ctx, source, msg.delegation.fee ) elif msg.proposal is not None: proposed_protocols = [_get_protocol_hash(p) for p in msg.proposal.proposals] await layout.require_confirm_proposals(ctx, proposed_protocols) elif msg.ballot is not None: proposed_protocol = _get_protocol_hash(msg.ballot.proposal) submitted_ballot = _get_ballot(msg.ballot.ballot) await layout.require_confirm_ballot(ctx, proposed_protocol, submitted_ballot) else: raise wire.DataError("Invalid operation") w = bytearray() _get_operation_bytes(w, msg) opbytes = bytes(w) # watermark 0x03 is prefix for transactions, delegations, originations, reveals... watermark = bytes([3]) wm_opbytes = watermark + opbytes wm_opbytes_hash = hashlib.blake2b(wm_opbytes, outlen=32).digest() signature = ed25519.sign(node.private_key(), wm_opbytes_hash) sig_op_contents = opbytes + signature sig_op_contents_hash = hashlib.blake2b(sig_op_contents, outlen=32).digest() ophash = helpers.base58_encode_check(sig_op_contents_hash, prefix="o") sig_prefixed = helpers.base58_encode_check( signature, prefix=helpers.TEZOS_SIGNATURE_PREFIX ) return TezosSignedTx( signature=sig_prefixed, sig_op_contents=sig_op_contents, operation_hash=ophash )
def _get_protocol_hash(proposal): return helpers.base58_encode_check(proposal, prefix="P")