Open-source 2-of-3 policy-enforced threshold HSM: auto-signs cold→hot treasury refills under on-device Coldcard policy, no human in the loop. Includes the full operator manual + quick-start, the reference coordinator/signing code, and a signer-host bootstrap. No keys, seeds, or secrets — placeholders only. Live signet demo: https://multisighsm.mineracks.com Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
31 lines
1.2 KiB
Python
31 lines
1.2 KiB
Python
import sys, io, time
|
|
from base64 import b64decode, b64encode
|
|
from ckcc.client import ColdcardDevice
|
|
from ckcc.protocol import CCProtocolPacker
|
|
from ckcc.cli import real_file_upload
|
|
|
|
sock, inp, outp = sys.argv[1], sys.argv[2], sys.argv[3]
|
|
psbt = b64decode(open(inp).read().strip())
|
|
dev = ColdcardDevice(sn=sock)
|
|
txn_len, sha = real_file_upload(io.BytesIO(psbt), dev)
|
|
ok = dev.send_recv(CCProtocolPacker.sign_transaction(txn_len, sha, flags=0x0), timeout=None)
|
|
assert ok is None, ('sign_transaction rejected', ok)
|
|
def story():
|
|
s = dev.send_recv(b'EXEC' + b"RV.write(repr(sim_display.story))", encrypt=False)
|
|
return (s.decode() if isinstance(s,(bytes,bytearray)) else s)
|
|
print('STORY:', story()[:500])
|
|
done = None
|
|
for i in range(50):
|
|
try: dev.send_recv(CCProtocolPacker.sim_keypress(b'y'))
|
|
except Exception as e: pass
|
|
time.sleep(0.4)
|
|
d = dev.send_recv(CCProtocolPacker.get_signed_txn(), timeout=None)
|
|
if d is not None:
|
|
done = d; break
|
|
if not done:
|
|
print('NO RESULT after polling. STORY now:', story()[:500]); sys.exit(1)
|
|
result_len, result_sha = done
|
|
result = dev.download_file(result_len, result_sha, file_number=1)
|
|
open(outp,'wb').write(b64encode(result))
|
|
print('SIGNED_OK bytes=%d -> %s' % (result_len, outp))
|