mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-22 22:38:08 +00:00
trezorctl: sign_tx command based on tx_sign_tool by mruddy
This commit is contained in:
parent
54426761c6
commit
23d75bfc10
1
setup.py
1
setup.py
@ -26,6 +26,7 @@ setup(
|
|||||||
py_modules=[
|
py_modules=[
|
||||||
'trezorlib.ckd_public',
|
'trezorlib.ckd_public',
|
||||||
'trezorlib.client',
|
'trezorlib.client',
|
||||||
|
'trezorlib.coins',
|
||||||
'trezorlib.debuglink',
|
'trezorlib.debuglink',
|
||||||
'trezorlib.ed25519cosi',
|
'trezorlib.ed25519cosi',
|
||||||
'trezorlib.ed25519raw',
|
'trezorlib.ed25519raw',
|
||||||
|
@ -1,114 +0,0 @@
|
|||||||
#!/usr/bin/env python2
|
|
||||||
#
|
|
||||||
# Copyright (C) 2017 mruddy
|
|
||||||
#
|
|
||||||
# This library is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# 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 GNU Lesser General Public License
|
|
||||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import binascii
|
|
||||||
from trezorlib.client import TrezorClient
|
|
||||||
from trezorlib.transport_hid import HidTransport
|
|
||||||
from trezorlib.tx_api import TxApiBitcoin, TxApiTestnet, TxApiLitecoin
|
|
||||||
from trezorlib import types_pb2 as types
|
|
||||||
|
|
||||||
# Python2 vs Python3
|
|
||||||
try:
|
|
||||||
input = raw_input
|
|
||||||
except NameError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def get_client():
|
|
||||||
devices = HidTransport.enumerate() # list all connected TREZORs on USB
|
|
||||||
if len(devices) == 0: # check whether we found any
|
|
||||||
return None
|
|
||||||
transport = devices[0] # use first connected device
|
|
||||||
return TrezorClient(transport) # creates object for communicating with TREZOR
|
|
||||||
|
|
||||||
|
|
||||||
def get_txapi():
|
|
||||||
coin = input('Which coin {Bitcoin, Testnet, Litecoin}? ').strip()
|
|
||||||
if coin not in {'Bitcoin', 'Testnet', 'Litecoin'}:
|
|
||||||
return None, None
|
|
||||||
txapi_lookup = {
|
|
||||||
'Bitcoin': TxApiBitcoin,
|
|
||||||
'Testnet': TxApiTestnet,
|
|
||||||
'Litecoin': TxApiLitecoin
|
|
||||||
}
|
|
||||||
return coin, txapi_lookup[coin]
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
client = get_client()
|
|
||||||
if not client:
|
|
||||||
print('No TREZOR connected')
|
|
||||||
return
|
|
||||||
|
|
||||||
print()
|
|
||||||
print('Welcome to the user-unfriendly transaction signing tool')
|
|
||||||
print('USE AT YOUR OWN RISK!!!')
|
|
||||||
print()
|
|
||||||
|
|
||||||
coin, txapi = get_txapi()
|
|
||||||
if not txapi:
|
|
||||||
print('Coin not supported')
|
|
||||||
return
|
|
||||||
|
|
||||||
client.set_tx_api(txapi)
|
|
||||||
|
|
||||||
inputs = []
|
|
||||||
|
|
||||||
while True:
|
|
||||||
print()
|
|
||||||
prev_in_hash = input('Previous input hash (empty to move on): ').strip()
|
|
||||||
if prev_in_hash == '':
|
|
||||||
break
|
|
||||||
prev_in_vout = input('Previous input index: ').strip()
|
|
||||||
addrn = input("Node path to sign with (e.g.- %s/0'/0/0): " % coin).strip()
|
|
||||||
inputs.append(types.TxInputType(
|
|
||||||
prev_hash=binascii.unhexlify(prev_in_hash),
|
|
||||||
prev_index=int(prev_in_vout, 10),
|
|
||||||
address_n=client.expand_path(addrn)
|
|
||||||
))
|
|
||||||
|
|
||||||
outputs = []
|
|
||||||
|
|
||||||
while True:
|
|
||||||
print()
|
|
||||||
out_addr = input('Pay to address (empty to move on): ').strip()
|
|
||||||
if out_addr == '':
|
|
||||||
break
|
|
||||||
out_amount = input('Amount (in satoshis): ').strip()
|
|
||||||
outputs.append(types.TxOutputType(
|
|
||||||
amount=int(out_amount, 10),
|
|
||||||
script_type=types.PAYTOADDRESS,
|
|
||||||
address=out_addr
|
|
||||||
))
|
|
||||||
|
|
||||||
(signatures, serialized_tx) = client.sign_tx(coin, inputs, outputs)
|
|
||||||
|
|
||||||
client.close()
|
|
||||||
|
|
||||||
print()
|
|
||||||
print('Signed Transaction:', binascii.hexlify(serialized_tx))
|
|
||||||
|
|
||||||
# note: these api's are useful for checking and sending the output of this tool:
|
|
||||||
# https://btc.blockr.io/tx/push -or- https://live.blockcypher.com/btc/pushtx/
|
|
||||||
# https://tbtc.blockr.io/tx/push -or- https://live.blockcypher.com/btc-testnet/pushtx/
|
|
||||||
# https://ltc.blockr.io/tx/push -or - https://live.blockcypher.com/ltc/pushtx/
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
71
trezorctl
71
trezorctl
@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
# This file is part of the TREZOR project.
|
# This file is part of the TREZOR project.
|
||||||
#
|
#
|
||||||
# Copyright (C) 2012-2016 Marek Palatinus <slush@satoshilabs.com>
|
# Copyright (C) 2012-2017 Marek Palatinus <slush@satoshilabs.com>
|
||||||
# Copyright (C) 2012-2016 Pavol Rusnak <stick@satoshilabs.com>
|
# Copyright (C) 2012-2017 Pavol Rusnak <stick@satoshilabs.com>
|
||||||
# Copyright (C) 2016 Jochen Hoenicke <hoenicke@gmail.com>
|
# Copyright (C) 2016-2017 Jochen Hoenicke <hoenicke@gmail.com>
|
||||||
|
# Copyright (C) 2017 mruddy
|
||||||
#
|
#
|
||||||
# This library is free software: you can redistribute it and/or modify
|
# This library is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU Lesser General Public License as published by
|
# it under the terms of the GNU Lesser General Public License as published by
|
||||||
@ -27,6 +28,7 @@ import json
|
|||||||
|
|
||||||
from trezorlib.client import TrezorClient, TrezorClientVerbose, CallException
|
from trezorlib.client import TrezorClient, TrezorClientVerbose, CallException
|
||||||
import trezorlib.types_pb2 as types
|
import trezorlib.types_pb2 as types
|
||||||
|
from trezorlib.coins import coins_txapi
|
||||||
|
|
||||||
|
|
||||||
def get_transport_class_by_name(name):
|
def get_transport_class_by_name(name):
|
||||||
@ -431,6 +433,69 @@ def get_public_node(connect, coin, address, curve, show_display):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Signing options
|
||||||
|
#
|
||||||
|
|
||||||
|
@cli.command(help='Sign transaction.')
|
||||||
|
@click.option('-c', '--coin', default='Bitcoin')
|
||||||
|
# @click.option('-n', '--address', required=True, help="BIP-32 path, e.g. m/44'/0'/0'/0/0")
|
||||||
|
# @click.option('-t', '--script-type', type=click.Choice(['address', 'segwit', 'p2shsegwit']), default='address')
|
||||||
|
# @click.option('-o', '--output', required=True, help='Transaction output')
|
||||||
|
# @click.option('-f', '--fee', required=True, help='Transaction fee (sat/B)')
|
||||||
|
@click.pass_obj
|
||||||
|
def sign_tx(connect, coin):
|
||||||
|
client = connect()
|
||||||
|
try:
|
||||||
|
txapi = coins_txapi[coin]
|
||||||
|
except:
|
||||||
|
raise Exception('Coin "%s" is not supported' % coin)
|
||||||
|
client.set_tx_api(txapi)
|
||||||
|
|
||||||
|
try:
|
||||||
|
input = raw_input
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
inputs = []
|
||||||
|
while True:
|
||||||
|
click.echo()
|
||||||
|
prev = input('Input (prevhash:previndex, empty to move on): ').strip()
|
||||||
|
if prev == '':
|
||||||
|
break
|
||||||
|
prev_in_hash, prev_in_vout = prev.split(':')
|
||||||
|
addrn = input("Node path to sign with (e.g.- %s/0'/0/0): " % coin).strip()
|
||||||
|
inputs.append(types.TxInputType(
|
||||||
|
prev_hash=binascii.unhexlify(prev_in_hash),
|
||||||
|
prev_index=int(prev_in_vout, 10),
|
||||||
|
address_n=client.expand_path(addrn)
|
||||||
|
))
|
||||||
|
|
||||||
|
outputs = []
|
||||||
|
while True:
|
||||||
|
click.echo()
|
||||||
|
out_addr = input('Pay to address (empty to move on): ').strip()
|
||||||
|
if out_addr == '':
|
||||||
|
break
|
||||||
|
out_amount = input('Amount (in satoshis): ').strip()
|
||||||
|
outputs.append(types.TxOutputType(
|
||||||
|
amount=int(out_amount, 10),
|
||||||
|
script_type=types.PAYTOADDRESS,
|
||||||
|
address=out_addr
|
||||||
|
))
|
||||||
|
|
||||||
|
(signatures, serialized_tx) = client.sign_tx(coin, inputs, outputs)
|
||||||
|
|
||||||
|
client.close()
|
||||||
|
|
||||||
|
click.echo()
|
||||||
|
click.echo('Signed Transaction:')
|
||||||
|
click.echo(binascii.hexlify(serialized_tx))
|
||||||
|
click.echo()
|
||||||
|
click.echo('Use the following form to broadcast it to the network:')
|
||||||
|
click.echo(txapi.url.replace('/api/', '/tx/send'))
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Message functions
|
# Message functions
|
||||||
#
|
#
|
||||||
|
@ -34,6 +34,7 @@ from . import tools
|
|||||||
# from . import mapping
|
# from . import mapping
|
||||||
from . import messages_pb2 as proto
|
from . import messages_pb2 as proto
|
||||||
from . import types_pb2 as types
|
from . import types_pb2 as types
|
||||||
|
from .coins import coins_slip44
|
||||||
from .debuglink import DebugLink
|
from .debuglink import DebugLink
|
||||||
|
|
||||||
# Python2 vs Python3
|
# Python2 vs Python3
|
||||||
@ -481,20 +482,8 @@ class ProtocolMixin(object):
|
|||||||
n = n[1:]
|
n = n[1:]
|
||||||
|
|
||||||
# coin_name/a/b/c => 44'/SLIP44_constant'/a/b/c
|
# coin_name/a/b/c => 44'/SLIP44_constant'/a/b/c
|
||||||
coins = {
|
if n[0] in coins_slip44:
|
||||||
"Bitcoin": 0,
|
n = ["44'", "%d'" % coins_slip44[n[0]]] + n[1:]
|
||||||
"Testnet": 1,
|
|
||||||
"Namecoin": 7,
|
|
||||||
"Litecoin": 2,
|
|
||||||
"Dogecoin": 3,
|
|
||||||
"Dash": 5,
|
|
||||||
"Ether": 60,
|
|
||||||
"EtherClassic": 61,
|
|
||||||
"Zcash": 133,
|
|
||||||
"Decred": 42
|
|
||||||
}
|
|
||||||
if n[0] in coins:
|
|
||||||
n = ["44'", "%d'" % coins[n[0]]] + n[1:]
|
|
||||||
|
|
||||||
path = []
|
path = []
|
||||||
for x in n:
|
for x in n:
|
||||||
|
24
trezorlib/coins.py
Normal file
24
trezorlib/coins.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
from .tx_api import TxApiBitcoin, TxApiTestnet, TxApiLitecoin, TxApiZcash, TxApiDash, TxApiBcash
|
||||||
|
|
||||||
|
coins_slip44 = {
|
||||||
|
'Bitcoin': 0,
|
||||||
|
'Testnet': 1,
|
||||||
|
'Litecoin': 2,
|
||||||
|
'Dogecoin': 3,
|
||||||
|
'Dash': 5,
|
||||||
|
'Namecoin': 7,
|
||||||
|
'Decred': 42,
|
||||||
|
'Ether': 60,
|
||||||
|
'EtherClassic': 61,
|
||||||
|
'Zcash': 133,
|
||||||
|
'Bcash': 145,
|
||||||
|
}
|
||||||
|
|
||||||
|
coins_txapi = {
|
||||||
|
'Bitcoin': TxApiBitcoin,
|
||||||
|
'Testnet': TxApiTestnet,
|
||||||
|
'Litecoin': TxApiLitecoin,
|
||||||
|
'Dash': TxApiDash,
|
||||||
|
'Zcash': TxApiZcash,
|
||||||
|
'Bcash': TxApiBcash,
|
||||||
|
}
|
@ -173,8 +173,11 @@ class TxApiBlockCypher(TxApi):
|
|||||||
return t
|
return t
|
||||||
|
|
||||||
|
|
||||||
TxApiBitcoin = TxApiInsight(network='insight_bitcoin', url='https://insight.bitpay.com/api/')
|
TxApiBitcoin = TxApiInsight(network='insight_bitcoin', url='https://btc-bitcore1.trezor.io/api/')
|
||||||
TxApiTestnet = TxApiInsight(network='insight_testnet', url='https://test-insight.bitpay.com/api/')
|
TxApiTestnet = TxApiInsight(network='insight_testnet', url='https://testnet-bitcore3.trezor.io/api/')
|
||||||
TxApiLitecoin = TxApiBlockCypher(network='blockcypher_litecoin', url='https://api.blockcypher.com/v1/ltc/main/')
|
TxApiLitecoin = TxApiInsight(network='insight_litecoin', url='https://ltc-bitcore1.trezor.io/api/')
|
||||||
|
TxApiDash = TxApiInsight(network='insight_dash', url='https://dash-bitcore1.trezor.io/api/')
|
||||||
|
TxApiZcash = TxApiInsight(network='insight_zcash', url='https://zec-bitcore1.trezor.io/api/', zcash=True)
|
||||||
|
TxApiBcash = TxApiInsight(network='insight_zcash', url='https://bch-bitcore2.trezor.io/api/')
|
||||||
|
|
||||||
TxApiSegnet = TxApiSmartbit(network='smartbit_segnet', url='https://segnet-api.smartbit.com.au/v1/blockchain/')
|
TxApiSegnet = TxApiSmartbit(network='smartbit_segnet', url='https://segnet-api.smartbit.com.au/v1/blockchain/')
|
||||||
TxApiZcashTestnet = TxApiInsight(network='insight_zcashtestnet', url='https://explorer.testnet.z.cash/api/', zcash=True)
|
|
||||||
|
Loading…
Reference in New Issue
Block a user