Skip to content

A MetaMask snap that displays how many times you have interacted with an address.

License

Apache-2.0, MIT-0 licenses found

Licenses found

Apache-2.0
LICENSE.APACHE2
MIT-0
LICENSE.MIT0
Notifications You must be signed in to change notification settings

Montoya/insights-counter

Repository files navigation

Insights Snap

Tutorial

Steps to code this yourself:

1. Go to the snap manifest packages/snap/snap.manifest.json and change the permissions to the following:

  "initialPermissions": {
    "snap_manageState": {}, 
    "endowment:transaction-insight": {}
  },

2. Go to the snap source code packages/snap/src/index.ts and replace it with this:

import { OnTransactionHandler } from '@metamask/snaps-types';
import { text } from '@metamask/snaps-ui';
import { hasProperty, isObject } from '@metamask/utils';

/**
 * Handle an incoming transaction, and return any insights.
 *
 * @param args - The request handler args as object.
 * @param args.transaction - The transaction object.
 * @returns The transaction insights.
 */
export const onTransaction: OnTransactionHandler = async ({ transaction }) => {
  if (
    !isObject(transaction) ||
    !hasProperty(transaction, 'to') ||
    typeof transaction.to !== 'string'
  ) {
    console.warn('Unknown transaction type.');
    return { content: text('Unknown transaction') };
  }

  return { content: text('**Test:** Successful') };
};

This will handle a typical transaction and show a generic message in the transaction insights interface.

Run yarn && yarn start to build the snap, launch the local server, and install it.

You can then try going to a generic contract on mainnet and interact with it to see the transaction insights displayed: Simple Storage.

3. Modify the snap source code return to get and display the address you are interacting with:

  return { content: text('**You are interacting with:** ' + transaction.to) };

Go back to the dapp, reconnect the snap to install the latest version, and go back to the contract to interact with it. This time you will see the address of the contract.

4. Use manageState to store a counter for each address you interact with:

  let state = (await snap.request({
    method: 'snap_manageState',
    params: { operation: 'get' },
  })) as { addresses: {} } || null; 

  if (!state) { // if no data this is likely null 
    state = { addresses: {} };
    // initialize state if empty and set default data
    await snap.request({
      method: 'snap_manageState',
      params: { operation: 'update', newState: state },
    });
  }

  let interactions = state.addresses['address:'+transaction.to] || 0; 

  interactions++; 

  let returnText = 'You have interacted with this address '+interactions+' times.'; 
  if(interactions < 2) { 
    returnText = 'This is the **first time** you are interacting with this address.'; 
  }

  state.addresses['address:'+transaction.to] = interactions; 

  snap.request({
    method: 'snap_manageState',
    params: { operation: 'update', newState: state },
  });

Add the panel type to the types you request from snaps-ui:

import { panel, text } from '@metamask/snaps-ui';

And modify the return value to display the number of times the user has interacted with this address:

  return { content: panel([
    text('**You are interacting with:** ' + transaction.to),
    text(returnText)
  ]) };

The final source code of the snap is:

import { OnTransactionHandler } from '@metamask/snaps-types';
import { panel, text } from '@metamask/snaps-ui';
import { hasProperty, isObject } from '@metamask/utils';

/**
 * Handle an incoming transaction, and return any insights.
 *
 * @param args - The request handler args as object.
 * @param args.transaction - The transaction object.
 * @returns The transaction insights.
 */
export const onTransaction: OnTransactionHandler = async ({ transaction }) => {
  if (
    !isObject(transaction) ||
    !hasProperty(transaction, 'to') ||
    typeof transaction.to !== 'string'
  ) {
    console.warn('Unknown transaction type.');
    return { content: text('Unknown transaction') };
  }

  let state = (await snap.request({
    method: 'snap_manageState',
    params: { operation: 'get' },
  })) as { addresses: {} } || null; 

  if (!state) { // if no data this is likely null 
    state = { addresses: {} };
    // initialize state if empty and set default data
    await snap.request({
      method: 'snap_manageState',
      params: { operation: 'update', newState: state },
    });
  }

  let interactions = state.addresses['address:'+transaction.to] || 0; 

  interactions++; 

  let returnText = 'You have interacted with this address '+interactions+' times.'; 
  if(interactions < 2) { 
    returnText = 'This is the **first time** you are interacting with this address.'; 
  }

  state.addresses['address:'+transaction.to] = interactions; 

  await snap.request({
    method: 'snap_manageState',
    params: { operation: 'update', newState: state },
  });

  return { content: panel([
    text('**You are interacting with:** ' + transaction.to),
    text(returnText)
  ]) };
};

Only ~50 lines of code!

Reconnect the snap to install the latest version, then try interacting with a contract multiple times to see the count go up. You can try interacting with different addresses and you will that the result matches how many times you interact with each one!

Caveats

  1. This snap only runs when the user views the transaction insights tab for this snap. So it is really a count of that. If the user interacts with an address without viewing the tab, then that is never counted.
  2. The transaction insights tab is loaded more than once when viewed, so the counter will fire multiple times, giving innacurate counts. To mitigate this, I have added a timestamp checker to only update the count if at least 4 seconds have passed since the last update. The source code in this repository has this feature.

About

A MetaMask snap that displays how many times you have interacted with an address.

Topics

Resources

License

Apache-2.0, MIT-0 licenses found

Licenses found

Apache-2.0
LICENSE.APACHE2
MIT-0
LICENSE.MIT0

Stars

Watchers

Forks