Bingen Eguzkitza 3 роки тому
коміт
07c9a67856
4 змінених файлів з 126 додано та 0 видалено
  1. +1
    -0
      .gitignore
  2. +9
    -0
      README.md
  3. +16
    -0
      requirements.txt
  4. +100
    -0
      safe_sign.py

+ 1
- 0
.gitignore Переглянути файл

@@ -0,0 +1 @@
env

+ 9
- 0
README.md Переглянути файл

@@ -0,0 +1,9 @@
# Simple offline Gnosis Safe signer

Usage:

```
python3 ./safe_sign.py -s <your-safe-tx-hash> -k <your-wallet-keystore-file>
```

Main logic extracted from [gnosis-py](https://github.com/gnosis/gnosis-py).

+ 16
- 0
requirements.txt Переглянути файл

@@ -0,0 +1,16 @@
bitarray==1.2.2
cytoolz==0.11.2
eth-abi==3.0.0
eth-account==0.6.1
eth-hash==0.3.2
eth-keyfile==0.6.0
eth-keys==0.4.0
eth-rlp==0.3.0
eth-typing==3.0.0
eth-utils==2.0.0
hexbytes==0.2.2
parsimonious==0.8.1
pycryptodome==3.14.1
rlp==3.0.0
six==1.16.0
toolz==0.11.2

+ 100
- 0
safe_sign.py Переглянути файл

@@ -0,0 +1,100 @@
import sys, getopt
import json
from getpass import getpass
from eth_account import Account
from hexbytes import HexBytes

"""
Main logic extracted from:
https://github.com/gnosis/gnosis-py
"""

def signature_to_bytes(v: int, r: int, s: int) -> bytes:
"""
Convert ecdsa signature to bytes
:param v:
:param r:
:param s:
:return: signature in form of {bytes32 r}{bytes32 s}{uint8 v}
"""

byte_order = "big"

return (
r.to_bytes(32, byteorder=byte_order)
+ s.to_bytes(32, byteorder=byte_order)
+ v.to_bytes(1, byteorder=byte_order)
)

def sign(private_key: str, safe_tx_hash: HexBytes) -> bytes:
"""
{bytes32 r}{bytes32 s}{uint8 v}
:param private_key:
:return: Signature
"""
account = Account.from_key(private_key)
signature_dict = account.signHash(safe_tx_hash)
signature = signature_to_bytes(
signature_dict["v"], signature_dict["r"], signature_dict["s"]
)

"""
# Insert signature sorted
if account.address not in self.signers:
new_owners = self.signers + [account.address]
new_owner_pos = sorted(new_owners, key=lambda x: int(x, 16)).index(
account.address
)
self.signatures = (
self.signatures[: 65 * new_owner_pos]
+ signature
+ self.signatures[65 * new_owner_pos :]
)
"""
return signature

def get_private_key(keystore: str) -> str:
with open(keystore) as f:
encrypted = f.readlines()
print(encrypted)
print(type(encrypted[0]))
print(json.loads(encrypted[0]))

password = getpass("Enter password:")

return Account.decrypt(json.loads(encrypted[0]), password)

def trim_tx_hash(safe_tx_hash: str) -> str:
if safe_tx_hash[0:2] == "0x":
return safe_tx_hash[2:]
return safe_tx_hash

def get_args(argv):
help_string = 'Usage: python3 safe_sign.py -s hash -k keystore'
if len(argv) < 4:
print(help_string)
sys.exit(2)
try:
opts, args = getopt.getopt(argv,"hs:k:",["hash=,keystore="])
except getopt.GetoptError:
print(help_string)
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
print(help_string)
sys.exit()
elif opt in ("-s", "--hash"):
safe_tx_hash = arg
elif opt in ("-k", "--keystore"):
keystore = arg

return safe_tx_hash, keystore

if __name__ == "__main__":
safe_tx_hash, keystore = get_args(sys.argv[1:])
safe_tx_hash = trim_tx_hash(safe_tx_hash)
pk = get_private_key(keystore)
hb = HexBytes(safe_tx_hash)
signature = sign(pk, hb)

print(HexBytes(signature).hex())

Завантаження…
Відмінити
Зберегти