WalletConnect / walletconnect-monorepo

WalletConnect Monorepo
Apache License 2.0
1.46k stars 715 forks source link

Here is a better alternative to rn-nodeify #753

Closed cdiddy77 closed 1 year ago

cdiddy77 commented 2 years ago

At the beginning of the quick start for Dapps (React Native) it proposes that folks use npx rn-nodeify --install --hack. This is problematic for a couple of reasons:

  1. It doesn't appear to work. I was not able to get it to work despite much effort. I finally gave up after applying sed hacks and many rm -rf node_mdules and pod installs.
  2. It's an ugly hack. (See rn-nodeify author's remarks). Not that co-opting the bundler to replace all your nodejs modules is not a hack, but at least its a hack that more or less the entire web dev world depends on. And even if rn-nodeify did work, it has consequences and is fragile.

Here is a better way:

Use the new metro bundler to do essentially what browserfy and webpack do. Here's how I got it to work:

In package.json:

  "dependencies": {
    . . . 
    "@react-native-async-storage/async-storage": "^1.15.17",
    "@walletconnect/react-native-dapp": "^1.7.1",
    "react-native-qrcode-svg": "6.0.6",
    "react-native-randombytes": "^3.6.1",
    "react-native-svg": "9.6.4"
  },
  "devDependencies": {
    . . . 
    "node-libs-react-native": "^1.2.1",
  },

The various react-native* deps are because even though new RN is good about having pod install take care of installing pods for native modules, it doesn't detect second- and greater order native deps. Note the specific versions. These are the versions that @walletconnect transitively requires. Blindly doing npm install -s react-native-svg for example will result in 2 versions of the SVG package being brought in, which results in a crash at startup.

The important one is the devDependency for node-libs-react-native

Next, create or edit metro.config.js :

module.exports = {
  resolver: {
    extraNodeModules: require("node-libs-react-native")
  },
  . . . 
};

This is the magic: It says: hey, metro, if you see, oh, say import * from "crypto"; and you can't find crypto, go ask node-libs-react-native, which then hooks up react-native-crypto.

There's one more little step, which is that Node.js modules often depend on certain globals. You hook these up by adding:

require("node-libs-react-native/globals.js");
 . . . 

at the top of index.js

It was just about that simple. I would strongly encourage to update the documentation for this amazing codebase and enable more folks to get it working faster. rn-nodeify is really an abominable hack, and whereas a better cleaner solution exists, now that the metro bundler has become sufficiently enhanced.

giovanni-caiazzo commented 2 years ago

Hi! This is great, however how can WalletConnect be used alongside ethers? The other project @walletconnect/web3-provider exposes the provider that can be digested by ethers, but this one does not... The rpcUrl field in the connector property is empty and so I can't use that as well and @walletconnect/web3-provider is not usable in a react native project even with this awesome solution. I'm stumped, can anyone help me?

giovanni-caiazzo commented 2 years ago

Hi! This is great, however how can WalletConnect be used alongside ethers? The other project @walletconnect/web3-provider exposes the provider that can be digested by ethers, but this one does not... The rpcUrl field in the connector property is empty and so I can't use that as well and @walletconnect/web3-provider is not usable in a react native project even with this awesome solution. I'm stumped, can anyone help me?

I found a solution. @walletconnect/web3-provider must be used together with @walletconnect/react-native-dapp so that you can set (example for BSC chain):

const provider = new WalletConnectProvider({
        rpc: {
            56: 'https://bsc-dataseed1.binance.org:443',
        },
        chainId: 56,
        connector: connector,
        qrcode: false,
    });

where connector is the instance passed by @walletconnect/react-native-dapp and qrcode: false is needed because otherwise it tries to call window.document.

Also for expo users: unfortunately to get walletconnect working on Android 11+ you need at least to expo prebuild to add

<queries>
    <intent>
      <action android:name="android.intent.action.VIEW"/>
      <category android:name="android.intent.category.BROWSABLE"/>
      <data android:scheme="https"/>
    </intent>
    <intent>
      <action android:name="android.intent.action.VIEW"/>
      <category android:name="android.intent.category.BROWSABLE"/>
      <data android:scheme="http"/>
    </intent>
    <intent>
      <action android:name="android.intent.action.VIEW"/>
      <category android:name="android.intent.category.BROWSABLE"/>
      <data android:scheme="wc"/>
    </intent>
    <intent>
      <action android:name="android.intent.action.VIEW"/>
      <category android:name="android.intent.category.BROWSABLE"/>
      <data android:scheme="mqtt"/>
    </intent>
    <intent>
      <action android:name="android.intent.action.VIEW"/>
      <category android:name="android.intent.category.BROWSABLE"/>
      <data android:scheme="wamp"/>
    </intent>
  </queries>

Otherwise your app can't see which apps are installed that support wallet connect and can't also send websocket requests (this last part I am not too sure, but at least you need the wc intent)

gate3 commented 2 years ago

@cdiddy77 thank you for the alternative its absolutely necessary. However I ran into another issue, actually a recurring one, I keep getting this error

null is not an object(evaluating 'RNRandomBytes.seed')

Any clues on how to solve this will be greatly appreciated

cdiddy77 commented 2 years ago

I don't think that I saw this one. If you think it's related to your dependencies, I might check the versions of what you have in your package.json with what is in other deps. 'Yarn why' is your friend.

gate3 commented 2 years ago

Thank @cdiddy77 .. used yarn why and I think the issue is coming from the wallet connect crypto library. I've followed your setup a few times and still get exactly thesame result. I can push a copy of my code if you have the time to take a look.

cdiddy77 commented 2 years ago

Happy to take a look

gate3 commented 2 years ago

Thank you.. here is a codesandbox https://codesandbox.io/s/l2pnn5

gate3 commented 2 years ago

Happy to take a look

Thank you @cdiddy77 .. this works now. Apparently it can only work in a project with native module capability. I tried it using the bare workflow from expo and it works great. Thanks once again

andiskim commented 2 years ago

At the beginning of the quick start for Dapps (React Native) it proposes that folks use npx rn-nodeify --install --hack. This is problematic for a couple of reasons:

  1. It doesn't appear to work. I was not able to get it to work despite much effort. I finally gave up after applying sed hacks and many rm -rf node_mdules and pod installs.
  2. It's an ugly hack. (See rn-nodeify author's remarks). Not that co-opting the bundler to replace all your nodejs modules is not a hack, but at least its a hack that more or less the entire web dev world depends on. And even if rn-nodeify did work, it has consequences and is fragile.

Here is a better way:

Use the new metro bundler to do essentially what browserfy and webpack do. Here's how I got it to work:

In package.json:

  "dependencies": {
    . . . 
    "@react-native-async-storage/async-storage": "^1.15.17",
    "@walletconnect/react-native-dapp": "^1.7.1",
    "react-native-qrcode-svg": "6.0.6",
    "react-native-randombytes": "^3.6.1",
    "react-native-svg": "9.6.4"
  },
  "devDependencies": {
    . . . 
    "node-libs-react-native": "^1.2.1",
  },

The various react-native* deps are because even though new RN is good about having pod install take care of installing pods for native modules, it doesn't detect second- and greater order native deps. Note the specific versions. These are the versions that @WalletConnect transitively requires. Blindly doing npm install -s react-native-svg for example will result in 2 versions of the SVG package being brought in, which results in a crash at startup.

The important one is the devDependency for node-libs-react-native

Next, create or edit metro.config.js :

module.exports = {
  resolver: {
    extraNodeModules: require("node-libs-react-native")
  },
  . . . 
};

This is the magic: It says: hey, metro, if you see, oh, say import * from "crypto"; and you can't find crypto, go ask node-libs-react-native, which then hooks up react-native-crypto.

There's one more little step, which is that Node.js modules often depend on certain globals. You hook these up by adding:

require("node-libs-react-native/globals.js");
 . . . 

at the top of index.js

It was just about that simple. I would strongly encourage to update the documentation for this amazing codebase and enable more folks to get it working faster. rn-nodeify is really an abominable hack, and whereas a better cleaner solution exists, now that the metro bundler has become sufficiently enhanced.

THANK YOU! it works

emzet93 commented 2 years ago

@cdiddy77 thanks! I love your approach! rn-nodeify really seems like a huge hack and it brings a lot of issues with build and create mess in project dependencies.

I tried your method and it seems to work - app is building, launching and I'm able to connect with my metamask wallet. However, I faced some other issues and I'm wondering if any of them sounds familiar:

  1. There are some problems with AsyncStorage - I'm able to connect to my wallet and I can see that all data is saved properly in AsyncStorage. However, after killing the app, the data is not rehydrated and connector.connected points to false.
  2. Connecting to wallet works properly in debug mode on iOS. But when I change scheme to release, executing connector.connect() results with getBrowerCrypto().getRandomValues is not a function error. So it looks like it's not able to resolve crypto package or sth
  3. I'm not able to disconnect the wallet - executing connector.killSession() throws TypeError: this._formatRequest is not a function

+1 to add this process in documantation

EDIT My bad, I didn't configure metro.config.js properly - extraNodeModules was overridden by sth else. So now 1 and 2 issues described above are gone and works as expected 🎉

There is still this issue with disconnecting the wallet, but I faced it even before when using rn-nodeify, so I beleive it's not connected with your soultion

heymage commented 2 years ago

@gate3 What was the change that worked for you in the end regarding the null is not an object(evaluating 'RNRandomBytes.seed') error? I have the same issue and had a look at your code sandbox, but I don't get it to work :(

gate3 commented 2 years ago

@gate3 What was the change that worked for you in the end regarding the null is not an object(evaluating 'RNRandomBytes.seed') error? I have the same issue and had a look at your code sandbox, but I don't get it to work :(

hi @mrcgrhrdt in my case I had two issues:

  1. I was using an expo project that was just a Js project without native app capabilities. If this is the same for you I will advice you eject or you create a new app with the bare workflow.

  2. I didn't configure the metro.config.js file properly. Here is what it looks like for me now in my non-expo app

extraNodeModules: modules.reduce(
      (acc, name) => {
        acc[name] = path.join(__dirname, 'node_modules', name);
        return acc;
      },
      { ...require('node-libs-react-native') }
    ),

Basically just make sure to spread the require('node-libs-react-native') in an object along with whatever was in extraModules before.

Cancuuu commented 2 years ago

image

im facing that issue, i do this steps https://github.com/WalletConnect/walletconnect-monorepo/issues/753#issue-1126720686 and put the "require("node-libs-react-native/globals.js");" in App.js (im using Expo) and then the other instructions of quick start for Dapps (React Native).

gate3 commented 2 years ago

image

im facing that issue, i do this steps #753 (comment) and put the "require("node-libs-react-native/globals.js");" in App.js (im using Expo) and then the other instructions of quick start for Dapps (React Native).

Hi @Cancuuu is this a managed expo app or a bare workflow expo app. From my experience i don't think the managed expo app works for this use case. And if its a barebones app, try uploading the repo and sharing a link, I can help take a look.

Apologies for misleading here, it works.. I will post a project once i bootstrap it.

Cancuuu commented 2 years ago

image im facing that issue, i do this steps #753 (comment) and put the "require("node-libs-react-native/globals.js");" in App.js (im using Expo) and then the other instructions of quick start for Dapps (React Native).

Hi @Cancuuu is this a managed expo app or a bare workflow expo app. From my experience i don't think the managed expo app works for this use case. And if its a barebones app, try uploading the repo and sharing a link, I can help take a look.

Thank you so much gate! the repo is private rn, but I will send it to you asap when it becomes public 😉

walidsahli commented 2 years ago

@emzet93 i got the same issue as you I'm not able to disconnect the wallet - executing connector.killSession() throws TypeError: this._formatRequest is not a function i solve it by image and using connector.killSession() instead

emzet93 commented 2 years ago

@walidsahli yeah exactly. I think this is caused by using this inside of those methods and destructing object properties just causes loosing context.

Abubakar672 commented 2 years ago

Hey everyone i am facing this error can some one help me out in this. I have tired alot of methods but none of them work, Do anyone of you know the solution to this.

Screen Shot 2022-05-24 at 7 16 36 PM Screen Shot 2022-05-24 at 7 16 44 PM
linxianxi commented 2 years ago

@gate3null is not an object(evaluating 'RNRandomBytes.seed')关于错误,最终对您有用的更改是什么?我有同样的问题,并查看了您的代码沙箱,但我没有让它工作:(

It works for me

npm i crypto-browserify stream-browserify

and

extraNodeModules: {
      ...require('node-libs-react-native'),
      crypto: require.resolve('crypto-browserify'),
      stream: require.resolve('stream-browserify'),
    },
gate3 commented 2 years ago

Just putting this here in case anybody needs it.. its bootstrapped and ready to go. Already has walletConnect and ethersjs installed.

Bare Workflow https://github.com/weedle-app/weedle-expo-bare-workflow

Managed Workflow https://github.com/weedle-app/weedle-expo-managed-workflow

jtculbreth commented 2 years ago

@cdiddy77 thanks! I love your approach! rn-nodeify really seems like a huge hack and it brings a lot of issues with build and create mess in project dependencies.

I tried your method and it seems to work - app is building, launching and I'm able to connect with my metamask wallet. However, I faced some other issues and I'm wondering if any of them sounds familiar:

  1. There are some problems with AsyncStorage - I'm able to connect to my wallet and I can see that all data is saved properly in AsyncStorage. However, after killing the app, the data is not rehydrated and connector.connected points to false.
  2. Connecting to wallet works properly in debug mode on iOS. But when I change scheme to release, executing connector.connect() results with getBrowerCrypto().getRandomValues is not a function error. So it looks like it's not able to resolve crypto package or sth
  3. I'm not able to disconnect the wallet - executing connector.killSession() throws TypeError: this._formatRequest is not a function

+1 to add this process in documantation

EDIT My bad, I didn't configure metro.config.js properly - extraNodeModules was overridden by sth else. So now 1 and 2 issues described above are gone and works as expected 🎉

There is still this issue with disconnecting the wallet, but I faced it even before when using rn-nodeify, so I beleive it's not connected with your soultion

Is the function "getBrowerCrypto" misspelled?

aindong commented 2 years ago

Just putting this here in case anybody needs it.. its bootstrapped and ready to go. Already has walletConnect and ethersjs installed.

Bare Workflow https://github.com/weedle-app/weedle-expo-bare-workflow

Managed Workflow https://github.com/weedle-app/weedle-expo-managed-workflow

Thank you @gate3 this is the best solution reference to follow :)

aditya172926 commented 1 year ago

I followed your steps and the app is building successfully on android device. But when I click on connect wallet I get this warning on react native

Error: Secure random number generation is not supported by this browser.
Use Chrome, Firefox or Internet Explorer 11

@gate3

finessevanes commented 1 year ago

@cdiddy77 thank you for your feedback and contribution! Since we are putting in all of our efforts into v2, I'm going to close this issue since it's a documentation update request for v1.

drattansingh commented 1 year ago

I followed all your steps in my react.js project however when I run it, the URL is incorrectly displaying as: https://localhost:3000/[object%20Object]

Any ideas?

ghost commented 1 year ago

Hi @cdiddy77 In my latest project, I am using react-native-chart-kit and it requires react-native-svg@13.4.0, but this @walletconnect/react-native-dapp only supports 9.6.4 version. So it says "Tried to register two views with the same name RNSVGRect" Could you please help me fix this issue?