본문으로 건너뛰기

Events & Logs

Monolythium emits events at two layers: Cosmos ABCI events (from SDK modules) and EVM logs (from smart contracts). Both are queryable and subscribable in real time.


Cosmos ABCI Events

Every Cosmos SDK transaction emits structured events as key-value attribute pairs. Modules emit events for state changes like transfers, delegations, and governance actions.

Event Structure

Event {
type: "transfer"
attributes: [
{ key: "sender", value: "mono1abc..." },
{ key: "recipient", value: "mono1def..." },
{ key: "amount", value: "1000000000000000000alyth" }
]
}

Query Events via CLI

# Find all transfer events sent by a specific address
monod query txs --events 'transfer.sender=mono1abc...' --chain-id mono_6940-1

# Find delegation events
monod query txs --events 'delegate.validator=monovaloper1xyz...'

# Combine multiple event filters (AND logic)
monod query txs \
--events 'message.module=bank&transfer.recipient=mono1def...'

# Query a specific transaction
monod query tx <txhash> --output json

Query Events via REST

curl "https://api.testnet.mononodes.xyz/cosmos/tx/v1beta1/txs?events=transfer.sender='mono1abc...'" \
| jq '.tx_responses[].events'

Common Cosmos Event Types

ModuleEvent TypeKey Attributes
banktransfersender, recipient, amount
stakingdelegatedelegator, validator, amount
stakingunbonddelegator, validator, amount, completion_time
stakingredelegatedelegator, source_validator, destination_validator
govproposal_votevoter, proposal_id, option
govsubmit_proposalproposal_id, proposal_type
distributionwithdraw_rewardsdelegator, validator, amount
x/burnfee_burnamount, burned, proposer_reward
x/validatorregister_validatorvalidator, burn_amount, self_delegation

EVM Logs

Smart contracts emit logs (events in Solidity) that are stored in transaction receipts. Each log has an address, indexed topics, and a data payload.

Log Structure

Log {
address: "0xContractAddress..."
topics: [
"0xddf252ad...", // topic[0]: event signature hash
"0x000...sender", // topic[1]: indexed param (from)
"0x000...recip" // topic[2]: indexed param (to)
]
data: "0x0000...amount" // non-indexed params (ABI-encoded)
}

Topic 0 is always the keccak256 hash of the event signature:

Transfer(address,address,uint256)
→ 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef

Query Logs via eth_getLogs

curl -X POST https://evm.testnet.mononodes.xyz \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_getLogs",
"params": [{
"fromBlock": "0x1",
"toBlock": "latest",
"address": "0xContractAddress...",
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
]
}],
"id": 1
}'

Filter Parameters

ParameterDescription
fromBlockStart block (hex or "earliest", "latest")
toBlockEnd block (hex or "latest")
addressContract address or array of addresses
topicsArray of topic filters (positional, null for wildcard)
{
"topics": [
"0xddf252ad...",
null,
"0x000...recipient"
]
}

This matches Transfer events to a specific recipient, from any sender.


Subscribing to Events

EVM WebSocket (eth_subscribe)

import { ethers } from "ethers";

const provider = new ethers.WebSocketProvider(
"wss://evm.testnet.mononodes.xyz"
);

// Subscribe to all new blocks
provider.on("block", (blockNumber) => {
console.log("New block:", blockNumber);
});

// Subscribe to ERC-20 Transfer events on a specific contract
const transferTopic = ethers.id("Transfer(address,address,uint256)");
const filter = {
address: "0xTokenContract...",
topics: [transferTopic],
};

provider.on(filter, (log) => {
const parsed = contractInterface.parseLog(log);
console.log(
`Transfer: ${parsed.args.from}${parsed.args.to}, ${ethers.formatEther(parsed.args.value)} tokens`
);
});

CometBFT WebSocket (/subscribe)

import WebSocket from "ws";

const ws = new WebSocket("wss://rpc.testnet.mononodes.xyz/websocket");

ws.on("open", () => {
// Subscribe to transfer events
ws.send(JSON.stringify({
jsonrpc: "2.0",
method: "subscribe",
id: 1,
params: {
query: "transfer.sender='mono1abc...'"
}
}));

// Subscribe to new blocks
ws.send(JSON.stringify({
jsonrpc: "2.0",
method: "subscribe",
id: 2,
params: {
query: "tm.event='NewBlock'"
}
}));
});

ws.on("message", (data) => {
const msg = JSON.parse(data.toString());
if (msg.result?.events) {
console.log("Events:", msg.result.events);
}
});

Parsing Examples

Parse EVM Logs with ethers.js

import { ethers } from "ethers";

const erc20Abi = [
"event Transfer(address indexed from, address indexed to, uint256 value)",
"event Approval(address indexed owner, address indexed spender, uint256 value)",
];

const iface = new ethers.Interface(erc20Abi);
const provider = new ethers.JsonRpcProvider("https://evm.testnet.mononodes.xyz");

// Get logs for a block range
const logs = await provider.getLogs({
address: "0xTokenContract...",
fromBlock: 100000,
toBlock: 100100,
topics: [ethers.id("Transfer(address,address,uint256)")],
});

for (const log of logs) {
const parsed = iface.parseLog(log);
if (parsed) {
console.log({
event: parsed.name,
from: parsed.args.from,
to: parsed.args.to,
value: ethers.formatEther(parsed.args.value),
block: log.blockNumber,
txHash: log.transactionHash,
});
}
}

Parse Cosmos Events with CosmJS

import { StargateClient } from "@cosmjs/stargate";

const client = await StargateClient.connect("https://rpc.testnet.mononodes.xyz");

// Get a specific transaction
const tx = await client.getTx("TXHASH...");
if (tx) {
// tx.events is an array of { type, attributes[] }
for (const event of tx.events) {
if (event.type === "transfer") {
const sender = event.attributes.find(a => a.key === "sender")?.value;
const recipient = event.attributes.find(a => a.key === "recipient")?.value;
const amount = event.attributes.find(a => a.key === "amount")?.value;
console.log(`Transfer: ${sender}${recipient}: ${amount}`);
}
}
}

// Search transactions by event
const txs = await client.searchTx("transfer.sender='mono1abc...'");
for (const tx of txs) {
console.log(`Tx ${tx.hash}: height ${tx.height}`);
}

Event Indexing Tips

  • Block range limits: eth_getLogs has a block range cap (typically 1,000-10,000 blocks). Paginate large queries.
  • Indexed parameters: Only indexed Solidity event parameters appear in topics. Non-indexed parameters are ABI-encoded in data.
  • Cosmos event encoding: Attribute values are strings. Numeric values need parsing.
  • WebSocket reconnection: Always implement reconnection logic for production subscriptions. WebSocket connections may drop.
Rate Limits

Public RPC endpoints enforce rate limits on eth_getLogs and event subscription queries. For heavy indexing workloads, run your own node.