Compare commits

...

9 Commits

Author SHA1 Message Date
nolash
7efdbf4f30 Revert foreign change 2021-05-15 06:18:01 +02:00
nolash
dddc869355 Add decimals and token name to default token api call return struct 2021-05-15 00:21:26 +02:00
nolash
8bf1364864 Upgrade acoutns index 2021-05-13 18:00:59 +02:00
0d6d7179eb Merge branch 'philip/default-token-bug-fix' into 'master'
Fix hard-coded token symbols.

Closes cic-ussd#42

See merge request grassrootseconomics/cic-internal-integration!142
2021-05-12 11:26:20 +00:00
e7f48f3ce0 Refactors to fix hard-coded token symbols. 2021-05-12 12:51:55 +03:00
Louis Holbrook
b252fab018 Merge branch 'lash/catch-no-contract-crash' into 'master'
cic-eth-tracker: Catch bogus transfers where token address is no contract

See merge request grassrootseconomics/cic-internal-integration!141
2021-05-12 08:10:46 +00:00
nolash
4667916d80 Catch bogus transfers where token address is no contract 2021-05-12 08:48:50 +02:00
1f668384cc Merge branch 'philip/fix-africastalking-parser' into 'master'
Philip/fix africastalking parser

Closes cic-ussd#41

See merge request grassrootseconomics/cic-internal-integration!140
2021-05-11 10:58:00 +00:00
123dc55687 Philip/fix africastalking parser 2021-05-11 10:58:00 +00:00
17 changed files with 86 additions and 47 deletions

View File

@@ -16,4 +16,6 @@ def default_token(self):
return {
'symbol': self.default_token_symbol,
'address': self.default_token_address,
'name': self.default_token_name,
'decimals': self.default_token_decimals,
}

View File

@@ -3,7 +3,10 @@ import logging
# external imports
import celery
from cic_eth_registry.error import UnknownContractError
from cic_eth_registry.error import (
UnknownContractError,
NotAContractError,
)
from chainlib.status import Status as TxStatus
from chainlib.eth.address import to_checksum_address
from chainlib.eth.error import RequestMismatchException
@@ -124,8 +127,7 @@ class CallbackFilter(SyncFilter):
(transfer_type, transfer_data) = parser(tx, conn)
if transfer_type == None:
continue
else:
pass
break
except RequestMismatchException:
continue
@@ -168,7 +170,9 @@ class CallbackFilter(SyncFilter):
t = self.call_back(transfer_type, result)
logg.info('callback success task id {} tx {} queue {}'.format(t, tx.hash, t.queue))
except UnknownContractError:
logg.debug('callback filter {}:{} skipping "transfer" method on unknown contract {} tx {}'.format(tx.queue, tx.method, transfer_data['to'], tx.hash))
logg.debug('callback filter {}:{} skipping "transfer" method on unknown contract {} tx {}'.format(self.queue, self.method, transfer_data['to'], tx.hash))
except NotAContractError:
logg.debug('callback filter {}:{} skipping "transfer" on non-contract address {} tx {}'.format(self.queue, self.method, transfer_data['to'], tx.hash))
def __str__(self):

View File

@@ -22,6 +22,7 @@ from chainlib.eth.connection import (
from chainlib.chain import ChainSpec
from chainqueue.db.models.otx import Otx
from cic_eth_registry.error import UnknownContractError
from cic_eth_registry.erc20 import ERC20Token
import liveness.linux
@@ -203,6 +204,11 @@ def main():
BaseTask.default_token_symbol = config.get('CIC_DEFAULT_TOKEN_SYMBOL')
BaseTask.default_token_address = registry.by_name(BaseTask.default_token_symbol)
default_token = ERC20Token(chain_spec, rpc, BaseTask.default_token_address)
default_token.load(rpc)
BaseTask.default_token_decimals = default_token.decimals
BaseTask.default_token_name = default_token.name
BaseTask.run_dir = config.get('CIC_RUN_DIR')
logg.info('default token set to {} {}'.format(BaseTask.default_token_symbol, BaseTask.default_token_address))

View File

@@ -67,6 +67,8 @@ def main():
token_info = t.get()
print('Default token symbol: {}'.format(token_info['symbol']))
print('Default token address: {}'.format(token_info['address']))
logg.debug('Default token name: {}'.format(token_info['name']))
logg.debug('Default token decimals: {}'.format(token_info['decimals']))
if __name__ == '__main__':

View File

@@ -33,6 +33,8 @@ class BaseTask(celery.Task):
create_gas_oracle = RPCGasOracle
default_token_address = None
default_token_symbol = None
default_token_name = None
default_token_decimals = None
run_dir = '/run'
def create_session(self):

View File

@@ -1,4 +1,4 @@
cic-base==0.1.2b9
cic-base~=0.1.2b11
celery==4.4.7
crypto-dev-signer~=0.4.14b3
confini~=0.3.6rc3
@@ -7,7 +7,7 @@ redis==3.5.3
alembic==1.4.2
websockets==8.1
requests~=2.24.0
eth_accounts_index~=0.0.11a11
eth_accounts_index~=0.0.11a12
erc20-transfer-authorization~=0.3.1a6
uWSGI==2.0.19.1
semver==2.13.0

View File

@@ -4,7 +4,7 @@ LOCALE_FALLBACK=en
LOCALE_PATH=/usr/src/cic-ussd/var/lib/locale/
MAX_BODY_LENGTH=1024
PASSWORD_PEPPER=QYbzKff6NhiQzY3ygl2BkiKOpER8RE/Upqs/5aZWW+I=
SERVICE_CODE=*483*46#
SERVICE_CODE=*483*46#,*483*061#,*384*96#
[phone_number]
REGION=KE

View File

@@ -24,7 +24,7 @@ def from_wei(value: int) -> float:
"""This function converts values in Wei to a token in the cic network.
:param value: Value in Wei
:type value: int
:return: SRF equivalent of value in Wei
:return: platform's default token equivalent of value in Wei
:rtype: float
"""
value = float(value) / 1e+6
@@ -33,9 +33,9 @@ def from_wei(value: int) -> float:
def to_wei(value: int) -> int:
"""This functions converts values from a token in the cic network to Wei.
:param value: Value in SRF
:param value: Value in platform's default token
:type value: int
:return: Wei equivalent of value in SRF
:return: Wei equivalent of value in platform's default token
:rtype: int
"""
return int(value * 1e+6)
return int(value * 1e+6)

View File

@@ -13,7 +13,7 @@ import argparse
import logging
import urllib
from xdg.BaseDirectory import xdg_config_home
from urllib import request
from urllib import parse, request
# third-party imports
from confini import Config
@@ -92,9 +92,9 @@ def main():
data['text'] = user_input
req = urllib.request.Request(url)
data_str = json.dumps(data)
data_bytes = data_str.encode('utf-8')
req.add_header('Content-Type', 'application/json')
urlencoded_data = parse.urlencode(data)
data_bytes = urlencoded_data.encode('utf-8')
req.add_header('Content-Type', 'application/x-www-form-urlencoded')
req.data = data_bytes
response = urllib.request.urlopen(req)
response_data = response.read().decode('utf-8')

View File

@@ -4,6 +4,7 @@
# standard imports
import json
import logging
from urllib.parse import parse_qs
# third-party imports
import celery
@@ -33,8 +34,7 @@ from cic_ussd.requests import (get_request_endpoint,
from cic_ussd.runnable.server_base import exportable_parser, logg
from cic_ussd.session.ussd_session import UssdSession as InMemoryUssdSession
from cic_ussd.state_machine import UssdStateMachine
from cic_ussd.validator import check_ip, check_request_content_length, check_service_code, validate_phone_number, \
validate_presence
from cic_ussd.validator import check_ip, check_request_content_length, validate_phone_number, validate_presence
args = exportable_parser.parse_args()
@@ -124,6 +124,9 @@ else:
raise InitializationError(f'Default token data for: {chain_str} not found.')
valid_service_codes = config.get('APP_SERVICE_CODE').split(",")
def application(env, start_response):
"""Loads python code for application to be accessible over web server
:param env: Object containing server and request information
@@ -139,13 +142,27 @@ def application(env, start_response):
if get_request_method(env=env) == 'POST' and get_request_endpoint(env=env) == '/':
# get post data
post_data = json.load(env.get('wsgi.input'))
if env.get('CONTENT_TYPE') != 'application/x-www-form-urlencoded':
start_response('405 Play by the rules', errors_headers)
return []
service_code = post_data.get('serviceCode')
phone_number = post_data.get('phoneNumber')
external_session_id = post_data.get('sessionId')
user_input = post_data.get('text')
post_data = env.get('wsgi.input').read()
post_data = post_data.decode('utf-8')
try:
post_data = parse_qs(post_data)
except TypeError:
start_response('400 Size matters', errors_headers)
return []
service_code = post_data.get('serviceCode')[0]
phone_number = post_data.get('phoneNumber')[0]
external_session_id = post_data.get('sessionId')[0]
try:
user_input = post_data.get('text')[0]
except TypeError:
user_input = ""
# add validation for phone number
if phone_number:
@@ -162,14 +179,14 @@ def application(env, start_response):
return []
# validate service code
if not check_service_code(code=service_code, config=config):
if service_code not in valid_service_codes:
response = define_multilingual_responses(
key='ussd.kenya.invalid_service_code',
locales=['en', 'sw'],
prefix='END',
valid_service_code=config.get('APP_SERVICE_CODE'))
response_bytes, headers = define_response_with_content(headers=errors_headers, response=response)
start_response('400 Invalid service code', headers)
valid_service_code=valid_service_codes[0])
response_bytes, headers = define_response_with_content(headers=headers, response=response)
start_response('200 OK', headers)
return [response_bytes]
# validate phone number
@@ -192,3 +209,8 @@ def application(env, start_response):
start_response('200 OK,', headers)
SessionBase.session.close()
return [response_bytes]
else:
start_response('405 Play by the rules', errors_headers)
return []

View File

@@ -12,6 +12,7 @@ from cic_ussd.chain import Chain
from cic_ussd.db.models.account import AccountStatus, Account
from cic_ussd.operations import save_to_in_memory_ussd_session_data
from cic_ussd.phone_number import get_user_by_phone_number
from cic_ussd.processor import retrieve_token_symbol
from cic_ussd.redis import create_cached_data_key, get_cached_data
from cic_ussd.transactions import OutgoingTransactionProcessor
@@ -124,14 +125,18 @@ def process_transaction_request(state_machine_data: Tuple[str, dict, Account]):
"""
user_input, ussd_session, user = state_machine_data
# retrieve token symbol
chain_str = Chain.spec.__str__()
# get user from phone number
recipient_phone_number = ussd_session.get('session_data').get('recipient_phone_number')
recipient = get_user_by_phone_number(phone_number=recipient_phone_number)
to_address = recipient.blockchain_address
from_address = user.blockchain_address
amount = int(ussd_session.get('session_data').get('transaction_amount'))
chain_str = Chain.spec.__str__()
token_symbol = retrieve_token_symbol(chain_str=chain_str)
outgoing_tx_processor = OutgoingTransactionProcessor(chain_str=chain_str,
from_address=from_address,
to_address=to_address)
outgoing_tx_processor.process_outgoing_transfer_transaction(amount=amount)
outgoing_tx_processor.process_outgoing_transfer_transaction(amount=amount, token_symbol=token_symbol)

View File

@@ -120,7 +120,7 @@ class OutgoingTransactionProcessor:
self.from_address = from_address
self.to_address = to_address
def process_outgoing_transfer_transaction(self, amount: int, token_symbol='SRF'):
def process_outgoing_transfer_transaction(self, amount: int, token_symbol: str):
"""This function initiates standard transfers between one account to another
:param amount: The amount of tokens to be sent
:type amount: int

View File

@@ -45,19 +45,6 @@ def check_request_content_length(config: Config, env: dict):
config.get('APP_MAX_BODY_LENGTH'))
def check_service_code(code: str, config: Config):
"""Checks whether provided code matches expected service code
:param config: A dictionary object containing configuration values
:type config: Config
:param code: Service code passed over request
:type code: str
:return: Service code validity
:rtype: boolean
"""
return code == config.get('APP_SERVICE_CODE')
def check_known_user(phone: str):
"""
This method attempts to ascertain whether the user already exists and is known to the system.

View File

@@ -158,6 +158,8 @@ en:
Your Sarafu-Network balances is: %{token_balance}
00. Back
99. Exit
invalid_service_code: |-
Please dial %{valid_service_code} to access Sarafu Network
help: |-
CON For assistance call %{support_phone}
00. Back

View File

@@ -158,6 +158,8 @@ sw:
Akaunti yako ya Sarafu-Network ina salio ifuatayo: %{token_balance}
00. Nyuma
99. Ondoka
invalid_service_code: |-
Bonyeza %{valid_service_code} kutumia mtandao wa Sarafu
help: |-
CON Kwa usaidizi piga simu %{support_phone}
0. Nyuma

View File

@@ -54,10 +54,10 @@ ENV PATH $NVM_DIR/versions/node//v$NODE_VERSION/bin:$PATH
ARG pip_extra_args=""
ARG pip_index_url=https://pypi.org/simple
ARG pip_extra_index_url=https://pip.grassrootseconomics.net:8433
ARG cic_base_version=0.1.2b8
ARG cic_eth_version=0.11.0b12
ARG cic_base_version=0.1.2b11
ARG cic_eth_version=0.11.0b14
ARG sarafu_token_version=0.0.1a8
ARG sarafu_faucet_version=0.0.3a2
ARG sarafu_faucet_version=0.0.3a3
RUN pip install --index-url https://pypi.org/simple --extra-index-url $pip_extra_index_url \
cic-base[full_graph]==$cic_base_version \
cic-eth==$cic_eth_version \

View File

@@ -33,6 +33,7 @@ from chainlib.eth.tx import TxFactory
from chainlib.jsonrpc import jsonrpc_template
from chainlib.eth.error import EthException
from chainlib.chain import ChainSpec
from chainlib.eth.constant import ZERO_ADDRESS
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
from crypto_dev_signer.keystore.dict import DictKeystore
from cic_types.models.person import Person
@@ -51,7 +52,7 @@ argparser.add_argument('-c', type=str, default=config_dir, help='config root to
argparser.add_argument('--old-chain-spec', type=str, dest='old_chain_spec', default='evm:oldchain:1', help='chain spec')
argparser.add_argument('-i', '--chain-spec', type=str, dest='i', help='chain spec')
argparser.add_argument('-r', '--registry-address', type=str, dest='r', help='CIC Registry address')
argparser.add_argument('--token-symbol', default='SRF', type=str, dest='token_symbol', help='Token symbol to use for trnsactions')
argparser.add_argument('--token-symbol', default='GFT', type=str, dest='token_symbol', help='Token symbol to use for trnsactions')
argparser.add_argument('--head', action='store_true', help='start at current block height (overrides --offset)')
argparser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration')
argparser.add_argument('-q', type=str, default='cic-eth', help='celery queue to submit transaction tasks to')
@@ -252,6 +253,10 @@ def main():
except ValueError as e:
logg.critical('lookup failed for token {}: {}'.format(token_symbol, e))
sys.exit(1)
if sarafu_token_address == ZERO_ADDRESS:
raise KeyError('token address for symbol {} is zero'.format(token_symbol))
logg.info('found token address {}'.format(sarafu_token_address))
syncer_backend = MemBackend(chain_str, 0)