UNPKG

envio

Version:

A latency and sync speed optimized, developer friendly blockchain data indexer.

1,023 lines (977 loc) 38.3 kB
// Generated by ReScript, PLEASE EDIT WITH CARE import * as Env from "./Env.res.mjs"; import * as Evm from "./sources/Evm.res.mjs"; import * as Svm from "./sources/Svm.res.mjs"; import * as Core from "./Core.res.mjs"; import * as Fuel from "./sources/Fuel.res.mjs"; import * as Table from "./db/Table.res.mjs"; import * as Utils from "./Utils.res.mjs"; import * as Address from "./Address.res.mjs"; import * as ChainMap from "./ChainMap.res.mjs"; import * as Internal from "./Internal.res.mjs"; import * as BigDecimal from "./bindings/BigDecimal.res.mjs"; import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js"; import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js"; import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js"; import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js"; import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js"; import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs"; import * as EventConfigBuilder from "./EventConfigBuilder.res.mjs"; import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js"; let name = "envio_addresses"; function makeId(chainId, address) { return chainId.toString() + "-" + address; } function getAddress(entity) { let sepIdx = entity.id.indexOf("-"); return entity.id.slice(sepIdx + 1 | 0, entity.id.length); } let schema = S$RescriptSchema.schema(s => ({ id: s.m(S$RescriptSchema.string), chain_id: s.m(S$RescriptSchema.int), registration_block: s.m(S$RescriptSchema.int), registration_log_index: s.m(S$RescriptSchema.int), contract_name: s.m(S$RescriptSchema.string) })); let table = Table.mkTable(name, undefined, [ Table.mkField("id", "String", S$RescriptSchema.string, undefined, undefined, undefined, true, undefined, undefined, undefined, undefined, undefined), Table.mkField("chain_id", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined), Table.mkField("registration_block", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined), Table.mkField("registration_log_index", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined), Table.mkField("contract_name", "String", S$RescriptSchema.string, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined) ], undefined); let entityConfig_storage = { postgres: true, clickhouse: false }; let entityConfig = { name: name, index: -1, schema: schema, table: table, storage: entityConfig_storage }; let EnvioAddresses = { name: name, index: -1, makeId: makeId, getAddress: getAddress, schema: schema, table: table, entityConfig: entityConfig }; let rpcSourceForSchema = S$RescriptSchema.$$enum([ "sync", "fallback", "realtime" ]); let rpcConfigSchema = S$RescriptSchema.schema(s => ({ url: s.m(S$RescriptSchema.string), for: s.m(rpcSourceForSchema), ws: s.m(S$RescriptSchema.option(S$RescriptSchema.string)), initialBlockInterval: s.m(S$RescriptSchema.option(S$RescriptSchema.int)), backoffMultiplicative: s.m(S$RescriptSchema.option(S$RescriptSchema.float)), accelerationAdditive: s.m(S$RescriptSchema.option(S$RescriptSchema.int)), intervalCeiling: s.m(S$RescriptSchema.option(S$RescriptSchema.int)), backoffMillis: s.m(S$RescriptSchema.option(S$RescriptSchema.int)), fallbackStallTimeout: s.m(S$RescriptSchema.option(S$RescriptSchema.int)), queryTimeoutMillis: s.m(S$RescriptSchema.option(S$RescriptSchema.int)), pollingInterval: s.m(S$RescriptSchema.option(S$RescriptSchema.int)) })); let chainContractSchema = S$RescriptSchema.schema(s => ({ addresses: s.m(S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.string))), startBlock: s.m(S$RescriptSchema.option(S$RescriptSchema.int)) })); let publicConfigChainSchema = S$RescriptSchema.schema(s => ({ id: s.m(S$RescriptSchema.int), startBlock: s.m(S$RescriptSchema.int), endBlock: s.m(S$RescriptSchema.option(S$RescriptSchema.int)), maxReorgDepth: s.m(S$RescriptSchema.option(S$RescriptSchema.int)), blockLag: s.m(S$RescriptSchema.option(S$RescriptSchema.int)), hypersync: s.m(S$RescriptSchema.option(S$RescriptSchema.string)), rpcs: s.m(S$RescriptSchema.option(S$RescriptSchema.array(rpcConfigSchema))), rpc: s.m(S$RescriptSchema.option(S$RescriptSchema.string)), contracts: s.m(S$RescriptSchema.option(S$RescriptSchema.dict(chainContractSchema))) })); let svmEventDescriptorSchema = S$RescriptSchema.schema(s => ({ discriminator: s.m(S$RescriptSchema.option(S$RescriptSchema.string)), discriminatorByteLen: s.m(S$RescriptSchema.int), includeTransaction: s.m(S$RescriptSchema.bool), includeLogs: s.m(S$RescriptSchema.bool), includeTokenBalances: s.m(S$RescriptSchema.bool), accountFilters: s.m(S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.schema(s => ({ position: s.m(S$RescriptSchema.int), values: s.m(S$RescriptSchema.array(S$RescriptSchema.string)) }))))), isInner: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)), accounts: s.m(S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.string))), args: s.m(S$RescriptSchema.option(S$RescriptSchema.json(false))) })); let svmAbiSchema = S$RescriptSchema.schema(s => ({ programId: s.m(S$RescriptSchema.string), definedTypes: s.m(S$RescriptSchema.json(false)), source: s.m(S$RescriptSchema.string) })); let contractEventItemSchema = S$RescriptSchema.schema(s => ({ name: s.m(S$RescriptSchema.string), sighash: s.m(S$RescriptSchema.string), params: s.m(S$RescriptSchema.option(S$RescriptSchema.array(EventConfigBuilder.paramMetaSchema))), kind: s.m(S$RescriptSchema.option(S$RescriptSchema.string)), blockFields: s.m(S$RescriptSchema.option(S$RescriptSchema.array(Internal.evmBlockFieldSchema))), transactionFields: s.m(S$RescriptSchema.option(S$RescriptSchema.array(Internal.evmTransactionFieldSchema))), svm: s.m(S$RescriptSchema.option(svmEventDescriptorSchema)) })); let contractConfigSchema = S$RescriptSchema.schema(s => ({ abi: s.m(S$RescriptSchema.json(false)), handler: s.m(S$RescriptSchema.option(S$RescriptSchema.string)), events: s.m(S$RescriptSchema.option(S$RescriptSchema.array(contractEventItemSchema))), svmAbi: s.m(S$RescriptSchema.option(svmAbiSchema)) })); let publicConfigEcosystemSchema = S$RescriptSchema.schema(s => ({ chains: s.m(S$RescriptSchema.dict(publicConfigChainSchema)), contracts: s.m(S$RescriptSchema.option(S$RescriptSchema.dict(contractConfigSchema))), programs: s.m(S$RescriptSchema.option(S$RescriptSchema.dict(contractConfigSchema))) })); let publicConfigEvmSchema = S$RescriptSchema.schema(s => ({ chains: s.m(S$RescriptSchema.dict(publicConfigChainSchema)), contracts: s.m(S$RescriptSchema.option(S$RescriptSchema.dict(contractConfigSchema))), addressFormat: s.m(S$RescriptSchema.option(S$RescriptSchema.$$enum([ "lowercase", "checksum" ]))), globalBlockFields: s.m(S$RescriptSchema.option(S$RescriptSchema.array(Internal.evmBlockFieldSchema))), globalTransactionFields: s.m(S$RescriptSchema.option(S$RescriptSchema.array(Internal.evmTransactionFieldSchema))) })); let compositeIndexFieldSchema = S$RescriptSchema.schema(s => ({ fieldName: s.m(S$RescriptSchema.string), direction: s.m(S$RescriptSchema.string) })); let derivedFieldSchema = S$RescriptSchema.schema(s => ({ fieldName: s.m(S$RescriptSchema.string), derivedFromEntity: s.m(S$RescriptSchema.string), derivedFromField: s.m(S$RescriptSchema.string), description: s.m(S$RescriptSchema.option(S$RescriptSchema.string)) })); let propertySchema = S$RescriptSchema.schema(s => ({ name: s.m(S$RescriptSchema.string), postgresDbName: s.m(S$RescriptSchema.option(S$RescriptSchema.string)), clickhouseDbName: s.m(S$RescriptSchema.option(S$RescriptSchema.string)), type: s.m(S$RescriptSchema.string), isNullable: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)), isArray: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)), isIndex: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)), linkedEntity: s.m(S$RescriptSchema.option(S$RescriptSchema.string)), enum: s.m(S$RescriptSchema.option(S$RescriptSchema.string)), entity: s.m(S$RescriptSchema.option(S$RescriptSchema.string)), precision: s.m(S$RescriptSchema.option(S$RescriptSchema.int)), scale: s.m(S$RescriptSchema.option(S$RescriptSchema.int)), description: s.m(S$RescriptSchema.option(S$RescriptSchema.string)) })); let entityStorageSchema = S$RescriptSchema.schema(s => ({ postgres: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)), clickhouse: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)) })); let entityJsonSchema = S$RescriptSchema.schema(s => ({ name: s.m(S$RescriptSchema.string), storage: s.m(S$RescriptSchema.option(entityStorageSchema)), properties: s.m(S$RescriptSchema.array(propertySchema)), derivedFields: s.m(S$RescriptSchema.option(S$RescriptSchema.array(derivedFieldSchema))), compositeIndices: s.m(S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.array(compositeIndexFieldSchema)))), description: s.m(S$RescriptSchema.option(S$RescriptSchema.string)) })); function getFieldTypeAndSchema(prop, enumConfigsByName) { let typ = prop.type; let isNullable = Stdlib_Option.getOr(prop.isNullable, false); let isArray = Stdlib_Option.getOr(prop.isArray, false); let isIndex = Stdlib_Option.getOr(prop.isIndex, false); let match; switch (typ) { case "bigdecimal" : match = [ { type: "BigDecimal", config: Stdlib_Option.map(prop.precision, p => [ p, Stdlib_Option.getOr(prop.scale, 0) ]) }, BigDecimal.schema ]; break; case "bigint" : match = [ { type: "BigInt", precision: prop.precision }, Utils.$$BigInt.schema ]; break; case "boolean" : match = [ "Boolean", S$RescriptSchema.bool ]; break; case "date" : match = [ "Date", Utils.Schema.dbDate ]; break; case "entity" : let entityName = Stdlib_Option.getOrThrow(prop.entity, undefined); match = [ { type: "Entity", name: entityName }, S$RescriptSchema.string ]; break; case "enum" : let enumName = Stdlib_Option.getOrThrow(prop.enum, undefined); let enumConfig = Stdlib_Option.getOrThrow(enumConfigsByName[enumName], undefined); match = [ { type: "Enum", config: enumConfig }, enumConfig.schema ]; break; case "float" : match = [ "Number", S$RescriptSchema.float ]; break; case "int" : match = [ "Int32", S$RescriptSchema.int ]; break; case "json" : match = [ "Json", S$RescriptSchema.json(false) ]; break; case "serial" : match = [ "Serial", S$RescriptSchema.int ]; break; case "string" : match = [ "String", S$RescriptSchema.string ]; break; default: match = Stdlib_JsError.throwWithMessage("Unknown field type in entity config: " + typ); } let baseSchema = match[1]; let fieldSchema = isArray ? S$RescriptSchema.array(baseSchema) : baseSchema; let fieldSchema$1 = isNullable ? S$RescriptSchema.$$null(fieldSchema) : fieldSchema; return [ match[0], fieldSchema$1, isNullable, isArray, isIndex ]; } function parseEnumsFromJson(enumsJson) { return Object.entries(enumsJson).map(param => Table.makeEnumConfig(param[0], param[1])); } function parseEntitiesFromJson(entitiesJson, enumConfigsByName, globalStorage) { return entitiesJson.map((entityJson, index) => { let entityName = entityJson.name; let fields = entityJson.properties.map(prop => { let match = getFieldTypeAndSchema(prop, enumConfigsByName); return Table.mkField(prop.name, match[0], match[1], undefined, match[3], match[2], prop.name === "id", match[4], prop.linkedEntity, prop.description, prop.postgresDbName, prop.clickhouseDbName); }); let derivedFields = Stdlib_Option.getOr(entityJson.derivedFields, []).map(df => Table.mkDerivedFromField(df.fieldName, df.derivedFromEntity, df.derivedFromField, df.description)); let compositeIndices = Stdlib_Option.getOr(entityJson.compositeIndices, []).map(ci => ci.map(f => ({ fieldName: f.fieldName, direction: f.direction === "Asc" ? "Asc" : "Desc" }))); let table = Table.mkTable(entityName, compositeIndices, fields.concat(derivedFields), entityJson.description); let getApiFieldName = prop => { let match = prop.linkedEntity; if (match !== undefined) { return prop.name + "_id"; } else { return prop.name; } }; let schema = S$RescriptSchema.schema(s => { let dict = {}; entityJson.properties.forEach(prop => { let match = getFieldTypeAndSchema(prop, enumConfigsByName); dict[getApiFieldName(prop)] = s.m(match[1]); }); return dict; }); let s = entityJson.storage; let storage; if (s !== undefined) { let s$1 = Primitive_option.valFromOption(s); storage = { postgres: Stdlib_Option.getOr(s$1.postgres, false), clickhouse: Stdlib_Option.getOr(s$1.clickhouse, false) }; } else { storage = { postgres: globalStorage.postgres, clickhouse: globalStorage.clickhouse }; } return { name: entityName, index: index, schema: schema, table: table, storage: storage }; }); } let publicConfigStorageSchema = S$RescriptSchema.schema(s => ({ postgres: s.m(S$RescriptSchema.bool), clickhouse: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)) })); let publicConfigSchema = S$RescriptSchema.schema(s => ({ name: s.m(S$RescriptSchema.string), description: s.m(S$RescriptSchema.option(S$RescriptSchema.string)), handlers: s.m(S$RescriptSchema.option(S$RescriptSchema.string)), isDev: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)), fullBatchSize: s.m(S$RescriptSchema.option(S$RescriptSchema.int)), rollbackOnReorg: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)), saveFullHistory: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)), rawEvents: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)), storage: s.m(publicConfigStorageSchema), evm: s.m(S$RescriptSchema.option(publicConfigEvmSchema)), fuel: s.m(S$RescriptSchema.option(publicConfigEcosystemSchema)), svm: s.m(S$RescriptSchema.option(publicConfigEcosystemSchema)), enums: s.m(S$RescriptSchema.option(S$RescriptSchema.dict(S$RescriptSchema.array(S$RescriptSchema.string)))), entities: s.m(S$RescriptSchema.option(S$RescriptSchema.array(entityJsonSchema))) })); function fromPublic(publicConfigJson) { let publicConfig; try { publicConfig = S$RescriptSchema.parseOrThrow(publicConfigJson, publicConfigSchema); } catch (raw_exn) { let exn = Primitive_exceptions.internalToException(raw_exn); if (exn.RE_EXN_ID === S$RescriptSchema.Raised) { publicConfig = Stdlib_JsError.throwWithMessage(`Invalid indexer config: ` + Utils.prettifyExn(exn._1)); } else { throw exn; } } let match = publicConfig.evm; let match$1 = publicConfig.fuel; let match$2 = publicConfig.svm; let match$3 = match !== undefined ? ( match$1 !== undefined || match$2 !== undefined ? Stdlib_JsError.throwWithMessage("Invalid indexer config: Multiple ecosystems are not supported for a single indexer") : [ Primitive_option.valFromOption(match).chains, "evm" ] ) : ( match$1 !== undefined ? ( match$2 !== undefined ? Stdlib_JsError.throwWithMessage("Invalid indexer config: Multiple ecosystems are not supported for a single indexer") : [ Primitive_option.valFromOption(match$1).chains, "fuel" ] ) : ( match$2 !== undefined ? [ Primitive_option.valFromOption(match$2).chains, "svm" ] : Stdlib_JsError.throwWithMessage("Invalid indexer config: No ecosystem configured (evm, fuel, or svm)") ) ); let ecosystemName = match$3[1]; let publicChainsConfig = match$3[0]; let ecosystem; switch (ecosystemName) { case "evm" : ecosystem = Evm.ecosystem; break; case "fuel" : ecosystem = Fuel.ecosystem; break; case "svm" : ecosystem = Svm.ecosystem; break; } let evm = publicConfig.evm; let lowercaseAddresses = evm !== undefined ? Stdlib_Option.getOr(Primitive_option.valFromOption(evm).addressFormat, "checksum") === "lowercase" : false; let match$4 = publicConfig.evm; let match$5 = publicConfig.fuel; let match$6 = publicConfig.svm; let publicContractsConfig; switch (ecosystemName) { case "evm" : publicContractsConfig = match$4 !== undefined ? Primitive_option.valFromOption(match$4).contracts : undefined; break; case "fuel" : publicContractsConfig = match$5 !== undefined ? Primitive_option.valFromOption(match$5).contracts : undefined; break; case "svm" : publicContractsConfig = match$6 !== undefined ? Primitive_option.valFromOption(match$6).programs : undefined; break; } let evm$1 = publicConfig.evm; let match$7; if (evm$1 !== undefined) { let evm$2 = Primitive_option.valFromOption(evm$1); match$7 = [ new Set(EventConfigBuilder.alwaysIncludedBlockFields.concat(Stdlib_Option.getOr(evm$2.globalBlockFields, []))), new Set(Stdlib_Option.getOr(evm$2.globalTransactionFields, [])) ]; } else { match$7 = [ new Set(EventConfigBuilder.alwaysIncludedBlockFields), new Set() ]; } let globalTransactionFieldsSet = match$7[1]; let globalBlockFieldsSet = match$7[0]; let contractDataByName = {}; if (publicContractsConfig !== undefined) { Object.entries(publicContractsConfig).forEach(param => { let contractConfig = param[1]; let capitalizedName = Utils.$$String.capitalize(param[0]); let abi = contractConfig.abi; let events = contractConfig.events; let eventSignatures = events !== undefined ? events.map(eventItem => eventItem.sighash) : []; contractDataByName[capitalizedName] = { abi: abi, eventSignatures: eventSignatures, events: contractConfig.events, svmAbi: contractConfig.svmAbi }; }); } let buildContractEvents = (contractName, events, abi, chainId, startBlock, addresses, svmDefinedTypesOpt) => { let svmDefinedTypes = svmDefinedTypesOpt !== undefined ? svmDefinedTypesOpt : null; if (events !== undefined) { return events.map(eventItem => { let eventName = eventItem.name; let sighash = eventItem.sighash; let params = Stdlib_Option.getOr(eventItem.params, []); let kind = eventItem.kind; switch (ecosystemName) { case "evm" : return EventConfigBuilder.buildEvmEventConfig(contractName, eventName, sighash, params, false, undefined, undefined, undefined, chainId, ecosystem.onEventBlockFilterSchema, eventItem.blockFields, eventItem.transactionFields, startBlock, Primitive_option.some(globalBlockFieldsSet), Primitive_option.some(globalTransactionFieldsSet)); case "fuel" : if (kind !== undefined) { return EventConfigBuilder.buildFuelEventConfig(contractName, eventName, kind, sighash, abi, false, undefined, undefined, startBlock); } else { return Stdlib_JsError.throwWithMessage(`Fuel event ` + contractName + `.` + eventName + ` is missing "kind" in internal config`); } case "svm" : let len = addresses.length; let programId = len !== 1 ? ( len !== 0 ? Stdlib_JsError.throwWithMessage(`SVM program ` + contractName + ` on chain ` + chainId.toString() + ` has multiple addresses; a program is uniquely identified by a single program_id`) : Stdlib_JsError.throwWithMessage(`SVM program ` + contractName + ` on chain ` + chainId.toString() + ` is missing a program_id`) ) : addresses[0]; let s = eventItem.svm; let svm = s !== undefined ? Primitive_option.valFromOption(s) : Stdlib_JsError.throwWithMessage(`SVM instruction ` + contractName + `.` + eventName + ` is missing the "svm" descriptor in internal config`); let accountFilters = Stdlib_Option.getOr(svm.accountFilters, []).map(group => group.map(af => ({ position: af.position, values: af.values }))); return EventConfigBuilder.buildSvmInstructionEventConfig(contractName, eventName, programId, svm.discriminator, svm.discriminatorByteLen, svm.includeTransaction, svm.includeLogs, svm.includeTokenBalances, accountFilters, svm.isInner, false, undefined, undefined, Stdlib_Option.getOr(svm.accounts, []), Stdlib_Option.getOr(svm.args, null), svmDefinedTypes, startBlock); } }); } else { return []; } }; let parseAddress = addressString => { switch (ecosystemName) { case "evm" : if (lowercaseAddresses) { return Address.Evm.fromStringLowercaseOrThrow(addressString); } else { return Address.Evm.fromStringOrThrow(addressString); } case "fuel" : case "svm" : return addressString; } }; let parseRpcSourceFor = sourceFor => { switch (sourceFor) { case "sync" : return "Sync"; case "fallback" : return "Fallback"; case "realtime" : return "Realtime"; } }; let chains = Object.keys(publicChainsConfig).map(chainName => { let publicChainConfig = publicChainsConfig[chainName]; let chainId = publicChainConfig.id; let chainContracts = Stdlib_Option.getOr(publicChainConfig.contracts, {}); let contracts = Object.entries(contractDataByName).map(param => { let contractData = param[1]; let capitalizedName = param[0]; let chainContract = chainContracts[capitalizedName]; let rawAddresses = Stdlib_Option.getOr(Stdlib_Option.flatMap(chainContract, cc => cc.addresses), []); let addresses = rawAddresses.map(parseAddress); let startBlock = Stdlib_Option.flatMap(chainContract, cc => cc.startBlock); let events = buildContractEvents(capitalizedName, contractData.events, contractData.abi, chainId, startBlock, rawAddresses, Stdlib_Option.getOr(Stdlib_Option.map(contractData.svmAbi, a => a.definedTypes), null)); return { name: capitalizedName, abi: contractData.abi, addresses: addresses, events: events, startBlock: startBlock }; }); let contractNameByAddress = {}; contracts.forEach(contract => { contract.addresses.forEach(address => { let existingContractName = contractNameByAddress[address]; if (existingContractName !== undefined) { return Stdlib_JsError.throwWithMessage(existingContractName === contract.name ? `Address ` + address + ` is listed multiple times for the contract ` + contract.name + ` on chain ` + chainId.toString() + `. Please remove the duplicate from your config.` : `Address ` + address + ` on chain ` + chainId.toString() + ` is configured for multiple contracts: ` + existingContractName + ` and ` + contract.name + `. Indexing the same address with multiple contract definitions is not supported. Please define the events on a single contract definition instead.`); } else { contractNameByAddress[address] = contract.name; return; } }); }); let sourceConfig; switch (ecosystemName) { case "evm" : let rpcs = Stdlib_Option.getOr(publicChainConfig.rpcs, []).map(rpcConfig => { let initialBlockInterval = rpcConfig.initialBlockInterval; let backoffMultiplicative = rpcConfig.backoffMultiplicative; let accelerationAdditive = rpcConfig.accelerationAdditive; let intervalCeiling = rpcConfig.intervalCeiling; let backoffMillis = rpcConfig.backoffMillis; let queryTimeoutMillis = rpcConfig.queryTimeoutMillis; let fallbackStallTimeout = rpcConfig.fallbackStallTimeout; let pollingInterval = rpcConfig.pollingInterval; let hasSyncConfig = Stdlib_Option.isSome(initialBlockInterval) || Stdlib_Option.isSome(backoffMultiplicative) || Stdlib_Option.isSome(accelerationAdditive) || Stdlib_Option.isSome(intervalCeiling) || Stdlib_Option.isSome(backoffMillis) || Stdlib_Option.isSome(queryTimeoutMillis) || Stdlib_Option.isSome(fallbackStallTimeout) || Stdlib_Option.isSome(pollingInterval); let syncConfig = hasSyncConfig ? ({ initialBlockInterval: initialBlockInterval, backoffMultiplicative: backoffMultiplicative, accelerationAdditive: accelerationAdditive, intervalCeiling: intervalCeiling, backoffMillis: backoffMillis, queryTimeoutMillis: queryTimeoutMillis, fallbackStallTimeout: fallbackStallTimeout, pollingInterval: pollingInterval }) : undefined; return { url: rpcConfig.url, sourceFor: parseRpcSourceFor(rpcConfig.for), syncConfig: syncConfig, ws: rpcConfig.ws }; }); sourceConfig = { TAG: "EvmSourceConfig", hypersync: publicChainConfig.hypersync, rpcs: rpcs }; break; case "fuel" : let hypersync = publicChainConfig.hypersync; sourceConfig = hypersync !== undefined ? ({ TAG: "FuelSourceConfig", hypersync: hypersync }) : Stdlib_JsError.throwWithMessage(`Chain ` + chainName + ` is missing hypersync endpoint in config`); break; case "svm" : let hypersync$1 = publicChainConfig.hypersync; let rpc = publicChainConfig.rpc; if (Stdlib_Option.isNone(hypersync$1) && Stdlib_Option.isNone(rpc)) { Stdlib_JsError.throwWithMessage(`Chain ` + chainName + ` is missing a data source: provide either an rpc endpoint or an experimental hypersync config`); } sourceConfig = { TAG: "SvmSourceConfig", hypersync: hypersync$1, rpc: rpc }; break; } let tmp; switch (ecosystemName) { case "evm" : tmp = Stdlib_Option.getOr(publicChainConfig.maxReorgDepth, 200); break; case "fuel" : case "svm" : tmp = 0; break; } return { name: chainName, id: chainId, startBlock: publicChainConfig.startBlock, endBlock: publicChainConfig.endBlock, maxReorgDepth: tmp, blockLag: Stdlib_Option.getOr(publicChainConfig.blockLag, 0), contracts: contracts, sourceConfig: sourceConfig }; }); let chainMap = ChainMap.fromArrayUnsafe(chains.map(chain => [ ChainMap.Chain.makeUnsafe(chain.id), chain ])); let allEnums = parseEnumsFromJson(Stdlib_Option.getOr(publicConfig.enums, {})); let enumConfigsByName = Object.fromEntries(allEnums.map(enumConfig => [ enumConfig.name, enumConfig ])); let globalStorage_postgres = publicConfig.storage.postgres; let globalStorage_clickhouse = Stdlib_Option.getOr(publicConfig.storage.clickhouse, false); let globalStorage = { postgres: globalStorage_postgres, clickhouse: globalStorage_clickhouse }; let userEntities = parseEntitiesFromJson(Stdlib_Option.getOr(publicConfig.entities, []), enumConfigsByName, globalStorage); let allEntities = userEntities.concat([entityConfig]); let userEntitiesByName = Object.fromEntries(userEntities.map(entityConfig => [ entityConfig.name, entityConfig ])); let contractHandlers = publicContractsConfig !== undefined ? Object.entries(publicContractsConfig).map(param => ({ name: Utils.$$String.capitalize(param[0]), handler: param[1].handler })) : []; return { name: publicConfig.name, description: publicConfig.description, handlers: Stdlib_Option.getOr(publicConfig.handlers, "src/handlers"), contractHandlers: contractHandlers, shouldRollbackOnReorg: Stdlib_Option.getOr(publicConfig.rollbackOnReorg, true), shouldSaveFullHistory: Stdlib_Option.getOr(publicConfig.saveFullHistory, false), storage: globalStorage, chainMap: chainMap, defaultChain: chains[0], ecosystem: ecosystem, enableRawEvents: Stdlib_Option.getOr(publicConfig.rawEvents, false), maxAddrInPartition: Env.maxAddrInPartition, batchSize: Stdlib_Option.getOr(publicConfig.fullBatchSize, 5000), lowercaseAddresses: lowercaseAddresses, isDev: Stdlib_Option.getOr(publicConfig.isDev, false), userEntitiesByName: userEntitiesByName, userEntities: userEntities, allEntities: allEntities, allEnums: allEnums }; } function getEventConfig(config, contractName, eventName, chainId) { let chains; if (chainId !== undefined) { let chain = ChainMap.Chain.makeUnsafe(chainId); let exit = 0; let chainConfig; try { chainConfig = ChainMap.get(config.chainMap, chain); exit = 1; } catch (exn) { chains = Stdlib_JsError.throwWithMessage(`Chain ` + chainId.toString() + ` is not configured. Add it to config.yaml or pass a configured chain.`); } if (exit === 1) { chains = [chainConfig]; } } else { chains = ChainMap.values(config.chainMap); } return Stdlib_Array.reduce(chains, undefined, (acc, chain) => { if (acc !== undefined) { return acc; } else { return Stdlib_Option.flatMap(chain.contracts.find(c => c.name === contractName), contract => contract.events.find(e => e.name === eventName)); } }); } function shouldSaveHistory(config, isInReorgThreshold) { if (config.shouldSaveFullHistory) { return true; } else if (config.shouldRollbackOnReorg) { return isInReorgThreshold; } else { return false; } } function shouldPruneHistory(config, isInReorgThreshold) { if (!config.shouldSaveFullHistory && config.shouldRollbackOnReorg) { return isInReorgThreshold; } else { return false; } } function getChain(config, chainId) { let chain = ChainMap.Chain.makeUnsafe(chainId); if (ChainMap.has(config.chainMap, chain)) { return chain; } else { return Stdlib_JsError.throwWithMessage("No chain with id " + ChainMap.Chain.toString(chain) + " found in config.yaml"); } } let primedJson = { contents: undefined }; let cached = { contents: undefined }; function prime(json) { primedJson.contents = json; cached.contents = undefined; } function getPublicConfigJson() { let json = primedJson.contents; if (json !== undefined) { return json; } else { return JSON.parse(Core.getConfigJson(undefined, undefined)); } } function stripSensitiveData(json) { let cloned = JSON.parse(JSON.stringify(json)); let stripChains = ecosystem => { if (ecosystem === undefined) { return; } if (typeof ecosystem !== "object" || ecosystem === null || Array.isArray(ecosystem)) { return; } let match = ecosystem["chains"]; if (match === undefined) { return; } if (typeof match !== "object" || match === null || Array.isArray(match)) { return; } Object.values(match).forEach(chainJson => { if (typeof chainJson !== "object" || chainJson === null || Array.isArray(chainJson)) { return; } Utils.Dict.deleteInPlace(chainJson, "rpcs"); Utils.Dict.deleteInPlace(chainJson, "rpc"); Utils.Dict.deleteInPlace(chainJson, "hypersync"); }); }; if (typeof cloned === "object" && cloned !== null && !Array.isArray(cloned)) { Utils.Dict.deleteInPlace(cloned, "isDev"); stripChains(cloned["evm"]); stripChains(cloned["fuel"]); stripChains(cloned["svm"]); } return cloned; } function canonicalJson(json) { if (Array.isArray(json)) { return json.map(canonicalJson); } if (json === null) { return json; } switch (typeof json) { case "object" : let sorted = {}; Object.keys(json).toSorted(Primitive_string.compare).forEach(k => { sorted[k] = canonicalJson(json[k]); }); return sorted; default: return json; } } function diffPaths(stored, current) { let canonEq = (a, b) => JSON.stringify(canonicalJson(a)) === JSON.stringify(canonicalJson(b)); let acc = []; let go = (s, c, prefix) => { if (canonEq(s, c)) { return; } if (Array.isArray(s)) { if (Array.isArray(c)) { let maxLen = Math.max(s.length, c.length); for (let i = 0; i < maxLen; ++i) { let p = prefix + `[` + i.toString() + `]`; let match = s[i]; let match$1 = c[i]; if (match !== undefined && match$1 !== undefined) { go(match, match$1, p); } else { acc.push(p); } } return; } } else { switch (typeof s) { case "object" : if (typeof c === "object" && c !== null && !Array.isArray(c)) { let keys = new Set(Object.keys(s).concat(Object.keys(c))); Array.from(keys).toSorted(Primitive_string.compare).forEach(k => { let p = prefix === "" ? k : prefix + `.` + k; let match = s[k]; let match$1 = c[k]; if (match !== undefined) { if (match$1 !== undefined) { return go(match, match$1, p); } else { acc.push(p); return; } } else if (match$1 !== undefined) { acc.push(p); return; } else { return; } }); return; } break; } } acc.push(prefix === "" ? "<root>" : prefix); }; let getTopKey = (j, k) => { if (typeof j === "object" && j !== null && !Array.isArray(j)) { return j[k]; } }; let topKeyDiffers = k => { let match = getTopKey(stored, k); let match$1 = getTopKey(current, k); if (match !== undefined) { if (match$1 !== undefined) { return !canonEq(match, match$1); } else { return true; } } else { return match$1 !== undefined; } }; let runTier = keys => { keys.forEach(k => { let match = getTopKey(stored, k); let match$1 = getTopKey(current, k); if (match !== undefined) { if (match$1 !== undefined) { return go(match, match$1, k); } else { acc.push(k); return; } } else if (match$1 !== undefined) { acc.push(k); return; } else { return; } }); }; if (typeof stored === "object" && stored !== null && !Array.isArray(stored) && typeof current === "object" && current !== null && !Array.isArray(current)) { let tiers = [ ["version"], ["name"], ["storage"], [ "evm", "fuel", "svm" ], ["entities"] ]; let firstHit = Stdlib_Array.reduce(tiers, undefined, (acc, tier) => { if (acc !== undefined) { return acc; } let hits = tier.filter(topKeyDiffers); if (hits.length !== 0) { return hits; } }); if (firstHit !== undefined) { runTier(firstHit); } else { let knownSet = new Set(tiers.flat()); runTier(Array.from(new Set(Object.keys(stored).concat(Object.keys(current)))).filter(k => !knownSet.has(k)).toSorted(Primitive_string.compare).filter(topKeyDiffers)); } } else { go(stored, current, ""); } return acc; } function throwIfIncompatible(changedPaths, resetCommand, runCommand, hasClickhouse) { if (changedPaths.length === 0) { return; } let bullets = changedPaths.map(p => ` - ` + p).join("\n"); let option1 = "Revert the changes above"; let padTo = (s, col) => s + " ".repeat(Math.max(col - s.length | 0, 1)); let col = Math.max(option1.length, resetCommand.length) + 2 | 0; let option3; if (runCommand !== undefined) { let clickhouseLine = hasClickhouse ? " ENVIO_CLICKHOUSE_DATABASE=<new_db> \\\n" : ""; option3 = `\n 3. Run a second indexer alongside this one — keep both datasets:\n ENVIO_PG_SCHEMA=<new_schema> \\\n` + clickhouseLine + ` ENVIO_INDEXER_PORT=<new_port> \\\n ` + runCommand; } else { option3 = ""; } Stdlib_JsError.throwWithMessage(`The following config changes are incompatible with the existing indexer data:\n\n` + bullets + `\n\nPick one:\n 1. ` + padTo(option1, col) + `# resume indexing where it left off\n 2. ` + padTo(resetCommand, col) + `# delete all indexed data and start over` + option3); } function loadWithoutRegistrations() { let c = cached.contents; if (c !== undefined) { return c; } let c$1 = fromPublic(getPublicConfigJson()); cached.contents = c$1; return c$1; } function getPgUserEntities(config) { return config.userEntities.filter(e => e.storage.postgres); } export { EnvioAddresses, rpcSourceForSchema, rpcConfigSchema, chainContractSchema, publicConfigChainSchema, svmEventDescriptorSchema, svmAbiSchema, contractEventItemSchema, contractConfigSchema, publicConfigEcosystemSchema, publicConfigEvmSchema, compositeIndexFieldSchema, derivedFieldSchema, propertySchema, entityStorageSchema, entityJsonSchema, getFieldTypeAndSchema, parseEnumsFromJson, parseEntitiesFromJson, publicConfigStorageSchema, publicConfigSchema, fromPublic, getEventConfig, shouldSaveHistory, shouldPruneHistory, getChain, prime, getPublicConfigJson, stripSensitiveData, canonicalJson, diffPaths, throwIfIncompatible, loadWithoutRegistrations, getPgUserEntities, } /* schema Not a pure module */