From 7b16a36a62d393c8aa96c84d2c7a15f9ce648662 Mon Sep 17 00:00:00 2001 From: Louis Holbrook Date: Fri, 9 Apr 2021 13:00:15 +0000 Subject: [PATCH] Implement migration script with ussd and notify --- apps/cic-eth/cic_eth/db/models/base.py | 11 +- .../cic_eth/runnable/daemons/tasker.py | 2 +- apps/cic-eth/config/database.ini | 1 + apps/cic-eth/config/docker/database.ini | 1 + apps/cic-meta/package.json | 4 +- apps/cic-meta/scripts/server/server.ts | 2 + apps/cic-meta/src/assets/phone.ts | 8 +- apps/cic-meta/src/digest.ts | 1 + apps/cic-notify/docker/Dockerfile | 2 +- apps/cic-ussd/.config/app.ini | 7 +- apps/cic-ussd/.config/database.ini | 2 + apps/cic-ussd/.config/redis.ini | 6 +- apps/cic-ussd/cic_ussd/db/models/base.py | 110 +- apps/cic-ussd/cic_ussd/error.py | 9 +- apps/cic-ussd/cic_ussd/metadata/__init__.py | 7 +- apps/cic-ussd/cic_ussd/metadata/base.py | 7 + apps/cic-ussd/cic_ussd/metadata/phone.py | 85 + apps/cic-ussd/cic_ussd/metadata/signer.py | 2 +- apps/cic-ussd/cic_ussd/metadata/user.py | 22 +- apps/cic-ussd/cic_ussd/processor.py | 4 +- apps/cic-ussd/cic_ussd/runnable/server.py | 14 +- apps/cic-ussd/cic_ussd/runnable/tasker.py | 7 +- .../cic_ussd/state_machine/logic/user.py | 4 +- apps/cic-ussd/cic_ussd/tasks/base.py | 24 +- .../cic_ussd/tasks/callback_handler.py | 19 +- apps/cic-ussd/cic_ussd/tasks/metadata.py | 14 +- apps/cic-ussd/cic_ussd/tasks/ussd_session.py | 1 + apps/cic-ussd/cic_ussd/validator.py | 10 +- apps/cic-ussd/docker/Dockerfile | 2 +- apps/cic-ussd/docker/start_tasker.sh | 2 +- apps/cic-ussd/docker/start_uwsgi.sh | 4 +- apps/cic-ussd/requirements.txt | 4 +- apps/contract-migration/scripts/README.md | 244 +- .../scripts/{ => cic_eth}/import_balance.py | 13 +- .../scripts/{ => cic_eth}/import_users.py | 31 +- .../{ => cic_eth/traffic}/cmd/__init__.py | 0 .../{ => cic_eth/traffic}/cmd/traffic.py | 0 .../{ => cic_eth/traffic}/common/__init__.py | 0 .../{ => cic_eth/traffic}/common/argparse.py | 0 .../{ => cic_eth/traffic}/common/config.py | 0 .../{ => cic_eth/traffic}/common/log.py | 0 .../{ => cic_eth/traffic}/common/registry.py | 0 .../{ => cic_eth/traffic}/common/rpc.py | 0 .../{ => cic_eth/traffic}/common/signer.py | 0 .../{ => cic_eth/traffic}/local/account.py | 0 .../{ => cic_eth/traffic}/local/noop.py | 0 .../{ => cic_eth/traffic}/local/transfer.py | 0 .../scripts/{ => cic_eth/traffic}/traffic.py | 0 .../scripts/{ => cic_meta}/import_meta.js | 1 + .../scripts/cic_meta/import_meta_phone.js | 134 ++ .../scripts/cic_ussd/import_balance.py | 157 ++ .../scripts/cic_ussd/import_task.py | 218 ++ .../scripts/cic_ussd/import_users.py | 191 ++ .../scripts/cic_ussd/import_util.py | 72 + .../scripts/config/meta.ini | 3 + .../scripts/create_import_users.py | 13 +- .../scripts/eth/import_balance.py | 309 +++ .../import_users.py} | 34 +- .../_logs/2021-02-12T18_59_21_680Z-debug.log | 1383 ----------- .../scripts/false/anonymous-cli-metrics.json | 1 - .../scripts/import_balance.sh | 1 - .../scripts/import_users.sh | 1 - .../scripts/package-lock.json | 2111 ++++++++++++++++- apps/contract-migration/scripts/verify.py | 94 +- docker-compose.yml | 15 +- 65 files changed, 3892 insertions(+), 1532 deletions(-) create mode 100644 apps/cic-ussd/cic_ussd/metadata/base.py create mode 100644 apps/cic-ussd/cic_ussd/metadata/phone.py rename apps/contract-migration/scripts/{ => cic_eth}/import_balance.py (97%) rename apps/contract-migration/scripts/{ => cic_eth}/import_users.py (85%) rename apps/contract-migration/scripts/{ => cic_eth/traffic}/cmd/__init__.py (100%) rename apps/contract-migration/scripts/{ => cic_eth/traffic}/cmd/traffic.py (100%) rename apps/contract-migration/scripts/{ => cic_eth/traffic}/common/__init__.py (100%) rename apps/contract-migration/scripts/{ => cic_eth/traffic}/common/argparse.py (100%) rename apps/contract-migration/scripts/{ => cic_eth/traffic}/common/config.py (100%) rename apps/contract-migration/scripts/{ => cic_eth/traffic}/common/log.py (100%) rename apps/contract-migration/scripts/{ => cic_eth/traffic}/common/registry.py (100%) rename apps/contract-migration/scripts/{ => cic_eth/traffic}/common/rpc.py (100%) rename apps/contract-migration/scripts/{ => cic_eth/traffic}/common/signer.py (100%) rename apps/contract-migration/scripts/{ => cic_eth/traffic}/local/account.py (100%) rename apps/contract-migration/scripts/{ => cic_eth/traffic}/local/noop.py (100%) rename apps/contract-migration/scripts/{ => cic_eth/traffic}/local/transfer.py (100%) rename apps/contract-migration/scripts/{ => cic_eth/traffic}/traffic.py (100%) rename apps/contract-migration/scripts/{ => cic_meta}/import_meta.js (99%) create mode 100644 apps/contract-migration/scripts/cic_meta/import_meta_phone.js create mode 100644 apps/contract-migration/scripts/cic_ussd/import_balance.py create mode 100644 apps/contract-migration/scripts/cic_ussd/import_task.py create mode 100644 apps/contract-migration/scripts/cic_ussd/import_users.py create mode 100644 apps/contract-migration/scripts/cic_ussd/import_util.py create mode 100644 apps/contract-migration/scripts/eth/import_balance.py rename apps/contract-migration/scripts/{import_sovereign_users.py => eth/import_users.py} (83%) delete mode 100644 apps/contract-migration/scripts/false/_logs/2021-02-12T18_59_21_680Z-debug.log delete mode 100644 apps/contract-migration/scripts/false/anonymous-cli-metrics.json delete mode 100644 apps/contract-migration/scripts/import_balance.sh delete mode 100644 apps/contract-migration/scripts/import_users.sh diff --git a/apps/cic-eth/cic_eth/db/models/base.py b/apps/cic-eth/cic_eth/db/models/base.py index fc3541c5..9cdcabf7 100644 --- a/apps/cic-eth/cic_eth/db/models/base.py +++ b/apps/cic-eth/cic_eth/db/models/base.py @@ -10,6 +10,7 @@ from sqlalchemy.pool import ( StaticPool, QueuePool, AssertionPool, + NullPool, ) logg = logging.getLogger() @@ -64,6 +65,7 @@ class SessionBase(Model): if SessionBase.poolable: poolclass = QueuePool if pool_size > 1: + logg.info('db using queue pool') e = create_engine( dsn, max_overflow=pool_size*3, @@ -74,17 +76,22 @@ class SessionBase(Model): echo=debug, ) else: - if debug: + if pool_size == 0: + logg.info('db using nullpool') + poolclass = NullPool + elif debug: + logg.info('db using assertion pool') poolclass = AssertionPool else: + logg.info('db using static pool') poolclass = StaticPool - e = create_engine( dsn, poolclass=poolclass, echo=debug, ) else: + logg.info('db not poolable') e = create_engine( dsn, echo=debug, diff --git a/apps/cic-eth/cic_eth/runnable/daemons/tasker.py b/apps/cic-eth/cic_eth/runnable/daemons/tasker.py index ef7c122b..8a4a47f5 100644 --- a/apps/cic-eth/cic_eth/runnable/daemons/tasker.py +++ b/apps/cic-eth/cic_eth/runnable/daemons/tasker.py @@ -91,7 +91,7 @@ logg.debug('config loaded from {}:\n{}'.format(args.c, config)) # connect to database dsn = dsn_from_config(config) -SessionBase.connect(dsn, pool_size=50, debug=config.true('DATABASE_DEBUG')) +SessionBase.connect(dsn, pool_size=int(config.get('DATABASE_POOL_SIZE')), debug=config.true('DATABASE_DEBUG')) # verify database connection with minimal sanity query session = SessionBase.create_session() diff --git a/apps/cic-eth/config/database.ini b/apps/cic-eth/config/database.ini index 50a2dd0d..4517445c 100644 --- a/apps/cic-eth/config/database.ini +++ b/apps/cic-eth/config/database.ini @@ -6,4 +6,5 @@ HOST=localhost PORT=5432 ENGINE=postgresql DRIVER=psycopg2 +POOL_SIZE=50 DEBUG=0 diff --git a/apps/cic-eth/config/docker/database.ini b/apps/cic-eth/config/docker/database.ini index a5f2be48..6448be0e 100644 --- a/apps/cic-eth/config/docker/database.ini +++ b/apps/cic-eth/config/docker/database.ini @@ -6,4 +6,5 @@ HOST=localhost PORT=63432 ENGINE=postgresql DRIVER=psycopg2 +POOL_SIZE=50 DEBUG=0 diff --git a/apps/cic-meta/package.json b/apps/cic-meta/package.json index 39144727..ef706733 100644 --- a/apps/cic-meta/package.json +++ b/apps/cic-meta/package.json @@ -1,6 +1,6 @@ { "name": "cic-client-meta", - "version": "0.0.7-alpha.3", + "version": "0.0.7-alpha.6", "description": "Signed CRDT metadata graphs for the CIC network", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -40,6 +40,6 @@ ], "license": "GPL-3.0-or-later", "engines": { - "node": "~15.3.0" + "node": "~14.16.1" } } diff --git a/apps/cic-meta/scripts/server/server.ts b/apps/cic-meta/scripts/server/server.ts index ca9c2dfb..9bef8bda 100755 --- a/apps/cic-meta/scripts/server/server.ts +++ b/apps/cic-meta/scripts/server/server.ts @@ -114,6 +114,7 @@ async function processRequest(req, res) { return; } + if (!['PUT', 'GET', 'POST'].includes(req.method)) { res.writeHead(405, {"Content-Type": "text/plain"}); res.end(); @@ -123,6 +124,7 @@ async function processRequest(req, res) { try { digest = parseDigest(req.url); } catch(e) { + console.error('digest error: ' + e) res.writeHead(400, {"Content-Type": "text/plain"}); res.end(); return; diff --git a/apps/cic-meta/src/assets/phone.ts b/apps/cic-meta/src/assets/phone.ts index e786265e..7ace058f 100644 --- a/apps/cic-meta/src/assets/phone.ts +++ b/apps/cic-meta/src/assets/phone.ts @@ -1,12 +1,12 @@ import { ArgPair, Syncable } from '../sync'; -import { Addressable, addressToBytes, bytesToHex, toKey } from '../digest'; +import { Addressable, mergeKey } from '../digest'; class Phone extends Syncable implements Addressable { address: string value: number - constructor(address:string, v:number) { + constructor(address:string, v:string) { const o = { msisdn: v, } @@ -17,8 +17,8 @@ class Phone extends Syncable implements Addressable { }); } - public static async toKey(msisdn:number) { - return await toKey(msisdn.toString(), ':cic.msisdn'); + public static async toKey(msisdn:string) { + return await mergeKey(Buffer.from(msisdn), Buffer.from(':cic.phone')); } public key(): string { diff --git a/apps/cic-meta/src/digest.ts b/apps/cic-meta/src/digest.ts index 8681578d..d66f7463 100644 --- a/apps/cic-meta/src/digest.ts +++ b/apps/cic-meta/src/digest.ts @@ -61,6 +61,7 @@ function addressToBytes(s:string) { export { toKey, toAddressKey, + mergeKey, bytesToHex, addressToBytes, Addressable, diff --git a/apps/cic-notify/docker/Dockerfile b/apps/cic-notify/docker/Dockerfile index 67b2e4c4..ea00a238 100644 --- a/apps/cic-notify/docker/Dockerfile +++ b/apps/cic-notify/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.8.6 +FROM python:3.8.6-slim-buster RUN apt-get update && \ apt install -y gcc gnupg libpq-dev wget make g++ gnupg bash procps diff --git a/apps/cic-ussd/.config/app.ini b/apps/cic-ussd/.config/app.ini index 3efaaabc..5df11153 100644 --- a/apps/cic-ussd/.config/app.ini +++ b/apps/cic-ussd/.config/app.ini @@ -1,11 +1,14 @@ [app] -ALLOWED_IP=127.0.0.1 +ALLOWED_IP=0.0.0.0/0 LOCALE_FALLBACK=en -LOCALE_PATH=var/lib/locale/ +LOCALE_PATH=/usr/src/cic-ussd/var/lib/locale/ MAX_BODY_LENGTH=1024 PASSWORD_PEPPER=QYbzKff6NhiQzY3ygl2BkiKOpER8RE/Upqs/5aZWW+I= SERVICE_CODE=*483*46# +[phone_number] +REGION=KE + [ussd] MENU_FILE=/usr/src/data/ussd_menu.json diff --git a/apps/cic-ussd/.config/database.ini b/apps/cic-ussd/.config/database.ini index 7e2c3e44..5bce6bcf 100644 --- a/apps/cic-ussd/.config/database.ini +++ b/apps/cic-ussd/.config/database.ini @@ -6,3 +6,5 @@ HOST=localhost PORT=5432 ENGINE=postgresql DRIVER=psycopg2 +DEBUG=0 +POOL_SIZE=1 diff --git a/apps/cic-ussd/.config/redis.ini b/apps/cic-ussd/.config/redis.ini index 44b3a0bf..417481db 100644 --- a/apps/cic-ussd/.config/redis.ini +++ b/apps/cic-ussd/.config/redis.ini @@ -1,9 +1,9 @@ [celery] -BROKER_URL=redis:// -RESULT_URL=redis:// +BROKER_URL=redis://redis:6379 +RESULT_URL=redis://redis:6379 [redis] -HOSTNAME=localhost +HOSTNAME=redis PASSWORD= PORT=6379 DATABASE=0 diff --git a/apps/cic-ussd/cic_ussd/db/models/base.py b/apps/cic-ussd/cic_ussd/db/models/base.py index 9ff5227e..d76ee6c4 100644 --- a/apps/cic-ussd/cic_ussd/db/models/base.py +++ b/apps/cic-ussd/cic_ussd/db/models/base.py @@ -1,47 +1,129 @@ -# standard imports +# stanard imports +import logging import datetime -# third-party imports +# external imports from sqlalchemy import Column, Integer, DateTime from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker +from sqlalchemy.pool import ( + StaticPool, + QueuePool, + AssertionPool, + NullPool, + ) + +logg = logging.getLogger().getChild(__name__) Model = declarative_base(name='Model') class SessionBase(Model): + """The base object for all SQLAlchemy enabled models. All other models must extend this. + """ __abstract__ = True - id = Column(Integer, primary_key=True) created = Column(DateTime, default=datetime.datetime.utcnow) updated = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow) + id = Column(Integer, primary_key=True) + engine = None - session = None - query = None + """Database connection engine of the running aplication""" + sessionmaker = None + """Factory object responsible for creating sessions from the connection pool""" + transactional = True + """Whether the database backend supports query transactions. Should be explicitly set by initialization code""" + poolable = True + """Whether the database backend supports connection pools. Should be explicitly set by initialization code""" + procedural = True + """Whether the database backend supports stored procedures""" + localsessions = {} + """Contains dictionary of sessions initiated by db model components""" + @staticmethod def create_session(): - session = sessionmaker(bind=SessionBase.engine) - return session() + """Creates a new database session. + """ + return SessionBase.sessionmaker() + @staticmethod def _set_engine(engine): + """Sets the database engine static property + """ SessionBase.engine = engine + SessionBase.sessionmaker = sessionmaker(bind=SessionBase.engine) + @staticmethod - def build(): - Model.metadata.create_all(bind=SessionBase.engine) + def connect(dsn, pool_size=16, debug=False): + """Create new database connection engine and connect to database backend. + + :param dsn: DSN string defining connection. + :type dsn: str + """ + e = None + if SessionBase.poolable: + poolclass = QueuePool + if pool_size > 1: + logg.info('db using queue pool') + e = create_engine( + dsn, + max_overflow=pool_size*3, + pool_pre_ping=True, + pool_size=pool_size, + pool_recycle=60, + poolclass=poolclass, + echo=debug, + ) + else: + if pool_size == 0: + poolclass = NullPool + elif debug: + poolclass = AssertionPool + else: + poolclass = StaticPool + e = create_engine( + dsn, + poolclass=poolclass, + echo=debug, + ) + else: + logg.info('db connection not poolable') + e = create_engine( + dsn, + echo=debug, + ) + + SessionBase._set_engine(e) - @staticmethod - # https://docs.sqlalchemy.org/en/13/core/pooling.html#pool-disconnects - def connect(data_source_name): - engine = create_engine(data_source_name, pool_pre_ping=True) - SessionBase._set_engine(engine) @staticmethod def disconnect(): + """Disconnect from database and free resources. + """ SessionBase.engine.dispose() SessionBase.engine = None + + @staticmethod + def bind_session(session=None): + localsession = session + if localsession == None: + localsession = SessionBase.create_session() + localsession_key = str(id(localsession)) + logg.debug('creating new session {}'.format(localsession_key)) + SessionBase.localsessions[localsession_key] = localsession + return localsession + + + @staticmethod + def release_session(session=None): + session_key = str(id(session)) + if SessionBase.localsessions.get(session_key) != None: + logg.debug('commit and destroy session {}'.format(session_key)) + session.commit() + session.close() diff --git a/apps/cic-ussd/cic_ussd/error.py b/apps/cic-ussd/cic_ussd/error.py index 006a7a49..256e77c6 100644 --- a/apps/cic-ussd/cic_ussd/error.py +++ b/apps/cic-ussd/cic_ussd/error.py @@ -18,7 +18,7 @@ class ActionDataNotFoundError(OSError): pass -class UserMetadataNotFoundError(OSError): +class MetadataNotFoundError(OSError): """Raised when metadata is expected but not available in cache.""" pass @@ -31,3 +31,10 @@ class UnsupportedMethodError(OSError): class CachedDataNotFoundError(OSError): """Raised when the method passed to the make request function is unsupported.""" pass + + +class MetadataStoreError(Exception): + """Raised when metadata storage fails""" + pass + + diff --git a/apps/cic-ussd/cic_ussd/metadata/__init__.py b/apps/cic-ussd/cic_ussd/metadata/__init__.py index 1c90189e..44c4a217 100644 --- a/apps/cic-ussd/cic_ussd/metadata/__init__.py +++ b/apps/cic-ussd/cic_ussd/metadata/__init__.py @@ -3,7 +3,10 @@ # third-party imports import requests from chainlib.eth.address import to_checksum -from hexathon import add_0x +from hexathon import ( + add_0x, + strip_0x, + ) # local imports from cic_ussd.error import UnsupportedMethodError @@ -40,4 +43,4 @@ def blockchain_address_to_metadata_pointer(blockchain_address: str): :return: :rtype: """ - return bytes.fromhex(blockchain_address[2:]) + return bytes.fromhex(strip_0x(blockchain_address)) diff --git a/apps/cic-ussd/cic_ussd/metadata/base.py b/apps/cic-ussd/cic_ussd/metadata/base.py new file mode 100644 index 00000000..8f163d78 --- /dev/null +++ b/apps/cic-ussd/cic_ussd/metadata/base.py @@ -0,0 +1,7 @@ +class Metadata: + """ + :cvar base_url: + :type base_url: + """ + + base_url = None diff --git a/apps/cic-ussd/cic_ussd/metadata/phone.py b/apps/cic-ussd/cic_ussd/metadata/phone.py new file mode 100644 index 00000000..4f1d8d51 --- /dev/null +++ b/apps/cic-ussd/cic_ussd/metadata/phone.py @@ -0,0 +1,85 @@ +# standard imports +import json +import logging +import os + +# external imports +import requests +from cic_types.models.person import generate_metadata_pointer +from cic_ussd.metadata import make_request +from cic_ussd.metadata.signer import Signer + +# local imports +from cic_ussd.error import MetadataStoreError +from .base import Metadata + +logg = logging.getLogger().getChild(__name__) + + +class PhonePointerMetadata(Metadata): + + def __init__(self, identifier: bytes, engine: str): + """ + :param identifier: + :type identifier: + """ + + self.headers = { + 'X-CIC-AUTOMERGE': 'server', + 'Content-Type': 'application/json' + } + self.identifier = identifier + self.metadata_pointer = generate_metadata_pointer( + identifier=self.identifier, + cic_type=':cic.phone' + ) + if self.base_url: + self.url = os.path.join(self.base_url, self.metadata_pointer) + + self.engine = engine + + + def create(self, data: str): + try: + data = json.dumps(data).encode('utf-8') + result = make_request(method='POST', url=self.url, data=data, headers=self.headers) + metadata = result.content + logg.debug('data {} meta {} resp {} stats {}'.format(data, metadata, result.reason, result.status_code)) + self.edit(data=metadata, engine=self.engine) + result.raise_for_status() + except requests.exceptions.HTTPError as error: + raise MetadataStoreError(error) + + + def edit(self, data: bytes, engine: str): + """ + :param data: + :type data: + :param engine: + :type engine: + :return: + :rtype: + """ + cic_meta_signer = Signer() + signature = cic_meta_signer.sign_digest(data=data) + algorithm = cic_meta_signer.get_operational_key().get('algo') + decoded_data = data.decode('utf-8') + formatted_data = { + 'm': decoded_data, + 's': { + 'engine': engine, + 'algo': algorithm, + 'data': signature, + 'digest': json.loads(data).get('digest'), + } + } + formatted_data = json.dumps(formatted_data).encode('utf-8') + + try: + result = make_request(method='PUT', url=self.url, data=formatted_data, headers=self.headers) + logg.debug(f'signed phone pointer metadata submission status: {result.status_code}.') + result.raise_for_status() + logg.info('phone {} metadata pointer {} set to {}'.format(self.identifier.decode('utf-8'), self.metadata_pointer, decoded_data)) + except requests.exceptions.HTTPError as error: + raise MetadataStoreError(error) + diff --git a/apps/cic-ussd/cic_ussd/metadata/signer.py b/apps/cic-ussd/cic_ussd/metadata/signer.py index 5639fcd5..dc187d29 100644 --- a/apps/cic-ussd/cic_ussd/metadata/signer.py +++ b/apps/cic-ussd/cic_ussd/metadata/signer.py @@ -44,7 +44,7 @@ class Signer: gpg_keys = self.gpg.list_keys() key_algorithm = gpg_keys[0].get('algo') key_id = gpg_keys[0].get("keyid") - logg.info(f'using signing key: {key_id}, algorithm: {key_algorithm}') + logg.debug(f'using signing key: {key_id}, algorithm: {key_algorithm}') return gpg_keys[0] def sign_digest(self, data: bytes): diff --git a/apps/cic-ussd/cic_ussd/metadata/user.py b/apps/cic-ussd/cic_ussd/metadata/user.py index 6a63b1bf..7565350b 100644 --- a/apps/cic-ussd/cic_ussd/metadata/user.py +++ b/apps/cic-ussd/cic_ussd/metadata/user.py @@ -12,30 +12,28 @@ from cic_ussd.chain import Chain from cic_ussd.metadata import make_request from cic_ussd.metadata.signer import Signer from cic_ussd.redis import cache_data +from cic_ussd.error import MetadataStoreError +from .base import Metadata logg = logging.getLogger() -class UserMetadata: - """ - :cvar base_url: - :type base_url: - """ - base_url = None +class UserMetadata(Metadata): + def __init__(self, identifier: bytes): """ :param identifier: :type identifier: """ - self. headers = { + self.headers = { 'X-CIC-AUTOMERGE': 'server', 'Content-Type': 'application/json' } self.identifier = identifier self.metadata_pointer = generate_metadata_pointer( identifier=self.identifier, - cic_type='cic.person' + cic_type=':cic.person' ) if self.base_url: self.url = os.path.join(self.base_url, self.metadata_pointer) @@ -49,7 +47,7 @@ class UserMetadata: logg.info(f'Get sign material response status: {result.status_code}') result.raise_for_status() except requests.exceptions.HTTPError as error: - raise RuntimeError(error) + raise MetadataStoreError(error) def edit(self, data: bytes, engine: str): """ @@ -76,10 +74,10 @@ class UserMetadata: try: result = make_request(method='PUT', url=self.url, data=formatted_data, headers=self.headers) - logg.info(f'Signed content submission status: {result.status_code}.') + logg.debug(f'signed user metadata submission status: {result.status_code}.') result.raise_for_status() except requests.exceptions.HTTPError as error: - raise RuntimeError(error) + raise MetadataStoreError(error) def query(self): result = make_request(method='GET', url=self.url) @@ -99,4 +97,4 @@ class UserMetadata: logg.info('The data is not available and might need to be added.') result.raise_for_status() except requests.exceptions.HTTPError as error: - raise RuntimeError(error) + raise MetadataNotFoundError(error) diff --git a/apps/cic-ussd/cic_ussd/processor.py b/apps/cic-ussd/cic_ussd/processor.py index 5dbf7b7c..413ee0e0 100644 --- a/apps/cic-ussd/cic_ussd/processor.py +++ b/apps/cic-ussd/cic_ussd/processor.py @@ -15,7 +15,7 @@ from cic_ussd.balance import BalanceManager, compute_operational_balance, get_ca from cic_ussd.chain import Chain from cic_ussd.db.models.user import AccountStatus, User from cic_ussd.db.models.ussd_session import UssdSession -from cic_ussd.error import UserMetadataNotFoundError +from cic_ussd.error import MetadataNotFoundError from cic_ussd.menu.ussd_menu import UssdMenu from cic_ussd.metadata import blockchain_address_to_metadata_pointer from cic_ussd.phone_number import get_user_by_phone_number @@ -235,7 +235,7 @@ def process_display_user_metadata(user: User, display_key: str): products=products ) else: - raise UserMetadataNotFoundError(f'Expected user metadata but found none in cache for key: {user.blockchain_address}') + raise MetadataNotFoundError(f'Expected user metadata but found none in cache for key: {user.blockchain_address}') def process_account_statement(user: User, display_key: str, ussd_session: dict): diff --git a/apps/cic-ussd/cic_ussd/runnable/server.py b/apps/cic-ussd/cic_ussd/runnable/server.py index 36942c0f..e969d619 100644 --- a/apps/cic-ussd/cic_ussd/runnable/server.py +++ b/apps/cic-ussd/cic_ussd/runnable/server.py @@ -23,10 +23,11 @@ from cic_ussd.encoder import PasswordEncoder from cic_ussd.files.local_files import create_local_file_data_stores, json_file_parser from cic_ussd.menu.ussd_menu import UssdMenu from cic_ussd.metadata.signer import Signer -from cic_ussd.metadata.user import UserMetadata +from cic_ussd.metadata.base import Metadata from cic_ussd.operations import (define_response_with_content, process_menu_interaction_requests, define_multilingual_responses) +from cic_ussd.phone_number import process_phone_number from cic_ussd.redis import InMemoryStore from cic_ussd.requests import (get_request_endpoint, get_request_method, @@ -64,7 +65,6 @@ config.censor('PASSWORD', 'DATABASE') # define log levels if args.vv: logging.getLogger().setLevel(logging.DEBUG) - logging.getLogger('sqlalchemy.engine').setLevel(logging.DEBUG) elif args.v: logging.getLogger().setLevel(logging.INFO) @@ -86,7 +86,7 @@ UssdMenu.ussd_menu_db = ussd_menu_db # set up db data_source_name = dsn_from_config(config) -SessionBase.connect(data_source_name=data_source_name) +SessionBase.connect(data_source_name, pool_size=int(config.get('DATABASE_POOL_SIZE')), debug=config.true('DATABASE_DEBUG')) # create session for the life time of http request SessionBase.session = SessionBase.create_session() @@ -99,7 +99,7 @@ InMemoryStore.cache = redis.StrictRedis(host=config.get('REDIS_HOSTNAME'), InMemoryUssdSession.redis_cache = InMemoryStore.cache # define metadata URL -UserMetadata.base_url = config.get('CIC_META_URL') +Metadata.base_url = config.get('CIC_META_URL') # define signer values export_dir = config.get('PGP_EXPORT_DIR') @@ -151,6 +151,10 @@ def application(env, start_response): external_session_id = post_data.get('sessionId') user_input = post_data.get('text') + # add validation for phone number + if phone_number: + phone_number = process_phone_number(phone_number=phone_number, region=config.get('PHONE_NUMBER_REGION')) + # validate ip address if not check_ip(config=config, env=env): start_response('403 Sneaky, sneaky', errors_headers) @@ -174,8 +178,10 @@ def application(env, start_response): # validate phone number if not validate_phone_number(phone_number): + logg.error('invalid phone number {}'.format(phone_number)) start_response('400 Invalid phone number format', errors_headers) return [] + logg.debug('session {} started for {}'.format(external_session_id, phone_number)) # handle menu interaction requests chain_str = chain_spec.__str__() diff --git a/apps/cic-ussd/cic_ussd/runnable/tasker.py b/apps/cic-ussd/cic_ussd/runnable/tasker.py index 0c341e61..ac39e06f 100644 --- a/apps/cic-ussd/cic_ussd/runnable/tasker.py +++ b/apps/cic-ussd/cic_ussd/runnable/tasker.py @@ -13,13 +13,14 @@ from confini import Config from cic_ussd.db import dsn_from_config from cic_ussd.db.models.base import SessionBase from cic_ussd.metadata.signer import Signer -from cic_ussd.metadata.user import UserMetadata +from cic_ussd.metadata.base import Metadata from cic_ussd.redis import InMemoryStore from cic_ussd.session.ussd_session import UssdSession as InMemoryUssdSession from cic_ussd.validator import validate_presence logging.basicConfig(level=logging.WARNING) logg = logging.getLogger() +logging.getLogger('gnupg').setLevel(logging.WARNING) config_directory = '/usr/local/etc/cic-ussd/' @@ -47,7 +48,7 @@ logg.debug(config) # connect to database data_source_name = dsn_from_config(config) -SessionBase.connect(data_source_name=data_source_name) +SessionBase.connect(data_source_name, pool_size=int(config.get('DATABASE_POOL_SIZE')), debug=config.true('DATABASE_DEBUG')) # verify database connection with minimal sanity query session = SessionBase.create_session() @@ -63,7 +64,7 @@ InMemoryStore.cache = redis.StrictRedis(host=config.get('REDIS_HOSTNAME'), InMemoryUssdSession.redis_cache = InMemoryStore.cache # define metadata URL -UserMetadata.base_url = config.get('CIC_META_URL') +Metadata.base_url = config.get('CIC_META_URL') # define signer values export_dir = config.get('PGP_EXPORT_DIR') diff --git a/apps/cic-ussd/cic_ussd/state_machine/logic/user.py b/apps/cic-ussd/cic_ussd/state_machine/logic/user.py index e85a26e6..5849bd77 100644 --- a/apps/cic-ussd/cic_ussd/state_machine/logic/user.py +++ b/apps/cic-ussd/cic_ussd/state_machine/logic/user.py @@ -11,7 +11,7 @@ from cic_types.models.person import generate_vcard_from_contact_data, manage_ide # local imports from cic_ussd.chain import Chain from cic_ussd.db.models.user import User -from cic_ussd.error import UserMetadataNotFoundError +from cic_ussd.error import MetadataNotFoundError from cic_ussd.metadata import blockchain_address_to_metadata_pointer from cic_ussd.operations import save_to_in_memory_ussd_session_data from cic_ussd.redis import get_cached_data @@ -181,7 +181,7 @@ def edit_user_metadata_attribute(state_machine_data: Tuple[str, dict, User]): user_metadata = get_cached_data(key=key) if not user_metadata: - raise UserMetadataNotFoundError(f'Expected user metadata but found none in cache for key: {blockchain_address}') + raise MetadataNotFoundError(f'Expected user metadata but found none in cache for key: {blockchain_address}') given_name = ussd_session.get('session_data').get('given_name') family_name = ussd_session.get('session_data').get('family_name') diff --git a/apps/cic-ussd/cic_ussd/tasks/base.py b/apps/cic-ussd/cic_ussd/tasks/base.py index 4b5e535b..0f9a7438 100644 --- a/apps/cic-ussd/cic_ussd/tasks/base.py +++ b/apps/cic-ussd/cic_ussd/tasks/base.py @@ -5,9 +5,24 @@ import celery import sqlalchemy # local imports +from cic_ussd.error import MetadataStoreError +from cic_ussd.db.models.base import SessionBase -class CriticalTask(celery.Task): +class BaseTask(celery.Task): + + session_func = SessionBase.create_session + + def create_session(self): + return BaseTask.session_func() + + + def log_banner(self): + logg.debug('task {} root uuid {}'.format(self.__class__.__name__, self.request.root_id)) + return + + +class CriticalTask(BaseTask): retry_jitter = True retry_backoff = True retry_backoff_max = 8 @@ -17,4 +32,11 @@ class CriticalSQLAlchemyTask(CriticalTask): autoretry_for = ( sqlalchemy.exc.DatabaseError, sqlalchemy.exc.TimeoutError, + sqlalchemy.exc.ResourceClosedError, + ) + + +class CriticalMetadataTask(CriticalTask): + autoretry_for = ( + MetadataStoreError, ) diff --git a/apps/cic-ussd/cic_ussd/tasks/callback_handler.py b/apps/cic-ussd/cic_ussd/tasks/callback_handler.py index 0b569d04..2c247339 100644 --- a/apps/cic-ussd/cic_ussd/tasks/callback_handler.py +++ b/apps/cic-ussd/cic_ussd/tasks/callback_handler.py @@ -53,6 +53,18 @@ def process_account_creation_callback(self, result: str, url: str, status_code: session.add(user) session.commit() session.close() + + queue = self.request.delivery_info.get('routing_key') + s = celery.signature( + 'cic_ussd.tasks.metadata.add_phone_pointer', + [ + result, + phone_number, + 'pgp', + ], + queue=queue, + ) + s.apply_async() # expire cache cache.expire(task_id, timedelta(seconds=180)) @@ -65,6 +77,8 @@ def process_account_creation_callback(self, result: str, url: str, status_code: session.close() raise ActionDataNotFoundError(f'Account creation task: {task_id}, returned unexpected response: {status_code}') + session.close() + @celery_app.task def process_incoming_transfer_callback(result: dict, param: str, status_code: int): @@ -118,6 +132,7 @@ def process_incoming_transfer_callback(result: dict, param: str, status_code: in session.close() raise ValueError(f'Unexpected status code: {status_code}.') + session.close() @celery_app.task def process_balances_callback(result: list, param: str, status_code: int): @@ -161,7 +176,6 @@ def define_transaction_action_tag( def process_statement_callback(result, param: str, status_code: int): if status_code == 0: # create session - session = SessionBase.create_session() processed_transactions = [] # process transaction data to cache @@ -174,6 +188,7 @@ def process_statement_callback(result, param: str, status_code: int): if '0x0000000000000000000000000000000000000000' in source_token: pass else: + session = SessionBase.create_session() # describe a processed transaction processed_transaction = {} @@ -202,6 +217,8 @@ def process_statement_callback(result, param: str, status_code: int): else: logg.warning(f'Tx with recipient not found in cic-ussd') + session.close() + # add transaction values processed_transaction['to_value'] = from_wei(value=transaction.get('to_value')).__str__() processed_transaction['from_value'] = from_wei(value=transaction.get('from_value')).__str__() diff --git a/apps/cic-ussd/cic_ussd/tasks/metadata.py b/apps/cic-ussd/cic_ussd/tasks/metadata.py index 4410148a..095613fc 100644 --- a/apps/cic-ussd/cic_ussd/tasks/metadata.py +++ b/apps/cic-ussd/cic_ussd/tasks/metadata.py @@ -2,15 +2,18 @@ import json import logging -# third-party imports +# external imports import celery +from hexathon import strip_0x # local imports from cic_ussd.metadata import blockchain_address_to_metadata_pointer from cic_ussd.metadata.user import UserMetadata +from cic_ussd.metadata.phone import PhonePointerMetadata +from cic_ussd.tasks.base import CriticalMetadataTask celery_app = celery.current_app -logg = logging.getLogger() +logg = logging.getLogger().getChild(__name__) @celery_app.task @@ -46,3 +49,10 @@ def edit_user_metadata(blockchain_address: str, data: bytes, engine: str): identifier = blockchain_address_to_metadata_pointer(blockchain_address=blockchain_address) user_metadata_client = UserMetadata(identifier=identifier) user_metadata_client.edit(data=data, engine=engine) + + +@celery_app.task(bind=True, base=CriticalMetadataTask) +def add_phone_pointer(self, blockchain_address: str, phone: str, engine: str): + stripped_address = strip_0x(blockchain_address) + phone_metadata_client = PhonePointerMetadata(identifier=phone.encode('utf-8'), engine=engine) + phone_metadata_client.create(data=stripped_address) diff --git a/apps/cic-ussd/cic_ussd/tasks/ussd_session.py b/apps/cic-ussd/cic_ussd/tasks/ussd_session.py index 85f388e2..dac199f2 100644 --- a/apps/cic-ussd/cic_ussd/tasks/ussd_session.py +++ b/apps/cic-ussd/cic_ussd/tasks/ussd_session.py @@ -70,3 +70,4 @@ def persist_session_to_db(external_session_id: str): session.close() raise SessionNotFoundError('Session does not exist!') + session.close() diff --git a/apps/cic-ussd/cic_ussd/validator.py b/apps/cic-ussd/cic_ussd/validator.py index 26c89242..1fc10065 100644 --- a/apps/cic-ussd/cic_ussd/validator.py +++ b/apps/cic-ussd/cic_ussd/validator.py @@ -2,6 +2,7 @@ import logging import os import re +import ipaddress # third-party imports from confini import Config @@ -21,7 +22,14 @@ def check_ip(config: Config, env: dict): :return: Request IP validity :rtype: boolean """ - return env.get('REMOTE_ADDR') == config.get('APP_ALLOWED_IP') + # TODO: do once at boot time + actual_ip = ipaddress.ip_network(env.get('REMOTE_ADDR') + '/32') + for allowed_net_src in config.get('APP_ALLOWED_IP').split(','): + allowed_net = ipaddress.ip_network(allowed_net_src) + if actual_ip.subnet_of(allowed_net): + return True + + return False def check_request_content_length(config: Config, env: dict): diff --git a/apps/cic-ussd/docker/Dockerfile b/apps/cic-ussd/docker/Dockerfile index 8257348e..d49058e0 100644 --- a/apps/cic-ussd/docker/Dockerfile +++ b/apps/cic-ussd/docker/Dockerfile @@ -51,4 +51,4 @@ RUN cd cic-ussd && \ COPY cic-ussd/.config/ /usr/local/etc/cic-ussd/ COPY cic-ussd/cic_ussd/db/migrations/ /usr/local/share/cic-ussd/alembic -WORKDIR /root \ No newline at end of file +WORKDIR /root diff --git a/apps/cic-ussd/docker/start_tasker.sh b/apps/cic-ussd/docker/start_tasker.sh index bd588f28..37f32597 100644 --- a/apps/cic-ussd/docker/start_tasker.sh +++ b/apps/cic-ussd/docker/start_tasker.sh @@ -2,4 +2,4 @@ . /root/db.sh -/usr/local/bin/cic-ussd-tasker -vv "$@" \ No newline at end of file +/usr/local/bin/cic-ussd-tasker $@ diff --git a/apps/cic-ussd/docker/start_uwsgi.sh b/apps/cic-ussd/docker/start_uwsgi.sh index ac5261cb..ff3271ec 100644 --- a/apps/cic-ussd/docker/start_uwsgi.sh +++ b/apps/cic-ussd/docker/start_uwsgi.sh @@ -2,4 +2,6 @@ . /root/db.sh -/usr/local/bin/uwsgi --wsgi-file /usr/local/lib/python3.8/site-packages/cic_ussd/runnable/server.py --http :9000 --pyargv "-vv" +server_port=${SERVER_PORT:-9000} + +/usr/local/bin/uwsgi --wsgi-file /usr/local/lib/python3.8/site-packages/cic_ussd/runnable/server.py --http :$server_port --pyargv "$@" diff --git a/apps/cic-ussd/requirements.txt b/apps/cic-ussd/requirements.txt index 15ecc96c..7738c9b6 100644 --- a/apps/cic-ussd/requirements.txt +++ b/apps/cic-ussd/requirements.txt @@ -1,4 +1,4 @@ -cic_base[full_graph]~=0.1.2a58 -cic-eth~=0.11.0a4 +cic_base[full_graph]~=0.1.2a61 +cic-eth~=0.11.0b1 cic-notify~=0.4.0a3 cic-types~=0.1.0a10 diff --git a/apps/contract-migration/scripts/README.md b/apps/contract-migration/scripts/README.md index cdefe7f5..01861ac5 100644 --- a/apps/contract-migration/scripts/README.md +++ b/apps/contract-migration/scripts/README.md @@ -2,88 +2,234 @@ This folder contains tools to generate and import test data. -## DATA CREATION +## OVERVIEW -Does not need the cluster to run. +Three sets of tools are available, sorted by respective subdirectories. -Vanilla: +* **eth**: Import using sovereign wallets. +* **cic_eth**: Import using the `cic_eth` custodial engine. +* **cic_ussd**: Import using the `cic_ussd` interface (backed by `cic_eth`) + +Each of the modules include two main scripts: + +* **import_users.py**: Registers all created accounts in the network +* **import_balance.py**: Transfer an opening balance using an external keystore wallet + +The balance script will sync with the blockchain, processing transactions and triggering actions when it finds. In its current version it does not keep track of any other state, so it will run indefinitly and needs You the Human to decide when it has done what it needs to do. + + +In addition the following common tools are available: + +* **create_import_users.py**: User creation script +* **verify.py**: Import verification script +* **cic_meta**: Metadata imports + + +## REQUIREMENTS + +A virtual environment for the python scripts is recommended. We know it works with `python 3.8.x`. Let us know if you run it successfully with other minor versions. + +``` +python3 -m venv .venv +source .venv/bin/activate +``` + +Install all requirements from the `requirements.txt` file: + +`pip install --extra-index-url https://pip.grassrootseconomics.net:8433 -r requirements.txt` + + +If you are importing metadata, also do ye olde: + +`npm install` + + +## HOW TO USE + +### Step 1 - Data creation + +Before running any of the imports, the user data to import has to be generated and saved to disk. + +The script does not need any services to run. + +Vanilla version: `python create_import_users.py [--dir ] ` -If you want to use the `import_balance.py` script to add to the user's balance from an external address, add: +If you want to use a `import_balance.py` script to add to the user's balance from an external address, use: `python create_import_users.py --gift-threshold [--dir ] ` -## IMPORT +### Step 2 - Services -Make sure the following is running in the cluster: - * eth - * postgres - * redis - * cic-meta-server +Unless you know what you are doing, start with a clean slate, and execute (in the repository root): + +`docker-compose down -v` + +Then go through, in sequence: + +#### Base requirements + +If you are importing using `eth` and _not_ importing metadata, then the only service you need running in the cluster is: +* eth + +In all other cases you will _also_ need: +* postgres +* redis -If using the _custodial_ alternative for user imports, also run: - * cic-eth-tasker - * cic-eth-dispatcher - * cic-eth-tracker +#### EVM provisions + +This step is needed in *all* cases. + +`RUN_MASK=1 docker-compose up contract-migration` + +After this step is run, you can find top-level ethereum addresses (like the cic registry address, which you will need below) in `/service-configs/.env` -You will want to run these in sequence: +#### Custodial provisions + +This step is _only_ needed if you are importing using `cic_eth` or `cic_ussd` + +`RUN_MASK=2 docker-compose up contract-migration` -## 1. Metadata +#### Custodial services -`node import_meta.js ` +If importing using `cic_eth` or `cic_ussd` also run: +* cic-eth-tasker +* cic-eth-dispatcher +* cic-eth-tracker +* cic-eth-retrier + +If importing using `cic_ussd` also run: +* cic-ussd-tasker +* cic-ussd-server +* cic-notify-tasker + +If metadata is to be imported, also run: +* cic-meta-server + + + +### Step 3 - User imports + +If you did not change the docker-compose setup, your `eth_provider` the you need for the commands below will be `http://localhost:63545`. + +Only run _one_ of the alternatives. + +The keystore file used for transferring external opening balances tracker is relative to the directory you found this README in. Of course you can use a different wallet, but then you will have to provide it with tokens yourself (hint: `../reset.sh`) + +All external balance transactions are saved in raw wire format in `/txs`, with transaction hash as file name. + + + +#### Alternative 1 - Sovereign wallet import - `eth` + + +First, make a note of the **block height** before running anything. + +To import, run to _completion_: + +`python eth/import_users.py -v -c config -p -r -y ../keystore/UTC--2021-01-08T17-18-44.521011372Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c ` + +After the script completes, keystore files for all generated accouts will be found in `/keystore`, all with `foo` as password (would set it empty, but believe it or not some interfaces out there won't work unless you have one). + +Then run: + +`python eth/import_balance.py -v -c config -r -p --offset -y ../keystore/UTC--2021-01-08T17-18-44.521011372Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c ` + + + +#### Alternative 2 - Custodial engine import - `cic_eth` + +Run in sequence, in first terminal: + +`python cic_eth/import_balance.py -v -c config -p -r -y ../keystore/UTC--2021-01-08T17-18-44.521011372Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c --head out` + +In another terminal: + +`python cic_eth/import_users.py -v -c config --redis-host-callback out` + +The `redis_hostname_in_docker` value is the hostname required to reach the redis server from within the docker cluster, and should be `redis` if you left the docker-compose unchanged. The `import_users` script will receive the address of each newly created custodial account on a redis subscription fed by a callback task in the `cic_eth` account creation task chain. + + +#### Alternative 3 - USSD import - `cic_ussd` + +If you have previously run the `cic_ussd` import incompletely, it could be a good idea to purge the queue. If you have left docker-compose unchanged, `redis_url` should be `redis://localhost:63379`. + +`celery -A cic_ussd.import_task purge -Q cic-import-ussd --broker ` + +Then, in sequence, run in first terminal: + +`python cic_eth/import_balance.py -v -c config -p -r -y ../keystore/UTC--2021-01-08T17-18-44.521011372Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c out` + +In second terminal: + +`python cic_ussd/import_users.py -v -c config out` + +The balance script is a celery task worker, and will not exit by itself in its current version. However, after it's done doing its job, you will find "reached nonce ... exiting" among the last lines of the log. + +The connection parameters for the `cic-ussd-server` is currently _hardcoded_ in the `import_users.py` script file. + + +### Step 4 - Metadata import (optional) + +The metadata import scripts can be run at any time after step 1 has been completed. + + +#### Importing user metadata + +To import the main user metadata structs, run: + +`node cic_meta/import_meta.js ` Monitors a folder for output from the `import_users.py` script, adding the metadata found to the `cic-meta` service. - -## 2. Balances - -(Only if you used the `--gift-threshold` option above) - -`python -c config -i -r -p --head -y ../keystore/UTC--2021-01-08T17-18-44.521011372Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c ` - -This will monitor new mined blocks and send balances to the newly created accounts. +If _number of users_ is omitted the script will run until manually interrupted. -### 3. Users +#### Importing phone pointer -Only use **one** of the following +`node cic_meta/import_meta_phone.js ` -#### Custodial +If you imported using `cic_ussd`, the phone pointer is _already added_ and this script will do nothing. -This alternative generates accounts using the `cic-eth` custodial engine -Without any modifications to the cluster and config files: +### Step 5 - Verify -`python import_users.py -c config --redis-host-callback redis ` +`python verify.py -v -c config -r -p ` -** A note on the The callback**: The script uses a redis callback to retrieve the newly generated custodial address. This is the redis server _from the perspective of the cic-eth component_. +Included checks: +* Private key is in cic-eth keystore +* Address is in accounts index +* Address has gas balance +* Address has triggered the token faucet +* Address has token balance matching the gift threshold +* Personal metadata can be retrieved and has exact match +* Phone pointer metadata can be retrieved and matches address +* USSD menu response is initial state after registration -#### Sovereign +Checks can be selectively included and excluded. See `--help` for details. -This alternative generates keystore files, while registering corresponding addresses in the accounts registry directly - -`python import_sovereign_users.py -c config -i -r -p -y ../keystore/UTC--2021-01-08T17-18-44.521011372Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c ` - -A `keystore` sub-directory in the data path is created, with ethereum keystore files for all generated private keys. Passphrase is set to empty string for all of them. - -## VERIFY - -`python verify.py -c config -i -r -p ` - -Checks - * Private key is in cic-eth keystore - * Address is in accounts index - * Address has balance matching the gift threshold - * Metadata can be retrieved and has exact match +Will output one line for each check, with name of check and number of errors found per check. Should exit with code 0 if all input data is found in the respective services. ## KNOWN ISSUES -If the faucet disbursement is set to a non-zero amount, the balances will be off. The verify script needs to be improved to check the faucet amount. +- If the faucet disbursement is set to a non-zero amount, the balances will be off. The verify script needs to be improved to check the faucet amount. + +- When the account callback in `cic_eth` fails, the `cic_eth/import_users.py` script will exit with a cryptic complaint concerning a `None` value. + +- Sovereign import scripts use the same keystore, and running them simultaneously will mess up the transaction nonce sequence. Better would be to use two different keystore wallets so balance and users scripts can be run simultaneously. + +- `pycrypto` and `pycryptodome` _have to be installed in that order_. If you get errors concerning `Crypto.KDF` then uninstall both and re-install in that order. Make sure you use the versions listed in `requirements.txt`. `pycryptodome` is a legacy dependency and will be removed as soon as possible. + +- Sovereign import script is very slow because it's scrypt'ing keystore files for the accounts that it creates. An improvement would be optional and/or asynchronous keyfile generation. + +- Running the balance script should be _optional_ in all cases, but is currently required in the case of `cic_ussd` because it is needed to generate the metadata. An improvement would be moving the task to `import_users.py`, for a different queue than the balance tx handler. + +- `cic_ussd` imports is poorly implemented, and consumes a lot of resources. Therefore it takes a long time to complete. Reducing the amount of polls for the phone pointer would go a long way to improve it. diff --git a/apps/contract-migration/scripts/import_balance.py b/apps/contract-migration/scripts/cic_eth/import_balance.py similarity index 97% rename from apps/contract-migration/scripts/import_balance.py rename to apps/contract-migration/scripts/cic_eth/import_balance.py index 3b708236..618f2421 100644 --- a/apps/contract-migration/scripts/import_balance.py +++ b/apps/contract-migration/scripts/cic_eth/import_balance.py @@ -10,7 +10,7 @@ import hashlib import csv import json -# third-party impotts +# external imports import eth_abi import confini from hexathon import ( @@ -42,7 +42,7 @@ from cic_types.models.person import Person logging.basicConfig(level=logging.WARNING) logg = logging.getLogger() -config_dir = '/usr/local/etc/cic-syncer' +config_dir = './config' argparser = argparse.ArgumentParser(description='daemon that monitors transactions in new blocks') argparser.add_argument('-p', '--provider', dest='p', type=str, help='chain rpc provider address') @@ -162,6 +162,15 @@ class Handler: (tx_hash_hex, o) = self.tx_factory.transfer(self.token_address, signer_address, recipient, balance_full) logg.info('submitting erc20 transfer tx {} for recipient {}'.format(tx_hash_hex, recipient)) r = conn.do(o) + + tx_path = os.path.join( + user_dir, + 'txs', + strip_0x(tx_hash_hex), + ) + f = open(tx_path, 'w') + f.write(strip_0x(o['params'][0])) + f.close() # except TypeError as e: # logg.warning('typerror {}'.format(e)) # pass diff --git a/apps/contract-migration/scripts/import_users.py b/apps/contract-migration/scripts/cic_eth/import_users.py similarity index 85% rename from apps/contract-migration/scripts/import_users.py rename to apps/contract-migration/scripts/cic_eth/import_users.py index acba257f..f5312187 100644 --- a/apps/contract-migration/scripts/import_users.py +++ b/apps/contract-migration/scripts/cic_eth/import_users.py @@ -7,6 +7,7 @@ import argparse import uuid import datetime import time +import phonenumbers from glob import glob # third-party imports @@ -17,7 +18,7 @@ from hexathon import ( add_0x, strip_0x, ) -from chainlib.eth.address import to_checksum +from chainlib.eth.address import to_checksum_address from cic_types.models.person import Person from cic_eth.api.api_task import Api from chainlib.chain import ChainSpec @@ -75,9 +76,15 @@ os.makedirs(user_new_dir) meta_dir = os.path.join(args.user_dir, 'meta') os.makedirs(meta_dir) +phone_dir = os.path.join(args.user_dir, 'phone') +os.makedirs(os.path.join(phone_dir, 'meta')) + user_old_dir = os.path.join(args.user_dir, 'old') os.stat(user_old_dir) +txs_dir = os.path.join(args.user_dir, 'txs') +os.makedirs(txs_dir) + chain_spec = ChainSpec.from_chain_str(config.get('CIC_CHAIN_SPEC')) chain_str = str(chain_spec) @@ -165,12 +172,32 @@ if __name__ == '__main__': f.write(json.dumps(o)) f.close() - #old_address = to_checksum(add_0x(y[:len(y)-5])) #fi.write('{},{}\n'.format(new_address, old_address)) meta_key = generate_metadata_pointer(bytes.fromhex(new_address_clean), 'cic.person') meta_filepath = os.path.join(meta_dir, '{}.json'.format(new_address_clean.upper())) os.symlink(os.path.realpath(filepath), meta_filepath) + phone_object = phonenumbers.parse(u.tel) + phone = phonenumbers.format_number(phone_object, phonenumbers.PhoneNumberFormat.E164) + meta_phone_key = generate_metadata_pointer(phone.encode('utf-8'), ':cic.phone') + meta_phone_filepath = os.path.join(phone_dir, 'meta', meta_phone_key) + + filepath = os.path.join( + phone_dir, + 'new', + meta_phone_key[:2].upper(), + meta_phone_key[2:4].upper(), + meta_phone_key.upper(), + ) + os.makedirs(os.path.dirname(filepath), exist_ok=True) + + f = open(filepath, 'w') + f.write(to_checksum_address(new_address_clean)) + f.close() + + os.symlink(os.path.realpath(filepath), meta_phone_filepath) + + i += 1 sys.stdout.write('imported {} {}'.format(i, u).ljust(200) + "\r") diff --git a/apps/contract-migration/scripts/cmd/__init__.py b/apps/contract-migration/scripts/cic_eth/traffic/cmd/__init__.py similarity index 100% rename from apps/contract-migration/scripts/cmd/__init__.py rename to apps/contract-migration/scripts/cic_eth/traffic/cmd/__init__.py diff --git a/apps/contract-migration/scripts/cmd/traffic.py b/apps/contract-migration/scripts/cic_eth/traffic/cmd/traffic.py similarity index 100% rename from apps/contract-migration/scripts/cmd/traffic.py rename to apps/contract-migration/scripts/cic_eth/traffic/cmd/traffic.py diff --git a/apps/contract-migration/scripts/common/__init__.py b/apps/contract-migration/scripts/cic_eth/traffic/common/__init__.py similarity index 100% rename from apps/contract-migration/scripts/common/__init__.py rename to apps/contract-migration/scripts/cic_eth/traffic/common/__init__.py diff --git a/apps/contract-migration/scripts/common/argparse.py b/apps/contract-migration/scripts/cic_eth/traffic/common/argparse.py similarity index 100% rename from apps/contract-migration/scripts/common/argparse.py rename to apps/contract-migration/scripts/cic_eth/traffic/common/argparse.py diff --git a/apps/contract-migration/scripts/common/config.py b/apps/contract-migration/scripts/cic_eth/traffic/common/config.py similarity index 100% rename from apps/contract-migration/scripts/common/config.py rename to apps/contract-migration/scripts/cic_eth/traffic/common/config.py diff --git a/apps/contract-migration/scripts/common/log.py b/apps/contract-migration/scripts/cic_eth/traffic/common/log.py similarity index 100% rename from apps/contract-migration/scripts/common/log.py rename to apps/contract-migration/scripts/cic_eth/traffic/common/log.py diff --git a/apps/contract-migration/scripts/common/registry.py b/apps/contract-migration/scripts/cic_eth/traffic/common/registry.py similarity index 100% rename from apps/contract-migration/scripts/common/registry.py rename to apps/contract-migration/scripts/cic_eth/traffic/common/registry.py diff --git a/apps/contract-migration/scripts/common/rpc.py b/apps/contract-migration/scripts/cic_eth/traffic/common/rpc.py similarity index 100% rename from apps/contract-migration/scripts/common/rpc.py rename to apps/contract-migration/scripts/cic_eth/traffic/common/rpc.py diff --git a/apps/contract-migration/scripts/common/signer.py b/apps/contract-migration/scripts/cic_eth/traffic/common/signer.py similarity index 100% rename from apps/contract-migration/scripts/common/signer.py rename to apps/contract-migration/scripts/cic_eth/traffic/common/signer.py diff --git a/apps/contract-migration/scripts/local/account.py b/apps/contract-migration/scripts/cic_eth/traffic/local/account.py similarity index 100% rename from apps/contract-migration/scripts/local/account.py rename to apps/contract-migration/scripts/cic_eth/traffic/local/account.py diff --git a/apps/contract-migration/scripts/local/noop.py b/apps/contract-migration/scripts/cic_eth/traffic/local/noop.py similarity index 100% rename from apps/contract-migration/scripts/local/noop.py rename to apps/contract-migration/scripts/cic_eth/traffic/local/noop.py diff --git a/apps/contract-migration/scripts/local/transfer.py b/apps/contract-migration/scripts/cic_eth/traffic/local/transfer.py similarity index 100% rename from apps/contract-migration/scripts/local/transfer.py rename to apps/contract-migration/scripts/cic_eth/traffic/local/transfer.py diff --git a/apps/contract-migration/scripts/traffic.py b/apps/contract-migration/scripts/cic_eth/traffic/traffic.py similarity index 100% rename from apps/contract-migration/scripts/traffic.py rename to apps/contract-migration/scripts/cic_eth/traffic/traffic.py diff --git a/apps/contract-migration/scripts/import_meta.js b/apps/contract-migration/scripts/cic_meta/import_meta.js similarity index 99% rename from apps/contract-migration/scripts/import_meta.js rename to apps/contract-migration/scripts/cic_meta/import_meta.js index 56c754f3..28cf5f7d 100644 --- a/apps/contract-migration/scripts/import_meta.js +++ b/apps/contract-migration/scripts/cic_meta/import_meta.js @@ -101,6 +101,7 @@ function importMeta(keystore) { const file = files[i]; if (file.substr(-5) != '.json') { console.debug('skipping file', file); + continue; } const filePath = path.join(workDir, file); doOne(keystore, filePath); diff --git a/apps/contract-migration/scripts/cic_meta/import_meta_phone.js b/apps/contract-migration/scripts/cic_meta/import_meta_phone.js new file mode 100644 index 00000000..9c82afe5 --- /dev/null +++ b/apps/contract-migration/scripts/cic_meta/import_meta_phone.js @@ -0,0 +1,134 @@ +const fs = require('fs'); +const path = require('path'); +const http = require('http'); + +const cic = require('cic-client-meta'); +const vcfp = require('vcard-parser'); + +//const conf = JSON.parse(fs.readFileSync('./cic.conf')); + +const config = new cic.Config('./config'); +config.process(); +console.log(config); + + +function sendit(uid, envelope) { + const d = envelope.toJSON(); + + const contentLength = (new TextEncoder().encode(d)).length; + const opts = { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': contentLength, + 'X-CIC-AUTOMERGE': 'client', + + }, + }; + let url = config.get('META_URL'); + url = url.replace(new RegExp('^(.+://[^/]+)/*$'), '$1/'); + console.log('posting to url: ' + url + uid); + const req = http.request(url + uid, opts, (res) => { + res.on('data', process.stdout.write); + res.on('end', () => { + console.log('result', res.statusCode, res.headers); + }); + }); + if (!req.write(d)) { + console.error('foo', d); + process.exit(1); + } + req.end(); +} + +function doOne(keystore, filePath, address) { + const signer = new cic.PGPSigner(keystore); + + const j = JSON.parse(fs.readFileSync(filePath).toString()); + const b = Buffer.from(j['vcard'], 'base64'); + const s = b.toString(); + const o = vcfp.parse(s); + const phone = o.tel[0].value; + + cic.Phone.toKey(phone).then((uid) => { + const o = fs.readFileSync(filePath, 'utf-8'); + + const s = new cic.Syncable(uid, o); + s.setSigner(signer); + s.onwrap = (env) => { + sendit(uid, env); + }; + s.sign(); + }); +} + +const privateKeyPath = path.join(config.get('PGP_EXPORTS_DIR'), config.get('PGP_PRIVATE_KEY_FILE')); +const publicKeyPath = path.join(config.get('PGP_EXPORTS_DIR'), config.get('PGP_PRIVATE_KEY_FILE')); +pk = fs.readFileSync(privateKeyPath); +pubk = fs.readFileSync(publicKeyPath); + +new cic.PGPKeyStore( + config.get('PGP_PASSPHRASE'), + pk, + pubk, + undefined, + undefined, + importMetaPhone, +); + +const batchSize = 16; +const batchDelay = 1000; +const total = parseInt(process.argv[3]); +const dataDir = process.argv[2]; +const workDir = path.join(dataDir, 'phone/meta'); +const userDir = path.join(dataDir, 'new'); +let count = 0; +let batchCount = 0; + + +function importMetaPhone(keystore) { + let err; + let files; + + try { + err, files = fs.readdirSync(workDir); + } catch { + console.error('source directory not yet ready', workDir); + setTimeout(importMetaPhone, batchDelay, keystore); + return; + } + let limit = batchSize; + if (files.length < limit) { + limit = files.length; + } + for (let i = 0; i < limit; i++) { + const file = files[i]; + if (file.substr(0) == '.') { + console.debug('skipping file', file); + } + const filePath = path.join(workDir, file); + + const address = fs.readFileSync(filePath).toString().substring(2).toUpperCase(); + const metaFilePath = path.join( + userDir, + address.substring(0, 2), + address.substring(2, 4), + address + '.json', + ); + + doOne(keystore, metaFilePath, address); + fs.unlinkSync(filePath); + count++; + batchCount++; + if (batchCount == batchSize) { + console.debug('reached batch size, breathing'); + batchCount=0; + setTimeout(importMeta, batchDelay, keystore); + return; + } + } + if (count == total) { + return; + } + setTimeout(importMetaPhone, 100, keystore); +} diff --git a/apps/contract-migration/scripts/cic_ussd/import_balance.py b/apps/contract-migration/scripts/cic_ussd/import_balance.py new file mode 100644 index 00000000..35430e95 --- /dev/null +++ b/apps/contract-migration/scripts/cic_ussd/import_balance.py @@ -0,0 +1,157 @@ +# standard imports +import os +import sys +import logging +import argparse +import hashlib +import redis +import celery + +# external imports +import confini +from chainlib.eth.connection import EthHTTPConnection +from chainlib.chain import ChainSpec +from hexathon import ( + strip_0x, + add_0x, + ) +from chainlib.eth.address import to_checksum_address +from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer +from crypto_dev_signer.keystore.dict import DictKeystore +from cic_types.models.person import Person + +# local imports +from import_util import BalanceProcessor +from import_task import * + +logging.basicConfig(level=logging.WARNING) +logg = logging.getLogger() + +config_dir = './config' + +argparser = argparse.ArgumentParser(description='daemon that monitors transactions in new blocks') +argparser.add_argument('-p', '--provider', dest='p', type=str, help='chain rpc provider address') +argparser.add_argument('-y', '--key-file', dest='y', type=str, help='Ethereum keystore file to use for signing') +argparser.add_argument('-c', type=str, default=config_dir, help='config root to use') +argparser.add_argument('--old-chain-spec', type=str, dest='old_chain_spec', default='evm:oldchain:1', help='chain spec') +argparser.add_argument('-i', '--chain-spec', type=str, dest='i', help='chain spec') +argparser.add_argument('-r', '--registry-address', type=str, dest='r', help='CIC Registry address') +argparser.add_argument('--meta-host', dest='meta_host', type=str, help='metadata server host') +argparser.add_argument('--meta-port', dest='meta_port', type=int, help='metadata server host') +argparser.add_argument('--redis-host', dest='redis_host', type=str, help='redis host to use for task submission') +argparser.add_argument('--redis-port', dest='redis_port', type=int, help='redis host to use for task submission') +argparser.add_argument('--redis-db', dest='redis_db', type=int, help='redis db to use for task submission and callback') +argparser.add_argument('--token-symbol', default='SRF', type=str, dest='token_symbol', help='Token symbol to use for trnsactions') +argparser.add_argument('--head', action='store_true', help='start at current block height (overrides --offset)') +argparser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration') +argparser.add_argument('-q', type=str, default='cic-eth', help='celery queue to submit transaction tasks to') +argparser.add_argument('--offset', type=int, default=0, help='block offset to start syncer from') +argparser.add_argument('-v', help='be verbose', action='store_true') +argparser.add_argument('-vv', help='be more verbose', action='store_true') +argparser.add_argument('user_dir', default='out', type=str, help='user export directory') +args = argparser.parse_args(sys.argv[1:]) + +if args.v == True: + logging.getLogger().setLevel(logging.INFO) +elif args.vv == True: + logging.getLogger().setLevel(logging.DEBUG) + +config_dir = os.path.join(args.c) +os.makedirs(config_dir, 0o777, True) +config = confini.Config(config_dir, args.env_prefix) +config.process() +# override args +args_override = { + 'CIC_CHAIN_SPEC': getattr(args, 'i'), + 'ETH_PROVIDER': getattr(args, 'p'), + 'CIC_REGISTRY_ADDRESS': getattr(args, 'r'), + 'REDIS_HOST': getattr(args, 'redis_host'), + 'REDIS_PORT': getattr(args, 'redis_port'), + 'REDIS_DB': getattr(args, 'redis_db'), + 'META_HOST': getattr(args, 'meta_host'), + 'META_PORT': getattr(args, 'meta_port'), + } +config.dict_override(args_override, 'cli flag') +config.censor('PASSWORD', 'DATABASE') +config.censor('PASSWORD', 'SSL') +logg.debug('config loaded from {}:\n{}'.format(config_dir, config)) + +redis_host = config.get('REDIS_HOST') +redis_port = config.get('REDIS_PORT') +redis_db = config.get('REDIS_DB') +r = redis.Redis(redis_host, redis_port, redis_db) +celery_app = celery.Celery(backend=config.get('CELERY_RESULT_URL'), broker=config.get('CELERY_BROKER_URL')) + +signer_address = None +keystore = DictKeystore() +if args.y != None: + logg.debug('loading keystore file {}'.format(args.y)) + signer_address = keystore.import_keystore_file(args.y) + logg.debug('now have key for signer address {}'.format(signer_address)) +signer = EIP155Signer(keystore) + +queue = args.q +chain_str = config.get('CIC_CHAIN_SPEC') +block_offset = 0 +if args.head: + block_offset = -1 +else: + block_offset = args.offset + +chain_spec = ChainSpec.from_chain_str(chain_str) +old_chain_spec_str = args.old_chain_spec +old_chain_spec = ChainSpec.from_chain_str(old_chain_spec_str) + +user_dir = args.user_dir # user_out_dir from import_users.py + +token_symbol = args.token_symbol + +MetadataTask.meta_host = config.get('META_HOST') +MetadataTask.meta_port = config.get('META_PORT') +ImportTask.chain_spec = chain_spec + +def main(): + conn = EthHTTPConnection(config.get('ETH_PROVIDER')) + + ImportTask.balance_processor = BalanceProcessor(conn, chain_spec, config.get('CIC_REGISTRY_ADDRESS'), signer_address, signer) + ImportTask.balance_processor.init() + + # TODO get decimals from token + balances = {} + f = open('{}/balances.csv'.format(user_dir, 'r')) + remove_zeros = 10**6 + i = 0 + while True: + l = f.readline() + if l == None: + break + r = l.split(',') + try: + address = to_checksum_address(r[0]) + sys.stdout.write('loading balance {} {} {}'.format(i, address, r[1]).ljust(200) + "\r") + except ValueError: + break + balance = int(int(r[1].rstrip()) / remove_zeros) + balances[address] = balance + i += 1 + + f.close() + + ImportTask.balances = balances + ImportTask.count = i + + s = celery.signature( + 'import_task.send_txs', + [ + MetadataTask.balance_processor.nonce_offset, + ], + queue='cic-import-ussd', + ) + s.apply_async() + + argv = ['worker', '-Q', 'cic-import-ussd', '--loglevel=DEBUG'] + celery_app.worker_main(argv) + + +if __name__ == '__main__': + main() diff --git a/apps/contract-migration/scripts/cic_ussd/import_task.py b/apps/contract-migration/scripts/cic_ussd/import_task.py new file mode 100644 index 00000000..a3f2abf0 --- /dev/null +++ b/apps/contract-migration/scripts/cic_ussd/import_task.py @@ -0,0 +1,218 @@ +# standard imports +import os +import logging +import urllib.parse +import urllib.error +import urllib.request +import json + +# external imports +import celery +from hexathon import ( + strip_0x, + add_0x, + ) +from chainlib.eth.address import to_checksum_address +from chainlib.eth.tx import ( + unpack, + raw, + ) +from cic_types.processor import generate_metadata_pointer +from cic_types.models.person import Person + +#logg = logging.getLogger().getChild(__name__) +logg = logging.getLogger() + +celery_app = celery.current_app + + +class ImportTask(celery.Task): + + balances = None + import_dir = 'out' + count = 0 + chain_spec = None + balance_processor = None + max_retries = None + +class MetadataTask(ImportTask): + + meta_host = None + meta_port = None + meta_path = '' + meta_ssl = False + autoretry_for = ( + urllib.error.HTTPError, + OSError, + ) + retry_jitter = True + retry_backoff = True + retry_backoff_max = 60 + + @classmethod + def meta_url(self): + scheme = 'http' + if self.meta_ssl: + scheme += s + url = urllib.parse.urlparse('{}://{}:{}/{}'.format(scheme, self.meta_host, self.meta_port, self.meta_path)) + return urllib.parse.urlunparse(url) + + +def old_address_from_phone(base_path, phone): + pidx = generate_metadata_pointer(phone.encode('utf-8'), ':cic.phone') + phone_idx_path = os.path.join('{}/phone/{}/{}/{}'.format( + base_path, + pidx[:2], + pidx[2:4], + pidx, + ) + ) + f = open(phone_idx_path, 'r') + old_address = f.read() + f.close() + + return old_address + + +@celery_app.task(bind=True, base=MetadataTask) +def resolve_phone(self, phone): + identifier = generate_metadata_pointer(phone.encode('utf-8'), ':cic.phone') + url = urllib.parse.urljoin(self.meta_url(), identifier) + logg.debug('attempt getting phone pointer at {} for phone {}'.format(url, phone)) + r = urllib.request.urlopen(url) + address = json.load(r) + address = address.replace('"', '') + logg.debug('address {} for phone {}'.format(address, phone)) + + return address + + +@celery_app.task(bind=True, base=MetadataTask) +def generate_metadata(self, address, phone): + old_address = old_address_from_phone(self.import_dir, phone) + + logg.debug('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> foo') + logg.debug('address {}'.format(address)) + old_address_upper = strip_0x(old_address).upper() + metadata_path = '{}/old/{}/{}/{}.json'.format( + self.import_dir, + old_address_upper[:2], + old_address_upper[2:4], + old_address_upper, + ) + + f = open(metadata_path, 'r') + o = json.load(f) + f.close() + + u = Person.deserialize(o) + + if u.identities.get('evm') == None: + u.identities['evm'] = {} + sub_chain_str = '{}:{}'.format(self.chain_spec.common_name(), self.chain_spec.network_id()) + u.identities['evm'][sub_chain_str] = [add_0x(address)] + + new_address_clean = strip_0x(address) + filepath = os.path.join( + self.import_dir, + 'new', + new_address_clean[:2].upper(), + new_address_clean[2:4].upper(), + new_address_clean.upper() + '.json', + ) + os.makedirs(os.path.dirname(filepath), exist_ok=True) + + o = u.serialize() + f = open(filepath, 'w') + f.write(json.dumps(o)) + f.close() + + meta_key = generate_metadata_pointer(bytes.fromhex(new_address_clean), ':cic.person') + meta_filepath = os.path.join( + self.import_dir, + 'meta', + '{}.json'.format(new_address_clean.upper()), + ) + os.symlink(os.path.realpath(filepath), meta_filepath) + + logg.debug('found metadata {} for phone {}'.format(o, phone)) + + return address + + +@celery_app.task(bind=True, base=MetadataTask) +def opening_balance_tx(self, address, phone, serial): + + + old_address = old_address_from_phone(self.import_dir, phone) + + k = to_checksum_address(strip_0x(old_address)) + balance = self.balances[k] + logg.debug('found balance {} for address {} phone {}'.format(balance, old_address, phone)) + + decimal_balance = self.balance_processor.get_decimal_amount(int(balance)) + + (tx_hash_hex, o) = self.balance_processor.get_rpc_tx(address, decimal_balance, serial) + + tx = unpack(bytes.fromhex(strip_0x(o)), self.chain_spec) + logg.debug('generated tx token value {} to {} tx hash {}'.format(decimal_balance, address, tx_hash_hex)) + + tx_path = os.path.join( + self.import_dir, + 'txs', + strip_0x(tx_hash_hex), + ) + + f = open(tx_path, 'w') + f.write(strip_0x(o)) + f.close() + + tx_nonce_path = os.path.join( + self.import_dir, + 'txs', + '.' + str(tx['nonce']), + ) + os.symlink(os.path.realpath(tx_path), tx_nonce_path) + + return tx['hash'] + + +@celery_app.task(bind=True, base=ImportTask, autoretry_for=(FileNotFoundError,), max_retries=None, default_retry_delay=0.1) +def send_txs(self, nonce): + + if nonce == self.count + self.balance_processor.nonce_offset: + logg.info('reached nonce {} (offset {} + count {}) exiting'.format(nonce, self.balance_processor.nonce_offset, self.count)) + return + + + logg.debug('attempt to open symlink for nonce {}'.format(nonce)) + tx_nonce_path = os.path.join( + self.import_dir, + 'txs', + '.' + str(nonce), + ) + f = open(tx_nonce_path, 'r') + tx_signed_raw_hex = f.read() + f.close() + + os.unlink(tx_nonce_path) + + o = raw(add_0x(tx_signed_raw_hex)) + tx_hash_hex = self.balance_processor.conn.do(o) + + logg.info('sent nonce {} tx hash {}'.format(nonce, tx_hash_hex)) #tx_signed_raw_hex)) + + nonce += 1 + + queue = self.request.delivery_info.get('routing_key') + s = celery.signature( + 'import_task.send_txs', + [ + nonce, + ], + queue=queue, + ) + s.apply_async() + + + return nonce diff --git a/apps/contract-migration/scripts/cic_ussd/import_users.py b/apps/contract-migration/scripts/cic_ussd/import_users.py new file mode 100644 index 00000000..ca9bf3f1 --- /dev/null +++ b/apps/contract-migration/scripts/cic_ussd/import_users.py @@ -0,0 +1,191 @@ +# standard imports +import os +import sys +import json +import logging +import argparse +import uuid +import datetime +import time +import urllib.request +from glob import glob + +# third-party imports +import redis +import confini +import celery +from hexathon import ( + add_0x, + strip_0x, + ) +from chainlib.eth.address import to_checksum +from cic_types.models.person import Person +from cic_eth.api.api_task import Api +from chainlib.chain import ChainSpec +from cic_types.processor import generate_metadata_pointer +import phonenumbers + +logging.basicConfig(level=logging.WARNING) +logg = logging.getLogger() + +default_config_dir = '/usr/local/etc/cic' + +argparser = argparse.ArgumentParser() +argparser.add_argument('-c', type=str, default=default_config_dir, help='config file') +argparser.add_argument('-i', '--chain-spec', dest='i', type=str, help='Chain specification string') +argparser.add_argument('--redis-host', dest='redis_host', type=str, help='redis host to use for task submission') +argparser.add_argument('--redis-port', dest='redis_port', type=int, help='redis host to use for task submission') +argparser.add_argument('--redis-db', dest='redis_db', type=int, help='redis db to use for task submission and callback') +argparser.add_argument('--batch-size', dest='batch_size', default=100, type=int, help='burst size of sending transactions to node') # batch size should be slightly below cumulative gas limit worth, eg 80000 gas txs with 8000000 limit is a bit less than 100 batch size +argparser.add_argument('--batch-delay', dest='batch_delay', default=3, type=int, help='seconds delay between batches') +argparser.add_argument('--timeout', default=60.0, type=float, help='Callback timeout') +argparser.add_argument('-q', type=str, default='cic-eth', help='Task queue') +argparser.add_argument('-v', action='store_true', help='Be verbose') +argparser.add_argument('-vv', action='store_true', help='Be more verbose') +argparser.add_argument('user_dir', type=str, help='path to users export dir tree') +args = argparser.parse_args() + +if args.v: + logg.setLevel(logging.INFO) +elif args.vv: + logg.setLevel(logging.DEBUG) + +config_dir = args.c +config = confini.Config(config_dir, os.environ.get('CONFINI_ENV_PREFIX')) +config.process() +args_override = { + 'CIC_CHAIN_SPEC': getattr(args, 'i'), + 'REDIS_HOST': getattr(args, 'redis_host'), + 'REDIS_PORT': getattr(args, 'redis_port'), + 'REDIS_DB': getattr(args, 'redis_db'), + } +config.dict_override(args_override, 'cli') +celery_app = celery.Celery(broker=config.get('CELERY_BROKER_URL'), backend=config.get('CELERY_RESULT_URL')) + +redis_host = config.get('REDIS_HOST') +redis_port = config.get('REDIS_PORT') +redis_db = config.get('REDIS_DB') +r = redis.Redis(redis_host, redis_port, redis_db) + +ps = r.pubsub() + +user_new_dir = os.path.join(args.user_dir, 'new') +os.makedirs(user_new_dir) + +meta_dir = os.path.join(args.user_dir, 'meta') +os.makedirs(meta_dir) + +user_old_dir = os.path.join(args.user_dir, 'old') +os.stat(user_old_dir) + +txs_dir = os.path.join(args.user_dir, 'txs') +os.makedirs(txs_dir) + +chain_spec = ChainSpec.from_chain_str(config.get('CIC_CHAIN_SPEC')) +chain_str = str(chain_spec) + +batch_size = args.batch_size +batch_delay = args.batch_delay + + + +def build_ussd_request(phone, host, port, service_code, username, password, ssl=False): + url = 'http' + if ssl: + url += 's' + url += '://{}:{}'.format(host, port) + url += '/?username={}&password={}'.format(username, password) #config.get('USSD_USER'), config.get('USSD_PASS')) + + logg.info('ussd service url {}'.format(url)) + logg.info('ussd phone {}'.format(phone)) + + session = uuid.uuid4().hex + data = { + 'sessionId': session, + 'serviceCode': service_code, + 'phoneNumber': phone, + 'text': service_code, + } + req = urllib.request.Request(url) + data_str = json.dumps(data) + data_bytes = data_str.encode('utf-8') + req.add_header('Content-Type', 'application/json') + req.data = data_bytes + + return req + + +def register_ussd(i, u): + phone_object = phonenumbers.parse(u.tel) + phone = phonenumbers.format_number(phone_object, phonenumbers.PhoneNumberFormat.E164) + logg.debug('tel {} {}'.format(u.tel, phone)) + req = build_ussd_request(phone, 'localhost', 63315, '*483*46#', '', '') + response = urllib.request.urlopen(req) + response_data = response.read().decode('utf-8') + state = response_data[:3] + out = response_data[4:] + logg.debug('ussd reponse: {}'.format(out)) + + +if __name__ == '__main__': + + i = 0 + j = 0 + for x in os.walk(user_old_dir): + for y in x[2]: + if y[len(y)-5:] != '.json': + continue + filepath = os.path.join(x[0], y) + f = open(filepath, 'r') + try: + o = json.load(f) + except json.decoder.JSONDecodeError as e: + f.close() + logg.error('load error for {}: {}'.format(y, e)) + continue + f.close() + u = Person.deserialize(o) + + new_address = register_ussd(i, u) + + phone_object = phonenumbers.parse(u.tel) + phone = phonenumbers.format_number(phone_object, phonenumbers.PhoneNumberFormat.E164) + + s_phone = celery.signature( + 'import_task.resolve_phone', + [ + phone, + ], + queue='cic-import-ussd', + ) + + s_meta = celery.signature( + 'import_task.generate_metadata', + [ + phone, + ], + queue='cic-import-ussd', + ) + + s_balance = celery.signature( + 'import_task.opening_balance_tx', + [ + phone, + i, + ], + queue='cic-import-ussd', + ) + + s_meta.link(s_balance) + s_phone.link(s_meta) + s_phone.apply_async(countdown=7) # block time plus a bit of time for ussd processing + + i += 1 + sys.stdout.write('imported {} {}'.format(i, u).ljust(200) + "\r") + + j += 1 + if j == batch_size: + time.sleep(batch_delay) + j = 0 + + #fi.close() diff --git a/apps/contract-migration/scripts/cic_ussd/import_util.py b/apps/contract-migration/scripts/cic_ussd/import_util.py new file mode 100644 index 00000000..ebe706bb --- /dev/null +++ b/apps/contract-migration/scripts/cic_ussd/import_util.py @@ -0,0 +1,72 @@ +# standard imports +import logging + +# external imports +from eth_contract_registry import Registry +from eth_token_index import TokenUniqueSymbolIndex +from chainlib.eth.gas import OverrideGasOracle +from chainlib.eth.nonce import OverrideNonceOracle +from chainlib.eth.erc20 import ERC20 +from chainlib.eth.tx import ( + count, + TxFormat, + ) + +logg = logging.getLogger().getChild(__name__) + + +class BalanceProcessor: + + def __init__(self, conn, chain_spec, registry_address, signer_address, signer): + + self.chain_spec = chain_spec + self.conn = conn + #self.signer_address = signer_address + self.registry_address = registry_address + + self.token_index_address = None + self.token_address = None + self.signer_address = signer_address + self.signer = signer + + o = count(signer_address) + c = self.conn.do(o) + self.nonce_offset = int(c, 16) + self.gas_oracle = OverrideGasOracle(conn=conn, limit=8000000) + + self.value_multiplier = 1 + + + def init(self): + # Get Token registry address + registry = Registry(self.chain_spec) + o = registry.address_of(self.registry_address, 'TokenRegistry') + r = self.conn.do(o) + self.token_index_address = registry.parse_address_of(r) + logg.info('found token index address {}'.format(self.token_index_address)) + + token_registry = TokenUniqueSymbolIndex(self.chain_spec) + o = token_registry.address_of(self.token_index_address, 'SRF') + r = self.conn.do(o) + self.token_address = token_registry.parse_address_of(r) + logg.info('found SRF token address {}'.format(self.token_address)) + + tx_factory = ERC20(self.chain_spec) + o = tx_factory.decimals(self.token_address) + r = self.conn.do(o) + n = tx_factory.parse_decimals(r) + self.value_multiplier = 10 ** n + + + def get_rpc_tx(self, recipient, value, i): + logg.debug('initiating nonce offset {} for recipient {}'.format(self.nonce_offset + i, recipient)) + nonce_oracle = OverrideNonceOracle(self.signer_address, self.nonce_offset + i) + tx_factory = ERC20(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle, gas_oracle=self.gas_oracle) + return tx_factory.transfer(self.token_address, self.signer_address, recipient, value, tx_format=TxFormat.RLP_SIGNED) + #(tx_hash_hex, o) = tx_factory.transfer(self.token_address, self.signer_address, recipient, value) + #self.conn.do(o) + #return tx_hash_hex + + + def get_decimal_amount(self, value): + return value * self.value_multiplier diff --git a/apps/contract-migration/scripts/config/meta.ini b/apps/contract-migration/scripts/config/meta.ini index 0d16ee28..a5363cc7 100644 --- a/apps/contract-migration/scripts/config/meta.ini +++ b/apps/contract-migration/scripts/config/meta.ini @@ -1,2 +1,5 @@ [meta] url = http://localhost:63380 +host = localhost +port = 63380 +ssl = 0 diff --git a/apps/contract-migration/scripts/create_import_users.py b/apps/contract-migration/scripts/create_import_users.py index 2e514751..9f7c3d9c 100644 --- a/apps/contract-migration/scripts/create_import_users.py +++ b/apps/contract-migration/scripts/create_import_users.py @@ -24,6 +24,7 @@ from cic_types.models.person import ( get_contact_data_from_vcard, ) from chainlib.eth.address import to_checksum_address +import phonenumbers logging.basicConfig(level=logging.WARNING) logg = logging.getLogger() @@ -80,10 +81,12 @@ phone_idx = [] user_dir = args.dir user_count = args.user_count +random.seed() + def genPhoneIndex(phone): h = hashlib.new('sha256') h.update(phone.encode('utf-8')) - h.update(b'cic.msisdn') + h.update(b':cic.phone') return h.digest().hex() @@ -101,7 +104,9 @@ def genDate(): def genPhone(): - return fake.msisdn() + phone_str = '+254' + str(random.randint(100000000, 999999999)) + phone_object = phonenumbers.parse(phone_str) + return phonenumbers.format_number(phone_object, phonenumbers.PhoneNumberFormat.E164) def genPersonal(phone): @@ -205,14 +210,14 @@ if __name__ == '__main__': f.close() pidx = genPhoneIndex(phone) - d = prepareLocalFilePath(os.path.join(user_dir, 'phone'), uid) + d = prepareLocalFilePath(os.path.join(user_dir, 'phone'), pidx) f = open('{}/{}'.format(d, pidx), 'w') f.write(eth) f.close() amount = genAmount() fa.write('{},{}\n'.format(eth,amount)) - logg.debug('pidx {}, uid {}, eth {}, amount {}'.format(pidx, uid, eth, amount)) + logg.debug('pidx {}, uid {}, eth {}, amount {}, phone {}'.format(pidx, uid, eth, amount, phone)) i += 1 diff --git a/apps/contract-migration/scripts/eth/import_balance.py b/apps/contract-migration/scripts/eth/import_balance.py new file mode 100644 index 00000000..618f2421 --- /dev/null +++ b/apps/contract-migration/scripts/eth/import_balance.py @@ -0,0 +1,309 @@ +# standard imports +import os +import sys +import logging +import time +import argparse +import sys +import re +import hashlib +import csv +import json + +# external imports +import eth_abi +import confini +from hexathon import ( + strip_0x, + add_0x, + ) +from chainsyncer.backend import MemBackend +from chainsyncer.driver import HeadSyncer +from chainlib.eth.connection import EthHTTPConnection +from chainlib.eth.block import ( + block_latest, + block_by_number, + Block, + ) +from chainlib.eth.hash import keccak256_string_to_hex +from chainlib.eth.address import to_checksum_address +from chainlib.eth.erc20 import ERC20 +from chainlib.eth.gas import OverrideGasOracle +from chainlib.eth.nonce import RPCNonceOracle +from chainlib.eth.tx import TxFactory +from chainlib.eth.rpc import jsonrpc_template +from chainlib.eth.error import EthException +from chainlib.chain import ChainSpec +from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer +from crypto_dev_signer.keystore.dict import DictKeystore +from cic_types.models.person import Person + + +logging.basicConfig(level=logging.WARNING) +logg = logging.getLogger() + +config_dir = './config' + +argparser = argparse.ArgumentParser(description='daemon that monitors transactions in new blocks') +argparser.add_argument('-p', '--provider', dest='p', type=str, help='chain rpc provider address') +argparser.add_argument('-y', '--key-file', dest='y', type=str, help='Ethereum keystore file to use for signing') +argparser.add_argument('-c', type=str, default=config_dir, help='config root to use') +argparser.add_argument('--old-chain-spec', type=str, dest='old_chain_spec', default='evm:oldchain:1', help='chain spec') +argparser.add_argument('-i', '--chain-spec', type=str, dest='i', help='chain spec') +argparser.add_argument('-r', '--registry-address', type=str, dest='r', help='CIC Registry address') +argparser.add_argument('--token-symbol', default='SRF', type=str, dest='token_symbol', help='Token symbol to use for trnsactions') +argparser.add_argument('--head', action='store_true', help='start at current block height (overrides --offset)') +argparser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration') +argparser.add_argument('-q', type=str, default='cic-eth', help='celery queue to submit transaction tasks to') +argparser.add_argument('--offset', type=int, default=0, help='block offset to start syncer from') +argparser.add_argument('-v', help='be verbose', action='store_true') +argparser.add_argument('-vv', help='be more verbose', action='store_true') +argparser.add_argument('user_dir', type=str, help='user export directory') +args = argparser.parse_args(sys.argv[1:]) + +if args.v == True: + logging.getLogger().setLevel(logging.INFO) +elif args.vv == True: + logging.getLogger().setLevel(logging.DEBUG) + +config_dir = os.path.join(args.c) +os.makedirs(config_dir, 0o777, True) +config = confini.Config(config_dir, args.env_prefix) +config.process() +# override args +args_override = { + 'CIC_CHAIN_SPEC': getattr(args, 'i'), + 'ETH_PROVIDER': getattr(args, 'p'), + 'CIC_REGISTRY_ADDRESS': getattr(args, 'r'), + } +config.dict_override(args_override, 'cli flag') +config.censor('PASSWORD', 'DATABASE') +config.censor('PASSWORD', 'SSL') +logg.debug('config loaded from {}:\n{}'.format(config_dir, config)) + +#app = celery.Celery(backend=config.get('CELERY_RESULT_URL'), broker=config.get('CELERY_BROKER_URL')) + +signer_address = None +keystore = DictKeystore() +if args.y != None: + logg.debug('loading keystore file {}'.format(args.y)) + signer_address = keystore.import_keystore_file(args.y) + logg.debug('now have key for signer address {}'.format(signer_address)) +signer = EIP155Signer(keystore) + +queue = args.q +chain_str = config.get('CIC_CHAIN_SPEC') +block_offset = 0 +if args.head: + block_offset = -1 +else: + block_offset = args.offset + +chain_spec = ChainSpec.from_chain_str(chain_str) +old_chain_spec_str = args.old_chain_spec +old_chain_spec = ChainSpec.from_chain_str(old_chain_spec_str) + +user_dir = args.user_dir # user_out_dir from import_users.py + +token_symbol = args.token_symbol + + +class Handler: + + account_index_add_signature = keccak256_string_to_hex('add(address)')[:8] + + def __init__(self, conn, chain_spec, user_dir, balances, token_address, signer, gas_oracle, nonce_oracle): + self.token_address = token_address + self.user_dir = user_dir + self.balances = balances + self.chain_spec = chain_spec + self.tx_factory = ERC20(chain_spec, signer, gas_oracle, nonce_oracle) + + + def name(self): + return 'balance_handler' + + + def filter(self, conn, block, tx, db_session): + if tx.payload == None or len(tx.payload) == 0: + logg.debug('no payload, skipping {}'.format(tx)) + return + + if tx.payload[:8] == self.account_index_add_signature: + recipient = eth_abi.decode_single('address', bytes.fromhex(tx.payload[-64:])) + #original_address = to_checksum_address(self.addresses[to_checksum_address(recipient)]) + user_file = 'new/{}/{}/{}.json'.format( + recipient[2:4].upper(), + recipient[4:6].upper(), + recipient[2:].upper(), + ) + filepath = os.path.join(self.user_dir, user_file) + o = None + try: + f = open(filepath, 'r') + o = json.load(f) + f.close() + except FileNotFoundError: + logg.error('no import record of address {}'.format(recipient)) + return + u = Person.deserialize(o) + original_address = u.identities[old_chain_spec.engine()]['{}:{}'.format(old_chain_spec.common_name(), old_chain_spec.network_id())][0] + try: + balance = self.balances[original_address] + except KeyError as e: + logg.error('balance get fail orig {} new {}'.format(original_address, recipient)) + return + + # TODO: store token object in handler ,get decimals from there + multiplier = 10**6 + balance_full = balance * multiplier + logg.info('registered {} originally {} ({}) tx hash {} balance {}'.format(recipient, original_address, u, tx.hash, balance_full)) + + (tx_hash_hex, o) = self.tx_factory.transfer(self.token_address, signer_address, recipient, balance_full) + logg.info('submitting erc20 transfer tx {} for recipient {}'.format(tx_hash_hex, recipient)) + r = conn.do(o) + + tx_path = os.path.join( + user_dir, + 'txs', + strip_0x(tx_hash_hex), + ) + f = open(tx_path, 'w') + f.write(strip_0x(o['params'][0])) + f.close() +# except TypeError as e: +# logg.warning('typerror {}'.format(e)) +# pass +# except IndexError as e: +# logg.warning('indexerror {}'.format(e)) +# pass +# except EthException as e: +# logg.error('send error {}'.format(e).ljust(200)) + #except KeyError as e: + # logg.error('key record not found in imports: {}'.format(e).ljust(200)) + + +#class BlockGetter: +# +# def __init__(self, conn, gas_oracle, nonce_oracle, chain_spec): +# self.conn = conn +# self.tx_factory = ERC20(signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle, chain_id=chain_id) +# +# +# def get(self, n): +# o = block_by_number(n) +# r = self.conn.do(o) +# b = None +# try: +# b = Block(r) +# except TypeError as e: +# if r == None: +# logg.debug('block not found {}'.format(n)) +# else: +# logg.error('block retrieve error {}'.format(e)) +# return b + + +def progress_callback(block_number, tx_index, s): + sys.stdout.write(str(s).ljust(200) + "\n") + + + +def main(): + global chain_str, block_offset, user_dir + + conn = EthHTTPConnection(config.get('ETH_PROVIDER')) + gas_oracle = OverrideGasOracle(conn=conn, limit=8000000) + nonce_oracle = RPCNonceOracle(signer_address, conn) + + # Get Token registry address + txf = TxFactory(chain_spec, signer=signer, gas_oracle=gas_oracle, nonce_oracle=None) + tx = txf.template(signer_address, config.get('CIC_REGISTRY_ADDRESS')) + + registry_addressof_method = keccak256_string_to_hex('addressOf(bytes32)')[:8] + data = add_0x(registry_addressof_method) + data += eth_abi.encode_single('bytes32', b'TokenRegistry').hex() + txf.set_code(tx, data) + + o = jsonrpc_template() + o['method'] = 'eth_call' + o['params'].append(txf.normalize(tx)) + o['params'].append('latest') + r = conn.do(o) + token_index_address = to_checksum_address(eth_abi.decode_single('address', bytes.fromhex(strip_0x(r)))) + logg.info('found token index address {}'.format(token_index_address)) + + + # Get Sarafu token address + tx = txf.template(signer_address, token_index_address) + data = add_0x(registry_addressof_method) + h = hashlib.new('sha256') + h.update(token_symbol.encode('utf-8')) + z = h.digest() + data += eth_abi.encode_single('bytes32', z).hex() + txf.set_code(tx, data) + o = jsonrpc_template() + o['method'] = 'eth_call' + o['params'].append(txf.normalize(tx)) + o['params'].append('latest') + r = conn.do(o) + try: + sarafu_token_address = to_checksum_address(eth_abi.decode_single('address', bytes.fromhex(strip_0x(r)))) + except ValueError as e: + logg.critical('lookup failed for token {}: {}'.format(token_symbol, e)) + sys.exit(1) + logg.info('found token address {}'.format(sarafu_token_address)) + + syncer_backend = MemBackend(chain_str, 0) + + if block_offset == -1: + o = block_latest() + r = conn.do(o) + block_offset = int(strip_0x(r), 16) + 1 +# +# addresses = {} +# f = open('{}/addresses.csv'.format(user_dir, 'r')) +# while True: +# l = f.readline() +# if l == None: +# break +# r = l.split(',') +# try: +# k = r[0] +# v = r[1].rstrip() +# addresses[k] = v +# sys.stdout.write('loading address mapping {} -> {}'.format(k, v).ljust(200) + "\r") +# except IndexError as e: +# break +# f.close() + + # TODO get decimals from token + balances = {} + f = open('{}/balances.csv'.format(user_dir, 'r')) + remove_zeros = 10**6 + i = 0 + while True: + l = f.readline() + if l == None: + break + r = l.split(',') + try: + address = to_checksum_address(r[0]) + sys.stdout.write('loading balance {} {} {}'.format(i, address, r[1]).ljust(200) + "\r") + except ValueError: + break + balance = int(int(r[1].rstrip()) / remove_zeros) + balances[address] = balance + i += 1 + + f.close() + + syncer_backend.set(block_offset, 0) + syncer = HeadSyncer(syncer_backend, progress_callback=progress_callback) + handler = Handler(conn, chain_spec, user_dir, balances, sarafu_token_address, signer, gas_oracle, nonce_oracle) + syncer.add_filter(handler) + syncer.loop(1, conn) + + +if __name__ == '__main__': + main() diff --git a/apps/contract-migration/scripts/import_sovereign_users.py b/apps/contract-migration/scripts/eth/import_users.py similarity index 83% rename from apps/contract-migration/scripts/import_sovereign_users.py rename to apps/contract-migration/scripts/eth/import_users.py index bf7eff60..c5a5fb69 100644 --- a/apps/contract-migration/scripts/import_sovereign_users.py +++ b/apps/contract-migration/scripts/eth/import_users.py @@ -7,6 +7,7 @@ import argparse import uuid import datetime import time +import phonenumbers from glob import glob # external imports @@ -67,9 +68,15 @@ os.makedirs(user_new_dir) meta_dir = os.path.join(args.user_dir, 'meta') os.makedirs(meta_dir) +phone_dir = os.path.join(args.user_dir, 'phone') +os.makedirs(os.path.join(phone_dir, 'meta')) + user_old_dir = os.path.join(args.user_dir, 'old') os.stat(user_old_dir) +txs_dir = os.path.join(args.user_dir, 'txs') +os.makedirs(txs_dir) + chain_spec = ChainSpec.from_chain_str(config.get('CIC_CHAIN_SPEC')) chain_str = str(chain_spec) @@ -88,7 +95,7 @@ signer = EIP155Signer(keystore) nonce_oracle = RPCNonceOracle(signer_address, rpc) -registry = Registry() +registry = Registry(chain_spec) o = registry.address_of(config.get('CIC_REGISTRY_ADDRESS'), 'AccountRegistry') r = rpc.do(o) account_registry_address = registry.parse_address_of(r) @@ -109,7 +116,7 @@ def register_eth(i, u): rpc.do(o) pk = keystore.get(address) - keyfile_content = to_keyfile_dict(pk, '') + keyfile_content = to_keyfile_dict(pk, 'foo') keyfile_path = os.path.join(keyfile_dir, '{}.json'.format(address)) f = open(keyfile_path, 'w') json.dump(keyfile_content, f) @@ -166,10 +173,31 @@ if __name__ == '__main__': f.write(json.dumps(o)) f.close() - meta_key = generate_metadata_pointer(bytes.fromhex(new_address_clean), 'cic.person') + meta_key = generate_metadata_pointer(bytes.fromhex(new_address_clean), ':cic.person') meta_filepath = os.path.join(meta_dir, '{}.json'.format(new_address_clean.upper())) os.symlink(os.path.realpath(filepath), meta_filepath) + phone_object = phonenumbers.parse(u.tel) + phone = phonenumbers.format_number(phone_object, phonenumbers.PhoneNumberFormat.E164) + logg.debug('>>>>> Using phone {}'.format(phone)) + meta_phone_key = generate_metadata_pointer(phone.encode('utf-8'), ':cic.phone') + meta_phone_filepath = os.path.join(phone_dir, 'meta', meta_phone_key) + + filepath = os.path.join( + phone_dir, + 'new', + meta_phone_key[:2].upper(), + meta_phone_key[2:4].upper(), + meta_phone_key.upper(), + ) + os.makedirs(os.path.dirname(filepath), exist_ok=True) + + f = open(filepath, 'w') + f.write(to_checksum_address(new_address_clean)) + f.close() + + os.symlink(os.path.realpath(filepath), meta_phone_filepath) + i += 1 sys.stdout.write('imported {} {}'.format(i, u).ljust(200) + "\r") diff --git a/apps/contract-migration/scripts/false/_logs/2021-02-12T18_59_21_680Z-debug.log b/apps/contract-migration/scripts/false/_logs/2021-02-12T18_59_21_680Z-debug.log deleted file mode 100644 index 011bfd8b..00000000 --- a/apps/contract-migration/scripts/false/_logs/2021-02-12T18_59_21_680Z-debug.log +++ /dev/null @@ -1,1383 +0,0 @@ -0 info it worked if it ends with ok -1 verbose cli [ -1 verbose cli '/usr/bin/node', -1 verbose cli '/usr/bin/npm', -1 verbose cli 'install', -1 verbose cli '--no-cache', -1 verbose cli '../../../apps/cic-meta' -1 verbose cli ] -2 info using npm@6.14.11 -3 info using node@v15.6.0 -4 verbose npm-session 64ba63e9b9f4a63f -5 silly install loadCurrentTree -6 silly install readLocalPackageData -7 silly pacote directory manifest for undefined@file:../../cic-meta fetched in 4ms -8 timing stage:loadCurrentTree Completed in 473ms -9 silly install loadIdealTree -10 silly install cloneCurrentTreeToIdealTree -11 timing stage:loadIdealTree:cloneCurrentTree Completed in 3ms -12 silly install loadShrinkwrap -13 timing stage:loadIdealTree:loadShrinkwrap Completed in 57ms -14 silly install loadAllDepsIntoIdealTree -15 silly resolveWithNewModule cic-client-meta@0.0.7-alpha.1 checking installable status -16 silly removeObsoleteDep removing cic-client-meta@0.0.7-alpha.1 from the tree as its been replaced by a newer version or is no longer required -17 silly removeObsoleteDep removing @ethereumjs/tx@3.0.0-beta.1 from the tree as its been replaced by a newer version or is no longer required -18 silly removeObsoleteDep removing @ethereumjs/common@2.0.0-beta.1 from the tree as its been replaced by a newer version or is no longer required -19 silly removeObsoleteDep removing crc-32@1.2.0 from the tree as its been replaced by a newer version or is no longer required -20 silly removeObsoleteDep removing exit-on-epipe@1.0.1 from the tree as its been replaced by a newer version or is no longer required -21 silly removeObsoleteDep removing printj@1.1.2 from the tree as its been replaced by a newer version or is no longer required -22 silly removeObsoleteDep removing automerge@0.14.1 from the tree as its been replaced by a newer version or is no longer required -23 silly removeObsoleteDep removing immutable@3.8.2 from the tree as its been replaced by a newer version or is no longer required -24 silly removeObsoleteDep removing transit-immutable-js@0.7.0 from the tree as its been replaced by a newer version or is no longer required -25 silly removeObsoleteDep removing transit-js@0.8.867 from the tree as its been replaced by a newer version or is no longer required -26 silly removeObsoleteDep removing ethereumjs-wallet@1.0.1 from the tree as its been replaced by a newer version or is no longer required -27 silly removeObsoleteDep removing aes-js@3.1.2 from the tree as its been replaced by a newer version or is no longer required -28 silly removeObsoleteDep removing bs58check@2.1.2 from the tree as its been replaced by a newer version or is no longer required -29 silly removeObsoleteDep removing bs58@4.0.1 from the tree as its been replaced by a newer version or is no longer required -30 silly removeObsoleteDep removing base-x@3.0.8 from the tree as its been replaced by a newer version or is no longer required -31 silly removeObsoleteDep removing create-hash@1.2.0 from the tree as its been replaced by a newer version or is no longer required -32 silly removeObsoleteDep removing cipher-base@1.0.4 from the tree as its been replaced by a newer version or is no longer required -33 silly removeObsoleteDep removing md5.js@1.3.5 from the tree as its been replaced by a newer version or is no longer required -34 silly removeObsoleteDep removing hash-base@3.1.0 from the tree as its been replaced by a newer version or is no longer required -35 silly removeObsoleteDep removing ripemd160@2.0.2 from the tree as its been replaced by a newer version or is no longer required -36 silly removeObsoleteDep removing sha.js@2.4.11 from the tree as its been replaced by a newer version or is no longer required -37 silly removeObsoleteDep removing ethereum-cryptography@0.1.3 from the tree as its been replaced by a newer version or is no longer required -38 silly removeObsoleteDep removing @types/pbkdf2@3.1.0 from the tree as its been replaced by a newer version or is no longer required -39 silly removeObsoleteDep removing @types/node@14.14.6 from the tree as its been replaced by a newer version or is no longer required -40 silly removeObsoleteDep removing @types/secp256k1@4.0.1 from the tree as its been replaced by a newer version or is no longer required -41 silly removeObsoleteDep removing blakejs@1.1.0 from the tree as its been replaced by a newer version or is no longer required -42 silly removeObsoleteDep removing browserify-aes@1.2.0 from the tree as its been replaced by a newer version or is no longer required -43 silly removeObsoleteDep removing buffer-xor@1.0.3 from the tree as its been replaced by a newer version or is no longer required -44 silly removeObsoleteDep removing evp_bytestokey@1.0.3 from the tree as its been replaced by a newer version or is no longer required -45 silly removeObsoleteDep removing create-hmac@1.1.7 from the tree as its been replaced by a newer version or is no longer required -46 silly removeObsoleteDep removing hash.js@1.1.7 from the tree as its been replaced by a newer version or is no longer required -47 silly removeObsoleteDep removing keccak@3.0.1 from the tree as its been replaced by a newer version or is no longer required -48 silly removeObsoleteDep removing node-gyp-build@4.2.3 from the tree as its been replaced by a newer version or is no longer required -49 silly removeObsoleteDep removing pbkdf2@3.1.1 from the tree as its been replaced by a newer version or is no longer required -50 silly removeObsoleteDep removing randombytes@2.1.0 from the tree as its been replaced by a newer version or is no longer required -51 silly removeObsoleteDep removing scrypt-js@3.0.1 from the tree as its been replaced by a newer version or is no longer required -52 silly removeObsoleteDep removing secp256k1@4.0.2 from the tree as its been replaced by a newer version or is no longer required -53 silly removeObsoleteDep removing elliptic@6.5.3 from the tree as its been replaced by a newer version or is no longer required -54 silly removeObsoleteDep removing brorand@1.1.0 from the tree as its been replaced by a newer version or is no longer required -55 silly removeObsoleteDep removing hmac-drbg@1.0.1 from the tree as its been replaced by a newer version or is no longer required -56 silly removeObsoleteDep removing minimalistic-crypto-utils@1.0.1 from the tree as its been replaced by a newer version or is no longer required -57 silly removeObsoleteDep removing setimmediate@1.0.5 from the tree as its been replaced by a newer version or is no longer required -58 silly removeObsoleteDep removing ethereumjs-util@7.0.7 from the tree as its been replaced by a newer version or is no longer required -59 silly removeObsoleteDep removing @types/bn.js@4.11.6 from the tree as its been replaced by a newer version or is no longer required -60 silly removeObsoleteDep removing bn.js@5.1.3 from the tree as its been replaced by a newer version or is no longer required -61 silly removeObsoleteDep removing ethjs-util@0.1.6 from the tree as its been replaced by a newer version or is no longer required -62 silly removeObsoleteDep removing is-hex-prefixed@1.0.0 from the tree as its been replaced by a newer version or is no longer required -63 silly removeObsoleteDep removing strip-hex-prefix@1.0.0 from the tree as its been replaced by a newer version or is no longer required -64 silly removeObsoleteDep removing rlp@2.2.6 from the tree as its been replaced by a newer version or is no longer required -65 silly removeObsoleteDep removing utf8@3.0.0 from the tree as its been replaced by a newer version or is no longer required -66 silly removeObsoleteDep removing openpgp@4.10.8 from the tree as its been replaced by a newer version or is no longer required -67 silly removeObsoleteDep removing asn1.js@5.4.1 from the tree as its been replaced by a newer version or is no longer required -68 silly removeObsoleteDep removing bn.js@4.11.9 from the tree as its been replaced by a newer version or is no longer required -69 silly removeObsoleteDep removing minimalistic-assert@1.0.1 from the tree as its been replaced by a newer version or is no longer required -70 silly removeObsoleteDep removing node-fetch@2.6.1 from the tree as its been replaced by a newer version or is no longer required -71 silly removeObsoleteDep removing node-localstorage@1.3.1 from the tree as its been replaced by a newer version or is no longer required -72 silly removeObsoleteDep removing write-file-atomic@1.3.4 from the tree as its been replaced by a newer version or is no longer required -73 silly removeObsoleteDep removing imurmurhash@0.1.4 from the tree as its been replaced by a newer version or is no longer required -74 silly removeObsoleteDep removing slide@1.1.6 from the tree as its been replaced by a newer version or is no longer required -75 silly removeObsoleteDep removing pg@8.4.2 from the tree as its been replaced by a newer version or is no longer required -76 silly removeObsoleteDep removing buffer-writer@2.0.0 from the tree as its been replaced by a newer version or is no longer required -77 silly removeObsoleteDep removing packet-reader@1.0.0 from the tree as its been replaced by a newer version or is no longer required -78 silly removeObsoleteDep removing pg-connection-string@2.4.0 from the tree as its been replaced by a newer version or is no longer required -79 silly removeObsoleteDep removing pg-pool@3.2.2 from the tree as its been replaced by a newer version or is no longer required -80 silly removeObsoleteDep removing pg-protocol@1.3.0 from the tree as its been replaced by a newer version or is no longer required -81 silly removeObsoleteDep removing pg-types@2.2.0 from the tree as its been replaced by a newer version or is no longer required -82 silly removeObsoleteDep removing pg-int8@1.0.1 from the tree as its been replaced by a newer version or is no longer required -83 silly removeObsoleteDep removing postgres-array@2.0.0 from the tree as its been replaced by a newer version or is no longer required -84 silly removeObsoleteDep removing postgres-bytea@1.0.0 from the tree as its been replaced by a newer version or is no longer required -85 silly removeObsoleteDep removing postgres-date@1.0.7 from the tree as its been replaced by a newer version or is no longer required -86 silly removeObsoleteDep removing postgres-interval@1.2.0 from the tree as its been replaced by a newer version or is no longer required -87 silly removeObsoleteDep removing xtend@4.0.2 from the tree as its been replaced by a newer version or is no longer required -88 silly removeObsoleteDep removing pgpass@1.0.4 from the tree as its been replaced by a newer version or is no longer required -89 silly removeObsoleteDep removing split2@3.2.2 from the tree as its been replaced by a newer version or is no longer required -90 silly removeObsoleteDep removing readable-stream@3.6.0 from the tree as its been replaced by a newer version or is no longer required -91 silly removeObsoleteDep removing string_decoder@1.3.0 from the tree as its been replaced by a newer version or is no longer required -92 silly removeObsoleteDep removing sqlite3@5.0.0 from the tree as its been replaced by a newer version or is no longer required -93 silly removeObsoleteDep removing node-addon-api@2.0.0 from the tree as its been replaced by a newer version or is no longer required -94 silly removeObsoleteDep removing node-gyp@3.8.0 from the tree as its been replaced by a newer version or is no longer required -95 silly removeObsoleteDep removing fstream@1.0.12 from the tree as its been replaced by a newer version or is no longer required -96 silly removeObsoleteDep removing graceful-fs@4.2.4 from the tree as its been replaced by a newer version or is no longer required -97 silly removeObsoleteDep removing inherits@2.0.4 from the tree as its been replaced by a newer version or is no longer required -98 silly removeObsoleteDep removing mkdirp@0.5.5 from the tree as its been replaced by a newer version or is no longer required -99 silly removeObsoleteDep removing minimist@1.2.5 from the tree as its been replaced by a newer version or is no longer required -100 silly removeObsoleteDep removing rimraf@2.7.1 from the tree as its been replaced by a newer version or is no longer required -101 silly removeObsoleteDep removing glob@7.1.6 from the tree as its been replaced by a newer version or is no longer required -102 silly removeObsoleteDep removing fs.realpath@1.0.0 from the tree as its been replaced by a newer version or is no longer required -103 silly removeObsoleteDep removing inflight@1.0.6 from the tree as its been replaced by a newer version or is no longer required -104 silly removeObsoleteDep removing once@1.4.0 from the tree as its been replaced by a newer version or is no longer required -105 silly removeObsoleteDep removing wrappy@1.0.2 from the tree as its been replaced by a newer version or is no longer required -106 silly removeObsoleteDep removing minimatch@3.0.4 from the tree as its been replaced by a newer version or is no longer required -107 silly removeObsoleteDep removing brace-expansion@1.1.11 from the tree as its been replaced by a newer version or is no longer required -108 silly removeObsoleteDep removing balanced-match@1.0.0 from the tree as its been replaced by a newer version or is no longer required -109 silly removeObsoleteDep removing concat-map@0.0.1 from the tree as its been replaced by a newer version or is no longer required -110 silly removeObsoleteDep removing path-is-absolute@1.0.1 from the tree as its been replaced by a newer version or is no longer required -111 silly removeObsoleteDep removing nopt@3.0.6 from the tree as its been replaced by a newer version or is no longer required -112 silly removeObsoleteDep removing abbrev@1.1.1 from the tree as its been replaced by a newer version or is no longer required -113 silly removeObsoleteDep removing npmlog@4.1.2 from the tree as its been replaced by a newer version or is no longer required -114 silly removeObsoleteDep removing are-we-there-yet@1.1.5 from the tree as its been replaced by a newer version or is no longer required -115 silly removeObsoleteDep removing delegates@1.0.0 from the tree as its been replaced by a newer version or is no longer required -116 silly removeObsoleteDep removing readable-stream@2.3.7 from the tree as its been replaced by a newer version or is no longer required -117 silly removeObsoleteDep removing core-util-is@1.0.2 from the tree as its been replaced by a newer version or is no longer required -118 silly removeObsoleteDep removing isarray@1.0.0 from the tree as its been replaced by a newer version or is no longer required -119 silly removeObsoleteDep removing process-nextick-args@2.0.1 from the tree as its been replaced by a newer version or is no longer required -120 silly removeObsoleteDep removing safe-buffer@5.1.2 from the tree as its been replaced by a newer version or is no longer required -121 silly removeObsoleteDep removing string_decoder@1.1.1 from the tree as its been replaced by a newer version or is no longer required -122 silly removeObsoleteDep removing util-deprecate@1.0.2 from the tree as its been replaced by a newer version or is no longer required -123 silly removeObsoleteDep removing console-control-strings@1.1.0 from the tree as its been replaced by a newer version or is no longer required -124 silly removeObsoleteDep removing gauge@2.7.4 from the tree as its been replaced by a newer version or is no longer required -125 silly removeObsoleteDep removing aproba@1.2.0 from the tree as its been replaced by a newer version or is no longer required -126 silly removeObsoleteDep removing has-unicode@2.0.1 from the tree as its been replaced by a newer version or is no longer required -127 silly removeObsoleteDep removing object-assign@4.1.1 from the tree as its been replaced by a newer version or is no longer required -128 silly removeObsoleteDep removing signal-exit@3.0.3 from the tree as its been replaced by a newer version or is no longer required -129 silly removeObsoleteDep removing string-width@1.0.2 from the tree as its been replaced by a newer version or is no longer required -130 silly removeObsoleteDep removing code-point-at@1.1.0 from the tree as its been replaced by a newer version or is no longer required -131 silly removeObsoleteDep removing is-fullwidth-code-point@1.0.0 from the tree as its been replaced by a newer version or is no longer required -132 silly removeObsoleteDep removing number-is-nan@1.0.1 from the tree as its been replaced by a newer version or is no longer required -133 silly removeObsoleteDep removing strip-ansi@3.0.1 from the tree as its been replaced by a newer version or is no longer required -134 silly removeObsoleteDep removing ansi-regex@2.1.1 from the tree as its been replaced by a newer version or is no longer required -135 silly removeObsoleteDep removing wide-align@1.1.3 from the tree as its been replaced by a newer version or is no longer required -136 silly removeObsoleteDep removing set-blocking@2.0.0 from the tree as its been replaced by a newer version or is no longer required -137 silly removeObsoleteDep removing osenv@0.1.5 from the tree as its been replaced by a newer version or is no longer required -138 silly removeObsoleteDep removing os-homedir@1.0.2 from the tree as its been replaced by a newer version or is no longer required -139 silly removeObsoleteDep removing os-tmpdir@1.0.2 from the tree as its been replaced by a newer version or is no longer required -140 silly removeObsoleteDep removing request@2.88.2 from the tree as its been replaced by a newer version or is no longer required -141 silly removeObsoleteDep removing aws-sign2@0.7.0 from the tree as its been replaced by a newer version or is no longer required -142 silly removeObsoleteDep removing aws4@1.11.0 from the tree as its been replaced by a newer version or is no longer required -143 silly removeObsoleteDep removing caseless@0.12.0 from the tree as its been replaced by a newer version or is no longer required -144 silly removeObsoleteDep removing combined-stream@1.0.8 from the tree as its been replaced by a newer version or is no longer required -145 silly removeObsoleteDep removing delayed-stream@1.0.0 from the tree as its been replaced by a newer version or is no longer required -146 silly removeObsoleteDep removing extend@3.0.2 from the tree as its been replaced by a newer version or is no longer required -147 silly removeObsoleteDep removing forever-agent@0.6.1 from the tree as its been replaced by a newer version or is no longer required -148 silly removeObsoleteDep removing form-data@2.3.3 from the tree as its been replaced by a newer version or is no longer required -149 silly removeObsoleteDep removing asynckit@0.4.0 from the tree as its been replaced by a newer version or is no longer required -150 silly removeObsoleteDep removing mime-types@2.1.27 from the tree as its been replaced by a newer version or is no longer required -151 silly removeObsoleteDep removing mime-db@1.44.0 from the tree as its been replaced by a newer version or is no longer required -152 silly removeObsoleteDep removing har-validator@5.1.5 from the tree as its been replaced by a newer version or is no longer required -153 silly removeObsoleteDep removing ajv@6.12.6 from the tree as its been replaced by a newer version or is no longer required -154 silly removeObsoleteDep removing fast-deep-equal@3.1.3 from the tree as its been replaced by a newer version or is no longer required -155 silly removeObsoleteDep removing fast-json-stable-stringify@2.1.0 from the tree as its been replaced by a newer version or is no longer required -156 silly removeObsoleteDep removing json-schema-traverse@0.4.1 from the tree as its been replaced by a newer version or is no longer required -157 silly removeObsoleteDep removing uri-js@4.4.0 from the tree as its been replaced by a newer version or is no longer required -158 silly removeObsoleteDep removing punycode@2.1.1 from the tree as its been replaced by a newer version or is no longer required -159 silly removeObsoleteDep removing har-schema@2.0.0 from the tree as its been replaced by a newer version or is no longer required -160 silly removeObsoleteDep removing http-signature@1.2.0 from the tree as its been replaced by a newer version or is no longer required -161 silly removeObsoleteDep removing assert-plus@1.0.0 from the tree as its been replaced by a newer version or is no longer required -162 silly removeObsoleteDep removing jsprim@1.4.1 from the tree as its been replaced by a newer version or is no longer required -163 silly removeObsoleteDep removing extsprintf@1.3.0 from the tree as its been replaced by a newer version or is no longer required -164 silly removeObsoleteDep removing json-schema@0.2.3 from the tree as its been replaced by a newer version or is no longer required -165 silly removeObsoleteDep removing verror@1.10.0 from the tree as its been replaced by a newer version or is no longer required -166 silly removeObsoleteDep removing sshpk@1.16.1 from the tree as its been replaced by a newer version or is no longer required -167 silly removeObsoleteDep removing asn1@0.2.4 from the tree as its been replaced by a newer version or is no longer required -168 silly removeObsoleteDep removing safer-buffer@2.1.2 from the tree as its been replaced by a newer version or is no longer required -169 silly removeObsoleteDep removing bcrypt-pbkdf@1.0.2 from the tree as its been replaced by a newer version or is no longer required -170 silly removeObsoleteDep removing tweetnacl@0.14.5 from the tree as its been replaced by a newer version or is no longer required -171 silly removeObsoleteDep removing dashdash@1.14.1 from the tree as its been replaced by a newer version or is no longer required -172 silly removeObsoleteDep removing ecc-jsbn@0.1.2 from the tree as its been replaced by a newer version or is no longer required -173 silly removeObsoleteDep removing jsbn@0.1.1 from the tree as its been replaced by a newer version or is no longer required -174 silly removeObsoleteDep removing getpass@0.1.7 from the tree as its been replaced by a newer version or is no longer required -175 silly removeObsoleteDep removing is-typedarray@1.0.0 from the tree as its been replaced by a newer version or is no longer required -176 silly removeObsoleteDep removing isstream@0.1.2 from the tree as its been replaced by a newer version or is no longer required -177 silly removeObsoleteDep removing json-stringify-safe@5.0.1 from the tree as its been replaced by a newer version or is no longer required -178 silly removeObsoleteDep removing oauth-sign@0.9.0 from the tree as its been replaced by a newer version or is no longer required -179 silly removeObsoleteDep removing performance-now@2.1.0 from the tree as its been replaced by a newer version or is no longer required -180 silly removeObsoleteDep removing qs@6.5.2 from the tree as its been replaced by a newer version or is no longer required -181 silly removeObsoleteDep removing safe-buffer@5.2.1 from the tree as its been replaced by a newer version or is no longer required -182 silly removeObsoleteDep removing tough-cookie@2.5.0 from the tree as its been replaced by a newer version or is no longer required -183 silly removeObsoleteDep removing psl@1.8.0 from the tree as its been replaced by a newer version or is no longer required -184 silly removeObsoleteDep removing tunnel-agent@0.6.0 from the tree as its been replaced by a newer version or is no longer required -185 silly removeObsoleteDep removing uuid@3.4.0 from the tree as its been replaced by a newer version or is no longer required -186 silly removeObsoleteDep removing semver@5.3.0 from the tree as its been replaced by a newer version or is no longer required -187 silly removeObsoleteDep removing tar@2.2.2 from the tree as its been replaced by a newer version or is no longer required -188 silly removeObsoleteDep removing block-stream@0.0.9 from the tree as its been replaced by a newer version or is no longer required -189 silly removeObsoleteDep removing which@1.3.1 from the tree as its been replaced by a newer version or is no longer required -190 silly removeObsoleteDep removing isexe@2.0.0 from the tree as its been replaced by a newer version or is no longer required -191 silly removeObsoleteDep removing node-pre-gyp@0.11.0 from the tree as its been replaced by a newer version or is no longer required -192 silly removeObsoleteDep removing detect-libc@1.0.3 from the tree as its been replaced by a newer version or is no longer required -193 silly removeObsoleteDep removing needle@2.5.2 from the tree as its been replaced by a newer version or is no longer required -194 silly removeObsoleteDep removing debug@3.2.6 from the tree as its been replaced by a newer version or is no longer required -195 silly removeObsoleteDep removing ms@2.1.2 from the tree as its been replaced by a newer version or is no longer required -196 silly removeObsoleteDep removing iconv-lite@0.4.24 from the tree as its been replaced by a newer version or is no longer required -197 silly removeObsoleteDep removing sax@1.2.4 from the tree as its been replaced by a newer version or is no longer required -198 silly removeObsoleteDep removing nopt@4.0.3 from the tree as its been replaced by a newer version or is no longer required -199 silly removeObsoleteDep removing npm-packlist@1.4.8 from the tree as its been replaced by a newer version or is no longer required -200 silly removeObsoleteDep removing ignore-walk@3.0.3 from the tree as its been replaced by a newer version or is no longer required -201 silly removeObsoleteDep removing npm-bundled@1.1.1 from the tree as its been replaced by a newer version or is no longer required -202 silly removeObsoleteDep removing npm-normalize-package-bin@1.0.1 from the tree as its been replaced by a newer version or is no longer required -203 silly removeObsoleteDep removing rc@1.2.8 from the tree as its been replaced by a newer version or is no longer required -204 silly removeObsoleteDep removing deep-extend@0.6.0 from the tree as its been replaced by a newer version or is no longer required -205 silly removeObsoleteDep removing ini@1.3.5 from the tree as its been replaced by a newer version or is no longer required -206 silly removeObsoleteDep removing strip-json-comments@2.0.1 from the tree as its been replaced by a newer version or is no longer required -207 silly removeObsoleteDep removing tar@4.4.13 from the tree as its been replaced by a newer version or is no longer required -208 silly removeObsoleteDep removing chownr@1.1.4 from the tree as its been replaced by a newer version or is no longer required -209 silly removeObsoleteDep removing fs-minipass@1.2.7 from the tree as its been replaced by a newer version or is no longer required -210 silly removeObsoleteDep removing minipass@2.9.0 from the tree as its been replaced by a newer version or is no longer required -211 silly removeObsoleteDep removing yallist@3.1.1 from the tree as its been replaced by a newer version or is no longer required -212 silly removeObsoleteDep removing minizlib@1.3.3 from the tree as its been replaced by a newer version or is no longer required -213 silly removeObsoleteDep removing yargs@16.1.0 from the tree as its been replaced by a newer version or is no longer required -214 silly removeObsoleteDep removing cliui@7.0.3 from the tree as its been replaced by a newer version or is no longer required -215 silly removeObsoleteDep removing string-width@4.2.0 from the tree as its been replaced by a newer version or is no longer required -216 silly removeObsoleteDep removing emoji-regex@8.0.0 from the tree as its been replaced by a newer version or is no longer required -217 silly removeObsoleteDep removing is-fullwidth-code-point@3.0.0 from the tree as its been replaced by a newer version or is no longer required -218 silly removeObsoleteDep removing strip-ansi@6.0.0 from the tree as its been replaced by a newer version or is no longer required -219 silly removeObsoleteDep removing ansi-regex@5.0.0 from the tree as its been replaced by a newer version or is no longer required -220 silly removeObsoleteDep removing wrap-ansi@7.0.0 from the tree as its been replaced by a newer version or is no longer required -221 silly removeObsoleteDep removing ansi-styles@4.3.0 from the tree as its been replaced by a newer version or is no longer required -222 silly removeObsoleteDep removing color-convert@2.0.1 from the tree as its been replaced by a newer version or is no longer required -223 silly removeObsoleteDep removing color-name@1.1.4 from the tree as its been replaced by a newer version or is no longer required -224 silly removeObsoleteDep removing string-width@4.2.0 from the tree as its been replaced by a newer version or is no longer required -225 silly removeObsoleteDep removing is-fullwidth-code-point@3.0.0 from the tree as its been replaced by a newer version or is no longer required -226 silly removeObsoleteDep removing strip-ansi@6.0.0 from the tree as its been replaced by a newer version or is no longer required -227 silly removeObsoleteDep removing ansi-regex@5.0.0 from the tree as its been replaced by a newer version or is no longer required -228 silly removeObsoleteDep removing escalade@3.1.1 from the tree as its been replaced by a newer version or is no longer required -229 silly removeObsoleteDep removing get-caller-file@2.0.5 from the tree as its been replaced by a newer version or is no longer required -230 silly removeObsoleteDep removing require-directory@2.1.1 from the tree as its been replaced by a newer version or is no longer required -231 silly removeObsoleteDep removing string-width@4.2.0 from the tree as its been replaced by a newer version or is no longer required -232 silly removeObsoleteDep removing is-fullwidth-code-point@3.0.0 from the tree as its been replaced by a newer version or is no longer required -233 silly removeObsoleteDep removing strip-ansi@6.0.0 from the tree as its been replaced by a newer version or is no longer required -234 silly removeObsoleteDep removing ansi-regex@5.0.0 from the tree as its been replaced by a newer version or is no longer required -235 silly removeObsoleteDep removing y18n@5.0.5 from the tree as its been replaced by a newer version or is no longer required -236 silly removeObsoleteDep removing yargs-parser@20.2.3 from the tree as its been replaced by a newer version or is no longer required -237 timing stage:loadIdealTree:loadAllDepsIntoIdealTree Completed in 339ms -238 timing stage:loadIdealTree Completed in 441ms -239 silly currentTree scripts -239 silly currentTree └─┬ cic-client-meta@0.0.7-alpha.1 -239 silly currentTree ├── @ethereumjs/common@2.0.0-beta.1 -239 silly currentTree ├── @ethereumjs/tx@3.0.0-beta.1 -239 silly currentTree ├── @types/bn.js@4.11.6 -239 silly currentTree ├── @types/eslint-scope@3.7.0 -239 silly currentTree ├── @types/eslint@7.2.4 -239 silly currentTree ├── @types/estree@0.0.45 -239 silly currentTree ├── @types/json-schema@7.0.6 -239 silly currentTree ├── @types/mocha@8.0.3 -239 silly currentTree ├── @types/node@14.14.6 -239 silly currentTree ├── @types/pbkdf2@3.1.0 -239 silly currentTree ├── @types/secp256k1@4.0.1 -239 silly currentTree ├── @ungap/promise-all-settled@1.1.2 -239 silly currentTree ├── @webassemblyjs/ast@1.9.0 -239 silly currentTree ├── @webassemblyjs/floating-point-hex-parser@1.9.0 -239 silly currentTree ├── @webassemblyjs/helper-api-error@1.9.0 -239 silly currentTree ├── @webassemblyjs/helper-buffer@1.9.0 -239 silly currentTree ├── @webassemblyjs/helper-code-frame@1.9.0 -239 silly currentTree ├── @webassemblyjs/helper-fsm@1.9.0 -239 silly currentTree ├── @webassemblyjs/helper-module-context@1.9.0 -239 silly currentTree ├── @webassemblyjs/helper-wasm-bytecode@1.9.0 -239 silly currentTree ├── @webassemblyjs/helper-wasm-section@1.9.0 -239 silly currentTree ├── @webassemblyjs/ieee754@1.9.0 -239 silly currentTree ├── @webassemblyjs/leb128@1.9.0 -239 silly currentTree ├── @webassemblyjs/utf8@1.9.0 -239 silly currentTree ├── @webassemblyjs/wasm-edit@1.9.0 -239 silly currentTree ├── @webassemblyjs/wasm-gen@1.9.0 -239 silly currentTree ├── @webassemblyjs/wasm-opt@1.9.0 -239 silly currentTree ├── @webassemblyjs/wasm-parser@1.9.0 -239 silly currentTree ├── @webassemblyjs/wast-parser@1.9.0 -239 silly currentTree ├── @webassemblyjs/wast-printer@1.9.0 -239 silly currentTree ├── @webpack-cli/info@1.1.0 -239 silly currentTree ├── @webpack-cli/serve@1.1.0 -239 silly currentTree ├── @xtuc/ieee754@1.2.0 -239 silly currentTree ├── @xtuc/long@4.2.2 -239 silly currentTree ├── abbrev@1.1.1 -239 silly currentTree ├── acorn@8.0.4 -239 silly currentTree ├── aes-js@3.1.2 -239 silly currentTree ├── ajv-keywords@3.5.2 -239 silly currentTree ├── ajv@6.12.6 -239 silly currentTree ├── ansi-colors@4.1.1 -239 silly currentTree ├── ansi-regex@2.1.1 -239 silly currentTree ├── ansi-styles@4.3.0 -239 silly currentTree ├── anymatch@3.1.1 -239 silly currentTree ├── aproba@1.2.0 -239 silly currentTree ├─┬ are-we-there-yet@1.1.5 -239 silly currentTree │ ├── readable-stream@2.3.7 -239 silly currentTree │ ├── safe-buffer@5.1.2 -239 silly currentTree │ └── string_decoder@1.1.1 -239 silly currentTree ├── arg@4.1.3 -239 silly currentTree ├── argparse@1.0.10 -239 silly currentTree ├── array-back@4.0.1 -239 silly currentTree ├── asn1.js@5.4.1 -239 silly currentTree ├── asn1@0.2.4 -239 silly currentTree ├── assert-plus@1.0.0 -239 silly currentTree ├── asynckit@0.4.0 -239 silly currentTree ├── automerge@0.14.1 -239 silly currentTree ├── aws-sign2@0.7.0 -239 silly currentTree ├── aws4@1.11.0 -239 silly currentTree ├── balanced-match@1.0.0 -239 silly currentTree ├── base-x@3.0.8 -239 silly currentTree ├── bcrypt-pbkdf@1.0.2 -239 silly currentTree ├── binary-extensions@2.1.0 -239 silly currentTree ├── blakejs@1.1.0 -239 silly currentTree ├── block-stream@0.0.9 -239 silly currentTree ├── bn.js@4.11.9 -239 silly currentTree ├── brace-expansion@1.1.11 -239 silly currentTree ├── braces@3.0.2 -239 silly currentTree ├── brorand@1.1.0 -239 silly currentTree ├── browser-stdout@1.3.1 -239 silly currentTree ├── browserify-aes@1.2.0 -239 silly currentTree ├── browserslist@4.14.6 -239 silly currentTree ├── bs58@4.0.1 -239 silly currentTree ├── bs58check@2.1.2 -239 silly currentTree ├── buffer-from@1.1.1 -239 silly currentTree ├── buffer-writer@2.0.0 -239 silly currentTree ├── buffer-xor@1.0.3 -239 silly currentTree ├── camelcase@5.3.1 -239 silly currentTree ├── caniuse-lite@1.0.30001156 -239 silly currentTree ├── caseless@0.12.0 -239 silly currentTree ├── chalk@4.1.0 -239 silly currentTree ├── chokidar@3.4.3 -239 silly currentTree ├── chownr@1.1.4 -239 silly currentTree ├── chrome-trace-event@1.0.2 -239 silly currentTree ├── cipher-base@1.0.4 -239 silly currentTree ├─┬ cliui@7.0.3 -239 silly currentTree │ ├── ansi-regex@5.0.0 -239 silly currentTree │ ├── is-fullwidth-code-point@3.0.0 -239 silly currentTree │ ├── string-width@4.2.0 -239 silly currentTree │ └── strip-ansi@6.0.0 -239 silly currentTree ├── code-point-at@1.1.0 -239 silly currentTree ├── color-convert@2.0.1 -239 silly currentTree ├── color-name@1.1.4 -239 silly currentTree ├── colorette@1.2.1 -239 silly currentTree ├── combined-stream@1.0.8 -239 silly currentTree ├─┬ command-line-usage@6.1.0 -239 silly currentTree │ ├── ansi-styles@3.2.1 -239 silly currentTree │ ├── chalk@2.4.2 -239 silly currentTree │ ├── color-convert@1.9.3 -239 silly currentTree │ ├── color-name@1.1.3 -239 silly currentTree │ ├── escape-string-regexp@1.0.5 -239 silly currentTree │ ├── has-flag@3.0.0 -239 silly currentTree │ └── supports-color@5.5.0 -239 silly currentTree ├── commander@2.20.3 -239 silly currentTree ├── concat-map@0.0.1 -239 silly currentTree ├── console-control-strings@1.1.0 -239 silly currentTree ├── core-util-is@1.0.2 -239 silly currentTree ├── crc-32@1.2.0 -239 silly currentTree ├── create-hash@1.2.0 -239 silly currentTree ├── create-hmac@1.1.7 -239 silly currentTree ├─┬ cross-spawn@7.0.3 -239 silly currentTree │ └── which@2.0.2 -239 silly currentTree ├── dashdash@1.14.1 -239 silly currentTree ├── debug@3.2.6 -239 silly currentTree ├── decamelize@1.2.0 -239 silly currentTree ├── deep-extend@0.6.0 -239 silly currentTree ├── delayed-stream@1.0.0 -239 silly currentTree ├── delegates@1.0.0 -239 silly currentTree ├── detect-libc@1.0.3 -239 silly currentTree ├── diff@4.0.2 -239 silly currentTree ├── ecc-jsbn@0.1.2 -239 silly currentTree ├── electron-to-chromium@1.3.591 -239 silly currentTree ├── elliptic@6.5.3 -239 silly currentTree ├── emoji-regex@8.0.0 -239 silly currentTree ├── end-of-stream@1.4.4 -239 silly currentTree ├── enhanced-resolve@5.3.1 -239 silly currentTree ├── enquirer@2.3.6 -239 silly currentTree ├── envinfo@7.7.3 -239 silly currentTree ├── escalade@3.1.1 -239 silly currentTree ├── escape-string-regexp@4.0.0 -239 silly currentTree ├── eslint-scope@5.1.1 -239 silly currentTree ├── esprima@4.0.1 -239 silly currentTree ├─┬ esrecurse@4.3.0 -239 silly currentTree │ └── estraverse@5.2.0 -239 silly currentTree ├── estraverse@4.3.0 -239 silly currentTree ├── ethereum-cryptography@0.1.3 -239 silly currentTree ├─┬ ethereumjs-util@7.0.7 -239 silly currentTree │ └── bn.js@5.1.3 -239 silly currentTree ├── ethereumjs-wallet@1.0.1 -239 silly currentTree ├── ethjs-util@0.1.6 -239 silly currentTree ├── events@3.2.0 -239 silly currentTree ├── evp_bytestokey@1.0.3 -239 silly currentTree ├── execa@4.1.0 -239 silly currentTree ├── exit-on-epipe@1.0.1 -239 silly currentTree ├── extend@3.0.2 -239 silly currentTree ├── extsprintf@1.3.0 -239 silly currentTree ├── fast-deep-equal@3.1.3 -239 silly currentTree ├── fast-json-stable-stringify@2.1.0 -239 silly currentTree ├── fill-range@7.0.1 -239 silly currentTree ├── find-up@5.0.0 -239 silly currentTree ├── flat@5.0.2 -239 silly currentTree ├── forever-agent@0.6.1 -239 silly currentTree ├── form-data@2.3.3 -239 silly currentTree ├── fs-minipass@1.2.7 -239 silly currentTree ├── fs.realpath@1.0.0 -239 silly currentTree ├── fstream@1.0.12 -239 silly currentTree ├── function-bind@1.1.1 -239 silly currentTree ├── gauge@2.7.4 -239 silly currentTree ├── get-caller-file@2.0.5 -239 silly currentTree ├── get-stream@5.2.0 -239 silly currentTree ├── getpass@0.1.7 -239 silly currentTree ├── glob-parent@5.1.1 -239 silly currentTree ├── glob-to-regexp@0.4.1 -239 silly currentTree ├── glob@7.1.6 -239 silly currentTree ├── graceful-fs@4.2.4 -239 silly currentTree ├── growl@1.10.5 -239 silly currentTree ├── har-schema@2.0.0 -239 silly currentTree ├── har-validator@5.1.5 -239 silly currentTree ├── has-flag@4.0.0 -239 silly currentTree ├── has-unicode@2.0.1 -239 silly currentTree ├── has@1.0.3 -239 silly currentTree ├── hash-base@3.1.0 -239 silly currentTree ├── hash.js@1.1.7 -239 silly currentTree ├── he@1.2.0 -239 silly currentTree ├── hmac-drbg@1.0.1 -239 silly currentTree ├── http-signature@1.2.0 -239 silly currentTree ├── human-signals@1.1.1 -239 silly currentTree ├── iconv-lite@0.4.24 -239 silly currentTree ├── ignore-walk@3.0.3 -239 silly currentTree ├── immutable@3.8.2 -239 silly currentTree ├── import-local@3.0.2 -239 silly currentTree ├── imurmurhash@0.1.4 -239 silly currentTree ├── inflight@1.0.6 -239 silly currentTree ├── inherits@2.0.4 -239 silly currentTree ├── ini@1.3.5 -239 silly currentTree ├── interpret@2.2.0 -239 silly currentTree ├── is-binary-path@2.1.0 -239 silly currentTree ├── is-core-module@2.1.0 -239 silly currentTree ├── is-extglob@2.1.1 -239 silly currentTree ├── is-fullwidth-code-point@1.0.0 -239 silly currentTree ├── is-glob@4.0.1 -239 silly currentTree ├── is-hex-prefixed@1.0.0 -239 silly currentTree ├── is-number@7.0.0 -239 silly currentTree ├── is-plain-obj@2.1.0 -239 silly currentTree ├── is-stream@2.0.0 -239 silly currentTree ├── is-typedarray@1.0.0 -239 silly currentTree ├── isarray@1.0.0 -239 silly currentTree ├── isexe@2.0.0 -239 silly currentTree ├── isstream@0.1.2 -239 silly currentTree ├── jest-worker@26.6.2 -239 silly currentTree ├── js-yaml@3.14.0 -239 silly currentTree ├── jsbn@0.1.1 -239 silly currentTree ├── json-parse-better-errors@1.0.2 -239 silly currentTree ├── json-schema-traverse@0.4.1 -239 silly currentTree ├── json-schema@0.2.3 -239 silly currentTree ├── json-stringify-safe@5.0.1 -239 silly currentTree ├── jsprim@1.4.1 -239 silly currentTree ├── keccak@3.0.1 -239 silly currentTree ├── leven@3.1.0 -239 silly currentTree ├── loader-runner@4.1.0 -239 silly currentTree ├── locate-path@6.0.0 -239 silly currentTree ├── lodash@4.17.20 -239 silly currentTree ├── log-symbols@4.0.0 -239 silly currentTree ├── make-error@1.3.6 -239 silly currentTree ├── md5.js@1.3.5 -239 silly currentTree ├── merge-stream@2.0.0 -239 silly currentTree ├── mime-db@1.44.0 -239 silly currentTree ├── mime-types@2.1.27 -239 silly currentTree ├── mimic-fn@2.1.0 -239 silly currentTree ├── minimalistic-assert@1.0.1 -239 silly currentTree ├── minimalistic-crypto-utils@1.0.1 -239 silly currentTree ├── minimatch@3.0.4 -239 silly currentTree ├── minimist@1.2.5 -239 silly currentTree ├── minipass@2.9.0 -239 silly currentTree ├── minizlib@1.3.3 -239 silly currentTree ├── mkdirp@0.5.5 -239 silly currentTree ├─┬ mocha@8.2.1 -239 silly currentTree │ ├── ansi-regex@4.1.0 -239 silly currentTree │ ├── ansi-styles@3.2.1 -239 silly currentTree │ ├── cliui@5.0.0 -239 silly currentTree │ ├── color-convert@1.9.3 -239 silly currentTree │ ├── color-name@1.1.3 -239 silly currentTree │ ├── debug@4.2.0 -239 silly currentTree │ ├── emoji-regex@7.0.3 -239 silly currentTree │ ├── is-fullwidth-code-point@2.0.0 -239 silly currentTree │ ├── locate-path@3.0.0 -239 silly currentTree │ ├── p-limit@2.3.0 -239 silly currentTree │ ├── p-locate@3.0.0 -239 silly currentTree │ ├── path-exists@3.0.0 -239 silly currentTree │ ├── string-width@3.1.0 -239 silly currentTree │ ├── strip-ansi@5.2.0 -239 silly currentTree │ ├── strip-json-comments@3.1.1 -239 silly currentTree │ ├── which@2.0.2 -239 silly currentTree │ ├── wrap-ansi@5.1.0 -239 silly currentTree │ ├── y18n@4.0.0 -239 silly currentTree │ ├── yargs-parser@13.1.2 -239 silly currentTree │ └─┬ yargs@13.3.2 -239 silly currentTree │ └── find-up@3.0.0 -239 silly currentTree ├── ms@2.1.2 -239 silly currentTree ├── nanoid@3.1.12 -239 silly currentTree ├── needle@2.5.2 -239 silly currentTree ├── neo-async@2.6.2 -239 silly currentTree ├── node-addon-api@2.0.0 -239 silly currentTree ├── node-fetch@2.6.1 -239 silly currentTree ├── node-gyp-build@4.2.3 -239 silly currentTree ├── node-gyp@3.8.0 -239 silly currentTree ├── node-localstorage@2.1.6 -239 silly currentTree ├─┬ node-pre-gyp@0.11.0 -239 silly currentTree │ ├── nopt@4.0.3 -239 silly currentTree │ └── tar@4.4.13 -239 silly currentTree ├── node-releases@1.1.66 -239 silly currentTree ├── nopt@3.0.6 -239 silly currentTree ├── normalize-path@3.0.0 -239 silly currentTree ├── npm-bundled@1.1.1 -239 silly currentTree ├── npm-normalize-package-bin@1.0.1 -239 silly currentTree ├── npm-packlist@1.4.8 -239 silly currentTree ├── npm-run-path@4.0.1 -239 silly currentTree ├── npmlog@4.1.2 -239 silly currentTree ├── number-is-nan@1.0.1 -239 silly currentTree ├── oauth-sign@0.9.0 -239 silly currentTree ├── object-assign@4.1.1 -239 silly currentTree ├── once@1.4.0 -239 silly currentTree ├── onetime@5.1.2 -239 silly currentTree ├─┬ openpgp@4.10.8 -239 silly currentTree │ └── node-localstorage@1.3.1 -239 silly currentTree ├── os-homedir@1.0.2 -239 silly currentTree ├── os-tmpdir@1.0.2 -239 silly currentTree ├── osenv@0.1.5 -239 silly currentTree ├── p-limit@3.0.2 -239 silly currentTree ├── p-locate@5.0.0 -239 silly currentTree ├── p-try@2.2.0 -239 silly currentTree ├── packet-reader@1.0.0 -239 silly currentTree ├── path-exists@4.0.0 -239 silly currentTree ├── path-is-absolute@1.0.1 -239 silly currentTree ├── path-key@3.1.1 -239 silly currentTree ├── path-parse@1.0.6 -239 silly currentTree ├── pbkdf2@3.1.1 -239 silly currentTree ├── performance-now@2.1.0 -239 silly currentTree ├── pg-connection-string@2.4.0 -239 silly currentTree ├── pg-int8@1.0.1 -239 silly currentTree ├── pg-pool@3.2.2 -239 silly currentTree ├── pg-protocol@1.3.0 -239 silly currentTree ├── pg-types@2.2.0 -239 silly currentTree ├── pg@8.4.2 -239 silly currentTree ├── pgpass@1.0.4 -239 silly currentTree ├── picomatch@2.2.2 -239 silly currentTree ├─┬ pkg-dir@4.2.0 -239 silly currentTree │ ├── find-up@4.1.0 -239 silly currentTree │ ├── locate-path@5.0.0 -239 silly currentTree │ ├── p-limit@2.3.0 -239 silly currentTree │ └── p-locate@4.1.0 -239 silly currentTree ├── postgres-array@2.0.0 -239 silly currentTree ├── postgres-bytea@1.0.0 -239 silly currentTree ├── postgres-date@1.0.7 -239 silly currentTree ├── postgres-interval@1.2.0 -239 silly currentTree ├── printj@1.1.2 -239 silly currentTree ├── process-nextick-args@2.0.1 -239 silly currentTree ├── psl@1.8.0 -239 silly currentTree ├── pump@3.0.0 -239 silly currentTree ├── punycode@2.1.1 -239 silly currentTree ├── qs@6.5.2 -239 silly currentTree ├── randombytes@2.1.0 -239 silly currentTree ├── rc@1.2.8 -239 silly currentTree ├── readable-stream@3.6.0 -239 silly currentTree ├── readdirp@3.5.0 -239 silly currentTree ├── rechoir@0.7.0 -239 silly currentTree ├── reduce-flatten@2.0.0 -239 silly currentTree ├── request@2.88.2 -239 silly currentTree ├── require-directory@2.1.1 -239 silly currentTree ├── require-main-filename@2.0.0 -239 silly currentTree ├── resolve-cwd@3.0.0 -239 silly currentTree ├── resolve-from@5.0.0 -239 silly currentTree ├── resolve@1.18.1 -239 silly currentTree ├── rimraf@2.7.1 -239 silly currentTree ├── ripemd160@2.0.2 -239 silly currentTree ├── rlp@2.2.6 -239 silly currentTree ├── safe-buffer@5.2.1 -239 silly currentTree ├── safer-buffer@2.1.2 -239 silly currentTree ├── sax@1.2.4 -239 silly currentTree ├── schema-utils@3.0.0 -239 silly currentTree ├── scrypt-js@3.0.1 -239 silly currentTree ├── secp256k1@4.0.2 -239 silly currentTree ├── semver@5.3.0 -239 silly currentTree ├── serialize-javascript@5.0.1 -239 silly currentTree ├── set-blocking@2.0.0 -239 silly currentTree ├── setimmediate@1.0.5 -239 silly currentTree ├── sha.js@2.4.11 -239 silly currentTree ├── shebang-command@2.0.0 -239 silly currentTree ├── shebang-regex@3.0.0 -239 silly currentTree ├── signal-exit@3.0.3 -239 silly currentTree ├── slide@1.1.6 -239 silly currentTree ├── source-list-map@2.0.1 -239 silly currentTree ├── source-map-support@0.5.19 -239 silly currentTree ├── source-map@0.6.1 -239 silly currentTree ├── split2@3.2.2 -239 silly currentTree ├── sprintf-js@1.0.3 -239 silly currentTree ├── sqlite3@5.0.0 -239 silly currentTree ├── sshpk@1.16.1 -239 silly currentTree ├── string_decoder@1.3.0 -239 silly currentTree ├── string-width@1.0.2 -239 silly currentTree ├── strip-ansi@3.0.1 -239 silly currentTree ├── strip-final-newline@2.0.0 -239 silly currentTree ├── strip-hex-prefix@1.0.0 -239 silly currentTree ├── strip-json-comments@2.0.1 -239 silly currentTree ├── supports-color@7.2.0 -239 silly currentTree ├── table-layout@1.0.1 -239 silly currentTree ├── tapable@2.0.0 -239 silly currentTree ├── tar@2.2.2 -239 silly currentTree ├── terser-webpack-plugin@5.0.3 -239 silly currentTree ├─┬ terser@5.3.8 -239 silly currentTree │ └── source-map@0.7.3 -239 silly currentTree ├── to-regex-range@5.0.1 -239 silly currentTree ├── tough-cookie@2.5.0 -239 silly currentTree ├── transit-immutable-js@0.7.0 -239 silly currentTree ├── transit-js@0.8.867 -239 silly currentTree ├── ts-node@9.0.0 -239 silly currentTree ├── tslib@1.14.1 -239 silly currentTree ├── tunnel-agent@0.6.0 -239 silly currentTree ├── tweetnacl@0.14.5 -239 silly currentTree ├── typescript@4.0.5 -239 silly currentTree ├── typical@5.2.0 -239 silly currentTree ├── uri-js@4.4.0 -239 silly currentTree ├── utf8@3.0.0 -239 silly currentTree ├── util-deprecate@1.0.2 -239 silly currentTree ├── uuid@3.4.0 -239 silly currentTree ├── v8-compile-cache@2.2.0 -239 silly currentTree ├── verror@1.10.0 -239 silly currentTree ├── watchpack@2.0.1 -239 silly currentTree ├─┬ webpack-cli@4.2.0 -239 silly currentTree │ └── commander@6.2.0 -239 silly currentTree ├── webpack-merge@4.2.2 -239 silly currentTree ├── webpack-sources@2.2.0 -239 silly currentTree ├── webpack@5.4.0 -239 silly currentTree ├── which-module@2.0.0 -239 silly currentTree ├── which@1.3.1 -239 silly currentTree ├── wide-align@1.1.3 -239 silly currentTree ├── wordwrapjs@4.0.0 -239 silly currentTree ├── workerpool@6.0.2 -239 silly currentTree ├─┬ wrap-ansi@7.0.0 -239 silly currentTree │ ├── ansi-regex@5.0.0 -239 silly currentTree │ ├── is-fullwidth-code-point@3.0.0 -239 silly currentTree │ ├── string-width@4.2.0 -239 silly currentTree │ └── strip-ansi@6.0.0 -239 silly currentTree ├── wrappy@1.0.2 -239 silly currentTree ├── write-file-atomic@1.3.4 -239 silly currentTree ├── xtend@4.0.2 -239 silly currentTree ├── y18n@5.0.5 -239 silly currentTree ├── yallist@3.1.1 -239 silly currentTree ├── yargs-parser@20.2.3 -239 silly currentTree ├─┬ yargs-unparser@2.0.0 -239 silly currentTree │ ├── camelcase@6.2.0 -239 silly currentTree │ └── decamelize@4.0.0 -239 silly currentTree ├─┬ yargs@16.1.0 -239 silly currentTree │ ├── ansi-regex@5.0.0 -239 silly currentTree │ ├── is-fullwidth-code-point@3.0.0 -239 silly currentTree │ ├── string-width@4.2.0 -239 silly currentTree │ └── strip-ansi@6.0.0 -239 silly currentTree └── yn@3.1.1 -240 silly idealTree scripts -240 silly idealTree └─┬ cic-client-meta@0.0.7-alpha.1 -240 silly idealTree ├── @ethereumjs/common@2.0.0-beta.1 -240 silly idealTree ├── @ethereumjs/tx@3.0.0-beta.1 -240 silly idealTree ├── @types/bn.js@4.11.6 -240 silly idealTree ├── @types/eslint-scope@3.7.0 -240 silly idealTree ├── @types/eslint@7.2.4 -240 silly idealTree ├── @types/estree@0.0.45 -240 silly idealTree ├── @types/json-schema@7.0.6 -240 silly idealTree ├── @types/mocha@8.0.3 -240 silly idealTree ├── @types/node@14.14.6 -240 silly idealTree ├── @types/pbkdf2@3.1.0 -240 silly idealTree ├── @types/secp256k1@4.0.1 -240 silly idealTree ├── @ungap/promise-all-settled@1.1.2 -240 silly idealTree ├── @webassemblyjs/ast@1.9.0 -240 silly idealTree ├── @webassemblyjs/floating-point-hex-parser@1.9.0 -240 silly idealTree ├── @webassemblyjs/helper-api-error@1.9.0 -240 silly idealTree ├── @webassemblyjs/helper-buffer@1.9.0 -240 silly idealTree ├── @webassemblyjs/helper-code-frame@1.9.0 -240 silly idealTree ├── @webassemblyjs/helper-fsm@1.9.0 -240 silly idealTree ├── @webassemblyjs/helper-module-context@1.9.0 -240 silly idealTree ├── @webassemblyjs/helper-wasm-bytecode@1.9.0 -240 silly idealTree ├── @webassemblyjs/helper-wasm-section@1.9.0 -240 silly idealTree ├── @webassemblyjs/ieee754@1.9.0 -240 silly idealTree ├── @webassemblyjs/leb128@1.9.0 -240 silly idealTree ├── @webassemblyjs/utf8@1.9.0 -240 silly idealTree ├── @webassemblyjs/wasm-edit@1.9.0 -240 silly idealTree ├── @webassemblyjs/wasm-gen@1.9.0 -240 silly idealTree ├── @webassemblyjs/wasm-opt@1.9.0 -240 silly idealTree ├── @webassemblyjs/wasm-parser@1.9.0 -240 silly idealTree ├── @webassemblyjs/wast-parser@1.9.0 -240 silly idealTree ├── @webassemblyjs/wast-printer@1.9.0 -240 silly idealTree ├── @webpack-cli/info@1.1.0 -240 silly idealTree ├── @webpack-cli/serve@1.1.0 -240 silly idealTree ├── @xtuc/ieee754@1.2.0 -240 silly idealTree ├── @xtuc/long@4.2.2 -240 silly idealTree ├── abbrev@1.1.1 -240 silly idealTree ├── acorn@8.0.4 -240 silly idealTree ├── aes-js@3.1.2 -240 silly idealTree ├── ajv-keywords@3.5.2 -240 silly idealTree ├── ajv@6.12.6 -240 silly idealTree ├── ansi-colors@4.1.1 -240 silly idealTree ├── ansi-regex@2.1.1 -240 silly idealTree ├── ansi-styles@4.3.0 -240 silly idealTree ├── anymatch@3.1.1 -240 silly idealTree ├── aproba@1.2.0 -240 silly idealTree ├─┬ are-we-there-yet@1.1.5 -240 silly idealTree │ ├── readable-stream@2.3.7 -240 silly idealTree │ ├── safe-buffer@5.1.2 -240 silly idealTree │ └── string_decoder@1.1.1 -240 silly idealTree ├── arg@4.1.3 -240 silly idealTree ├── argparse@1.0.10 -240 silly idealTree ├── array-back@4.0.1 -240 silly idealTree ├── asn1.js@5.4.1 -240 silly idealTree ├── asn1@0.2.4 -240 silly idealTree ├── assert-plus@1.0.0 -240 silly idealTree ├── asynckit@0.4.0 -240 silly idealTree ├── automerge@0.14.1 -240 silly idealTree ├── aws-sign2@0.7.0 -240 silly idealTree ├── aws4@1.11.0 -240 silly idealTree ├── balanced-match@1.0.0 -240 silly idealTree ├── base-x@3.0.8 -240 silly idealTree ├── bcrypt-pbkdf@1.0.2 -240 silly idealTree ├── binary-extensions@2.1.0 -240 silly idealTree ├── blakejs@1.1.0 -240 silly idealTree ├── block-stream@0.0.9 -240 silly idealTree ├── bn.js@4.11.9 -240 silly idealTree ├── brace-expansion@1.1.11 -240 silly idealTree ├── braces@3.0.2 -240 silly idealTree ├── brorand@1.1.0 -240 silly idealTree ├── browser-stdout@1.3.1 -240 silly idealTree ├── browserify-aes@1.2.0 -240 silly idealTree ├── browserslist@4.14.6 -240 silly idealTree ├── bs58@4.0.1 -240 silly idealTree ├── bs58check@2.1.2 -240 silly idealTree ├── buffer-from@1.1.1 -240 silly idealTree ├── buffer-writer@2.0.0 -240 silly idealTree ├── buffer-xor@1.0.3 -240 silly idealTree ├── camelcase@5.3.1 -240 silly idealTree ├── caniuse-lite@1.0.30001156 -240 silly idealTree ├── caseless@0.12.0 -240 silly idealTree ├── chalk@4.1.0 -240 silly idealTree ├── chokidar@3.4.3 -240 silly idealTree ├── chownr@1.1.4 -240 silly idealTree ├── chrome-trace-event@1.0.2 -240 silly idealTree ├── cipher-base@1.0.4 -240 silly idealTree ├─┬ cliui@7.0.3 -240 silly idealTree │ ├── ansi-regex@5.0.0 -240 silly idealTree │ ├── is-fullwidth-code-point@3.0.0 -240 silly idealTree │ ├── string-width@4.2.0 -240 silly idealTree │ └── strip-ansi@6.0.0 -240 silly idealTree ├── code-point-at@1.1.0 -240 silly idealTree ├── color-convert@2.0.1 -240 silly idealTree ├── color-name@1.1.4 -240 silly idealTree ├── colorette@1.2.1 -240 silly idealTree ├── combined-stream@1.0.8 -240 silly idealTree ├─┬ command-line-usage@6.1.0 -240 silly idealTree │ ├── ansi-styles@3.2.1 -240 silly idealTree │ ├── chalk@2.4.2 -240 silly idealTree │ ├── color-convert@1.9.3 -240 silly idealTree │ ├── color-name@1.1.3 -240 silly idealTree │ ├── escape-string-regexp@1.0.5 -240 silly idealTree │ ├── has-flag@3.0.0 -240 silly idealTree │ └── supports-color@5.5.0 -240 silly idealTree ├── commander@2.20.3 -240 silly idealTree ├── concat-map@0.0.1 -240 silly idealTree ├── console-control-strings@1.1.0 -240 silly idealTree ├── core-util-is@1.0.2 -240 silly idealTree ├── crc-32@1.2.0 -240 silly idealTree ├── create-hash@1.2.0 -240 silly idealTree ├── create-hmac@1.1.7 -240 silly idealTree ├─┬ cross-spawn@7.0.3 -240 silly idealTree │ └── which@2.0.2 -240 silly idealTree ├── dashdash@1.14.1 -240 silly idealTree ├── debug@3.2.6 -240 silly idealTree ├── decamelize@1.2.0 -240 silly idealTree ├── deep-extend@0.6.0 -240 silly idealTree ├── delayed-stream@1.0.0 -240 silly idealTree ├── delegates@1.0.0 -240 silly idealTree ├── detect-libc@1.0.3 -240 silly idealTree ├── diff@4.0.2 -240 silly idealTree ├── ecc-jsbn@0.1.2 -240 silly idealTree ├── electron-to-chromium@1.3.591 -240 silly idealTree ├── elliptic@6.5.3 -240 silly idealTree ├── emoji-regex@8.0.0 -240 silly idealTree ├── end-of-stream@1.4.4 -240 silly idealTree ├── enhanced-resolve@5.3.1 -240 silly idealTree ├── enquirer@2.3.6 -240 silly idealTree ├── envinfo@7.7.3 -240 silly idealTree ├── escalade@3.1.1 -240 silly idealTree ├── escape-string-regexp@4.0.0 -240 silly idealTree ├── eslint-scope@5.1.1 -240 silly idealTree ├── esprima@4.0.1 -240 silly idealTree ├─┬ esrecurse@4.3.0 -240 silly idealTree │ └── estraverse@5.2.0 -240 silly idealTree ├── estraverse@4.3.0 -240 silly idealTree ├── ethereum-cryptography@0.1.3 -240 silly idealTree ├─┬ ethereumjs-util@7.0.7 -240 silly idealTree │ └── bn.js@5.1.3 -240 silly idealTree ├── ethereumjs-wallet@1.0.1 -240 silly idealTree ├── ethjs-util@0.1.6 -240 silly idealTree ├── events@3.2.0 -240 silly idealTree ├── evp_bytestokey@1.0.3 -240 silly idealTree ├── execa@4.1.0 -240 silly idealTree ├── exit-on-epipe@1.0.1 -240 silly idealTree ├── extend@3.0.2 -240 silly idealTree ├── extsprintf@1.3.0 -240 silly idealTree ├── fast-deep-equal@3.1.3 -240 silly idealTree ├── fast-json-stable-stringify@2.1.0 -240 silly idealTree ├── fill-range@7.0.1 -240 silly idealTree ├── find-up@5.0.0 -240 silly idealTree ├── flat@5.0.2 -240 silly idealTree ├── forever-agent@0.6.1 -240 silly idealTree ├── form-data@2.3.3 -240 silly idealTree ├── fs-minipass@1.2.7 -240 silly idealTree ├── fs.realpath@1.0.0 -240 silly idealTree ├── fstream@1.0.12 -240 silly idealTree ├── function-bind@1.1.1 -240 silly idealTree ├── gauge@2.7.4 -240 silly idealTree ├── get-caller-file@2.0.5 -240 silly idealTree ├── get-stream@5.2.0 -240 silly idealTree ├── getpass@0.1.7 -240 silly idealTree ├── glob-parent@5.1.1 -240 silly idealTree ├── glob-to-regexp@0.4.1 -240 silly idealTree ├── glob@7.1.6 -240 silly idealTree ├── graceful-fs@4.2.4 -240 silly idealTree ├── growl@1.10.5 -240 silly idealTree ├── har-schema@2.0.0 -240 silly idealTree ├── har-validator@5.1.5 -240 silly idealTree ├── has-flag@4.0.0 -240 silly idealTree ├── has-unicode@2.0.1 -240 silly idealTree ├── has@1.0.3 -240 silly idealTree ├── hash-base@3.1.0 -240 silly idealTree ├── hash.js@1.1.7 -240 silly idealTree ├── he@1.2.0 -240 silly idealTree ├── hmac-drbg@1.0.1 -240 silly idealTree ├── http-signature@1.2.0 -240 silly idealTree ├── human-signals@1.1.1 -240 silly idealTree ├── iconv-lite@0.4.24 -240 silly idealTree ├── ignore-walk@3.0.3 -240 silly idealTree ├── immutable@3.8.2 -240 silly idealTree ├── import-local@3.0.2 -240 silly idealTree ├── imurmurhash@0.1.4 -240 silly idealTree ├── inflight@1.0.6 -240 silly idealTree ├── inherits@2.0.4 -240 silly idealTree ├── ini@1.3.5 -240 silly idealTree ├── interpret@2.2.0 -240 silly idealTree ├── is-binary-path@2.1.0 -240 silly idealTree ├── is-core-module@2.1.0 -240 silly idealTree ├── is-extglob@2.1.1 -240 silly idealTree ├── is-fullwidth-code-point@1.0.0 -240 silly idealTree ├── is-glob@4.0.1 -240 silly idealTree ├── is-hex-prefixed@1.0.0 -240 silly idealTree ├── is-number@7.0.0 -240 silly idealTree ├── is-plain-obj@2.1.0 -240 silly idealTree ├── is-stream@2.0.0 -240 silly idealTree ├── is-typedarray@1.0.0 -240 silly idealTree ├── isarray@1.0.0 -240 silly idealTree ├── isexe@2.0.0 -240 silly idealTree ├── isstream@0.1.2 -240 silly idealTree ├── jest-worker@26.6.2 -240 silly idealTree ├── js-yaml@3.14.0 -240 silly idealTree ├── jsbn@0.1.1 -240 silly idealTree ├── json-parse-better-errors@1.0.2 -240 silly idealTree ├── json-schema-traverse@0.4.1 -240 silly idealTree ├── json-schema@0.2.3 -240 silly idealTree ├── json-stringify-safe@5.0.1 -240 silly idealTree ├── jsprim@1.4.1 -240 silly idealTree ├── keccak@3.0.1 -240 silly idealTree ├── leven@3.1.0 -240 silly idealTree ├── loader-runner@4.1.0 -240 silly idealTree ├── locate-path@6.0.0 -240 silly idealTree ├── lodash@4.17.20 -240 silly idealTree ├── log-symbols@4.0.0 -240 silly idealTree ├── make-error@1.3.6 -240 silly idealTree ├── md5.js@1.3.5 -240 silly idealTree ├── merge-stream@2.0.0 -240 silly idealTree ├── mime-db@1.44.0 -240 silly idealTree ├── mime-types@2.1.27 -240 silly idealTree ├── mimic-fn@2.1.0 -240 silly idealTree ├── minimalistic-assert@1.0.1 -240 silly idealTree ├── minimalistic-crypto-utils@1.0.1 -240 silly idealTree ├── minimatch@3.0.4 -240 silly idealTree ├── minimist@1.2.5 -240 silly idealTree ├── minipass@2.9.0 -240 silly idealTree ├── minizlib@1.3.3 -240 silly idealTree ├── mkdirp@0.5.5 -240 silly idealTree ├─┬ mocha@8.2.1 -240 silly idealTree │ ├── ansi-regex@4.1.0 -240 silly idealTree │ ├── ansi-styles@3.2.1 -240 silly idealTree │ ├── cliui@5.0.0 -240 silly idealTree │ ├── color-convert@1.9.3 -240 silly idealTree │ ├── color-name@1.1.3 -240 silly idealTree │ ├── debug@4.2.0 -240 silly idealTree │ ├── emoji-regex@7.0.3 -240 silly idealTree │ ├── is-fullwidth-code-point@2.0.0 -240 silly idealTree │ ├── locate-path@3.0.0 -240 silly idealTree │ ├── p-limit@2.3.0 -240 silly idealTree │ ├── p-locate@3.0.0 -240 silly idealTree │ ├── path-exists@3.0.0 -240 silly idealTree │ ├── string-width@3.1.0 -240 silly idealTree │ ├── strip-ansi@5.2.0 -240 silly idealTree │ ├── strip-json-comments@3.1.1 -240 silly idealTree │ ├── which@2.0.2 -240 silly idealTree │ ├── wrap-ansi@5.1.0 -240 silly idealTree │ ├── y18n@4.0.0 -240 silly idealTree │ ├── yargs-parser@13.1.2 -240 silly idealTree │ └─┬ yargs@13.3.2 -240 silly idealTree │ └── find-up@3.0.0 -240 silly idealTree ├── ms@2.1.2 -240 silly idealTree ├── nanoid@3.1.12 -240 silly idealTree ├── needle@2.5.2 -240 silly idealTree ├── neo-async@2.6.2 -240 silly idealTree ├── node-addon-api@2.0.0 -240 silly idealTree ├── node-fetch@2.6.1 -240 silly idealTree ├── node-gyp-build@4.2.3 -240 silly idealTree ├── node-gyp@3.8.0 -240 silly idealTree ├── node-localstorage@2.1.6 -240 silly idealTree ├─┬ node-pre-gyp@0.11.0 -240 silly idealTree │ ├── nopt@4.0.3 -240 silly idealTree │ └── tar@4.4.13 -240 silly idealTree ├── node-releases@1.1.66 -240 silly idealTree ├── nopt@3.0.6 -240 silly idealTree ├── normalize-path@3.0.0 -240 silly idealTree ├── npm-bundled@1.1.1 -240 silly idealTree ├── npm-normalize-package-bin@1.0.1 -240 silly idealTree ├── npm-packlist@1.4.8 -240 silly idealTree ├── npm-run-path@4.0.1 -240 silly idealTree ├── npmlog@4.1.2 -240 silly idealTree ├── number-is-nan@1.0.1 -240 silly idealTree ├── oauth-sign@0.9.0 -240 silly idealTree ├── object-assign@4.1.1 -240 silly idealTree ├── once@1.4.0 -240 silly idealTree ├── onetime@5.1.2 -240 silly idealTree ├─┬ openpgp@4.10.8 -240 silly idealTree │ └── node-localstorage@1.3.1 -240 silly idealTree ├── os-homedir@1.0.2 -240 silly idealTree ├── os-tmpdir@1.0.2 -240 silly idealTree ├── osenv@0.1.5 -240 silly idealTree ├── p-limit@3.0.2 -240 silly idealTree ├── p-locate@5.0.0 -240 silly idealTree ├── p-try@2.2.0 -240 silly idealTree ├── packet-reader@1.0.0 -240 silly idealTree ├── path-exists@4.0.0 -240 silly idealTree ├── path-is-absolute@1.0.1 -240 silly idealTree ├── path-key@3.1.1 -240 silly idealTree ├── path-parse@1.0.6 -240 silly idealTree ├── pbkdf2@3.1.1 -240 silly idealTree ├── performance-now@2.1.0 -240 silly idealTree ├── pg-connection-string@2.4.0 -240 silly idealTree ├── pg-int8@1.0.1 -240 silly idealTree ├── pg-pool@3.2.2 -240 silly idealTree ├── pg-protocol@1.3.0 -240 silly idealTree ├── pg-types@2.2.0 -240 silly idealTree ├── pg@8.4.2 -240 silly idealTree ├── pgpass@1.0.4 -240 silly idealTree ├── picomatch@2.2.2 -240 silly idealTree ├─┬ pkg-dir@4.2.0 -240 silly idealTree │ ├── find-up@4.1.0 -240 silly idealTree │ ├── locate-path@5.0.0 -240 silly idealTree │ ├── p-limit@2.3.0 -240 silly idealTree │ └── p-locate@4.1.0 -240 silly idealTree ├── postgres-array@2.0.0 -240 silly idealTree ├── postgres-bytea@1.0.0 -240 silly idealTree ├── postgres-date@1.0.7 -240 silly idealTree ├── postgres-interval@1.2.0 -240 silly idealTree ├── printj@1.1.2 -240 silly idealTree ├── process-nextick-args@2.0.1 -240 silly idealTree ├── psl@1.8.0 -240 silly idealTree ├── pump@3.0.0 -240 silly idealTree ├── punycode@2.1.1 -240 silly idealTree ├── qs@6.5.2 -240 silly idealTree ├── randombytes@2.1.0 -240 silly idealTree ├── rc@1.2.8 -240 silly idealTree ├── readable-stream@3.6.0 -240 silly idealTree ├── readdirp@3.5.0 -240 silly idealTree ├── rechoir@0.7.0 -240 silly idealTree ├── reduce-flatten@2.0.0 -240 silly idealTree ├── request@2.88.2 -240 silly idealTree ├── require-directory@2.1.1 -240 silly idealTree ├── require-main-filename@2.0.0 -240 silly idealTree ├── resolve-cwd@3.0.0 -240 silly idealTree ├── resolve-from@5.0.0 -240 silly idealTree ├── resolve@1.18.1 -240 silly idealTree ├── rimraf@2.7.1 -240 silly idealTree ├── ripemd160@2.0.2 -240 silly idealTree ├── rlp@2.2.6 -240 silly idealTree ├── safe-buffer@5.2.1 -240 silly idealTree ├── safer-buffer@2.1.2 -240 silly idealTree ├── sax@1.2.4 -240 silly idealTree ├── schema-utils@3.0.0 -240 silly idealTree ├── scrypt-js@3.0.1 -240 silly idealTree ├── secp256k1@4.0.2 -240 silly idealTree ├── semver@5.3.0 -240 silly idealTree ├── serialize-javascript@5.0.1 -240 silly idealTree ├── set-blocking@2.0.0 -240 silly idealTree ├── setimmediate@1.0.5 -240 silly idealTree ├── sha.js@2.4.11 -240 silly idealTree ├── shebang-command@2.0.0 -240 silly idealTree ├── shebang-regex@3.0.0 -240 silly idealTree ├── signal-exit@3.0.3 -240 silly idealTree ├── slide@1.1.6 -240 silly idealTree ├── source-list-map@2.0.1 -240 silly idealTree ├── source-map-support@0.5.19 -240 silly idealTree ├── source-map@0.6.1 -240 silly idealTree ├── split2@3.2.2 -240 silly idealTree ├── sprintf-js@1.0.3 -240 silly idealTree ├── sqlite3@5.0.0 -240 silly idealTree ├── sshpk@1.16.1 -240 silly idealTree ├── string_decoder@1.3.0 -240 silly idealTree ├── string-width@1.0.2 -240 silly idealTree ├── strip-ansi@3.0.1 -240 silly idealTree ├── strip-final-newline@2.0.0 -240 silly idealTree ├── strip-hex-prefix@1.0.0 -240 silly idealTree ├── strip-json-comments@2.0.1 -240 silly idealTree ├── supports-color@7.2.0 -240 silly idealTree ├── table-layout@1.0.1 -240 silly idealTree ├── tapable@2.0.0 -240 silly idealTree ├── tar@2.2.2 -240 silly idealTree ├── terser-webpack-plugin@5.0.3 -240 silly idealTree ├─┬ terser@5.3.8 -240 silly idealTree │ └── source-map@0.7.3 -240 silly idealTree ├── to-regex-range@5.0.1 -240 silly idealTree ├── tough-cookie@2.5.0 -240 silly idealTree ├── transit-immutable-js@0.7.0 -240 silly idealTree ├── transit-js@0.8.867 -240 silly idealTree ├── ts-node@9.0.0 -240 silly idealTree ├── tslib@1.14.1 -240 silly idealTree ├── tunnel-agent@0.6.0 -240 silly idealTree ├── tweetnacl@0.14.5 -240 silly idealTree ├── typescript@4.0.5 -240 silly idealTree ├── typical@5.2.0 -240 silly idealTree ├── uri-js@4.4.0 -240 silly idealTree ├── utf8@3.0.0 -240 silly idealTree ├── util-deprecate@1.0.2 -240 silly idealTree ├── uuid@3.4.0 -240 silly idealTree ├── v8-compile-cache@2.2.0 -240 silly idealTree ├── verror@1.10.0 -240 silly idealTree ├── watchpack@2.0.1 -240 silly idealTree ├─┬ webpack-cli@4.2.0 -240 silly idealTree │ └── commander@6.2.0 -240 silly idealTree ├── webpack-merge@4.2.2 -240 silly idealTree ├── webpack-sources@2.2.0 -240 silly idealTree ├── webpack@5.4.0 -240 silly idealTree ├── which-module@2.0.0 -240 silly idealTree ├── which@1.3.1 -240 silly idealTree ├── wide-align@1.1.3 -240 silly idealTree ├── wordwrapjs@4.0.0 -240 silly idealTree ├── workerpool@6.0.2 -240 silly idealTree ├─┬ wrap-ansi@7.0.0 -240 silly idealTree │ ├── ansi-regex@5.0.0 -240 silly idealTree │ ├── is-fullwidth-code-point@3.0.0 -240 silly idealTree │ ├── string-width@4.2.0 -240 silly idealTree │ └── strip-ansi@6.0.0 -240 silly idealTree ├── wrappy@1.0.2 -240 silly idealTree ├── write-file-atomic@1.3.4 -240 silly idealTree ├── xtend@4.0.2 -240 silly idealTree ├── y18n@5.0.5 -240 silly idealTree ├── yallist@3.1.1 -240 silly idealTree ├── yargs-parser@20.2.3 -240 silly idealTree ├─┬ yargs-unparser@2.0.0 -240 silly idealTree │ ├── camelcase@6.2.0 -240 silly idealTree │ └── decamelize@4.0.0 -240 silly idealTree ├─┬ yargs@16.1.0 -240 silly idealTree │ ├── ansi-regex@5.0.0 -240 silly idealTree │ ├── is-fullwidth-code-point@3.0.0 -240 silly idealTree │ ├── string-width@4.2.0 -240 silly idealTree │ └── strip-ansi@6.0.0 -240 silly idealTree └── yn@3.1.1 -241 silly install generateActionsToTake -242 timing stage:generateActionsToTake Completed in 13ms -243 silly diffTrees action count 1 -244 silly diffTrees update cic-client-meta@0.0.7-alpha.1 -245 silly decomposeActions action count 8 -246 silly decomposeActions unbuild cic-client-meta@0.0.7-alpha.1 -247 silly decomposeActions remove cic-client-meta@0.0.7-alpha.1 -248 silly decomposeActions preinstall cic-client-meta@0.0.7-alpha.1 -249 silly decomposeActions build cic-client-meta@0.0.7-alpha.1 -250 silly decomposeActions install cic-client-meta@0.0.7-alpha.1 -251 silly decomposeActions postinstall cic-client-meta@0.0.7-alpha.1 -252 silly decomposeActions finalize cic-client-meta@0.0.7-alpha.1 -253 silly decomposeActions refresh-package-json cic-client-meta@0.0.7-alpha.1 -254 silly install executeActions -255 silly doSerial global-install 8 -256 verbose correctMkdir /home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/contract-migration/scripts/false/_locks correctMkdir not in flight; initializing -257 verbose lock using /home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/contract-migration/scripts/false/_locks/staging-5da34164c06d3d08.lock for /home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/contract-migration/scripts/node_modules/.staging -258 silly doParallel extract 0 -259 silly doReverseSerial unbuild 8 -260 silly unbuild cic-client-meta@0.0.7-alpha.1 -261 info lifecycle cic-client-meta@0.0.7-alpha.1~preuninstall: cic-client-meta@0.0.7-alpha.1 -262 info lifecycle cic-client-meta@0.0.7-alpha.1~uninstall: cic-client-meta@0.0.7-alpha.1 -263 verbose unbuild rmStuff cic-client-meta@0.0.7-alpha.1 from /home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/contract-migration/scripts/node_modules -264 silly isEverInside /home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/contract-migration/scripts/node_modules/cic-client-meta is not inside /usr -265 silly isEverInside /home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/cic-meta is not inside /usr -266 silly isEverInside /home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/contract-migration/scripts/node_modules/cic-client-meta is not inside /usr/bin -267 silly isEverInside /home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/cic-meta is not inside /usr/bin -268 silly isEverInside /home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/contract-migration/scripts/node_modules/cic-client-meta is not inside /usr/lib/node_modules -269 silly isEverInside /home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/cic-meta is not inside /usr/lib/node_modules -270 info lifecycle cic-client-meta@0.0.7-alpha.1~postuninstall: cic-client-meta@0.0.7-alpha.1 -271 timing action:unbuild Completed in 5ms -272 silly doSerial remove 8 -273 silly remove /home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/contract-migration/scripts/node_modules/cic-client-meta -274 timing action:remove Completed in 1ms -275 silly doSerial move 8 -276 silly doSerial finalize 8 -277 silly finalize /home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/cic-meta -278 timing action:finalize Completed in 0ms -279 silly doParallel refresh-package-json 1 -280 silly refresh-package-json /home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/cic-meta -281 timing action:refresh-package-json Completed in 2ms -282 silly doParallel preinstall 1 -283 silly preinstall cic-client-meta@0.0.7-alpha.1 -284 info lifecycle cic-client-meta@0.0.7-alpha.1~preinstall: cic-client-meta@0.0.7-alpha.1 -285 timing action:preinstall Completed in 0ms -286 silly doSerial build 8 -287 silly build cic-client-meta@0.0.7-alpha.1 -288 info linkStuff cic-client-meta@0.0.7-alpha.1 -289 silly linkStuff cic-client-meta@0.0.7-alpha.1 has /home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/contract-migration/scripts/node_modules as its parent node_modules -290 verbose linkBins [ -290 verbose linkBins { 'cic-meta-server': 'dist-server/scripts/server/server.js' }, -290 verbose linkBins '/home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/contract-migration/scripts/node_modules/.bin', -290 verbose linkBins false -290 verbose linkBins ] -291 timing action:build Completed in 2ms -292 verbose unlock done using /home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/contract-migration/scripts/false/_locks/staging-5da34164c06d3d08.lock for /home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/contract-migration/scripts/node_modules/.staging -293 timing stage:rollbackFailedOptional Completed in 0ms -294 timing stage:runTopLevelLifecycles Completed in 1000ms -295 silly saveTree scripts -295 silly saveTree └─┬ cic-client-meta@0.0.7-alpha.1 -295 silly saveTree ├─┬ @ethereumjs/tx@3.0.0-beta.1 -295 silly saveTree │ ├─┬ @ethereumjs/common@2.0.0-beta.1 -295 silly saveTree │ │ └─┬ crc-32@1.2.0 -295 silly saveTree │ │ ├── exit-on-epipe@1.0.1 -295 silly saveTree │ │ └── printj@1.1.2 -295 silly saveTree │ └─┬ ethereumjs-util@7.0.7 -295 silly saveTree │ ├─┬ @types/bn.js@4.11.6 -295 silly saveTree │ │ └── @types/node@14.14.6 -295 silly saveTree │ ├── bn.js@5.1.3 -295 silly saveTree │ ├─┬ create-hash@1.2.0 -295 silly saveTree │ │ ├─┬ cipher-base@1.0.4 -295 silly saveTree │ │ │ ├── inherits@2.0.4 -295 silly saveTree │ │ │ └── safe-buffer@5.2.1 -295 silly saveTree │ │ ├── inherits@2.0.4 -295 silly saveTree │ │ ├─┬ md5.js@1.3.5 -295 silly saveTree │ │ │ └─┬ hash-base@3.1.0 -295 silly saveTree │ │ │ └─┬ readable-stream@3.6.0 -295 silly saveTree │ │ │ ├── string_decoder@1.3.0 -295 silly saveTree │ │ │ └── util-deprecate@1.0.2 -295 silly saveTree │ │ ├── ripemd160@2.0.2 -295 silly saveTree │ │ └── sha.js@2.4.11 -295 silly saveTree │ ├─┬ ethereum-cryptography@0.1.3 -295 silly saveTree │ │ ├── @types/pbkdf2@3.1.0 -295 silly saveTree │ │ ├── @types/secp256k1@4.0.1 -295 silly saveTree │ │ ├── blakejs@1.1.0 -295 silly saveTree │ │ ├─┬ browserify-aes@1.2.0 -295 silly saveTree │ │ │ ├── buffer-xor@1.0.3 -295 silly saveTree │ │ │ └── evp_bytestokey@1.0.3 -295 silly saveTree │ │ ├─┬ bs58check@2.1.2 -295 silly saveTree │ │ │ └─┬ bs58@4.0.1 -295 silly saveTree │ │ │ └── base-x@3.0.8 -295 silly saveTree │ │ ├── create-hmac@1.1.7 -295 silly saveTree │ │ ├─┬ hash.js@1.1.7 -295 silly saveTree │ │ │ └── minimalistic-assert@1.0.1 -295 silly saveTree │ │ ├─┬ keccak@3.0.1 -295 silly saveTree │ │ │ ├── node-addon-api@2.0.0 -295 silly saveTree │ │ │ └── node-gyp-build@4.2.3 -295 silly saveTree │ │ ├── pbkdf2@3.1.1 -295 silly saveTree │ │ ├── randombytes@2.1.0 -295 silly saveTree │ │ ├── scrypt-js@3.0.1 -295 silly saveTree │ │ ├─┬ secp256k1@4.0.2 -295 silly saveTree │ │ │ └─┬ elliptic@6.5.3 -295 silly saveTree │ │ │ ├── bn.js@4.11.9 -295 silly saveTree │ │ │ ├── brorand@1.1.0 -295 silly saveTree │ │ │ ├─┬ hmac-drbg@1.0.1 -295 silly saveTree │ │ │ │ └── minimalistic-crypto-utils@1.0.1 -295 silly saveTree │ │ │ └── minimalistic-crypto-utils@1.0.1 -295 silly saveTree │ │ └── setimmediate@1.0.5 -295 silly saveTree │ ├─┬ ethjs-util@0.1.6 -295 silly saveTree │ │ ├── is-hex-prefixed@1.0.0 -295 silly saveTree │ │ └── strip-hex-prefix@1.0.0 -295 silly saveTree │ └── rlp@2.2.6 -295 silly saveTree ├─┬ automerge@0.14.1 -295 silly saveTree │ ├── immutable@3.8.2 -295 silly saveTree │ ├── transit-immutable-js@0.7.0 -295 silly saveTree │ ├── transit-js@0.8.867 -295 silly saveTree │ └── uuid@3.4.0 -295 silly saveTree ├─┬ ethereumjs-wallet@1.0.1 -295 silly saveTree │ ├── aes-js@3.1.2 -295 silly saveTree │ └── utf8@3.0.0 -295 silly saveTree ├── ini@1.3.5 -295 silly saveTree ├─┬ openpgp@4.10.8 -295 silly saveTree │ ├─┬ asn1.js@5.4.1 -295 silly saveTree │ │ └── safer-buffer@2.1.2 -295 silly saveTree │ ├── node-fetch@2.6.1 -295 silly saveTree │ └─┬ node-localstorage@1.3.1 -295 silly saveTree │ └─┬ write-file-atomic@1.3.4 -295 silly saveTree │ ├── graceful-fs@4.2.4 -295 silly saveTree │ ├── imurmurhash@0.1.4 -295 silly saveTree │ └── slide@1.1.6 -295 silly saveTree ├─┬ pg@8.4.2 -295 silly saveTree │ ├── buffer-writer@2.0.0 -295 silly saveTree │ ├── packet-reader@1.0.0 -295 silly saveTree │ ├── pg-connection-string@2.4.0 -295 silly saveTree │ ├── pg-pool@3.2.2 -295 silly saveTree │ ├── pg-protocol@1.3.0 -295 silly saveTree │ ├─┬ pg-types@2.2.0 -295 silly saveTree │ │ ├── pg-int8@1.0.1 -295 silly saveTree │ │ ├── postgres-array@2.0.0 -295 silly saveTree │ │ ├── postgres-bytea@1.0.0 -295 silly saveTree │ │ ├── postgres-date@1.0.7 -295 silly saveTree │ │ └─┬ postgres-interval@1.2.0 -295 silly saveTree │ │ └── xtend@4.0.2 -295 silly saveTree │ └─┬ pgpass@1.0.4 -295 silly saveTree │ └── split2@3.2.2 -295 silly saveTree ├─┬ sqlite3@5.0.0 -295 silly saveTree │ ├─┬ node-gyp@3.8.0 -295 silly saveTree │ │ ├─┬ fstream@1.0.12 -295 silly saveTree │ │ │ ├─┬ mkdirp@0.5.5 -295 silly saveTree │ │ │ │ └── minimist@1.2.5 -295 silly saveTree │ │ │ └─┬ rimraf@2.7.1 -295 silly saveTree │ │ │ └─┬ glob@7.1.6 -295 silly saveTree │ │ │ ├── fs.realpath@1.0.0 -295 silly saveTree │ │ │ ├─┬ inflight@1.0.6 -295 silly saveTree │ │ │ │ ├─┬ once@1.4.0 -295 silly saveTree │ │ │ │ │ └── wrappy@1.0.2 -295 silly saveTree │ │ │ │ └── wrappy@1.0.2 -295 silly saveTree │ │ │ ├─┬ minimatch@3.0.4 -295 silly saveTree │ │ │ │ └─┬ brace-expansion@1.1.11 -295 silly saveTree │ │ │ │ ├── balanced-match@1.0.0 -295 silly saveTree │ │ │ │ └── concat-map@0.0.1 -295 silly saveTree │ │ │ ├── once@1.4.0 -295 silly saveTree │ │ │ └── path-is-absolute@1.0.1 -295 silly saveTree │ │ ├── glob@7.1.6 -295 silly saveTree │ │ ├── mkdirp@0.5.5 -295 silly saveTree │ │ ├─┬ nopt@3.0.6 -295 silly saveTree │ │ │ └── abbrev@1.1.1 -295 silly saveTree │ │ ├─┬ npmlog@4.1.2 -295 silly saveTree │ │ │ ├─┬ are-we-there-yet@1.1.5 -295 silly saveTree │ │ │ │ ├── delegates@1.0.0 -295 silly saveTree │ │ │ │ └─┬ readable-stream@2.3.7 -295 silly saveTree │ │ │ │ ├── core-util-is@1.0.2 -295 silly saveTree │ │ │ │ ├── isarray@1.0.0 -295 silly saveTree │ │ │ │ ├── process-nextick-args@2.0.1 -295 silly saveTree │ │ │ │ ├── safe-buffer@5.1.2 -295 silly saveTree │ │ │ │ └── string_decoder@1.1.1 -295 silly saveTree │ │ │ ├── console-control-strings@1.1.0 -295 silly saveTree │ │ │ ├─┬ gauge@2.7.4 -295 silly saveTree │ │ │ │ ├── aproba@1.2.0 -295 silly saveTree │ │ │ │ ├── has-unicode@2.0.1 -295 silly saveTree │ │ │ │ ├── object-assign@4.1.1 -295 silly saveTree │ │ │ │ ├── signal-exit@3.0.3 -295 silly saveTree │ │ │ │ ├─┬ string-width@1.0.2 -295 silly saveTree │ │ │ │ │ ├── code-point-at@1.1.0 -295 silly saveTree │ │ │ │ │ ├─┬ is-fullwidth-code-point@1.0.0 -295 silly saveTree │ │ │ │ │ │ └── number-is-nan@1.0.1 -295 silly saveTree │ │ │ │ │ └─┬ strip-ansi@3.0.1 -295 silly saveTree │ │ │ │ │ └── ansi-regex@2.1.1 -295 silly saveTree │ │ │ │ ├── strip-ansi@3.0.1 -295 silly saveTree │ │ │ │ └── wide-align@1.1.3 -295 silly saveTree │ │ │ └── set-blocking@2.0.0 -295 silly saveTree │ │ ├─┬ osenv@0.1.5 -295 silly saveTree │ │ │ ├── os-homedir@1.0.2 -295 silly saveTree │ │ │ └── os-tmpdir@1.0.2 -295 silly saveTree │ │ ├─┬ request@2.88.2 -295 silly saveTree │ │ │ ├── aws-sign2@0.7.0 -295 silly saveTree │ │ │ ├── aws4@1.11.0 -295 silly saveTree │ │ │ ├── caseless@0.12.0 -295 silly saveTree │ │ │ ├─┬ combined-stream@1.0.8 -295 silly saveTree │ │ │ │ └── delayed-stream@1.0.0 -295 silly saveTree │ │ │ ├── extend@3.0.2 -295 silly saveTree │ │ │ ├── forever-agent@0.6.1 -295 silly saveTree │ │ │ ├─┬ form-data@2.3.3 -295 silly saveTree │ │ │ │ ├── asynckit@0.4.0 -295 silly saveTree │ │ │ │ └─┬ mime-types@2.1.27 -295 silly saveTree │ │ │ │ └── mime-db@1.44.0 -295 silly saveTree │ │ │ ├─┬ har-validator@5.1.5 -295 silly saveTree │ │ │ │ ├─┬ ajv@6.12.6 -295 silly saveTree │ │ │ │ │ ├── fast-deep-equal@3.1.3 -295 silly saveTree │ │ │ │ │ ├── fast-json-stable-stringify@2.1.0 -295 silly saveTree │ │ │ │ │ ├── json-schema-traverse@0.4.1 -295 silly saveTree │ │ │ │ │ └─┬ uri-js@4.4.0 -295 silly saveTree │ │ │ │ │ └── punycode@2.1.1 -295 silly saveTree │ │ │ │ └── har-schema@2.0.0 -295 silly saveTree │ │ │ ├─┬ http-signature@1.2.0 -295 silly saveTree │ │ │ │ ├── assert-plus@1.0.0 -295 silly saveTree │ │ │ │ ├─┬ jsprim@1.4.1 -295 silly saveTree │ │ │ │ │ ├── extsprintf@1.3.0 -295 silly saveTree │ │ │ │ │ ├── json-schema@0.2.3 -295 silly saveTree │ │ │ │ │ └── verror@1.10.0 -295 silly saveTree │ │ │ │ └─┬ sshpk@1.16.1 -295 silly saveTree │ │ │ │ ├── asn1@0.2.4 -295 silly saveTree │ │ │ │ ├─┬ bcrypt-pbkdf@1.0.2 -295 silly saveTree │ │ │ │ │ └── tweetnacl@0.14.5 -295 silly saveTree │ │ │ │ ├── dashdash@1.14.1 -295 silly saveTree │ │ │ │ ├─┬ ecc-jsbn@0.1.2 -295 silly saveTree │ │ │ │ │ └── jsbn@0.1.1 -295 silly saveTree │ │ │ │ ├── getpass@0.1.7 -295 silly saveTree │ │ │ │ ├── jsbn@0.1.1 -295 silly saveTree │ │ │ │ └── tweetnacl@0.14.5 -295 silly saveTree │ │ │ ├── is-typedarray@1.0.0 -295 silly saveTree │ │ │ ├── isstream@0.1.2 -295 silly saveTree │ │ │ ├── json-stringify-safe@5.0.1 -295 silly saveTree │ │ │ ├── mime-types@2.1.27 -295 silly saveTree │ │ │ ├── oauth-sign@0.9.0 -295 silly saveTree │ │ │ ├── performance-now@2.1.0 -295 silly saveTree │ │ │ ├── qs@6.5.2 -295 silly saveTree │ │ │ ├─┬ tough-cookie@2.5.0 -295 silly saveTree │ │ │ │ └── psl@1.8.0 -295 silly saveTree │ │ │ └── tunnel-agent@0.6.0 -295 silly saveTree │ │ ├── rimraf@2.7.1 -295 silly saveTree │ │ ├── semver@5.3.0 -295 silly saveTree │ │ ├─┬ tar@2.2.2 -295 silly saveTree │ │ │ └── block-stream@0.0.9 -295 silly saveTree │ │ └─┬ which@1.3.1 -295 silly saveTree │ │ └── isexe@2.0.0 -295 silly saveTree │ └─┬ node-pre-gyp@0.11.0 -295 silly saveTree │ ├── detect-libc@1.0.3 -295 silly saveTree │ ├─┬ needle@2.5.2 -295 silly saveTree │ │ ├─┬ debug@3.2.6 -295 silly saveTree │ │ │ └── ms@2.1.2 -295 silly saveTree │ │ ├── iconv-lite@0.4.24 -295 silly saveTree │ │ └── sax@1.2.4 -295 silly saveTree │ ├── nopt@4.0.3 -295 silly saveTree │ ├─┬ npm-packlist@1.4.8 -295 silly saveTree │ │ ├── ignore-walk@3.0.3 -295 silly saveTree │ │ ├─┬ npm-bundled@1.1.1 -295 silly saveTree │ │ │ └── npm-normalize-package-bin@1.0.1 -295 silly saveTree │ │ └── npm-normalize-package-bin@1.0.1 -295 silly saveTree │ ├─┬ rc@1.2.8 -295 silly saveTree │ │ ├── deep-extend@0.6.0 -295 silly saveTree │ │ └── strip-json-comments@2.0.1 -295 silly saveTree │ └─┬ tar@4.4.13 -295 silly saveTree │ ├── chownr@1.1.4 -295 silly saveTree │ ├─┬ fs-minipass@1.2.7 -295 silly saveTree │ │ └─┬ minipass@2.9.0 -295 silly saveTree │ │ └── yallist@3.1.1 -295 silly saveTree │ ├── minipass@2.9.0 -295 silly saveTree │ ├── minizlib@1.3.3 -295 silly saveTree │ └── yallist@3.1.1 -295 silly saveTree └─┬ yargs@16.1.0 -295 silly saveTree ├─┬ cliui@7.0.3 -295 silly saveTree │ ├─┬ string-width@4.2.0 -295 silly saveTree │ │ ├── emoji-regex@8.0.0 -295 silly saveTree │ │ ├── is-fullwidth-code-point@3.0.0 -295 silly saveTree │ │ └─┬ strip-ansi@6.0.0 -295 silly saveTree │ │ └── ansi-regex@5.0.0 -295 silly saveTree │ ├── strip-ansi@6.0.0 -295 silly saveTree │ └─┬ wrap-ansi@7.0.0 -295 silly saveTree │ ├─┬ ansi-styles@4.3.0 -295 silly saveTree │ │ └─┬ color-convert@2.0.1 -295 silly saveTree │ │ └── color-name@1.1.4 -295 silly saveTree │ ├─┬ string-width@4.2.0 -295 silly saveTree │ │ ├── is-fullwidth-code-point@3.0.0 -295 silly saveTree │ │ └─┬ strip-ansi@6.0.0 -295 silly saveTree │ │ └── ansi-regex@5.0.0 -295 silly saveTree │ └── strip-ansi@6.0.0 -295 silly saveTree ├── escalade@3.1.1 -295 silly saveTree ├── get-caller-file@2.0.5 -295 silly saveTree ├── require-directory@2.1.1 -295 silly saveTree ├─┬ string-width@4.2.0 -295 silly saveTree │ ├── is-fullwidth-code-point@3.0.0 -295 silly saveTree │ └─┬ strip-ansi@6.0.0 -295 silly saveTree │ └── ansi-regex@5.0.0 -295 silly saveTree ├── y18n@5.0.5 -295 silly saveTree └── yargs-parser@20.2.3 -296 warn notsup Unsupported engine for cic-client-meta@0.0.7-alpha.1: wanted: {"node":"~15.3.0"} (current: {"node":"15.6.0","npm":"6.14.11"}) -297 warn notsup Not compatible with your version of node/npm: cic-client-meta@0.0.7-alpha.1 -298 verbose notsup Not compatible with your version of node/npm: cic-client-meta@0.0.7-alpha.1 -298 verbose notsup Required: {"node":"~15.3.0"} -298 verbose notsup Actual: {"npm":"6.14.11","node":"15.6.0"} -299 warn enoent ENOENT: no such file or directory, open '/home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/contract-migration/scripts/package.json' -300 verbose enoent This is related to npm not being able to find a file. -301 warn scripts No description -302 warn scripts No repository field. -303 warn scripts No README data -304 warn scripts No license field. -305 verbose stack Error: ENOENT: no such file or directory, chmod '/home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/contract-migration/scripts/node_modules/cic-client-meta/dist-server/scripts/server/server.js' -306 verbose cwd /home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/contract-migration/scripts -307 verbose Linux 5.10.8-arch1-1 -308 verbose argv "/usr/bin/node" "/usr/bin/npm" "install" "--no-cache" "../../../apps/cic-meta" -309 verbose node v15.6.0 -310 verbose npm v6.14.11 -311 error code ENOENT -312 error syscall chmod -313 error path /home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/contract-migration/scripts/node_modules/cic-client-meta/dist-server/scripts/server/server.js -314 error errno -2 -315 error enoent ENOENT: no such file or directory, chmod '/home/lash/src/ext/cic/grassrootseconomics/cic-internal-integration/apps/contract-migration/scripts/node_modules/cic-client-meta/dist-server/scripts/server/server.js' -316 error enoent This is related to npm not being able to find a file. -317 verbose exit [ -2, true ] diff --git a/apps/contract-migration/scripts/false/anonymous-cli-metrics.json b/apps/contract-migration/scripts/false/anonymous-cli-metrics.json deleted file mode 100644 index bd2344ca..00000000 --- a/apps/contract-migration/scripts/false/anonymous-cli-metrics.json +++ /dev/null @@ -1 +0,0 @@ -{"metricId":"ea11447f-da1c-49e6-b0a2-8a988a99e3ce","metrics":{"from":"2021-02-12T18:59:21.666Z","to":"2021-02-12T18:59:21.666Z","successfulInstalls":0,"failedInstalls":1}} \ No newline at end of file diff --git a/apps/contract-migration/scripts/import_balance.sh b/apps/contract-migration/scripts/import_balance.sh deleted file mode 100644 index 8db2632d..00000000 --- a/apps/contract-migration/scripts/import_balance.sh +++ /dev/null @@ -1 +0,0 @@ -python import_balance.py -c config -i evm:bloxberg:8996 -y /home/lash/tmp/d/keystore/UTC--2021-02-07T09-58-35.341813355Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c -v $@ diff --git a/apps/contract-migration/scripts/import_users.sh b/apps/contract-migration/scripts/import_users.sh deleted file mode 100644 index 38507b70..00000000 --- a/apps/contract-migration/scripts/import_users.sh +++ /dev/null @@ -1 +0,0 @@ -python import_users.py -c config --redis-host-callback redis -vv $@ diff --git a/apps/contract-migration/scripts/package-lock.json b/apps/contract-migration/scripts/package-lock.json index d2d7ed32..9737db2f 100644 --- a/apps/contract-migration/scripts/package-lock.json +++ b/apps/contract-migration/scripts/package-lock.json @@ -1,6 +1,2088 @@ { + "name": "scripts", + "lockfileVersion": 2, "requires": true, - "lockfileVersion": 1, + "packages": { + "": { + "dependencies": { + "cic-client-meta": "^0.0.7-alpha.5", + "vcard-parser": "^1.0.0" + } + }, + "node_modules/@ethereumjs/common": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.0.0.tgz", + "integrity": "sha512-yL0zA7Xwgz8IFHKW0VoXGjdZDVxUJg8BQ/muMHvYPW7zHJNNC80gQmvLH+MpvIg1TCXZkFXxrpYRAyCElSm+aw==", + "dependencies": { + "crc-32": "^1.2.0" + } + }, + "node_modules/@ethereumjs/tx": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.0.2.tgz", + "integrity": "sha512-zmFCosjOdj1WoYEiQBdC4sCOAllBEwxdKuY85L9FgZ4zVDfZUVsQ4S9paczt4hVt65A7N8sJwgVEzDaQmrRaqw==", + "dependencies": { + "@ethereumjs/common": "^2.0.0", + "ethereumjs-util": "^7.0.8" + } + }, + "node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "14.14.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.30.tgz", + "integrity": "sha512-gUWhy8s45fQp4PqqKecsnOkdW0kt1IaKjgOIR3HPokkzTmQj9ji2wWFID5THu1MKrtO+d4s2lVrlEhXUsPXSvg==" + }, + "node_modules/@types/pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/secp256k1": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.1.tgz", + "integrity": "sha512-+ZjSA8ELlOp8SlKi0YLB2tz9d5iPNEmOBd+8Rz21wTMdaXQIa9b6TEnD6l5qKOCypE7FSyPyck12qZJxSDNoog==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/aes-js": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.1.2.tgz", + "integrity": "sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==" + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "optional": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "node_modules/are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/are-we-there-yet/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/are-we-there-yet/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "optional": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "optional": true + }, + "node_modules/automerge": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/automerge/-/automerge-0.14.2.tgz", + "integrity": "sha512-shiwuJHCbNRI23WZyIECLV4Ovf3WiAFJ7P9BH4l5gON1In/UUbjcSJKRygtIirObw2UQumeYxp3F2XBdSvQHnA==", + "dependencies": { + "immutable": "^3.8.2", + "transit-immutable-js": "^0.7.0", + "transit-js": "^0.8.861", + "uuid": "^3.4.0" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "optional": true + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "node_modules/base-x": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz", + "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "optional": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/blakejs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.1.0.tgz", + "integrity": "sha1-ad+S75U6qIylGjLfarHFShVfx6U=" + }, + "node_modules/block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "optional": true, + "dependencies": { + "inherits": "~2.0.0" + }, + "engines": { + "node": "0.4 || >=0.5.8" + } + }, + "node_modules/bn.js": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", + "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "optional": true + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/cic-client-meta": { + "version": "0.0.7-alpha.5", + "resolved": "https://registry.npmjs.org/cic-client-meta/-/cic-client-meta-0.0.7-alpha.5.tgz", + "integrity": "sha512-h+0wmAKZIgezppBNYDmG387w6tI91FSWqONMTZbMuaO1Ej76Gg0Mk2UcDyAF/dmY6doXz3kHAbWkWat7mTzXAQ==", + "dependencies": { + "@ethereumjs/tx": "^3.0.0-beta.1", + "automerge": "^0.14.1", + "ethereumjs-wallet": "^1.0.1", + "ini": "^1.3.5", + "openpgp": "^4.10.8", + "pg": "^8.4.2", + "sqlite3": "^5.0.0", + "yargs": "^16.1.0" + }, + "engines": { + "node": "~15.3.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "optional": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/crc-32": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz", + "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==", + "dependencies": { + "exit-on-epipe": "~1.0.1", + "printj": "~1.1.0" + }, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "optional": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "optional": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/ethereumjs-util": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.0.8.tgz", + "integrity": "sha512-JJt7tDpCAmDPw/sGoFYeq0guOVqT3pTE9xlEbBmc/nlCij3JRCoS2c96SQ6kXVHOT3xWUNLDm5QCJLQaUnVAtQ==", + "dependencies": { + "@types/bn.js": "^4.11.3", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ethereumjs-wallet": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ethereumjs-wallet/-/ethereumjs-wallet-1.0.1.tgz", + "integrity": "sha512-3Z5g1hG1das0JWU6cQ9HWWTY2nt9nXCcwj7eXVNAHKbo00XAZO8+NHlwdgXDWrL0SXVQMvTWN8Q/82DRH/JhPw==", + "dependencies": { + "aes-js": "^3.1.1", + "bs58check": "^2.1.2", + "ethereum-cryptography": "^0.1.3", + "ethereumjs-util": "^7.0.2", + "randombytes": "^2.0.6", + "scrypt-js": "^3.0.1", + "utf8": "^3.0.0", + "uuid": "^3.3.2" + } + }, + "node_modules/ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dependencies": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/exit-on-epipe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", + "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "optional": true + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "engines": [ + "node >=0.6.0" + ], + "optional": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "optional": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "optional": true + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "optional": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "optional": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "optional": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore-walk": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "dependencies": { + "minimatch": "^3.0.4" + } + }, + "node_modules/immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha1-fY035q135dEnFIkTxXPggtd39VQ=", + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "optional": true + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "optional": true + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "optional": true + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, + "node_modules/json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "optional": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "optional": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "optional": true + }, + "node_modules/jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "engines": [ + "node >=0.6.0" + ], + "optional": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "node_modules/keccak": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz", + "integrity": "sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA==", + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/mime-db": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", + "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==", + "optional": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.29", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", + "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "optional": true, + "dependencies": { + "mime-db": "1.46.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "node_modules/minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/needle": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.6.0.tgz", + "integrity": "sha512-KKYdza4heMsEfSWD7VPUIz3zX2XDwOyX2d+geb4vrERZMT5RMU6ujjaD+I5Yr54uZxQ2w6XRTAhHBbSCyovZBg==", + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" + }, + "node_modules/node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/node-gyp": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", + "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", + "optional": true, + "dependencies": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/node-gyp-build": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz", + "integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-localstorage": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-localstorage/-/node-localstorage-1.3.1.tgz", + "integrity": "sha512-NMWCSWWc6JbHT5PyWlNT2i8r7PgGYXVntmKawY83k/M0UJScZ5jirb61TLnqKwd815DfBQu+lR3sRw08SPzIaQ==", + "dependencies": { + "write-file-atomic": "^1.1.4" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/node-pre-gyp": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz", + "integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==", + "dependencies": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/node-pre-gyp/node_modules/nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "dependencies": { + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/node-pre-gyp/node_modules/tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "dependencies": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/npm-bundled": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" + }, + "node_modules/npm-packlist": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", + "dependencies": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/openpgp": { + "version": "4.10.10", + "resolved": "https://registry.npmjs.org/openpgp/-/openpgp-4.10.10.tgz", + "integrity": "sha512-Ub48OogGPjNsr0G/wnJ/SyAQzt/tfcXZTWVZdjKFpXCQV1Ca+upFdSPPkBlGG3lb9EQGOKZJ2tzYNH6ZyKMkDQ==", + "dependencies": { + "asn1.js": "^5.0.0", + "node-fetch": "^2.1.2", + "node-localstorage": "~1.3.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", + "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "optional": true + }, + "node_modules/pg": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.5.1.tgz", + "integrity": "sha512-9wm3yX9lCfjvA98ybCyw2pADUivyNWT/yIP4ZcDVpMN0og70BUWYEGXPCTAQdGTAqnytfRADb7NERrY1qxhIqw==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.4.0", + "pg-pool": "^3.2.2", + "pg-protocol": "^1.4.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/pg-connection-string": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.4.0.tgz", + "integrity": "sha512-3iBXuv7XKvxeMrIgym7njT+HlZkwZqqGX4Bu9cci8xHZNT+Um1gWKqCsAzcC0d95rcKMU5WBg6YRUcHyV0HZKQ==" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.2.2.tgz", + "integrity": "sha512-ORJoFxAlmmros8igi608iVEbQNNZlp89diFVx6yV5v+ehmpMY9sK6QgpmgoXbmkNaBAx8cOOZh9g80kJv1ooyA==" + }, + "node_modules/pg-protocol": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.4.0.tgz", + "integrity": "sha512-El+aXWcwG/8wuFICMQjM5ZSAm6OWiJicFdNYo+VY3QP+8vI4SvLIWVe51PppTzMhikUJR+PsyIFKqfdXPz/yxA==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz", + "integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==", + "dependencies": { + "split2": "^3.1.1" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/printj": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", + "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==", + "bin": { + "printj": "bin/printj.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "optional": true + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "optional": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "optional": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/rlp": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.6.tgz", + "integrity": "sha512-HAfAmL6SDYNWPUOJNrM500x4Thn4PZsEy5pijPh40U9WfNk0z15hUYzO9xVIMAdIHdFtD8CBDHd75Td1g36Mjg==", + "dependencies": { + "bn.js": "^4.11.1" + }, + "bin": { + "rlp": "bin/rlp" + } + }, + "node_modules/rlp/node_modules/bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" + }, + "node_modules/secp256k1": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz", + "integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==", + "dependencies": { + "elliptic": "^6.5.2", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "node_modules/slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", + "engines": { + "node": "*" + } + }, + "node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/sqlite3": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.0.2.tgz", + "integrity": "sha512-1SdTNo+BVU211Xj1csWa8lV6KM0CtucDwRyA0VHl91wEH1Mgh7RxUpI4rVvG7OhHrzCSGaVyW5g8vKvlrk9DJA==", + "dependencies": { + "node-addon-api": "^3.0.0", + "node-pre-gyp": "^0.11.0" + }, + "optionalDependencies": { + "node-gyp": "3.x" + } + }, + "node_modules/sqlite3/node_modules/node-addon-api": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.1.0.tgz", + "integrity": "sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw==" + }, + "node_modules/sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "optional": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha1-DF8VX+8RUTczd96du1iNoFUA428=", + "dependencies": { + "is-hex-prefixed": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tar": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", + "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", + "optional": true, + "dependencies": { + "block-stream": "*", + "fstream": "^1.0.12", + "inherits": "2" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "optional": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/transit-immutable-js": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/transit-immutable-js/-/transit-immutable-js-0.7.0.tgz", + "integrity": "sha1-mT4lCJtjEf9AIUD1VidtbSUwBdk=" + }, + "node_modules/transit-js": { + "version": "0.8.867", + "resolved": "https://registry.npmjs.org/transit-js/-/transit-js-0.8.867.tgz", + "integrity": "sha512-rOwB4K0z/WZ+E2bV42iN9UV3mvGzmwSv/IpMOKdnFpawPAZT0d1L7f91Y+tZQF7lXSDGk+oln4XyIQXo+pyTGA==", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "optional": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/vcard-parser": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vcard-parser/-/vcard-parser-1.0.0.tgz", + "integrity": "sha512-rSEjrjBK3of4VimMR5vBjLLcN5ZCSp9yuVzyx5i4Fwx74Yd0s+DnHtSit/wAAtj1a7/T/qQc0ykwXADoD0+fTQ==" + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "engines": [ + "node >=0.6.0" + ], + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "optional": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/write-file-atomic": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", + "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "slide": "^1.1.5" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", + "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.5", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.5.tgz", + "integrity": "sha512-jYRGS3zWy20NtDtK2kBgo/TlAoy5YUuhD9/LZ7z7W4j1Fdw2cqD0xEEclf8fxc8xjD6X5Qr+qQQwCEsP8iRiYg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + } + }, "dependencies": { "@ethereumjs/common": { "version": "2.0.0", @@ -296,9 +2378,9 @@ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, "cic-client-meta": { - "version": "0.0.7-alpha.2", - "resolved": "https://registry.npmjs.org/cic-client-meta/-/cic-client-meta-0.0.7-alpha.2.tgz", - "integrity": "sha512-q7Ifz/THPIp9XvjUEK+WFM/UFk1R0VbGJXopQd/3gW3zRpxEPj5V1JfcTts7EkyS5eYaLA0/+E4u6j4ddgmsfg==", + "version": "0.0.7-alpha.5", + "resolved": "https://registry.npmjs.org/cic-client-meta/-/cic-client-meta-0.0.7-alpha.5.tgz", + "integrity": "sha512-h+0wmAKZIgezppBNYDmG387w6tI91FSWqONMTZbMuaO1Ej76Gg0Mk2UcDyAF/dmY6doXz3kHAbWkWat7mTzXAQ==", "requires": { "@ethereumjs/tx": "^3.0.0-beta.1", "automerge": "^0.14.1", @@ -1489,6 +3571,14 @@ "tweetnacl": "~0.14.0" } }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -1499,14 +3589,6 @@ "strip-ansi": "^3.0.0" } }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -1598,6 +3680,11 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" }, + "vcard-parser": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vcard-parser/-/vcard-parser-1.0.0.tgz", + "integrity": "sha512-rSEjrjBK3of4VimMR5vBjLLcN5ZCSp9yuVzyx5i4Fwx74Yd0s+DnHtSit/wAAtj1a7/T/qQc0ykwXADoD0+fTQ==" + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", diff --git a/apps/contract-migration/scripts/verify.py b/apps/contract-migration/scripts/verify.py index 6753847f..e4f51b11 100644 --- a/apps/contract-migration/scripts/verify.py +++ b/apps/contract-migration/scripts/verify.py @@ -11,6 +11,8 @@ import csv import json import urllib import copy +import uuid +import urllib.request # external imports import celery @@ -57,18 +59,29 @@ custodial_tests = [ 'faucet', ] -all_tests = custodial_tests + [ +metadata_tests = [ + 'metadata', + 'metadata_phone', + ] + +eth_tests = [ 'accounts_index', 'balance', - 'metadata', ] +phone_tests = [ + 'ussd', + ] + +all_tests = eth_tests + custodial_tests + metadata_tests + phone_tests + argparser = argparse.ArgumentParser(description='daemon that monitors transactions in new blocks') argparser.add_argument('-p', '--provider', dest='p', type=str, help='chain rpc provider address') argparser.add_argument('-c', type=str, default=config_dir, help='config root to use') argparser.add_argument('--old-chain-spec', type=str, dest='old_chain_spec', default='evm:oldchain:1', help='chain spec') argparser.add_argument('-i', '--chain-spec', type=str, dest='i', help='chain spec') argparser.add_argument('--meta-provider', type=str, dest='meta_provider', default='http://localhost:63380', help='cic-meta url') +argparser.add_argument('--ussd-provider', type=str, dest='ussd_provider', default='http://localhost:63315', help='cic-ussd url') argparser.add_argument('--skip-custodial', dest='skip_custodial', action='store_true', help='skip all custodial verifications') argparser.add_argument('--exclude', action='append', type=str, default=[], help='skip specified verification') argparser.add_argument('--include', action='append', type=str, help='include specified verification') @@ -98,6 +111,9 @@ args_override = { config.dict_override(args_override, 'cli flag') config.censor('PASSWORD', 'DATABASE') config.censor('PASSWORD', 'SSL') +config.add(args.meta_provider, '_META_PROVIDER', True) +config.add(args.ussd_provider, '_USSD_PROVIDER', True) + logg.debug('config loaded from {}:\n{}'.format(config_dir, config)) celery_app = celery.Celery(backend=config.get('CELERY_RESULT_URL'), broker=config.get('CELERY_BROKER_URL')) @@ -107,7 +123,6 @@ chain_str = str(chain_spec) old_chain_spec = ChainSpec.from_chain_str(args.old_chain_spec) old_chain_str = str(old_chain_spec) user_dir = args.user_dir # user_out_dir from import_users.py -meta_url = args.meta_provider exit_on_error = args.x active_tests = [] @@ -271,7 +286,7 @@ class Verifier: def verify_metadata(self, address, balance=None): k = generate_metadata_pointer(bytes.fromhex(strip_0x(address)), ':cic.person') - url = os.path.join(meta_url, k) + url = os.path.join(config.get('_META_PROVIDER'), k) logg.debug('verify metadata url {}'.format(url)) try: res = urllib.request.urlopen(url) @@ -299,6 +314,77 @@ class Verifier: raise VerifierError(o_retrieved, 'metadata (person)') + def verify_metadata_phone(self, address, balance=None): + upper_address = strip_0x(address).upper() + f = open(os.path.join( + self.data_dir, + 'new', + upper_address[:2], + upper_address[2:4], + upper_address + '.json', + ), 'r' + ) + o = json.load(f) + f.close() + + p = Person.deserialize(o) + + k = generate_metadata_pointer(p.tel.encode('utf-8'), ':cic.phone') + url = os.path.join(config.get('_META_PROVIDER'), k) + logg.debug('verify metadata phone url {}'.format(url)) + try: + res = urllib.request.urlopen(url) + except urllib.error.HTTPError as e: + raise VerifierError( + '({}) {}'.format(url, e), + 'metadata (phone)', + ) + b = res.read() + address_recovered = json.loads(b.decode('utf-8')) + address_recovered = address_recovered.replace('"', '') + + if strip_0x(address) != strip_0x(address_recovered): + raise VerifierError(address_recovered, 'metadata (phone)') + + + def verify_ussd(self, address, balance=None): + upper_address = strip_0x(address).upper() + f = open(os.path.join( + self.data_dir, + 'new', + upper_address[:2], + upper_address[2:4], + upper_address + '.json', + ), 'r' + ) + o = json.load(f) + f.close() + + p = Person.deserialize(o) + phone = p.tel + + session = uuid.uuid4().hex + data = { + 'sessionId': session, + 'serviceCode': config.get('APP_SERVICE_CODE'), + 'phoneNumber': phone, + 'text': config.get('APP_SERVICE_CODE'), + } + + req = urllib.request.Request(config.get('_USSD_PROVIDER')) + data_str = json.dumps(data) + data_bytes = data_str.encode('utf-8') + req.add_header('Content-Type', 'application/json') + req.data = data_bytes + response = urllib.request.urlopen(req) + response_data = response.read().decode('utf-8') + state = response_data[:3] + out = response_data[4:] + m = '{} {}'.format(state, out[:7]) + if m != 'CON Welcome': + raise VerifierError(response_data, 'ussd') + + def verify(self, address, balance, debug_stem=None): for k in active_tests: diff --git a/docker-compose.yml b/docker-compose.yml index cab858bd..85dbfbce 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -164,6 +164,7 @@ services: DATABASE_ENGINE: ${DATABASE_ENGINE:-postgres} DATABASE_DRIVER: ${DATABASE_DRIVER:-psycopg2} DATABASE_DEBUG: 1 + DATABASE_POOL_SIZE: 0 ETH_ABI_DIR: ${ETH_ABI_DIR:-/usr/local/share/cic/solidity/abi} CIC_TRUST_ADDRESS: ${DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER:-0xEb3907eCad74a0013c259D5874AE7f22DcBcC95C} CIC_CHAIN_SPEC: ${CIC_CHAIN_SPEC:-evm:bloxberg:8996} @@ -233,6 +234,7 @@ services: DATABASE_ENGINE: ${DATABASE_ENGINE:-postgres} DATABASE_DRIVER: ${DATABASE_DRIVER:-psycopg2} DATABASE_DEBUG: ${DATABASE_DEBUG:-0} + DATABASE_POOL_SIZE: 0 PGPASSWORD: ${DATABASE_PASSWORD:-tralala} CIC_CHAIN_SPEC: ${CIC_CHAIN_SPEC:-evm:bloxberg:8996} BANCOR_DIR: ${BANCOR_DIR:-/usr/local/share/cic/bancor} @@ -430,6 +432,7 @@ services: DATABASE_NAME: ${DATABASE_NAME_CIC_NOTIFY:-cic_notify} DATABASE_ENGINE: ${DATABASE_ENGINE:-postgres} DATABASE_DRIVER: ${DATABASE_DRIVER:-psycopg2} + DATABASE_POOL_SIZE: 0 PGPASSWORD: ${DATABASE_PASSWORD:-tralala} CELERY_BROKER_URL: ${CELERY_BROKER_URL:-redis://redis} CELERY_RESULT_URL: ${CELERY_BROKER_URL:-redis://redis} @@ -446,6 +449,7 @@ services: cic-meta-server: + hostname: meta build: context: apps/ dockerfile: cic-meta/docker/Dockerfile @@ -490,9 +494,10 @@ services: DATABASE_ENGINE: postgresql DATABASE_DRIVER: psycopg2 PGP_PASSPHRASE: merman - SERVER_PORT: 8000 + SERVER_PORT: 9000 + CIC_META_URL: ${CIC_META_URL:-http://meta:8000} ports: - - ${HTTP_PORT_CIC_USSD:-63315}:8000 + - ${HTTP_PORT_CIC_USSD:-63315}:9000 depends_on: - postgres - redis @@ -501,7 +506,7 @@ services: deploy: restart_policy: condition: on-failure - command: "/root/start_uwsgi.sh" + command: "/root/start_uwsgi.sh -vv" cic-ussd-tasker: # image: grassrootseconomics:cic-ussd @@ -516,9 +521,11 @@ services: DATABASE_NAME: cic_ussd DATABASE_ENGINE: postgresql DATABASE_DRIVER: psycopg2 + DATABASE_POOL_SIZE: 0 CELERY_BROKER_URL: ${CELERY_BROKER_URL:-redis://redis} CELERY_RESULT_URL: ${CELERY_BROKER_URL:-redis://redis} PGP_PASSPHRASE: merman + CIC_META_URL: ${CIC_META_URL:-http://meta:8000} depends_on: - postgres - redis @@ -527,4 +534,4 @@ services: deploy: restart_policy: condition: on-failure - command: "/root/start_tasker.sh -q cic-ussd" + command: "/root/start_tasker.sh -q cic-ussd -vv"