From 7f598e8f9c043944724b85a23ed9db4ce846064c Mon Sep 17 00:00:00 2001 From: moisses89 Date: Sat, 11 Feb 2023 22:10:17 +0100 Subject: [PATCH] Add sign with ledger --- .../operators/hw_accounts/ledger_account.py | 2 +- safe_cli/operators/safe_operator.py | 38 ++++++++++++++++--- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/safe_cli/operators/hw_accounts/ledger_account.py b/safe_cli/operators/hw_accounts/ledger_account.py index 3e7165fc..d75f37e1 100644 --- a/safe_cli/operators/hw_accounts/ledger_account.py +++ b/safe_cli/operators/hw_accounts/ledger_account.py @@ -52,7 +52,7 @@ def encrypt(self, password, kdf=None, iterations=None): # TODO with ledger pass - def signHash(self, message_hash, domain_hash: bytes): + def signHash(self, domain_hash: bytes, message_hash: bytes): signed = sign_typed_data_draft(domain_hash, message_hash, dongle=self.dongle) return (signed.v, signed.r, signed.s) diff --git a/safe_cli/operators/safe_operator.py b/safe_cli/operators/safe_operator.py index 34108165..20af6cf5 100644 --- a/safe_cli/operators/safe_operator.py +++ b/safe_cli/operators/safe_operator.py @@ -7,6 +7,8 @@ from eth_account import Account from eth_account.signers.local import LocalAccount from eth_utils import ValidationError +from gnosis.eth.eip712 import eip712_encode_hash, eip712_encode +from gnosis.safe.signatures import signature_to_bytes from hexbytes import HexBytes from ledgereth import get_account_by_path from ledgereth.comms import init_dongle @@ -299,13 +301,10 @@ def load_ledger_cli_owners(self): HTML( f"Loaded account {account.address} " f'with balance={Web3.fromWei(balance, "ether")} ether' + f'Ledger account cannot be defined as sender' ) ) - if not self.default_sender and balance > 0: - print_formatted_text( - HTML(f"Set account {account.address} as default sender of txs") - ) - self.default_sender = sender + # TODO add ledger as sender break def unload_cli_owners(self, owners: List[str]): @@ -845,6 +844,30 @@ def batch_safe_txs( else: return safe_tx + def ledger_sign(self,safe_tx:SafeTx, account: LedgerAccount) -> bytes: + """ + {bytes32 r}{bytes32 s}{uint8 v} + :param private_key: + :return: Signature + """ + encode_hash = eip712_encode(safe_tx.eip712_structured_data) + v,r,s = account.signHash(encode_hash[1], encode_hash[2]) + signature = signature_to_bytes( + v , r , s + ) + # Insert signature sorted + if account.address not in safe_tx.signers: + new_owners = safe_tx.signers + [account.address] + new_owner_pos = sorted(new_owners, key=lambda x: int(x, 16)).index( + account.address + ) + safe_tx.signatures = ( + safe_tx.signatures[: 65 * new_owner_pos] + + signature + + safe_tx.signatures[65 * new_owner_pos :] + ) + return safe_tx + # TODO Set sender so we can save gas in that signature def sign_transaction(self, safe_tx: SafeTx) -> SafeTx: permitted_signers = self.get_permitted_signers() @@ -863,7 +886,10 @@ def sign_transaction(self, safe_tx: SafeTx) -> SafeTx: raise NotEnoughSignatures(threshold) for selected_account in selected_accounts: - safe_tx.sign(selected_account.key) + if selected_account.key: + safe_tx.sign(selected_account.key) + else: + safe_tx = self.ledger_sign(safe_tx, selected_account) return safe_tx