Integration Tutorial Latest

Set up the repo and install packages

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

Create a new react project with react with name banana-sdk-demo and now let's move into to the directory

npx create-react-app banana-sdk-demo
cd banana-sdk-demo

Step 2: Installing banana sdk package

Run the following commands in your terminal. To configure necessary packages and dependencies

npm i @rize-labs/banana-wallet-sdk

Step 3: Fixing webpack polyfill issues

npm install constants-browserify crypto-browserify os-browserify path-browserify process stream-browserify webpack buffer ethers@^5.7.2 react-app-rewired

Step 4: Creating config-overrides.js file with 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.ignoreWarnings = [/Failed to parse source map/];
    config.resolve.extensions = [...config.resolve.extensions, ".ts", ".js"]
    config.plugins = [
      ...config.plugins,
      new ProvidePlugin({
        Buffer: ["buffer", "Buffer"],
      }),
      new ProvidePlugin({
          process: ["process"]
      }),
    ]
    return config;
  },
}

To learn more about it refer below page

🧊pageWebpack 5 Polyfill Issue

Step 5: Enforcing overrides

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:

  • Call stake method and make a transaction to blockchain by changing state variable.

  • Fetch value of state variable stakeAmount.

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:

0xCB8a3Ca479aa171aE895A5D2215A9115D261A566

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.

Import and stuff

import "./App.css";
import { Banana, Chains } from '@rize-labs/banana-wallet-sdk';
import { useEffect, useState } from "react";
import { ethers } from "ethers";
import { SampleAbi } from "./SampleAbi";

Download app.css and SampleAbi from here App.css and SampleAbi

Initializing some states for demo

  const [walletAddress, setWalletAddress] = useState("");
  const [bananaSdkInstance, setBananSdkInstance] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const [walletInstance, setWalletInstance] = useState(null);
  const [output, setOutput] = useState("Welcome to Banana Demo");
  const SampleContractAddress = "0xCB8a3Ca479aa171aE895A5D2215A9115D261A566";

Init Banana SDK instance

// calling it in useEffect

useEffect(() => {
    getBananaInstance();
}, []);

  const getBananaInstance = () => {
    const bananaInstance = new Banana(Chains.chiadoTestnet);
    setBananSdkInstance(bananaInstance);
  };

For simplicity here we are creating SDK instance for Chiado testnet network.

Creating Wallet

const createWallet = async () => {
    // starts loading
    setIsLoading(true);
    
    // creating wallet
    const wallet = await bananaSdkInstance.createWallet();
    setWalletInstance(wallet);
    
    // getting address for wallet created
    const address = await wallet.getAddress();
    setWalletAddress(address);
    setOutput("Wallet Address: " + address);
    setIsLoading(false);
 };

Dev just need to call createWallet method which will inherently ask user for wallet name once username is provided wallet would be initialized for user and the method would return an instance of wallet.

Connecting Wallet

const connectWallet = async () => {
    
    // checking does wallet name is cached in cookie 
    const walletName = bananaSdkInstance.getWalletName();
    
    // if cached we will use it 
    if (walletName) {
      setIsLoading(true);

     // connect wallet with cached wallet name
      const wallet = await bananaSdkInstance.connectWallet(walletName);
      setWalletInstance(wallet);

      // extracting wallet address for display purpose
      const address = await wallet.getAddress();
      setWalletAddress(address);
      setOutput("Wallet Address: " + address);
      setIsLoading(false);
    } else {
      setIsLoading(false);
      alert("You don't have wallet created!");
    }
  };

When the user wallet is created the wallet's public data is already cached into the user's cookie. The getWalletName function fetches the walletName from the cookie and once fetched we need to pass walletName into connectWallet which internally initializes and configures some wallet parameters and returns a wallet instance

Get ChainId

  const getChainId = async () => {
    setIsLoading(true);
    const signer = walletInstance.getSigner();
    const chainid = await signer.getChainId();
    setOutput(JSON.stringify(chainid));
    setIsLoading(false);
  };

Getting chainId is pretty straightforward forward devs just have to extract the signer from wallet once signer is extracted you can do getChainId to get the chainId of the current network.

Get Network

  const getNetwork = async () => {
    setIsLoading(true);
    const provider = walletInstance.getProvider();
    const network = await provider.getNetwork();
    setOutput(JSON.stringify(network));
    setIsLoading(false);
  };

Extracting the network is as easy as it looks dev just need to extract provider from wallet and from provider get network info using getNetwork method.

Make transaction

   const makeTransaction = async () => {
    setIsLoading(true);
    
    // getting signer
    const signer = walletInstance.getSigner();
    const amount = "0.00001";
    const tx = {
      gasLimit: "0x55555",
      to: SampleContractAddress,
      value: ethers.utils.parseEther(amount),
      data: new ethers.utils.Interface(SampleAbi).encodeFunctionData(
        "stake",
        []
      ),
    };

    try {
      // sending txn object via signer
      const txn = signer.sendTransaction(tx);
      setOutput(JSON.stringify(txn));
    } catch (err) {
      console.log(err);
    }
    setIsLoading(false);
  };

For making a transaction. you just need to create a transaction object. then extract signer from th wallet instance you received and just make transaction by passing txn object to the send transaction method.

PS: just make sure your wallet is funded before you make any transaction.

Signing message

  const signMessage = async () => {
    setIsLoading(true);
    const sampleMsg = "Hello World";
    const signer = walletInstance.getSigner();
    const signMessageResponse = await signer.signBananaMessage(sampleMsg);
    setOutput(JSON.stringify(signMessageResponse));
    setIsLoading(false);
  };

Signing a message is as simple as it looks. You just need to pass a message which you need to get signed once signed the method returns an object { messageSigned: "", signature: "" }

messageSigned: message which actually got signed.

signature: signature for the signed message.

JSX code for frontend

<div className="App">
  <h1>Banana SDK Demo</h1>
  {walletAddress && <p> Wallet Address: {walletAddress}</p>}
  <button className="btn" onClick={() => createWallet()}>
    Create Wallet
  </button>
  <button className="btn" onClick={() => connectWallet()}>
    Connect Wallet
  </button>
  <button className="btn" onClick={() => getChainId()}>
    ChainId
  </button>
  <button className="btn" onClick={() => getNetwork()}>
    Network
  </button>
  <button className="btn" onClick={() => makeTransaction()}>
    Make transaction
  </button>
  <button className="btn" onClick={() => signMessage()}>
    Sign message
  </button>
  <h1> Output Panel</h1>
  <div className="output-div">
    <p>{isLoading ? "Loading.." : output}</p>
  </div>
</div>

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

Last updated