RISE Logo-Light

Reading Contract Data

Query smart contracts with Ethers.js

Learn how to read data from smart contracts on RISE using Ethers.js.

Setup

Create a provider and contract instance:

import { ethers } from 'ethers';

const provider = new ethers.JsonRpcProvider('https://testnet.riselabs.xyz');

const contractAddress = '0x...';
const abi = [ /* contract ABI */ ];

const contract = new ethers.Contract(contractAddress, abi, provider);

Read Contract Data

Call view/pure functions:

// Simple read
const value = await contract.getValue();
console.log('Value:', value.toString());

// Read with arguments
const balance = await contract.balanceOf('0x...');
console.log('Balance:', ethers.formatEther(balance));

ERC-20 Token Example

Read ERC-20 token information:

const tokenAddress = '0x...';

const abi = [
  'function name() view returns (string)',
  'function symbol() view returns (string)',
  'function decimals() view returns (uint8)',
  'function totalSupply() view returns (uint256)',
  'function balanceOf(address) view returns (uint256)'
];

const token = new ethers.Contract(tokenAddress, abi, provider);

// Get token info
const name = await token.name();
const symbol = await token.symbol();
const decimals = await token.decimals();
const totalSupply = await token.totalSupply();

console.log('Token:', name);
console.log('Symbol:', symbol);
console.log('Decimals:', decimals);
console.log('Total Supply:', ethers.formatUnits(totalSupply, decimals));

// Check balance
const userAddress = '0x...';
const balance = await token.balanceOf(userAddress);
console.log('Balance:', ethers.formatUnits(balance, decimals), symbol);

Get Contract Events

Query past events:

// Get Transfer events
const filter = contract.filters.Transfer();
const events = await contract.queryFilter(filter, 0, 'latest');

console.log('Transfer events:', events.length);

events.forEach(event => {
  console.log({
    from: event.args.from,
    to: event.args.to,
    value: ethers.formatEther(event.args.value),
    blockNumber: event.blockNumber,
    transactionHash: event.transactionHash
  });
});

Filter Events by Parameters

// Get transfers TO a specific address
const toFilter = contract.filters.Transfer(null, '0x...');
const toEvents = await contract.queryFilter(toFilter);

// Get transfers FROM a specific address
const fromFilter = contract.filters.Transfer('0x...', null);
const fromEvents = await contract.queryFilter(fromFilter);

// Get specific block range
const recentEvents = await contract.queryFilter(
  contract.filters.Transfer(),
  -1000, // 1000 blocks ago
  'latest'
);

Listen to Events

Subscribe to realtime events:

// Listen to Transfer events
contract.on('Transfer', (from, to, value, event) => {
  console.log('Transfer detected:');
  console.log('From:', from);
  console.log('To:', to);
  console.log('Value:', ethers.formatEther(value));
  console.log('Block:', event.log.blockNumber);
});

// Listen once
contract.once('Transfer', (from, to, value) => {
  console.log('First transfer:', ethers.formatEther(value));
});

// Stop listening
contract.removeAllListeners('Transfer');

Get Block Data

// Get latest block
const blockNumber = await provider.getBlockNumber();
console.log('Latest block:', blockNumber);

// Get block details
const block = await provider.getBlock(blockNumber);
console.log('Block:', {
  number: block.number,
  hash: block.hash,
  timestamp: block.timestamp,
  transactions: block.transactions.length,
  gasUsed: block.gasUsed.toString()
});

// Get block with full transactions
const blockWithTxs = await provider.getBlock(blockNumber, true);
console.log('Transactions:', blockWithTxs.prefetchedTransactions);

Get Transaction Data

const txHash = '0x...';

// Get transaction
const tx = await provider.getTransaction(txHash);
console.log('Transaction:', {
  from: tx.from,
  to: tx.to,
  value: ethers.formatEther(tx.value),
  gasLimit: tx.gasLimit.toString(),
  gasPrice: ethers.formatUnits(tx.gasPrice, 'gwei') + ' Gwei',
  nonce: tx.nonce
});

// Get transaction receipt
const receipt = await provider.getTransactionReceipt(txHash);
console.log('Receipt:', {
  status: receipt.status, // 1 = success, 0 = failed
  blockNumber: receipt.blockNumber,
  gasUsed: receipt.gasUsed.toString(),
  contractAddress: receipt.contractAddress, // if contract deployment
  logs: receipt.logs.length
});

Parse Transaction Logs

Decode logs from a transaction:

const receipt = await provider.getTransactionReceipt(txHash);

// Parse logs with contract interface
const iface = new ethers.Interface(abi);

receipt.logs.forEach(log => {
  try {
    const parsedLog = iface.parseLog(log);
    console.log('Event:', parsedLog.name);
    console.log('Args:', parsedLog.args);
  } catch (e) {
    // Log doesn't match ABI
  }
});

Estimate Gas

Estimate gas for a function call:

const gasEstimate = await contract.transfer.estimateGas('0x...', ethers.parseEther('1'));
console.log('Estimated gas:', gasEstimate.toString());

// With specific transaction parameters
const gasWithParams = await contract.transfer.estimateGas(
  '0x...',
  ethers.parseEther('1'),
  {
    from: wallet.address
  }
);

Static Call (Simulate)

Simulate a transaction without sending it:

// Will revert if the transaction would fail
const result = await contract.transfer.staticCall('0x...', ethers.parseEther('1'));
console.log('Simulation result:', result);

// Useful for functions that return values
const mintResult = await contract.mint.staticCall(1000);
console.log('Would mint:', mintResult.toString(), 'tokens');

Call with Overrides

Override transaction parameters for a call:

const balance = await contract.balanceOf('0x...', {
  blockTag: 1000000 // Query at specific block
});

const historicalBalance = await contract.balanceOf('0x...', {
  blockTag: 'earliest' // Or 'latest', 'pending'
});

Example: Complete Token Info

import { ethers } from 'ethers';

const provider = new ethers.JsonRpcProvider('https://testnet.riselabs.xyz');
const tokenAddress = '0x8a93d247134d91e0de6f96547cb0204e5be8e5d8'; // USDC

const abi = [
  'function name() view returns (string)',
  'function symbol() view returns (string)',
  'function decimals() view returns (uint8)',
  'function totalSupply() view returns (uint256)',
  'function balanceOf(address) view returns (uint256)',
  'event Transfer(address indexed from, address indexed to, uint256 value)'
];

const token = new ethers.Contract(tokenAddress, abi, provider);

async function getTokenInfo() {
  // Get basic info
  const [name, symbol, decimals, totalSupply] = await Promise.all([
    token.name(),
    token.symbol(),
    token.decimals(),
    token.totalSupply()
  ]);

  console.log('Token Information:');
  console.log('Name:', name);
  console.log('Symbol:', symbol);
  console.log('Decimals:', decimals);
  console.log('Total Supply:', ethers.formatUnits(totalSupply, decimals));

  // Get recent transfers
  const transferFilter = token.filters.Transfer();
  const recentTransfers = await token.queryFilter(transferFilter, -1000, 'latest');

  console.log('\nRecent Transfers:', recentTransfers.length);

  // Show last 5 transfers
  recentTransfers.slice(-5).forEach(event => {
    console.log({
      from: event.args.from,
      to: event.args.to,
      value: ethers.formatUnits(event.args.value, decimals),
      block: event.blockNumber
    });
  });
}

getTokenInfo().catch(console.error);

Next Steps