Cronos developer series: build a simple Dapp with React, Crypto.com DeFi Wallet and MetaMask

Cronos is EVM compatible, which means that you can port any Dapp from another Ethereum-compatible chain to Cronos. This is excellent news for you, Solidity developer!

The Dapp must be configured to connect to Cronos and allow users to log in and sign transactions. Dapps may use two of the world’s most widely used crypto wallets, MetaMask and Crypto.com’s DeFi Wallet.

In this blog post, we will review a simple Dapp that connects to Cronos. You can play with the code available at this Github repository to create a user experience that works for you.

Please note that this is a guest post. It it is not endorsed by Cronos, MetaMask or Crypto.com.

As part of this tutorial, we are going to build a very simple Dapp that shows information and balances from the Cronos chain.

The Dapp will showcase 3 possible ways that the end-user can log in, for demonstration purposes. The following options differ by device type and login user experience, and you can select those that feel right for your Dapp:

Note: More login options are under development by wallet providers, for example native login in the Crypto.org desktop wallet and in the Crypto.com DeFi Wallet. They will be covered by future posts.

You need to have node version 14+ installed on your machine, for example using nvm. We will use React, Redux, and Typescript; therefore, it helps if you are familiar with these libraries and languages.

To play with the Dapp as a user, you need to install:

If you’d like, you can create a wallet in the DeFi Wallet app first, and then import your seed phrase to the MetaMask wallet so that you can use the same account in both wallets. Or vice versa. But remember that you should never share your seed phrase with anyone to keep your accounts secure!

To create test transactions on the Cronos Testnet, you will need some Test CRO tokens. Visit the Cronos Testnet Faucet, and enter your public account address, to receive the Test CROs.

First things first, let’s run the Dapp on your computer !

You must clone the repository to your machine and open a Terminal in the root folder of that repository. Enter the command npm install and then npm start. Then, open your browser at URL https://127.0.0.1:3000.

Make sure that your wallet apps are connected to Cronos Testnet. If Cronos Testnet is not yet set-up in your MetaMask wallet, don’t worry, the Dapp will configure it automatically.

The Dapp’s Connect Wallet button allows you to connect to the Dapp using various methods, as shown below:

Once you are connected, the Dapp shows some basic information regarding the chain that we are connected to, and the tokens that you own, as shown below:

CTOK is actually a dummy ERC20 token deployed to the Cronos Testnet, that anyone can mint in order to increase their balance whenever they want.

In the Dapp, you can click Mint 1 CTOK for Myself and then click the Refresh Balance button after a few seconds in order to see your updated balance.

If you want to test the Dapp on your mobile device, you need a way to tunnel the local port 127.0.0.1:3000 to an external web address that you can visit from the in-app browser of your wallet app. For tunneling we use ngrok, but a detailed explanation of ngrok would make this post too long, so we will leave this to more experienced users. Also, note that DeFi Wallet does not support the in-app browser on Tesnet, so you’ll need to use Cronos Mainnet to test the mobile experience once you have completed the rest of this tutorial.

Crypto.org exposes public JSON-RPC endpoints to access Cronos Mainnet and Cronos Testnet. The configuration values are shown in the config/config.ts file.

Here, we will be using Cronos Testnet. Hence, the rpcNetwork_mainnet values are provided only for reference.

If you expect high transaction volume in your Dapp, you will probably want to run your own full Cronos node instead of the publicly available one, to avoid rate limits.

In the world of Dapps, a Web3 provider is an object that can be called by the application to read the blockchain or send transactions to it.

Our goal is to create a Web3 provider. We could use one of the two widely used Javascript libraries, web3.js or ethers.js. Here, we use ethers.

We will store the wallet connection in the Redux store of the React application:

The general approach, when connecting to a wallet, is to access a provider object that is exposed by the wallet’s SDK, and then to use ethers.providers.JsonRpcProvider(provider) in order to generate a Web3 provider that will be called by the Dapp for blockchain read and write.

MetaMask handles read and write blockchain calls slightly differently. For example, on Ethereum Mainnet, MetaMask exposes its own provider for write transactions, but if the Dapp needs to read large amounts of blockchain data, it needs to call its own Infura or Alchemy account. That is the reason why we store two distinct Web3 providers in the IWallet object: a browser-based Web3 provider browserWeb3Provider for write transactions, and a server-based Web3 provider serverWeb3Provider that connects directly to the blockchain network’s RPC endpoint for read calls.

All of this will be shown with more details below.

The Connect Wallet button is located in the Header component of the React application. The following code excerpt shows that the login flow is executed by distinct helpers depending on the wallet selected by the user. See the repository for the full code.

For MetaMask, the login flow is located in the helpers/wallet-metamask.ts helper:

For Crypto.com DeFi Wallet using the Wallet Extension on browser, the login flow is located in the helpers/wallet-defiwallet helper:

For Crypto.com DeFi Wallet using Wallet Connect, the login flow is located in the helpers/wallet-connect helper. It works both in the browser and on mobile.

We can easily read the blockchain thanks to the serverWeb3Provider that is connected directly to the blockchain network’s RPC endpoint.

The serverWeb3Provider does not use the wallet connector, since there is no transaction signature required. If the Web3 Provider needs to know the user’s address, it can simply take it from the wallet.address field in the Redux store, which was updated at the time of login.

The following code excerpt shows how the Dapp reads the latest block’s number and the CRO and CTOK balances of the user using the standard ethers.js methods:

The above readhelpers are called by the Dapp at the time of login, as well as when the user clicks the Refresh Balance button. For example, you can see how the Refresh Balance button works here:

In order to sign a blockchain transaction, we must use the browserWeb3Provider that is connected directly to the wallet extension (MetaMask of DeFi Wallet).

First, we use browserWeb3Provider to create a ethers.Contractobject that is connected to the ERC20 smart contract and to the wallet’s signer:

Then we use the mint function that is exposed by the smart contract (via ethers.js) in order to request the minting of 1 CTOK for the user. The smart contract balances have 18 decimals here, hence we are minting 1,000,000,000,000,000,000 units of the token.

Go ahead and clone the entire Github repository. You can review it in more details to fully understand the login and transaction signing flows!

You can also test the Dapp on the Cronos Mainnet, simply by switching the configuration details in the config/config.ts file (network and contract address). For testing, do not forget to switch your DeFi Wallet to Mainnet in the browser extension as well as the mobile app.

Of course, this Dapp is a basic demo. Your Dapp will require more design and fine tuning if you want to offer a top-notch user experience. Check the repositories of some apps of the Cronos ecosystem like VVS Finance and Beefy Finance to find out how they have addressed similar challenges!

Finally, there are some great frameworks that developers can leverage in order to re-use frequently used connection methods, for example web3modal and web3-react. You can customize these frameworks to connect to the Cronos custom JSON-RPC network endpoints.

Feel free to post a pull request or an issue in Github if you would like to suggest improvements regarding this demo.