andieromero / walletconnect-js

Provenance Blockchain WalletConnect - Build Provenance Blockchain dApps using WalletConnect compliant wallets.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Provenance.io WalletConnect-JS

Library to interface with Provenance Wallet using WalletConnect.

Provenance is a distributed, proof of stake blockchain designed for the financial services industry.

For more information about Provenance Inc visit https://provenance.io

Table of Contents

  1. Installation
  2. Window messages
  3. WalletConnectContextProvider
  4. QRCodeModal
  5. useWalletConnect
  6. walletConnectService
  7. walletConnectState
  8. Web App
  9. Non React Setup
  10. Webpack 5 Issues
  11. Clone LocalStorage
  12. WalletConnect-js Status

Installation

Import the dependency

npm install @provenanceio/walletconnect-js --save

Importable items:

import {
  WINDOW_MESSAGES,
  WalletConnectContextProvider,
  useWalletConnect,
} from "@provenanceio/walletconnect-js";

Window Messages

Each method will return a window message indicating whether it failed or was completed as well as the result

Note A: See walletConnectService for all WINDOW_MESSAGES based on method. Note B: All of these are based off Node.js Event Emitters, read more on them here: Node.js Event Emitters

List of WINDOW_MESSAGES:

  export const WINDOW_MESSAGES = {
  // WalletConnect Connected
  CONNECTED: 'FWC_CONNECTED',
  // WalletConnect Disconnect
  DISCONNECT: 'FWC_DISCONNECT',
  // Send Message
  SEND_MESSAGE_COMPLETE: 'SEND_MESSAGE_COMPLETE',
  SEND_MESSAGE_FAILED: 'SEND_MESSAGE_FAILED',
  // JWT
  SIGN_JWT_COMPLETE: 'SIGN_JWT_COMPLETE',
  SIGN_JWT_FAILED: 'SIGN_JWT_FAILED',
  // Sign
  SIGN_MESSAGE_COMPLETE: 'SIGN_MESSAGE_COMPLETE',
  SIGN_MESSAGE_FAILED: 'SIGN_MESSAGE_FAILED',
};

Example Usage:

// (Example using sendMessage)

// Listen for complete/success
const successAction = (result) => {
  console.log(`WalletConnectJS | Send Message Complete | Result: `, result);
};
walletConnectService.addListener(
  WINDOW_MESSAGES.SEND_MESSAGE_COMPLETE,
  successAction
);
// Listen for error/failure
const failAction = (result) => {
  const { error } = result;
  console.log(`WalletConnectJS | Send Message Failed | result, error: `, result, error);
};
walletConnectService.addListener(
  WINDOW_MESSAGES.SEND_MESSAGE_FAILED,
  failAction
);

// Unmount listeners once they are no longer needed (typically in useEffect return)
// Remove event listeners once no longer needed (Node: Each requires specific function to remove, see Note B above)
walletConnectService.removeListener(
  WINDOW_MESSAGES.SEND_MESSAGE_COMPLETE,
  successAction
);
walletConnectService.removeListener(
  WINDOW_MESSAGES.SEND_MESSAGE_FAILED,
  failAction
);

WalletConnectContextProvider

React context provider to supply state to every child within

  • Include as parent to all Components using walletconnect-js

  • Optional: You may pass your own instance of walletConnectService into the context provider under the param service

  • Usage Example (w/React.js):

    // index.js
    ...
    
    ReactDOM.render(
      <WalletConnectContextProvider>
        <App />
      </WalletConnectContextProvider>,
      document.getElementById('root')
    );

QRCodeModal

To start the connection from dApp to wallet you will need to initiate the connection using the QRCodeModal component.

  • Takes in the following params:
    • walletConnectService: Service pulled out of useWalletConnect() hook (Required)
    • devWallets: Array of allowed dev wallets to connect into. (Optional)
    • hideWallets: Array of prod wallets to hide from user. (Optional)
    • For list of available wallets and their IDs see src/consts/walletList.ts
  • Usage:
    // App.js
    import { useWalletConnect, QRCodeModal } from '@provenanceio/walletconnect-js';
    ...
    export const App = () => {
      const { walletConnectService: wcs } = useWalletConnect();
      ...
      return (
        <QRCodeModal
          walletConnectService={wcs}
          devWallets={['figure_web_test', 'figure_mobile_test']}
          hideWallets={['figure_web', 'figure_mobile']}
        />
      )
    };
  • Note: This modal is built with React.js and will only work within a react project. If you are not using React.js look through the examples folder to see how to initiate the connection without QRCodeModal manually.

useWalletConnect

React hook which contains walletConnectService and walletConnectState

walletConnectService

  • Holds all main methods and functions to use WalletConnect service

  • connect

    Connect a WalletConnect wallet

    walletConnectService.connect({bridge, duration, noPopup});
    // WINDOW_MESSAGE: CONNECTED
    Param Type Required Default Example Info
    bridge string no "wss://figure.tech/service-wallet-connect-bridge/ws/external" "wss://custom.bridge" Custom bridge to connect into
    duration number no 1800 3600 Custom connection timeout in seconds
    noPopup boolean no false true Should the QRCodeModal popup automatically on connect call
    address string no '' tp1knsxfnn0lq48mmnkfnkgtkk8qnxxdu0y2tklkh Required address for dApp connection
    prohibitGroups boolean no false true Prohibit group accounts from connecting to this dApp
  • disconnect

    Disconnect current session

    walletConnectService.disconnect();
    // WINDOW_MESSAGE: DISCONNECT
  • generateAutoConnectUrl

    Change the amount of connection time remaining for the currenct walletconnect session

    walletConnectService.generateAutoConnectUrl({ url, duration, walletId });
    Param Type Required Default Example Info
    url string yes - 'https://figure.com' URL to send user (with wcjs functionality)
    duration number no current connected wallet timeout 3600 Seconds to set future connection to
    walletId string no current connected wallet type id 'provenance_extension' Which wallet to auto-connect with
  • resetConnectionTimeout

    Change the amount of connection time remaining for the currenct walletconnect session

    walletConnectService.resetConnectionTimeout(connectionTimeout);
    Param Type Required Default Example Info
    connectionTimeout number no 1800 3600 Seconds to extend current session
  • signJWT

    Prompt user to sign a generated JWT

    walletConnectService.signJWT(expire);
    // WINDOW_MESSAGES: SIGN_JWT_COMPLETE, SIGN_JWT_FAILED
    Param Type Required Default Example Info
    expire number no 24 hours (Date.now() + 86400) 1647020269 Custom expiration date (ms) of JWT
  • sendMessage

    Pass through a custom base64 encoded message

    walletConnectService.sendMessage({
      message,
      description,
      method,
      gasPrice,
      feeGranter,
      feePayer,
      memo,
      timeoutHeight,
      extensionOptions,
      nonCriticalExtensionOptions,
    });
    // WINDOW_MESSAGES: SEND_MESSAGE_COMPLETE, SEND_MESSAGE_FAILED
    Param Type Required Default Example Info
    message string / array yes - 'CiwvcHJvdmVuYW5jZS5tZX...' B64 encoded Message(s) to pass to wallet
    description string no 'Send Message' 'My Special Message' Prompt title on mobile wallet
    method string no 'provenance_sendTransaction' 'provenance_sendTransaction' Message method
    gasPrice object no { gasPrice: [Figure Default], gasPriceDenom: [Figure Default] } { gasPrice: 1337, gasPriceDenom: 'nhash' } Optional gasPrice object, defaults to Figure values
    feeGranter string no - 'tp1knsxfnn0lq48mmnkfnkgtkk8qnxxdu0y2tklkh' Specify a fee granter address
    feePayer string no - 'tp1knsxfnn0lq48mmnkfnkgtkk8qnxxdu0y2tklkh' Specify a fee payer address
    memo string no - 'My special memo' Specify a tx memo
    timeoutHeight number no - 3 Specify a tx timeoutHeight
    extensionOptions any[] no - ['CiwvcHJvdmVuYW5jZS5tZX...'] Specify tx extensionOptions
    nonCriticalExtensionOptions any[] no - ['CiwvcHJvdmVuYW5jZS5tZX...'] Specify tx nonCriticalExtensionOptions
  • signMessage

    Prompt user to sign a custom message

    walletConnectService.signMessage(message);
    // WINDOW_MESSAGES: SIGN_MESSAGE_COMPLETE, SIGN_MESSAGE_FAILED
    Param Type Required Default Example Info
    message hex string yes - 'My Custom Message' Hex string message to send

walletConnectState

  • Holds current walletconnect-js state values
    initialState: {
      account: '', // Figure account uuid [string]
      address: '', // Wallet address [string]
      bridge: 'wss://figure.tech/service-wallet-connect-bridge/ws/external', // WalletConnect bridge used for connection [string]
      connected: false, // WalletConnect connected [bool]
      connectionEat: null, // WalletConnect expires at time [number]
      connectionIat: null, // WalletConnect initialized at time [number]
      connectionTimeout: 1800, // Default timeout duration (seconds)
      connector: null, // WalletConnect connector
      figureConnected: false, // Account and address both exist [bool]
      isMobile: false, // Is the connected browser a mobile device [bool]
      loading: '', // Are any methods currently loading/pending [string]
      newAccount: false, // Is this a newly created account
      peer: {}, // Connected wallet info [object]
      publicKey: '', // Wallet public key (base64url encoded)
      QRCode: '', // QRCode image data to connect to WalletConnect bridge [string]
      QRCodeUrl: '', // QRCode url contained within image [string]
      showQRCodeModal: false, // Should the QR modal be open [bool]
      signedJWT: '', // Signed JWT token [string]
      walletApp: '', // What type of wallet is this "provenance_extension" | "provenance_mobile" | "figure_web"
      walletInfo: {}, // Contains wallet coin, id, and name
      representedGroupPolicy: null, //Present when the wallet holder is acting on behalf of a group
    }

Web App

This package comes bundled with a full demos that you can run locally to test out the various features of walletconnect-js. To see how to initiate and run the different examples, look through the README.md

  • Quick Start:
    1. Pull down the latest walletconnect-js.
    2. Run npm i to install all the required node packages
    3. Run npm run start to launch a localhost demo.

Non React Setup

This package works without react and with any other javascipt library/framework (tested with vanilla js)

Using a CDN Import

You can find this package on https://unpkg.com/: - Note: Change the version in the url as needed: https://unpkg.com/@provenanceio/walletconnect-js@2.0.0/umd/walletconnect-js.min.js - Example use: js <script src="https://unpkg.com/@provenanceio/walletconnect-js@2.0.0/umd/walletconnect-js.min.js"></script>

Using Imports

There are a few differences in getting setup and running: 1) Note Webpack 5 Issues 2) When connecting, you will need to manually generate the QR code image element (Component is only available to React.js apps) 3) Don't use the default imports (@provenanceio/walletconnect-js), instead pull the service from @provenanceio/walletconnect-js/lib/service 4) Don't forget to set up event and loading listeners * Basic non-React.js example with

import { WalletConnectService, WINDOW_MESSAGES } from '@provenanceio/walletconnect-js/lib/service';

      // Pull out the service (includes methods and state)
      const walletConnectService = new WalletConnectService();
      // Function to generate a QR code img element
      const generateQRImgElement = () => {
        // Pull `QRCode` from `WalletConnectService` state and use it as the element `src`
        const QRCodeData = walletConnectService.state.QRCode;
        const QRImage = document.createElement('img');
        QRImage.src = QRCodeData;
        return QRImage;
      };
      // Function to generate a custom button element
      const Button = (content: string, id?: string, onClick?: () => void) => {
        const button = document.createElement('button');
        button.textContent = content;
        button.id = id;
        if (onClick) button.addEventListener('click', onClick);
        return button;
      };
      // Initialize wcjs connection (builds qrCode into state)
      const connect = async () => {
        await walletConnectService.connect();
        // Build QRCode img element
        const QRImageElement = generateQRImgElement();
        // Take this QR element and appendChild to wherever you wanted to render it
        document.body.appendChild(QRImageElement);
        // User can now scan the QR code to connect
      }
      // Manually disconnect from the wc-js session
      const disconnect = async () => { await walletConnectService.disconnect(); };
      // wc-js has returned a connection event, we should have data to use
      const connectionEvent = (result) => {
        const { address, publicKey } = walletConnectService.state;
        document.body.innerHTML = `
          <div>Status: Connected to wallet via ${result.connectionType}</div>
          <div>Address: ${address}</div>
          <div>PublicKey: ${publicKey}</div>
        `;
        document.body.appendChild(Button('Disconnect', 'disconnect', disconnect));
      }
      // Something has caused wc-js to return a disconnect event, we're no longer connected
      const disconnectEvent = (result) => {
        // Clear everything out, re-add the connect button
        document.body.innerHTML = '';
        document.body.appendChild(Button('Connect', 'connect', connect));
      };
      // Listen for specific walletconnect-js events
      const setupEventListeners = () => {
        // Connected
        walletConnectService.addListener(WINDOW_MESSAGES.CONNECTED, connectionEvent)
        // Disconnected
        walletConnectService.addListener(WINDOW_MESSAGES.DISCONNECT, disconnectEvent)
      }
      // Initial function when page/app loads
      const init = () => {
        setupEventListeners();
        document.body.appendChild(Button('Connect', 'connect', connect));
      };
      // Run on app load
      init();

Webpack 5 Issues

If you are on Webpack version 5+ (Note: Create React App 5+ uses Webpack 5+) then you will likely encounter a message like this:

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

To fix this issue, add the following plugins and module rules to your webpack.config.js:

const webpack = require('webpack');
...
module.exports = {
  ...
  plugins: [
    ...
    // Work around for Buffer is undefined:
    // https://github.com/webpack/changelog-v5/issues/10
    new webpack.ProvidePlugin({
      Buffer: ['buffer', 'Buffer'],
    }),
    new webpack.ProvidePlugin({
        process: 'process/browser',
    }),
  ],
  resolve: {
    extensions: ['.js'],
    fallback: {
      crypto: require.resolve('crypto-browserify'),
      buffer: require.resolve("buffer/"),
      util: require.resolve("util/"),
      stream: require.resolve("stream-browserify")
    },
  },
};

If using React Create App, you will need to install a new package called react-app-rewired. After installing, swap your react-scripts start command with react-app-rewired start. Create a new file named config-overrides.js in the root of your project as follows:

const webpack = require("webpack");

module.exports = function override(config) {
  // Pull any existing fallbacks from config, or make a new fallback object
  const fallback = config.resolve.fallback || {};
  // Merge/add new webpack fallbacks
  Object.assign(fallback, {
    crypto: require.resolve("crypto-browserify"),
    buffer: require.resolve("buffer/"),
    stream: require.resolve("stream-browserify"),
    util: require.resolve("util/"),
  });
  // Set new fallback into config
  config.resolve.fallback = fallback;
  // Combine new plugins with any existing plugins
  config.plugins = (config.plugins || []).concat([
    new webpack.ProvidePlugin({
      process: "process/browser",
      Buffer: ["buffer", "Buffer"],
    }),
  ]);
  // Return updated/modified webpack config
  return config;
};

Next, make sure to have the following packages added into your package.json dependencies or devDependencies list:

  "buffer",
  "crypto-browserify",
  "process",
  "stream-browserify",
  "util"

Quickly add these to your dependencies with this command:

npm i --save-dev buffer crypto-browserify process stream-browserify util

For more information/examples, look through the webDemo files and structure which uses these methods.

Automatic localSession copy

Copy window.localStorage values from one site to another (mainly, to localHost)

  1. Run this command in console on the first page you with to copy from
copy(`Object.entries(${JSON.stringify(localStorage)})
.forEach(([k,v])=>localStorage.setItem(k,v))`);
  1. Paste result (clipboard should automatically have been filled) into target page console.
  2. Refresh page, storage values should be synced.

Status

Latest Release Apache 2.0 License LOC

This application is under heavy development. The upcoming public blockchain is the evolution of the private Provenance network blockchain started in 2018. Current development is being supported by Figure Technologies.

Back to top

About

Provenance Blockchain WalletConnect - Build Provenance Blockchain dApps using WalletConnect compliant wallets.

License:Apache License 2.0


Languages

Language:TypeScript 83.1%Language:JavaScript 16.9%