166 lines
5.0 KiB
Python
166 lines
5.0 KiB
Python
# standard imports
|
|
import datetime
|
|
import logging
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from chainlib.encode import TxHexNormalizer
|
|
from chainlib.eth.address import is_address, to_checksum_address
|
|
|
|
# external imports
|
|
from cic_eth_registry import CICRegistry
|
|
from cic_eth_registry.lookup.tokenindex import TokenIndexLookup
|
|
from cic_types.models.person import Person
|
|
from clicada.error import MetadataNotFoundError
|
|
from clicada.token import FileTokenStore, token_balance
|
|
|
|
# local imports
|
|
from clicada.tx import ResolvedTokenTx, TxGetter
|
|
from clicada.user import FileUserStore
|
|
from hexathon import add_0x
|
|
|
|
logg = logging.getLogger(__name__)
|
|
|
|
tx_normalizer = TxHexNormalizer()
|
|
|
|
|
|
def process_args(argparser):
|
|
argparser.add_argument("-m", "--method", type=str, help="lookup method")
|
|
argparser.add_argument(
|
|
"--meta-url", dest="meta_url", type=str, help="Url to retrieve metadata from"
|
|
)
|
|
argparser.add_argument(
|
|
"-f",
|
|
"--force-update",
|
|
dest="force_update",
|
|
action="store_true",
|
|
help="Update records of mutable entries",
|
|
)
|
|
argparser.add_argument(
|
|
"identifier", type=str, help="user identifier (phone_number or address)"
|
|
)
|
|
|
|
|
|
def extra_args():
|
|
return {
|
|
"force_update": "_FORCE",
|
|
"method": "META_LOOKUP_METHOD",
|
|
"meta_url": "META_URL",
|
|
"identifier": "_IDENTIFIER",
|
|
}
|
|
|
|
|
|
def apply_args(config, args):
|
|
if config.get("META_LOOKUP_METHOD"):
|
|
raise NotImplementedError(
|
|
'Sorry, currently only "phone" lookup method is implemented'
|
|
)
|
|
|
|
|
|
def validate(config, args):
|
|
pass
|
|
|
|
|
|
def execute(ctrl):
|
|
tx_getter = TxGetter(ctrl.get("TX_CACHE_URL"), 10)
|
|
|
|
store_path = os.path.join(str(Path.home()), ".clicada")
|
|
user_phone_file_label = "phone"
|
|
user_phone_store = FileUserStore(
|
|
ctrl.opener("meta"),
|
|
ctrl.chain(),
|
|
user_phone_file_label,
|
|
store_path,
|
|
int(ctrl.get("FILESTORE_TTL")),
|
|
encrypter=ctrl.encrypter,
|
|
)
|
|
|
|
identifier = ctrl.get("_IDENTIFIER")
|
|
ctrl.notify("resolving identifier {} to wallet address".format(identifier))
|
|
if is_address(identifier):
|
|
user_address = identifier
|
|
else:
|
|
user_address = user_phone_store.by_phone(identifier, update=ctrl.get("_FORCE"))
|
|
if user_address == None:
|
|
ctrl.ouch("unknown identifier: {}\n".format(identifier))
|
|
sys.exit(1)
|
|
try:
|
|
user_address = to_checksum_address(user_address)
|
|
except ValueError:
|
|
ctrl.ouch('invalid response "{}" for {}\n'.format(user_address, identifier))
|
|
sys.exit(1)
|
|
|
|
logg.debug("loaded user address {} for {}".format(user_address, identifier))
|
|
|
|
user_address_normal = tx_normalizer.wallet_address(user_address)
|
|
ctrl.notify("retrieving txs for address {}".format(user_address_normal))
|
|
txs = tx_getter.get(user_address)
|
|
|
|
token_store = FileTokenStore(ctrl.chain(), ctrl.conn(), "token", store_path)
|
|
|
|
user_address_file_label = "address"
|
|
user_address_store = FileUserStore(
|
|
ctrl.opener("meta"),
|
|
ctrl.chain(),
|
|
user_address_file_label,
|
|
store_path,
|
|
int(ctrl.get("FILESTORE_TTL")),
|
|
encrypter=ctrl.encrypter,
|
|
)
|
|
|
|
r = None
|
|
ctrl.write(
|
|
f"""
|
|
Phone: {ctrl.get("_IDENTIFIER")}
|
|
Network address: {add_0x(user_address)}
|
|
Chain: {ctrl.chain().common_name()}"""
|
|
)
|
|
ctrl.notify("resolving metadata for address {}".format(user_address_normal))
|
|
try:
|
|
r = user_address_store.by_address(
|
|
user_address_normal, update=ctrl.get("_FORCE")
|
|
)
|
|
if r:
|
|
ctrl.write(
|
|
f"""
|
|
Name: { str(r)}
|
|
Registered: {datetime.datetime.fromtimestamp(r.date_registered).ctime()}
|
|
Gender: {r.gender}
|
|
Location: {r.location["area_name"]}
|
|
Products: {",".join(r.products)}
|
|
Tags: {",".join(r.tags)}"""
|
|
)
|
|
except MetadataNotFoundError as e:
|
|
ctrl.ouch(f"MetadataNotFoundError: Could not resolve metadata for user {e}\n")
|
|
|
|
tx_lines = []
|
|
seen_tokens = {}
|
|
for tx_src in txs["data"]:
|
|
ctrl.notify("resolve details for tx {}".format(tx_src["tx_hash"]))
|
|
tx = ResolvedTokenTx.from_dict(tx_src)
|
|
tx.resolve(
|
|
token_store,
|
|
user_address_store,
|
|
show_decimals=True,
|
|
update=ctrl.get("_FORCE"),
|
|
)
|
|
tx_lines.append(tx)
|
|
seen_tokens[tx.source_token_label] = tx.source_token
|
|
seen_tokens[tx.destination_token_label] = tx.destination_token
|
|
|
|
for k in seen_tokens.keys():
|
|
ctrl.notify("resolve token {}".format(seen_tokens[k]))
|
|
(token_symbol, token_decimals) = token_store.by_address(seen_tokens[k])
|
|
ctrl.notify(
|
|
"get token balance for {} => {}".format(token_symbol, seen_tokens[k])
|
|
)
|
|
balance = token_balance(ctrl.chain(), ctrl.conn(), seen_tokens[k], user_address)
|
|
fmt = "{:." + str(token_decimals) + "f}"
|
|
decimal_balance = fmt.format(balance / (10**token_decimals))
|
|
ctrl.write("Balances:\n {} {}".format(token_symbol, decimal_balance))
|
|
|
|
print()
|
|
for l in tx_lines:
|
|
ctrl.write(l)
|