Gnosis Safe simple offline signer A simple tool to get signatures offline from a cold wallet.
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

101 líneas
2.6KB

  1. import sys, getopt
  2. import json
  3. from getpass import getpass
  4. from eth_account import Account
  5. from hexbytes import HexBytes
  6. """
  7. Main logic extracted from:
  8. https://github.com/gnosis/gnosis-py
  9. """
  10. def signature_to_bytes(v: int, r: int, s: int) -> bytes:
  11. """
  12. Convert ecdsa signature to bytes
  13. :param v:
  14. :param r:
  15. :param s:
  16. :return: signature in form of {bytes32 r}{bytes32 s}{uint8 v}
  17. """
  18. byte_order = "big"
  19. return (
  20. r.to_bytes(32, byteorder=byte_order)
  21. + s.to_bytes(32, byteorder=byte_order)
  22. + v.to_bytes(1, byteorder=byte_order)
  23. )
  24. def sign(private_key: str, safe_tx_hash: HexBytes) -> bytes:
  25. """
  26. {bytes32 r}{bytes32 s}{uint8 v}
  27. :param private_key:
  28. :return: Signature
  29. """
  30. account = Account.from_key(private_key)
  31. signature_dict = account.signHash(safe_tx_hash)
  32. signature = signature_to_bytes(
  33. signature_dict["v"], signature_dict["r"], signature_dict["s"]
  34. )
  35. """
  36. # Insert signature sorted
  37. if account.address not in self.signers:
  38. new_owners = self.signers + [account.address]
  39. new_owner_pos = sorted(new_owners, key=lambda x: int(x, 16)).index(
  40. account.address
  41. )
  42. self.signatures = (
  43. self.signatures[: 65 * new_owner_pos]
  44. + signature
  45. + self.signatures[65 * new_owner_pos :]
  46. )
  47. """
  48. return signature
  49. def get_private_key(keystore: str) -> str:
  50. with open(keystore) as f:
  51. encrypted = f.readlines()
  52. print(encrypted)
  53. print(type(encrypted[0]))
  54. print(json.loads(encrypted[0]))
  55. password = getpass("Enter password:")
  56. return Account.decrypt(json.loads(encrypted[0]), password)
  57. def trim_tx_hash(safe_tx_hash: str) -> str:
  58. if safe_tx_hash[0:2] == "0x":
  59. return safe_tx_hash[2:]
  60. return safe_tx_hash
  61. def get_args(argv):
  62. help_string = 'Usage: python3 safe_sign.py -s hash -k keystore'
  63. if len(argv) < 4:
  64. print(help_string)
  65. sys.exit(2)
  66. try:
  67. opts, args = getopt.getopt(argv,"hs:k:",["hash=,keystore="])
  68. except getopt.GetoptError:
  69. print(help_string)
  70. sys.exit(2)
  71. for opt, arg in opts:
  72. if opt == '-h':
  73. print(help_string)
  74. sys.exit()
  75. elif opt in ("-s", "--hash"):
  76. safe_tx_hash = arg
  77. elif opt in ("-k", "--keystore"):
  78. keystore = arg
  79. return safe_tx_hash, keystore
  80. if __name__ == "__main__":
  81. safe_tx_hash, keystore = get_args(sys.argv[1:])
  82. safe_tx_hash = trim_tx_hash(safe_tx_hash)
  83. pk = get_private_key(keystore)
  84. hb = HexBytes(safe_tx_hash)
  85. signature = sign(pk, hb)
  86. print(HexBytes(signature).hex())