Merge pull request #50 from clementperon/dev

Minor Clean / Python3 support
This commit is contained in:
Jean P
2019-01-22 13:15:29 +01:00
committed by GitHub
21 changed files with 599 additions and 436 deletions

4
.gitignore vendored
View File

@@ -2,6 +2,6 @@ bin
debug
dep
obj
src_common/glyphs.c
src_common/glyphs.h
src/glyphs.c
src/glyphs.h

View File

@@ -1,51 +0,0 @@
#!/usr/bin/env python
"""
*******************************************************************************
* Ledger Blue
* (c) 2016 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************
"""
from rlp.sedes import big_endian_int, binary, Binary
from rlp import Serializable
try:
from Crypto.Hash import keccak
sha3_256 = lambda x: keccak.new(digest_bits=256, data=x).digest()
except:
import sha3 as _sha3
sha3_256 = lambda x: _sha3.sha3_256(x).digest()
address = Binary.fixed_length(20, allow_empty=True)
def sha3(seed):
return sha3_256(str(seed))
class Transaction(Serializable):
fields = [
('nonce', big_endian_int),
('gasprice', big_endian_int),
('startgas', big_endian_int),
('to', address),
('value', big_endian_int),
('data', binary),
('v', big_endian_int),
('r', big_endian_int),
('s', big_endian_int),
]
def __init__(self, nonce, gasprice, startgas, to, value, data, v=0, r=0, s=0):
super(Transaction, self).__init__(nonce, gasprice, startgas, to, value, data, v, r, s)
UnsignedTransaction = Transaction.exclude(['v', 'r', 's'])

74
examples/ethBase.py Executable file
View File

@@ -0,0 +1,74 @@
#!/usr/bin/env python
"""
*******************************************************************************
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************
"""
from rlp.sedes import big_endian_int, binary, Binary
from rlp import Serializable
try:
from Crypto.Hash import keccak
def sha3_256(x): return keccak.new(digest_bits=256, data=x).digest()
except:
import sha3 as _sha3
def sha3_256(x): return _sha3.sha3_256(x).digest()
address = Binary.fixed_length(20, allow_empty=True)
def sha3(seed):
return sha3_256(str(seed))
class Transaction(Serializable):
fields = [
('nonce', big_endian_int),
('gasprice', big_endian_int),
('startgas', big_endian_int),
('to', address),
('value', big_endian_int),
('data', binary),
('v', big_endian_int),
('r', big_endian_int),
('s', big_endian_int),
]
def __init__(self, nonce, gasprice, startgas, to, value, data, v=0, r=0, s=0):
super(Transaction, self).__init__(
nonce, gasprice, startgas, to, value, data, v, r, s)
class UnsignedTransaction(Serializable):
fields = [
('nonce', big_endian_int),
('gasprice', big_endian_int),
('startgas', big_endian_int),
('to', address),
('value', big_endian_int),
('data', binary),
]
def unsigned_tx_from_tx(tx):
return UnsignedTransaction(
nonce=tx.nonce,
gasprice=tx.gasprice,
startgas=tx.startgas,
to=tx.to,
value=tx.value,
data=tx.data,
)

42
getPublicKey.py → examples/getPublicKey.py Normal file → Executable file
View File

@@ -1,8 +1,8 @@
#!/usr/bin/env python
"""
*******************************************************************************
* Ledger Blue
* (c) 2016 Ledger
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,38 +17,44 @@
* limitations under the License.
********************************************************************************
"""
from __future__ import print_function
from ledgerblue.comm import getDongle
from ledgerblue.commException import CommException
import argparse
import struct
import binascii
def parse_bip32_path(path):
if len(path) == 0:
return ""
result = ""
elements = path.split('/')
for pathElement in elements:
element = pathElement.split('\'')
if len(element) == 1:
result = result + struct.pack(">I", int(element[0]))
else:
result = result + struct.pack(">I", 0x80000000 | int(element[0]))
return result
if len(path) == 0:
return b""
result = b""
elements = path.split('/')
for pathElement in elements:
element = pathElement.split('\'')
if len(element) == 1:
result = result + struct.pack(">I", int(element[0]))
else:
result = result + struct.pack(">I", 0x80000000 | int(element[0]))
return result
parser = argparse.ArgumentParser()
parser.add_argument('--path', help="BIP 32 path to retrieve")
args = parser.parse_args()
if args.path == None:
args.path = "44'/60'/0'/0/0"
args.path = "44'/60'/0'/0/0"
donglePath = parse_bip32_path(args.path)
apdu = "e0020100".decode('hex') + chr(len(donglePath) + 1) + chr(len(donglePath) / 4) + donglePath
apdu = bytearray.fromhex("e0020100") + chr(len(donglePath) + 1).encode() + \
chr(len(donglePath) // 4).encode() + donglePath
dongle = getDongle(True)
result = dongle.exchange(bytes(apdu))
offset = 1 + result[0]
address = result[offset + 1 : offset + 1 + result[offset]]
address = result[offset + 1: offset + 1 + result[offset]]
print "Public key " + str(result[1 : 1 + result[0]]).encode('hex')
print "Address 0x" + str(address)
print("Public key", binascii.hexlify(result[1: 1 + result[0]]).decode())
print("Address 0x", address.decode(), sep='')

33
setSelfAddress.py → examples/setSelfAddress.py Normal file → Executable file
View File

@@ -1,8 +1,8 @@
#!/usr/bin/env python
"""
*******************************************************************************
* Ledger Blue
* (c) 2016 Ledger
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,28 +22,31 @@ from ledgerblue.commException import CommException
import argparse
import struct
def parse_bip32_path(path):
if len(path) == 0:
return ""
result = ""
elements = path.split('/')
for pathElement in elements:
element = pathElement.split('\'')
if len(element) == 1:
result = result + struct.pack(">I", int(element[0]))
else:
result = result + struct.pack(">I", 0x80000000 | int(element[0]))
return result
if len(path) == 0:
return b""
result = b""
elements = path.split('/')
for pathElement in elements:
element = pathElement.split('\'')
if len(element) == 1:
result = result + struct.pack(">I", int(element[0]))
else:
result = result + struct.pack(">I", 0x80000000 | int(element[0]))
return result
parser = argparse.ArgumentParser()
parser.add_argument('--path', help="BIP 32 path to retrieve")
args = parser.parse_args()
if args.path == None:
args.path = "44'/60'/0'/0/0"
args.path = "44'/60'/0'/0/0"
donglePath = parse_bip32_path(args.path)
apdu = "e0060000".decode('hex') + chr(len(donglePath) + 1) + chr(len(donglePath) / 4) + donglePath
apdu = bytearray.fromhex("e0060000") + chr(len(donglePath) + 1).encode() + \
chr(len(donglePath) // 4).encode() + donglePath
dongle = getDongle(True)
dongle.exchange(bytes(apdu))

97
examples/signTx.py Executable file
View File

@@ -0,0 +1,97 @@
#!/usr/bin/env python
"""
*******************************************************************************
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************
"""
from __future__ import print_function
from ledgerblue.comm import getDongle
from ledgerblue.commException import CommException
import argparse
import struct
import binascii
from ethBase import Transaction, UnsignedTransaction, unsigned_tx_from_tx
from rlp import encode
try:
from rlp.utils import decode_hex, encode_hex, str_to_bytes
except:
#Python3 hack import for pyethereum
from ethereum.utils import decode_hex, encode_hex, str_to_bytes
def parse_bip32_path(path):
if len(path) == 0:
return b""
result = b""
elements = path.split('/')
for pathElement in elements:
element = pathElement.split('\'')
if len(element) == 1:
result = result + struct.pack(">I", int(element[0]))
else:
result = result + struct.pack(">I", 0x80000000 | int(element[0]))
return result
parser = argparse.ArgumentParser()
parser.add_argument('--nonce', help="Nonce associated to the account", type=int, required=True)
parser.add_argument('--gasprice', help="Network gas price", type=int, required=True)
parser.add_argument('--startgas', help="startgas", default='21000', type=int)
parser.add_argument('--amount', help="Amount to send in ether", type=int, required=True)
parser.add_argument('--to', help="Destination address", type=str, required=True)
parser.add_argument('--path', help="BIP 32 path to sign with")
parser.add_argument('--data', help="Data to add, hex encoded")
args = parser.parse_args()
if args.path == None:
args.path = "44'/60'/0'/0/0"
if args.data == None:
args.data = b""
else:
args.data = decode_hex(args.data[2:])
amount = args.amount * 10**18
tx = Transaction(
nonce=int(args.nonce),
gasprice=int(args.gasprice),
startgas=int(args.startgas),
to=decode_hex(args.to[2:]),
value=int(amount),
data=args.data,
)
encodedTx = encode(unsigned_tx_from_tx(tx), UnsignedTransaction)
donglePath = parse_bip32_path(args.path)
apdu = bytearray.fromhex("e0040000")
apdu.append(len(donglePath) + 1 + len(encodedTx))
apdu.append(len(donglePath) // 4)
apdu += donglePath + encodedTx
dongle = getDongle(True)
result = dongle.exchange(bytes(apdu))
v = result[0]
r = int(binascii.hexlify(result[1:1 + 32]), 16)
s = int(binascii.hexlify(result[1 + 32: 1 + 32 + 32]), 16)
tx = Transaction(tx.nonce, tx.gasprice, tx.startgas,
tx.to, tx.value, tx.data, v, r, s)
print("Signed transaction", encode_hex(encode(tx)))

194
examples/splitEther.py Executable file
View File

@@ -0,0 +1,194 @@
#!/usr/bin/env python
"""
*******************************************************************************
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************
"""
from __future__ import print_function
from ledgerblue.comm import getDongle
from ledgerblue.commException import CommException
import argparse
import struct
import requests
import json
from decimal import Decimal
from rlp import encode
from rlp.utils import decode_hex, encode_hex, str_to_bytes
from ethBase import Transaction, UnsignedTransaction, sha3
# https://etherscan.io/address/0x5dc8108fc79018113a58328f5283b376b83922ef#code
SPLIT_CONTRACT_FUNCTION = decode_hex("9c709343")
SPLIT_CONTRACT_ADDRESS = "5dc8108fc79018113a58328f5283b376b83922ef"
def rpc_call(http, url, methodDebug):
req = http.get(url)
if req.status_code == 200:
result = json.loads(req.text)
if 'error' in result:
raise Exception("Server error - " + methodDebug +
" - " + result['error']['message'])
return result
else:
raise Exception("Server error - " + methodDebug +
" got status " + req.status)
def parse_bip32_path(path):
if len(path) == 0:
return b""
result = b""
elements = path.split('/')
for pathElement in elements:
element = pathElement.split('\'')
if len(element) == 1:
result = result + struct.pack(">I", int(element[0]))
else:
result = result + struct.pack(">I", 0x80000000 | int(element[0]))
return result
parser = argparse.ArgumentParser()
parser.add_argument(
'--nonce', help="Nonce associated to the account (default : query account)")
parser.add_argument(
'--gasprice', help="Network gas price (default : query network)")
parser.add_argument('--startgas', help="startgas", default='80000')
parser.add_argument('--startgas-delta',
help="difference applied to startgas if gasprice is automatically fetched", default='1000')
parser.add_argument(
'--amount', help="Amount to send in ether (default : query amount, use maximum)")
parser.add_argument(
'--to', help="BIP 32 destination path (default : default ETC path)")
parser.add_argument(
'--split-to-eth', help="Split to the ETH chain (default : spit to ETC chain)", action='store_true')
parser.add_argument(
'--path', help="BIP 32 path to sign with (default : default ETH path)")
parser.add_argument(
'--broadcast', help="Broadcast generated transaction (default : false)", action='store_true')
args = parser.parse_args()
if args.path == None:
if args.split_to_eth: # sign from ETC
#args.path = "44'/60'/160720'/0'/0"
args.path = "44'/60'/0'/0"
else: # sign from ETH
args.path = "44'/60'/0'/0"
if args.to == None:
if args.split_to_eth: # target ETH
args.to = "44'/60'/0'/0"
else: # target ETC transitional
args.to = "44'/60'/160720'/0'/0"
dongle = getDongle(True)
donglePath = parse_bip32_path(args.to)
apdu = bytearray.fromhex("e0060000") + chr(len(donglePath) + 1).encode() + \
chr(len(donglePath) // 4).encode() + donglePath
dongle.exchange(bytes(apdu))
apdu = bytearray.fromhex("e0020000") + chr(len(donglePath) + 1).encode() + \
chr(len(donglePath) // 4).encode() + donglePath
result = dongle.exchange(bytes(apdu))
publicKey = str(result[1: 1 + result[0]])
encodedPublicKey = sha3(publicKey[1:])[12:]
if (args.nonce == None) or (args.amount == None):
donglePathFrom = parse_bip32_path(args.path)
apdu = bytearray.fromhex("e0020000") + chr(len(donglePathFrom) + 1).encode() + \
chr(len(donglePathFrom) // 4).encode() + donglePathFrom
result = dongle.exchange(bytes(apdu))
publicKeyFrom = str(result[1: 1 + result[0]])
encodedPublicKeyFrom = sha3(publicKeyFrom[1:])[12:]
http = None
if (args.gasprice == None) or (args.nonce == None) or (args.amount == None) or (args.broadcast):
http = requests.session()
if args.gasprice == None:
print("Fetching gas price")
result = rpc_call(
http, "https://api.etherscan.io/api?module=proxy&action=eth_gasPrice", "gasPrice")
args.gasprice = int(result['result'], 16)
print("Gas price:", str(args.gasprice))
if args.nonce == None:
print("Fetching nonce")
result = rpc_call(http, "https://api.etherscan.io/api?module=proxy&action=eth_getTransactionCount&address=0x" +
encodedPublicKeyFrom.encode('hex'), "getTransactionCount")
args.nonce = int(result['result'], 16)
print("Nonce for 0x", encodedPublicKeyFrom.encode('hex'), " ", args.nonce, sep='')
if args.amount == None:
print("Fetching balance")
result = rpc_call(http, "https://api.etherscan.io/api?module=account&action=balance&address=0x" +
encodedPublicKeyFrom.encode('hex'), "getBalance")
amount = int(result['result'])
print("Balance for 0x", encodedPublicKeyFrom.encode('hex'), " ", str(amount), sep='')
amount -= (int(args.startgas) - int(args.startgas_delta)) * \
int(args.gasprice)
amount = 2
if amount < 0:
raise Exception("Remaining amount too small to pay for contract fees")
else:
amount = Decimal(args.amount) * 10**18
print("Amount transferred", str((Decimal(amount) / 10 ** 18)),
"to", encodedPublicKey.encode('hex'))
txData = SPLIT_CONTRACT_FUNCTION
txData += "\x00" * 31
if (args.split_to_eth):
txData += "\x01"
else:
txData += "\x00"
txData += "\x00" * 12
txData += encodedPublicKey
tx = Transaction(
nonce=int(args.nonce),
gasprice=int(args.gasprice),
startgas=int(args.startgas),
to=decode_hex(SPLIT_CONTRACT_ADDRESS),
value=int(amount),
data=txData
)
encodedTx = encode(tx, UnsignedTransaction)
donglePath = parse_bip32_path(args.path)
apdu = "e0040000".decode('hex') + chr(len(donglePath) + 1 +
len(encodedTx)) + chr(len(donglePath) / 4) + donglePath + encodedTx
result = dongle.exchange(bytes(apdu))
v = result[0]
r = int(str(result[1:1 + 32]).encode('hex'), 16)
s = int(str(result[1 + 32: 1 + 32 + 32]).encode('hex'), 16)
tx = Transaction(tx.nonce, tx.gasprice, tx.startgas,
tx.to, tx.value, tx.data, v, r, s)
serializedTx = encode(tx)
print("Signed transaction", serializedTx.encode('hex'))
if (args.broadcast):
result = rpc_call(http, "https://api.etherscan.io/api?module=proxy&action=eth_sendRawTransaction&hex=0x" +
serializedTx.encode('hex'), "sendRawTransaction")
print(result)

View File

@@ -1,85 +0,0 @@
#!/usr/bin/env python
"""
*******************************************************************************
* Ledger Blue
* (c) 2016 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************
"""
from ledgerblue.comm import getDongle
from ledgerblue.commException import CommException
import argparse
import struct
from decimal import Decimal
from ethBase import Transaction, UnsignedTransaction
from rlp import encode
from rlp.utils import decode_hex, encode_hex, str_to_bytes
def parse_bip32_path(path):
if len(path) == 0:
return ""
result = ""
elements = path.split('/')
for pathElement in elements:
element = pathElement.split('\'')
if len(element) == 1:
result = result + struct.pack(">I", int(element[0]))
else:
result = result + struct.pack(">I", 0x80000000 | int(element[0]))
return result
parser = argparse.ArgumentParser()
parser.add_argument('--nonce', help="Nonce associated to the account")
parser.add_argument('--gasprice', help="Network gas price")
parser.add_argument('--startgas', help="startgas", default='21000')
parser.add_argument('--amount', help="Amount to send in ether")
parser.add_argument('--to', help="Destination address")
parser.add_argument('--path', help="BIP 32 path to sign with")
parser.add_argument('--data', help="Data to add, hex encoded")
args = parser.parse_args()
if args.path == None:
args.path = "44'/60'/0'/0/0"
if args.data == None:
args.data = ""
else:
args.data = decode_hex(args.data[2:])
amount = Decimal(args.amount) * 10**18
tx = Transaction(
nonce=int(args.nonce),
gasprice=int(args.gasprice),
startgas=int(args.startgas),
to=decode_hex(args.to[2:]),
value=int(amount),
data=args.data
)
encodedTx = encode(tx, UnsignedTransaction)
donglePath = parse_bip32_path(args.path)
apdu = "e0040000".decode('hex') + chr(len(donglePath) + 1 + len(encodedTx)) + chr(len(donglePath) / 4) + donglePath + encodedTx
dongle = getDongle(True)
result = dongle.exchange(bytes(apdu))
v = result[0]
r = int(str(result[1:1 + 32]).encode('hex'), 16)
s = int(str(result[1 + 32: 1 + 32 + 32]).encode('hex'), 16)
tx = Transaction(tx.nonce, tx.gasprice, tx.startgas, tx.to, tx.value, tx.data, v, r, s)
print "Signed transaction " + encode_hex(encode(tx))

View File

@@ -1,168 +0,0 @@
#!/usr/bin/env python
"""
*******************************************************************************
* Ledger Blue
* (c) 2016 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************
"""
from ledgerblue.comm import getDongle
from ledgerblue.commException import CommException
import argparse
import struct
import requests
import json
from decimal import Decimal
from rlp import encode
from rlp.utils import decode_hex, encode_hex, str_to_bytes
from ethBase import Transaction, UnsignedTransaction, sha3
# https://etherscan.io/address/0x5dc8108fc79018113a58328f5283b376b83922ef#code
SPLIT_CONTRACT_FUNCTION = decode_hex("9c709343")
SPLIT_CONTRACT_ADDRESS = "5dc8108fc79018113a58328f5283b376b83922ef"
def rpc_call(http, url, methodDebug):
req = http.get(url)
if req.status_code == 200:
result = json.loads(req.text)
if 'error' in result:
raise Exception("Server error - " + methodDebug + " - " + result['error']['message'])
return result
else:
raise Exception("Server error - " + methodDebug + " got status " + req.status)
def parse_bip32_path(path):
if len(path) == 0:
return ""
result = ""
elements = path.split('/')
for pathElement in elements:
element = pathElement.split('\'')
if len(element) == 1:
result = result + struct.pack(">I", int(element[0]))
else:
result = result + struct.pack(">I", 0x80000000 | int(element[0]))
return result
parser = argparse.ArgumentParser()
parser.add_argument('--nonce', help="Nonce associated to the account (default : query account)")
parser.add_argument('--gasprice', help="Network gas price (default : query network)")
parser.add_argument('--startgas', help="startgas", default='80000')
parser.add_argument('--startgas-delta', help="difference applied to startgas if gasprice is automatically fetched", default='1000')
parser.add_argument('--amount', help="Amount to send in ether (default : query amount, use maximum)")
parser.add_argument('--to', help="BIP 32 destination path (default : default ETC path)")
parser.add_argument('--split-to-eth', help="Split to the ETH chain (default : spit to ETC chain)", action='store_true')
parser.add_argument('--path', help="BIP 32 path to sign with (default : default ETH path)")
parser.add_argument('--broadcast', help="Broadcast generated transaction (default : false)", action='store_true')
args = parser.parse_args()
if args.path == None:
if args.split_to_eth: #sign from ETC
#args.path = "44'/60'/160720'/0'/0"
args.path = "44'/60'/0'/0"
else: #sign from ETH
args.path = "44'/60'/0'/0"
if args.to == None:
if args.split_to_eth: #target ETH
args.to = "44'/60'/0'/0"
else: #target ETC transitional
args.to = "44'/60'/160720'/0'/0"
dongle = getDongle(True)
donglePath = parse_bip32_path(args.to)
apdu = "e0060000".decode('hex') + chr(len(donglePath) + 1) + chr(len(donglePath) / 4) + donglePath
dongle.exchange(bytes(apdu))
apdu = "e0020000".decode('hex') + chr(len(donglePath) + 1) + chr(len(donglePath) / 4) + donglePath
result = dongle.exchange(bytes(apdu))
publicKey = str(result[1 : 1 + result[0]])
encodedPublicKey = sha3(publicKey[1:])[12:]
if (args.nonce == None) or (args.amount == None):
donglePathFrom = parse_bip32_path(args.path)
apdu = "e0020000".decode('hex') + chr(len(donglePathFrom) + 1) + chr(len(donglePathFrom) / 4) + donglePathFrom
result = dongle.exchange(bytes(apdu))
publicKeyFrom = str(result[1 : 1 + result[0]])
encodedPublicKeyFrom = sha3(publicKeyFrom[1:])[12:]
http = None
if (args.gasprice == None) or (args.nonce == None) or (args.amount == None) or (args.broadcast):
http = requests.session()
if args.gasprice == None:
print "Fetching gas price"
result = rpc_call(http, "https://api.etherscan.io/api?module=proxy&action=eth_gasPrice", "gasPrice")
args.gasprice = int(result['result'], 16)
print "Gas price " + str(args.gasprice)
if args.nonce == None:
print "Fetching nonce"
result = rpc_call(http, "https://api.etherscan.io/api?module=proxy&action=eth_getTransactionCount&address=0x" + encodedPublicKeyFrom.encode('hex'), "getTransactionCount")
args.nonce = int(result['result'], 16)
print "Nonce for 0x" + encodedPublicKeyFrom.encode('hex') + " " + str(args.nonce)
if args.amount == None:
print "Fetching balance"
result = rpc_call(http, "https://api.etherscan.io/api?module=account&action=balance&address=0x" + encodedPublicKeyFrom.encode('hex'), "getBalance")
amount = int(result['result'])
print "Balance for " + encodedPublicKeyFrom.encode('hex') + " " + str(amount)
amount -= (int(args.startgas) - int(args.startgas_delta)) * int(args.gasprice)
if amount < 0:
raise Exception("Remaining amount too small to pay for contract fees")
else:
amount = Decimal(args.amount) * 10**18
print "Amount transferred " + str((Decimal(amount) / 10 ** 18)) + " to " + encodedPublicKey.encode('hex')
txData = SPLIT_CONTRACT_FUNCTION
txData += "\x00" * 31
if (args.split_to_eth):
txData += "\x01"
else:
txData += "\x00"
txData += "\x00" * 12
txData += encodedPublicKey
tx = Transaction(
nonce=int(args.nonce),
gasprice=int(args.gasprice),
startgas=int(args.startgas),
to=decode_hex(SPLIT_CONTRACT_ADDRESS),
value=int(amount),
data=txData
)
encodedTx = encode(tx, UnsignedTransaction)
donglePath = parse_bip32_path(args.path)
apdu = "e0040000".decode('hex') + chr(len(donglePath) + 1 + len(encodedTx)) + chr(len(donglePath) / 4) + donglePath + encodedTx
result = dongle.exchange(bytes(apdu))
v = result[0]
r = int(str(result[1:1 + 32]).encode('hex'), 16)
s = int(str(result[1 + 32: 1 + 32 + 32]).encode('hex'), 16)
tx = Transaction(tx.nonce, tx.gasprice, tx.startgas, tx.to, tx.value, tx.data, v, r, s)
serializedTx = encode(tx)
print "Signed transaction " + serializedTx.encode('hex')
if (args.broadcast):
result = rpc_call(http, "https://api.etherscan.io/api?module=proxy&action=eth_sendRawTransaction&hex=0x" + serializedTx.encode('hex'), "sendRawTransaction")
print result

View File

@@ -1,9 +1,27 @@
/*******************************************************************************
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
#ifndef _CHAIN_CONFIG_H_
#define _CHAIN_CONFIG_H_
#include <stdint.h>
#include "os.h"
#ifndef CHAIN_CONFIG_H
#define CHAIN_CONFIG_H
typedef enum chain_kind_e {
CHAIN_KIND_ETHEREUM,
CHAIN_KIND_ETHEREUM_CLASSIC,
@@ -32,7 +50,6 @@ typedef struct chain_config_s {
const char* coinName; // ticker
uint32_t chainId;
chain_kind_t kind;
#ifdef TARGET_BLUE
const char* header_text;
unsigned int color_header;
@@ -41,5 +58,4 @@ typedef struct chain_config_s {
} chain_config_t;
#endif
#endif /* _CHAIN_CONFIG_H_ */

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* Ledger Blue
* (c) 2016 Ledger
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,9 +15,12 @@
* limitations under the License.
********************************************************************************/
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "os.h"
#include "cx.h"
#include "stdbool.h"
#include "ethUstream.h"
#include "ethUtils.h"
#include "uint256.h"
@@ -25,16 +28,12 @@
#include "chainConfig.h"
#include "os_io_seproxyhal.h"
#include "string.h"
#include "glyphs.h"
#define __NAME3(a, b, c) a##b##c
#define NAME3(a, b, c) __NAME3(a, b, c)
#include "utils.h"
unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
unsigned int io_seproxyhal_touch_settings(const bagl_element_t *e);
unsigned int io_seproxyhal_touch_exit(const bagl_element_t *e);
unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e);
@@ -167,21 +166,8 @@ static const char const CONTRACT_ADDRESS[] = "New contract";
static const char const SIGN_MAGIC[] = "\x19"
"Ethereum Signed Message:\n";
const unsigned char hex_digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
chain_config_t *chainConfig;
void array_hexstr(char *strbuf, const void *bin, unsigned int len) {
while (len--) {
*strbuf++ = hex_digits[((*((char *)bin)) >> 4) & 0xF];
*strbuf++ = hex_digits[(*((char *)bin)) & 0xF];
bin = (const void *)((unsigned int)bin + 1);
}
*strbuf = 0; // EOS
}
const bagl_element_t* ui_menu_item_out_over(const bagl_element_t* e) {
// the selection rectangle is after the none|touchable
e = (const bagl_element_t*)(((unsigned int)e)+sizeof(bagl_element_t));
@@ -238,9 +224,6 @@ const bagl_element_t ui_idle_blue[] = {
{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 0, 19, 56, 44, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP_LIGHT, BAGL_FONT_SYMBOLS_0|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, BAGL_FONT_SYMBOLS_0_SETTINGS, 0, COLOR_APP, 0xFFFFFF, io_seproxyhal_touch_settings, NULL, NULL},
{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 264, 19, 56, 44, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP_LIGHT, BAGL_FONT_SYMBOLS_0|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, BAGL_FONT_SYMBOLS_0_DASHBOARD, 0, COLOR_APP, 0xFFFFFF, io_seproxyhal_touch_exit, NULL, NULL},
// BADGE_<CHAINID>.GIF
//{{BAGL_ICON , 0x00, 135, 178, 50, 50, 0, 0, BAGL_FILL, 0 , COLOR_BG_1, 0 ,0 } , &NAME3(C_blue_badge_, CHAINID, ), 0, 0, 0, NULL, NULL, NULL },
{{BAGL_LABELINE , 0x00, 0, 270, 320, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_LIGHT_16_22PX|BAGL_FONT_ALIGNMENT_CENTER, 0 }, "Open your wallet", 0, 0, 0, NULL, NULL, NULL},
{{BAGL_LABELINE , 0x00, 0, 308, 320, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX|BAGL_FONT_ALIGNMENT_CENTER, 0 }, "Connect your Ledger Blue and open your", 0, 0, 0, NULL, NULL, NULL},
{{BAGL_LABELINE , 0x00, 0, 331, 320, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX|BAGL_FONT_ALIGNMENT_CENTER, 0 }, "preferred wallet to view your accounts.", 0, 0, 0, NULL, NULL, NULL},
@@ -318,7 +301,6 @@ const ux_menu_entry_t menu_about[] = {
};
const ux_menu_entry_t menu_main[] = {
//{NULL, NULL, 0, &NAME3(C_nanos_badge_, CHAINID, ), "Use wallet to", "view accounts", 33, 12},
{NULL, NULL, 0, NULL, "Use wallet to", "view accounts", 0, 0},
{menu_settings, NULL, 0, NULL, "Settings", NULL, 0, 0},
{menu_about, NULL, 0, NULL, "About", NULL, 0, 0},
@@ -971,17 +953,6 @@ const bagl_element_t ui_data_parameter_blue[] = {
{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 165, 414, 115, 36, 0,18, BAGL_FILL, 0x41ccb4, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_11_14PX|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, "CONFIRM", 0, 0x3ab7a2, COLOR_BG_1, io_seproxyhal_touch_data_ok, NULL, NULL},
};
int local_strchr(char *string, char ch) {
unsigned int length = strlen(string);
unsigned int i;
for (i=0; i<length; i++) {
if (string[i] == ch) {
return i;
}
}
return -1;
}
unsigned int ui_data_parameter_blue_prepro(const bagl_element_t* element) {
copy_element_and_map_coin_colors(element);
if(element->component.userid > 0) {
@@ -1114,33 +1085,6 @@ unsigned int ui_address_nanos_button(unsigned int button_mask, unsigned int butt
}
#endif // #if defined(TARGET_NANOS)
uint32_t getV(txContent_t *txContent) {
uint32_t v = 0;
if (txContent->vLength == 1) {
v = txContent->v[0];
}
else
if (txContent->vLength == 2) {
v = (txContent->v[0] << 8) | txContent->v[1];
}
else
if (txContent->vLength == 3) {
v = (txContent->v[0] << 16) | (txContent->v[1] << 8) | txContent->v[2];
}
else
if (txContent->vLength == 4) {
v = (txContent->v[0] << 24) | (txContent->v[1] << 16) |
(txContent->v[2] << 8) | txContent->v[3];
}
else
if (txContent->vLength != 0) {
PRINTF("Unexpected v format\n");
THROW(EXCEPTION);
}
return v;
}
void io_seproxyhal_send_status(uint32_t sw) {
G_io_apdu_buffer[0] = ((sw >> 8) & 0xff);
G_io_apdu_buffer[1] = (sw & 0xff);
@@ -1429,13 +1373,6 @@ uint32_t set_result_get_publicKey() {
return tx;
}
void convertUint256BE(uint8_t *data, uint32_t length, uint256_t *target) {
uint8_t tmp[32];
os_memset(tmp, 0, 32);
os_memmove(tmp + 32 - length, data, length);
readu256BE(tmp, target);
}
uint32_t splitBinaryParameterPart(char *result, uint8_t *parameter) {
uint32_t i;
for (i=0; i<8; i++) {

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* Ledger Blue
* (c) 2016 Ledger
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* Ledger Blue
* (c) 2016 Ledger
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,10 @@
* limitations under the License.
********************************************************************************/
#include "os.h"
#ifndef _TOKENS_H_
#define _TOKENS_H_
#include <stdint.h>
typedef struct tokenDefinition_t {
uint8_t address[20];
@@ -66,3 +69,5 @@ extern tokenDefinition_t const TOKENS_GOCHAIN[NUM_TOKENS_GOCHAIN];
extern tokenDefinition_t const TOKENS_MIX[NUM_TOKENS_MIX];
extern tokenDefinition_t const TOKENS_REOSC[NUM_TOKENS_REOSC];
extern tokenDefinition_t const TOKENS_HPB[NUM_TOKENS_HPB];
#endif /* _TOKENS_H_ */

78
src/utils.c Normal file
View File

@@ -0,0 +1,78 @@
/*******************************************************************************
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
#include <stdint.h>
#include <string.h>
#include "ethUstream.h"
#include "uint256.h"
static const unsigned char hex_digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
void array_hexstr(char *strbuf, const void *bin, unsigned int len) {
while (len--) {
*strbuf++ = hex_digits[((*((char *)bin)) >> 4) & 0xF];
*strbuf++ = hex_digits[(*((char *)bin)) & 0xF];
bin = (const void *)((unsigned int)bin + 1);
}
*strbuf = 0; // EOS
}
void convertUint256BE(uint8_t *data, uint32_t length, uint256_t *target) {
uint8_t tmp[32];
os_memset(tmp, 0, 32);
os_memmove(tmp + 32 - length, data, length);
readu256BE(tmp, target);
}
int local_strchr(char *string, char ch) {
unsigned int length = strlen(string);
unsigned int i;
for (i=0; i<length; i++) {
if (string[i] == ch) {
return i;
}
}
return -1;
}
uint32_t getV(txContent_t *txContent) {
uint32_t v = 0;
if (txContent->vLength == 1) {
v = txContent->v[0];
}
else
if (txContent->vLength == 2) {
v = (txContent->v[0] << 8) | txContent->v[1];
}
else
if (txContent->vLength == 3) {
v = (txContent->v[0] << 16) | (txContent->v[1] << 8) | txContent->v[2];
}
else
if (txContent->vLength == 4) {
v = (txContent->v[0] << 24) | (txContent->v[1] << 16) |
(txContent->v[2] << 8) | txContent->v[3];
}
else
if (txContent->vLength != 0) {
PRINTF("Unexpected v format\n");
THROW(EXCEPTION);
}
return v;
}

33
src/utils.h Normal file
View File

@@ -0,0 +1,33 @@
/*******************************************************************************
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
#ifndef _UTILS_H_
#define _UTILS_H_
#include <stdint.h>
#include "uint256.h"
void array_hexstr(char *strbuf, const void *bin, unsigned int len);
void convertUint256BE(uint8_t *data, uint32_t length, uint256_t *target);
int local_strchr(char *string, char ch);
uint32_t getV(txContent_t *txContent);
#endif /* _UTILS_H_ */

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* Ledger Blue
* (c) 2016 Ledger
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
* limitations under the License.
********************************************************************************/
#include <stdint.h>
#include "ethUstream.h"
#include "ethUtils.h"

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* Ledger Blue
* (c) 2016 Ledger
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,9 +15,14 @@
* limitations under the License.
********************************************************************************/
#ifndef _ETHUSTREAM_H_
#define _ETHUSTREAM_H_
#include <stdbool.h>
#include <stdint.h>
#include "os.h"
#include "cx.h"
#include <stdbool.h>
struct txContext_t;
@@ -96,3 +101,5 @@ parserStatus_e processTx(txContext_t *context, uint8_t *buffer,
parserStatus_e continueTx(txContext_t *context);
void copyTxData(txContext_t *context, uint8_t *out, uint32_t length);
uint8_t readTxByte(txContext_t *context);
#endif /* _ETHUSTREAM_H_ */

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* Ledger Blue
* (c) 2016 Ledger
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,9 +23,12 @@
* @date 8th of March 2016
*/
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "os.h"
#include "cx.h"
#include <stdbool.h>
#include "ethUtils.h"
#include "chainConfig.h"

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* Ledger Blue
* (c) 2016 Ledger
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,11 @@
* limitations under the License.
********************************************************************************/
#include "os.h"
#ifndef _ETHUTILS_H_
#define _ETHUTILS_H_
#include <stdint.h>
#include "cx.h"
/**
@@ -46,3 +50,5 @@ void getEthAddressStringFromBinary(uint8_t *address, uint8_t *out,
bool adjustDecimals(char *src, uint32_t srcLength, char *target,
uint32_t targetLength, uint8_t decimals);
#endif /* _ETHUTILS_H_ */

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* Ledger Blue
* (c) 2016 Ledger
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
#include <stdio.h>
#include <stdlib.h>
#include "uint256.h"
static const char HEXDIGITS[] = "0123456789abcdef";

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* Ledger Blue
* (c) 2016 Ledger
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,9 @@
// Adapted from https://github.com/calccrypto/uint256_t
#ifndef _UINT256_H_
#define _UINT256_H_
#include <stdint.h>
#include <stdbool.h>
@@ -63,3 +66,5 @@ bool tostring128(uint128_t *number, uint32_t base, char *out,
uint32_t outLength);
bool tostring256(uint256_t *number, uint32_t base, char *out,
uint32_t outLength);
#endif /* _UINT256_H_ */