Hello, Events

Read the code for this tutorial here

Overview

In this tutorial we are going to build a simple application that will allow you to connect to Keplr, you will also have to create a viewing key to be able to see your balance, just as we have done in other examples. But now we will use events to detect if you switch accounts, which is very important to know.

Requirements

For this tutorial you will need to have a Vue app created. You can find how to do it here. Also, install your dependencies and install Griptape:

# With npm
npm install && npm install @stakeordie/griptape.js

# With yarn
yarn && yarn add @stakeordie/griptape.js

Getting Started

This tutorial consist of these steps:

  1. Grip your application

  2. Bootstrap the application

  3. Create a contract definition

  4. Build the application

Grip your application

Go to the main.js and import gripApp and getKeplrAccountProvider from @stakeordie/griptape.js package.

main.js
import {
  gripApp,
  getKeplrAccountProvider
} from '@stakeordie/griptape.js';

You can check how to grip your app here

Bootstrap the application

Open up App.vue and add a button to bootstrap the application.

You can check how to grip your app here

Create a contract definition

In order to interact with a contract, you first need to create its definition. First we need to import createContractClient and snip20Def APIs from @stakeordie/griptape.jsto our file src/contracts/sscrt.js Once that is done, we create the definition sscrt to which we are going to assign an id that can be the name you want, we are also going to assign an address of instantiated contract on the blockchain.

Finally, Griptape has SNIP-20 compliant contract definitions, so you don't need to write it yourself.

src/contracts/sscrt.js
import {
  createContractClient,
  snip20Def
} from '@stakeordie/griptape.js';

export const sscrt = createContractClient({
  id: 'sscrt',
  at: 'secret18vd8fpwxzck93qlwghaj6arh4p7c5n8978vsyg',
  definition: snip20Def
});

Learn more about contract definitions here

Build the application

To build this application we must import boostrap, viewingKeyManager, onAccountAvailable, onAccountChange and coinConvert APIs from @stakeordie/griptape.js, in addition to importing the definition of the contract sscrt that we have just created.

src/App.vue
import {
  viewingKeyManager,
  coinConvert,
  bootstrap,
  onAccountAvailable,
  onAccountChange
} from '@stakeordie/griptape.js';
import { sscrt } from './contracts/sscrt';

Now, you may notice that we are using the event onAccountAvailable, where you can call the viewingKeyManager from our contract sscrt to know if we already have a viewing key. If that's the case, the key is assigned to this.viewingKey variable.

src/App.vue
this.removeOnAccountAvailable = onAccountAvailable(async () => {
      this.isConnected = true;
      const key = viewingKeyManager.get(sscrt.at);
      if (key) {
        this.viewingKey = key;
        await this.getBalance();
      }
 });

Now, in order to detect when changing the account, we have the event onAccountChange, then we show an alert that says it has changed the account, and we will assign it the false value to the this.isAccountChanged variable.

src/App.vue
this.removeOnAccountChange = onAccountChange(() => {
      alert("You have changed your account, please refresh this page.");
      this.isAccountChanged = false;
});

Viewing Keys

To create a viewing key, we're going to make an asynchronous request to sscrt.createViewingKey(), if this doesn't return a response, the function ends. If it is the case and if it returns a response then, we parse the result.

Now we send our contract sscrt and our key. We also need to check if a viewing key already exists so we can add it by viewingKeyManager.add() or replace it by viewingKeyManager.set()with the new key.

src/App.vue
 async createViewingKey() {
      this.loading = true;
      try {
        const result = await sscrt.createViewingKey();
        if (result.isEmpty()) return;
        const { create_viewing_key: { key } } = result.parse();
        const currentKey = viewingKeyManager.get(sscrt.at);
        if (currentKey) {
          viewingKeyManager.set(sscrt, key);
        } else {
          viewingKeyManager.add(sscrt, key);
        }
        this.viewingKey = key;
      } catch (e) {
        // ignore for now
      } finally {
        this.loading = false;
      }
    }

Learn more about viewing keys here

After having our viewing key, we want to see our balance. For that reason, we create the function getBalance, within the function, we can see that we make an asynchronous request to obtain the value of our viewing key.

If we do not have a viewing key the function ends, but if this is the case, where we have a viewing key, then we went to consult our amount In sscrt.getBalance(), then we convert our amount with the function coinConvert where ... and finally we assign the value of balance to the variable this.balance.

src/App.vue
async getBalance() {
      const key = viewingKeyManager.get(sscrt.at);
      if (!key) return
      const { balance: { amount } } = await sscrt.getBalance();
      const balance = coinConvert(amount, '6', 'human');
      this.balance = balance;
    }

Finally, joining all our code we have the full application.

<template>
  <div>
     <h1>Hello, Events!</h1>
      <p>Is connected? {{isConnected ? "Yes" : "No"}}</p>
      <button
        @click="connect"
        :disabled="isConnected">
        Bootstrap
      </button>
      <p>Your balance is: {{balance}}</p>
      <button @click="createViewingKey">{{loading ? 'Loading...' : 'Create Viewing Key'}}</button>
      <button :hidden="isAccountChanged" @click="reload">Refresh</button>
  </div>
</template>

<script>
import {
  viewingKeyManager,
  coinConvert,
  bootstrap,
  onAccountAvailable,
  onAccountChange
} from '@stakeordie/griptape.js';
import { sscrt } from './contracts/sscrt';

export default {
  data() {
    return {
      viewingKey: '',
      balance: '',
      loading: false,
      isAccountChanged:true,
      isConnected:false,
      removeOnAccountAvailable: null,
      removeOnAccountChange: null,
    }
  },

  mounted() {
    this.removeOnAccountAvailable = onAccountAvailable(async () => {
      this.isConnected = true;
      const key = viewingKeyManager.get(sscrt.at);
      if (key) {
        this.viewingKey = key;
        await this.getBalance();
      }
    });
    this.removeOnAccountChange = onAccountChange(() => {
      alert("You have changed your account, please refresh this page.");
      this.isAccountChanged = false;
    });
  },
  unmounted(){
    this.removeOnAccountAvailable();
    this.removeOnAccountChange();
  },
  methods: {
    reload(){
      window.location.reload()
    },
    async createViewingKey() {
      this.loading = true;

      try {
        const result = await sscrt.createViewingKey();

        if (result.isEmpty()) return;

        const { create_viewing_key: { key } } = result.parse();
        const currentKey = viewingKeyManager.get(sscrt.at);
        
        if (currentKey) {
          viewingKeyManager.set(sscrt, key);
        } else {
          viewingKeyManager.add(sscrt, key);
        }
        this.viewingKey = key;
      } catch (e) {
        // ignore for now
      } finally {
        this.loading = false;
      }
    },
    async connect() {
      await bootstrap();
    },

    async getBalance() {
      const key = viewingKeyManager.get(sscrt.at);
      
      if (!key) return;

      const { balance: { amount } } = await sscrt.getBalance();
      const balance = coinConvert(amount, '6', 'human');
      this.balance = balance;
    }
  }
}
</script>

Last updated