Skip to content

Commit 716d9d4

Browse files
committed
EDGE do not re-sign PSBT
1 parent d49ba0d commit 716d9d4

File tree

1 file changed

+45
-12
lines changed

1 file changed

+45
-12
lines changed

hwilib/devices/coldcard.py

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,21 @@ def __init__(self, path: str, password: Optional[str] = None, expert: bool = Fal
100100
device.open_path(path.encode())
101101
self.device = ColdcardDevice(dev=device)
102102

103+
self._is_edge = None
104+
105+
@property
106+
def is_edge(self):
107+
"""
108+
Cached property, no need to ask device more than once
109+
:return: bool
110+
"""
111+
if self._is_edge is None:
112+
try:
113+
self._is_edge = self.is_edge_firmware()
114+
except: pass # silent fail, normal firmware is implied
115+
116+
return self._is_edge
117+
103118
@coldcard_exception
104119
def get_pubkey_at_path(self, path: str) -> ExtendedKey:
105120
self.device.check_mitm()
@@ -132,14 +147,15 @@ def sign_tx(self, tx: PSBT) -> PSBT:
132147

133148
# For multisigs, we may need to do multiple passes if we appear in an input multiple times
134149
passes = 1
135-
for psbt_in in tx.inputs:
136-
our_keys = 0
137-
for key in psbt_in.hd_keypaths.keys():
138-
keypath = psbt_in.hd_keypaths[key]
139-
if keypath.fingerprint == master_fp and key not in psbt_in.partial_sigs:
140-
our_keys += 1
141-
if our_keys > passes:
142-
passes = our_keys
150+
if not self.is_edge:
151+
for psbt_in in tx.inputs:
152+
our_keys = 0
153+
for key in psbt_in.hd_keypaths.keys():
154+
keypath = psbt_in.hd_keypaths[key]
155+
if keypath.fingerprint == master_fp and key not in psbt_in.partial_sigs:
156+
our_keys += 1
157+
if our_keys > passes:
158+
passes = our_keys
143159

144160
for _ in range(passes):
145161
# Get psbt in hex and then make binary
@@ -390,13 +406,27 @@ def toggle_passphrase(self) -> bool:
390406
"""
391407
raise UnavailableActionError('The Coldcard does not support toggling passphrase from the host')
392408

393-
def can_sign_taproot(self) -> bool:
409+
def firmware_version(self) -> str:
410+
return self.device.send_recv(CCProtocolPacker.version()).split("\n")[1]
411+
412+
def is_edge_firmware(self):
413+
"""
414+
:return: True if this device is running EDGE firmware, False otherwise
394415
"""
395-
The Coldard does not support Taproot yet.
416+
if self.device.is_simulator:
417+
cmd = "import version; RV.write(str(int(getattr(version, 'is_edge', 0))))"
418+
rv = self.device.send_recv(b'EXEC' + cmd.encode('utf-8'), timeout=60000, encrypt=False)
419+
return rv == b"1"
420+
else:
421+
_, ver, _, _, _ = self.device.send_recv(CCProtocolPacker.version()).split("\n")
422+
return "X" == self.firmware_version()[-1]
396423

397-
:returns: False, always
424+
def can_sign_taproot(self) -> bool:
425+
"""
426+
Only COLDCARD EDGE support taproot.
427+
:returns: Whether Taproot is supported
398428
"""
399-
return False
429+
return self.is_edge
400430

401431

402432
def enumerate(password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN, allow_emulators: bool = True) -> List[Dict[str, Any]]:
@@ -422,6 +452,9 @@ def enumerate(password: Optional[str] = None, expert: bool = False, chain: Chain
422452
with handle_errors(common_err_msgs["enumerate"], d_data):
423453
try:
424454
client = ColdcardClient(path)
455+
if client.is_edge:
456+
d_data['label'] = 'edge'
457+
d_data['model'] = 'edge_' + d_data['model']
425458
d_data['fingerprint'] = client.get_master_fingerprint().hex()
426459
except RuntimeError as e:
427460
# Skip the simulator if it's not there

0 commit comments

Comments
 (0)