From d3cd848cc9a1bd633ffec7695f164ca3e1bf6fff Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 2 Oct 2025 16:02:40 +0200 Subject: [PATCH 1/2] Update and improvements to the config-schema reference --- .../Advanced/config-schema-reference.md | 128 ++++++++++-------- docs/HyperRPC/hyperrpc-supported-networks.md | 1 + .../HyperSync/hypersync-supported-networks.md | 1 + scripts/generate-config-schema-doc.js | 118 +++++++++++----- static/schemas/config.evm.json | 34 +++++ supported-networks.json | 2 +- 6 files changed, 186 insertions(+), 98 deletions(-) diff --git a/docs/HyperIndex/Advanced/config-schema-reference.md b/docs/HyperIndex/Advanced/config-schema-reference.md index 0c2564df..5c321c2c 100644 --- a/docs/HyperIndex/Advanced/config-schema-reference.md +++ b/docs/HyperIndex/Advanced/config-schema-reference.md @@ -25,6 +25,8 @@ Static, deep-linkable reference for the `config.yaml` JSON Schema. - [save_full_history](#savefullhistory) - [field_selection](#fieldselection) - [raw_events](#rawevents) +- [preload_handlers](#preloadhandlers) +- [address_format](#addressformat) ### description {#description} @@ -56,10 +58,10 @@ name: MyIndexer Ecosystem of the project. -- **type**: `anyOf(unknown | null)` +- **type**: `anyOf(object | null)` Variants: -- `1`: [EcosystemTag](#ecosystemtag) +- `1`: [EcosystemTag](#def-ecosystemtag) - `2`: `null` @@ -116,9 +118,9 @@ contracts: Configuration of the blockchain networks that the project is deployed on. -- **type**: `array<unknown>` -- **items**: `unknown` -- **items ref**: [Network](#network) +- **type**: `array>` +- **items**: `object` +- **items ref**: [Network](#def-network) Example (config.yaml): @@ -149,10 +151,10 @@ unordered_multichain_mode: true The event decoder to use for the indexer (default: hypersync-client) -- **type**: `anyOf(unknown | null)` +- **type**: `anyOf(object | null)` Variants: -- `1`: [EventDecoder](#eventdecoder) +- `1`: [EventDecoder](#def-eventdecoder) - `2`: `null` @@ -192,10 +194,10 @@ save_full_history: false Select the block and transaction fields to include in all events globally -- **type**: `anyOf(unknown | null)` +- **type**: `anyOf(object | null)` Variants: -- `1`: [FieldSelection](#fieldselection) +- `1`: [FieldSelection](#def-fieldselection) - `2`: `null` @@ -206,7 +208,7 @@ field_selection: transaction_fields: - hash block_fields: - - timestamp + - miner ``` ### raw_events {#rawevents} @@ -222,9 +224,27 @@ Example (config.yaml): raw_events: true ``` +### preload_handlers {#preloadhandlers} + +Makes handlers run twice to enable preload optimisations. Removes handlerWithLoader API, since it's not needed. (recommended, default: false) + +- **type**: `boolean | null` + + +### address_format {#addressformat} + +Address format for Ethereum addresses: 'checksum' or 'lowercase' (default: checksum) + +- **type**: `anyOf(object | null)` + +Variants: +- `1`: [AddressFormat](#def-addressformat) +- `2`: `null` + + ## Definitions -### EcosystemTag {#ecosystemtag} +### EcosystemTag {#def-ecosystemtag} - **type**: `enum (1 values)` - **allowed**: `evm` @@ -235,7 +255,7 @@ Example (config.yaml): ecosystem: evm ``` -### GlobalContract_for_ContractConfig {#globalcontractforcontractconfig} +### GlobalContract_for_ContractConfig {#def-globalcontractforcontractconfig} - **type**: `object` - **required**: `name`, `handler`, `events` @@ -244,7 +264,7 @@ Properties: - `name`: `string` – A unique project-wide name for this contract (no spaces) - `abi_file_path`: `string | null` – Relative path (from config) to a json abi. If this is used then each configured event should simply be referenced by its name - `handler`: `string` – The relative path to a file where handlers are registered for the given contract -- `events`: `array<unknown>` – A list of events that should be indexed on this contract +- `events`: `array>` – A list of events that should be indexed on this contract Example (config.yaml): @@ -256,7 +276,7 @@ contracts: - event: "NewGreeting(address user, string greeting)" ``` -### EventConfig {#eventconfig} +### EventConfig {#def-eventconfig} - **type**: `object` - **required**: `event` @@ -264,7 +284,7 @@ contracts: Properties: - `event`: `string` – The human readable signature of an event 'eg. Transfer(address indexed from, address indexed to, uint256 value)' OR a reference to the name of an event in a json ABI file defined in your contract config. A provided signature will take precedence over what is defined in the json ABI - `name`: `string | null` – Name of the event in the HyperIndex generated code. When ommitted, the event field will be used. Should be unique per contract -- `field_selection`: `anyOf(unknown | null)` – Select the block and transaction fields to include in the specific event +- `field_selection`: `anyOf(object | null)` – Select the block and transaction fields to include in the specific event Example (config.yaml): @@ -280,50 +300,32 @@ contracts: - transactionIndex ``` -### FieldSelection {#fieldselection} +### FieldSelection {#def-fieldselection} - **type**: `object` Properties: - `transaction_fields`: `array | null` – The transaction fields to include in the event, or in all events if applied globally + - Available values: +`transactionIndex`, `hash`, `from`, `to`, `gas`, `gasPrice`, `maxPriorityFeePerGas`, `maxFeePerGas`, `cumulativeGasUsed`, `effectiveGasPrice`, `gasUsed`, `input`, `nonce`, `value`, `v`, `r`, `s`, `contractAddress`, `logsBloom`, `root`, `status`, `yParity`, `chainId`, `accessList`, `maxFeePerBlobGas`, `blobVersionedHashes`, `kind`, `l1Fee`, `l1GasPrice`, `l1GasUsed`, `l1FeeScalar`, `gasUsedForL1`, `authorizationList` - `block_fields`: `array | null` – The block fields to include in the event, or in all events if applied globally + - Available values: +`parentHash`, `nonce`, `sha3Uncles`, `logsBloom`, `transactionsRoot`, `stateRoot`, `receiptsRoot`, `miner`, `difficulty`, `totalDifficulty`, `extraData`, `size`, `gasLimit`, `gasUsed`, `uncles`, `baseFeePerGas`, `blobGasUsed`, `excessBlobGas`, `parentBeaconBlockRoot`, `withdrawalsRoot`, `l1BlockNumber`, `sendCount`, `sendRoot`, `mixHash` -Example (config.yaml): - -```yaml -events: - - event: "Assigned(address indexed user, uint256 amount)" - field_selection: - transaction_fields: - - transactionIndex - block_fields: - - timestamp -``` - -### TransactionField {#transactionfield} - -- **type**: `enum (33 values)` -- **allowed**: `transactionIndex`, `hash`, `from`, `to`, `gas`, `gasPrice`, `maxPriorityFeePerGas`, `maxFeePerGas`, `cumulativeGasUsed`, `effectiveGasPrice`, `gasUsed`, `input`, `nonce`, `value`, `v`, `r`, `s`, `contractAddress`, `logsBloom`, `root`, `status`, `yParity`, `chainId`, `accessList`, `maxFeePerBlobGas`, `blobVersionedHashes`, `kind`, `l1Fee`, `l1GasPrice`, `l1GasUsed`, `l1FeeScalar`, `gasUsedForL1`, `authorizationList` - -### BlockField {#blockfield} - -- **type**: `enum (24 values)` -- **allowed**: `parentHash`, `nonce`, `sha3Uncles`, `logsBloom`, `transactionsRoot`, `stateRoot`, `receiptsRoot`, `miner`, `difficulty`, `totalDifficulty`, `extraData`, `size`, `gasLimit`, `gasUsed`, `uncles`, `baseFeePerGas`, `blobGasUsed`, `excessBlobGas`, `parentBeaconBlockRoot`, `withdrawalsRoot`, `l1BlockNumber`, `sendCount`, `sendRoot`, `mixHash` - -### Network {#network} +### Network {#def-network} - **type**: `object` - **required**: `id`, `start_block`, `contracts` Properties: - `id`: `integer` – The public blockchain network ID. -- `rpc_config`: `anyOf(unknown | null)` – RPC configuration for utilizing as the network's data-source. Typically optional for chains with HyperSync support, which is highly recommended. HyperSync dramatically enhances performance, providing up to a 1000x speed boost over traditional RPC. -- `rpc`: `anyOf(unknown | null)` – RPC configuration for your indexer. If not specified otherwise, for networks supported by HyperSync, RPC serves as a fallback for added reliability. For others, it acts as the primary data-source. HyperSync offers significant performance improvements, up to a 1000x faster than traditional RPC. -- `hypersync_config`: `anyOf(unknown | null)` – Optional HyperSync Config for additional fine-tuning +- `rpc_config`: `anyOf(object | null)` – RPC configuration for utilizing as the network's data-source. Typically optional for chains with HyperSync support, which is highly recommended. HyperSync dramatically enhances performance, providing up to a 1000x speed boost over traditional RPC. +- `rpc`: `anyOf(object | null)` – RPC configuration for your indexer. If not specified otherwise, for networks supported by HyperSync, RPC serves as a fallback for added reliability. For others, it acts as the primary data-source. HyperSync offers significant performance improvements, up to a 1000x faster than traditional RPC. +- `hypersync_config`: `anyOf(object | null)` – Optional HyperSync Config for additional fine-tuning - `confirmed_block_threshold`: `integer | null` – The number of blocks from the head that the indexer should account for in case of reorgs. - `start_block`: `integer` – The block at which the indexer should start ingesting data - `end_block`: `integer | null` – The block at which the indexer should terminate. -- `contracts`: `array<unknown>` – All the contracts that should be indexed on the given network +- `contracts`: `array>` – All the contracts that should be indexed on the given network Example (config.yaml): @@ -337,13 +339,13 @@ networks: address: 0x1111111111111111111111111111111111111111 ``` -### RpcConfig {#rpcconfig} +### RpcConfig {#def-rpcconfig} - **type**: `object` - **required**: `url` Properties: -- `url`: `anyOf(string | array<string>)` – URL of the RPC endpoint. Can be a single URL or an array of URLs. If multiple URLs are provided, the first one will be used as the primary RPC endpoint and the rest will be used as fallbacks. +- `url`: `anyOf(string | array)` – URL of the RPC endpoint. Can be a single URL or an array of URLs. If multiple URLs are provided, the first one will be used as the primary RPC endpoint and the rest will be used as fallbacks. - `initial_block_interval`: `integer | null` – The starting interval in range of blocks per query - `backoff_multiplicative`: `number | null` – After an RPC error, how much to scale back the number of blocks requested at once - `acceleration_additive`: `integer | null` – Without RPC errors or timeouts, how much to increase the number of blocks requested by for the next batch @@ -362,14 +364,14 @@ networks: initial_block_interval: 1000 ``` -### NetworkRpc {#networkrpc} +### NetworkRpc {#def-networkrpc} -- **type**: `anyOf(string | unknown | array<unknown>)` +- **type**: `anyOf(string | object | array>)` Variants: - `1`: `string` -- `2`: [Rpc](#rpc) -- `3`: `array<unknown>` +- `2`: [Rpc](#def-rpc) +- `3`: `array>` Example (config.yaml): @@ -379,14 +381,14 @@ networks: rpc: https://eth.llamarpc.com ``` -### Rpc {#rpc} +### Rpc {#def-rpc} - **type**: `object` - **required**: `url`, `for` Properties: - `url`: `string` – The RPC endpoint URL. -- `for`: `unknown` – Determines if this RPC is for historical sync, real-time chain indexing, or as a fallback. +- `for`: `object` – Determines if this RPC is for historical sync, real-time chain indexing, or as a fallback. - `initial_block_interval`: `integer | null` – The starting interval in range of blocks per query - `backoff_multiplicative`: `number | null` – After an RPC error, how much to scale back the number of blocks requested at once - `acceleration_additive`: `integer | null` – Without RPC errors or timeouts, how much to increase the number of blocks requested by for the next batch @@ -405,7 +407,7 @@ networks: for: sync ``` -### For {#for} +### For {#def-for} - **type**: `oneOf(const sync | const fallback)` @@ -413,7 +415,7 @@ Variants: - `1`: `const sync` - `2`: `const fallback` -### HypersyncConfig {#hypersyncconfig} +### HypersyncConfig {#def-hypersyncconfig} - **type**: `object` - **required**: `url` @@ -430,17 +432,18 @@ networks: url: https://eth.hypersync.xyz ``` -### NetworkContract_for_ContractConfig {#networkcontractforcontractconfig} +### NetworkContract_for_ContractConfig {#def-networkcontractforcontractconfig} - **type**: `object` - **required**: `name` Properties: - `name`: `string` – A unique project-wide name for this contract if events and handler are defined OR a reference to the name of contract defined globally at the top level -- `address`: `unknown` – A single address or a list of addresses to be indexed. This can be left as null in the case where this contracts addresses will be registered dynamically. +- `address`: `object` – A single address or a list of addresses to be indexed. This can be left as null in the case where this contracts addresses will be registered dynamically. +- `start_block`: `integer | null` – The block at which the indexer should start ingesting data for this specific contract. If not specified, uses the network start_block. Can be greater than the network start_block for more specific indexing. - `abi_file_path`: `string | null` – Relative path (from config) to a json abi. If this is used then each configured event should simply be referenced by its name - `handler`: `string` – The relative path to a file where handlers are registered for the given contract -- `events`: `array<unknown>` – A list of events that should be indexed on this contract +- `events`: `array>` – A list of events that should be indexed on this contract Example (config.yaml): @@ -457,13 +460,13 @@ networks: - event: Transfer(address indexed from, address indexed to, uint256 value) ``` -### Addresses {#addresses} +### Addresses {#def-addresses} -- **type**: `anyOf(anyOf(string | integer) | array<anyOf(string | integer)>)` +- **type**: `anyOf(anyOf(string | integer) | array)` Variants: - `1`: `anyOf(string | integer)` -- `2`: `array<anyOf(string | integer)>` +- `2`: `array` Example (config.yaml): @@ -477,7 +480,7 @@ networks: - 0x2222222222222222222222222222222222222222 ``` -### EventDecoder {#eventdecoder} +### EventDecoder {#def-eventdecoder} - **type**: `enum (2 values)` - **allowed**: `viem`, `hypersync-client` @@ -488,3 +491,8 @@ Example (config.yaml): event_decoder: hypersync-client ``` +### AddressFormat {#def-addressformat} + +- **type**: `enum (2 values)` +- **allowed**: `checksum`, `lowercase` + diff --git a/docs/HyperRPC/hyperrpc-supported-networks.md b/docs/HyperRPC/hyperrpc-supported-networks.md index 4539d6ba..e8368c10 100644 --- a/docs/HyperRPC/hyperrpc-supported-networks.md +++ b/docs/HyperRPC/hyperrpc-supported-networks.md @@ -40,6 +40,7 @@ Here is a table of the currently supported networks on HyperRPC and their respec | Bsc Testnet | 97 | https://bsc-testnet.rpc.hypersync.xyz or https://97.rpc.hypersync.xyz | | | Celo | 42220 | https://celo.rpc.hypersync.xyz or https://42220.rpc.hypersync.xyz | | | Chainweb Testnet 20 | 5920 | https://chainweb-testnet-20.rpc.hypersync.xyz or https://5920.rpc.hypersync.xyz | | +| Chainweb Testnet 21 | 5921 | https://chainweb-testnet-21.rpc.hypersync.xyz or https://5921.rpc.hypersync.xyz | | | Chainweb Testnet 22 | 5922 | https://chainweb-testnet-22.rpc.hypersync.xyz or https://5922.rpc.hypersync.xyz | | | Chainweb Testnet 23 | 5923 | https://chainweb-testnet-23.rpc.hypersync.xyz or https://5923.rpc.hypersync.xyz | | | Chainweb Testnet 24 | 5924 | https://chainweb-testnet-24.rpc.hypersync.xyz or https://5924.rpc.hypersync.xyz | | diff --git a/docs/HyperSync/hypersync-supported-networks.md b/docs/HyperSync/hypersync-supported-networks.md index f3337ed4..3f18ab6a 100644 --- a/docs/HyperSync/hypersync-supported-networks.md +++ b/docs/HyperSync/hypersync-supported-networks.md @@ -48,6 +48,7 @@ If you are a network operator or user and would like improved service support or | Bsc Testnet | 97 | https://bsc-testnet.hypersync.xyz or https://97.hypersync.xyz | 🎒 | | | Celo | 42220 | https://celo.hypersync.xyz or https://42220.hypersync.xyz | 🪨 | | | Chainweb Testnet 20 | 5920 | https://chainweb-testnet-20.hypersync.xyz or https://5920.hypersync.xyz | 🪨 | | +| Chainweb Testnet 21 | 5921 | https://chainweb-testnet-21.hypersync.xyz or https://5921.hypersync.xyz | 🪨 | | | Chainweb Testnet 22 | 5922 | https://chainweb-testnet-22.hypersync.xyz or https://5922.hypersync.xyz | 🪨 | | | Chainweb Testnet 23 | 5923 | https://chainweb-testnet-23.hypersync.xyz or https://5923.hypersync.xyz | 🪨 | | | Chainweb Testnet 24 | 5924 | https://chainweb-testnet-24.hypersync.xyz or https://5924.hypersync.xyz | 🪨 | | diff --git a/scripts/generate-config-schema-doc.js b/scripts/generate-config-schema-doc.js index 0331f1bf..2de60e91 100644 --- a/scripts/generate-config-schema-doc.js +++ b/scripts/generate-config-schema-doc.js @@ -37,11 +37,10 @@ const EXAMPLE_SNIPPETS = { event_decoder: "event_decoder: hypersync-client", rollback_on_reorg: "rollback_on_reorg: true", save_full_history: "save_full_history: false", - field_selection: `field_selection:\n transaction_fields:\n - hash\n block_fields:\n - timestamp`, + field_selection: `field_selection:\n transaction_fields:\n - hash\n block_fields:\n - miner`, raw_events: "raw_events: true", }, defs: { - FieldSelection: `events:\n - event: "Assigned(address indexed user, uint256 amount)"\n field_selection:\n transaction_fields:\n - transactionIndex\n block_fields:\n - timestamp`, Network: `networks:\n - id: 1\n start_block: 0\n end_block: 19000000\n contracts:\n - name: Greeter\n address: 0x1111111111111111111111111111111111111111`, RpcConfig: `networks:\n - id: 1\n rpc_config:\n url: https://eth.llamarpc.com\n initial_block_interval: 1000`, Rpc: `networks:\n - id: 1\n rpc:\n - url: https://eth.llamarpc.com\n for: sync`, @@ -57,18 +56,24 @@ const EXAMPLE_SNIPPETS = { }; /** Utility functions **/ -function slugify(text) { - return String(text) +function slugify(text, preserveUnderscores = false) { + let result = String(text) .trim() - .toLowerCase() - .replace(/[^a-z0-9\s-]/g, "") - .replace(/\s+/g, "-") - .replace(/-+/g, "-"); + .toLowerCase(); + + if (preserveUnderscores) { + result = result.replace(/[^a-z0-9\s_-]/g, ""); + } else { + result = result.replace(/[^a-z0-9\s-]/g, ""); + } + + result = result.replace(/\s+/g, "-").replace(/-+/g, "-"); + + return result; } function toInlineCode(value) { - const s = String(value).replace(//g, ">"); - return "`" + s + "`"; + return "`" + String(value) + "`"; } function ensureDirSync(filePath) { @@ -93,9 +98,18 @@ function resolveRef(ref, rootSchema) { return node; } -function describeType(schema) { +function describeType(schema, rootSchema = null) { if (!schema) return "unknown"; + // Handle $ref first + if (schema.$ref && rootSchema) { + const refName = schema.$ref.split("/").slice(-1)[0]; + const resolved = resolveRef(schema.$ref, rootSchema); + if (resolved) { + return `object<${refName}>`; + } + } + if (schema.enum) { return `enum (${schema.enum.length} values)`; } @@ -103,21 +117,21 @@ function describeType(schema) { return `const ${String(schema.const)}`; } if (schema.anyOf) { - const parts = schema.anyOf.map((s) => describeType(s)); + const parts = schema.anyOf.map((s) => describeType(s, rootSchema)); return `anyOf(${parts.join(" | ")})`; } if (schema.oneOf) { - const parts = schema.oneOf.map((s) => describeType(s)); + const parts = schema.oneOf.map((s) => describeType(s, rootSchema)); return `oneOf(${parts.join(" | ")})`; } if (schema.allOf) { - const parts = schema.allOf.map((s) => describeType(s)); + const parts = schema.allOf.map((s) => describeType(s, rootSchema)); return `allOf(${parts.join(" & ")})`; } if (schema.type === "array") { const items = Array.isArray(schema.items) - ? schema.items.map(describeType).join(", ") - : describeType(schema.items); + ? schema.items.map(s => describeType(s, rootSchema)).join(", ") + : describeType(schema.items, rootSchema); return `array<${items}>`; } if (schema.type === "object") { @@ -169,11 +183,11 @@ function renderProperty(name, schema, rootSchema, level = 4) { level === 3 ? `\n### ${name} {#${anchor}}\n` : level === 4 - ? `\n#### ${name} {#${anchor}}\n` - : `\n##### ${name} {#${anchor}}\n`; + ? `\n#### ${name} {#${anchor}}\n` + : `\n##### ${name} {#${anchor}}\n`; let out = heading; if (schema.description) out += `\n${schema.description}\n`; - out += `\n- **type**: ${toInlineCode(describeType(schema))}\n`; + out += `\n- **type**: ${toInlineCode(describeType(schema, rootSchema))}\n`; if (schema.enum) out += `- **allowed**: ${renderEnumValues(schema)}\n`; const nb = renderNumberBounds(schema); if (nb) out += `- **bounds**: ${nb}\n`; @@ -184,19 +198,30 @@ function renderProperty(name, schema, rootSchema, level = 4) { if (target) { // link to defs if available const refName = schema.$ref.split("/").slice(-1)[0]; - out += `- **ref**: [${refName}](#${slugify(refName)})\n`; + out += `- **ref**: [${refName}](#def-${slugify(refName)})\n`; } } // Arrays if (schema.type === "array" && schema.items) { const itemType = Array.isArray(schema.items) - ? schema.items.map(describeType).join(", ") - : describeType(schema.items); + ? schema.items.map(s => describeType(s, rootSchema)).join(", ") + : describeType(schema.items, rootSchema); out += `- **items**: ${toInlineCode(itemType)}\n`; if (!Array.isArray(schema.items) && schema.items.$ref) { const refName = schema.items.$ref.split("/").slice(-1)[0]; - out += `- **items ref**: [${refName}](#${slugify(refName)})\n`; + out += `- **items ref**: [${refName}](#def-${slugify(refName)})\n`; + + // Special handling for TransactionField and BlockField enums + if (refName === "TransactionField" || refName === "BlockField") { + const enumSchema = resolveRef(schema.items.$ref, rootSchema); + if (enumSchema && enumSchema.enum) { + out += `\nAvailable ${refName} values:\n`; + enumSchema.enum.forEach((value, index) => { + out += `${index + 1}. ${toInlineCode(value)}\n`; + }); + } + } } } @@ -211,8 +236,7 @@ function renderProperty(name, schema, rootSchema, level = 4) { propKeys.forEach((propName) => { const prop = props[propName]; out += - `- ${toInlineCode(propName)}: ${toInlineCode(describeType(prop))}${ - prop.description ? ` – ${prop.description}` : "" + `- ${toInlineCode(propName)}: ${toInlineCode(describeType(prop))}${prop.description ? ` – ${prop.description}` : "" }` + "\n"; }); } @@ -223,14 +247,14 @@ function renderProperty(name, schema, rootSchema, level = 4) { const variants = schema.anyOf || schema.oneOf; out += `\nVariants:\n`; variants.forEach((v, i) => { - const label = v.$ref ? v.$ref.split("/").slice(-1)[0] : describeType(v); + const label = v.$ref ? v.$ref.split("/").slice(-1)[0] : describeType(v, rootSchema); if (v.$ref) { - out += `- ${toInlineCode(String(i + 1))}: [${label}](#${slugify( + out += `- ${toInlineCode(String(i + 1))}: [${label}](#def-${slugify( label )})\n`; } else { out += `- ${toInlineCode(String(i + 1))}: ${toInlineCode( - describeType(v) + describeType(v, rootSchema) )}\n`; } }); @@ -282,10 +306,15 @@ function generateMarkdown(schema) { if (defNames.length) { md += h2("Definitions"); defNames.forEach((defName) => { + // Skip separate TransactionField and BlockField sections since they're now shown inline in FieldSelection + if (defName === "TransactionField" || defName === "BlockField") { + return; // Skip these definitions + } + const defSchema = defs[defName]; - md += `\n### ${defName} {#${slugify(defName)}}\n`; + md += `\n### ${defName} {#def-${slugify(defName)}}\n`; if (defSchema.description) md += `\n${defSchema.description}\n`; - md += `\n- **type**: ${toInlineCode(describeType(defSchema))}\n`; + md += `\n- **type**: ${toInlineCode(describeType(defSchema, schema))}\n`; if (defSchema.enum) { md += `- **allowed**: ${renderEnumValues(defSchema)}\n`; } @@ -302,9 +331,24 @@ function generateMarkdown(schema) { dPropNames.forEach((dpName) => { const dp = dProps[dpName]; md += - `- ${toInlineCode(dpName)}: ${toInlineCode(describeType(dp))}${ - dp.description ? ` – ${dp.description}` : "" + `- ${toInlineCode(dpName)}: ${toInlineCode(describeType(dp, schema))}${dp.description ? ` – ${dp.description}` : "" }` + "\n"; + + // Special handling for TransactionField and BlockField arrays within FieldSelection + if (dpName === "transaction_fields" || dpName === "block_fields") { + if (dp.items && dp.items.$ref) { + const refName = dp.items.$ref.split("/").slice(-1)[0]; + if (refName === "TransactionField" || refName === "BlockField") { + const enumSchema = resolveRef(dp.items.$ref, schema); + if (enumSchema && enumSchema.enum) { + const values = enumSchema.enum.map(toInlineCode).join(", "); + md += ` - Available values: +${values} +`; + } + } + } + } }); } } @@ -312,8 +356,8 @@ function generateMarkdown(schema) { // arrays if (defSchema.type === "array" && defSchema.items) { const itemType = Array.isArray(defSchema.items) - ? defSchema.items.map(describeType).join(", ") - : describeType(defSchema.items); + ? defSchema.items.map(s => describeType(s, schema)).join(", ") + : describeType(defSchema.items, schema); md += `- **items**: ${toInlineCode(itemType)}\n`; } @@ -324,14 +368,14 @@ function generateMarkdown(schema) { variants.forEach((v, i) => { const label = v.$ref ? v.$ref.split("/").slice(-1)[0] - : describeType(v); + : describeType(v, schema); if (v.$ref) { - md += `- ${toInlineCode(String(i + 1))}: [${label}](#${slugify( + md += `- ${toInlineCode(String(i + 1))}: [${label}](#def-${slugify( label )})\n`; } else { md += `- ${toInlineCode(String(i + 1))}: ${toInlineCode( - describeType(v) + describeType(v, schema) )}\n`; } }); diff --git a/static/schemas/config.evm.json b/static/schemas/config.evm.json index ed0349cf..1117e8a7 100644 --- a/static/schemas/config.evm.json +++ b/static/schemas/config.evm.json @@ -106,6 +106,24 @@ "boolean", "null" ] + }, + "preload_handlers": { + "description": "Makes handlers run twice to enable preload optimisations. Removes handlerWithLoader API, since it's not needed. (recommended, default: false)", + "type": [ + "boolean", + "null" + ] + }, + "address_format": { + "description": "Address format for Ethereum addresses: 'checksum' or 'lowercase' (default: checksum)", + "anyOf": [ + { + "$ref": "#/$defs/AddressFormat" + }, + { + "type": "null" + } + ] } }, "additionalProperties": false, @@ -576,6 +594,15 @@ "description": "A single address or a list of addresses to be indexed. This can be left as null in the case where this contracts addresses will be registered dynamically.", "$ref": "#/$defs/Addresses" }, + "start_block": { + "description": "The block at which the indexer should start ingesting data for this specific contract. If not specified, uses the network start_block. Can be greater than the network start_block for more specific indexing.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0 + }, "abi_file_path": { "description": "Relative path (from config) to a json abi. If this is used then each configured event should simply be referenced by its name", "type": [ @@ -637,6 +664,13 @@ "viem", "hypersync-client" ] + }, + "AddressFormat": { + "type": "string", + "enum": [ + "checksum", + "lowercase" + ] } } } diff --git a/supported-networks.json b/supported-networks.json index c5c3db80..58831e8e 100644 --- a/supported-networks.json +++ b/supported-networks.json @@ -2,4 +2,4 @@ "supported-networks/any-evm-with-rpc", "supported-networks/local-anvil", "supported-networks/local-hardhat", - "supported-networks/0g-newton-testnet","supported-networks/abstract","supported-networks/aleph-zero-evm","supported-networks/altlayer-op-demo-testnet","supported-networks/ancient8","supported-networks/arbitrum","supported-networks/arbitrum-blueberry","supported-networks/arbitrum-nova","supported-networks/arbitrum-sepolia","supported-networks/artela-testnet","supported-networks/arthera-mainnet","supported-networks/asset-chain-mainnet","supported-networks/astar-zkevm","supported-networks/astar-zkyoto","supported-networks/aurora","supported-networks/aurora-turbo","supported-networks/avalanche","supported-networks/b2-hub-testnet","supported-networks/b3","supported-networks/b3-sepolia-testnet","supported-networks/base","supported-networks/base-sepolia","supported-networks/beam","supported-networks/berachain","supported-networks/berachain-artio-testnet","supported-networks/berachain-bartio","supported-networks/bevm-mainnet","supported-networks/bevm-testnet","supported-networks/bitfinity-mainnet","supported-networks/bitfinity-testnet","supported-networks/bitgert-mainnet","supported-networks/bitlayer","supported-networks/blast","supported-networks/blast-sepolia","supported-networks/bob-mainnet","supported-networks/boba","supported-networks/boba-bnb-mainnet","supported-networks/botanix-testnet","supported-networks/bsc","supported-networks/bsc-testnet","supported-networks/canto","supported-networks/canto-testnet","supported-networks/celo","supported-networks/celo-alfajores-testnet","supported-networks/chainweb-testnet-20","supported-networks/chainweb-testnet-22","supported-networks/chainweb-testnet-23","supported-networks/chainweb-testnet-24","supported-networks/chiliz","supported-networks/chiliz-testnet-spicy","supported-networks/citrea-devnet","supported-networks/citrea-testnet","supported-networks/core","supported-networks/creator-testnet","supported-networks/cronos-zkevm","supported-networks/cronos-zkevm-testnet","supported-networks/crossfi-mainnet","supported-networks/crossfi-mainnet","supported-networks/crossfi-testnet","supported-networks/curtis","supported-networks/cyber","supported-networks/damon","supported-networks/degen-chain","supported-networks/dfk-chain","supported-networks/dogechain-mainnet","supported-networks/dogechain-testnet","supported-networks/dos-chain","supported-networks/energy-web","supported-networks/eos","supported-networks/eth","supported-networks/etherlink-testnet","supported-networks/exosama","supported-networks/fantom","supported-networks/fantom-testnet","supported-networks/flare","supported-networks/flare-songbird","supported-networks/flow","supported-networks/flow-testnet","supported-networks/fraxtal","supported-networks/fuel-mainnet","supported-networks/fuel-testnet","supported-networks/fuji","supported-networks/galadriel-devnet","supported-networks/gnosis","supported-networks/gnosis-chiado","supported-networks/gravity-alpha-mainnet","supported-networks/harmony-shard-0","supported-networks/heco-chain","supported-networks/holesky","supported-networks/hyperliquid","supported-networks/immutable-zkevm","supported-networks/immutable-zkevm-testnet","supported-networks/ink","supported-networks/iotex-network","supported-networks/japan-open-chain","supported-networks/kaia","supported-networks/kakarot-starknet-sepolia","supported-networks/kroma","supported-networks/layeredge-testnet","supported-networks/lightlink-pegasus-testnet","supported-networks/lightlink-phoenix","supported-networks/linea","supported-networks/lisk","supported-networks/lukso","supported-networks/lukso-testnet","supported-networks/manta","supported-networks/manta-pacific-sepolia","supported-networks/mantle","supported-networks/megaeth-testnet","supported-networks/merlin","supported-networks/metall2","supported-networks/meter-mainnet","supported-networks/meter-testnet","supported-networks/mev-commit","supported-networks/mint-mainnet","supported-networks/mode","supported-networks/monad-testnet","supported-networks/moonbase-alpha","supported-networks/moonbeam","supported-networks/morph","supported-networks/nautilus","supported-networks/neo-x-testnet","supported-networks/nibiru-testnet","supported-networks/now-chaint","supported-networks/oasis-emerald","supported-networks/oasis-sapphire","supported-networks/onigiri-subnet","supported-networks/onigiri-test-subnet","supported-networks/ontology-mainnet","supported-networks/ontology-testnet","supported-networks/op-celestia-raspberry","supported-networks/opbnb","supported-networks/optimism","supported-networks/optimism-sepolia","supported-networks/optopia","supported-networks/peaq","supported-networks/plume","supported-networks/polygon","supported-networks/polygon-amoy","supported-networks/polygon-zkevm","supported-networks/polygon-zkevm-cardona-testnet","supported-networks/public-goods-network","supported-networks/pulsechain","supported-networks/puppynet-shibarium","supported-networks/ronin","supported-networks/rootstock","supported-networks/saakuru","supported-networks/satoshivm","supported-networks/scroll","supported-networks/scroll-sepolia","supported-networks/sentient-testnet","supported-networks/sepolia","supported-networks/shibarium","supported-networks/shimmer-evm","supported-networks/skale-europa","supported-networks/soneium","supported-networks/sonic","supported-networks/sophon","supported-networks/sophon-testnet","supported-networks/stratovm-testnet","supported-networks/superseed","supported-networks/superseed-sepolia-testnet","supported-networks/swell","supported-networks/taiko","supported-networks/tangle","supported-networks/tanssi-demo","supported-networks/taraxa","supported-networks/telos-evm-mainnet","supported-networks/telos-evm-testnet","supported-networks/torus-mainnet","supported-networks/torus-testnet","supported-networks/unichain","supported-networks/unichain-sepolia","supported-networks/unicorn-ultra-nebulas-testnet","supported-networks/velas-mainnet","supported-networks/viction","supported-networks/worldchain","supported-networks/x-layer-mainnet","supported-networks/x-layer-testnet","supported-networks/xdc","supported-networks/xdc-testnet","supported-networks/zeta","supported-networks/zeta-testnet","supported-networks/zircuit","supported-networks/zklink-nova-mainnet","supported-networks/zksync","supported-networks/zksync-sepolia-testnet","supported-networks/zora","supported-networks/zora-sepolia"]} \ No newline at end of file + "supported-networks/0g-newton-testnet","supported-networks/abstract","supported-networks/aleph-zero-evm","supported-networks/altlayer-op-demo-testnet","supported-networks/ancient8","supported-networks/arbitrum","supported-networks/arbitrum-blueberry","supported-networks/arbitrum-nova","supported-networks/arbitrum-sepolia","supported-networks/artela-testnet","supported-networks/arthera-mainnet","supported-networks/asset-chain-mainnet","supported-networks/astar-zkevm","supported-networks/astar-zkyoto","supported-networks/aurora","supported-networks/aurora-turbo","supported-networks/avalanche","supported-networks/b2-hub-testnet","supported-networks/b3","supported-networks/b3-sepolia-testnet","supported-networks/base","supported-networks/base-sepolia","supported-networks/beam","supported-networks/berachain","supported-networks/berachain-artio-testnet","supported-networks/berachain-bartio","supported-networks/bevm-mainnet","supported-networks/bevm-testnet","supported-networks/bitfinity-mainnet","supported-networks/bitfinity-testnet","supported-networks/bitgert-mainnet","supported-networks/bitlayer","supported-networks/blast","supported-networks/blast-sepolia","supported-networks/bob-mainnet","supported-networks/boba","supported-networks/boba-bnb-mainnet","supported-networks/botanix-testnet","supported-networks/bsc","supported-networks/bsc-testnet","supported-networks/canto","supported-networks/canto-testnet","supported-networks/celo","supported-networks/celo-alfajores-testnet","supported-networks/chainweb-testnet-20","supported-networks/chainweb-testnet-21","supported-networks/chainweb-testnet-22","supported-networks/chainweb-testnet-23","supported-networks/chainweb-testnet-24","supported-networks/chiliz","supported-networks/chiliz-testnet-spicy","supported-networks/citrea-devnet","supported-networks/citrea-testnet","supported-networks/core","supported-networks/creator-testnet","supported-networks/cronos-zkevm","supported-networks/cronos-zkevm-testnet","supported-networks/crossfi-mainnet","supported-networks/crossfi-mainnet","supported-networks/crossfi-testnet","supported-networks/curtis","supported-networks/cyber","supported-networks/damon","supported-networks/degen-chain","supported-networks/dfk-chain","supported-networks/dogechain-mainnet","supported-networks/dogechain-testnet","supported-networks/dos-chain","supported-networks/energy-web","supported-networks/eos","supported-networks/eth","supported-networks/etherlink-testnet","supported-networks/exosama","supported-networks/fantom","supported-networks/fantom-testnet","supported-networks/flare","supported-networks/flare-songbird","supported-networks/flow","supported-networks/flow-testnet","supported-networks/fraxtal","supported-networks/fuel-mainnet","supported-networks/fuel-testnet","supported-networks/fuji","supported-networks/galadriel-devnet","supported-networks/gnosis","supported-networks/gnosis-chiado","supported-networks/gravity-alpha-mainnet","supported-networks/harmony-shard-0","supported-networks/heco-chain","supported-networks/holesky","supported-networks/hyperliquid","supported-networks/immutable-zkevm","supported-networks/immutable-zkevm-testnet","supported-networks/ink","supported-networks/iotex-network","supported-networks/japan-open-chain","supported-networks/kaia","supported-networks/kakarot-starknet-sepolia","supported-networks/kroma","supported-networks/layeredge-testnet","supported-networks/lightlink-pegasus-testnet","supported-networks/lightlink-phoenix","supported-networks/linea","supported-networks/lisk","supported-networks/lukso","supported-networks/lukso-testnet","supported-networks/manta","supported-networks/manta-pacific-sepolia","supported-networks/mantle","supported-networks/megaeth-testnet","supported-networks/merlin","supported-networks/metall2","supported-networks/meter-mainnet","supported-networks/meter-testnet","supported-networks/mev-commit","supported-networks/mint-mainnet","supported-networks/mode","supported-networks/monad-testnet","supported-networks/moonbase-alpha","supported-networks/moonbeam","supported-networks/morph","supported-networks/nautilus","supported-networks/neo-x-testnet","supported-networks/nibiru-testnet","supported-networks/now-chaint","supported-networks/oasis-emerald","supported-networks/oasis-sapphire","supported-networks/onigiri-subnet","supported-networks/onigiri-test-subnet","supported-networks/ontology-mainnet","supported-networks/ontology-testnet","supported-networks/op-celestia-raspberry","supported-networks/opbnb","supported-networks/optimism","supported-networks/optimism-sepolia","supported-networks/optopia","supported-networks/peaq","supported-networks/plume","supported-networks/polygon","supported-networks/polygon-amoy","supported-networks/polygon-zkevm","supported-networks/polygon-zkevm-cardona-testnet","supported-networks/public-goods-network","supported-networks/pulsechain","supported-networks/puppynet-shibarium","supported-networks/ronin","supported-networks/rootstock","supported-networks/saakuru","supported-networks/satoshivm","supported-networks/scroll","supported-networks/scroll-sepolia","supported-networks/sentient-testnet","supported-networks/sepolia","supported-networks/shibarium","supported-networks/shimmer-evm","supported-networks/skale-europa","supported-networks/soneium","supported-networks/sonic","supported-networks/sophon","supported-networks/sophon-testnet","supported-networks/stratovm-testnet","supported-networks/superseed","supported-networks/superseed-sepolia-testnet","supported-networks/swell","supported-networks/taiko","supported-networks/tangle","supported-networks/tanssi-demo","supported-networks/taraxa","supported-networks/telos-evm-mainnet","supported-networks/telos-evm-testnet","supported-networks/torus-mainnet","supported-networks/torus-testnet","supported-networks/unichain","supported-networks/unichain-sepolia","supported-networks/unicorn-ultra-nebulas-testnet","supported-networks/velas-mainnet","supported-networks/viction","supported-networks/worldchain","supported-networks/x-layer-mainnet","supported-networks/x-layer-testnet","supported-networks/xdc","supported-networks/xdc-testnet","supported-networks/zeta","supported-networks/zeta-testnet","supported-networks/zircuit","supported-networks/zklink-nova-mainnet","supported-networks/zksync","supported-networks/zksync-sepolia-testnet","supported-networks/zora","supported-networks/zora-sepolia"]} \ No newline at end of file From 55557f1a684e36a6275b23d8f8776ef2a2e99b0b Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 2 Oct 2025 16:39:28 +0200 Subject: [PATCH 2/2] Readd the example under 'events' for FieldSelection --- docs/HyperIndex/Advanced/config-schema-reference.md | 13 +++++++++++++ scripts/generate-config-schema-doc.js | 1 + 2 files changed, 14 insertions(+) diff --git a/docs/HyperIndex/Advanced/config-schema-reference.md b/docs/HyperIndex/Advanced/config-schema-reference.md index 5c321c2c..0b148c0d 100644 --- a/docs/HyperIndex/Advanced/config-schema-reference.md +++ b/docs/HyperIndex/Advanced/config-schema-reference.md @@ -312,6 +312,19 @@ Properties: - Available values: `parentHash`, `nonce`, `sha3Uncles`, `logsBloom`, `transactionsRoot`, `stateRoot`, `receiptsRoot`, `miner`, `difficulty`, `totalDifficulty`, `extraData`, `size`, `gasLimit`, `gasUsed`, `uncles`, `baseFeePerGas`, `blobGasUsed`, `excessBlobGas`, `parentBeaconBlockRoot`, `withdrawalsRoot`, `l1BlockNumber`, `sendCount`, `sendRoot`, `mixHash` +Example (config.yaml): + +```yaml +events: + - event: "Assigned(address indexed user, uint256 amount)" + # can be within an event as shown here, or globally for all events + field_selection: + transaction_fields: + - transactionIndex + block_fields: + - miner +``` + ### Network {#def-network} - **type**: `object` diff --git a/scripts/generate-config-schema-doc.js b/scripts/generate-config-schema-doc.js index 2de60e91..74cead00 100644 --- a/scripts/generate-config-schema-doc.js +++ b/scripts/generate-config-schema-doc.js @@ -41,6 +41,7 @@ const EXAMPLE_SNIPPETS = { raw_events: "raw_events: true", }, defs: { + FieldSelection: `# within a contract\nevents:\n - event: "Assigned(address indexed user, uint256 amount)"\n # can be within an event as shown here, or globally for all events\n field_selection:\n transaction_fields:\n - transactionIndex\n block_fields:\n - miner`, Network: `networks:\n - id: 1\n start_block: 0\n end_block: 19000000\n contracts:\n - name: Greeter\n address: 0x1111111111111111111111111111111111111111`, RpcConfig: `networks:\n - id: 1\n rpc_config:\n url: https://eth.llamarpc.com\n initial_block_interval: 1000`, Rpc: `networks:\n - id: 1\n rpc:\n - url: https://eth.llamarpc.com\n for: sync`,