docs: def start(self, contract_names, target):
          '''
          loads the contracts -- starts their event listeners
          :param contract_names:
          :return:
          '''
  
          if isinstance(contract_names, str):
              contract_names = [contract_names]
  
          if not isinstance(contract_names, list):
              return None, "error: expecting a string, or a list of contract names"
  
          contract_listeners = []
  
          for name in contract_names:
              c, err = Contract.get(name, self)
              if err:
                  EZO.log.error(red("error loading contract {}".format(name)))
                  EZO.log.error(red(err))
                  continue
              if not c:
                  EZO.log.warn(blue("contract {} not found".format(name)))
                  continue
  
              address, err = Contract.get_address(name, c.hash, self.db, target=target)
  
              if err:
                  EZO.log.error(red("error obtaining address for contract {}").format(name))
                  EZO.log.error(red(err))
                  continue
              if not address:
                  EZO.log.error(red("no address for contract {}".format(name)))
                  continue
  
              contract_listeners.append(c.listen(address, target))
  
          if contract_listeners:
              loop = asyncio.get_event_loop()
              loop.run_until_complete(
                  asyncio.gather(*contract_listeners)
              )
          else:
              return None, "unable to start contract listeners"