Compare commits

...

9 Commits

Author SHA1 Message Date
b15cfee1c9 Merge branch 'sohail/pip-url-fix' into 'master'
fix: update default pip to new url

Closes #171

See merge request grassrootseconomics/cic-internal-integration!316
2021-12-10 14:55:50 +00:00
efb1967f46 fix: update default pip to new url 2021-12-10 14:55:50 +00:00
019824d1f4 Merge branch 'bvander/docs-updates' into 'master'
documentation: updated the docs with new links and getting started

See merge request grassrootseconomics/cic-internal-integration!314
2021-12-09 09:20:03 +00:00
d4c7fd3d7e documentation: updated the docs with new links and getting started 2021-12-09 09:20:03 +00:00
4b87a40cc2 Fixing path because it was messed up in the mr 2021-12-02 20:52:06 +00:00
9f9d557c73 Merge branch 'blairv/bug-template' into 'master'
Update bug.md

See merge request grassrootseconomics/cic-internal-integration!313
2021-12-02 20:49:00 +00:00
9814da78b8 Update bug.md 2021-12-02 20:47:11 +00:00
cd102807a6 Merge branch 'philip/social-pin-recovery' into 'master'
Philip/social pin recovery

See merge request grassrootseconomics/cic-internal-integration!311
2021-11-29 21:24:38 +00:00
c3c43c28a5 Philip/social pin recovery 2021-11-29 21:24:37 +00:00
34 changed files with 950 additions and 129 deletions

View File

@@ -0,0 +1,44 @@
<!---
Please read this!
Before opening a new issue, make sure to search for keywords in the issues
filtered by the "bug" label:
- https://gitlab.com/groups/grassrootseconomics/-/issues?scope=all&state=all&label_name[]=bug
and verify the issue you're about to submit isn't a duplicate.
--->
### Summary
<!-- Summarize the bug encountered concisely. -->
### Steps to reproduce
<!-- Describe how one can reproduce the issue - this is very important. Please use an ordered list. -->
### Example Project
<!-- If possible, please create an example project here on GitLab.com that exhibits the problematic
behavior, and link to it here in the bug report. If you are using an older version of GitLab, this
will also determine whether the bug is fixed in a more recent version. -->
### What is the current *bug* behavior?
<!-- Describe what actually happens. -->
### What is the expected *correct* behavior?
<!-- Describe what you should see instead. -->
### Relevant logs and/or screenshots
<!-- Paste any relevant logs - please use code blocks (```) to format console output, logs, and code
as it's tough to read otherwise. -->
### Possible fixes
<!-- If you can, link to the line of code that might be responsible for the problem. -->
/label ~"bug"

View File

@@ -1,41 +1,19 @@
# cic-internal-integration
# Community Inclusion Currency Stack (CIC Stack)
A custodial evm wallet for executing transactions via USSD
## Getting started
This repo uses docker-compose and docker buildkit. Set the following environment variables to get started:
```
export COMPOSE_DOCKER_CLI_BUILD=1
export DOCKER_BUILDKIT=1
```
start services, database, redis and local ethereum node
```
docker-compose up -d
```
To get started see [./apps/contract-migration/README.md](./apps/contract-migration/README.md)
Run app/contract-migration to deploy contracts
```
RUN_MASK=3 docker-compose up contract-migration
```
## Documentation
stop cluster
```
docker-compose down
```
[https://docs.grassecon.org/cic_stack/](https://docs.grassecon.org/cic_stack/)
stop cluster and delete data
```
docker-compose down -v --remove-orphans
```
rebuild an images
```
docker-compose up --build <service_name>
```
to delete the buildkit cache
```
docker builder prune --filter type=exec.cachemount
```

View File

@@ -4,7 +4,7 @@ FROM $DOCKER_REGISTRY/cic-base-images:python-3.8.6-dev-e8eb2ee2
COPY requirements.txt .
ARG EXTRA_PIP_INDEX_URL="https://pip.grassrootseconomics.net:8433"
ARG EXTRA_PIP_INDEX_URL="https://pip.grassrootseconomics.net"
ARG EXTRA_PIP_ARGS=""
ARG PIP_INDEX_URL="https://pypi.org/simple"

View File

@@ -2,7 +2,7 @@
set -e
pip install --extra-index-url https://pip.grassrootseconomics.net:8433 \
pip install --extra-index-url https://pip.grassrootseconomics.net \
--extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple \
-r test_requirements.txt

View File

@@ -7,7 +7,7 @@ FROM $DOCKER_REGISTRY/cic-base-images:python-3.8.6-dev-e8eb2ee2
# TODO can we take all the requirements out of setup.py and just do a pip install -r requirements.txt && python setup.py
#COPY cic-eth/requirements.txt .
ARG EXTRA_PIP_INDEX_URL=https://pip.grassrootseconomics.net:8433
ARG EXTRA_PIP_INDEX_URL=https://pip.grassrootseconomics.net
ARG EXTRA_PIP_ARGS=""
ARG PIP_INDEX_URL=https://pypi.org/simple
@@ -15,7 +15,7 @@ RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
pip install --index-url $PIP_INDEX_URL \
--pre \
--extra-index-url $EXTRA_PIP_INDEX_URL $EXTRA_PIP_ARGS \
cic-eth-aux-erc20-demurrage-token~=0.0.2a7
cic-eth-aux-erc20-demurrage-token~=0.0.2a7
COPY *requirements.txt ./
@@ -26,7 +26,7 @@ RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
-r requirements.txt \
-r services_requirements.txt \
-r admin_requirements.txt
COPY . .
RUN python setup.py install

View File

@@ -2,7 +2,7 @@
set -e
pip install --extra-index-url https://pip.grassrootseconomics.net:8433 --extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple \
pip install --extra-index-url https://pip.grassrootseconomics.net --extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple \
-r admin_requirements.txt \
-r services_requirements.txt \
-r test_requirements.txt

View File

@@ -2,7 +2,7 @@
set -e
pip install --extra-index-url https://pip.grassrootseconomics.net:8433 --extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple
pip install --extra-index-url https://pip.grassrootseconomics.net --extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple
-r admin_requirements.txt
-r services_requirements.txt
-r test_requirements.txt

View File

@@ -6,7 +6,7 @@ FROM $DOCKER_REGISTRY/cic-base-images:python-3.8.6-dev-e8eb2ee2
RUN apt-get install libffi-dev -y
ARG EXTRA_PIP_INDEX_URL=https://pip.grassrootseconomics.net:8433
ARG EXTRA_PIP_INDEX_URL=https://pip.grassrootseconomics.net
ARG EXTRA_PIP_ARGS=""
ARG PIP_INDEX_URL=https://pypi.org/simple

View File

@@ -2,7 +2,7 @@
set -e
pip install --extra-index-url https://pip.grassrootseconomics.net:8433 \
pip install --extra-index-url https://pip.grassrootseconomics.net \
--extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple \
-r test_requirements.txt

View File

@@ -8,7 +8,7 @@ RUN apt-get install libffi-dev -y
COPY requirements.txt .
ARG EXTRA_PIP_INDEX_URL="https://pip.grassrootseconomics.net:8433"
ARG EXTRA_PIP_INDEX_URL="https://pip.grassrootseconomics.net"
ARG EXTRA_PIP_ARGS=""
ARG PIP_INDEX_URL="https://pypi.org/simple"
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \

View File

@@ -24,6 +24,8 @@ def upgrade():
sa.Column('preferred_language', sa.String(), nullable=True),
sa.Column('password_hash', sa.String(), nullable=True),
sa.Column('failed_pin_attempts', sa.Integer(), nullable=False),
sa.Column('guardians', sa.String(), nullable=True),
sa.Column('guardian_quora', sa.Integer(), nullable=False),
sa.Column('status', sa.Integer(), nullable=False),
sa.Column('created', sa.DateTime(), nullable=False),
sa.Column('updated', sa.DateTime(), nullable=False),

View File

@@ -4,6 +4,8 @@ import json
# external imports
from cic_eth.api import Api
from cic_types.condiments import MetadataPointer
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm.session import Session
# local imports
from cic_ussd.account.metadata import get_cached_preferred_language, parse_account_metadata
@@ -12,8 +14,9 @@ from cic_ussd.db.enum import AccountStatus
from cic_ussd.db.models.base import SessionBase
from cic_ussd.db.models.task_tracker import TaskTracker
from cic_ussd.encoder import check_password_hash, create_password_hash
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm.session import Session
from cic_ussd.phone_number import Support
support_phone = Support.phone_number
class Account(SessionBase):
@@ -29,12 +32,16 @@ class Account(SessionBase):
failed_pin_attempts = Column(Integer)
status = Column(Integer)
preferred_language = Column(String)
guardians = Column(String)
guardian_quora = Column(Integer)
def __init__(self, blockchain_address, phone_number):
self.blockchain_address = blockchain_address
self.phone_number = phone_number
self.password_hash = None
self.failed_pin_attempts = 0
# self.guardians = f'{support_phone}' if support_phone else None
self.guardian_quora = 1
self.status = AccountStatus.PENDING.value
def __repr__(self):
@@ -45,6 +52,28 @@ class Account(SessionBase):
self.failed_pin_attempts = 0
self.status = AccountStatus.ACTIVE.value
def add_guardian(self, phone_number: str):
set_guardians = phone_number
if self.guardians:
set_guardians = self.guardians.split(',')
set_guardians.append(phone_number)
','.join(set_guardians)
self.guardians = set_guardians
def remove_guardian(self, phone_number: str):
set_guardians = self.guardians.split(',')
set_guardians.remove(phone_number)
if len(set_guardians) > 1:
self.guardians = ','.join(set_guardians)
else:
self.guardians = set_guardians[0]
def get_guardians(self) -> list:
return self.guardians.split(',') if self.guardians else []
def set_guardian_quora(self, quora: int):
self.guardian_quora = quora
def create_password(self, password):
"""This method takes a password value and hashes the value before assigning it to the corresponding
`hashed_password` attribute in the user record.

View File

@@ -317,6 +317,102 @@
"display_key": "ussd.kenya.exit_successful_token_selection",
"name": "exit_successful_token_selection",
"parent": null
},
"54": {
"description": "Pin management menu for operations related to an account's pin.",
"display_key": "ussd.kenya.pin_management",
"name": "pin_management",
"parent": "start"
},
"55": {
"description": "Phone number entry for account whose pin is being reset.",
"display_key": "ussd.kenya.reset_guarded_pin",
"name": "reset_guarded_pin",
"parent": "pin_management"
},
"56": {
"description": "Pin entry for initiating request to reset an account's pin.",
"display_key": "ussd.kenya.reset_guarded_pin_authorization",
"name": "reset_guarded_pin_authorization",
"parent": "pin_management"
},
"57": {
"description": "Exit menu following successful pin reset initiation.",
"display_key": "ussd.kenya.exit_pin_reset_initiated_success",
"name": "exit_pin_reset_initiated_success",
"parent": "pin_management"
},
"58": {
"description": "Exit menu in the event that an account is not a set guardian.",
"display_key": "ussd.kenya.exit_not_authorized_for_pin_reset",
"name": "exit_not_authorized_for_pin_reset",
"parent": "pin_management"
},
"59": {
"description": "Pin guard menu for handling guardianship operations.",
"display_key": "ussd.kenya.guard_pin",
"name": "guard_pin",
"parent": "pin_management"
},
"60": {
"description": "Pin entry to display a list of set guardians.",
"display_key": "ussd.kenya.guardian_list_pin_authorization",
"name": "guardian_list_pin_authorization",
"parent": "guard_pin"
},
"61": {
"description": "Menu to display list of set guardians.",
"display_key": "ussd.kenya.guardian_list",
"name": "guardian_list",
"parent": "guard_pin"
},
"62": {
"description": "Phone number entry to add an account as a guardian to reset pin.",
"display_key": "ussd.kenya.add_guardian",
"name": "add_guardian",
"parent": "guard_pin"
},
"63": {
"description": "Pin entry to confirm addition of an account as a guardian.",
"display_key": "ussd.kenya.add_guardian_pin_authorization",
"name": "add_guardian_pin_authorization",
"parent": "guard_pin"
},
"64": {
"description": "Exit menu when an account is successfully added as pin reset guardian.",
"display_key": "ussd.kenya.exit_guardian_addition_success",
"name": "exit_guardian_addition_success",
"parent": "guard_pin"
},
"65": {
"description": "Phone number entry to remove an account as a guardian to reset pin.",
"display_key": "ussd.kenya.remove_guardian",
"name": "remove_guardian",
"parent": "guard_pin"
},
"66": {
"description": "Pin entry to confirm removal of an account as a guardian.",
"display_key": "ussd.kenya.remove_guardian_pin_authorization",
"name": "remove_guardian_pin_authorization",
"parent": "guard_pin"
},
"67": {
"description": "Exit menu when an account is successfully removed as pin reset guardian.",
"display_key": "ussd.kenya.exit_guardian_removal_success",
"name": "exit_guardian_removal_success",
"parent": "guard_pin"
},
"68": {
"description": "Exit menu when invalid phone number entry for guardian addition. ",
"display_key": "ussd.kenya.exit_invalid_guardian_addition",
"name": "exit_invalid_guardian_addition",
"parent": "guard_pin"
},
"69": {
"description": "Exit menu when invalid phone number entry for guardian removal. ",
"display_key": "ussd.kenya.exit_invalid_guardian_removal",
"name": "exit_invalid_guardian_removal",
"parent": "guard_pin"
}
}
}

View File

@@ -5,7 +5,6 @@ from typing import Optional
import phonenumbers
# local imports
from cic_ussd.db.models.account import Account
class E164Format:

View File

@@ -121,6 +121,27 @@ class MenuProcessor:
self.display_key, preferred_language, last_transaction_set=last_transaction_set
)
def add_guardian_pin_authorization(self):
guardian_information = self.guardian_metadata()
return self.pin_authorization(guardian_information=guardian_information)
def guardian_list(self):
preferred_language = get_cached_preferred_language(self.account.blockchain_address)
if not preferred_language:
preferred_language = i18n.config.get('fallback')
set_guardians = self.account.get_guardians()
if set_guardians:
guardians_list = ''
guardians_list_header = translation_for('helpers.guardians_list_header', preferred_language)
for phone_number in set_guardians:
guardian = Account.get_by_phone_number(phone_number, self.session)
guardian_information = guardian.standard_metadata_id()
guardians_list += f'{guardian_information}\n'
guardians_list = guardians_list_header + '\n' + guardians_list
else:
guardians_list = translation_for('helpers.no_guardians_list', preferred_language)
return translation_for(self.display_key, preferred_language, guardians_list=guardians_list)
def account_tokens(self) -> str:
cached_token_data_list = get_cached_token_data_list(self.account.blockchain_address)
token_data_list = parse_token_list(cached_token_data_list)
@@ -207,6 +228,20 @@ class MenuProcessor:
f'{self.display_key}.retry', preferred_language, retry_pin_entry=retry_pin_entry
)
def guarded_account_metadata(self):
guarded_account_phone_number = self.ussd_session.get('data').get('guarded_account_phone_number')
guarded_account = Account.get_by_phone_number(guarded_account_phone_number, self.session)
return guarded_account.standard_metadata_id()
def guardian_metadata(self):
guardian_phone_number = self.ussd_session.get('data').get('guardian_phone_number')
guardian = Account.get_by_phone_number(guardian_phone_number, self.session)
return guardian.standard_metadata_id()
def reset_guarded_pin_authorization(self):
guarded_account_information = self.guarded_account_metadata()
return self.pin_authorization(guarded_account_information=guarded_account_information)
def start_menu(self):
"""
:return:
@@ -277,6 +312,47 @@ class MenuProcessor:
sender_information=tx_sender_information
)
def exit_guardian_addition_success(self) -> str:
guardian_information = self.guardian_metadata()
preferred_language = get_cached_preferred_language(self.account.blockchain_address)
if not preferred_language:
preferred_language = i18n.config.get('fallback')
return translation_for(self.display_key,
preferred_language,
guardian_information=guardian_information)
def exit_guardian_removal_success(self):
guardian_information = self.guardian_metadata()
preferred_language = get_cached_preferred_language(self.account.blockchain_address)
if not preferred_language:
preferred_language = i18n.config.get('fallback')
return translation_for(self.display_key,
preferred_language,
guardian_information=guardian_information)
def exit_invalid_guardian_addition(self):
failure_reason = self.ussd_session.get('data').get('failure_reason')
preferred_language = get_cached_preferred_language(self.account.blockchain_address)
if not preferred_language:
preferred_language = i18n.config.get('fallback')
return translation_for(self.display_key, preferred_language, error_exit=failure_reason)
def exit_invalid_guardian_removal(self):
failure_reason = self.ussd_session.get('data').get('failure_reason')
preferred_language = get_cached_preferred_language(self.account.blockchain_address)
if not preferred_language:
preferred_language = i18n.config.get('fallback')
return translation_for(self.display_key, preferred_language, error_exit=failure_reason)
def exit_pin_reset_initiated_success(self):
guarded_account_information = self.guarded_account_metadata()
preferred_language = get_cached_preferred_language(self.account.blockchain_address)
if not preferred_language:
preferred_language = i18n.config.get('fallback')
return translation_for(self.display_key,
preferred_language,
guarded_account_information=guarded_account_information)
def exit_insufficient_balance(self):
"""
:return:
@@ -379,18 +455,41 @@ def response(account: Account, display_key: str, menu_name: str, session: Sessio
return menu_processor.transaction_pin_authorization()
if menu_name == 'token_selection_pin_authorization':
logg.debug(f'RESPONSE IS: {menu_processor.token_selection_pin_authorization()}')
return menu_processor.token_selection_pin_authorization()
if menu_name == 'exit_insufficient_balance':
return menu_processor.exit_insufficient_balance()
if menu_name == 'exit_invalid_guardian_addition':
return menu_processor.exit_invalid_guardian_addition()
if menu_name == 'exit_invalid_guardian_removal':
return menu_processor.exit_invalid_guardian_removal()
if menu_name == 'exit_successful_transaction':
return menu_processor.exit_successful_transaction()
if menu_name == 'exit_guardian_addition_success':
return menu_processor.exit_guardian_addition_success()
if menu_name == 'exit_guardian_removal_success':
return menu_processor.exit_guardian_removal_success()
if menu_name == 'exit_pin_reset_initiated_success':
return menu_processor.exit_pin_reset_initiated_success()
if menu_name == 'account_balances':
return menu_processor.account_balances()
if menu_name == 'guardian_list':
return menu_processor.guardian_list()
if menu_name == 'add_guardian_pin_authorization':
return menu_processor.add_guardian_pin_authorization()
if menu_name == 'reset_guarded_pin_authorization':
return menu_processor.reset_guarded_pin_authorization()
if 'pin_authorization' in menu_name:
return menu_processor.pin_authorization()

View File

@@ -81,6 +81,18 @@ def menu_six_selected(state_machine_data: Tuple[str, dict, Account, Session]) ->
return user_input == '6'
def menu_nine_selected(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
"""
This function checks that user input matches a string with value '6'
:param state_machine_data: A tuple containing user input, a ussd session and user object.
:type state_machine_data: tuple
:return: A user input's match with '6'
:rtype: bool
"""
user_input, ussd_session, account, session = state_machine_data
return user_input == '9'
def menu_zero_zero_selected(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
"""
This function checks that user input matches a string with value '00'

View File

@@ -0,0 +1,200 @@
# standard imports
import logging
from typing import Tuple
# external imports
import celery
import i18n
from phonenumbers.phonenumberutil import NumberParseException
from sqlalchemy.orm.session import Session
# local imports
from cic_ussd.account.metadata import get_cached_preferred_language
from cic_ussd.db.models.account import Account
from cic_ussd.db.models.base import SessionBase
from cic_ussd.phone_number import process_phone_number, E164Format
from cic_ussd.session.ussd_session import save_session_data
from cic_ussd.translation import translation_for
logg = logging.getLogger(__file__)
def save_guardian_to_session_data(state_machine_data: Tuple[str, dict, Account, Session]):
"""
:param state_machine_data:
:type state_machine_data:
:return:
:rtype:
"""
user_input, ussd_session, account, session = state_machine_data
session_data = ussd_session.get('data') or {}
guardian_phone_number = process_phone_number(phone_number=user_input, region=E164Format.region)
session_data['guardian_phone_number'] = guardian_phone_number
save_session_data('cic-ussd', session, session_data, ussd_session)
def save_guarded_account_session_data(state_machine_data: Tuple[str, dict, Account, Session]):
"""
:param state_machine_data:
:type state_machine_data:
:return:
:rtype:
"""
user_input, ussd_session, account, session = state_machine_data
session_data = ussd_session.get('data') or {}
guarded_account_phone_number = process_phone_number(phone_number=user_input, region=E164Format.region)
session_data['guarded_account_phone_number'] = guarded_account_phone_number
save_session_data('cic-ussd', session, session_data, ussd_session)
def retrieve_person_metadata(state_machine_data: Tuple[str, dict, Account, Session]):
"""
:param state_machine_data:
:type state_machine_data:
:return:
:rtype:
"""
user_input, ussd_session, account, session = state_machine_data
guardian_phone_number = process_phone_number(user_input, E164Format.region)
guardian = Account.get_by_phone_number(guardian_phone_number, session)
blockchain_address = guardian.blockchain_address
s_query_person_metadata = celery.signature(
'cic_ussd.tasks.metadata.query_person_metadata', [blockchain_address], queue='cic-ussd')
s_query_person_metadata.apply_async()
def is_valid_guardian_addition(state_machine_data: Tuple[str, dict, Account, Session]):
"""
:param state_machine_data:
:type state_machine_data:
:return:
:rtype:
"""
user_input, ussd_session, account, session = state_machine_data
try:
phone_number = process_phone_number(user_input, E164Format.region)
except NumberParseException:
phone_number = None
preferred_language = get_cached_preferred_language(account.blockchain_address)
if not preferred_language:
preferred_language = i18n.config.get('fallback')
is_valid_account = Account.get_by_phone_number(phone_number, session) is not None
is_initiator = phone_number == account.phone_number
is_existent_guardian = phone_number in account.get_guardians()
failure_reason = ''
if not is_valid_account:
failure_reason = translation_for('helpers.error.no_matching_account', preferred_language)
if is_initiator:
failure_reason = translation_for('helpers.error.is_initiator', preferred_language)
if is_existent_guardian:
failure_reason = translation_for('helpers.error.is_existent_guardian', preferred_language)
if failure_reason:
session_data = ussd_session.get('data') or {}
session_data['failure_reason'] = failure_reason
save_session_data('cic-ussd', session, session_data, ussd_session)
return phone_number is not None and is_valid_account and not is_existent_guardian and not is_initiator
def add_pin_guardian(state_machine_data: Tuple[str, dict, Account, Session]):
"""
:param state_machine_data:
:type state_machine_data:
:return:
:rtype:
"""
user_input, ussd_session, account, session = state_machine_data
guardian_phone_number = ussd_session.get('data').get('guardian_phone_number')
account.add_guardian(guardian_phone_number)
session.add(account)
session.flush()
SessionBase.release_session(session=session)
def is_set_pin_guardian(account: Account, checked_number: str, preferred_language: str, session: Session, ussd_session: dict):
""""""
failure_reason = ''
set_guardians = []
if account:
set_guardians = account.get_guardians()
else:
failure_reason = translation_for('helpers.error.no_matching_account', preferred_language)
is_set_guardian = checked_number in set_guardians
is_initiator = checked_number == account.phone_number
if not is_set_guardian:
failure_reason = translation_for('helpers.error.is_not_existent_guardian', preferred_language)
if is_initiator:
failure_reason = translation_for('helpers.error.is_initiator', preferred_language)
if failure_reason:
session_data = ussd_session.get('data') or {}
session_data['failure_reason'] = failure_reason
save_session_data('cic-ussd', session, session_data, ussd_session)
return is_set_guardian and not is_initiator
def is_dialers_pin_guardian(state_machine_data: Tuple[str, dict, Account, Session]):
user_input, ussd_session, account, session = state_machine_data
phone_number = process_phone_number(phone_number=user_input, region=E164Format.region)
preferred_language = get_cached_preferred_language(account.blockchain_address)
if not preferred_language:
preferred_language = i18n.config.get('fallback')
return is_set_pin_guardian(account, phone_number, preferred_language, session, ussd_session)
def is_others_pin_guardian(state_machine_data: Tuple[str, dict, Account, Session]):
user_input, ussd_session, account, session = state_machine_data
preferred_language = get_cached_preferred_language(account.blockchain_address)
phone_number = process_phone_number(phone_number=user_input, region=E164Format.region)
guarded_account = Account.get_by_phone_number(phone_number, session)
if not preferred_language:
preferred_language = i18n.config.get('fallback')
return is_set_pin_guardian(guarded_account, account.phone_number, preferred_language, session, ussd_session)
def remove_pin_guardian(state_machine_data: Tuple[str, dict, Account, Session]):
"""
:param state_machine_data:
:type state_machine_data:
:return:
:rtype:
"""
user_input, ussd_session, account, session = state_machine_data
guardian_phone_number = ussd_session.get('data').get('guardian_phone_number')
account.remove_guardian(guardian_phone_number)
session.add(account)
session.flush()
SessionBase.release_session(session=session)
def initiate_pin_reset(state_machine_data: Tuple[str, dict, Account, Session]):
"""
:param state_machine_data:
:type state_machine_data:
:return:
:rtype:
"""
user_input, ussd_session, account, session = state_machine_data
session_data = ussd_session.get('data')
quorum_count = session_data['quorum_count'] if session_data.get('quorum_count') else 0
quorum_count += 1
session_data['quorum_count'] = quorum_count
save_session_data('cic-ussd', session, session_data, ussd_session)
guarded_account_phone_number = session_data.get('guarded_account_phone_number')
guarded_account = Account.get_by_phone_number(guarded_account_phone_number, session)
if quorum_count >= guarded_account.guardian_quora:
guarded_account.reset_pin(session)
logg.debug(f'Reset initiated for: {guarded_account.phone_number}')
session_data['quorum_count'] = 0
save_session_data('cic-ussd', session, session_data, ussd_session)

View File

@@ -10,7 +10,7 @@ RUN mkdir -vp pgp/keys
RUN mkdir -vp cic-ussd
RUN mkdir -vp data
ARG EXTRA_PIP_INDEX_URL=https://pip.grassrootseconomics.net:8433
ARG EXTRA_PIP_INDEX_URL=https://pip.grassrootseconomics.net
ARG EXTRA_PIP_ARGS=""
ARG PIP_INDEX_URL=https://pypi.org/simple
@@ -18,7 +18,7 @@ RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
pip install --index-url $PIP_INDEX_URL \
--pre \
--extra-index-url $EXTRA_PIP_INDEX_URL $EXTRA_PIP_ARGS \
cic-eth-aux-erc20-demurrage-token~=0.0.2a7
cic-eth-aux-erc20-demurrage-token~=0.0.2a7
COPY *requirements.txt ./

View File

@@ -3,7 +3,7 @@
set -e
pip install --extra-index-url https://pip.grassrootseconomics.net:8433 \
pip install --extra-index-url https://pip.grassrootseconomics.net \
--extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple \
-r test_requirements.txt

View File

@@ -11,5 +11,7 @@
"account_creation_prompt",
"exit_successful_transaction",
"exit_insufficient_balance",
"exit_invalid_guardian_addition",
"exit_invalid_guardian_removal",
"complete"
]

View File

@@ -0,0 +1,16 @@
[
"pin_management",
"reset_guarded_pin",
"reset_guarded_pin_authorization",
"exit_pin_reset_initiated_success",
"exit_not_authorized_for_pin_reset",
"guard_pin",
"guardian_list_pin_authorization",
"guardian_list",
"add_guardian",
"add_guardian_pin_authorization",
"exit_guardian_addition_success",
"remove_guardian",
"remove_guardian_pin_authorization",
"exit_guardian_removal_success"
]

View File

@@ -50,7 +50,7 @@
{
"trigger": "scan_data",
"source": "account_management",
"dest": "enter_current_pin",
"dest": "pin_management",
"conditions": "cic_ussd.state_machine.logic.menu.menu_five_selected"
},
{

View File

@@ -0,0 +1,119 @@
[
{
"trigger": "scan_data",
"source": "guard_pin",
"dest": "guardian_list_pin_authorization",
"conditions": "cic_ussd.state_machine.logic.menu.menu_one_selected"
},
{
"trigger": "scan_data",
"source": "guardian_list_pin_authorization",
"dest": "guardian_list",
"conditions": "cic_ussd.state_machine.logic.pin.is_authorized_pin"
},
{
"trigger": "scan_data",
"source": "guardian_list_pin_authorization",
"dest": "exit_pin_blocked",
"conditions": "cic_ussd.state_machine.logic.pin.is_blocked_pin"
},
{
"trigger": "scan_data",
"source": "guard_pin",
"dest": "add_guardian",
"conditions": "cic_ussd.state_machine.logic.menu.menu_two_selected"
},
{
"trigger": "scan_data",
"source": "add_guardian",
"dest": "add_guardian_pin_authorization",
"after": [
"cic_ussd.state_machine.logic.pin_guard.save_guardian_to_session_data",
"cic_ussd.state_machine.logic.pin_guard.retrieve_person_metadata"
],
"conditions": "cic_ussd.state_machine.logic.pin_guard.is_valid_guardian_addition"
},
{
"trigger": "scan_data",
"source": "add_guardian",
"dest": "exit_invalid_guardian_addition",
"unless": "cic_ussd.state_machine.logic.pin_guard.is_valid_guardian_addition"
},
{
"trigger": "scan_data",
"source": "add_guardian_pin_authorization",
"dest": "exit_guardian_addition_success",
"after": "cic_ussd.state_machine.logic.pin_guard.add_pin_guardian",
"conditions": "cic_ussd.state_machine.logic.pin.is_authorized_pin"
},
{
"trigger": "scan_data",
"source": "add_guardian_pin_authorization",
"dest": "exit_pin_blocked",
"conditions": "cic_ussd.state_machine.logic.pin.is_locked_account"
},
{
"trigger": "scan_data",
"source": "guard_pin",
"dest": "remove_guardian",
"conditions": "cic_ussd.state_machine.logic.menu.menu_three_selected"
},
{
"trigger": "scan_data",
"source": "remove_guardian",
"dest": "remove_guardian_pin_authorization",
"after": [
"cic_ussd.state_machine.logic.pin_guard.save_guardian_to_session_data",
"cic_ussd.state_machine.logic.pin_guard.retrieve_person_metadata"
],
"conditions": "cic_ussd.state_machine.logic.pin_guard.is_dialers_pin_guardian"
},
{
"trigger": "scan_data",
"source": "remove_guardian",
"dest": "exit_invalid_guardian_removal",
"unless": "cic_ussd.state_machine.logic.pin_guard.is_dialers_pin_guardian"
},
{
"trigger": "scan_data",
"source": "remove_guardian_pin_authorization",
"dest": "exit_guardian_removal_success",
"after": "cic_ussd.state_machine.logic.pin_guard.remove_pin_guardian",
"conditions": "cic_ussd.state_machine.logic.pin.is_authorized_pin"
},
{
"trigger": "scan_data",
"source": "remove_guardian_pin_authorization",
"dest": "exit_pin_blocked",
"conditions": "cic_ussd.state_machine.logic.pin.is_locked_account"
},
{
"trigger": "scan_data",
"source": "exit_guardian_removal_success",
"dest": "exit",
"conditions": "cic_ussd.state_machine.logic.menu.menu_nine_selected"
},
{
"trigger": "scan_data",
"source": "exit_invalid_guardian_addition",
"dest": "exit",
"conditions": "cic_ussd.state_machine.logic.menu.menu_nine_selected"
},
{
"trigger": "scan_data",
"source": "exit_invalid_guardian_removal",
"dest": "exit",
"conditions": "cic_ussd.state_machine.logic.menu.menu_nine_selected"
},
{
"trigger": "scan_data",
"source": "guardian_list",
"dest": "exit",
"conditions": "cic_ussd.state_machine.logic.menu.menu_nine_selected"
},
{
"trigger": "scan_data",
"source": "guard_pin",
"dest": "exit_invalid_menu_option"
}
]

View File

@@ -0,0 +1,20 @@
[
{
"trigger": "scan_data",
"source": "pin_management",
"dest": "enter_current_pin",
"conditions": "cic_ussd.state_machine.logic.menu.menu_one_selected"
},
{
"trigger": "scan_data",
"source": "pin_management",
"dest": "reset_guarded_pin",
"conditions": "cic_ussd.state_machine.logic.menu.menu_two_selected"
},
{
"trigger": "scan_data",
"source": "pin_management",
"dest": "guard_pin",
"conditions": "cic_ussd.state_machine.logic.menu.menu_three_selected"
}
]

View File

@@ -0,0 +1,43 @@
[
{
"trigger": "scan_data",
"source": "reset_guarded_pin",
"dest": "reset_guarded_pin_authorization",
"after": [
"cic_ussd.state_machine.logic.pin_guard.save_guarded_account_session_data",
"cic_ussd.state_machine.logic.pin_guard.retrieve_person_metadata"
],
"conditions": "cic_ussd.state_machine.logic.pin_guard.is_others_pin_guardian"
},
{
"trigger": "scan_data",
"source": "reset_guarded_pin_authorization",
"dest": "exit_pin_reset_initiated_success",
"after": "cic_ussd.state_machine.logic.pin_guard.initiate_pin_reset",
"conditions": "cic_ussd.state_machine.logic.pin.is_authorized_pin"
},
{
"trigger": "scan_data",
"source": "exit_pin_reset_initiated_success",
"dest": "exit",
"conditions": "cic_ussd.state_machine.logic.menu.menu_nine_selected"
},
{
"trigger": "scan_data",
"source": "reset_guarded_pin_authorization",
"dest": "exit_pin_blocked",
"conditions": "cic_ussd.state_machine.logic.pin.is_locked_account"
},
{
"trigger": "scan_data",
"source": "reset_guarded_pin",
"dest": "exit_not_authorized_for_pin_reset",
"unless": "cic_ussd.state_machine.logic.pin_guard.is_others_pin_guardian"
},
{
"trigger": "scan_data",
"source": "exit_not_authorized_for_pin_reset",
"dest": "exit",
"conditions": "cic_ussd.state_machine.logic.menu.menu_nine_selected"
}
]

View File

@@ -18,4 +18,19 @@ en:
sent: |-
Sent
to: |-
To
To
guardians_list_header: |-
Walinzi uliowaongeza ni:
no_guardians_list: |-
No guardians set
error:
no_phone_number_provided: |-
No phone number was provided.
no_matching_account: |-
The number provided is not registered.
is_initiator: |-
Phone number cannot be your own.
is_existent_guardian: |-
This phone number is is already added as a guardian.
is_not_existent_guardian: |-
Phone number not set as PIN reset guardian.

View File

@@ -18,4 +18,19 @@ sw:
sent: |-
Ulituma
to: |-
Kwa
Kwa
guardians_list_header: |-
Your set guardians are:
no_guardians_list: |-
Hamna walinzi walioongezwa
error:
no_phone_number_provided: |-
Namabari ya simu haijawekwa.
no_matching_account: |-
Nambari uliyoweka haijasajiliwa.
is_initiator: |-
Nambari yafaa kuwa tofauti na yako.
is_existent_guardian: |-
Namabari hii tayari imeongezwa kama mlinzi wa nambari ya siri.
is_not_existent_guardian: |-
Nambari hii haijaongezwa kama mlinzi wa nambari ya siri.

View File

@@ -70,7 +70,7 @@ en:
2. Change language
3. Check balance
4. Check statement
5. Change PIN
5. PIN options
0. Back
metadata_management: |-
CON My profile
@@ -96,6 +96,13 @@ en:
0. Back
retry_pin_entry: |-
CON Incorrect PIN entered, please try again. You have %{remaining_attempts} attempts remaining.
0. Back
pin_management: |-
CON Pin options
1. Change PIN
2. Reset PIN
3. Guard PIN
0. Back
enter_current_pin:
first: |-
CON Enter current PIN.
@@ -108,6 +115,73 @@ en:
new_pin_confirmation: |-
CON Enter your new four number PIN again
0. Back
reset_guarded_pin: |-
CON Enter phone number you are the guardian to reset their pin
0. Back
reset_guarded_pin_authorization:
first: |-
CON Enter YOUR pin to confirm %{guarded_account_information}'s reset
0. Back
retry: |-
%{retry_pin_entry}
exit_pin_reset_initiated_success: |-
CON Success: You have initiated a PIN reset for %{guarded_account_information}
0. Back
9. Exit
exit_not_authorized_for_pin_reset: |-
CON Failure: You are not authorized to reset that PIN. You must be a guardian!
0. Back
9. Exit
guard_pin: |-
CON Pin guard
1. View guardians
2. Add guardian
3. Remove guardian
0. Back
guardian_list_pin_authorization:
first: |-
CON Enter your pin to view set guardians
0. Back
retry: |-
%{retry_pin_entry}
guardian_list: |-
CON %{guardians_list}
0. Back
9. Exit
add_guardian: |-
CON Enter phone number to add as pin reset guardian
0. Back
add_guardian_pin_authorization:
first: |-
CON Enter your pin to add %{guardian_information} as your PIN reset guardian
0. Back
retry: |-
%{retry_pin_entry}
exit_guardian_addition_success: |-
CON Success: %{guardian_information} can now reset your PIN
0. Back
9. Exit
exit_invalid_guardian_addition: |-
CON %{error_exit}
0. Back
9. Exit
remove_guardian: |-
CON Enter phone number to revoke guardianship:
0. Back
remove_guardian_pin_authorization:
first: |-
CON Enter your pin to remove %{guardian_information} as your PIN reset guardian
0. Back
retry: |-
%{retry_pin_entry}
exit_guardian_removal_success: |-
CON Success: %{guardian_information} PIN reset guardianship is revoked
0. Back
9. Exit
exit_invalid_guardian_removal: |-
CON %{error_exit}
0. Back
9. Exit
transaction_pin_authorization:
first: |-
CON %{recipient_information} will receive %{transaction_amount} %{token_symbol} from %{sender_information}.

View File

@@ -69,7 +69,7 @@ sw:
2. Chagua lugha utakayotumia
3. Angalia salio
4. Angalia taarifa ya matumizi
5. Badilisha nambari ya siri
5. Mipangilio ya nambari ya siri
0. Nyuma
metadata_management: |-
CON Wasifu wangu
@@ -95,6 +95,13 @@ sw:
0. Nyuma
retry_pin_entry: |-
CON Nambari uliyoweka si sahihi, jaribu tena. Una majaribio %{remaining_attempts} yaliyobaki.
0. Nyuma
pin_management: |-
CON Pin options
1. Badilisha nambari yangu ya siri
2. Tuma ombili la kubadilisha nambari ya siri
3. Linda nambari ya siri
0. Nyuma
enter_current_pin:
first: |-
CON Weka nambari ya siri.
@@ -107,6 +114,73 @@ sw:
new_pin_confirmation: |-
CON Weka nambari yako ya siri tena
0. Nyuma
reset_guarded_pin: |-
CON Weka nambari ya simu ili kutuma ombi la kubalisha nambari ya siri.
0. Nyuma
reset_guarded_pin_authorization:
first: |-
CON Weka nambari YAKO ya siri ili kudhibitisha ombi la kubadilisha nambari ya siri ya %{guarded_account_information}.
0. Nyuma
retry: |-
%{retry_pin_entry}
exit_pin_reset_initiated_success: |-
CON Ombi lako la kubadili nambari ya siri ya %{guarded_account_information} limetumwa.
0. Nyuma
9. Ondoka
exit_not_authorized_for_pin_reset: |-
CON Huruhusiwi kutuma ombi la kubadilisha nambari ya siri.
0. Nyuma
9. Ondoka
guard_pin: |-
CON Linda nambari ya siri
1. Walinzi wa namabari ya siri
2. Ongeza mlinzi
3. Ondoa mlinzi
0. Nyuma
guardian_list_pin_authorization:
first: |-
CON Weka nambari yako ya siri ili kuona walinzi uliowaongeza
0. Nyuma
retry: |-
%{retry_pin_entry}
guardian_list: |-
CON %{guardians_list}
0. Nyuma
9. Ondoka
add_guardian: |-
CON Weka nambari ya simu ili kuongeza mlinzi
0. Nyuma
add_guardian_pin_authorization:
first: |-
CON Weka nambari YAKO ya siri ili kumwongeza %{guardian_information} kama mlinzi
0. Nyuma
retry: |-
%{retry_pin_entry}
exit_guardian_addition_success: |-
CON Ombi lako la kumwongeza: %{guardian_information} kama mlinzi limefanikiwa
0. Nyuma
9. Ondoka
exit_invalid_guardian_addition: |-
CON %{error_exit}
0. Nyuma
9. Ondoka
remove_guardian: |-
CON Weka nambari ya simu ili kuondoa mlinzi
0. Nyuma
remove_guardian_pin_authorization:
first: |-
CON Weka nambari YAKO ya siri ili kumwondoa %{guardian_information} kama mlinzi
0. Nyuma
retry: |-
%{retry_pin_entry}
exit_guardian_removal_success: |-
CON Ombi lako la kumwondoa: %{guardian_information} kama mlinzi limefanikiwa
0. Nyuma
9. Ondoka
exit_invalid_guardian_removal: |-
CON %{error_exit}
0. Nyuma
9. Ondoka
transaction_pin_authorization:
first: |-
CON %{recipient_information} atapokea %{transaction_amount} %{token_symbol} kutoka kwa %{sender_information}.

View File

@@ -27,6 +27,7 @@ In the current version of the scripts, two token types may be deployed; [`giftab
This step may be run multiple times, as long as the token symbol is different from all previously deployed tokens.
## 4. Initialize custodial engine.
Adds system accounts to the custodial engine, and unlocks the initialization seal. After this step, the custodial system is ready to use.
@@ -35,10 +36,12 @@ Adds system accounts to the custodial engine, and unlocks the initialization sea
## Services dependency graph
1. evm
2. bootstrap runlevel 1
3. bootstrap runlevel 2
4. bootstrap runlevel 3
2. bootstrap runlevel 1 - deploy global contracts (RUN_MASK=1 docker-compose up bootstrap)
3. bootstrap runlevel 2 - deploy instance contracts (RUN_MASK=2 docker-compose up bootstrap)
4. bootstrap runlevel 4 - deploy token (RUN_MASK=4 docker-compose up bootstrap)
5. redis
6. postgres
7. cic-eth-tasker
8. boostrap runlevel 4
7. cic-eth-tasker
8. boostrap runlevel 8 - deploy custodial contracts (RUN_MASK=8 docker-compose up bootstrap)
9. boostrap runlevel 16 - data seeding for development (RUN_MASK=16 docker-compose up bootstrap)
10. bring up the remainig services (docker-compose up -d)

View File

@@ -19,7 +19,7 @@ COPY requirements.txt .
#RUN apt-get install libffi-dev
ARG pip_index_url=https://pypi.org/simple
ARG EXTRA_PIP_INDEX_URL="https://pip.grassrootseconomics.net:8433"
ARG EXTRA_PIP_INDEX_URL="https://pip.grassrootseconomics.net"
ARG EXTRA_PIP_ARGS=""
ARG PIP_INDEX_URL="https://pypi.org/simple"
ARG pip_trusted_host=pypi.org

View File

@@ -6,24 +6,22 @@ This folder contains tools to generate and import test data.
Three sets of tools are available, sorted by respective subdirectories.
* **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`)
- **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
- **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
- **create_import_users.py**: User creation script
- **verify.py**: Import verification script
- **cic_meta**: Metadata imports
## REQUIREMENTS
@@ -36,14 +34,12 @@ 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`
`pip install --extra-index-url https://pip.grassrootseconomics.net -r requirements.txt`
If you are importing metadata, also do ye olde:
`npm install`
## HOW TO USE
### Step 1 - Data creation
@@ -60,7 +56,6 @@ If you want to use a `import_balance.py` script to add to the user's balance fro
`python create_import_users.py --gift-threshold <max_units_to_send> [--dir <datadir>] <number_of_users>`
### Step 2 - Services
Unless you know what you are doing, start with a clean slate, and execute (in the repository root):
@@ -72,46 +67,46 @@ 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
- eth
In all other cases you will _also_ need:
* postgres
* redis
- postgres
- redis
#### EVM provisions
This step is needed in *all* cases.
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 `<repository_root>/service-configs/.env`
#### 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`
#### Custodial services
If importing using `cic_eth` or `cic_ussd` also run:
* cic-eth-tasker
* cic-eth-dispatcher
* cic-eth-tracker
* cic-eth-retrier
- cic-eth-tasker
- cic-eth-dispatcher
- cic-eth-tracker
- cic-eth-retrier
If importing using `cic_ussd` also run:
* cic-user-tasker
* cic-user-ussd-server
* cic-notify-tasker
- cic-user-tasker
- cic-user-ussd-server
- cic-notify-tasker
If metadata is to be imported, also run:
* cic-meta-server
- cic-meta-server
### Step 3 - User imports
@@ -125,10 +120,7 @@ All external balance transactions are saved in raw wire format in `<datadir>/txs
If the contract migrations have been executed with the default "giftable" token contract, then the `token_symbol` in the `import_balance` scripts should be set to `GFT`.
#### Alternative 1 - Sovereign wallet import - `eth`
#### Alternative 1 - Sovereign wallet import - `eth`
First, make a note of the **block height** before running anything:
@@ -142,9 +134,7 @@ After the script completes, keystore files for all generated accouts will be fou
Then run:
`python eth/import_balance.py -v -r <cic_registry_address> -p <eth_provider> --token-symbol <token_symbol> --offset <block_height_at_start> -y ../keystore/UTC--2021-01-08T17-18-44.521011372Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c <datadir>`
`python eth/import_balance.py -v -r <cic_registry_address> -p <eth_provider> --token-symbol <token_symbol> --offset <block_height_at_start> -y ../keystore/UTC--2021-01-08T17-18-44.521011372Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c <datadir>`
#### Alternative 2 - Custodial engine import - `cic_eth`
@@ -158,7 +148,6 @@ In another terminal:
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`.
@@ -177,13 +166,10 @@ In the event that you are running the command in a local environment you may wan
`python cic_ussd/import_users.py -v --ussd-host <user_ussd_server_host> --ussd-port <user_ussd_server_port> --ussd-no-ssl -c config out`
### 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:
@@ -194,22 +180,18 @@ Monitors a folder for output from the `import_users.py` script, adding the metad
If _number of users_ is omitted the script will run until manually interrupted.
#### Importing phone pointer
`node cic_meta/import_meta_phone.js <datadir> <number_of_users>`
If you imported using `cic_ussd`, the phone pointer is _already added_ and this script will do nothing.
### Importing preferences metadata
`node cic_meta/import_meta_preferences.js <datadir> <number_of_users>`
If you used the `cic_ussd/import_user.py` script to import your users, preferences metadata is generated and will be imported.
##### Importing pins and ussd data (optional)
Once the user imports are complete the next step should be importing the user's pins and auxiliary ussd data. This can be done in 3 steps:
@@ -228,26 +210,26 @@ Once the creation of the pins file is complete, proceed to import the pins and u
`python cic_ussd/import_pins.py -c config -v pinsdir <path to pin export dir tree>`
- To import ussd data:
`python cic_ussd/import_ussd_data.py -c config -v userdir <path to the users export dir tree>`
`python cic_ussd/import_ussd_data.py -c config -v userdir <path to the users export dir tree>`
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 5 - Verify
`python verify.py -v -c config -r <cic_registry_address> -p <eth_provider> --token-symbol <token_symbol> <datadir>`
`python verify.py -v -c config -r <cic_registry_address> -p <eth_provider> --token-symbol <token_symbol> <datadir>`
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
- 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
Checks can be selectively included and excluded. See `--help` for details.
@@ -255,7 +237,6 @@ Will output one line for each check, with name of check and number of errors fou
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.

View File

@@ -17,13 +17,13 @@ COPY common/ cic_ussd/common/
COPY requirements.txt .
COPY config/ config
ARG EXTRA_PIP_INDEX_URL=https://pip.grassrootseconomics.net:8433
ARG EXTRA_PIP_INDEX_URL=https://pip.grassrootseconomics.net
ARG EXTRA_PIP_ARGS=""
ARG PIP_INDEX_URL=https://pypi.org/simple
RUN pip install --index-url $PIP_INDEX_URL \
--extra-index-url $EXTRA_PIP_INDEX_URL $EXTRA_PIP_ARGS \
-r requirements.txt
--extra-index-url $EXTRA_PIP_INDEX_URL $EXTRA_PIP_ARGS \
-r requirements.txt
COPY . .

View File

@@ -47,7 +47,7 @@ services:
args:
DOCKER_REGISTRY: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net:8433}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net}
EXTRA_PIP_ARGS: $EXTRA_PIP_ARGS
environment:
DEV_DATA_DIR: ${DEV_DATA_DIR:-/tmp/cic/config}
@@ -67,7 +67,7 @@ services:
RUN_MASK: ${RUN_MASK:-0}
TOKEN_NAME: $TOKEN_NAME
TOKEN_SYMBOL: $TOKEN_SYMBOL
TOKEN_TYPE: $TOKEN_TYPE
TOKEN_TYPE: ${TOKEN_TYPE:-giftable_erc20_token}
TOKEN_DECIMALS: $TOKEN_DECIMALS
TOKEN_REDISTRIBUTION_PERIOD: $TOKEN_REDISTRIBUTION_PERIOD
TOKEN_SUPPLY_LIMIT: $TOKEN_SUPPLY_LIMIT
@@ -100,7 +100,7 @@ services:
args:
DOCKER_REGISTRY: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net:8433}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net}
EXTRA_PIP_ARGS: $EXTRA_PIP_ARGS
environment:
DATABASE_HOST: ${DATABASE_HOST:-postgres}
@@ -130,7 +130,7 @@ services:
args:
DOCKER_REGISTRY: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net:8433}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net}
EXTRA_PIP_ARGS: $EXTRA_PIP_ARGS
environment:
CIC_REGISTRY_ADDRESS: $CIC_REGISTRY_ADDRESS
@@ -180,7 +180,7 @@ services:
args:
DOCKER_REGISTRY: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net:8433}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net}
EXTRA_PIP_ARGS: $EXTRA_PIP_ARGS
environment:
CIC_REGISTRY_ADDRESS: $CIC_REGISTRY_ADDRESS
@@ -228,7 +228,7 @@ services:
args:
DOCKER_REGISTRY: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net:8433}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net}
EXTRA_PIP_ARGS: $EXTRA_PIP_ARGS
environment:
RPC_PROVIDER: ${RPC_PROVIDER:-http://evm:8545}
@@ -272,7 +272,7 @@ services:
args:
DOCKER_REGISTRY: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net:8433}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net}
EXTRA_PIP_ARGS: $EXTRA_PIP_ARGS
environment:
RPC_PROVIDER: ${RPC_PROVIDER:-http://evm:8545}
@@ -319,7 +319,7 @@ services:
args:
DOCKER_REGISTRY: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net:8433}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net}
EXTRA_PIP_ARGS: $EXTRA_PIP_ARGS
environment:
CIC_REGISTRY_ADDRESS: $CIC_REGISTRY_ADDRESS
@@ -367,7 +367,7 @@ services:
args:
DOCKER_REGISTRY: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net:8433}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net}
EXTRA_PIP_ARGS: $EXTRA_PIP_ARGS
environment:
CIC_REGISTRY_ADDRESS: $CIC_REGISTRY_ADDRESS
@@ -415,7 +415,7 @@ services:
args:
DOCKER_REGISTRY: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net:8433}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net}
EXTRA_PIP_ARGS: $EXTRA_PIP_ARGS
environment:
DATABASE_HOST: ${DATABASE_HOST:-postgres}
@@ -534,7 +534,7 @@ services:
args:
DOCKER_REGISTRY: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net:8433}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net}
EXTRA_PIP_ARGS: $EXTRA_PIP_ARGS
environment:
DATABASE_HOST: ${DATABASE_HOST:-postgres}
@@ -564,7 +564,7 @@ services:
args:
DOCKER_REGISTRY: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net:8433}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net}
EXTRA_PIP_ARGS: $EXTRA_PIP_ARGS
environment:
DATABASE_HOST: ${DATABASE_HOST:-postgres}
@@ -604,7 +604,7 @@ services:
args:
DOCKER_REGISTRY: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net:8433}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net}
EXTRA_PIP_ARGS: $EXTRA_PIP_ARGS
environment:
DATABASE_HOST: ${DATABASE_HOST:-postgres}
@@ -635,7 +635,7 @@ services:
args:
DOCKER_REGISTRY: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net:8433}
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net}
EXTRA_PIP_ARGS: $EXTRA_PIP_ARGS
environment:
DATABASE_HOST: ${DATABASE_HOST:-postgres}