text: 'use strict';
  
  Object.defineProperty(exports, '__esModule', { value: true });
  
  function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
  
  var websocket = require('websocket');
  var xhr2Cookies = require('xhr2-cookies');
  var URL = _interopDefault(require('url-parse'));
  var isFunction = _interopDefault(require('lodash/isFunction'));
  var EventEmitter = _interopDefault(require('eventemitter3'));
  var http = _interopDefault(require('http'));
  var https = _interopDefault(require('https'));
  var isArray = _interopDefault(require('lodash/isArray'));
  var isObject = _interopDefault(require('lodash/isObject'));
  var _possibleConstructorReturn = _interopDefault(require('@babel/runtime/helpers/possibleConstructorReturn'));
  var _getPrototypeOf = _interopDefault(require('@babel/runtime/helpers/getPrototypeOf'));
  var _get = _interopDefault(require('@babel/runtime/helpers/get'));
  var _inherits = _interopDefault(require('@babel/runtime/helpers/inherits'));
  var _regeneratorRuntime = _interopDefault(require('@babel/runtime/regenerator'));
  var _asyncToGenerator = _interopDefault(require('@babel/runtime/helpers/asyncToGenerator'));
  var _classCallCheck = _interopDefault(require('@babel/runtime/helpers/classCallCheck'));
  var _createClass = _interopDefault(require('@babel/runtime/helpers/createClass'));
  var _typeof = _interopDefault(require('@babel/runtime/helpers/typeof'));
  
  var global = function () {
    return this || (typeof self === "undefined" ? "undefined" : _typeof(self)) === 'object' && self;
  }() || new Function('return this')();
  var ProviderResolver =
  function () {
    function ProviderResolver(providersModuleFactory) {
      _classCallCheck(this, ProviderResolver);
      this.providersModuleFactory = providersModuleFactory;
    }
    _createClass(ProviderResolver, [{
      key: "resolve",
      value: function resolve(provider, net) {
        if (typeof provider === 'string') {
          if (/^http(s)?:\/\//i.test(provider)) {
            return this.providersModuleFactory.createHttpProvider(provider);
          }
          if (/^ws(s)?:\/\//i.test(provider)) {
            return this.providersModuleFactory.createWebsocketProvider(provider);
          }
          if (provider && isObject(net) && isFunction(net.connect)) {
            return this.providersModuleFactory.createIpcProvider(provider, net);
          }
        }
        if (provider.sendPayload && provider.subscribe) {
          return provider;
        }
        if (typeof global.mist !== 'undefined' && provider.constructor.name === 'EthereumProvider') {
          return this.providersModuleFactory.createMistEthereumProvider(provider);
        }
        if (provider.isEIP1193) {
          return this.providersModuleFactory.createWeb3EthereumProvider(provider);
        }
        if (this.isMetamaskInpageProvider(provider)) {
          return this.providersModuleFactory.createMetamaskProvider(provider);
        }
        return this.providersModuleFactory.createCustomProvider(provider);
      }
    }, {
      key: "isMetamaskInpageProvider",
      value: function isMetamaskInpageProvider(provider) {
        return provider.constructor.name === 'MetamaskInpageProvider';
      }
    }]);
    return ProviderResolver;
  }();
  
  var messageId = 0;
  var JsonRpcMapper =
  function () {
    function JsonRpcMapper() {
      _classCallCheck(this, JsonRpcMapper);
    }
    _createClass(JsonRpcMapper, null, [{
      key: "toPayload",
      value: function toPayload(method, params) {
        if (!method) {
          throw new Error("JSONRPC method should be specified for params: \"".concat(JSON.stringify(params), "\"!"));
        }
        var id = messageId;
        messageId++;
        return {
          jsonrpc: '2.0',
          id: id,
          method: method,
          params: params || []
        };
      }
    }]);
    return JsonRpcMapper;
  }();
  
  var JsonRpcResponseValidator =
  function () {
    function JsonRpcResponseValidator() {
      _classCallCheck(this, JsonRpcResponseValidator);
    }
    _createClass(JsonRpcResponseValidator, null, [{
      key: "validate",
      value: function validate(response) {
        var payload = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
        if (isObject(response)) {
          if (response.error) {
            if (response.error instanceof Error) {
              return new Error("Node error: ".concat(response.error.message));
            }
            return new Error("Node error: ".concat(JSON.stringify(response.error)));
          }
          if (payload && response.id !== payload.id) {
            return new Error("Validation error: Invalid JSON-RPC response ID (request: ".concat(payload.id, " / response: ").concat(response.id, ")"));
          }
          if (response.result === undefined) {
            return new Error('Validation error: Undefined JSON-RPC result');
          }
          return true;
        }
        return new Error('Validation error: Response should be of type Object');
      }
    }]);
    return JsonRpcResponseValidator;
  }();
  
  var AbstractSocketProvider =
  function (_EventEmitter) {
    _inherits(AbstractSocketProvider, _EventEmitter);
    function AbstractSocketProvider(connection, timeout) {
      var _this;
      _classCallCheck(this, AbstractSocketProvider);
      _this = _possibleConstructorReturn(this, _getPrototypeOf(AbstractSocketProvider).call(this));
      _this.connection = connection;
      _this.timeout = timeout;
      _this.subscriptions = {};
      _this.registerEventListeners();
      _this.READY = 'ready';
      _this.CONNECT = 'connect';
      _this.ERROR = 'error';
      _this.CLOSE = 'close';
      _this.SOCKET_MESSAGE = 'socket_message';
      _this.SOCKET_READY = 'socket_ready';
      _this.SOCKET_CLOSE = 'socket_close';
      _this.SOCKET_ERROR = 'socket_error';
      _this.SOCKET_CONNECT = 'socket_connect';
      _this.SOCKET_NETWORK_CHANGED = 'socket_networkChanged';
      _this.SOCKET_ACCOUNTS_CHANGED = 'socket_accountsChanged';
      return _this;
    }
    _createClass(AbstractSocketProvider, [{
      key: "registerEventListeners",
      value: function registerEventListeners() {}
    }, {
      key: "removeAllSocketListeners",
      value: function removeAllSocketListeners() {
        this.removeAllListeners(this.SOCKET_MESSAGE);
        this.removeAllListeners(this.SOCKET_READY);
        this.removeAllListeners(this.SOCKET_CLOSE);
        this.removeAllListeners(this.SOCKET_ERROR);
        this.removeAllListeners(this.SOCKET_CONNECT);
      }
    }, {
      key: "disconnect",
      value: function disconnect(code, reason) {}
    }, {
      key: "send",
      value: function () {
        var _send = _asyncToGenerator(
        _regeneratorRuntime.mark(function _callee(method, parameters) {
          var response, validationResult;
          return _regeneratorRuntime.wrap(function _callee$(_context) {
            while (1) {
              switch (_context.prev = _context.next) {
                case 0:
                  _context.next = 2;
                  return this.sendPayload(JsonRpcMapper.toPayload(method, parameters));
                case 2:
                  response = _context.sent;
                  validationResult = JsonRpcResponseValidator.validate(response);
                  if (!(validationResult instanceof Error)) {
                    _context.next = 6;
                    break;
                  }
                  throw validationResult;
                case 6:
                  return _context.abrupt("return", response.result);
                case 7:
                case "end":
                  return _context.stop();
              }
            }
          }, _callee, this);
        }));
        function send(_x, _x2) {
          return _send.apply(this, arguments);
        }
        return send;
      }()
    }, {
      key: "sendBatch",
      value: function sendBatch(methods, moduleInstance) {
        var payload = [];
        methods.forEach(function (method) {
          method.beforeExecution(moduleInstance);
          payload.push(JsonRpcMapper.toPayload(method.rpcMethod, method.parameters));
        });
        return this.sendPayload(payload);
      }
    }, {
      key: "onReady",
      value: function onReady(event) {
        this.emit(this.READY, event);
        this.emit(this.SOCKET_READY, event);
      }
    }, {
      key: "onError",
      value: function onError(error) {
        this.emit(this.ERROR, error);
        this.emit(this.SOCKET_ERROR, error);
        this.removeAllSocketListeners();
        this.removeAllListeners();
      }
    }, {
      key: "onClose",
      value: function onClose() {
        var error = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
        this.emit(this.CLOSE, error);
        this.emit(this.SOCKET_CLOSE, error);
        this.removeAllSocketListeners();
        this.removeAllListeners();
      }
    }, {
      key: "onConnect",
      value: function () {
        var _onConnect = _asyncToGenerator(
        _regeneratorRuntime.mark(function _callee2() {
          var subscriptionKeys, subscriptionId, _i, key;
          return _regeneratorRuntime.wrap(function _callee2$(_context2) {
            while (1) {
              switch (_context2.prev = _context2.next) {
                case 0:
                  subscriptionKeys = Object.keys(this.subscriptions);
                  if (!(subscriptionKeys.length > 0)) {
                    _context2.next = 13;
                    break;
                  }
                  _i = 0;
                case 3:
                  if (!(_i < subscriptionKeys.length)) {
                    _context2.next = 13;
                    break;
                  }
                  key = subscriptionKeys[_i];
                  _context2.next = 7;
                  return this.subscribe(this.subscriptions[key].subscribeMethod, this.subscriptions[key].parameters[0], this.subscriptions[key].parameters.slice(1));
                case 7:
                  subscriptionId = _context2.sent;
                  delete this.subscriptions[subscriptionId];
                  this.subscriptions[this.getSubscriptionEvent(this.subscriptions[key].id)].id = subscriptionId;
                case 10:
                  _i++;
                  _context2.next = 3;
                  break;
                case 13:
                  this.emit(this.SOCKET_CONNECT);
                  this.emit(this.CONNECT);
                case 15:
                case "end":
                  return _context2.stop();
              }
            }
          }, _callee2, this);
        }));
        function onConnect() {
          return _onConnect.apply(this, arguments);
        }
        return onConnect;
      }()
    }, {
      key: "onMessage",
      value: function onMessage(response) {
        var event;
        if (!isObject(response)) {
          response = JSON.parse(response);
        }
        if (isArray(response)) {
          event = response[0].id;
        } else if (typeof response.id === 'undefined') {
          event = this.getSubscriptionEvent(response.params.subscription);
          response = response.params;
        } else {
          event = response.id;
        }
        this.emit(this.SOCKET_MESSAGE, response);
        this.emit(event, response);
      }
    }, {
      key: "reset",
      value: function reset() {
        this.removeAllListeners();
        this.registerEventListeners();
      }
    }, {
      key: "subscribe",
      value: function subscribe() {
        var _this2 = this;
        var subscribeMethod = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'eth_subscribe';
        var subscriptionMethod = arguments.length > 1 ? arguments[1] : undefined;
        var parameters = arguments.length > 2 ? arguments[2] : undefined;
        parameters.unshift(subscriptionMethod);
        return this.send(subscribeMethod, parameters).then(function (subscriptionId) {
          _this2.subscriptions[subscriptionId] = {
            id: subscriptionId,
            subscribeMethod: subscribeMethod,
            parameters: parameters
          };
          return subscriptionId;
        }).catch(function (error) {
          throw new Error("Provider error: ".concat(error));
        });
      }
    }, {
      key: "unsubscribe",
      value: function unsubscribe(subscriptionId) {
        var _this3 = this;
        var unsubscribeMethod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'eth_unsubscribe';
        if (this.hasSubscription(subscriptionId)) {
          return this.send(unsubscribeMethod, [subscriptionId]).then(function (response) {
            if (response) {
              _this3.removeAllListeners(_this3.getSubscriptionEvent(subscriptionId));
              delete _this3.subscriptions[subscriptionId];
            }
            return response;
          });
        }
        return Promise.reject(new Error("Provider error: Subscription with ID ".concat(subscriptionId, " does not exist.")));
      }
    }, {
      key: "clearSubscriptions",
      value: function clearSubscriptions() {
        var _this4 = this;
        var unsubscribeMethod = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'eth_unsubscribe';
        var unsubscribePromises = [];
        Object.keys(this.subscriptions).forEach(function (key) {
          _this4.removeAllListeners(key);
          unsubscribePromises.push(_this4.unsubscribe(_this4.subscriptions[key].id, unsubscribeMethod));
        });
        return Promise.all(unsubscribePromises).then(function (results) {
          if (results.includes(false)) {
            throw new Error("Could not unsubscribe all subscriptions: ".concat(JSON.stringify(results)));
          }
          return true;
        });
      }
    }, {
      key: "hasSubscription",
      value: function hasSubscription(subscriptionId) {
        return typeof this.getSubscriptionEvent(subscriptionId) !== 'undefined';
      }
    }, {
      key: "getSubscriptionEvent",
      value: function getSubscriptionEvent(subscriptionId) {
        var _this5 = this;
        if (this.subscriptions[subscriptionId]) {
          return subscriptionId;
        }
        var event;
        Object.keys(this.subscriptions).forEach(function (key) {
          if (_this5.subscriptions[key].id === subscriptionId) {
            event = key;
          }
        });
        return event;
      }
    }, {
      key: "connected",
      get: function get() {}
    }]);
    return AbstractSocketProvider;
  }(EventEmitter);
  
  var WebsocketProvider =
  function (_AbstractSocketProvid) {
    _inherits(WebsocketProvider, _AbstractSocketProvid);
    function WebsocketProvider(connection, timeout) {
      var _this;
      _classCallCheck(this, WebsocketProvider);
      _this = _possibleConstructorReturn(this, _getPrototypeOf(WebsocketProvider).call(this, connection, timeout));
      _this.host = _this.connection.url;
      return _this;
    }
    _createClass(WebsocketProvider, [{
      key: "onMessage",
      value: function onMessage(messageEvent) {
        _get(_getPrototypeOf(WebsocketProvider.prototype), "onMessage", this).call(this, messageEvent.data);
      }
    }, {
      key: "onError",
      value: function onError(event) {
        if (event.code === 'ECONNREFUSED') {
          this.reconnect();
          return;
        }
        _get(_getPrototypeOf(WebsocketProvider.prototype), "onError", this).call(this, event);
      }
    }, {
      key: "onClose",
      value: function onClose(closeEvent) {
        if (closeEvent.code !== 1000) {
          this.reconnect();
          return;
        }
        _get(_getPrototypeOf(WebsocketProvider.prototype), "onClose", this).call(this);
      }
    }, {
      key: "reconnect",
      value: function reconnect() {
        var _this2 = this;
        setTimeout(function () {
          _this2.removeAllSocketListeners();
          var connection = [];
          if (_this2.connection.constructor.name === 'W3CWebsocket') {
            connection = new _this2.connection.constructor(_this2.host, _this2.connection._client.protocol, null, _this2.connection._client.headers, _this2.connection._client.requestOptions, _this2.connection._client.config);
          } else {
            var protocol = _this2.connection.protocol || undefined;
            connection = new _this2.connection.constructor(_this2.host, protocol);
          }
          _this2.connection = connection;
          _this2.registerEventListeners();
        }, 5000);
      }
    }, {
      key: "disconnect",
      value: function disconnect() {
        var code = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
        var reason = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
        this.connection.close(code, reason);
      }
    }, {
      key: "registerEventListeners",
      value: function registerEventListeners() {
        this.connection.addEventListener('message', this.onMessage.bind(this));
        this.connection.addEventListener('open', this.onReady.bind(this));
        this.connection.addEventListener('open', this.onConnect.bind(this));
        this.connection.addEventListener('close', this.onClose.bind(this));
        this.connection.addEventListener('error', this.onError.bind(this));
      }
    }, {
      key: "removeAllListeners",
      value: function removeAllListeners(event) {
        switch (event) {
          case this.SOCKET_MESSAGE:
            this.connection.removeEventListener('message', this.onMessage);
            break;
          case this.SOCKET_READY:
            this.connection.removeEventListener('open', this.onReady);
            break;
          case this.SOCKET_CLOSE:
            this.connection.removeEventListener('close', this.onClose);
            break;
          case this.SOCKET_ERROR:
            this.connection.removeEventListener('error', this.onError);
            break;
          case this.SOCKET_CONNECT:
            this.connection.removeEventListener('connect', this.onConnect);
            break;
        }
        _get(_getPrototypeOf(WebsocketProvider.prototype), "removeAllListeners", this).call(this, event);
      }
    }, {
      key: "isConnecting",
      value: function isConnecting() {
        return this.connection.readyState === this.connection.CONNECTING;
      }
    }, {
      key: "sendPayload",
      value: function sendPayload(payload) {
        var _this3 = this;
        return new Promise(function (resolve, reject) {
          if (!_this3.isConnecting()) {
            var timeout, id;
            if (_this3.connection.readyState !== _this3.connection.OPEN) {
              return reject(new Error('Connection error: Connection is not open on send()'));
            }
            _this3.connection.send(JSON.stringify(payload));
            if (_this3.timeout) {
              timeout = setTimeout(function () {
                reject(new Error('Connection error: Timeout exceeded'));
              }, _this3.timeout);
            }
            if (isArray(payload)) {
              id = payload[0].id;
            } else {
              id = payload.id;
            }
            _this3.once(id, function (response) {
              if (timeout) {
                clearTimeout(timeout);
              }
              return resolve(response);
            });
            return;
          }
          _this3.on('connect', function () {
            _this3.sendPayload(payload).then(resolve).catch(reject);
            _this3.removeAllListeners('connect');
          });
        });
      }
    }, {
      key: "connected",
      get: function get() {
        return this.connection.readyState === this.connection.OPEN;
      }
    }]);
    return WebsocketProvider;
  }(AbstractSocketProvider);
  
  var IpcProvider =
  function (_AbstractSocketProvid) {
    _inherits(IpcProvider, _AbstractSocketProvid);
    function IpcProvider(connection, path) {
      var _this;
      _classCallCheck(this, IpcProvider);
      _this = _possibleConstructorReturn(this, _getPrototypeOf(IpcProvider).call(this, connection, null));
      _this.host = path;
      _this.chunks = '';
      return _this;
    }
    _createClass(IpcProvider, [{
      key: "disconnect",
      value: function disconnect() {
        this.connection.destroy();
      }
    }, {
      key: "reconnect",
      value: function reconnect() {
        this.connection.connect({
          path: this.path
        });
      }
    }, {
      key: "onMessage",
      value: function onMessage(message) {
        var chunk = message.toString('utf8');
        if (chunk.indexOf('\n') < 0) {
          this.chunks += chunk;
          return;
        }
        _get(_getPrototypeOf(IpcProvider.prototype), "onMessage", this).call(this, this.chunks + chunk.substring(0, chunk.indexOf('\n')));
        this.chunks = chunk.substring(chunk.indexOf('\n') + 1);
      }
    }, {
      key: "registerEventListeners",
      value: function registerEventListeners() {
        this.connection.on('data', this.onMessage.bind(this));
        this.connection.on('connect', this.onConnect.bind(this));
        this.connection.on('error', this.onError.bind(this));
        this.connection.on('close', this.onClose.bind(this));
        this.connection.on('timeout', this.onClose.bind(this));
        this.connection.on('ready', this.onReady.bind(this));
      }
    }, {
      key: "removeAllListeners",
      value: function removeAllListeners(event) {
        switch (event) {
          case this.SOCKET_MESSAGE:
            this.connection.removeListener('data', this.onMessage);
            break;
          case this.SOCKET_READY:
            this.connection.removeListener('ready', this.onReady);
            break;
          case this.SOCKET_CLOSE:
            this.connection.removeListener('close', this.onClose);
            break;
          case this.SOCKET_ERROR:
            this.connection.removeListener('error', this.onError);
            break;
          case this.SOCKET_CONNECT:
            this.connection.removeListener('connect', this.onConnect);
            break;
        }
        _get(_getPrototypeOf(IpcProvider.prototype), "removeAllListeners", this).call(this, event);
      }
    }, {
      key: "sendPayload",
      value: function sendPayload(payload) {
        var _this2 = this;
        return new Promise(function (resolve, reject) {
          if (!_this2.connection.writable) {
            _this2.connection.connect({
              path: _this2.path
            });
          }
          if (_this2.connection.write(JSON.stringify(payload))) {
            var id;
            if (isArray(payload)) {
              id = payload[0].id;
            } else {
              id = payload.id;
            }
            _this2.once(id, resolve);
            return;
          }
          return reject(new Error("Connection error: Couldn't write on the socket with Socket.write(payload)"));
        });
      }
    }, {
      key: "connected",
      get: function get() {
        return !this.connection.pending;
      }
    }]);
    return IpcProvider;
  }(AbstractSocketProvider);
  
  var HttpProvider =
  function () {
    function HttpProvider() {
      var host = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'http://localhost:8545';
      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      var providersModuleFactory = arguments.length > 2 ? arguments[2] : undefined;
      _classCallCheck(this, HttpProvider);
      this.host = host;
      this.timeout = options.timeout || 0;
      this.headers = options.headers;
      this.connected = true;
      this.providersModuleFactory = providersModuleFactory;
      this.agent = {};
      var keepAlive = false;
      if (options.keepAlive === true || options.keepAlive !== false) {
        keepAlive = true;
      }
      if (host.substring(0, 5) === 'https') {
        this.agent['httpsAgent'] = new https.Agent({
          keepAlive: keepAlive
        });
      } else {
        this.agent['httpAgent'] = new http.Agent({
          keepAlive: keepAlive
        });
      }
    }
    _createClass(HttpProvider, [{
      key: "subscribe",
      value: function subscribe() {
        throw new Error('Subscriptions are not supported with the HttpProvider.');
      }
    }, {
      key: "unsubscribe",
      value: function unsubscribe() {
        throw new Error('Subscriptions are not supported with the HttpProvider.');
      }
    }, {
      key: "disconnect",
      value: function disconnect() {
        return true;
      }
    }, {
      key: "send",
      value: function () {
        var _send = _asyncToGenerator(
        _regeneratorRuntime.mark(function _callee(method, parameters) {
          var response, validationResult;
          return _regeneratorRuntime.wrap(function _callee$(_context) {
            while (1) {
              switch (_context.prev = _context.next) {
                case 0:
                  _context.next = 2;
                  return this.sendPayload(JsonRpcMapper.toPayload(method, parameters));
                case 2:
                  response = _context.sent;
                  validationResult = JsonRpcResponseValidator.validate(response);
                  if (!(validationResult instanceof Error)) {
                    _context.next = 6;
                    break;
                  }
                  throw validationResult;
                case 6:
                  return _context.abrupt("return", response.result);
                case 7:
                case "end":
                  return _context.stop();
              }
            }
          }, _callee, this);
        }));
        function send(_x, _x2) {
          return _send.apply(this, arguments);
        }
        return send;
      }()
    }, {
      key: "sendBatch",
      value: function sendBatch(methods, moduleInstance) {
        var payload = [];
        methods.forEach(function (method) {
          method.beforeExecution(moduleInstance);
          payload.push(JsonRpcMapper.toPayload(method.rpcMethod, method.parameters));
        });
        return this.sendPayload(payload);
      }
    }, {
      key: "sendPayload",
      value: function sendPayload(payload) {
        var _this = this;
        return new Promise(function (resolve, reject) {
          var request = _this.providersModuleFactory.createXMLHttpRequest(_this.host, _this.timeout, _this.headers, _this.agent);
          request.onreadystatechange = function () {
            if (request.readyState !== 0 && request.readyState !== 1) {
              _this.connected = true;
            }
            if (request.readyState === 4) {
              if (request.status === 200) {
                try {
                  return resolve(JSON.parse(request.responseText));
                } catch (error) {
                  reject(new Error("Invalid JSON as response: ".concat(request.responseText)));
                }
              }
              if (_this.isInvalidHttpEndpoint(request)) {
                reject(new Error("Connection refused or URL couldn't be resolved: ".concat(_this.host)));
              }
            }
          };
          request.ontimeout = function () {
            _this.connected = false;
            reject(new Error("Connection error: Timeout exceeded after ".concat(_this.timeout, "ms")));
          };
          try {
            request.send(JSON.stringify(payload));
          } catch (error) {
            _this.connected = false;
            reject(error);
          }
        });
      }
    }, {
      key: "isInvalidHttpEndpoint",
      value: function isInvalidHttpEndpoint(request) {
        return request.response === null && request.status === 0;
      }
    }]);
    return HttpProvider;
  }();
  
  var BatchRequest =
  function () {
    function BatchRequest(moduleInstance) {
      _classCallCheck(this, BatchRequest);
      this.moduleInstance = moduleInstance;
      this.methods = [];
    }
    _createClass(BatchRequest, [{
      key: "add",
      value: function add(method) {
        if (!isObject(method) && method) {
          throw new Error('Please provide a object of type AbstractMethod.');
        }
        this.methods.push(method);
      }
    }, {
      key: "execute",
      value: function execute() {
        var _this = this;
        return this.moduleInstance.currentProvider.sendBatch(this.methods, this.moduleInstance).then(function (response) {
          var errors = [];
          _this.methods.forEach(function (method, index) {
            if (!isArray(response)) {
              method.callback(new Error("BatchRequest error: Response should be of type Array but is: ".concat(_typeof(response))), null);
              errors.push("Response should be of type Array but is: ".concat(_typeof(response)));
              return;
            }
            var responseItem = response[index] || null;
            var validationResult = JsonRpcResponseValidator.validate(responseItem);
            if (validationResult) {
              try {
                var mappedResult = method.afterExecution(responseItem.result);
                response[index] = mappedResult;
                method.callback(false, mappedResult);
              } catch (error) {
                errors.push(error);
                method.callback(error, null);
              }
              return;
            }
            errors.push(validationResult);
            method.callback(validationResult, null);
          });
          if (errors.length > 0) {
            throw new Error("BatchRequest error: ".concat(JSON.stringify(errors)));
          }
          return {
            methods: _this.methods,
            response: response
          };
        });
      }
    }]);
    return BatchRequest;
  }();
  
  var Web3EthereumProvider =
  function (_AbstractSocketProvid) {
    _inherits(Web3EthereumProvider, _AbstractSocketProvid);
    function Web3EthereumProvider(connection) {
      var _this;
      _classCallCheck(this, Web3EthereumProvider);
      _this = _possibleConstructorReturn(this, _getPrototypeOf(Web3EthereumProvider).call(this, connection, null));
      _this.host = 'Web3EthereumProvider';
      return _this;
    }
    _createClass(Web3EthereumProvider, [{
      key: "registerEventListeners",
      value: function registerEventListeners() {
        this.connection.on('notification', this.onMessage.bind(this));
        this.connection.on('connect', this.onConnect.bind(this));
        this.connection.on('connect', this.onReady.bind(this));
        this.connection.on('close', this.onClose.bind(this));
        this.connection.on('networkChanged', this.onNetworkChanged.bind(this));
        this.connection.on('accountsChanged', this.onAccountsChanged.bind(this));
      }
    }, {
      key: "removeAllListeners",
      value: function removeAllListeners(event) {
        switch (event) {
          case this.SOCKET_NETWORK_CHANGED:
            this.connection.removeListener('networkChanged', this.onNetworkChanged);
            break;
          case this.SOCKET_ACCOUNTS_CHANGED:
            this.connection.removeListener('accountsChanged', this.onAccountsChanged);
            break;
          case this.SOCKET_MESSAGE:
            this.connection.removeListener('notification', this.onMessage);
            break;
          case this.SOCKET_READY:
            this.connection.removeListener('connect', this.onReady);
            break;
          case this.SOCKET_CLOSE:
            this.connection.removeListener('close', this.onClose);
            break;
          case this.SOCKET_ERROR:
            this.connection.removeListener('close', this.onError);
            break;
          case this.SOCKET_CONNECT:
            this.connection.removeListener('connect', this.onConnect);
            break;
        }
        _get(_getPrototypeOf(Web3EthereumProvider.prototype), "removeAllListeners", this).call(this, event);
      }
    }, {
      key: "removeAllSocketListeners",
      value: function removeAllSocketListeners() {
        this.connection.removeAllListeners();
      }
    }, {
      key: "onNetworkChanged",
      value: function onNetworkChanged(networkId) {
        this.emit('networkChanged', networkId);
      }
    }, {
      key: "onAccountsChanged",
      value: function onAccountsChanged(accounts) {
        this.emit('accountsChanged', accounts);
      }
    }, {
      key: "onMessage",
      value: function onMessage(response) {
        this.emit(this.getSubscriptionEvent(response.subscription), response);
      }
    }, {
      key: "send",
      value: function () {
        var _send = _asyncToGenerator(
        _regeneratorRuntime.mark(function _callee(method, parameters) {
          var response, validationResult;
          return _regeneratorRuntime.wrap(function _callee$(_context) {
            while (1) {
              switch (_context.prev = _context.next) {
                case 0:
                  response = this.connection.send(method, parameters);
                  validationResult = JsonRpcResponseValidator.validate(response);
                  if (!(validationResult instanceof Error)) {
                    _context.next = 4;
                    break;
                  }
                  throw validationResult;
                case 4:
                  return _context.abrupt("return", response);
                case 5:
                case "end":
                  return _context.stop();
              }
            }
          }, _callee, this);
        }));
        function send(_x, _x2) {
          return _send.apply(this, arguments);
        }
        return send;
      }()
    }, {
      key: "sendBatch",
      value: function sendBatch(methods, moduleInstance) {
        var _this2 = this;
        var methodCalls = [];
        methods.forEach(function (method) {
          method.beforeExecution(moduleInstance);
          methodCalls.push(_this2.connection.send(method.rpcMethod, method.parameters));
        });
        return Promise.all(methodCalls);
      }
    }]);
    return Web3EthereumProvider;
  }(AbstractSocketProvider);
  
  var MetamaskProvider =
  function (_AbstractSocketProvid) {
    _inherits(MetamaskProvider, _AbstractSocketProvid);
    function MetamaskProvider(inpageProvider) {
      var _this;
      _classCallCheck(this, MetamaskProvider);
      _this = _possibleConstructorReturn(this, _getPrototypeOf(MetamaskProvider).call(this, inpageProvider, null));
      _this.host = 'metamask';
      return _this;
    }
    _createClass(MetamaskProvider, [{
      key: "registerEventListeners",
      value: function registerEventListeners() {
        this.connection.on('accountsChanged', this.onAccountsChanged.bind(this));
        this.connection.on('networkChanged', this.onReady.bind(this));
        this.connection.on('networkChanged', this.onNetworkChanged.bind(this));
        this.connection.on('data', this.onMessage.bind(this));
        this.connection.on('error', this.onError.bind(this));
      }
    }, {
      key: "onMessage",
      value: function onMessage(metamaskParam, payload) {
        _get(_getPrototypeOf(MetamaskProvider.prototype), "onMessage", this).call(this, payload);
      }
    }, {
      key: "removeAllListeners",
      value: function removeAllListeners(event) {
        switch (event) {
          case this.SOCKET_NETWORK_CHANGED:
            this.connection.removeListener('networkChanged', this.onNetworkChanged);
            break;
          case this.SOCKET_ACCOUNTS_CHANGED:
            this.connection.removeListener('accountsChanged', this.onAccountsChanged);
            break;
          case this.SOCKET_MESSAGE:
            this.connection.removeListener('data', this.onMessage);
            break;
          case this.SOCKET_ERROR:
            this.connection.removeListener('error', this.onError);
            break;
        }
        _get(_getPrototypeOf(MetamaskProvider.prototype), "removeAllListeners", this).call(this, event);
      }
    }, {
      key: "removeAllSocketListeners",
      value: function removeAllSocketListeners() {
        this.connection.removeListener(this.SOCKET_NETWORK_CHANGED, this.onNetworkChanged);
        this.connection.removeListener(this.SOCKET_ACCOUNTS_CHANGED, this.onAccountsChanged);
        _get(_getPrototypeOf(MetamaskProvider.prototype), "removeAllSocketListeners", this).call(this);
      }
    }, {
      key: "onNetworkChanged",
      value: function onNetworkChanged(networkId) {
        this.emit('networkChanged', networkId);
      }
    }, {
      key: "onAccountsChanged",
      value: function onAccountsChanged(accounts) {
        this.emit('accountsChanged', accounts);
      }
    }, {
      key: "disconnect",
      value: function disconnect() {
        return true;
      }
    }, {
      key: "sendPayload",
      value: function sendPayload(payload) {
        var _this2 = this;
        return new Promise(function (resolve, reject) {
          _this2.connection.send(payload, function (error, response) {
            _this2.removeAllListeners(payload.id);
            if (!error) {
              return resolve(response);
            }
            reject(error);
          });
        });
      }
    }, {
      key: "connected",
      get: function get() {
        return this.connection.isConnected();
      }
    }]);
    return MetamaskProvider;
  }(AbstractSocketProvider);
  
  var MistEthereumProvider =
  function (_AbstractSocketProvid) {
    _inherits(MistEthereumProvider, _AbstractSocketProvid);
    function MistEthereumProvider(connection) {
      var _this;
      _classCallCheck(this, MistEthereumProvider);
      _this = _possibleConstructorReturn(this, _getPrototypeOf(MistEthereumProvider).call(this, connection, null));
      _this.host = 'mist';
      return _this;
    }
    _createClass(MistEthereumProvider, [{
      key: "registerEventListeners",
      value: function registerEventListeners() {
        this.connection.on('data', this.onMessage.bind(this));
        this.connection.on('error', this.onError.bind(this));
        this.connection.on('connect', this.onConnect.bind(this));
        this.connection.on('connect', this.onReady.bind(this));
        this.connection.on('end', this.onClose.bind(this));
      }
    }, {
      key: "removeAllListeners",
      value: function removeAllListeners(event) {
        switch (event) {
          case this.SOCKET_MESSAGE:
            this.connection.removeListener('data', this.onMessage);
            break;
          case this.SOCKET_ERROR:
            this.connection.removeListener('error', this.onError);
            break;
          case this.SOCKET_CONNECT:
            this.connection.removeListener('connect', this.onConnect);
            break;
          case this.SOCKET_READY:
            this.connection.removeListener('connect', this.onConnect);
            break;
          case this.SOCKET_CLOSE:
            this.connection.removeListener('end', this.onClose);
            break;
        }
        _get(_getPrototypeOf(MistEthereumProvider.prototype), "removeAllListeners", this).call(this, event);
      }
    }, {
      key: "disconnect",
      value: function disconnect() {
        return true;
      }
    }, {
      key: "sendPayload",
      value: function sendPayload(payload) {
        var _this2 = this;
        return new Promise(function (resolve, reject) {
          _this2.connection.send(payload, function (error, response) {
            _this2.removeAllListeners(payload.id);
            if (!error) {
              return resolve(response);
            }
            reject(error);
          });
        });
      }
    }, {
      key: "connected",
      get: function get() {
        return this.connection.isConnected();
      }
    }]);
    return MistEthereumProvider;
  }(AbstractSocketProvider);
  
  var CustomProvider =
  function () {
    function CustomProvider(connection) {
      _classCallCheck(this, CustomProvider);
      this.host = 'CustomProvider';
      this.connection = connection;
      this.checkConnectionMethods();
    }
    _createClass(CustomProvider, [{
      key: "checkConnectionMethods",
      value: function checkConnectionMethods() {
        if (this.connection.send || this.connection.sendAsync) {
          return true;
        }
        throw new Error('Invalid provider injected!');
      }
    }, {
      key: "subscribe",
      value: function subscribe() {
        throw new Error('Subscriptions are not supported with the CustomProvider.');
      }
    }, {
      key: "unsubscribe",
      value: function unsubscribe() {
        throw new Error('Subscriptions are not supported with the CustomProvider.');
      }
    }, {
      key: "send",
      value: function () {
        var _send = _asyncToGenerator(
        _regeneratorRuntime.mark(function _callee(method, parameters) {
          var response, validationResult;
          return _regeneratorRuntime.wrap(function _callee$(_context) {
            while (1) {
              switch (_context.prev = _context.next) {
                case 0:
                  _context.next = 2;
                  return this.sendPayload(JsonRpcMapper.toPayload(method, parameters));
                case 2:
                  response = _context.sent;
                  validationResult = JsonRpcResponseValidator.validate(response);
                  if (!(validationResult instanceof Error)) {
                    _context.next = 6;
                    break;
                  }
                  throw validationResult;
                case 6:
                  return _context.abrupt("return", response.result);
                case 7:
                case "end":
                  return _context.stop();
              }
            }
          }, _callee, this);
        }));
        function send(_x, _x2) {
          return _send.apply(this, arguments);
        }
        return send;
      }()
    }, {
      key: "sendBatch",
      value: function sendBatch(methods, moduleInstance) {
        var payload = [];
        methods.forEach(function (method) {
          method.beforeExecution(moduleInstance);
          payload.push(JsonRpcMapper.toPayload(method.rpcMethod, method.parameters));
        });
        return this.sendPayload(payload);
      }
    }, {
      key: "sendPayload",
      value: function sendPayload(payload) {
        var _this = this;
        return new Promise(function (resolve, reject) {
          if (_this.connection.sendAsync) {
            _this.connection.sendAsync(payload, function (error, response) {
              if (!error) {
                resolve(response);
              }
              reject(error);
            });
            return;
          }
          _this.connection.send(payload, function (error, response) {
            if (!error) {
              resolve(response);
            }
            reject(error);
          });
        });
      }
    }]);
    return CustomProvider;
  }();
  
  var ProvidersModuleFactory =
  function () {
    function ProvidersModuleFactory() {
      _classCallCheck(this, ProvidersModuleFactory);
    }
    _createClass(ProvidersModuleFactory, [{
      key: "createBatchRequest",
      value: function createBatchRequest(moduleInstance) {
        return new BatchRequest(moduleInstance);
      }
    }, {
      key: "createProviderResolver",
      value: function createProviderResolver() {
        return new ProviderResolver(this);
      }
    }, {
      key: "createHttpProvider",
      value: function createHttpProvider(url) {
        var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
        return new HttpProvider(url, options, this);
      }
    }, {
      key: "createXMLHttpRequest",
      value: function createXMLHttpRequest(host) {
        var timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
        var headers = arguments.length > 2 ? arguments[2] : undefined;
        var agent = arguments.length > 3 ? arguments[3] : undefined;
        var request = new xhr2Cookies.XMLHttpRequest();
        request.nodejsSet(agent);
        request.open('POST', host, true);
        request.setRequestHeader('Content-Type', 'application/json');
        request.timeout = timeout;
        request.withCredentials = true;
        if (headers) {
          headers.forEach(function (header) {
            request.setRequestHeader(header.name, header.value);
          });
        }
        return request;
      }
    }, {
      key: "createWebsocketProvider",
      value: function createWebsocketProvider(url) {
        var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
        var connection = '';
        if (typeof process !== 'undefined' && process.versions != null && process.versions.node != null) {
          var authToken;
          var headers = options.headers || {};
          var urlObject = new URL(url);
          if (urlObject.username && urlObject.password) {
            authToken = Buffer.from("".concat(urlObject.username, ":").concat(urlObject.password), 'base64');
            headers.authorization = "Basic ".concat(authToken);
          }
          if (urlObject.auth) {
            headers.authorization = Buffer.from(urlObject.auth, 'base64');
          }
          connection = new websocket.w3cwebsocket(url, options.protocol, null, headers, null, options.clientConfig);
        } else {
          connection = new window.WebSocket(url, options.protocol);
        }
        return new WebsocketProvider(connection, options.timeout);
      }
    }, {
      key: "createIpcProvider",
      value: function createIpcProvider(path, net) {
        return new IpcProvider(net.connect({
          path: path
        }), path);
      }
    }, {
      key: "createWeb3EthereumProvider",
      value: function createWeb3EthereumProvider(connection) {
        return new Web3EthereumProvider(connection);
      }
    }, {
      key: "createMetamaskProvider",
      value: function createMetamaskProvider(inpageProvider) {
        return new MetamaskProvider(inpageProvider);
      }
    }, {
      key: "createMistEthereumProvider",
      value: function createMistEthereumProvider(mistEthereumProvider) {
        return new MistEthereumProvider(mistEthereumProvider);
      }
    }, {
      key: "createCustomProvider",
      value: function createCustomProvider(connection) {
        return new CustomProvider(connection);
      }
    }]);
    return ProvidersModuleFactory;
  }();
  
  var global$1 = function () {
    return this || (typeof self === "undefined" ? "undefined" : _typeof(self)) === 'object' && self;
  }() || new Function('return this')();
  var ProviderDetector =
  function () {
    function ProviderDetector() {
      _classCallCheck(this, ProviderDetector);
    }
    _createClass(ProviderDetector, null, [{
      key: "detect",
      value: function detect() {
        if (typeof global$1.ethereumProvider !== 'undefined' && global$1.ethereumProvider.constructor.name === 'EthereumProvider') {
          return global$1.ethereumProvider;
        }
        if (typeof global$1.web3 !== 'undefined' && global$1.web3.currentProvider) {
          return global$1.web3.currentProvider;
        }
        return null;
      }
    }]);
    return ProviderDetector;
  }();
  
  function HttpProvider$1(url) {
    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    return new ProvidersModuleFactory().createHttpProvider(url, options);
  }
  function WebsocketProvider$1(url) {
    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    return new ProvidersModuleFactory().createWebsocketProvider(url, options);
  }
  function IpcProvider$1(path, net) {
    return new ProvidersModuleFactory().createIpcProvider(path, net);
  }
  function BatchRequest$1(moduleInstance) {
    return new ProvidersModuleFactory().createBatchRequest(moduleInstance);
  }
  function ProviderResolver$1() {
    return new ProvidersModuleFactory().createProviderResolver();
  }
  
  exports.ProviderDetector = ProviderDetector;
  exports.HttpProvider = HttpProvider$1;
  exports.WebsocketProvider = WebsocketProvider$1;
  exports.IpcProvider = IpcProvider$1;
  exports.BatchRequest = BatchRequest$1;
  exports.ProviderResolver = ProviderResolver$1;
  exports.ProvidersModuleFactory = ProvidersModuleFactory;
  exports.Web3EthereumProvider = Web3EthereumProvider;
  