Skip to content
LogoLogo

Watch Token Roles

token.watchRole

Watches TIP-20 RoleMembershipUpdated events for a token. The event is emitted when a role is granted to, or revoked from, an account. Learn more about roles

Usage

import {  } from './viem.config'
 
const  = ..({
  : '0x20c0000000000000000000000000000000000000',
})
 
.(() => {
  for (const  of ) .(.)
{  role: '0x114e74f6ea3bd819998f78687bfcb11b140da08e9b7d222fa9c1f1ba1f2aa122',  account: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',  sender: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',  hasRole: true}
})
 
// Later, tear down the watcher.
.()

Also callable standalone: Actions.token.watchRole(client, options), with Actions imported from 'viem/tempo'.

Recipes

Alert on Unexpected issuer Grants

Filter args.role with TokenRole.serialize and page an operator when the issuer role is granted to an account outside your allowlist.

import {  } from 'viem/tempo'
import {  } from './viem.config'
 
// Accounts authorized to hold the issuer role.
const  = new <string>([
  '0x8ba1f109551bD432803012645Ac136ddd64DBA72',
])
 
const  = ..({
  : { : .('issuer') },
  : '0x20c0000000000000000000000000000000000000',
})
 
.(() => {
  for (const  of ) {
    if (!.. || .(..)) continue
    .('Unexpected grant:', .., 'by', ..)
Unexpected grant: 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 by 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
  }
})

Pause Issuance When Your Service Loses the issuer Role

Filter args.account and args.role together to react when your own service account's issuer access is revoked, halting mint jobs before they fail onchain.

import {  } from 'viem/tempo'
import {  } from './viem.config'
 
const  = ..({
  : {
    : ..,
    : .('issuer'),
  },
  : '0x20c0000000000000000000000000000000000000',
})
 
.(() => {
  for (const  of ) {
    // Halt issuance jobs until access is restored.
    if (!..) .('Issuer role revoked by', ..)
  }
})

Return Value

Returns a watcher handle. Watching starts when the first listener (or async iterator) attaches, and stops when off is called.

type ReturnType = {
  /** Registers a log listener. Starts the watcher on first registration. Returns an unregister function. */
  onLogs: (fn: (logs: readonly Log[]) => void) => () => void
  /** Registers an error listener. Returns an unregister function. */
  onError: (fn: (error: Error) => void) => () => void
  /** Tears down the watcher: removes listeners, ends iterators, stops the poll or subscription. */
  off: () => void
  /** Async-iterates emitted log batches (latest-only stream). */
  [Symbol.asyncIterator]: () => AsyncIterableIterator<{ logs: readonly Log[] }>
}

Each log is decoded, with the event arguments on args:

type Log = {
  /** Decoded `RoleMembershipUpdated` event arguments. */
  args: {
    /** Role that was updated (bytes32 role hash). */
    role: Hex
    /** Account whose membership changed. */
    account: Address
    /** Address that performed the update. */
    sender: Address
    /** Whether the account now holds the role. */
    hasRole: boolean
  }
  /** Name of the emitted event. */
  eventName: 'RoleMembershipUpdated'
  // ...standard log fields (address, blockHash, blockNumber, logIndex, transactionHash, ...)
}

Role values are bytes32 role hashes. Compare them against a named role (defaultAdmin, pause, unpause, issuer, burnBlocked) with TokenRole.serialize from viem/tempo.

Parameters

args

  • Type: object
type Args = {
  /** Filter by role (bytes32 role hash). */
  role?: Hex | Hex[] | null
  /** Filter by account. */
  account?: Address | Address[] | null
  /** Filter by sender. */
  sender?: Address | Address[] | null
}

Indexed argument values to filter logs by. Derive a role hash from a named role with TokenRole.serialize from viem/tempo, for example TokenRole.serialize('issuer').

batch

  • Type: boolean
  • Default: true

Whether to batch the logs found within a poll interval into a single emission. When false, each log is emitted on its own.

fromBlock

  • Type: bigint

Block number from which to start watching for logs.

poll

  • Type: boolean

Whether to poll for new logs instead of using a subscription. Defaults to true when the transport cannot subscribe or fromBlock is provided.

pollingInterval

  • Type: number
  • Default: client.pollingInterval

Polling frequency (in ms).

token

  • Type: Address | bigint

Token to operate on: a TIP-20 token id or a contract address.