Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:26:05 +08:00
commit 8bcde7080b
26 changed files with 5957 additions and 0 deletions

View File

@@ -0,0 +1,88 @@
/**
* Basic HyperIndex Event Handler Example
*
* This example demonstrates the fundamental patterns for handling
* blockchain events with HyperIndex.
*/
import { MyContract } from "generated";
// Simple event handler - creates a new entity for each event
MyContract.Transfer.handler(async ({ event, context }) => {
// Create unique ID using chainId, transaction hash, and log index
const id = `${event.chainId}-${event.transaction.hash}-${event.logIndex}`;
// Create the entity object with all required fields
const transfer = {
id,
from: event.params.from,
to: event.params.to,
amount: event.params.amount,
token_id: event.srcAddress, // Relationship to Token entity
blockNumber: BigInt(event.block.number),
blockTimestamp: BigInt(event.block.timestamp),
transactionHash: event.transaction.hash,
};
// Save the entity
context.Transfer.set(transfer);
});
// Handler that updates existing entities
MyContract.Approval.handler(async ({ event, context }) => {
// Load existing token entity
const tokenId = `${event.chainId}-${event.srcAddress}`;
const token = await context.Token.get(tokenId);
if (token) {
// Update entity using spread operator (entities are immutable)
const updatedToken = {
...token,
lastApprovalTime: BigInt(event.block.timestamp),
approvalCount: token.approvalCount + BigInt(1),
};
context.Token.set(updatedToken);
}
// Create approval record
const approval = {
id: `${event.chainId}-${event.transaction.hash}-${event.logIndex}`,
owner: event.params.owner,
spender: event.params.spender,
amount: event.params.value,
token_id: tokenId,
blockTimestamp: BigInt(event.block.timestamp),
};
context.Approval.set(approval);
});
// Get-or-create pattern for entities that may not exist
MyContract.Mint.handler(async ({ event, context }) => {
const tokenId = `${event.chainId}-${event.srcAddress}`;
// Try to load existing token
let token = await context.Token.get(tokenId);
if (!token) {
// Create new token with default values
token = {
id: tokenId,
address: event.srcAddress,
name: "Unknown",
symbol: "???",
decimals: BigInt(18),
totalSupply: BigInt(0),
transferCount: BigInt(0),
};
}
// Update with new values
const updatedToken = {
...token,
totalSupply: token.totalSupply + event.params.amount,
};
context.Token.set(updatedToken);
});

View File

@@ -0,0 +1,193 @@
/**
* Factory Pattern Example for HyperIndex
*
* This example demonstrates how to handle dynamically created contracts
* using the factory pattern (e.g., Uniswap pairs, token deployments).
*
* In config.yaml, the dynamic contract should have NO address field:
*
* contracts:
* - name: Factory
* address: 0xFactoryAddress
* handler: src/factory.ts
* events:
* - event: PairCreated(address indexed token0, address indexed token1, address pair)
*
* - name: Pair
* handler: src/pair.ts
* events:
* - event: Swap(...)
* - event: Mint(...)
* - event: Burn(...)
* # No address field - registered dynamically
*/
import { Factory, Pair } from "generated";
// Step 1: Register the dynamic contract BEFORE the handler
// This tells HyperIndex to start indexing events from this new contract
Factory.PairCreated.contractRegister(({ event, context }) => {
// The method name is `add{ContractName}` based on your config.yaml contract name
context.addPair(event.params.pair);
});
// Step 2: Handle the factory event (runs after contractRegister)
Factory.PairCreated.handler(async ({ event, context }) => {
// Create token entities if they don't exist
const token0Id = `${event.chainId}-${event.params.token0}`;
const token1Id = `${event.chainId}-${event.params.token1}`;
let token0 = await context.Token.get(token0Id);
if (!token0) {
token0 = {
id: token0Id,
address: event.params.token0,
name: "Unknown",
symbol: "???",
decimals: BigInt(18),
};
context.Token.set(token0);
}
let token1 = await context.Token.get(token1Id);
if (!token1) {
token1 = {
id: token1Id,
address: event.params.token1,
name: "Unknown",
symbol: "???",
decimals: BigInt(18),
};
context.Token.set(token1);
}
// Create the pair entity
const pairId = `${event.chainId}-${event.params.pair}`;
const pair = {
id: pairId,
address: event.params.pair,
token0_id: token0Id,
token1_id: token1Id,
reserve0: BigInt(0),
reserve1: BigInt(0),
totalSupply: BigInt(0),
txCount: BigInt(0),
createdAtTimestamp: BigInt(event.block.timestamp),
createdAtBlockNumber: BigInt(event.block.number),
};
context.Pair.set(pair);
// Update factory stats
const factoryId = `${event.chainId}-factory`;
let factory = await context.Factory.get(factoryId);
if (!factory) {
factory = {
id: factoryId,
pairCount: BigInt(0),
totalVolumeUSD: BigInt(0),
};
}
context.Factory.set({
...factory,
pairCount: factory.pairCount + BigInt(1),
});
});
// Step 3: Handle events from dynamically registered contracts
Pair.Swap.handler(async ({ event, context }) => {
const pairId = `${event.chainId}-${event.srcAddress}`;
const pair = await context.Pair.get(pairId);
if (!pair) {
// This shouldn't happen if contractRegister worked correctly
console.error(`Pair not found: ${pairId}`);
return;
}
// Create swap entity
const swap = {
id: `${event.chainId}-${event.transaction.hash}-${event.logIndex}`,
pair_id: pairId,
sender: event.params.sender,
to: event.params.to,
amount0In: event.params.amount0In,
amount1In: event.params.amount1In,
amount0Out: event.params.amount0Out,
amount1Out: event.params.amount1Out,
blockNumber: BigInt(event.block.number),
blockTimestamp: BigInt(event.block.timestamp),
};
context.Swap.set(swap);
// Update pair stats
context.Pair.set({
...pair,
txCount: pair.txCount + BigInt(1),
});
});
Pair.Sync.handler(async ({ event, context }) => {
const pairId = `${event.chainId}-${event.srcAddress}`;
const pair = await context.Pair.get(pairId);
if (pair) {
context.Pair.set({
...pair,
reserve0: event.params.reserve0,
reserve1: event.params.reserve1,
});
}
});
Pair.Mint.handler(async ({ event, context }) => {
const pairId = `${event.chainId}-${event.srcAddress}`;
const pair = await context.Pair.get(pairId);
if (pair) {
const mint = {
id: `${event.chainId}-${event.transaction.hash}-${event.logIndex}`,
pair_id: pairId,
sender: event.params.sender,
amount0: event.params.amount0,
amount1: event.params.amount1,
blockNumber: BigInt(event.block.number),
blockTimestamp: BigInt(event.block.timestamp),
};
context.Mint.set(mint);
context.Pair.set({
...pair,
txCount: pair.txCount + BigInt(1),
});
}
});
Pair.Burn.handler(async ({ event, context }) => {
const pairId = `${event.chainId}-${event.srcAddress}`;
const pair = await context.Pair.get(pairId);
if (pair) {
const burn = {
id: `${event.chainId}-${event.transaction.hash}-${event.logIndex}`,
pair_id: pairId,
sender: event.params.sender,
to: event.params.to,
amount0: event.params.amount0,
amount1: event.params.amount1,
blockNumber: BigInt(event.block.number),
blockTimestamp: BigInt(event.block.timestamp),
};
context.Burn.set(burn);
context.Pair.set({
...pair,
txCount: pair.txCount + BigInt(1),
});
}
});