Initial commit
This commit is contained in:
commit
4788326c4e
28
cic_tools/eth/checksum.py
Normal file
28
cic_tools/eth/checksum.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# third-party imports
|
||||||
|
import sha3
|
||||||
|
from hexathon import (
|
||||||
|
strip_0x,
|
||||||
|
uniform,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def to_checksum(address_hex):
|
||||||
|
|
||||||
|
address_hex = strip_0x(address_hex)
|
||||||
|
address_hex = uniform(address_hex)
|
||||||
|
h = sha3.keccak_256()
|
||||||
|
h.update(address_hex.encode('utf-8'))
|
||||||
|
z = h.digest()
|
||||||
|
|
||||||
|
checksum_address_hex = '0x'
|
||||||
|
|
||||||
|
for (i, c) in enumerate(address_hex):
|
||||||
|
if c in '1234567890':
|
||||||
|
checksum_address_hex += c
|
||||||
|
elif c in 'abcdef':
|
||||||
|
if z[int(i / 2)] & (0x80 >> ((i % 2) * 4)) > 1:
|
||||||
|
checksum_address_hex += c.upper()
|
||||||
|
else:
|
||||||
|
checksum_address_hex += c
|
||||||
|
|
||||||
|
return checksum_address_hex
|
31
cic_tools/eth/connection.py
Normal file
31
cic_tools/eth/connection.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import logging
|
||||||
|
import json
|
||||||
|
from urllib.request import (
|
||||||
|
Request,
|
||||||
|
urlopen,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .error import DefaultErrorParser
|
||||||
|
from .method import jsonrpc_result
|
||||||
|
|
||||||
|
error_parser = DefaultErrorParser()
|
||||||
|
logg = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class HTTPConnection:
|
||||||
|
|
||||||
|
def __init__(self, url):
|
||||||
|
self.url = url
|
||||||
|
|
||||||
|
|
||||||
|
def do(self, o, error_parser=error_parser):
|
||||||
|
req = Request(
|
||||||
|
self.url,
|
||||||
|
method='POST',
|
||||||
|
)
|
||||||
|
req.add_header('Content-Type', 'application/json')
|
||||||
|
data = json.dumps(o)
|
||||||
|
logg.debug('(HTTP) send {}'.format(data))
|
||||||
|
res = urlopen(req, data=data.encode('utf-8'))
|
||||||
|
o = json.load(res)
|
||||||
|
return jsonrpc_result(o, error_parser)
|
2
cic_tools/eth/constant.py
Normal file
2
cic_tools/eth/constant.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
zero_address = '0x{:040x}'.format(0)
|
||||||
|
zero_content = '0x{:064x}'.format(0)
|
8
cic_tools/eth/error.py
Normal file
8
cic_tools/eth/error.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
class EthException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultErrorParser:
|
||||||
|
|
||||||
|
def translate(self, error):
|
||||||
|
return EthException('default parser code {}'.format(error))
|
7
cic_tools/eth/hash.py
Normal file
7
cic_tools/eth/hash.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import sha3
|
||||||
|
|
||||||
|
|
||||||
|
def keccak256_hex(s):
|
||||||
|
h = sha3.keccak_256()
|
||||||
|
h.update(s.encode('utf-8'))
|
||||||
|
return h.digest().hex()
|
61
cic_tools/eth/method.py
Normal file
61
cic_tools/eth/method.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import sha3
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from hexathon import add_0x
|
||||||
|
from eth_abi import encode_single
|
||||||
|
|
||||||
|
from .hash import keccak256_hex
|
||||||
|
from .constant import zero_address
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: move to cic-contracts
|
||||||
|
erc20_balance_signature = keccak256_hex('balanceOf(address)')[:8]
|
||||||
|
erc20_decimals_signature = keccak256_hex('decimals()')[:8]
|
||||||
|
|
||||||
|
|
||||||
|
def jsonrpc_template():
|
||||||
|
return {
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': str(uuid.uuid4()),
|
||||||
|
'method': None,
|
||||||
|
'params': [],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def erc20_balance(contract_address, address, sender_address=zero_address):
|
||||||
|
o = jsonrpc_template()
|
||||||
|
o['method'] = 'eth_call'
|
||||||
|
data = erc20_balance_signature
|
||||||
|
data += encode_single('address', address).hex()
|
||||||
|
data = add_0x(data)
|
||||||
|
a = call(contract_address, data=data)
|
||||||
|
o['params'].append(a)
|
||||||
|
o['params'].append('latest')
|
||||||
|
return o
|
||||||
|
|
||||||
|
|
||||||
|
def erc20_decimals(contract_address, sender_address=zero_address):
|
||||||
|
o = jsonrpc_template()
|
||||||
|
o['method'] = 'eth_call'
|
||||||
|
arg = add_0x(erc20_decimals_signature)
|
||||||
|
#o['params'].append(arg)
|
||||||
|
a = call(contract_address, arg)
|
||||||
|
o['params'].append(a)
|
||||||
|
o['params'].append('latest')
|
||||||
|
return o
|
||||||
|
|
||||||
|
|
||||||
|
def call(contract_address, data, sender_address=zero_address):
|
||||||
|
return {
|
||||||
|
'from': sender_address,
|
||||||
|
'to': contract_address,
|
||||||
|
'data': data,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def jsonrpc_result(o, ep):
|
||||||
|
if o.get('error') != None:
|
||||||
|
raise ep.translate(o)
|
||||||
|
return o['result']
|
||||||
|
|
||||||
|
|
0
cic_tools/eth/runnable/__init__.py
Normal file
0
cic_tools/eth/runnable/__init__.py
Normal file
99
cic_tools/eth/runnable/balance.py
Normal file
99
cic_tools/eth/runnable/balance.py
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#!python3
|
||||||
|
|
||||||
|
"""Token balance query script
|
||||||
|
|
||||||
|
.. moduleauthor:: Louis Holbrook <dev@holbrook.no>
|
||||||
|
.. pgp:: 0826EDA1702D1E87C6E2875121D2E7BB88C2A746
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
# standard imports
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# third-party imports
|
||||||
|
from hexathon import (
|
||||||
|
add_0x,
|
||||||
|
strip_0x,
|
||||||
|
even,
|
||||||
|
)
|
||||||
|
import sha3
|
||||||
|
from eth_abi import encode_single
|
||||||
|
|
||||||
|
# local imports
|
||||||
|
from cic_tools.eth.checksum import to_checksum
|
||||||
|
from cic_tools.eth.method import (
|
||||||
|
jsonrpc_template,
|
||||||
|
erc20_balance,
|
||||||
|
erc20_decimals,
|
||||||
|
jsonrpc_result,
|
||||||
|
)
|
||||||
|
from cic_tools.eth.connection import HTTPConnection
|
||||||
|
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.WARNING)
|
||||||
|
logg = logging.getLogger()
|
||||||
|
|
||||||
|
default_abi_dir = os.environ.get('ETH_ABI_DIR', '/usr/share/local/cic/solidity/abi')
|
||||||
|
default_eth_provider = os.environ.get('ETH_PROVIDER', 'http://localhost:8545')
|
||||||
|
|
||||||
|
argparser = argparse.ArgumentParser()
|
||||||
|
argparser.add_argument('-p', '--provider', dest='p', default=default_eth_provider, type=str, help='Web3 provider url (http only)')
|
||||||
|
argparser.add_argument('-t', '--token-address', dest='t', type=str, help='Token address. If not set, will return gas balance')
|
||||||
|
argparser.add_argument('-u', '--unsafe', dest='u', action='store_true', help='Auto-convert address to checksum adddress')
|
||||||
|
argparser.add_argument('--abi-dir', dest='abi_dir', type=str, default=default_abi_dir, help='Directory containing bytecode and abi (default {})'.format(default_abi_dir))
|
||||||
|
argparser.add_argument('-v', action='store_true', help='Be verbose')
|
||||||
|
argparser.add_argument('account', type=str, help='Account address')
|
||||||
|
args = argparser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
if args.v:
|
||||||
|
logg.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
conn = HTTPConnection(args.p)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# w3 = web3.Web3(web3.Web3.HTTPProvider(args.p))
|
||||||
|
# REPLACE WITH URLLIB
|
||||||
|
|
||||||
|
account = to_checksum(args.account)
|
||||||
|
if not args.u and account != add_0x(args.account):
|
||||||
|
raise ValueError('invalid checksum address')
|
||||||
|
|
||||||
|
r = None
|
||||||
|
decimals = 18
|
||||||
|
if args.t != None:
|
||||||
|
# determine decimals
|
||||||
|
decimals_o = erc20_decimals(args.t)
|
||||||
|
r = conn.do(decimals_o)
|
||||||
|
decimals = int(strip_0x(r), 16)
|
||||||
|
|
||||||
|
# get balance
|
||||||
|
balance_o = erc20_balance(args.t, account)
|
||||||
|
r = conn.do(balance_o)
|
||||||
|
|
||||||
|
else:
|
||||||
|
o = jsonrpc_template()
|
||||||
|
o['method'] = 'eth_getBalance'
|
||||||
|
o['params'].append(account)
|
||||||
|
r = conn.do(o)
|
||||||
|
|
||||||
|
hx = strip_0x(r)
|
||||||
|
balance = int(hx, 16)
|
||||||
|
logg.debug('balance {} = {} decimals {}'.format(even(hx), balance, decimals))
|
||||||
|
|
||||||
|
balance_str = str(balance)
|
||||||
|
balance_len = len(balance_str)
|
||||||
|
if balance_len < 19:
|
||||||
|
print('0.{}'.format(balance_str.zfill(decimals)))
|
||||||
|
else:
|
||||||
|
offset = balance_len-decimals
|
||||||
|
print('{}.{}'.format(balance_str[:offset],balance_str[offset:]))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
8
cic_tools/eth/runnable/checksum.py
Normal file
8
cic_tools/eth/runnable/checksum.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# standard imports
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# local imports
|
||||||
|
from cic_tools.eth.checksum import to_checksum
|
||||||
|
|
||||||
|
|
||||||
|
print(to_checksum(sys.argv[1]))
|
13
requirements.txt
Normal file
13
requirements.txt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
cryptocurrency-cli-tools==0.0.4
|
||||||
|
giftable-erc20-token==0.0.7b6
|
||||||
|
eth-accounts-index==0.0.10a6
|
||||||
|
erc20-single-shot-faucet==0.2.0a5
|
||||||
|
erc20-approval-escrow==0.3.0a4
|
||||||
|
cic-eth==0.10.0a21+build.e4161b3e
|
||||||
|
vobject==0.9.6.1
|
||||||
|
faker==4.17.1
|
||||||
|
eth-address-index==0.1.0a5
|
||||||
|
crypto-dev-signer==0.4.13rc2
|
||||||
|
pysha3==1.0.2
|
||||||
|
hexathon==0.0.1a2
|
||||||
|
eth-abi==2.1.1
|
36
setup.cfg
Normal file
36
setup.cfg
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
[metadata]
|
||||||
|
name = cic-tools
|
||||||
|
version = 0.0.1a1
|
||||||
|
description = Executable tools for CIC network
|
||||||
|
author = Louis Holbrook
|
||||||
|
author_email = dev@holbrook.no
|
||||||
|
url = https://gitlab.com/grassrootseconomics/cic-tools
|
||||||
|
keywords =
|
||||||
|
cic
|
||||||
|
cryptocurrency
|
||||||
|
ethereum
|
||||||
|
solidarity
|
||||||
|
mutual_credit
|
||||||
|
classifiers =
|
||||||
|
Programming Language :: Python :: 3
|
||||||
|
Operating System :: OS Independent
|
||||||
|
Development Status :: 3 - Alpha
|
||||||
|
Environment :: Console
|
||||||
|
Intended Audience :: Developers
|
||||||
|
License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
||||||
|
Topic :: Internet
|
||||||
|
# Topic :: Blockchain :: EVM
|
||||||
|
license = GPL3
|
||||||
|
licence_files =
|
||||||
|
LICENSE.txt
|
||||||
|
|
||||||
|
[options]
|
||||||
|
python_requires = >= 3.6
|
||||||
|
packages =
|
||||||
|
cic_tools.eth
|
||||||
|
cic_tools.eth.runnable
|
||||||
|
|
||||||
|
[options.entry_points]
|
||||||
|
console_scripts =
|
||||||
|
eth-balance = cic_tools.eth.runnable.balance:main
|
||||||
|
eth-checksum = cic_tools.eth.runnable.checksum:main
|
Loading…
Reference in New Issue
Block a user