Initial commit
This commit is contained in:
88
skills/hyperindex-development/examples/basic-handler.ts
Normal file
88
skills/hyperindex-development/examples/basic-handler.ts
Normal 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);
|
||||
});
|
||||
193
skills/hyperindex-development/examples/factory-pattern.ts
Normal file
193
skills/hyperindex-development/examples/factory-pattern.ts
Normal 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),
|
||||
});
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user