Custom RPC node with web3Auth x Moralis

Hello,

I am using web3Auth and I can get it work in a local enviroment, but itā€™s not reliable. It would appear that the default RPC nodes donā€™t always work.

For example
Rinkeby infura RPC returns 429, but metamask still works
Eth Mainnet RPC https://broken-blue-forest.quiknode.pro/60023510ffcb97e58b168c479c0a48bcf2f84729 returns 404

But to use a different RPC Iā€™m not sure how to go about it since itā€™s not directly written in the documentation.

This is the default code recommended by Moralis. Thereā€™s no place for RPC

     await authenticate({
        provider: "web3Auth",
        clientId: #####,
        chainId: 1,
        theme: "light", //or "dark"
        loginMethodsOrder: ["google", "facebook", "twitter", "discord", "reddit", "apple", "line", "github", "kakao", "linkedin", "weibo", "wechat", "email_passwordless"]
    })

web3Auth Telegram told me it could be customized (although thatā€™s all I could get out of them)

The web3auth documentationā€¦which does have an RPC node parameter, but I donā€™t know how you can also make that work with Moralis.

      const web3auth = new Web3Auth({
        clientId,
        chainConfig: {
          chainNamespace: CHAIN_NAMESPACES.EIP155,
          chainId: "0x1",
          rpcTarget: "https://rpc.ankr.com/eth", // This is the mainnet RPC we have added, please pass on your own endpoint while creating an app
        },
      });

For your local development only for testing, you can change the RPC in node_modules\moralis\lib\browser\Web3Connector\Web3AuthConnector.js:

// Build config
ethChainConfig = {
  chainNamespace: 'eip155',
  chainId: (0, _verifyChainId.default)(chainId)
}; // Build Web3Auth

to

// change chainId and RPC for your chain
if (chainId === '0x13881') {
  ethChainConfig = {
    chainNamespace: 'eip155',
    chainId: (0, _verifyChainId.default)(chainId),
    rpcTarget: 'https://rpc-mumbai.matic.today'
  }; // Build Web3Auth

} else {
  ethChainConfig = {
    chainNamespace: 'eip155',
    chainId: (0, _verifyChainId.default)(chainId),
  }; // Build Web3Auth
}

Then restart your app server. If it doesnā€™t work, clear your browser cache.

1 Like

Thank you glad, but what about production?

For production, you would have to fork the Moralis JS SDK and change the base connector and then use that custom SDK. Or apply a patch for this change e.g. with patch-package so itā€™s added when you deploy your project.

You can suggest they add the RPC URL in authenticate so you donā€™t have to do this at https://roadmap.moralis.io for a future SDK version.

1 Like

Ok makes sense. While you are here, another param is the client ID provided by web3auth which is currently exposed to the client. Is it a security risk?

It shouldnā€™t, because you can limit the client id to specific url, so it wont work on non Whitelisted Urls

1 Like

glad, Iā€™m trying to fork moralis, but when I add it to packages, it doesnā€™t change to to the correct folder structure with the dist and lib subfolders.

It has the original structure as seen in the repo (which doesnā€™t have the lib and dist). This is the first time trying to fork a library.

Iā€™ve tried yarn add and npm install, both with different, but still incorrect results. When I simply do npm install moralis, it does install the original non-forked version of moralis.

Iā€™m guessing Iā€™m missing a step here. Any help?

My forked repo: https://github.com/quarkstars/Moralis-JS-SDK

Iā€™ve also tried

cd ./node_modules/moralis && npm install && npm run build

which completes

but it still doesnā€™t seem to have the lib folder

Doing it that way wonā€™t work as the package is deployed to npm by a specific user and for you installing it will always pull from that user because package names are unique.
A way to do that is by cloning the repo and deploy to npm locally on your machine and pull from there, doing this, youā€™ll have to build your project locally before deploying.

Iā€™m not sure I did exacly what you are saying, I just installed Moralis, took the prebuilt version (with lib and dist) and created my own repo from that, then added that as a package dependency. Works so far.

Installing it using npm wonā€™t install the fix you made there. You should make the fix locally in the node modules or try it out the way I explained. You need a little understanding of how npm works locally to fix that though

Iā€™m so confused, I canā€™t seem to make changes in node_modules\moralis\lib\browser\Web3Connector\Web3AuthConnector.js and have them impact the site.

This is the original moralis 1.8.0 and editing directly in the node_modules on my local enviroment.

Even COMMENTING OUT the entire Web3AuthConnector.js, it still opens up the login and launches web3authā€™s pop up. Huh??

However, if I delete the Web3AuthConnector.js it says thereā€™s missing required stuff.

I have tried reseting VS Code and the browser and still the same issue.

Have you restarted your app server?

The local next server is being restarted. Iā€™m gonna take a shot at deploying it on vercel and see what happens in a totally different enviroment.

When I deployed production (vercel) using my custom fork I still get the same issue. This is the file (the console.logs dontā€™ appear in my consoleā€¦)

"use strict";

var _Reflect$construct = require("@babel/runtime-corejs3/core-js-stable/reflect/construct");

var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");

var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");

_Object$defineProperty(exports, "__esModule", {

  value: true

});

exports.Web3Auth = void 0;

var _regenerator = _interopRequireDefault(require("@babel/runtime-corejs3/regenerator"));

var _concat = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/concat"));

var _promise = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/promise"));

var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/asyncToGenerator"));

var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/createClass"));

var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/classCallCheck"));

var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/assertThisInitialized"));

var _inherits2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/inherits"));

var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/possibleConstructorReturn"));

var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/getPrototypeOf"));

var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/defineProperty"));

var _ethers = require("ethers");

var _verifyChainId = _interopRequireDefault(require("../utils/verifyChainId"));

var _AbstractWeb3Connector = _interopRequireDefault(require("./AbstractWeb3Connector"));

function _createSuper(Derived) {

  var hasNativeReflectConstruct = _isNativeReflectConstruct();

  return function () {

    var Super = (0, _getPrototypeOf2.default)(Derived),

        result;

    if (hasNativeReflectConstruct) {

      var NewTarget = (0, _getPrototypeOf2.default)(this).constructor;

      result = _Reflect$construct(Super, arguments, NewTarget);

    } else {

      result = Super.apply(this, arguments);

    }

    return (0, _possibleConstructorReturn2.default)(this, result);

  };

}

function _isNativeReflectConstruct() {

  if (typeof Reflect === "undefined" || !_Reflect$construct) return false;

  if (_Reflect$construct.sham) return false;

  if (typeof Proxy === "function") return true;

  try {

    Boolean.prototype.valueOf.call(_Reflect$construct(Boolean, [], function () {}));

    return true;

  } catch (e) {

    return false;

  }

}

var Web3Auth = /*#__PURE__*/function (_AbstractWeb3Connecto) {

  (0, _inherits2.default)(Web3Auth, _AbstractWeb3Connecto);

  var _super = _createSuper(Web3Auth);

  function Web3Auth() {

    var _context;

    var _this;

    (0, _classCallCheck2.default)(this, Web3Auth);

    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {

      args[_key] = arguments[_key];

    }

    _this = _super.call.apply(_super, (0, _concat.default)(_context = [this]).call(_context, args));

    (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "type", 'web3Auth');

    (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "connect", function (web3auth) {

      return new _promise.default(function (resolve, reject) {

        (function (web3auth) {

          web3auth.loginModal.on('MODAL_VISIBILITY', /*#__PURE__*/function () {

            var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(visibility) {

              return _regenerator.default.wrap(function (_context2) {

                while (1) {

                  switch (_context2.prev = _context2.next) {

                    case 0:

                      if (!visibility) {

                        reject(new Error('Web3Auth: User closed login modal.'));

                      }

                    case 1:

                    case "end":

                      return _context2.stop();

                  }

                }

              }, _callee);

            }));

            return function () {

              return _ref.apply(this, arguments);

            };

          }());

        })(web3auth);

        web3auth.connect().then(resolve).catch(reject);

      });

    });

    (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "activate", /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() {

      var _ref3,

          _ref3$chainId,

          chainId,

          clientId,

          theme,

          appLogo,

          loginMethodsOrder,

          _Web3Auth,

          _require,

          _window,

          _window$Web3auth,

          ethChainConfig,

          web3auth,

          provider,

          _web3auth,

          _web3auth2,

          _web3auth3,

          isSocialLogin,

          ether,

          signer,

          values,

          providerChainId,

          _args2 = arguments;

      return _regenerator.default.wrap(function (_context3) {

        console.log('148', chainId)

        while (1) {

          switch (_context3.prev = _context3.next) {

            case 0:

              _ref3 = _args2.length > 0 && _args2[0] !== undefined ? _args2[0] : {}, _ref3$chainId = _ref3.chainId, chainId = _ref3$chainId === void 0 ? '0x1' : _ref3$chainId, clientId = _ref3.clientId, theme = _ref3.theme, appLogo = _ref3.appLogo, loginMethodsOrder = _ref3.loginMethodsOrder;

              if (clientId) {

                _context3.next = 3;

                break;

              }

              throw new Error('"clientId" not provided, please provide clientId');

            case 3:

              try {

                _Web3Auth = (_require = require('@web3auth/web3auth')) === null || _require === void 0 ? void 0 : _require.Web3Auth;

              } catch (_unused) {// Do Nothing Individual Checks are done below

              } // Check if user is using CDN to import

              if (!_Web3Auth) {

                _Web3Auth = (_window = window) === null || _window === void 0 ? void 0 : (_window$Web3auth = _window.Web3auth) === null || _window$Web3auth === void 0 ? void 0 : _window$Web3auth.Web3Auth;

              } // Error checking for if library is not installed

              if (_Web3Auth) {

                _context3.next = 7;

                break;

              }

              throw new Error('"@web3auth/web3auth" not installed, please install');

            case 7:

              // change chainId and RPC for your chain

              if (chainId === '0x1') {

                console.log('182', chainId)

                ethChainConfig = {

                  chainNamespace: 'eip155',

                  chainId: (0, _verifyChainId.default)(chainId),

                  rpcTarget: 'https://speedy-nodes-nyc.moralis.io/9e***********d1/eth/mainnet'

                }; // Build Web3Auth

              } else {

                console.log('190', chainId)

                ethChainConfig = {

                  chainNamespace: 'eip155',

                  chainId: (0, _verifyChainId.default)(chainId),

                }; // Build Web3Auth

              }

              try {

                web3auth = new _Web3Auth({

                  chainConfig: ethChainConfig,

                  uiConfig: {

                    theme: theme !== null && theme !== void 0 ? theme : 'dark',

                    appLogo: appLogo !== null && appLogo !== void 0 ? appLogo : 'https://moralis.io/wp-content/uploads/2021/05/moralisWhiteLogo.svg',

                    loginMethodsOrder: loginMethodsOrder

                  },

                  clientId: clientId

                });

              } catch (_unused2) {// Do Nothing error checked below

              }

              if (web3auth) {

                _context3.next = 11;

                break;

              }

              throw new Error('Could not connect via Web3Auth, error during initializing Web3Auth');

            case 11:

              _context3.next = 13;

              return web3auth.initModal();

            case 13:

              provider = null;

              _context3.next = 16;

              return _this.connect(web3auth);

            case 16:

              provider = _context3.sent;

              if (provider) {

                _context3.next = 19;

                break;

              }

              throw new Error('Could not connect via Web3Auth, error in connecting to provider');

            case 19:

              _context3.prev = 19;

              isSocialLogin = (_web3auth = web3auth) !== null && _web3auth !== void 0 && _web3auth.provider ? false : true;

              ether = new _ethers.ethers.providers.Web3Provider((_web3auth2 = web3auth) !== null && _web3auth2 !== void 0 && _web3auth2.provider ? web3auth.provider : web3auth);

              signer = ether.getSigner();

              _context3.next = 25;

              return _promise.default.all([ether.getNetwork(), signer.getAddress()]);

            case 25:

              values = _context3.sent;

              providerChainId = values[0].chainId;

              _this.account = values[1].toLocaleLowerCase();

              _this.chainId = "0x".concat(providerChainId.toString(16));

              _this.provider = isSocialLogin ? ether : (_web3auth3 = web3auth) === null || _web3auth3 === void 0 ? void 0 : _web3auth3.provider;

              _this.web3Instance = web3auth;

              _this.subscribeToEvents(_this.provider);

              return _context3.abrupt("return", {

                chainId: _this.chainId,

                account: _this.account,

                provider: _this.provider

              });

            case 35:

              _context3.prev = 35;

              _context3.t0 = _context3["catch"](19);

              throw new Error('Could not connect via Web3Auth, error while authenticating');

            case 38:

            case "end":

              return _context3.stop();

          }

        }

      }, _callee2, null, [[19, 35]]);

    })));

    (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "deactivate", /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3() {

      return _regenerator.default.wrap(function (_context4) {

        while (1) {

          switch (_context4.prev = _context4.next) {

            case 0:

              _this.unsubscribeToEvents(_this.provider);

              if (!_this.web3Instance) {

                _context4.next = 4;

                break;

              }

              _context4.next = 4;

              return _this.web3Instance.logout();

            case 4:

              _this.account = null;

              _this.chainId = null;

              _this.provider = null;

            case 7:

            case "end":

              return _context4.stop();

          }

        }

      }, _callee3);

    })));

    return _this;

  }

  return (0, _createClass2.default)(Web3Auth);

}(_AbstractWeb3Connector.default);

exports.Web3Auth = Web3Auth;

OH NEVERMIND, they are appearing in my console. The chainId should be 1 (number), not the string (your code has a bug)

Okay, so going back to the issues with the package not being updated when editing code, it has something to do with package-lock.json and the versions stored there. I even had to update the version of my fork for my production enviroment to realize it should look for changesā€¦Iā€™m now the first running the newest version of Moralis 1.8.1.

BUT BACK TO THE ORIGINAL ISSUE:
It appears to be using my custom rpc but now Iā€™m getting error 403, not authorized https://f*******w.usemoralis.com:2053/server/users 403

Whatā€™s the deal?

Okay, I switched servers, and now it works.

Wow, thatā€™s a lot of work to jump through to put in a custom RPC which is REQUIRED for web3auth. I hope someone at Moralis is taking notes and implements this feature. There is really no point to offer intergration with web3auth if you have to use their crappy rpcs (they say in their documentation that you need to switch it)

Hi Mikiekwoods,

Actually I passed the rpcTarget directly at the top level of the config and it works:

await authenticate({
provider: ā€œweb3Authā€,
clientId: ā€œā€¦ā€,
chainId: ā€œ0x5ā€,
rpcTarget: ā€œhttps://rpc.ankr.com/ethā€
})

my only question is that I thought Moralis would provide an rpc Targetā€¦ what am I supposed to put there as a valid target ?

you should put there a public RPC url, if you put your speedy node url then anyone can see it and use it

1 Like