VeChain Docs
  • Welcome to VeChain
  • Blockchain Basics
    • Introduction to blockchain
    • Introduction to digital property
    • The evolution of the internet
  • Introduction to VeChain
    • About the VeChain blockchain
      • Consensus Deep Dive
      • Governance
    • Dual-Token Economic Model
      • VeChain (VET)
      • VeThor (VTHO)
    • Acquire VeChain Assets
    • Sustainability
  • Core Concepts
    • Networks
      • Thor Solo Node
      • Testnet
      • Mainnet
    • Nodes
      • Node Rewards Programme
    • Blocks
      • Block Model
    • Transactions
      • Transaction Model
      • Transaction Fees
      • Transaction Calculation
      • Meta Transaction Features
        • Transaction Uniqueness
        • Controllable Transaction Lifecycle
        • Clauses (Multi-Task Transaction)
        • Fee Delegation
          • Multi-Party Payment (MPP)
          • Designated Gas Payer (VIP-191)
        • Transaction Dependency
    • Block Explorers
    • Wallets
      • VeWorld
        • User Guide
          • Setup
          • Wallet
          • Signing
          • Activities
          • Settings
        • FAQ
      • Sync2
        • User Guide
          • Setup
          • Wallet
          • Signing
          • Activities
          • Settings
        • FAQ
      • Sync
        • User Guide
          • Wallet
          • Ledger Device
          • Browser dApps and web
          • Interact with dApps
          • Activities
          • Settings
          • Report an Issue
          • Contributing
        • FAQ
    • EVM Compatibility
      • VeChain Modifications
      • Methodology
      • Test Coverage
        • Gas model
        • Raw transaction
        • hardhat specific
          • Ganache failures
          • evm_increaseTime
        • Failures in constructor
        • eth_sign
        • Contract address prediction
        • BadBeacon proxy address at 0x1
      • How to Recreate
      • Additional Information
        • Using Governance Contracts
        • ERC1820/ERC777 Testnet
        • Delegate Options
    • Account Abstraction
      • UserOperation
      • Bundler
      • EntryPoint Contract
      • Account Factory Contract
      • Paymaster Contract
    • Token Bound Accounts
  • How to run a node
    • Nodes
    • How to run a Thor Solo Node
    • Custom Network
    • Connect Sync2 to a Thor Solo Node
  • Developer Resources
    • Getting Started
    • How to build on VeChain
      • Connect to the Network
      • Read Data
        • Read Blocks
        • Read Transactions
        • Read Accounts
        • States & Views
        • Events & Logs
        • VET Transfers
      • Write Data
        • Transactions
        • Fee Delegation
      • Listen to Changes
        • Events
        • VET Transfers
        • Transactions
        • Blocks
        • Beats
      • Build with Hardhat
      • Utilities
        • BigInt and Unit-Handling
        • Name Service Lookups
    • Example dApps
      • Buy me a Coffee
      • Token Bound Accounts
      • PWA with Privy and Account Abstraction
    • EVM Compatibility for Developers
      • Key Architectural Differences and Optimizations
      • Practical Implications for Developers: Key Considerations
      • RPC Methods (Detailed Breakdown)
      • Frequently Asked Questions (FAQs)
      • VeChain Blockchain Specifications
      • Key Differences Between VeChain and Ethereum (Summary)
      • Best Practices for Developing on VeChainThor
    • How to verify Address-Ownership
      • Next.js Session Verification
    • Debug Reverted Transactions
    • Account Abstraction
    • VIP-191: Designated Gas Payer
      • How to Integrate VIP-191 (I)
      • How to Integrate VIP-191 (II)
      • How to Integrate VIP-191 (III)
    • Index with Graph Node
      • Setup with Docker
      • Index with OpenZeppelin
        • Create Subgraph Project
        • Configure Contracts
        • Deploy Subgraph and start Indexing
        • Track Subgraph Indexing
        • Access Subgraph
        • Update Subgraph
    • SDKs & Providers
      • SDK
        • Architecture
        • Accounts
        • Bloom Filter
        • Certificates
        • Contracts
        • Cryptography
        • Debug
        • Encoding
        • Polls
        • Subscriptions
        • Thor Client
        • Transactions
      • Thor DevKit
        • Installation
        • Usage
          • Cryptography
          • Accounts
          • Encoding
          • Transactions
          • Certificates
          • Bloom Filter
      • DApp Kit
        • v2
          • Installation
          • React
            • Installation
            • Usage
          • Vanilla JS
            • Installation
            • Usage
          • Core
            • Installation
            • Usage
          • Theme Variables
          • i18n
        • v1
          • Installation
          • React
            • Installation
            • Usage
          • Vanilla JS
            • Installation
            • Usage
          • Core
            • Installation
            • Usage
          • Theme Variables
          • i18n
          • Node Polyfills
          • V0 to V1
        • v0
          • Installation
          • Usage
          • React
            • Installation
            • Usage
          • Vanilla (UI)
            • Installation
            • Usage
          • Styles (UI)
          • i18n
      • VeChain Kit
      • DevPal
      • Web3-Providers-Connex
        • Installation
        • Usage
      • Connex
        • Installation
        • API Specification
    • Frameworks & IDEs
      • Hardhat
      • Remix
    • Built-in Contracts
    • VORJ
    • Useful Links
  • How to contribute
Powered by GitBook
On this page
  • Example Data
  • contracts.load(address, abi)
  • Create Contract Object
  • contract.filters.<EventName>(output)
  • Get Logs
  • Browse Results
  • Example Project
  • filterEventLogs(): Multiple Events in one Request
  • filterRawEventLogs(criteria)
  • Request Logs
  • Handle Response
  • Example Project

Was this helpful?

  1. Developer Resources
  2. How to build on VeChain
  3. Read Data

Events & Logs

PreviousStates & ViewsNextVET Transfers

Last updated 2 months ago

Was this helpful?

Events are signals that are emitted from smart contracts. Every event is logged, immutable and accessible using a blockchain node only. Smart contracts can not access events themself.

Client-Applications can either listen to events and act accordingly or use logged events to access historical data.

The example uses a public contract and paginates thru the results.

Example Data

This example used below will utilize the VTHO contract, which manages VeChain's VTHO Token.

  • Smart Contract Address: 0x0000000000000000000000000000456e65726779

  • The contract's source code can be found on GitHub at:

  • Its Application Binary Interface (ABI) is shared on b32, a repository that gathers publicly available interfaces for VeChain projects:

contracts.load(address, abi)

A contract instance using address and ABI definition provides instant access to logs.

Create Contract Object

To filter events, just like with any other interaction, a contract object needs to be created. It requies to specify a network first, because in general a contract with a specific address only exists on one network

import { HttpClient, ThorClient } from '@vechain/sdk-network';
import { ErrorDecoder } from 'ethers-decode-error';
import energyAbi from './energy.json' assert { type: 'json' };

const thor = ThorClient.at('https://testnet.vechain.org/'));
const vtho = thor.contracts.load(
  '0x0000000000000000000000000000456e65726779',
  energyAbi
);

The Contract-Loader always requires a JSON ABI Definition.

Fragments are not supported.

contract.filters.<EventName>(output)

The filters provide a simple way to access events in a human-readable way and to populate log requests with the correct criteria. The feature is available for every "event available in the ABI of the contract. In the case of VTHO Transfers and Approvals, emitted every time a user calls transfer and approve respectively.

For example, a filter for all Transfers can be created using:

const allTransfers = vtho.filters.Transfer()
const filteredTransfers = vtho.filters.Transfer(<from>, <to>)

Another example filters for all transfers to a specific address:

const filteredTransfers = vtho.filters.Transfer(null, <to>)

_to is the second output of the ABI. Unwanted filters needs to be skipped by passing null. There's a third one for the Transfer event, which is _value.

To filter all transfers of a specific value use:

const filteredTransfers = vtho.filters.Transfer(null, null, <value>)

Get Logs

To receive the logs from the blockchain, the built filter object provides a .get() function. Calling it will return the list of matching events.

const allTransfers = vtho.filters.Transfer()
const result = await allTransfers.get()

For pagination, there are three optional parameters that allow filtering for a specific range, paginating, and ordering the result set. All options are optional:

.get(
 { unit?: 'block' | 'time', from?: number, to?: number },
 { offset?: number, limit?: number },
 'asc' | 'desc'
)

Browse Results

.get() returns a list of results because it can support multiple requests as well.

The data is available in both raw and decoded forms:

const transfers = vtho.filters

  // pass filters in the order of the input definition for the event
  // skip values by passing null or undefined
  .Transfer(null, '0x0000000000000000000000000000456e65726779');

const results = await transfers.get(null, { limit: 2})

results.forEach(result => {
    result.forEach(log => {
        // raw log data
        console.log(log)

        // access to decoded data
        console.log("Transfer", log.decodedData._from, log.decodedData._to, log.decodedData._value)
    })
})

Example Project

filterEventLogs(): Multiple Events in one Request

With filterEventLogs(), logs for multiple events can be requested in a single request, improving network performance and simplifying interaction.

For example, requesting VTHO Transfers from and to an address in one request:

const results = await thor.logs.filterEventLogs({
  criteriaSet: [
    ...vtho.filters.Transfer(ZERO_ADDRESS).criteriaSet, // FROM Zero
    ...vtho.filters.Transfer(null, ZERO_ADDRESS).criteriaSet, // TO Zero
  ],
  range: {
    unit: 'block',
    from: 1_000_000,
    to: 20_000_000,
  },
});

results.forEach((result) => {
  result.forEach((log) => {
    console.log(
      'Transfer',
      log.decodedData._from,
      log.decodedData._to,
      log.decodedData._value
    );
  });
});

filterRawEventLogs(criteria)

Request Logs

Due to the potentially large amount of log entries, it is essential to implement filtering and pagination mechanisms for efficient data access.

To access and retrieve logs, the logs.filterRawEventLogs function allows filtering based on a specified range and enables pagination by utilizing offset and limits.

Illustrated in the following example is the process of retrieving transfer events for VTHO tokens. Initially, the event that requires filtering must be encoded into a byte format.

import { ABIEvent } from '@vechain/sdk-core';

const event = new ABIEvent(
  'event Transfer(address indexed from, address indexed to, uint256 amount)'
);
const encodedTopics = event.encodeFilterTopics([])

indexed variables can be filtered directly in the filter request, providing fast access to a subset of information. The list argument on the encoding can provide them.

Our example will filter for the second variable to:

const encodedTopics = event.encodeFilterTopics([
  // first indexed value is "from", set to null to not use it
  null,

  // second indexed value is "to"
  '0x0000000000000000000000000000456e65726779',
]);

With the encoded version logs.filterRawEventLogs can be called to return all matching logs:

const filteredLogs = await thor.logs.filterRawEventLogs({
  criteriaSet: [
    // filter by address and topics, empty topics are ignored
    {
      address: '0x0000000000000000000000000000456e65726779',
      topic0: encodedTopics[0],
      topic1: encodedTopics[1],
      topic2: encodedTopics[2],
      topic3: encodedTopics[3],
      topic4: encodedTopics[4],
    },
  ]
});

For pagination options ({ offset?: number, limit?: number }) and order ('asc' | 'desc') can be passed as additional parameter. Additionally the logs can be restricted to a certain block range by defining a range ({ unit?: 'block' | 'time', from?: number, to?: number }).

Handle Response

The response needs to be decoded using the event definition to gain access to all information. event.decodeEventLog(log) can be used on a selected event or in our example on all returned logs:

const decodedLogs = filteredLogs.map(log => event.decodeEventLog(log))

Each decoded log will have an attribute for each event variable, like decodedLog.from and can alternatively be accessed as list in the order of the event parameter definition (decodedLog[0] equals from).

Example Project

You can find the full documentation in the description of the .

The types of the results are fully documented in the

https://github.com/vechain/thor/blob/f58c17ae50f1ec8698d9daf6e05076d17dcafeaf/builtin/gen/energy.sol
https://gitabihub.com/vechain/b32/blob/master/ABIs/energy.json
Filter Event Logs Options
Event Logs Interface.