diff --git a/requirements.txt b/requirements.txt index 6e26533d..a87dfe57 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ requests==2.20.0 base58==1.0.2 +PyYAML==3.13 \ No newline at end of file diff --git a/src/config/__init__.py b/src/config/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/config/addr_type.py b/src/config/addr_type.py new file mode 100644 index 00000000..a8e4abaa --- /dev/null +++ b/src/config/addr_type.py @@ -0,0 +1,8 @@ +from enum import Enum + + +class AddrType(Enum): + KT = 1 + TZ = 2 + KTALS = 3 + TZALS = 4 diff --git a/src/config/config_parser.py b/src/config/config_parser.py new file mode 100644 index 00000000..76143af9 --- /dev/null +++ b/src/config/config_parser.py @@ -0,0 +1,31 @@ +from abc import ABC, abstractmethod + + +class ConfigParser(ABC): + def __init__(self, text, verbose=None): + super(ConfigParser, self).__init__() + self.conf_text = text + self.verbose = verbose + self.conf_obj = None + + @abstractmethod + def parse(self): + pass + + @abstractmethod + def validate(self): + pass + + @staticmethod + def load_file(conf_file_path): + with open(conf_file_path, 'r') as file: + return file.readlines() + + def set_conf_obj(self, conf_obj): + self.conf_obj = conf_obj + + def get_conf_obj(self): + return self.conf_obj + + def get_conf_obj_attr(self, attr): + return self.conf_obj[attr] diff --git a/src/config/test_AppYamlConfParser.py b/src/config/test_AppYamlConfParser.py new file mode 100644 index 00000000..31622b76 --- /dev/null +++ b/src/config/test_AppYamlConfParser.py @@ -0,0 +1,153 @@ +from unittest import TestCase + +from config.addr_type import AddrType +from config.yaml_app_conf_parser import AppYamlConfParser + + +class TestYamlAppConfParser(TestCase): + def test_validate(self): + data_fine = """ + version : 1.0 + baking_address : tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj + payment_address : tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj + founders_map : {'KT2Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj':0.5,'KT3Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj':0.5} + owners_map : {'KT2Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj':0.5,'KT3Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj':0.5} + service_fee : 4.53 + """ + + managers = {'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj': 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj'} + cnf_prsr = AppYamlConfParser(data_fine, dict(), managers) + cnf_prsr.parse() + cnf_prsr.validate() + + self.assertEqual(cnf_prsr.get_conf_obj_attr('baking_address'), 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address'), 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address_pkh'), 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address_manager'), 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address_type'), AddrType.TZ) + self.assertEqual(0, cnf_prsr.get_conf_obj_attr('min_delegation_amt')) + self.assertEqual(cnf_prsr.get_conf_obj_attr('excluded_delegators_set'), set()) + self.assertEqual(cnf_prsr.get_conf_obj_attr('prcnt_scale'), None) + self.assertEqual(cnf_prsr.get_conf_obj_attr('pymnt_scale'), None) + + def test_validate_no_founders_map(self): + data_no_founders = """ + version : 1.0 + baking_address : tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj + payment_address : tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj + owners_map : {'KT2Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj':0.5,'KT3Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj':0.5} + service_fee : 4.5 + """ + + managers_map = {'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj': 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj'} + cnf_prsr = AppYamlConfParser(data_no_founders, dict(), managers_map) + cnf_prsr.parse() + cnf_prsr.validate() + + self.assertEqual(cnf_prsr.get_conf_obj_attr('baking_address'), 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address'), 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address_pkh'), 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address_manager'), 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address_type'), AddrType.TZ) + self.assertEqual(cnf_prsr.get_conf_obj_attr('founders_map'), dict()) + self.assertEqual(cnf_prsr.get_conf_obj_attr('specials_map'), dict()) + self.assertEqual(cnf_prsr.get_conf_obj_attr('supporters_set'), set()) + self.assertEqual(cnf_prsr.get_conf_obj_attr('excluded_delegators_set'), set()) + self.assertEqual(cnf_prsr.get_conf_obj_attr('prcnt_scale'), None) + self.assertEqual(cnf_prsr.get_conf_obj_attr('pymnt_scale'), None) + self.assertEqual(0, cnf_prsr.get_conf_obj_attr('min_delegation_amt')) + + def test_validate_pymnt_alias(self): + data_no_founders = """ + version : 1.0 + baking_address : tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj + payment_address : ktPay + owners_map : {'KT2Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj':0.5,'KT3Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj':0.5} + service_fee : 4.5 + min_delegation_amt : 100 + """ + + managers_map = {'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj': 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj', + 'KT1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj': 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj'} + + known_contracts = {'ktPay': 'KT1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj'} + + cnf_prsr = AppYamlConfParser(data_no_founders, known_contracts, managers_map) + cnf_prsr.parse() + cnf_prsr.validate() + + self.assertEqual(cnf_prsr.get_conf_obj_attr('baking_address'), 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address'), 'ktPay') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address_pkh'), 'KT1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address_manager'), 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address_type'), AddrType.KTALS) + + self.assertEqual(cnf_prsr.get_conf_obj_attr('founders_map'), dict()) + self.assertEqual(cnf_prsr.get_conf_obj_attr('specials_map'), dict()) + self.assertEqual(cnf_prsr.get_conf_obj_attr('supporters_set'), set()) + self.assertEqual(cnf_prsr.get_conf_obj_attr('excluded_delegators_set'), set()) + + self.assertEqual(100, cnf_prsr.get_conf_obj_attr('min_delegation_amt')) + self.assertEqual(cnf_prsr.get_conf_obj_attr('prcnt_scale'), None) + self.assertEqual(cnf_prsr.get_conf_obj_attr('pymnt_scale'), None) + + def test_validate_scales(self): + data_fine = """ + version : 1.0 + baking_address : tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj + payment_address : tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj + founders_map : {'KT2Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj':0.5,'KT3Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj':0.5} + owners_map : {'KT2Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj':0.5,'KT3Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj':0.5} + service_fee : 4.5 + pymnt_scale : 3 + prcnt_scale : 5 + """ + + managers = {'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj': 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj', + 'KT1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj': 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj'} + cnf_prsr = AppYamlConfParser(data_fine, dict(), managers) + cnf_prsr.parse() + cnf_prsr.validate() + + self.assertEqual(cnf_prsr.get_conf_obj_attr('baking_address'), 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address'), 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address_pkh'), 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address_manager'), 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address_type'), AddrType.TZ) + self.assertEqual(0, cnf_prsr.get_conf_obj_attr('min_delegation_amt')) + self.assertEqual(cnf_prsr.get_conf_obj_attr('excluded_delegators_set'), set()) + self.assertEqual(cnf_prsr.get_conf_obj_attr('prcnt_scale'), 5) + self.assertEqual(cnf_prsr.get_conf_obj_attr('pymnt_scale'), 3) + + def test_validate_empty(self): + data_fine = """ + version : 1.0 + baking_address : tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj + payment_address : KT1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj + service_fee : 4.5 + founders_map : {} + owners_map : {} + prcnt_scale : None + pymnt_scale : None + specials_map : {} + supporters_set : {} + min_delegation_amt : 0 + excluded_delegators_set : {} + """ + + managers = {'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj': 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj', + 'KT1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj': 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj'} + cnf_prsr = AppYamlConfParser(data_fine, dict(), managers) + cnf_prsr.parse() + cnf_prsr.validate() + + self.assertEqual(cnf_prsr.get_conf_obj_attr('baking_address'), 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address'), 'KT1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address_pkh'), 'KT1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address_manager'), 'tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj') + self.assertEqual(cnf_prsr.get_conf_obj_attr('payment_address_type'), AddrType.KT) + self.assertEqual(0, cnf_prsr.get_conf_obj_attr('min_delegation_amt')) + self.assertEqual(cnf_prsr.get_conf_obj_attr('excluded_delegators_set'), set()) + self.assertEqual(cnf_prsr.get_conf_obj_attr('supporters_set'), set()) + self.assertEqual(cnf_prsr.get_conf_obj_attr('prcnt_scale'), None) + self.assertEqual(cnf_prsr.get_conf_obj_attr('pymnt_scale'), None) diff --git a/src/config/test_yamlConfParser.py b/src/config/test_yamlConfParser.py new file mode 100644 index 00000000..c8236546 --- /dev/null +++ b/src/config/test_yamlConfParser.py @@ -0,0 +1,26 @@ +from unittest import TestCase + +from config.yaml_conf_parser import YamlConfParser + +document = """ +none: [~, null] +bool: [true, false, on, off] +int: 42 +float: 3.14159 +list: [LITE, RES_ACID, SUS_DEXT] +dict: {hp: 13, sp: 5} +""" + + +class TestYamlConfParser(TestCase): + def test_parse(self): + appConfParser = YamlConfParser(document) + conf_obj = appConfParser.parse() + + self.assertEqual(conf_obj['none'], [None, None]) + self.assertEqual(conf_obj['bool'], [True, False, True, False]) + self.assertEqual(conf_obj['list'], ['LITE', 'RES_ACID', 'SUS_DEXT']) + self.assertEqual(conf_obj['dict']['hp'], 13) + self.assertEqual(conf_obj['int'], 42) + + appConfParser.validate() \ No newline at end of file diff --git a/src/config/yaml_app_conf_parser.py b/src/config/yaml_app_conf_parser.py new file mode 100644 index 00000000..bee45f71 --- /dev/null +++ b/src/config/yaml_app_conf_parser.py @@ -0,0 +1,189 @@ +from config.addr_type import AddrType +from config.yaml_conf_parser import YamlConfParser +from util.address_validator import AddressValidator +from util.fee_validator import FeeValidator + +SERVICE_FEE = 'service_fee' +OWNERS_MAP = 'owners_map' +FOUNDERS_MAP = 'founders_map' +BAKING_ADDRESS = 'baking_address' +PRCNT_SCALE = "prcnt_scale" +PYMNT_SCALE = "pymnt_scale" +EXCLUDED_DELEGATORS_SET = "excluded_delegators_set" +SPECIALS_MAP = 'specials_map' +SUPPORTERS_SET = 'supporters_set' +PAYMENT_ADDRESS = 'payment_address' +MIN_DELEGATION_AMT = 'min_delegation_amt' + +PKH_LENGHT = 36 + + +class AppYamlConfParser(YamlConfParser): + def __init__(self, yaml_text, known_contracts, managers, verbose=None) -> None: + super().__init__(yaml_text, verbose) + self.known_contracts = known_contracts + self.managers = managers + + def parse(self): + yaml_conf_dict = super().parse() + self.set_conf_obj(yaml_conf_dict) + + def validate(self): + conf_obj = self.get_conf_obj() + self.__validate_share_map(conf_obj, FOUNDERS_MAP) + self.__validate_share_map(conf_obj, OWNERS_MAP) + self.__validate_service_fee(conf_obj) + self.__validate_baking_address(conf_obj[BAKING_ADDRESS]) + self.__validate_payment_address(conf_obj) + self.__validate_min_delegation_amt(conf_obj) + self.__validate_address_set(conf_obj, SUPPORTERS_SET) + self.__validate_address_set(conf_obj, EXCLUDED_DELEGATORS_SET) + self.__validate_specials_map(conf_obj) + self.__validate_scale(conf_obj, PYMNT_SCALE) + self.__validate_scale(conf_obj, PRCNT_SCALE) + + def __validate_share_map(self, conf_obj, map_name): + """ + all shares in the map must sum up to 1 + :param conf_obj: configuration object + :param map_name: name of the map to validate + :return: None + """ + + if map_name not in conf_obj: + conf_obj[map_name] = dict() + return + + if isinstance(conf_obj[map_name],str) and conf_obj[map_name].lower() == 'none': + conf_obj[map_name] = dict() + return + + if not conf_obj[map_name]: + return + + share_map = conf_obj[map_name] + + validator = AddressValidator(map_name) + for key, value in share_map.items(): + validator.validate(key) + + if len(share_map) > 0: + try: + if abs(1 - sum(share_map.values()) > 1e-4): # a zero check actually + raise Exception("Map '{}' shares does not sum up to 1!".format(map_name)) + except TypeError: + raise Exception("Map '{}' values must be number!".format(map_name)) + + def __validate_service_fee(self, conf_obj): + if SERVICE_FEE not in conf_obj: + raise Exception("Service fee is not set") + + FeeValidator(SERVICE_FEE).validate(conf_obj[(SERVICE_FEE)]) + + def __validate_min_delegation_amt(self, conf_obj): + if MIN_DELEGATION_AMT not in conf_obj: + conf_obj[MIN_DELEGATION_AMT] = 0 + return + + if not self.__validate_non_negative_int(conf_obj[MIN_DELEGATION_AMT] ): + raise Exception("Invalid value:'{}'. {} parameter value must be an non negative integer". + format(conf_obj[MIN_DELEGATION_AMT], MIN_DELEGATION_AMT)) + + + def __validate_payment_address(self, conf_obj): + pymnt_addr = conf_obj[(PAYMENT_ADDRESS)] + + if not pymnt_addr: + raise Exception("Payment address must be set") + + if len(pymnt_addr) == PKH_LENGHT and (pymnt_addr.startswith("KT") or pymnt_addr.startswith("tz")): + conf_obj[('%s_type' % PAYMENT_ADDRESS)] = AddrType.KT if pymnt_addr.startswith("KT") else AddrType.TZ + conf_obj[('%s_pkh' % PAYMENT_ADDRESS)] = pymnt_addr + conf_obj[('%s_manager' % PAYMENT_ADDRESS)] = self.managers[pymnt_addr] + else: + if pymnt_addr in self.known_contracts: + pkh = self.known_contracts[pymnt_addr] + + conf_obj[('%s_type' % PAYMENT_ADDRESS)] = AddrType.KTALS if pkh.startswith("KT") else AddrType.TZALS + conf_obj[('%s_pkh' % PAYMENT_ADDRESS)] = pkh + conf_obj[('%s_manager' % PAYMENT_ADDRESS)] = self.managers[pkh] + + else: + raise Exception("Payment Address ({}) cannot be translated into a PKH or alias".format(pymnt_addr)) + + def __validate_baking_address(self, baking_address): + + if not baking_address: + raise Exception("Baking address must be set") + + # key_name must has a length of 36 and starts with tz or KT, an alias is not expected + if len(baking_address) == PKH_LENGHT: + if not baking_address.startswith("tz"): + raise Exception("Baking address must be a valid tz address") + else: + raise Exception("Baking address length must be {}".format(PKH_LENGHT)) + + pass + + def __validate_specials_map(self, conf_obj): + if SPECIALS_MAP not in conf_obj: + conf_obj[SPECIALS_MAP] = dict() + return + + if isinstance(conf_obj[SPECIALS_MAP],str) and conf_obj[SPECIALS_MAP].lower() == 'none': + conf_obj[SPECIALS_MAP] = dict() + return + + if not conf_obj[SPECIALS_MAP]: + return + + addr_validator = AddressValidator(SPECIALS_MAP) + for key, value in conf_obj[SPECIALS_MAP].items(): + addr_validator.validate(key) + FeeValidator(key).validate(value) + + def __validate_address_set(self, conf_obj, set_name): + if set_name not in conf_obj: + conf_obj[set_name] = set() + return + + if isinstance(conf_obj[set_name],str) and conf_obj[set_name].lower() == 'none': + conf_obj[set_name] = set() + return + + if not conf_obj[set_name]: # empty sets are evaluated as dict + conf_obj[set_name] = set() + return + + validator = AddressValidator(set_name) + for addr in conf_obj[set_name]: + validator.validate(addr) + + def __validate_scale(self, conf_obj, scale_name): + if scale_name not in conf_obj: + conf_obj[scale_name] = None + return + + if isinstance(conf_obj[scale_name],str) and conf_obj[scale_name].lower() == 'none': + conf_obj[scale_name] = None + return + + if conf_obj[scale_name] is None: + return + + if not self.__validate_non_negative_int(conf_obj[scale_name]): + raise Exception("Invalid value:'{}'. {} parameter value must be an non negative integer or None. ". + format(conf_obj[MIN_DELEGATION_AMT], MIN_DELEGATION_AMT)) + + def __validate_non_negative_int(self, param_value): + try: + param_value += 1 + except TypeError: + return False + + param_value -= 1 # old value + + if param_value < 0: + return False + + return True diff --git a/src/config/yaml_conf_parser.py b/src/config/yaml_conf_parser.py new file mode 100644 index 00000000..77cbd031 --- /dev/null +++ b/src/config/yaml_conf_parser.py @@ -0,0 +1,16 @@ +import yaml + +from config.config_parser import ConfigParser + + +class YamlConfParser(ConfigParser): + def __init__(self, yaml_text, verbose=None) -> None: + super().__init__(yaml_text, verbose) + + def parse(self): + self.set_conf_obj(yaml.safe_load(self.conf_text)) + + return self.get_conf_obj() + + def validate(self): + return True diff --git a/src/util/address_validator.py b/src/util/address_validator.py new file mode 100644 index 00000000..aae63df0 --- /dev/null +++ b/src/util/address_validator.py @@ -0,0 +1,15 @@ +PKH_LENGHT = 36 + + +class AddressValidator: + + def __init__(self, context) -> None: + super().__init__() + self.context = context + + def validate(self, address): + if len(address) == PKH_LENGHT: + if not address.startswith("tz") and not address.startswith("KT"): + raise Exception("Incorrect input in {}, {} is Not a tz or KT address".format(self.context, address)) + else: + raise Exception("Incorrect input in {}, address({}) length must be {}".format(self.context, address, PKH_LENGHT)) diff --git a/src/util/test_parse_list_known_addresses_response.py b/src/util/test_parse_list_known_addresses_response.py new file mode 100644 index 00000000..2d79430d --- /dev/null +++ b/src/util/test_parse_list_known_addresses_response.py @@ -0,0 +1,77 @@ +from unittest import TestCase + +from util.client_utils import parse_list_known_addresses_response, parse_get_manager_for_contract_response, \ + parse_client_list_known_contracts_response + + +class TestParse_client_utils(TestCase): + def test_parse_list_known_addresses_response(self): + response = """ + Disclaimer: + The Tezos network is a new blockchain technology. + Users are solely responsible for any risks associated + with usage of the Tezos network. Users should do their + own research to determine if Tezos is the appropriate + platform for their needs and should apply judgement and + care in their network interactions. + + habanoz: tz1fyvFH2pd3V9UEq5psqVokVBYkt7rHTKio (unencrypted sk known) + mainnetme: tz1a5GGJeyqeQ4ihZqbiRVcvj5rY5kMAt3Xa (tcp sk known) + zeronetme: tz1MZ72sJEVen3Qgc7uWvqKhKFJW84bNGd6T (unencrypted sk not known) + """ + + dict = parse_list_known_addresses_response(response) + + habanoz = dict['tz1fyvFH2pd3V9UEq5psqVokVBYkt7rHTKio'] + + self.assertEqual(habanoz['alias'], 'habanoz') + self.assertEqual(habanoz['sk'], True) + self.assertEqual(habanoz['pkh'], 'tz1fyvFH2pd3V9UEq5psqVokVBYkt7rHTKio') + + mainnetme = dict['tz1a5GGJeyqeQ4ihZqbiRVcvj5rY5kMAt3Xa'] + + self.assertEqual(mainnetme['alias'], 'mainnetme') + self.assertEqual(mainnetme['sk'], True) + self.assertEqual(mainnetme['pkh'], 'tz1a5GGJeyqeQ4ihZqbiRVcvj5rY5kMAt3Xa') + + zeronetme = dict['tz1MZ72sJEVen3Qgc7uWvqKhKFJW84bNGd6T'] + + self.assertEqual(zeronetme['alias'], 'zeronetme') + self.assertEqual(zeronetme['sk'], False) + self.assertEqual(zeronetme['pkh'], 'tz1MZ72sJEVen3Qgc7uWvqKhKFJW84bNGd6T') + + def test_get_manager(self): + response = """ + Disclaimer: + The Tezos network is a new blockchain technology. + Users are solely responsible for any risks associated + with usage of the Tezos network. Users should do their + own research to determine if Tezos is the appropriate + platform for their needs and should apply judgement and + care in their network interactions. + +tz1PJnnddwa1P5jg5sChddigxfMccK8nwLiV (known as habanoz) + """ + + manager = parse_get_manager_for_contract_response(response) + self.assertEqual('tz1PJnnddwa1P5jg5sChddigxfMccK8nwLiV', manager) + + def test_parse_client_list_known_contracts_response(self): + response = """ + Disclaimer: + The Tezos network is a new blockchain technology. + Users are solely responsible for any risks associated + with usage of the Tezos network. Users should do their + own research to determine if Tezos is the appropriate + platform for their needs and should apply judgement and + care in their network interactions. + +newcontr: KT1XqEHigP5XumZy9i76QyVd6u93VD4HTqJK +habanoz: tz1fyvFH2pd3V9UEq5psqVokVBYkt7rHTKio +mainnetme: tz1a5GGJeyqeQ4ihZqbiRVcvj5rY5kMAt3Xa + """ + + dict = parse_client_list_known_contracts_response(response) + self.assertTrue(dict['newcontr']=='KT1XqEHigP5XumZy9i76QyVd6u93VD4HTqJK') + self.assertTrue(dict['habanoz']=='tz1fyvFH2pd3V9UEq5psqVokVBYkt7rHTKio') + self.assertTrue(dict['mainnetme']=='tz1a5GGJeyqeQ4ihZqbiRVcvj5rY5kMAt3Xa') \ No newline at end of file diff --git a/tz1feDGidZm6ngyHWcYTonkym1QreM9VqzY3.yaml b/tz1feDGidZm6ngyHWcYTonkym1QreM9VqzY3.yaml new file mode 100644 index 00000000..283e9bd8 --- /dev/null +++ b/tz1feDGidZm6ngyHWcYTonkym1QreM9VqzY3.yaml @@ -0,0 +1,12 @@ +version : 1.0 +baking_address : tz1Z1tMai15JWUWeN2PKL9faXXVPMuWamzJj +payment_address : kt1Pay +service_fee : 4.5 +founders_map : {} +owners_map : {} +prcnt_scale : {} +pymnt_scale : {} +specials_map : {} +supporters_set : {} +min_delegation_amt : 0 +excluded_delegators_set : {} \ No newline at end of file