Banana <> Astar

Set up the repo and install packages

Step 1: Create a new repo with create-react-app

Create a new typescript based react project with react with name banana-rainbow-integ and now let's move into to the directory

npx create-react-app banana-wallet-demo --template typescript
cd banana-rainbow-integ

Step 2: Installing rainbowkit, wagmi and Banana rainbow plugin package

npm install @rainbow-me/rainbowkit@0.8.1 wagmi@0.9.0 @rize-labs/banana-rainbowkit-plugin

Step 3: Fixing webpack 5 and polyfill issues

npm install react-app-rewired 

npm install stream-browserify constants-browserify crypto-browserify os-browserify path-browserify process stream-browserify buffer ethers@^5.7.2

Create a file name `config-overrides.js` with the below content

const { ProvidePlugin }= require("webpack")

module.exports = {
  webpack: function (config, env) {
    config.module.rules = config.module.rules.map(rule => {
      if (rule.oneOf instanceof Array) {
        rule.oneOf[rule.oneOf.length - 1].exclude = [/\.(js|mjs|jsx|cjs|ts|tsx)$/, /\.html$/, /\.json$/];
      }
      return rule;
    });
    config.resolve.fallback = {
      ...config.resolve.fallback,
      stream: require.resolve("stream-browserify"),
      buffer: require.resolve("buffer"),
      crypto: require.resolve("crypto-browserify"),
      process: require.resolve("process"),
      os: require.resolve("os-browserify"),
      path: require.resolve("path-browserify"),
      constants: require.resolve("constants-browserify"), 
      fs: false
    }
    config.resolve.extensions = [...config.resolve.extensions, ".ts", ".js"]
    config.ignoreWarnings = [/Failed to parse source map/];
    config.plugins = [
      ...config.plugins,
      new ProvidePlugin({
        Buffer: ["buffer", "Buffer"],
      }),
      new ProvidePlugin({
          process: ["process"]
      }),
    ]
    return config;
  },
}

Step 4: Modify package.json

Change package.json accordingly to use the start app with react-app-rewired

react-scripts start -> react-app-rewired start

Smart Contracts

We will be having a very basic smart contract for the demo purpose for this demo. There will be two functionalities:

  • Make a transaction to the blockchain by making a state variable change its value.

  • Fetch value of state variable

Here is the smart contract code:

pragma solidity ^0.8.12;

contract Sample {

    uint public stakedAmount = 0;
    
    function stake() external payable {
        stakedAmount = stakedAmount + msg.value;
    }

    function returnStake() external {
        payable(0x48701dF467Ba0efC8D8f34B2686Dc3b0A0b1cab5).transfer(stakedAmount);
    }
}

You can deploy it using remix.ethereum.org and save the smart contract address.

For your reference a sample contract has been deployed here:

0x59DC70db4A6914Bece003Eff48C8fa4166aaC05a

Building the frontend

We will have a simple front end with some buttons to interact with the blockchain. Although Banana SDK provides you with a smart contract wallet you don't need worry about its deployment. Everything is handled by us in the SDK so you can just concentrate on building your Dapp.

In App.tsx

let's import the required for rainbow

Importing required modules for rainbow

import "@rainbow-me/rainbowkit/styles.css";
import {
  RainbowKitProvider,
  connectorsForWallets,
} from "@rainbow-me/rainbowkit";
import {
  metaMaskWallet,
  injectedWallet,
  rainbowWallet,
  walletConnectWallet,
} from "@rainbow-me/rainbowkit/wallets";

let's import modules required from wagmi

import { polygonMumbai, optimismGoerli, goerli, gnosis, gnosisChiado  } from "@wagmi/chains";
import { jsonRpcProvider } from 'wagmi/providers/jsonRpc';
import { configureChains, createClient, WagmiConfig } from "wagmi";

Importing BananaWallet plugin from banana-rainbowkit-plugin package

import { BananaWallet, astarChain } from '@rize-labs/banana-rainbowkit-plugin'

Configure chains and providers

const { chains, provider } = configureChains( 
  // currently on these three chains are supported by BananaWallet
  [polygonMumbai, optimismGoerli, goerli, gnosis, gnosisChiado, astarChain],
   [
      jsonRpcProvider({
        rpc: chain => ({ http: chain.rpcUrls.default.http[0] }),
      }),
    ]
);

Creating connectors for rainbow

  const connectors = connectorsForWallets([
    {
      groupName: "Recommended",
      wallets: [
        BananaWallet({ chains, connect: { networkId: 592 } }), // networkId: 592 for astar
        metaMaskWallet({ chains, shimDisconnect: true }),
        rainbowWallet({ chains }),
        walletConnectWallet({ chains }),
        injectedWallet({ chains, shimDisconnect: true }),
      ],
    },
  ]);

Creating wagmiClient

  const wagmiClient = createClient({
    autoConnect: true,
    connectors,
    provider,
  });

Providing context of Rainbowkit and wagmi

  return (
    <div className="App">
      <WagmiConfig client={wagmiClient}>
        <RainbowKitProvider chains={chains}>
          <Demo />
        </RainbowKitProvider>
      </WagmiConfig>
    </div>
  );

Putting all together you can find the final App.tsx file here:

Let's start creating Demo.tsx which will contain logic for doing multiple things with wallet instance

Importing Hooks from wagmi

import { useSigner, useProvider, useAccount } from "wagmi";

Extracting signers and providers from wagmi hooks

const { isConnected } = useAccount();
const provider = useProvider();
const { data: signer } = useSigner();

Implementing function to getChainid of current chain

  const getChainID = async () => {
    try {
      //@ts-ignore
      const chainId = await signer.getChainId();
      setOutput(JSON.stringify(chainId.toString()));
    } catch (e) {
      console.error(e);
    }
  };

Implementing function to getBalance of an address

  const getBalance = async () => {
    try {
      //@ts-ignore
      const account = await signer.getAddress();
      const balanceChk1 = await provider!.getBalance(account);
      setOutput(JSON.stringify(balanceChk1));
    } catch (e) {
      console.error(e);
    }
  };

Implementing function to get network info

  const getNetworks = async () => {
    try {
      const network = await provider!.getNetwork();
      setOutput(JSON.stringify(network));
    } catch (e) {
      console.error(e);
    }
  };

Implementing function to sign Message using Banana Wallet

  const signMessage = async () => {
    try {
      setIsLoading(true);
      const message = "Welcome to Banana Wallet";

      //@ts-ignore
      const sig = await signer.signBananaMessage(message);
      setOutput(JSON.stringify(sig));
      setIsLoading(false);
    } catch (e) {
      setIsLoading(false);
      console.error(e);
    }
  };

implementing function to sendEth

  const sendETH = async () => {
    try {
      setIsLoading(true);
      //@ts-ignore
      const toAddress = ethers.Wallet.createRandom().address;

      const tx1 = {
        gasLimit: "0x55555",
        to: toAddress,
        value: ethers.utils.parseEther("0.000001"),
        data: "0x",
      };

      //@ts-ignore
      const txnResp = await signer.sendTransaction(tx1);
      setOutput(JSON.stringify(txnResp));
      setIsLoading(false);
    } catch (e) {
      setIsLoading(false);
      console.error(e);
    }
  };

Implementing function to make call to smart contract method

  const stakeTxn = async () => {
    try {
      setIsLoading(true);
      const amount = "0.00001";

      const tx = {
        gasLimit: "0x55555",
        to: SampleContractAddress,
        value: ethers.utils.parseEther(amount),
        data: new ethers.utils.Interface(SampleAbi).encodeFunctionData(
          "stake",
          []
        ),
      };

      //@ts-ignore
      const txn = await signer.sendTransaction(tx);
      setOutput(JSON.stringify(txn));
      setIsLoading(false)
    } catch (err) {
      setIsLoading(false);
      console.log(err);
    }
  };

Putting all together

Full code can be found here

If you have any questions please post them Banana SDK Discord forum.

Last updated