Compare commits
5 Commits
cic-eth-se
...
sohail/hel
| Author | SHA1 | Date | |
|---|---|---|---|
|
cadaa582f6
|
|||
| cb61e45e4c | |||
| e5b06b18d7 | |||
|
|
5d1a30021a | ||
|
|
ade3f4e917 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,4 +15,3 @@ build/
|
|||||||
.idea
|
.idea
|
||||||
**/.vim
|
**/.vim
|
||||||
**/*secret.yaml
|
**/*secret.yaml
|
||||||
.envrc
|
|
||||||
@@ -15,5 +15,5 @@ To get started see [./apps/contract-migration/README.md](./apps/contract-migrati
|
|||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
[https://docs.grassecon.org/cic_stack/](https://docs.grassecon.org/cic_stack/)
|
[https://docs.grassecon.org/software/](https://docs.grassecon.org/software/)
|
||||||
|
|
||||||
|
|||||||
@@ -1,36 +1 @@
|
|||||||
# CIC-ETH
|
# CIC-ETH
|
||||||
|
|
||||||
## Testing CIC-ETH locally.
|
|
||||||
|
|
||||||
### Setup a Virtual Env
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python3 -m venv ./venv # Python 3.9
|
|
||||||
source ./venv/activate
|
|
||||||
```
|
|
||||||
|
|
||||||
### Running All Unit Tests
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bash ./tests/run_tests.sh # This will also install required dependencies
|
|
||||||
```
|
|
||||||
|
|
||||||
### Running Specific Unit Tests
|
|
||||||
|
|
||||||
Ensure that:
|
|
||||||
|
|
||||||
- You have called `bash ./tests/run_tests.sh` at least once or run the following to install required dependencies
|
|
||||||
- You have activated the virtual environment
|
|
||||||
|
|
||||||
```
|
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
Then here is an example that only runs tests with the keyword(-k) `test_server`
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pytest -s -v --log-cli-level DEBUG --log-level DEBUG -k test_server
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -6,8 +6,11 @@
|
|||||||
# standard imports
|
# standard imports
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
# external imports
|
# external imports
|
||||||
import celery
|
import celery
|
||||||
|
from chainlib.chain import ChainSpec
|
||||||
|
from hexathon import strip_0x
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
from cic_eth.api.base import ApiBase
|
from cic_eth.api.base import ApiBase
|
||||||
from cic_eth.enum import LockEnum
|
from cic_eth.enum import LockEnum
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
# standard imports
|
|
||||||
import os
|
|
||||||
import random
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def blockchain_address() -> str:
|
|
||||||
return os.urandom(20).hex().lower()
|
|
||||||
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
# standard imports
|
|
||||||
import os
|
|
||||||
|
|
||||||
# external imports
|
|
||||||
import pytest
|
|
||||||
from celery import uuid
|
|
||||||
# test imports
|
|
||||||
from cic_eth.pytest.helpers.accounts import blockchain_address
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
|
||||||
def task_uuid():
|
|
||||||
return uuid()
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
|
||||||
def default_token_data(foo_token_symbol, foo_token):
|
|
||||||
return {
|
|
||||||
'symbol': foo_token_symbol,
|
|
||||||
'address': foo_token,
|
|
||||||
'name': 'Giftable Token',
|
|
||||||
'decimals': 6,
|
|
||||||
"converters": []
|
|
||||||
}
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
|
||||||
def mock_account_creation_task_request(mocker, task_uuid):
|
|
||||||
def mock_request(self):
|
|
||||||
mocked_task_request = mocker.patch('celery.app.task.Task.request')
|
|
||||||
mocked_task_request.id = task_uuid
|
|
||||||
return mocked_task_request
|
|
||||||
mocker.patch('cic_eth.api.api_task.Api.create_account', mock_request)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
|
||||||
def mock_account_creation_task_result(mocker, task_uuid):
|
|
||||||
def task_result(self):
|
|
||||||
sync_res = mocker.patch('celery.result.AsyncResult')
|
|
||||||
sync_res.id = task_uuid
|
|
||||||
sync_res.get.return_value = blockchain_address()
|
|
||||||
return sync_res
|
|
||||||
mocker.patch('cic_eth.api.api_task.Api.create_account', task_result)
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
|
||||||
def mock_token_api_query(foo_token_symbol, foo_token, mocker, task_uuid):
|
|
||||||
def mock_query(self, token_symbol, proof=None):
|
|
||||||
sync_res = mocker.patch('celery.result.AsyncResult')
|
|
||||||
sync_res.id = task_uuid
|
|
||||||
sync_res.get.return_value = [
|
|
||||||
{
|
|
||||||
'address': foo_token,
|
|
||||||
'converters': [],
|
|
||||||
'decimals': 6,
|
|
||||||
'name': 'Giftable Token',
|
|
||||||
'proofs': ['5b1549818725ca07c19fc47fda5d8d85bbebb1283855d5ab99785dcb7d9051d3'],
|
|
||||||
'symbol': foo_token_symbol,
|
|
||||||
},{'5b1549818725ca07c19fc47fda5d8d85bbebb1283855d5ab99785dcb7d9051d3': ['Eb3907eCad74a0013c259D5874AE7f22DcBcC95C','Eb3907eCad74a0013c259D5874AE7f22DcBcC95C']}
|
|
||||||
]
|
|
||||||
return sync_res
|
|
||||||
mocker.patch('cic_eth.api.api_task.Api.token', mock_query)
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
|
||||||
def mock_tokens_api_query(foo_token_symbol, foo_token, mocker, task_uuid):
|
|
||||||
def mock_query(self, token_symbol, proof=None):
|
|
||||||
sync_res = mocker.patch('celery.result.AsyncResult')
|
|
||||||
sync_res.id = task_uuid
|
|
||||||
sync_res.get.return_value = [[
|
|
||||||
{
|
|
||||||
'address': foo_token,
|
|
||||||
'converters': [],
|
|
||||||
'decimals': 6,
|
|
||||||
'name': 'Giftable Token',
|
|
||||||
'proofs': ['5b1549818725ca07c19fc47fda5d8d85bbebb1283855d5ab99785dcb7d9051d3'],
|
|
||||||
'symbol': foo_token_symbol,
|
|
||||||
},{'5b1549818725ca07c19fc47fda5d8d85bbebb1283855d5ab99785dcb7d9051d3': ['Eb3907eCad74a0013c259D5874AE7f22DcBcC95C','Eb3907eCad74a0013c259D5874AE7f22DcBcC95C']}
|
|
||||||
], [
|
|
||||||
{
|
|
||||||
'address': foo_token,
|
|
||||||
'converters': [],
|
|
||||||
'decimals': 6,
|
|
||||||
'name': 'Giftable Token',
|
|
||||||
'proofs': ['5b1549818725ca07c19fc47fda5d8d85bbebb1283855d5ab99785dcb7d9051d3'],
|
|
||||||
'symbol': foo_token_symbol,
|
|
||||||
},{'5b1549818725ca07c19fc47fda5d8d85bbebb1283855d5ab99785dcb7d9051d3': ['Eb3907eCad74a0013c259D5874AE7f22DcBcC95C','Eb3907eCad74a0013c259D5874AE7f22DcBcC95C']}
|
|
||||||
]]
|
|
||||||
return sync_res
|
|
||||||
mocker.patch('cic_eth.api.api_task.Api.tokens', mock_query)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
|
||||||
def mock_sync_balance_api_query(balances, mocker, task_uuid):
|
|
||||||
def sync_api_query(self, address: str, token_symbol: str):
|
|
||||||
sync_res = mocker.patch('celery.result.AsyncResult')
|
|
||||||
sync_res.id = task_uuid
|
|
||||||
sync_res.get.return_value = balances
|
|
||||||
return sync_res
|
|
||||||
mocker.patch('cic_eth.api.api_task.Api.balance', sync_api_query)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
|
||||||
def mock_sync_default_token_api_query(default_token_data, mocker, task_uuid):
|
|
||||||
def mock_query(self):
|
|
||||||
sync_res = mocker.patch('celery.result.AsyncResult')
|
|
||||||
sync_res.id = task_uuid
|
|
||||||
sync_res.get.return_value = default_token_data
|
|
||||||
return sync_res
|
|
||||||
mocker.patch('cic_eth.api.api_task.Api.default_token', mock_query)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
|
||||||
def mock_transaction_list_query(mocker):
|
|
||||||
query_args = {}
|
|
||||||
|
|
||||||
def mock_query(self, address: str, limit: int):
|
|
||||||
query_args['address'] = address
|
|
||||||
query_args['limit'] = limit
|
|
||||||
|
|
||||||
mocker.patch('cic_eth.api.api_task.Api.list', mock_query)
|
|
||||||
return query_args
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
|
||||||
def mock_transfer_api(mocker):
|
|
||||||
transfer_args = {}
|
|
||||||
|
|
||||||
def mock_transfer(self, from_address: str, to_address: str, value: int, token_symbol: str):
|
|
||||||
transfer_args['from_address'] = from_address
|
|
||||||
transfer_args['to_address'] = to_address
|
|
||||||
transfer_args['value'] = value
|
|
||||||
transfer_args['token_symbol'] = token_symbol
|
|
||||||
|
|
||||||
mocker.patch('cic_eth.api.api_task.Api.transfer', mock_transfer)
|
|
||||||
return transfer_args
|
|
||||||
@@ -1,11 +1,15 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
import sys
|
import sys
|
||||||
|
import os
|
||||||
import logging
|
import logging
|
||||||
import uuid
|
import uuid
|
||||||
import json
|
import json
|
||||||
|
import argparse
|
||||||
|
|
||||||
# external imports
|
# external imports
|
||||||
import redis
|
import redis
|
||||||
|
from xdg.BaseDirectory import xdg_config_home
|
||||||
|
from chainlib.chain import ChainSpec
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
import cic_eth.cli
|
import cic_eth.cli
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
import logging
|
|
||||||
|
|
||||||
import cic_eth.cli
|
|
||||||
from cic_eth.server.app import create_app
|
|
||||||
from cic_eth.server.celery import create_celery_wrapper
|
|
||||||
|
|
||||||
arg_flags = cic_eth.cli.argflag_std_base
|
|
||||||
local_arg_flags = cic_eth.cli.argflag_local_taskcallback
|
|
||||||
argparser = cic_eth.cli.ArgumentParser(arg_flags)
|
|
||||||
argparser.process_local_flags(local_arg_flags)
|
|
||||||
args = argparser.parse_args()
|
|
||||||
config = cic_eth.cli.Config.from_args(args, arg_flags, local_arg_flags)
|
|
||||||
# Define log levels
|
|
||||||
if args.vv:
|
|
||||||
logging.getLogger().setLevel(logging.DEBUG)
|
|
||||||
elif args.v:
|
|
||||||
logging.getLogger().setLevel(logging.INFO)
|
|
||||||
|
|
||||||
|
|
||||||
# Setup Celery App
|
|
||||||
celery_app = cic_eth.cli.CeleryApp.from_config(config)
|
|
||||||
celery_app.set_default()
|
|
||||||
|
|
||||||
|
|
||||||
chain_spec = config.get('CHAIN_SPEC')
|
|
||||||
celery_queue = config.get('CELERY_QUEUE')
|
|
||||||
redis_host = config.get('REDIS_HOST')
|
|
||||||
redis_port = config.get('REDIS_PORT')
|
|
||||||
redis_db = config.get('REDIS_DB')
|
|
||||||
redis_timeout = config.get('REDIS_TIMEOUT')
|
|
||||||
|
|
||||||
celery_wrapper = create_celery_wrapper(celery_queue=celery_queue, chain_spec=chain_spec,
|
|
||||||
redis_db=redis_db, redis_host=redis_host, redis_port=redis_port, redis_timeout=redis_timeout)
|
|
||||||
app = create_app(celery_wrapper)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import uvicorn
|
|
||||||
uvicorn.run(app, host="0.0.0.0", port=5000, log_level="info")
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
from . import converters
|
|
||||||
from . import cache
|
|
||||||
from . import celery
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
import logging
|
|
||||||
import sys
|
|
||||||
from typing import List, Optional, Union
|
|
||||||
|
|
||||||
from cic_eth.server import cache, converters
|
|
||||||
from cic_eth.server.cache import setup_cache
|
|
||||||
from cic_eth.server.celery import create_celery_wrapper
|
|
||||||
from cic_eth.server.models import (DefaultToken, Token, TokenBalance,
|
|
||||||
Transaction)
|
|
||||||
from fastapi import FastAPI, Query
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def create_app(celery_wrapper):
|
|
||||||
|
|
||||||
app = FastAPI(debug=True,
|
|
||||||
title="Grassroots Economics",
|
|
||||||
description="CIC ETH API",
|
|
||||||
version="0.0.1",
|
|
||||||
terms_of_service="https://www.grassrootseconomics.org/pages/terms-and-conditions.html",
|
|
||||||
contact={
|
|
||||||
"name": "Grassroots Economics",
|
|
||||||
"url": "https://www.grassrootseconomics.org",
|
|
||||||
"email": "will@grassecon.org"
|
|
||||||
},
|
|
||||||
license_info={
|
|
||||||
"name": "GPLv3",
|
|
||||||
})
|
|
||||||
|
|
||||||
@app.get("/transactions", response_model=List[Transaction])
|
|
||||||
def transactions(address: str, limit: Optional[str] = 10):
|
|
||||||
return celery_wrapper('list', address, limit=limit)
|
|
||||||
|
|
||||||
@app.get("/balance", response_model=List[TokenBalance])
|
|
||||||
def balance(token_symbol: str, address: str = Query(..., title="Address", min_length=40, max_length=42), include_pending: bool = True):
|
|
||||||
log.info(f"address: {address}")
|
|
||||||
log.info(f"token_symbol: {token_symbol}")
|
|
||||||
data = celery_wrapper('balance', address, token_symbol,
|
|
||||||
include_pending=include_pending)
|
|
||||||
for b in data:
|
|
||||||
token = get_token(token_symbol)
|
|
||||||
b['balance_network'] = converters.from_wei(
|
|
||||||
token.decimals, int(b['balance_network']))
|
|
||||||
b['balance_incoming'] = converters.from_wei(
|
|
||||||
token.decimals, int(b['balance_incoming']))
|
|
||||||
b['balance_outgoing'] = converters.from_wei(
|
|
||||||
token.decimals, int(b['balance_outgoing']))
|
|
||||||
|
|
||||||
b.update({
|
|
||||||
"balance_available": int(b['balance_network']) + int(b['balance_incoming']) - int(b['balance_outgoing'])
|
|
||||||
})
|
|
||||||
return data
|
|
||||||
|
|
||||||
@app.post("/create_account")
|
|
||||||
def create_account(password: Optional[str] = None, register: bool = True):
|
|
||||||
data = celery_wrapper(
|
|
||||||
'create_account', password=password, register=register)
|
|
||||||
return data
|
|
||||||
|
|
||||||
# def refill_gas(start_response, query: dict):
|
|
||||||
# address = query.pop('address')
|
|
||||||
# data = celery_wrapper('refill_gas', address)
|
|
||||||
# return data
|
|
||||||
|
|
||||||
# def ping(start_response, query: dict):
|
|
||||||
# data = celery_wrapper('ping', **query)
|
|
||||||
# return data
|
|
||||||
|
|
||||||
@app.post("/transfer")
|
|
||||||
def transfer(from_address: str, to_address: str, value: int, token_symbol: str):
|
|
||||||
token = get_token(
|
|
||||||
token_symbol)
|
|
||||||
wei_value = converters.to_wei(token.decimals, int(value))
|
|
||||||
data = celery_wrapper('transfer', from_address,
|
|
||||||
to_address, wei_value, token_symbol)
|
|
||||||
return data
|
|
||||||
|
|
||||||
@app.post("/transfer_from")
|
|
||||||
def transfer_from(from_address: str, to_address: str, value: int, token_symbol: str, spender_address: str):
|
|
||||||
token = get_token(
|
|
||||||
token_symbol)
|
|
||||||
wei_value = converters.to_wei(token.decimals, int(value))
|
|
||||||
data = celery_wrapper('transfer_from', from_address, to_address,
|
|
||||||
wei_value, token_symbol, spender_address)
|
|
||||||
return data
|
|
||||||
|
|
||||||
@app.get("/token", response_model=Token)
|
|
||||||
def token(token_symbol: str, proof: Optional[str] = None):
|
|
||||||
token = get_token(token_symbol)
|
|
||||||
if token == None:
|
|
||||||
sys.stderr.write(f"Cached Token {token_symbol} not found")
|
|
||||||
data = celery_wrapper('token', token_symbol, proof=proof)
|
|
||||||
token = Token.new(data)
|
|
||||||
sys.stderr.write(f"Token {token}")
|
|
||||||
|
|
||||||
return token
|
|
||||||
|
|
||||||
@app.get("/tokens", response_model=List[Token])
|
|
||||||
def tokens(token_symbols: Optional[List[str]] = Query(None), proof: Optional[Union[str, List[str], List[List[str]]]] = None):
|
|
||||||
data = celery_wrapper('tokens', token_symbols,
|
|
||||||
catch=len(token_symbols), proof=proof)
|
|
||||||
if data:
|
|
||||||
tokens = []
|
|
||||||
for token in data:
|
|
||||||
print(f"Token: {token}")
|
|
||||||
tokens.append(Token.new(token))
|
|
||||||
return tokens
|
|
||||||
return None
|
|
||||||
|
|
||||||
@app.get("/default_token", response_model=DefaultToken)
|
|
||||||
def default_token():
|
|
||||||
data = celery_wrapper('default_token')
|
|
||||||
return data
|
|
||||||
|
|
||||||
def get_token(token_symbol: str):
|
|
||||||
data = celery_wrapper('token', token_symbol)
|
|
||||||
return Token.new(data)
|
|
||||||
return app
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
# standard imports
|
|
||||||
import hashlib
|
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
from typing import Optional, Union
|
|
||||||
|
|
||||||
from cic_eth.server.models import Token
|
|
||||||
from cic_types.condiments import MetadataPointer
|
|
||||||
from redis import Redis, StrictRedis
|
|
||||||
|
|
||||||
logg = logging.getLogger(__file__)
|
|
||||||
|
|
||||||
|
|
||||||
class Cache:
|
|
||||||
store: Redis = None
|
|
||||||
|
|
||||||
|
|
||||||
def setup_cache(redis_host, redis_port, redis_db):
|
|
||||||
# Define universal redis cache access
|
|
||||||
Cache.store = StrictRedis(
|
|
||||||
host=redis_host, port=redis_port, db=redis_db, decode_responses=True)
|
|
||||||
|
|
||||||
|
|
||||||
def get_token_data(token_symbol: str):
|
|
||||||
"""
|
|
||||||
:param token_symbol:
|
|
||||||
:type token_symbol:
|
|
||||||
:return:
|
|
||||||
:rtype:
|
|
||||||
"""
|
|
||||||
identifier = [token_symbol.encode('utf-8')]
|
|
||||||
key = cache_data_key(identifier, MetadataPointer.TOKEN_DATA)
|
|
||||||
logg.debug(f'Retrieving token data for: {token_symbol} at: {key}')
|
|
||||||
token_data_str = get_cached_data(key=key)
|
|
||||||
if(token_data_str is None):
|
|
||||||
logg.debug(f'No token data found for: {token_symbol}')
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
token_data = json.loads(token_data_str)
|
|
||||||
logg.debug(f'Retrieved token data: {token_data}')
|
|
||||||
return token_data
|
|
||||||
|
|
||||||
|
|
||||||
def set_token_data(token_symbol: str, token: dict):
|
|
||||||
"""
|
|
||||||
:param token_symbol:
|
|
||||||
:type token_symbol:
|
|
||||||
:return:
|
|
||||||
:rtype:
|
|
||||||
"""
|
|
||||||
identifier = [token_symbol.encode('utf-8')]
|
|
||||||
key = cache_data_key(identifier, MetadataPointer.TOKEN_DATA)
|
|
||||||
cache_data(key, json.dumps(token))
|
|
||||||
logg.debug(f'Cached token data for: {token_symbol} at: {key}')
|
|
||||||
|
|
||||||
|
|
||||||
def get_default_token() -> Optional[str]:
|
|
||||||
"""This function attempts to retrieve the default token's data from the redis cache.
|
|
||||||
:return:
|
|
||||||
:rtype:
|
|
||||||
"""
|
|
||||||
logg.debug(f'Retrieving default token from cache')
|
|
||||||
# TODO: What should the identifier be?
|
|
||||||
key = cache_data_key(identifier="ff".encode('utf-8'),
|
|
||||||
salt=MetadataPointer.TOKEN_DEFAULT)
|
|
||||||
default_token_str = get_cached_data(key=key)
|
|
||||||
if default_token_str is None:
|
|
||||||
logg.debug(f'No cached default token found: {key}')
|
|
||||||
return None
|
|
||||||
default_token = json.loads(default_token_str)
|
|
||||||
logg.debug(f'Retrieved default token data: {default_token}')
|
|
||||||
return default_token
|
|
||||||
|
|
||||||
|
|
||||||
def set_default_token(default_token: dict):
|
|
||||||
"""
|
|
||||||
:param default_token:
|
|
||||||
:type default_token:
|
|
||||||
:return:
|
|
||||||
:rtype:
|
|
||||||
"""
|
|
||||||
logg.debug(f'Setting default token in cache')
|
|
||||||
key = cache_data_key(identifier="ff".encode('utf-8'),
|
|
||||||
salt=MetadataPointer.TOKEN_DEFAULT)
|
|
||||||
cache_data(key, json.dumps(default_token))
|
|
||||||
|
|
||||||
|
|
||||||
def cache_data(key: str, data: str):
|
|
||||||
"""
|
|
||||||
:param key:
|
|
||||||
:type key:
|
|
||||||
:param data:
|
|
||||||
:type data:
|
|
||||||
:return:
|
|
||||||
:rtype:
|
|
||||||
"""
|
|
||||||
cache = Cache.store
|
|
||||||
cache.set(name=key, value=data)
|
|
||||||
cache.persist(name=key)
|
|
||||||
logg.debug(f'caching: {data} with key: {key}.')
|
|
||||||
|
|
||||||
|
|
||||||
def get_cached_data(key: str):
|
|
||||||
"""
|
|
||||||
:param key:
|
|
||||||
:type key:
|
|
||||||
:return:
|
|
||||||
:rtype:
|
|
||||||
"""
|
|
||||||
cache = Cache.store
|
|
||||||
return cache.get(name=key)
|
|
||||||
|
|
||||||
|
|
||||||
def cache_data_key(identifier: Union[list, bytes], salt: MetadataPointer):
|
|
||||||
"""
|
|
||||||
:param identifier:
|
|
||||||
:type identifier:
|
|
||||||
:param salt:
|
|
||||||
:type salt:
|
|
||||||
:return:
|
|
||||||
:rtype:
|
|
||||||
"""
|
|
||||||
hash_object = hashlib.new("sha256")
|
|
||||||
if isinstance(identifier, list):
|
|
||||||
for identity in identifier:
|
|
||||||
hash_object.update(identity)
|
|
||||||
else:
|
|
||||||
hash_object.update(identifier)
|
|
||||||
hash_object.update(salt.value.encode(encoding="utf-8"))
|
|
||||||
return hash_object.digest().hex()
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
import json
|
|
||||||
import logging
|
|
||||||
import sys
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
import redis
|
|
||||||
from cic_eth.api.api_task import Api
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def create_celery_wrapper(chain_spec,
|
|
||||||
celery_queue,
|
|
||||||
redis_host,
|
|
||||||
redis_port,
|
|
||||||
redis_db,
|
|
||||||
redis_timeout):
|
|
||||||
def call(method, *args, catch=1, **kwargs):
|
|
||||||
""" Creates a redis channel and calls `cic_eth.api` with the provided `method` and `*args`. Returns the result of the api call. Catch allows you to specify how many messages to catch before returning.
|
|
||||||
"""
|
|
||||||
log.debug(f"Using redis: {redis_host}, {redis_port}, {redis_db}")
|
|
||||||
redis_channel = str(uuid.uuid4())
|
|
||||||
r = redis.Redis(redis_host, redis_port, redis_db)
|
|
||||||
ps = r.pubsub()
|
|
||||||
ps.subscribe(redis_channel)
|
|
||||||
api = Api(
|
|
||||||
chain_spec,
|
|
||||||
queue=celery_queue,
|
|
||||||
callback_param='{}:{}:{}:{}'.format(
|
|
||||||
redis_host, redis_port, redis_db, redis_channel),
|
|
||||||
callback_task='cic_eth.callbacks.redis.redis',
|
|
||||||
callback_queue=celery_queue,
|
|
||||||
)
|
|
||||||
getattr(api, method)(*args, **kwargs)
|
|
||||||
|
|
||||||
ps.get_message()
|
|
||||||
try:
|
|
||||||
data = []
|
|
||||||
if catch == 1:
|
|
||||||
message = ps.get_message(timeout=redis_timeout)
|
|
||||||
data = json.loads(message['data'])["result"]
|
|
||||||
raise data
|
|
||||||
else:
|
|
||||||
for _i in range(catch):
|
|
||||||
message = ps.get_message(
|
|
||||||
timeout=redis_timeout)
|
|
||||||
result = json.loads(message['data'])["result"]
|
|
||||||
data.append(result)
|
|
||||||
|
|
||||||
except TimeoutError as e:
|
|
||||||
sys.stderr.write(
|
|
||||||
f"cic_eth.api.{method}({args}, {kwargs}) timed out:\n {e}")
|
|
||||||
raise e
|
|
||||||
except Exception as e:
|
|
||||||
sys.stderr.write(
|
|
||||||
f'Unable to parse Data:\n{data}\n Error:\n{e}')
|
|
||||||
raise e
|
|
||||||
|
|
||||||
log.debug(
|
|
||||||
f"cic_eth.api.{method}(args={args}, kwargs={kwargs})\n {data}")
|
|
||||||
|
|
||||||
ps.unsubscribe()
|
|
||||||
return data
|
|
||||||
return call
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
# Stolen from ussd
|
|
||||||
|
|
||||||
from math import trunc
|
|
||||||
|
|
||||||
def from_wei(decimals: int, value: int) -> float:
|
|
||||||
"""This function converts values in Wei to a token in the cic network.
|
|
||||||
:param decimals: The decimals required for wei values.
|
|
||||||
:type decimals: int
|
|
||||||
:param value: Value in Wei
|
|
||||||
:type value: int
|
|
||||||
:return: SRF equivalent of value in Wei
|
|
||||||
:rtype: float
|
|
||||||
"""
|
|
||||||
value = float(value) / (10**decimals)
|
|
||||||
return truncate(value=value, decimals=2)
|
|
||||||
|
|
||||||
|
|
||||||
def to_wei(decimals: int, value: int) -> int:
|
|
||||||
"""This functions converts values from a token in the cic network to Wei.
|
|
||||||
:param decimals: The decimals required for wei values.
|
|
||||||
:type decimals: int
|
|
||||||
:param value: Value in SRF
|
|
||||||
:type value: int
|
|
||||||
:return: Wei equivalent of value in SRF
|
|
||||||
:rtype: int
|
|
||||||
"""
|
|
||||||
return int(value * (10**decimals))
|
|
||||||
|
|
||||||
def truncate(value: float, decimals: int) -> float:
|
|
||||||
"""This function truncates a value to a specified number of decimals places.
|
|
||||||
:param value: The value to be truncated.
|
|
||||||
:type value: float
|
|
||||||
:param decimals: The number of decimals for the value to be truncated to
|
|
||||||
:type decimals: int
|
|
||||||
:return: The truncated value.
|
|
||||||
:rtype: int
|
|
||||||
"""
|
|
||||||
stepper = 10.0**decimals
|
|
||||||
return trunc(stepper*value) / stepper
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from typing import List, Optional
|
|
||||||
|
|
||||||
from pydantic import BaseModel, Field
|
|
||||||
|
|
||||||
|
|
||||||
class Transaction(BaseModel):
|
|
||||||
block_number: Optional[int] = Field(None, example=24531)
|
|
||||||
date_checked: Optional[str] = Field(
|
|
||||||
None, example='2021-11-12T09:36:40.725296')
|
|
||||||
date_created: Optional[str] = Field(
|
|
||||||
None, example='2021-11-12T09:36:40.131292')
|
|
||||||
date_updated: Optional[str] = Field(
|
|
||||||
None, example='2021-11-12T09:36:40.131292')
|
|
||||||
destination_token: Optional[str] = Field(
|
|
||||||
None, example=365185044137427460620354810422988491181438940190
|
|
||||||
)
|
|
||||||
destination_token_decimals: Optional[int] = Field(None, example=6)
|
|
||||||
destination_token_symbol: Optional[str] = Field(None, example='COFE')
|
|
||||||
from_value: Optional[int] = Field(None, example=100000000)
|
|
||||||
hash: Optional[str] = Field(
|
|
||||||
None,
|
|
||||||
example=90380195350511178677041624165156640995490505896556680958001954705731707874291,
|
|
||||||
)
|
|
||||||
nonce: Optional[int] = Field(None, example=1)
|
|
||||||
recipient: Optional[str] = Field(
|
|
||||||
None, example='872e1ec9d499b242ebfcfd0a279a4c3e0cd472c0'
|
|
||||||
)
|
|
||||||
sender: Optional[str] = Field(
|
|
||||||
None, example='1a92b05e0b880127a4c26ac0f68a52df3ac6b89d'
|
|
||||||
)
|
|
||||||
signed_tx: Optional[str] = Field(
|
|
||||||
None,
|
|
||||||
example=1601943273486236942256143665779318355236220334071247753507187634376562549990085710958441113013370129915441072693447256942510246386178938683325073160349857879326297351587330623503997011254644396580777843154770873208185332563272343361515226115860084201932230246018679661802320007832375955345977725551120479084062615799940692628221555193198194825737613358738414884130187144700126061702642574663703095161159219410608270,
|
|
||||||
)
|
|
||||||
source_token: Optional[str] = Field(
|
|
||||||
None, example=365185044137427460620354810422988491181438940190
|
|
||||||
)
|
|
||||||
source_token_decimals: Optional[int] = Field(None, example=6)
|
|
||||||
source_token_symbol: Optional[str] = Field(None, example='COFE')
|
|
||||||
status: Optional[str] = Field(None, example='SUCCESS')
|
|
||||||
status_code: Optional[int] = Field(None, example=4104)
|
|
||||||
timestamp: Optional[int] = Field(None, example=1636709800)
|
|
||||||
to_value: Optional[int] = Field(None, example=100000000)
|
|
||||||
tx_hash: Optional[str] = Field(
|
|
||||||
None,
|
|
||||||
example=90380195350511178677041624165156640995490505896556680958001954705731707874291,
|
|
||||||
)
|
|
||||||
tx_index: Optional[int] = Field(None, example=0)
|
|
||||||
|
|
||||||
|
|
||||||
class DefaultToken(BaseModel):
|
|
||||||
symbol: Optional[str] = Field(None, description='Token Symbol')
|
|
||||||
address: Optional[str] = Field(None, description='Token Address')
|
|
||||||
name: Optional[str] = Field(None, description='Token Name')
|
|
||||||
decimals: Optional[int] = Field(None, description='Decimals')
|
|
||||||
|
|
||||||
|
|
||||||
class TokenBalance(BaseModel):
|
|
||||||
address: Optional[str] = None
|
|
||||||
converters: Optional[List[str]] = None
|
|
||||||
balance_network: Optional[int] = None
|
|
||||||
balance_incoming: Optional[int] = None
|
|
||||||
balance_outgoing: Optional[int] = None
|
|
||||||
balance_available: Optional[int] = None
|
|
||||||
|
|
||||||
|
|
||||||
class Token(BaseModel):
|
|
||||||
decimals: Optional[int] = None
|
|
||||||
name: Optional[str] = None
|
|
||||||
address: Optional[str] = None
|
|
||||||
symbol: Optional[str] = None
|
|
||||||
proofs: Optional[List[str]] = None
|
|
||||||
converters: Optional[List[str]] = None
|
|
||||||
proofs_with_signers: Optional[List[Proof]] = None
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def new(data: List[dict]) -> Token:
|
|
||||||
proofs_with_signers = [{"proof": proof, "signers": signers}
|
|
||||||
for (proof, signers) in data[1].items()]
|
|
||||||
return Token(**data[0],
|
|
||||||
proofs_with_signers=proofs_with_signers,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Proof(BaseModel):
|
|
||||||
proof: Optional[str] = None
|
|
||||||
signers: Optional[List[str]] = None
|
|
||||||
|
|
||||||
|
|
||||||
Token.update_forward_refs()
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
[redis]
|
|
||||||
host=redis
|
|
||||||
database=0
|
|
||||||
password=
|
|
||||||
port=6379
|
|
||||||
@@ -5,5 +5,3 @@ urlybird~=0.0.1
|
|||||||
cic-eth-registry~=0.6.6
|
cic-eth-registry~=0.6.6
|
||||||
cic-types~=0.2.1a8
|
cic-types~=0.2.1a8
|
||||||
cic-eth-aux-erc20-demurrage-token~=0.0.3
|
cic-eth-aux-erc20-demurrage-token~=0.0.3
|
||||||
fastapi[all]==0.70.1
|
|
||||||
uvicorn[standard]<0.16.0
|
|
||||||
@@ -36,7 +36,6 @@ packages =
|
|||||||
cic_eth.db.models
|
cic_eth.db.models
|
||||||
cic_eth.queue
|
cic_eth.queue
|
||||||
cic_eth.ext
|
cic_eth.ext
|
||||||
cic_eth.server
|
|
||||||
cic_eth.runnable
|
cic_eth.runnable
|
||||||
cic_eth.runnable.daemons
|
cic_eth.runnable.daemons
|
||||||
cic_eth.runnable.daemons.filters
|
cic_eth.runnable.daemons.filters
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ from cic_eth.pytest.fixtures_database import *
|
|||||||
from cic_eth.pytest.fixtures_role import *
|
from cic_eth.pytest.fixtures_role import *
|
||||||
from cic_eth.pytest.fixtures_contract import *
|
from cic_eth.pytest.fixtures_contract import *
|
||||||
from cic_eth.pytest.fixtures_token import *
|
from cic_eth.pytest.fixtures_token import *
|
||||||
from cic_eth.pytest.patches.account import *
|
|
||||||
|
|
||||||
from chainlib.eth.pytest import *
|
from chainlib.eth.pytest import *
|
||||||
from eth_contract_registry.pytest import *
|
from eth_contract_registry.pytest import *
|
||||||
from cic_eth_registry.pytest.fixtures_contracts import *
|
from cic_eth_registry.pytest.fixtures_contracts import *
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
pip install --extra-index-url https://pip.grassrootseconomics.net --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 admin_requirements.txt
|
||||||
-r services_requirements.txt \
|
-r services_requirements.txt
|
||||||
-r test_requirements.txt
|
-r test_requirements.txt
|
||||||
|
|
||||||
export PYTHONPATH=. && pytest -x --cov=cic_eth --cov-fail-under=90 --cov-report term-missing tests
|
export PYTHONPATH=. && pytest -x --cov=cic_eth --cov-fail-under=90 --cov-report term-missing tests
|
||||||
|
|||||||
@@ -1,171 +0,0 @@
|
|||||||
# coding: utf-8
|
|
||||||
from __future__ import absolute_import
|
|
||||||
|
|
||||||
import logging
|
|
||||||
import time
|
|
||||||
|
|
||||||
import hexathon
|
|
||||||
import pytest
|
|
||||||
from cic_eth.server.app import create_app
|
|
||||||
from cic_eth.server.celery import create_celery_wrapper
|
|
||||||
from fastapi.testclient import TestClient
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
|
||||||
def celery_wrapper(api):
|
|
||||||
""" Creates a redis channel and calls `cic_eth.api` with the provided `method` and `*args`. Returns the result of the api call. Catch allows you to specify how many messages to catch before returning.
|
|
||||||
"""
|
|
||||||
def wrapper(method, *args, catch=1, **kwargs):
|
|
||||||
t = getattr(api, method)(*args, **kwargs)
|
|
||||||
return t.get()
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
|
||||||
def client(celery_wrapper):
|
|
||||||
app = create_app(celery_wrapper)
|
|
||||||
return TestClient(app)
|
|
||||||
|
|
||||||
|
|
||||||
def test_default_token(client,mock_sync_default_token_api_query):
|
|
||||||
# Default Token
|
|
||||||
response = client.get('/default_token')
|
|
||||||
log.debug(f"balance response {response}")
|
|
||||||
default_token = response.json()
|
|
||||||
assert default_token == {'symbol': 'FOO', 'address': '0xe7c559c40B297d7f039767A2c3677E20B24F1385', 'name': 'Giftable Token', 'decimals': 6}
|
|
||||||
|
|
||||||
def test_token(client, mock_token_api_query):
|
|
||||||
# Default Token
|
|
||||||
response = client.get('/token?token_symbol=FOO')
|
|
||||||
log.debug(f"token response {response}")
|
|
||||||
token = response.json()
|
|
||||||
assert token == {
|
|
||||||
'address': '0xe7c559c40B297d7f039767A2c3677E20B24F1385',
|
|
||||||
'converters': [],
|
|
||||||
'decimals': 6,
|
|
||||||
'name': 'Giftable Token',
|
|
||||||
'proofs': ['5b1549818725ca07c19fc47fda5d8d85bbebb1283855d5ab99785dcb7d9051d3'],
|
|
||||||
'proofs_with_signers': [{'proof': '5b1549818725ca07c19fc47fda5d8d85bbebb1283855d5ab99785dcb7d9051d3',
|
|
||||||
'signers': ['Eb3907eCad74a0013c259D5874AE7f22DcBcC95C', 'Eb3907eCad74a0013c259D5874AE7f22DcBcC95C']}],
|
|
||||||
'symbol': 'FOO',
|
|
||||||
}
|
|
||||||
|
|
||||||
def test_tokens(client, mock_tokens_api_query):
|
|
||||||
# Default Token
|
|
||||||
response = client.get(
|
|
||||||
'/tokens', params={'token_symbols': ['FOO', 'FOO']})
|
|
||||||
|
|
||||||
log.debug(f"tokens response {response}")
|
|
||||||
tokens = response.json()
|
|
||||||
assert tokens == [
|
|
||||||
{
|
|
||||||
'address': '0xe7c559c40B297d7f039767A2c3677E20B24F1385',
|
|
||||||
'converters': [],
|
|
||||||
'decimals': 6,
|
|
||||||
'name': 'Giftable Token',
|
|
||||||
'proofs': ['5b1549818725ca07c19fc47fda5d8d85bbebb1283855d5ab99785dcb7d9051d3'],
|
|
||||||
'proofs_with_signers': [{'proof': '5b1549818725ca07c19fc47fda5d8d85bbebb1283855d5ab99785dcb7d9051d3',
|
|
||||||
'signers': ['Eb3907eCad74a0013c259D5874AE7f22DcBcC95C', 'Eb3907eCad74a0013c259D5874AE7f22DcBcC95C']}],
|
|
||||||
'symbol': 'FOO',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'address': '0xe7c559c40B297d7f039767A2c3677E20B24F1385',
|
|
||||||
'converters': [],
|
|
||||||
'decimals': 6,
|
|
||||||
'name': 'Giftable Token',
|
|
||||||
'proofs': ['5b1549818725ca07c19fc47fda5d8d85bbebb1283855d5ab99785dcb7d9051d3'],
|
|
||||||
'proofs_with_signers': [{'proof': '5b1549818725ca07c19fc47fda5d8d85bbebb1283855d5ab99785dcb7d9051d3',
|
|
||||||
'signers': ['Eb3907eCad74a0013c259D5874AE7f22DcBcC95C', 'Eb3907eCad74a0013c259D5874AE7f22DcBcC95C']}],
|
|
||||||
'symbol': 'FOO',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
@pytest.mark.skip("Not implemented")
|
|
||||||
def test_account(client):
|
|
||||||
# Default Token
|
|
||||||
response = client.get('/default_token')
|
|
||||||
log.debug(f"balance response {response}")
|
|
||||||
default_token = response.json()
|
|
||||||
|
|
||||||
# Create Account 1
|
|
||||||
params = {
|
|
||||||
'password': '',
|
|
||||||
'register': True
|
|
||||||
}
|
|
||||||
response = client.post(
|
|
||||||
'/create_account',
|
|
||||||
params=params)
|
|
||||||
address_1 = hexathon.valid(response.json())
|
|
||||||
|
|
||||||
# Create Account 2
|
|
||||||
params = {
|
|
||||||
'password': '',
|
|
||||||
'register': True
|
|
||||||
}
|
|
||||||
response = client.post('/create_account',
|
|
||||||
params=params)
|
|
||||||
address_2 = hexathon.valid(response.json())
|
|
||||||
time.sleep(30) # Required to allow balance to show
|
|
||||||
|
|
||||||
# Balance Account 1
|
|
||||||
params = {
|
|
||||||
'address': address_1,
|
|
||||||
'token_symbol': 'COFE',
|
|
||||||
'include_pending': True
|
|
||||||
}
|
|
||||||
response = client.get('/balance',
|
|
||||||
params=params)
|
|
||||||
balance = response.json()
|
|
||||||
|
|
||||||
assert (balance[0] == {
|
|
||||||
"address": default_token.get('address').lower(),
|
|
||||||
"balance_available": 30000,
|
|
||||||
"balance_incoming": 0,
|
|
||||||
"balance_network": 30000,
|
|
||||||
"balance_outgoing": 0,
|
|
||||||
"converters": []
|
|
||||||
})
|
|
||||||
|
|
||||||
# Transfer
|
|
||||||
params = {
|
|
||||||
'from_address': address_1,
|
|
||||||
'to_address': address_2,
|
|
||||||
'value': 100,
|
|
||||||
'token_symbol': 'COFE'
|
|
||||||
}
|
|
||||||
response = client.post('/transfer',
|
|
||||||
params=params)
|
|
||||||
transfer = response.json()
|
|
||||||
|
|
||||||
# Balance Account 1
|
|
||||||
params = {
|
|
||||||
'address': address_1,
|
|
||||||
'token_symbol': 'COFE',
|
|
||||||
'include_pending': True
|
|
||||||
}
|
|
||||||
response = client.get('/balance',
|
|
||||||
params=params)
|
|
||||||
balance_after_transfer = response.json()
|
|
||||||
assert (balance_after_transfer[0] == {
|
|
||||||
"address": default_token.get('address').lower(),
|
|
||||||
"balance_available": 29900,
|
|
||||||
"balance_incoming": 0,
|
|
||||||
"balance_network": 30000,
|
|
||||||
"balance_outgoing": 100,
|
|
||||||
"converters": []
|
|
||||||
})
|
|
||||||
|
|
||||||
# Transactions Account 1
|
|
||||||
params = {
|
|
||||||
'address': address_1,
|
|
||||||
'limit': 10
|
|
||||||
}
|
|
||||||
response = client.get('/transactions',
|
|
||||||
params=params)
|
|
||||||
transactions = response.json()
|
|
||||||
# TODO: What are the other 2 transactions
|
|
||||||
assert len(transactions) == 3
|
|
||||||
# Check the transaction is correct
|
|
||||||
# TODO wtf is READSEND (Ready to send? Or already sent)
|
|
||||||
assert transactions[0].status == 'READYSEND'
|
|
||||||
@@ -796,18 +796,18 @@ invalid_service_code,Please dial %{valid_service_code} to access Sarafu Network,
|
|||||||
help,"CON For assistance call %{support_phone}
|
help,"CON For assistance call %{support_phone}
|
||||||
00. Back
|
00. Back
|
||||||
99. Exit","CON Kwa usaidizi piga simu %{support_phone}
|
99. Exit","CON Kwa usaidizi piga simu %{support_phone}
|
||||||
0. Rudi
|
00. Rudi
|
||||||
9. Ondoka","CON Kwa utethyo kuna simu %{support_phone}
|
99. Ondoka","CON Kwa utethyo kuna simu %{support_phone}
|
||||||
0. Itina
|
00. Itina
|
||||||
9. Ondoka","CON Kwa uteithio hora thimu %{support_phone}
|
99. Ondoka","CON Kwa uteithio hora thimu %{support_phone}
|
||||||
0. Coka
|
00. Coka
|
||||||
9. Uma","CON Kwa Kuavizwa piga simu %{support_phone}
|
99. Uma","CON Kwa Kuavizwa piga simu %{support_phone}
|
||||||
0. Uya nyuma
|
00. Uya nyuma
|
||||||
9. Uka","CON Kuom kony go simu e %{support_phone}
|
99. Uka","CON Kuom kony go simu e %{support_phone}
|
||||||
0. Dog chien
|
00. Dog chien
|
||||||
9. Wuogi","CON Qarqars simu dai%{support_phone}
|
99. Wuogi","CON Qarqars simu dai%{support_phone}
|
||||||
0. Dheebi
|
00. Dheebi
|
||||||
9. Bai"
|
99. Bai"
|
||||||
complete,"CON Your request has been sent. You will receive an SMS shortly.
|
complete,"CON Your request has been sent. You will receive an SMS shortly.
|
||||||
00. Back
|
00. Back
|
||||||
99. Exit","CON Ombi lako limetumwa. Utapokea uthibitishaji wa SMS kwa muda mfupi.
|
99. Exit","CON Ombi lako limetumwa. Utapokea uthibitishaji wa SMS kwa muda mfupi.
|
||||||
|
@@ -13,4 +13,4 @@ port =
|
|||||||
ssl =
|
ssl =
|
||||||
|
|
||||||
[system]
|
[system]
|
||||||
guardians_file = var/lib/sys/guardians.txt
|
guardians_file = cic_ussd/data/sys/guardians.txt
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[PIP]
|
[PIP]
|
||||||
extra_index_host = pip.grassrootseconomics.net
|
extra_index_host = pip.grassrootseconomics.net
|
||||||
extra_index_port =
|
extra_index_port = 8433
|
||||||
extra_index_path = /
|
extra_index_path = /
|
||||||
extra_index_proto = https
|
extra_index_proto = https
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ states=states/
|
|||||||
transitions=transitions/
|
transitions=transitions/
|
||||||
|
|
||||||
[system]
|
[system]
|
||||||
guardians_file = var/lib/sys/guardians.txt
|
guardians_file = cic_ussd/data/sys/guardians.txt
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[PIP]
|
[PIP]
|
||||||
extra_index_host = pip.grassrootseconomics.net
|
extra_index_host = pip.grassrootseconomics.net
|
||||||
extra_index_port =
|
extra_index_port = 8433
|
||||||
extra_index_path = /
|
extra_index_path = /
|
||||||
extra_index_proto = https
|
extra_index_proto = https
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
[locale]
|
[locale]
|
||||||
fallback=sw
|
fallback=sw
|
||||||
path=
|
path=cic_ussd/data/locale/
|
||||||
file_builders=var/lib/sys/
|
file_builders=cic_ussd/data/sys/
|
||||||
|
|
||||||
[schema]
|
[schema]
|
||||||
file_path = data/schema
|
file_path = data/schema
|
||||||
|
|
||||||
[languages]
|
[languages]
|
||||||
file = var/lib/sys/languages.json
|
file = cic_ussd/data/sys/languages.json
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[ussd]
|
[ussd]
|
||||||
menu_file=cic_ussd/db/ussd_menu.json
|
menu_file=cic_ussd/data/sys/ussd_menu.json
|
||||||
service_code=*483*46#,*483*061#,*384*96#
|
service_code=*483*46#,*483*061#,*384*96#
|
||||||
user =
|
user =
|
||||||
pass =
|
pass =
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
[locale]
|
[locale]
|
||||||
fallback=sw
|
fallback=sw
|
||||||
path=var/lib/locale/
|
path=cic_ussd/data/locale/
|
||||||
file_builders=var/lib/sys/
|
file_builders=cic_ussd/data/sys/
|
||||||
|
|
||||||
[schema]
|
[schema]
|
||||||
file_path = /usr/local/lib/python3.8/site-packages/cic_translations/data/schema
|
file_path = /usr/local/lib/python3.8/site-packages/cic_translations/data/schema
|
||||||
|
|
||||||
[languages]
|
[languages]
|
||||||
file = var/lib/sys/languages.json
|
file = cic_ussd/data/sys/languages.json
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[ussd]
|
[ussd]
|
||||||
menu_file=data/ussd_menu.json
|
menu_file=cic_ussd/data/sys/ussd_menu.json
|
||||||
service_code=*483*46#,*483*061#,*384*96#
|
service_code=*483*46#,*483*061#,*384*96#
|
||||||
user =
|
user =
|
||||||
pass =
|
pass =
|
||||||
|
|||||||
@@ -3,12 +3,10 @@ ARG DOCKER_REGISTRY="registry.gitlab.com/grassrootseconomics"
|
|||||||
FROM $DOCKER_REGISTRY/cic-base-images:python-3.8.6-dev-e8eb2ee2
|
FROM $DOCKER_REGISTRY/cic-base-images:python-3.8.6-dev-e8eb2ee2
|
||||||
|
|
||||||
RUN apt-get install -y redis-server
|
RUN apt-get install -y redis-server
|
||||||
|
|
||||||
# create secrets directory
|
# create secrets directory
|
||||||
RUN mkdir -vp pgp/keys
|
RUN mkdir -vp pgp/keys
|
||||||
|
|
||||||
# create application directory
|
|
||||||
RUN mkdir -vp cic-ussd
|
|
||||||
RUN mkdir -vp data
|
|
||||||
|
|
||||||
ARG EXTRA_PIP_INDEX_URL=https://pip.grassrootseconomics.net
|
ARG EXTRA_PIP_INDEX_URL=https://pip.grassrootseconomics.net
|
||||||
ARG EXTRA_PIP_ARGS=""
|
ARG EXTRA_PIP_ARGS=""
|
||||||
@@ -25,7 +23,8 @@ RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
|
|||||||
COPY . .
|
COPY . .
|
||||||
RUN python setup.py install
|
RUN python setup.py install
|
||||||
|
|
||||||
COPY cic_ussd/db/ussd_menu.json data/
|
# create local files directory
|
||||||
|
RUN mkdir -vp cic_ussd/data/locale
|
||||||
|
|
||||||
COPY docker/*.sh ./
|
COPY docker/*.sh ./
|
||||||
RUN chmod +x /root/*.sh
|
RUN chmod +x /root/*.sh
|
||||||
|
|||||||
@@ -45,10 +45,10 @@ services:
|
|||||||
context: apps/contract-migration
|
context: apps/contract-migration
|
||||||
dockerfile: docker/Dockerfile
|
dockerfile: docker/Dockerfile
|
||||||
args:
|
args:
|
||||||
DOCKER_REGISTRY: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}
|
DOCKER_REGISTRY: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}
|
||||||
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
|
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
|
||||||
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net}
|
EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net}
|
||||||
EXTRA_PIP_ARGS: $EXTRA_PIP_ARGS
|
EXTRA_PIP_ARGS: $EXTRA_PIP_ARGS
|
||||||
environment:
|
environment:
|
||||||
DEV_DATA_DIR: ${DEV_DATA_DIR:-/tmp/cic/config}
|
DEV_DATA_DIR: ${DEV_DATA_DIR:-/tmp/cic/config}
|
||||||
DEV_CONFIG_RESET: $DEV_CONFIG_RESET
|
DEV_CONFIG_RESET: $DEV_CONFIG_RESET
|
||||||
@@ -172,42 +172,6 @@ services:
|
|||||||
set +a
|
set +a
|
||||||
./start_tasker.sh --aux-all -q cic-eth -vv
|
./start_tasker.sh --aux-all -q cic-eth -vv
|
||||||
|
|
||||||
cic-eth-server:
|
|
||||||
image: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}/cic-eth:${TAG:-latest}
|
|
||||||
ports:
|
|
||||||
- 5000:5000
|
|
||||||
build:
|
|
||||||
context: apps/cic-eth
|
|
||||||
dockerfile: docker/Dockerfile
|
|
||||||
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}
|
|
||||||
EXTRA_PIP_ARGS: $EXTRA_PIP_ARGS
|
|
||||||
environment:
|
|
||||||
REDIS_PORT: 6379
|
|
||||||
REDIS_HOST: redis
|
|
||||||
CHAIN_SPEC: ${CHAIN_SPEC:-evm:byzantium:8996:bloxberg}
|
|
||||||
CELERY_BROKER_URL: ${CELERY_BROKER_URL:-redis://redis}
|
|
||||||
CELERY_RESULT_URL: ${CELERY_RESULT_URL:-redis://redis}
|
|
||||||
CELERY_DEBUG: ${CELERY_DEBUG:-1}
|
|
||||||
restart: unless-stopped
|
|
||||||
depends_on:
|
|
||||||
- cic-eth-tasker
|
|
||||||
- cic-eth-tracker
|
|
||||||
- cic-eth-dispatcher
|
|
||||||
volumes:
|
|
||||||
# - ./apps/cic-eth/:/root
|
|
||||||
- signer-data:/run/crypto-dev-signer
|
|
||||||
- contract-config:/tmp/cic/config/:ro
|
|
||||||
command:
|
|
||||||
- /bin/bash
|
|
||||||
- -c
|
|
||||||
- |
|
|
||||||
set -a
|
|
||||||
if [[ -f /tmp/cic/config/env_reset ]]; then source /tmp/cic/config/env_reset; fi
|
|
||||||
set +a
|
|
||||||
python -m cic_eth.runnable.daemons.server
|
|
||||||
|
|
||||||
cic-eth-tracker:
|
cic-eth-tracker:
|
||||||
image: ${IMAGE_BASE_URL:-registry.gitlab.com/grassrootseconomics/cic-internal-integration}/cic-eth:${TAG:-latest}
|
image: ${IMAGE_BASE_URL:-registry.gitlab.com/grassrootseconomics/cic-internal-integration}/cic-eth:${TAG:-latest}
|
||||||
|
|||||||
Reference in New Issue
Block a user