@morpho-dev/router 0.7.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +834 -334
- package/dist/drizzle/migrations/0000_setup_single_migration_folder.sql +64 -64
- package/dist/drizzle/migrations/0001_add-trigger-for-consumed-events.sql +5 -5
- package/dist/drizzle/migrations/0002_insert-status-code.sql +1 -1
- package/dist/drizzle/migrations/0003_update-triggers-for-consumed-events.sql +1 -1
- package/dist/drizzle/migrations/0004_drop-status-offers-foreign-key-constraint.sql +1 -1
- package/dist/drizzle/migrations/0005_add-index-to-boost-group-query-and-offer-hash.sql +1 -1
- package/dist/drizzle/migrations/0006_add-callbacks-and-positions-relations.sql +11 -11
- package/dist/drizzle/migrations/0008_validation.sql +10 -10
- package/dist/drizzle/migrations/0009_add-transfers-table.sql +4 -4
- package/dist/drizzle/migrations/0010_add-price.sql +1 -1
- package/dist/drizzle/migrations/0011_nullable-callback-amount.sql +1 -1
- package/dist/drizzle/migrations/0012_add-position-asset.sql +1 -1
- package/dist/drizzle/migrations/0013_remove-depecrated-domains.sql +13 -13
- package/dist/drizzle/migrations/0014_rename-offers-v2-into-offers.sql +19 -19
- package/dist/drizzle/migrations/0015_add-lots-table.sql +3 -3
- package/dist/drizzle/migrations/0016_merkle-metadata.sql +7 -7
- package/dist/drizzle/migrations/0017_dusty_the_hunter.sql +1 -1
- package/dist/drizzle/migrations/0018_add_chain_collector_constraints.sql +3 -3
- package/dist/drizzle/migrations/0019_add-obligation-units-shares.sql +2 -2
- package/dist/drizzle/migrations/0020_add-session.sql +1 -1
- package/dist/drizzle/migrations/0021_drop_chain_collector_epoch_indexes.sql +2 -2
- package/dist/drizzle/migrations/0021_migrate-rate-to-price.sql +6 -6
- package/dist/drizzle/migrations/0022_consolidate-price.sql +5 -5
- package/dist/drizzle/migrations/0023_remove-block-number-for-collaterals.sql +1 -1
- package/dist/drizzle/migrations/0024_add-obligation-id-to-lots.sql +8 -0
- package/dist/drizzle/migrations/0025_rename-price-to-tick.sql +202 -0
- package/dist/drizzle/migrations/0026_add-receiver-if-maker-is-seller.sql +1 -0
- package/dist/drizzle/migrations/meta/0000_snapshot.json +48 -48
- package/dist/drizzle/migrations/meta/0001_snapshot.json +48 -48
- package/dist/drizzle/migrations/meta/0002_snapshot.json +48 -48
- package/dist/drizzle/migrations/meta/0003_snapshot.json +48 -48
- package/dist/drizzle/migrations/meta/0004_snapshot.json +47 -47
- package/dist/drizzle/migrations/meta/0005_snapshot.json +47 -47
- package/dist/drizzle/migrations/meta/0006_snapshot.json +61 -61
- package/dist/drizzle/migrations/meta/0008_snapshot.json +62 -62
- package/dist/drizzle/migrations/meta/0009_snapshot.json +66 -66
- package/dist/drizzle/migrations/meta/0010_snapshot.json +66 -66
- package/dist/drizzle/migrations/meta/0013_snapshot.json +48 -48
- package/dist/drizzle/migrations/meta/0014_snapshot.json +48 -48
- package/dist/drizzle/migrations/meta/0015_snapshot.json +52 -52
- package/dist/drizzle/migrations/meta/0016_snapshot.json +61 -61
- package/dist/drizzle/migrations/meta/0017_snapshot.json +61 -61
- package/dist/drizzle/migrations/meta/0018_snapshot.json +62 -62
- package/dist/drizzle/migrations/meta/0019_snapshot.json +62 -62
- package/dist/drizzle/migrations/meta/0023_snapshot.json +62 -62
- package/dist/drizzle/migrations/meta/0024_snapshot.json +1448 -0
- package/dist/drizzle/migrations/meta/0025_snapshot.json +1448 -0
- package/dist/drizzle/migrations/meta/0026_snapshot.json +1454 -0
- package/dist/drizzle/migrations/meta/_journal.json +21 -0
- package/dist/evm/bytecode/morpho.txt +1 -1
- package/dist/index.browser.d.mts +206 -77
- package/dist/index.browser.d.mts.map +1 -1
- package/dist/index.browser.d.ts +206 -77
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +445 -197
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +440 -198
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.node.d.mts +347 -119
- package/dist/index.node.d.mts.map +1 -1
- package/dist/index.node.d.ts +347 -119
- package/dist/index.node.d.ts.map +1 -1
- package/dist/index.node.js +865 -312
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +861 -314
- package/dist/index.node.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.node.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.node.mjs","names":["max","batch","batch","toSnakeCase","fromSnakeCase","create","Logger.getLogger","Utils.retry","create","Admin.create","Logger.getLogger","Tracer.getTracer","Tracer.startActiveSpan","Utils.wait","Type","chains","viemEthereum","viemBase","viemAnvil","DEFAULT_BATCH_SIZE","BigMath.min","BigMath.max","batch","Errors.BaseError","create","z","from","InvalidOptionError","Errors.BaseError","z","z","LLTV.LLTVSchema","from","LLTV.from","random","Random.address","Errors.BaseError","z","from","Errors.BaseError","z","Collateral.CollateralsSchema","Maturity.MaturitySchema","from","Maturity.from","fromSnakeCase","Format.fromSnakeCase","random","Random.address","Collateral.random","fromOffer","Errors.BaseError","z","Maturity.MaturitySchema","Collateral.CollateralsSchema","from","fromSnakeCase","Format.fromSnakeCase","Format.toSnakeCase","random","Random.int","Random.address","Maturity.from","LLTV.from","Random.bool","Random.hex","Collateral.random","Random.float","Obligation.id","Obligation.from","encode","decode","Collateral.from","Errors.BaseError","from","from","z","from","Format.fromSnakeCase","Obligation.id","Obligation.random","Random.int","Errors.BaseError","from","Errors.BaseError","from","VERSION","from","Offer.hash","Offer.serialize","Offer.OfferSchema","Errors.BaseError","oracles","Position.Type","Offer.Status","chains","Logger.getLogger","Chain.streamLogs","Offer.consumedEvent","Offer.takeEvent","groups","consumedEventsTable","groupsTable","Logger.getLogger","Chain.streamLogs","Tree.decode","Tree.DecodeError","Callback.isEmptyCallback","Position.from","Offer.hash","obligationId","Offer.obligationId","Obligation.from","Oracle.from","hash","Utils.batch","Abi.Oracle","Utils.batchMulticall","Utils.batchMulticall","Logger.getLogger","Abi.MetaMorpho","ERC4626.convertToAssets","ERC4626.DenominatorIsZeroError","Utils.batchMulticall","Logger.getLogger","Chain.streamLogs","Transfer.from","Errors.ReorgError","Fetchers.snapshotVaultPositions","Fetchers.snapshotERC20Positions","Errors.BaseError","Logger.getLogger","Errors.ReorgError","Collector.create","CollectFunctions.collectOffersV2","CollectFunctions.collectConsumedEvents","CollectFunctions.collectPrices","CollectFunctions.collectPositions","from","CollectorBuilder.createBuilder","from","Collectors.from","create","Tracer.getTracer","Tracer.startActiveSpan","Collector.start","create","Collector.names","from","from","from","Obligation.id","z","Payload.API_ERROR_CODES","from","DEFAULT_LIMIT","z","Logger.getLogger","ApiSchema.safeParse","ApiPayload.failure","ApiPayload.success","ApiSchema.BookResponse.from","ApiSchema.safeParse","ApiPayload.failure","ApiPayload.InternalServerError","parseCursor","findStartIndex","formatCursor","ApiPayload.success","ApiPayload.BadRequestError","GateConfig.configs","Maturity.from","GateConfig.assets","oracles","GateConfig.oracles","ApiSchema.safeParse","ApiPayload.failure","ApiPayload.BadRequestError","ApiPayload.success","Maturity.MaturityType","Maturity.from","Callback.Type","Logger.getLogger","Schema.safeParse","ApiPayload.failure","Health.create","ApiPayload.APIError","Format.toSnakeCase","ApiPayload.success","Logger.getLogger","ApiSchema.safeParse","ApiPayload.failure","ApiPayload.NotFoundError","Obligation.id","ApiPayload.success","ApiSchema.ObligationResponse.from","getObligations","Logger.getLogger","ApiSchema.safeParse","ApiPayload.failure","Obligation.id","ApiPayload.success","ApiSchema.ObligationResponse.from","DEFAULT_BATCH_SIZE","DEFAULT_LIMIT","create","Offer.serialize","Offer.obligationId","Utils.batch","DEFAULT_BATCH_SIZE","offersTable","obligationCollateralsTable","oraclesTable","obligationsTable","Maturity.from","now","Time.now","Obligation.from","Collateral.from","LLTV.from","groupsTable","validationsTable","statusTable","Quote.from","OffersDomain.DEFAULT_LIMIT","obligationCollateralsTable","oraclesTable","offersTable","positionsTable","offsetsTable","callbacksTable","lotsTable","groupsTable","offersCallbacksTable","obligationsTable","Maturity.from","getOffers","Logger.getLogger","ApiSchema.safeParse","ApiPayload.failure","ApiPayload.success","hash","Offer.hash","ApiSchema.OfferResponse.from","Logger.getLogger","ApiSchema.safeParse","ApiPayload.failure","ApiPayload.success","ApiSchema.PositionResponse.from","Logger.getLogger","ApiSchema.safeParse","ApiPayload.failure","ApiPayload.BadRequestError","Offer.fromSnakeCase","hash","Offer.hash","Offer.InvalidOfferError","ApiPayload.success","Tree.from","Tree.encodeUnsigned","from","create","serve","Tracer.getTracer","Tracer.startActiveSpan","Controllers.getOffers","Controllers.getObligations","Controllers.getObligation","Controllers.getBook","failure","ApiPayload.failure","Controllers.getUserPositions","Controllers.getHealth","Controllers.getHealthCollectors","Controllers.getHealthChains","Controllers.getConfigContracts","Controllers.getSwaggerJson","Controllers.getDocsHtml","Controllers.getIntegratorDocsHtml","connect","Offer.fromSnakeCase","Maturity.from","Obligation.fromSnakeCase","Obligation.id","Quote.fromSnakeCase","Errors.BaseError","create","chains","Collector.names","DEFAULT_LIMIT","create","Logger.getLogger","obligationCollateralsTable","oraclesTable","offersTable","validationsTable","statusTable","groupsTable","obligationsTable","offsetsTable","lotsTable","offersCallbacksTable","callbacksTable","positionsTable","create","Utils.batch","DEFAULT_BATCH_SIZE","callbacksTable","offersCallbacksTable","create","groups","Utils.batch","DEFAULT_BATCH_SIZE","groupsTable","consumedEventsTable","create","groups","Utils.batch","DEFAULT_BATCH_SIZE","groupsTable","create","lotsTable","create","obligations","id","Obligation.id","Utils.batch","DEFAULT_BATCH_SIZE","obligationsTable","obligationCollateralsTable","create","offsetsTable","create","oraclesTable","Oracle.from","Utils.batch","DEFAULT_BATCH_SIZE","DEFAULT_LIMIT","create","positions","Position.Type","Utils.batch","DEFAULT_BATCH_SIZE","positionsTable","offsetsTable","lotsTable","groupsTable","offersTable","transfersTable","create","transfers","Utils.batch","DEFAULT_BATCH_SIZE","transfersTable","positionsTable","create","trees","treesTable","Tree.proofs","Offer.hash","Utils.batch","DEFAULT_BATCH_SIZE","merklePathsTable","create","validationsTable","statusTable","status","Offer.Status","Utils.batch","DEFAULT_BATCH_SIZE","BookDomain.create","BlocksDomain.create","CallbacksDomain.create","OffersDomain.create","ConsumedDomain.create","GroupsDomain.create","LotsDomain.create","ObligationsDomain.create","OffsetsDomain.create","OraclesDomain.create","TreesDomain.create","ValidationsDomain.create","PositionsDomain.create","TransfersDomain.create","connect","offersSchema","drizzleLite","Tracer.getTracer","Tracer.startActiveSpan","migratePostgres","migratePGLite","OfferCore.toSnakeCase","Gate.run","Maturity.from","Callback.isEmptyCallback","BigMath.atMostOneNonZero","chains","GateConfig.assets","GateConfig.oracles","Rules.sameMaker","Rules.amountMutualExclusivity","Rules.chains","Rules.maturity","Rules.callback","Rules.token","Rules.oracle","Tree.from","Offer.from","signatureDomain","Tree.signatureDomain","Tree.signatureTypes","Tree.encode","Chain.streamLogs","Tree.decode","Errors.BaseError","Chain.getChain","EVMClient.from"],"sources":["../src/logger/Logger.ts","../src/tracer/Tracer.ts","../src/utils/BigMath.ts","../src/utils/batch.ts","../src/utils/retry.ts","../src/utils/batchMulticall.ts","../src/utils/Errors.ts","../src/utils/Format.ts","../src/utils/Group.ts","../src/utils/lazy.ts","../src/utils/wait.ts","../src/utils/poll.ts","../src/utils/Random.ts","../src/utils/time.ts","../src/utils/index.ts","../src/indexer/collectors/Admin.ts","../src/indexer/collectors/Collector.ts","../src/core/Abi/MetaMorpho.ts","../src/core/Abi/MetaMorphoFactory.ts","../src/core/Abi/MorphoV2.ts","../src/core/Abi/index.ts","../src/core/Callback.ts","../src/core/Chain.ts","../src/core/ChainRegistry.ts","../src/utils/zod.ts","../src/core/LLTV.ts","../src/core/Collateral.ts","../src/core/ERC4626.ts","../src/core/Liquidity.ts","../src/core/Maturity.ts","../src/core/Obligation.ts","../src/core/Offer.ts","../src/core/Oracle.ts","../src/core/Position.ts","../src/core/Quote.ts","../src/core/TradingFee.ts","../src/core/Transfer.ts","../src/core/Tree.ts","../src/core/types.ts","../src/database/drizzle/VERSION.ts","../src/database/drizzle/schema.ts","../src/indexer/collectors/CollectFunctions/collectConsumedEvents.ts","../src/indexer/collectors/CollectFunctions/collectOffers.ts","../src/indexer/collectors/fetchers/fetchOraclePrices.ts","../src/indexer/collectors/fetchers/snapshotERC20Positions.ts","../src/indexer/collectors/fetchers/snapshotVaultPositions.ts","../src/indexer/collectors/CollectFunctions/collectPositions.ts","../src/indexer/collectors/CollectFunctions/collectPrices.ts","../src/indexer/collectors/CollectorBuilder.ts","../src/indexer/collectors/Collectors.ts","../src/indexer/Indexer.ts","../src/api/Health.ts","../src/api/Schema/BookResponse.ts","../src/api/Schema/health.ts","../src/api/Schema/ObligationResponse.ts","../src/api/Schema/OfferResponse.ts","../src/api/Controllers/Payload.ts","../src/api/Schema/openapi.ts","../src/api/Schema/PositionResponse.ts","../src/api/Schema/requests.ts","../src/api/Controllers/getBook.ts","../src/api/Controllers/getConfigContracts.ts","../src/gatekeeper/GateConfig.ts","../src/gatekeeper/ConfigRules.ts","../src/api/Controllers/getConfigRules.ts","../src/api/Controllers/getDocs.ts","../src/api/Controllers/getHealth.ts","../src/api/Controllers/getObligation.ts","../src/api/Controllers/getObligations.ts","../src/database/constants.ts","../src/database/domains/Offers.ts","../src/api/Controllers/getOffers.ts","../src/api/Controllers/getUserPositions.ts","../src/api/Controllers/validateOffers.ts","../src/api/Controllers/index.ts","../src/api/Api.ts","../src/api/RouterApi.ts","../src/client/Client.ts","../src/database/drizzle/index.ts","../src/database/domains/Blocks.ts","../src/database/domains/Book.ts","../src/database/domains/Callbacks.ts","../src/database/domains/Consumed.ts","../src/database/domains/Groups.ts","../src/database/domains/Lots.ts","../src/database/domains/Obligations.ts","../src/database/domains/Offsets.ts","../src/database/domains/Oracles.ts","../src/database/domains/Positions.ts","../src/database/domains/Transfers.ts","../src/database/domains/Trees.ts","../src/database/domains/Validations.ts","../src/database/Database.ts","../src/gatekeeper/Client.ts","../src/gatekeeper/Gate.ts","../src/gatekeeper/Gatekeeper.ts","../src/gatekeeper/Rules.ts","../src/gatekeeper/morphoRules.ts","../src/mempool/MempoolEVMClient.ts","../src/mempool/MempoolClient.ts","../src/mempool/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { stringify } from \"viem\";\nimport type { Compute } from \"#core\";\n\nexport const LogLevelValues = [\n \"trace\",\n \"debug\",\n \"info\",\n \"warn\",\n \"error\",\n \"fatal\",\n \"silent\",\n] as const;\nexport type LogLevel = (typeof LogLevelValues)[number];\ntype ActiveLogLevel = Exclude<LogLevel, \"silent\">;\n\nexport type LogEntry = Compute<{ msg: string } & Record<string, unknown>>;\nexport type LogFn = (entry: LogEntry) => void;\n\nexport type Logger = {\n trace: LogFn;\n debug: LogFn;\n info: LogFn;\n warn: LogFn;\n error: LogFn;\n fatal: LogFn;\n};\n\nexport function defaultLogger(minLevel?: LogLevel, pretty?: boolean): Logger {\n const threshold: LogLevel = minLevel ?? (process.env.ROUTER_LOG_LEVEL as LogLevel) ?? \"info\";\n const prettyEnabled: boolean =\n typeof pretty === \"boolean\"\n ? pretty\n : String(process.env.ROUTER_LOG_PRETTY ?? \"false\").toLowerCase() === \"true\";\n\n const levelIndexByName: Record<LogLevel, number> = LogLevelValues.reduce(\n (acc, lvl, idx) => {\n acc[lvl] = idx;\n return acc;\n },\n {} as Record<LogLevel, number>,\n );\n\n const isEnabled = (methodLevel: LogLevel): boolean =>\n levelIndexByName[methodLevel] >= levelIndexByName[threshold];\n\n const wrap = <L extends ActiveLogLevel>(\n consoleMethod: \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\",\n methodLevel: L,\n ): LogFn =>\n isEnabled(methodLevel)\n ? (entry: LogEntry) => {\n if (!prettyEnabled) {\n // biome-ignore lint/suspicious/noConsole: console is used for logging\n console[consoleMethod](stringify({ level: methodLevel, ...entry }));\n return;\n }\n\n const { msg, ...rest } = entry;\n const stack =\n typeof (rest as Record<string, unknown>).stack === \"string\"\n ? (rest as Record<string, unknown>).stack\n : undefined;\n if (stack) delete (rest as Record<string, unknown>).stack;\n const timestamp = new Date().toISOString();\n const level = methodLevel.toUpperCase();\n\n const extras: string = Object.entries(rest)\n .map(([k, v]) => `${k}=${formatValue(v)}`)\n .join(\" \");\n\n const line =\n extras.length > 0\n ? `${timestamp} [${level}] ${msg} ${extras}`\n : `${timestamp} [${level}] ${msg}`;\n // biome-ignore lint/suspicious/noConsole: console is used for logging\n console[consoleMethod](line);\n if (stack) {\n // biome-ignore lint/suspicious/noConsole: console is used for logging\n console[consoleMethod](stack);\n }\n }\n : () => {};\n\n return {\n trace: wrap(\"trace\", \"trace\"),\n debug: wrap(\"debug\", \"debug\"),\n info: wrap(\"info\", \"info\"),\n warn: wrap(\"warn\", \"warn\"),\n error: wrap(\"error\", \"error\"),\n fatal: wrap(\"error\", \"fatal\"),\n };\n}\n\nexport function silentLogger(): Logger {\n const noop = (() => {}) as LogFn;\n return { trace: noop, debug: noop, info: noop, warn: noop, error: noop, fatal: noop };\n}\n\nconst loggerContext = new AsyncLocalStorage<Logger>();\n\nexport function runWithLogger<T>(logger: Logger, fn: () => Promise<T>): Promise<T> {\n return loggerContext.run(logger, fn);\n}\n\nexport function getLogger(): Logger {\n return loggerContext.getStore() ?? defaultLogger();\n}\n\nfunction formatValue(value: unknown): string {\n if (\n value === null ||\n value === undefined ||\n typeof value === \"number\" ||\n typeof value === \"bigint\" ||\n typeof value === \"boolean\"\n ) {\n return String(value);\n }\n if (typeof value === \"string\") {\n if (value.includes(\" \")) return JSON.stringify(value);\n return value;\n }\n try {\n return stringify(value as unknown as Record<string, unknown>);\n } catch {\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n }\n}\n","import { type Tracer as OtelTracer, type Span, SpanStatusCode, trace } from \"@opentelemetry/api\";\nimport { OTLPTraceExporter } from \"@opentelemetry/exporter-trace-otlp-proto\";\nimport { AWSXRayIdGenerator } from \"@opentelemetry/id-generator-aws-xray\";\nimport { registerInstrumentations } from \"@opentelemetry/instrumentation\";\nimport { HttpInstrumentation } from \"@opentelemetry/instrumentation-http\";\nimport { PgInstrumentation } from \"@opentelemetry/instrumentation-pg\";\nimport { AWSXRayPropagator } from \"@opentelemetry/propagator-aws-xray\";\nimport { resourceFromAttributes } from \"@opentelemetry/resources\";\nimport { BatchSpanProcessor, NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\";\nimport { ATTR_SERVICE_NAME } from \"@opentelemetry/semantic-conventions\";\n\nexport type Tracer = OtelTracer;\n\nlet provider: NodeTracerProvider | null = null;\n\n/**\n * Instantiates a new tracer for the given service.\n *\n * @param serviceName - The name of the service to trace.\n *\n * @example\n * ```ts\n * Tracer.init(\"router\");\n * ```\n */\nexport function init(serviceName: string): void {\n if (provider) return;\n\n const exporter = new OTLPTraceExporter({\n url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT ?? \"http://localhost:4318/v1/traces\",\n });\n\n const useAwsXRay = (process.env.TRACE_EXPORTER ?? \"otlp\").toLowerCase() === \"xray\";\n\n provider = new NodeTracerProvider({\n resource: resourceFromAttributes({\n [ATTR_SERVICE_NAME]: serviceName,\n }),\n ...(useAwsXRay ? { idGenerator: new AWSXRayIdGenerator() } : {}),\n spanProcessors: [new BatchSpanProcessor(exporter)],\n });\n\n registerInstrumentations({\n tracerProvider: provider,\n instrumentations: [new HttpInstrumentation(), new PgInstrumentation()],\n });\n\n provider.register({\n propagator: useAwsXRay ? new AWSXRayPropagator() : undefined,\n });\n}\n\n/**\n * Returns the existing tracer.\n *\n * @returns The existing tracer. {@link Tracer}\n * @throws If the tracer is not initialized.\n *\n * @example\n * ```ts\n * const tracer = Tracer.getTracer(\"router.api\");\n * tracer.startSpan(\"indexer.next\", async (span) => {\n * span.end();\n * });\n * ```\n */\nexport function getTracer(name: string): Tracer {\n return trace.getTracer(name);\n}\n\n/**\n * Shuts down the tracer.\n *\n * @example\n * ```ts\n * await Tracer.shutdown();\n * ```\n */\nexport async function shutdown(): Promise<void> {\n if (!provider) return;\n await provider.shutdown();\n provider = null;\n}\n\n/**\n * Helper to run a function inside an active span.\n * Takes care of recording exceptions and setting the span status to ERROR.\n * @param tracer - The tracer to use. {@link Tracer}\n * @param name - The name of the span.\n * @param fn - The function to run inside the span.\n * @returns The result of the function.\n *\n * @example\n * ```ts\n * const tracer = Tracer.getTracer(\"router.api\");\n * const result = await Tracer.startActiveSpan(tracer, \"indexer.next\", async (span) => {\n * return await indexer.next();\n * });\n * ```\n */\nexport function startActiveSpan<T>(\n tracer: Tracer,\n name: string,\n fn: (span: Span) => Promise<T> | T,\n): Promise<T> {\n return tracer.startActiveSpan(name, async (span) => {\n try {\n return await fn(span);\n } catch (err) {\n span.recordException(err as Error);\n span.setStatus({ code: SpanStatusCode.ERROR });\n throw err;\n } finally {\n span.end();\n }\n });\n}\n","export function max(a: bigint, b: bigint): bigint {\n return a > b ? a : b;\n}\n\nexport function min(a: bigint, b: bigint): bigint {\n return a < b ? a : b;\n}\n\n/**\n * Checks if at most one of the given values is non-zero.\n * @param values - The bigint values to check.\n * @returns True if zero or one value is non-zero, false if two or more are non-zero.\n */\nexport function atMostOneNonZero(...values: bigint[]): boolean {\n let nonZeroCount = 0;\n for (const value of values) {\n if (value !== 0n) {\n nonZeroCount++;\n if (nonZeroCount > 1) return false;\n }\n }\n return true;\n}\n","/**\n * Splits an array into batches of a specified size.\n * @param array The array to split.\n * @param batchSize The size of each batch.\n * @returns An iterator that yields each batch.\n * @example\n * ```typescript\n * const array = [1, 2, 3, 4, 5];\n * for (const batch of batch(array, 2)) {\n * console.log(batch);\n * }\n * // Output:\n * // [1, 2]\n * // [3, 4]\n * // [5]\n * ```\n */\nexport function* batch<T>(\n array: T[] | readonly T[],\n batchSize: number,\n): Generator<T[], void, unknown> {\n for (let i = 0; i < array.length; i += batchSize) {\n yield array.slice(i, i + batchSize);\n }\n}\n","export const retry = async <T>(fn: () => Promise<T>, attempts = 3, delayMs = 50): Promise<T> => {\n let lastErr: unknown;\n for (let i = 0; i < attempts; i++) {\n try {\n return await fn();\n } catch (err) {\n lastErr = err;\n if (i < attempts - 1) await new Promise((r) => setTimeout(r, delayMs));\n }\n }\n throw lastErr;\n};\n","import type { MulticallParameters, PublicClient, Transport } from \"viem\";\nimport { multicall } from \"viem/actions\";\nimport type { Chain } from \"#core\";\nimport { batch } from \"#utils/batch.ts\";\nimport { retry } from \"#utils/retry.ts\";\n\n/**\n * Helper function to execute multicall in batches with retry logic.\n * Abstracts the common pattern of batching calls, retrying, and collecting results.\n *\n * @param parameters - Configuration for batched multicall\n * @returns Promise resolving to flattened array of results\n */\nexport async function batchMulticall<TResult>(parameters: {\n client: PublicClient<Transport, Chain.Chain>;\n calls: MulticallParameters[\"contracts\"];\n batchSize: number;\n retryAttempts: number;\n retryDelayMs: number;\n blockNumber?: bigint;\n}): Promise<TResult[]> {\n const { client, calls, batchSize, retryAttempts, retryDelayMs, blockNumber } = parameters;\n const results: TResult[] = [];\n\n for (const callsBatch of batch(calls, batchSize)) {\n const batchResults = await retry(\n () =>\n multicall(client, {\n allowFailure: false,\n contracts: callsBatch,\n ...(blockNumber ? { blockNumber } : {}),\n }),\n retryAttempts,\n retryDelayMs,\n );\n results.push(...(batchResults as TResult[]));\n }\n\n return results;\n}\n","export type GlobalErrorType<name extends string = \"Error\"> = Error & {\n name: name;\n};\n\n/**\n * Base error class inherited by all errors thrown by mempool.\n *\n * @example\n * ```ts\n * import { Errors } from 'mempool'\n * throw new Errors.BaseError('An error occurred')\n * ```\n */\nexport class BaseError<cause extends Error | undefined = undefined> extends Error {\n details: string;\n shortMessage: string;\n\n override cause: cause;\n override name = \"BaseError\";\n\n constructor(\n shortMessage: string,\n options: {\n cause?: cause | undefined;\n details?: string | undefined;\n metaMessages?: (string | undefined)[] | undefined;\n } = {},\n ) {\n const details = (() => {\n if (options.cause instanceof BaseError) {\n if (options.cause.details) return options.cause.details;\n if (options.cause.shortMessage) return options.cause.shortMessage;\n }\n if (options.cause && \"details\" in options.cause && typeof options.cause.details === \"string\")\n return options.cause.details;\n if (options.cause?.message) return options.cause.message;\n return options.details!;\n })();\n\n const message = [\n shortMessage || \"An error occurred.\",\n ...(options.metaMessages ? [\"\", ...options.metaMessages] : []),\n ...(details ? [\"\", details ? `Details: ${details}` : undefined] : []),\n ]\n .filter((x) => typeof x === \"string\")\n .join(\"\\n\");\n\n super(message, options.cause ? { cause: options.cause } : undefined);\n\n this.cause = options.cause as cause;\n this.details = details;\n this.shortMessage = shortMessage;\n }\n\n walk(): Error;\n walk(fn: (err: unknown) => boolean): Error | null;\n walk(fn?: ((err: unknown) => boolean) | undefined): unknown {\n return walk(this, fn);\n }\n}\n\n/** @internal */\nfunction walk(err: unknown, fn?: ((err: unknown) => boolean) | undefined): unknown {\n if (fn?.(err)) return err;\n if (err && typeof err === \"object\" && \"cause\" in err && err.cause) return walk(err.cause, fn);\n return fn ? null : err;\n}\n\nexport class ReorgError extends BaseError {\n override name = \"ReorgError\";\n constructor(blockNumber: number) {\n super(`Reorg detected at block number ${blockNumber}`);\n }\n}\n","import { getAddress, isAddress } from \"viem\";\n\n/** The snake case representation of a type with bigint values stringified. */\nexport type Snake<T> = DeepMutable<SnakeKeys<StringifiedBigint<T>>>;\n\n/** Make arrays/tuples and object props mutable, deeply. */\ntype DeepMutable<T> =\n // leave functions/primitives as-is\n T extends (...args: unknown[]) => unknown\n ? T\n : T extends number | string | boolean | symbol | bigint | null | undefined\n ? T\n : // handle tuples first (preserve length/element types)\n T extends readonly [...infer R]\n ? { -readonly [K in keyof R]: DeepMutable<R[K]> }\n : // then general readonly arrays\n T extends ReadonlyArray<infer U>\n ? Array<DeepMutable<U>>\n : // then objects: strip readonly from props and recurse\n T extends object\n ? { -readonly [K in keyof T]: DeepMutable<T[K]> }\n : T;\n\n/** Stringifies bigint values to strings and preserves branded primitives. */\ntype StringifiedBigint<T> =\n // non-distributive check so that `bigint & Brand<...>` is still caught here\n [T] extends [bigint]\n ? string\n : [T] extends [`0x${string}`]\n ? string\n : // Preserve branded primitives by matching the primitive first.\n T extends number\n ? T\n : T extends string\n ? T\n : T extends boolean\n ? T\n : T extends symbol\n ? T\n : T extends null | undefined\n ? T\n : T extends readonly (infer U)[]\n ? readonly StringifiedBigint<U>[]\n : T extends object\n ? { [K in keyof T]: StringifiedBigint<T[K]> }\n : T;\n\n/** Key remapping that also preserves branded primitives. */\ntype SnakeKeys<T> = T extends readonly (infer U)[]\n ? readonly SnakeKeys<U>[]\n : T extends number | string | boolean | symbol | null | undefined\n ? T\n : T extends object\n ? { [K in keyof T as ToSnakeCase<Extract<K, string>>]: SnakeKeys<T[K]> }\n : T;\n\ntype ToSnakeCase<S extends string> = S extends `${infer Head}${infer Tail}`\n ? Tail extends Uncapitalize<Tail>\n ? `${Lowercase<Head>}${ToSnakeCase<Tail>}`\n : `${Lowercase<Head>}_${ToSnakeCase<Uncapitalize<Tail>>}`\n : S;\n\n/**\n * Formats object keys to snake case.\n * Preserves ethereum addresses as is.\n * Converts ethereum addresses to checksummed if used as values.\n * Stringifies bigint values to strings.\n */\nexport function toSnakeCase<T>(obj: T): Snake<T> {\n return stringifyBigint(\n processObject(\n obj,\n (s: string) => s.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`),\n (value: unknown) =>\n typeof value === \"string\" && isAddress(value.toLowerCase())\n ? getAddress(value.toLowerCase())\n : value,\n ),\n ) as Snake<T>;\n}\n\n/**\n * Formats a snake case object to its camel case type.\n * Preserves ethereum addresses as is.\n * Converts checksummed ethereum addresses to lowercase if used as values.\n * @warning Does not unstringify bigint values.\n */\nexport function fromSnakeCase<T>(obj: Snake<T>): T {\n return processObject(\n obj,\n (s: string) =>\n isAddress(s.toLowerCase()) ? s : s.replace(/_([a-z])/g, (_, c) => c.toUpperCase()),\n (value: unknown) =>\n typeof value === \"string\" && isAddress(value.toLowerCase()) ? value.toLowerCase() : value,\n ) as T;\n}\n\nfunction processObject<T>(\n obj: T,\n fnKey: (str: string) => string,\n fnValue: (value: unknown) => unknown,\n): unknown {\n if (typeof obj !== \"object\" || obj === null) return obj;\n\n if (Array.isArray(obj)) return obj.map((item) => processObject(item, fnKey, fnValue));\n\n return Object.entries(obj as Record<string, unknown>).reduce(\n (acc, [key, value]) => {\n const newKey = fnKey(key);\n acc[newKey] =\n typeof value === \"object\" && value !== null\n ? processObject(value, fnKey, fnValue)\n : fnValue(value);\n\n return acc;\n },\n {} as Record<string, unknown>,\n );\n}\n\nexport function stringifyBigint<T>(value: T): StringifiedBigint<T> {\n if (typeof value === \"bigint\") return value.toString() as StringifiedBigint<T>;\n if (Array.isArray(value)) return value.map(stringifyBigint) as StringifiedBigint<T>;\n if (value && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) {\n out[k] = stringifyBigint(v);\n }\n return out as StringifiedBigint<T>;\n }\n\n return value as StringifiedBigint<T>;\n}\n","import { type Hex, pad } from \"viem\";\n\n/**\n * Creates a bytes32 group identifier from a number.\n * @param n - A non-negative integer.\n * @throws {Error} If n is negative or not an integer.\n */\nexport const fromNumber = (n: number): Hex => {\n if (!Number.isInteger(n)) {\n throw new Error(`Group.fromNumber: expected integer, got ${n}`);\n }\n if (n < 0) {\n throw new Error(`Group.fromNumber: expected non-negative, got ${n}`);\n }\n return pad(`0x${n.toString(16)}`, { size: 32 });\n};\n","/**\n * Transform a polling function into an async generator.\n * @param fn - The polling function to transform.\n * @returns An async generator.\n */\nexport function lazy<T>(\n pollFn: (emit: (value: T) => void, { stop }: { stop: () => void }) => () => boolean,\n) {\n return () =>\n (async function* () {\n let active = true;\n let resolveNext: (() => void) | null = null;\n const queue: T[] = [];\n\n const wait = () =>\n new Promise<void>((resolve) => {\n resolveNext = resolve;\n });\n\n const emit = (item: T) => {\n queue.push(item);\n resolveNext?.();\n resolveNext = null;\n };\n\n let unpoll: (() => boolean) | null = null;\n const stop = () => {\n active = false;\n // stop the poller immediately if we already have it\n unpoll?.();\n resolveNext?.();\n resolveNext = null;\n };\n\n unpoll = pollFn(emit, { stop });\n\n try {\n while (active) {\n if (queue.length === 0) await wait();\n while (queue.length > 0 && active) yield queue.shift()!;\n }\n } finally {\n stop();\n }\n })();\n}\n","export async function wait(time: number) {\n return new Promise((res) => setTimeout(res, time));\n}\n","import { wait } from \"./wait.ts\";\n/**\n * Polls a function at a specified interval.\n * Inspired by https://github.com/wevm/viem/blob/845994d20275d08ff892018e237a4b599eeefb6a/src/utils/poll.ts\n */\nexport function poll<data>(\n fn: ({ unpoll }: { unpoll: () => void }) => Promise<data | undefined>,\n { interval }: { interval: () => Promise<number> },\n) {\n let active = true;\n const unwatch = () => (active = false);\n\n const watch = async () => {\n while (active) {\n const delay = await interval();\n if (!active) break;\n await wait(delay);\n if (!active) break;\n await fn({ unpoll: unwatch });\n }\n };\n\n watch();\n\n return unwatch;\n}\n","import type { Address, Hex } from \"viem\";\n\ntype Rng = () => number;\n\nlet currentRng: Rng = Math.random;\n\nconst FNV_OFFSET_BASIS = 2166136261;\nconst FNV_PRIME = 16777619;\n\nconst hashSeed = (seed: string): number => {\n let hash = FNV_OFFSET_BASIS;\n for (let i = 0; i < seed.length; i += 1) {\n hash ^= seed.charCodeAt(i);\n hash = Math.imul(hash, FNV_PRIME);\n }\n return hash >>> 0;\n};\n\nconst createSeededRng = (seed: string): Rng => {\n let state = hashSeed(seed);\n return () => {\n state += 0x6d2b79f5;\n let t = Math.imul(state ^ (state >>> 15), state | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n};\n\n/**\n * Runs a function with a deterministic RNG derived from the given seed.\n */\nexport function withSeed<T>(seed: string, fn: () => T): T {\n const previous = currentRng;\n currentRng = createSeededRng(seed);\n try {\n return fn();\n } finally {\n currentRng = previous;\n }\n}\n\n/**\n * Seeds the global RNG for deterministic test runs.\n */\nexport function seed(seed: string): void {\n currentRng = createSeededRng(seed);\n}\n\n/**\n * Returns a deterministic random float in [0, 1).\n */\nexport function float(): number {\n return currentRng();\n}\n\n/**\n * Returns a deterministic random integer in [min, maxExclusive).\n */\nexport function int(maxExclusive: number, min = 0): number {\n return Math.floor(float() * (maxExclusive - min)) + min;\n}\n\n/**\n * Returns a deterministic random boolean.\n */\nexport function bool(probability = 0.5): boolean {\n return float() < probability;\n}\n\n/**\n * Returns deterministic random bytes.\n */\nexport function bytes(length: number): Uint8Array {\n const output = new Uint8Array(length);\n for (let i = 0; i < length; i += 1) {\n output[i] = int(256);\n }\n return output;\n}\n\n/**\n * Returns a deterministic random hex string for the given byte length.\n */\nexport function hex(byteLength: number): Hex {\n const output = bytes(byteLength);\n const hexParts = Array.from(output, (byte) => byte.toString(16).padStart(2, \"0\"));\n return `0x${hexParts.join(\"\")}` as Hex;\n}\n\n/**\n * Returns a deterministic random address.\n */\nexport function address(): Address {\n return hex(20) as Address;\n}\n","export function now(): number {\n return Math.floor(Date.now() / 1000);\n}\n\nexport function max(): number {\n return 8640000000000000000;\n}\n","export * from \"./BigMath.ts\";\nexport * from \"./batch.ts\";\nexport * from \"./batchMulticall.ts\";\nexport * from \"./Errors.ts\";\nexport * from \"./Format.ts\";\nexport * as Group from \"./Group.ts\";\nexport * from \"./lazy.ts\";\nexport * from \"./poll.ts\";\nexport * as Random from \"./Random.ts\";\nexport * from \"./retry.ts\";\nexport * as Time from \"./time.ts\";\nexport * from \"./wait.ts\";\n","import type { Block, Hex, PublicClient, Transport } from \"viem\";\nimport type { Chain } from \"#core\";\nimport type { Database } from \"#database/index.ts\";\nimport { Collector } from \"#indexer/index.ts\";\nimport * as Logger from \"#logger/Logger.ts\";\nimport * as Utils from \"#utils/index.ts\";\n\nexport type Admin = {\n /** Sync the block and return true if the max block number was reached. */\n syncBlock: () => Promise<boolean>;\n};\n\ntype LightBlock = {\n hash: Hex;\n number: bigint;\n parentHash: Hex;\n};\n\nexport function create<client extends PublicClient<Transport, Chain.Chain>>(parameters: {\n client: client;\n db: Database.Database;\n options?: {\n maxBatchSize?: number;\n maxBlockNumber?: number;\n };\n}): Admin {\n const collector = \"admin\";\n const { client, db, options: { maxBatchSize = 25, maxBlockNumber } = {} } = parameters;\n\n const maxBlockNumberBI = maxBlockNumber !== undefined ? BigInt(maxBlockNumber) : undefined;\n\n let finalizedBlock: LightBlock | null = null;\n let unfinalizedBlocks: LightBlock[] = [];\n let initialized = false;\n\n const logger = Logger.getLogger();\n let isMaxBlockNumberReached = false;\n let tick = 0;\n return {\n syncBlock: async () => {\n if (!initialized) {\n await Promise.all(\n Collector.names.map((collectorName) =>\n db.blocks.init({ chainId: client.chain.id, collectorName }),\n ),\n );\n initialized = true;\n }\n if (isMaxBlockNumberReached) return true;\n\n const head = await client.getBlock({\n blockTag: \"latest\",\n includeTransactions: false,\n });\n\n await db.transaction(async (dbTx) => {\n const { epoch, blockNumber: latestSavedBlockNumber } = await dbTx.blocks.getChain(\n client.chain.id,\n );\n\n if (maxBlockNumberBI !== undefined && head.number! >= maxBlockNumberBI) {\n logger.info({\n msg: `Head is greater than max block number`,\n collector,\n chainId: client.chain.id,\n block_number: head.number,\n max_block_number: maxBlockNumber,\n });\n\n await dbTx.blocks.handleReorg({\n chainId: client.chain.id,\n blockNumber: maxBlockNumber!,\n epoch: epoch + 1n,\n });\n\n isMaxBlockNumberReached = true;\n return isMaxBlockNumberReached;\n }\n\n finalizedBlock = await fetchFinalizedBlock({\n tick,\n client,\n logger,\n collector,\n unfinalizedBlocks,\n previousFinalizedBlock: finalizedBlock,\n });\n tick++;\n\n let {\n block: returnedBlock,\n didReorgHappened,\n unfinalizedBlocks: newUnfinalizedBlocks,\n } = await reconcile({\n client,\n block: head,\n unfinalizedBlocks,\n finalizedBlock,\n logger,\n collector,\n maxBatchSize,\n });\n\n unfinalizedBlocks = newUnfinalizedBlocks;\n const blockNumber = Number(returnedBlock.number);\n\n didReorgHappened = didReorgHappened || blockNumber < latestSavedBlockNumber;\n\n if (didReorgHappened) {\n await dbTx.blocks.handleReorg({\n chainId: client.chain.id,\n blockNumber,\n epoch: epoch + 1n,\n });\n } else {\n await dbTx.blocks.advanceChain({\n chainId: client.chain.id,\n blockNumber,\n epoch,\n });\n }\n });\n\n return isMaxBlockNumberReached;\n },\n };\n}\n\nconst commonAncestor = (block: Block, unfinalizedBlocks: LightBlock[]): LightBlock | null => {\n const parent = unfinalizedBlocks.find((b) => b.hash === block.parentHash);\n if (parent) return parent;\n return null;\n};\n\nconst fetchFinalizedBlock = async (parameters: {\n tick: number;\n client: PublicClient<Transport, Chain.Chain>;\n logger: Logger.Logger;\n collector: string;\n unfinalizedBlocks: LightBlock[];\n previousFinalizedBlock: LightBlock | null;\n}): Promise<LightBlock> => {\n let { tick, client, logger, collector, unfinalizedBlocks, previousFinalizedBlock } = parameters;\n let finalizedBlock: LightBlock | null = previousFinalizedBlock;\n if (tick % 20 === 0 || previousFinalizedBlock === null) {\n finalizedBlock = await client.getBlock({\n blockTag: \"finalized\",\n includeTransactions: false,\n });\n\n if (finalizedBlock === null || finalizedBlock.number === null) {\n const msg = \"Failed to get finalized block\";\n logger.fatal({ collector, chainId: client.chain.id, msg });\n throw new Error(msg);\n }\n\n unfinalizedBlocks = unfinalizedBlocks.filter((b) => b.number >= finalizedBlock!.number!);\n }\n\n if (\n finalizedBlock!.number === null ||\n finalizedBlock!.hash === null ||\n finalizedBlock!.parentHash === null\n ) {\n const msg = \"Failed to get finalized block\";\n logger.fatal({ collector, chainId: client.chain.id, msg });\n throw new Error(msg);\n }\n\n return {\n hash: finalizedBlock!.hash,\n number: finalizedBlock!.number,\n parentHash: finalizedBlock!.parentHash,\n };\n};\n\n// greatly inspired by Ponder `ReconcileBlock`\n// https://github.com/ponder-sh/ponder/blob/d0bdadee06ebd93f05903b5a692ad46fe95371b9/packages/core/src/sync-realtime/index.ts#L792\nconst reconcile = async (parameters: {\n block: Block;\n client: PublicClient<Transport, Chain.Chain>;\n collector: string;\n unfinalizedBlocks: LightBlock[];\n finalizedBlock: LightBlock;\n logger: Logger.Logger;\n maxBatchSize: number;\n}): Promise<{ block: LightBlock; didReorgHappened: boolean; unfinalizedBlocks: LightBlock[] }> => {\n let { client, block, unfinalizedBlocks, finalizedBlock, logger, collector, maxBatchSize } =\n parameters;\n\n const chain = client.chain;\n\n if (block.hash === null || block.number === null || block.parentHash === null)\n throw new Error(\"Failed to get block\");\n\n const latestBlock = unfinalizedBlocks[unfinalizedBlocks.length - 1];\n\n if (latestBlock === undefined) {\n const newBlock = {\n hash: block.hash,\n number: block.number,\n parentHash: block.parentHash,\n };\n unfinalizedBlocks.push(newBlock);\n return { block: newBlock, didReorgHappened: false, unfinalizedBlocks };\n }\n\n if (latestBlock.hash === block.hash)\n return { block: latestBlock, didReorgHappened: false, unfinalizedBlocks };\n\n if (latestBlock.number >= block.number) {\n const ancestor = commonAncestor(block, unfinalizedBlocks) || finalizedBlock;\n logger.info({\n msg: `Reorg detected, latestBlock.number >= block.number`,\n collector,\n chain_id: chain.id,\n ancestor: ancestor.number,\n latest_block_number: latestBlock.number,\n block_number: block.number,\n });\n unfinalizedBlocks = unfinalizedBlocks.filter((b) => b.number <= ancestor.number);\n return { block: ancestor, didReorgHappened: true, unfinalizedBlocks };\n }\n\n if (latestBlock.number + 1n < block.number) {\n logger.debug({\n collector,\n chain_id: chain.id,\n block_range: [latestBlock.number, block.number],\n msg: `Missing blocks`,\n });\n\n const missingBlockNumbers = (() => {\n const missingBlockNumbers = [];\n let start = latestBlock.number + 1n;\n const threshold =\n latestBlock.number + BigInt(maxBatchSize) > block.number\n ? block.number\n : latestBlock.number + BigInt(maxBatchSize);\n while (start < threshold) {\n missingBlockNumbers.push(start);\n start = start + 1n;\n }\n return missingBlockNumbers;\n })();\n\n const missingBlocks = await Promise.all(\n missingBlockNumbers.map((blockNumber) =>\n Utils.retry(async () => await client.getBlock({ blockNumber, includeTransactions: false })),\n ),\n );\n\n for (const missingBlock of missingBlocks) {\n const {\n block: returnedBlock,\n didReorgHappened,\n unfinalizedBlocks: newUnfinalizedBlocks,\n } = await reconcile({\n client,\n block: missingBlock,\n unfinalizedBlocks,\n finalizedBlock,\n logger,\n collector,\n maxBatchSize,\n });\n // if returned block is different from the missing block, return the block and stop the loop\n // this means that max block number was reached\n if (returnedBlock.number !== missingBlock.number)\n return { block: returnedBlock, didReorgHappened, unfinalizedBlocks: newUnfinalizedBlocks };\n }\n return reconcile({\n client,\n block,\n unfinalizedBlocks,\n finalizedBlock,\n logger,\n collector,\n maxBatchSize,\n });\n }\n\n if (block.parentHash !== latestBlock.hash) {\n const ancestor = commonAncestor(block, unfinalizedBlocks) || finalizedBlock;\n logger.info({\n msg: `Reorg detected, block parent hash !== latest block hash`,\n collector,\n chain_id: chain.id,\n ancestor: ancestor.number,\n latest_block_number: latestBlock.number,\n block_number: block.number,\n });\n unfinalizedBlocks = unfinalizedBlocks.filter((b) => b.number <= ancestor.number);\n return { block: ancestor, didReorgHappened: true, unfinalizedBlocks };\n }\n\n const newBlock = {\n hash: block.hash,\n number: block.number,\n parentHash: block.parentHash,\n };\n\n unfinalizedBlocks.push(newBlock);\n return { block: newBlock, didReorgHappened: false, unfinalizedBlocks };\n};\n","import type { PublicClient, Transport } from \"viem\";\nimport type { Chain } from \"#core\";\nimport type { Database } from \"#database/index.ts\";\nimport * as Logger from \"#logger/Logger.ts\";\nimport { Tracer } from \"#tracer/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\nimport * as Admin from \"./Admin.ts\";\n\nexport const names = [\"offers\", \"consumed_events\", \"positions\", \"prices\"] as const;\n\nexport type Name = (typeof names)[number];\n\n/** A general collector interface. */\nexport type Collector<\n name extends Name = Name,\n client extends PublicClient<Transport, Chain.Chain> = PublicClient<Transport, Chain.Chain>,\n> = {\n /** The name of the collector. */\n readonly name: name;\n\n /** The chain the collector is running on. */\n readonly chain: client[\"chain\"];\n\n /** The public client used to query chain head. */\n readonly client: client;\n\n /** The database connection for collector metadata. */\n readonly db: Database.Database;\n\n /** The normal polling interval (ms) for this collector. */\n readonly interval: number;\n\n /** Start collecting data from external sources.\n * @yields The last block number processed by the collector.\n */\n collect: () => AsyncGenerator<number, void, void>;\n};\n\n/** A collector’s collect function signature */\nexport type CollectFn<\n collector extends Name,\n client extends PublicClient<Transport, Chain.Chain> = PublicClient<Transport, Chain.Chain>,\n> = (parameters: CollectParameters<collector, client>) => AsyncGenerator<number, void, void>;\n\n/** Core parameters every collector gets at runtime */\nexport type CollectParameters<\n collector extends Name,\n client extends PublicClient<Transport, Chain.Chain> = PublicClient<Transport, Chain.Chain>,\n> = {\n /** A public viem client with a defined chain. */\n client: client;\n /** The collector name. */\n collector: collector;\n /** The epoch the collector is running on. */\n epoch: bigint;\n /** The last block number processed by the collector. */\n lastBlockNumber: number;\n /** The database connection. */\n db: Database.Database;\n};\n\nexport function create<\n name extends Name,\n client extends PublicClient<Transport, Chain.Chain> = PublicClient<Transport, Chain.Chain>,\n>({\n name,\n collect,\n client,\n db,\n options,\n}: {\n name: name;\n collect: CollectFn<name, client>;\n client: client;\n db: Database.Database;\n options: { maxBlockNumber?: number; interval?: number };\n}): Collector<name, client> {\n const admin = Admin.create({\n client,\n db,\n options,\n });\n\n const chain = client.chain;\n const interval = options.interval ?? 10_000;\n\n return {\n name,\n chain,\n client,\n db,\n interval,\n collect: async function* () {\n const collector = name;\n const chain = client.chain;\n const logger = Logger.getLogger();\n const collectorId = `${client.chain.id.toString()}.collector.${collector}`;\n const tracer = Tracer.getTracer(`router.${collectorId}`);\n\n logger.info({\n msg: `Collector started`,\n collector,\n chain_id: chain.id,\n });\n\n let iterator: AsyncGenerator<number, void, void> | null = null;\n let lastBlockNumber: number | undefined;\n while (true) {\n try {\n if (iterator === null) {\n iterator = await Tracer.startActiveSpan(tracer, `${collectorId}.init`, async () => {\n const { collector: collectorBlock } = await db.blocks.init({\n collectorName: name,\n chainId: chain.id,\n });\n\n lastBlockNumber = collectorBlock.blockNumber;\n\n return collect({\n client,\n collector: name,\n epoch: collectorBlock.epoch,\n lastBlockNumber,\n db,\n });\n });\n }\n\n // important to sync block before collecting in case of reorg\n // epoch will be updated by syncBlock and the collector will be blocked when trying to save block number\n const isMaxBlockNumberReached = await Tracer.startActiveSpan(\n tracer,\n `${collectorId}.syncBlock`,\n async (span) => {\n const isMaxBlockNumberReached = await admin.syncBlock();\n span.setAttribute(\"collector.is_max_block_reached\", isMaxBlockNumberReached);\n return isMaxBlockNumberReached;\n },\n );\n\n if (\n isMaxBlockNumberReached &&\n options.maxBlockNumber !== undefined &&\n lastBlockNumber !== undefined &&\n options.maxBlockNumber === lastBlockNumber\n )\n return;\n\n const { blockNumber, done } = await Tracer.startActiveSpan(\n tracer,\n `${collectorId}.next`,\n async () => {\n if (iterator === null) throw new Error(\"Iterator is not initialized\");\n const { value: blockNumber, done } = await iterator.next();\n return { blockNumber, done };\n },\n );\n\n if (done) {\n iterator = null;\n } else {\n lastBlockNumber = blockNumber!;\n yield blockNumber!;\n }\n } catch (err) {\n const isError = err instanceof Error;\n logger.error({\n msg: \"Collector error\",\n collector,\n chain_id: chain.id,\n error: isError ? err.message : String(err),\n stack: isError ? err.stack : undefined,\n });\n }\n }\n },\n };\n}\n\n/** Start a collector with its own polling cadence based on chain head lag.\n * @param collector - The collector to start.\n * @returns A function to stop the collector.\n */\nexport function start(collector: Collector): () => void {\n let stopped = false;\n const it = collector.collect();\n const logger = Logger.getLogger();\n const collectorId = `${collector.chain.id.toString()}.collector.${collector.name}`;\n const tracer = Tracer.getTracer(`router.${collectorId}`);\n const blocks = collector.db.blocks;\n let initialized = false;\n\n (async () => {\n while (!stopped) {\n try {\n await Tracer.startActiveSpan(tracer, `${collectorId}.poll`, async () => {\n if (!initialized) {\n await blocks.init({\n chainId: collector.chain.id,\n collectorName: collector.name,\n });\n initialized = true;\n }\n const [block, { blockNumber: collectorBlockNumber }] = await Promise.all([\n collector.client.getBlock({\n blockTag: \"latest\",\n includeTransactions: false,\n }),\n blocks.getCollector({\n collectorName: collector.name,\n chainId: collector.chain.id,\n }),\n ]);\n\n const chainBlockNumber = Number(block.number);\n const delay = chainBlockNumber > collectorBlockNumber + 10 ? 250 : collector.interval;\n\n const waitSpan = tracer.startSpan(`${collectorId}.wait`);\n try {\n await Utils.wait(delay);\n } finally {\n waitSpan.end();\n }\n\n await it.next();\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n logger.error({\n msg: \"Collector polling error\",\n collector: collector.name,\n chain_id: collector.chain.id,\n err: error,\n });\n }\n }\n await it.return();\n })();\n\n return () => {\n stopped = true;\n };\n}\n","import { parseAbi } from \"viem\";\n\nexport const MetaMorpho = parseAbi([\n \"function balanceOf(address account) view returns (uint256)\",\n \"function DECIMALS_OFFSET() view returns (uint8)\",\n \"function totalAssets() view returns (uint256)\",\n \"function totalSupply() view returns (uint256)\",\n \"function maxWithdraw(address owner) view returns (uint256 assets)\",\n \"function asset() view returns (address)\",\n \"event Transfer(address indexed from, address indexed to, uint256 value)\",\n \"function withdrawQueue(uint256 index) view returns (bytes32)\",\n \"function withdrawQueueLength() view returns (uint256)\",\n]);\nexport type MetaMorpho = typeof MetaMorpho;\n","import { parseAbi } from \"viem\";\n\nexport const MetaMorphoFactory = parseAbi([\n \"event CreateMetaMorpho(address indexed metaMorpho,address indexed caller,address initialOwner,uint256 initialTimelock,address indexed asset,string name,string symbol,bytes32 salt)\",\n \"function isMetaMorpho(address) view returns (bool)\",\n]);\nexport type MetaMorphoFactory = typeof MetaMorphoFactory;\n","import { parseAbi } from \"viem\";\n\nexport const MorphoV2 = parseAbi([\n \"constructor()\",\n \"function collateralOf(bytes32 id, address user, address collateralToken) view returns (uint256)\",\n \"function consume(bytes32 group, uint256 amount)\",\n \"function consumed(address user, bytes32 group) view returns (uint256)\",\n \"function debtOf(bytes32 id, address user) view returns (uint256)\",\n \"function defaultFees(address loanToken, uint256 index) view returns (uint16)\",\n \"function feeSetter() view returns (address)\",\n \"function fees(bytes32 id) view returns (uint16[6])\",\n \"function flashLoan(address token, uint256 assets, address callback, bytes data)\",\n \"function isHealthy((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, bytes32 id, address borrower) view returns (bool)\",\n \"function liquidate((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, (uint256 collateralIndex, uint256 repaid, uint256 seized)[] seizures, address borrower, bytes data) returns ((uint256 collateralIndex, uint256 repaid, uint256 seized)[])\",\n \"function multicall(bytes[] calls)\",\n \"function obligationCreated(bytes32 id) view returns (bool)\",\n \"function obligationState(bytes32 id) view returns (uint128 totalUnits, uint128 totalShares, uint256 withdrawable, bool created)\",\n \"function owner() view returns (address)\",\n \"function repay((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, uint256 obligationUnits, address onBehalf)\",\n \"function session(address user) view returns (bytes32)\",\n \"function setDefaultTradingFee(address loanToken, uint256 index, uint256 newTradingFee)\",\n \"function setFeeSetter(address newFeeSetter)\",\n \"function setObligationTradingFee(bytes32 id, uint256 index, uint256 newTradingFee)\",\n \"function setOwner(address newOwner)\",\n \"function setTradingFeeRecipient(address recipient)\",\n \"function sharesOf(bytes32 id, address user) view returns (uint256)\",\n \"function shuffleSession()\",\n \"function supplyCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, address collateral, uint256 assets, address onBehalf)\",\n \"function take(uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, uint256 obligationShares, address taker, ((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, bool buy, address maker, uint256 assets, uint256 obligationUnits, uint256 obligationShares, uint256 start, uint256 expiry, uint256 tick, bytes32 group, bytes32 session, address callback, bytes callbackData) offer, (uint8 v, bytes32 r, bytes32 s) sig, bytes32 root, bytes32[] proof, address takerCallback, bytes takerCallbackData) returns (uint256, uint256, uint256, uint256)\",\n \"function totalShares(bytes32 id) view returns (uint256)\",\n \"function totalUnits(bytes32 id) view returns (uint256)\",\n \"function touchObligation((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation) returns (bytes32)\",\n \"function tradingFee(bytes32 id, uint256 timeToMaturity) view returns (uint256)\",\n \"function tradingFeeRecipient() view returns (address)\",\n \"function withdraw((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, uint256 obligationUnits, uint256 shares, address onBehalf) returns (uint256, uint256)\",\n \"function withdrawCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, address collateral, uint256 assets, address onBehalf)\",\n \"function withdrawable(bytes32 id) view returns (uint256)\",\n \"event Constructor(address indexed owner)\",\n \"event Consume(address indexed user, bytes32 indexed group, uint256 amount)\",\n \"event FlashLoan(address indexed caller, address indexed token, uint256 assets)\",\n \"event Liquidate(address indexed caller, bytes32 indexed id, (uint256 collateralIndex, uint256 repaid, uint256 seized)[] seizures, address indexed borrower, uint256 totalRepaid, uint256 badDebt)\",\n \"event ObligationCreated(bytes32 indexed id, (address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation)\",\n \"event Repay(address indexed caller, bytes32 indexed id, uint256 obligationUnits, address indexed onBehalf)\",\n \"event SetDefaultTradingFee(address indexed loanToken, uint256 indexed index, uint256 newTradingFee)\",\n \"event SetFeeSetter(address indexed feeSetter)\",\n \"event SetObligationTradingFee(bytes32 indexed id, uint256 indexed index, uint256 newTradingFee)\",\n \"event SetOwner(address indexed owner)\",\n \"event SetTradingFeeRecipient(address indexed recipient)\",\n \"event ShuffleSession(address indexed user, bytes32 session)\",\n \"event SupplyCollateral(address caller, bytes32 indexed id, address indexed collateral, uint256 assets, address indexed onBehalf)\",\n \"event Take(address caller, bytes32 indexed id, address indexed maker, address indexed taker, bool offerIsBuy, uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, uint256 obligationShares, bool buyerIsLender, bool sellerIsBorrower, bytes32 group, uint256 consumed)\",\n \"event Withdraw(address indexed caller, bytes32 indexed id, uint256 obligationUnits, uint256 shares, address indexed onBehalf)\",\n \"event WithdrawCollateral(address caller, bytes32 indexed id, address indexed collateral, uint256 assets, address indexed onBehalf)\",\n]);\nexport type MorphoV2 = typeof MorphoV2;\n","export * from \"./MetaMorpho.ts\";\nexport * from \"./MetaMorphoFactory.ts\";\nexport * from \"./MorphoV2.ts\";\n\nexport const Oracle = [\n {\n type: \"function\",\n name: \"price\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n },\n] as const;\n\nexport const ERC4626 = [\n {\n type: \"function\",\n name: \"asset\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\" }],\n stateMutability: \"view\",\n },\n] as const;\n\nexport const Morpho = [\n {\n type: \"function\",\n name: \"collateralOf\",\n inputs: [\n {\n name: \"\",\n type: \"address\",\n internalType: \"address\",\n },\n {\n name: \"\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n {\n name: \"\",\n type: \"address\",\n internalType: \"address\",\n },\n ],\n outputs: [\n {\n name: \"\",\n type: \"uint256\",\n internalType: \"uint256\",\n },\n ],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"debtOf\",\n inputs: [\n {\n name: \"\",\n type: \"address\",\n internalType: \"address\",\n },\n {\n name: \"\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n ],\n outputs: [\n {\n name: \"\",\n type: \"uint256\",\n internalType: \"uint256\",\n },\n ],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"market\",\n inputs: [\n {\n name: \"id\",\n type: \"bytes32\",\n internalType: \"Id\",\n },\n ],\n outputs: [\n {\n name: \"totalSupplyAssets\",\n type: \"uint128\",\n internalType: \"uint128\",\n },\n {\n name: \"totalSupplyShares\",\n type: \"uint128\",\n internalType: \"uint128\",\n },\n {\n name: \"totalBorrowAssets\",\n type: \"uint128\",\n internalType: \"uint128\",\n },\n {\n name: \"totalBorrowShares\",\n type: \"uint128\",\n internalType: \"uint128\",\n },\n {\n name: \"lastUpdate\",\n type: \"uint128\",\n internalType: \"uint128\",\n },\n {\n name: \"fee\",\n type: \"uint128\",\n internalType: \"uint128\",\n },\n ],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"position\",\n inputs: [\n {\n name: \"id\",\n type: \"bytes32\",\n internalType: \"Id\",\n },\n {\n name: \"user\",\n type: \"address\",\n internalType: \"address\",\n },\n ],\n outputs: [\n {\n name: \"supplyShares\",\n type: \"uint256\",\n internalType: \"uint256\",\n },\n {\n name: \"borrowShares\",\n type: \"uint128\",\n internalType: \"uint128\",\n },\n {\n name: \"collateral\",\n type: \"uint128\",\n internalType: \"uint128\",\n },\n ],\n stateMutability: \"view\",\n },\n] as const;\n","import type { Offer } from \"./index.ts\";\n\nexport type Callback = { type: Type.BuyWithEmptyCallback } | { type: Type.SellWithEmptyCallback };\n\nexport enum Type {\n BuyWithEmptyCallback = \"buy_with_empty_callback\",\n SellWithEmptyCallback = \"sell_with_empty_callback\",\n}\n\nexport const isEmptyCallback = (offer: Offer.Offer): boolean => offer.callback.data === \"0x\";\n","import type {\n AbiEvent,\n Address,\n ChainContract,\n ChainFormatters,\n GetLogsReturnType,\n PublicClient,\n} from \"viem\";\nimport { getBlock, getLogs } from \"viem/actions\";\nimport {\n type Chain as ViemChain,\n anvil as viemAnvil,\n base as viemBase,\n mainnet as viemEthereum,\n} from \"viem/chains\";\nimport type { Compute } from \"#core\";\nimport * as BigMath from \"#utils/BigMath.ts\";\nimport { batch } from \"#utils/batch.ts\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport type * as Callback from \"./Callback.ts\";\n\nexport type Chain = Compute<\n Omit<\n ViemChain<\n ChainFormatters,\n {\n morpho: ChainContract;\n morphoBlue: ChainContract;\n mempool: ChainContract;\n vaults: { factories: { v1_0: ChainContract; v1_1: ChainContract } };\n callbacks: Callback.Callback[];\n }\n >,\n \"custom\"\n > & {\n id: Id;\n name: Name;\n custom: {\n morpho: ChainContract;\n morphoBlue: ChainContract;\n mempool: ChainContract;\n vaults: { factories: { v1_0: ChainContract; v1_1: ChainContract } };\n callbacks: Callback.Callback[];\n };\n }\n>;\n\nexport const ChainId = {\n ETHEREUM: 1,\n BASE: 8453,\n \"ETHEREUM-VIRTUAL-TESTNET\": 109111114,\n ANVIL: 505050505, // random id to not clash with other chains\n} as const;\n\nexport type Name = Lowercase<keyof typeof ChainId>;\nexport const chainNames = Object.keys(ChainId).map((key) => key.toLowerCase()) as readonly Name[];\n\nexport type Id = (typeof ChainId)[Uppercase<Name>];\nexport const chainIds = Object.values(ChainId) as readonly Id[];\n\nconst chainNameLookup: Map<Id, Name> = new Map(\n Object.entries(ChainId).map(([key, value]) => [value, key.toLowerCase() as Name]),\n);\n\nexport function getChain(chainId: Id): Chain | undefined {\n const chainName = chainNameLookup.get(chainId);\n if (!chainName) return undefined;\n return chains[chainName];\n}\n\nexport const getWhitelistedChains = (): Chain[] => {\n return [chains.ethereum, chains.base, chains[\"ethereum-virtual-testnet\"], chains.anvil];\n};\n\nexport const chains: Record<Lowercase<Name>, Chain> = {\n ethereum: {\n ...viemEthereum,\n id: ChainId.ETHEREUM,\n name: \"ethereum\",\n custom: {\n morpho: { address: \"0x0000000000000000000000000000000000000000\", blockCreated: 0 },\n morphoBlue: { address: \"0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb\", blockCreated: 0 },\n mempool: {\n address: \"0x0000000000000000000000000000000000000000\",\n blockCreated: 23347674,\n },\n vaults: {\n factories: {\n v1_0: {\n address: \"0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101\",\n blockCreated: 18925584,\n },\n v1_1: {\n address: \"0x1897A8997241C1cD4bD0698647e4EB7213535c24\",\n blockCreated: 21439510,\n },\n },\n },\n callbacks: [],\n },\n },\n base: {\n ...viemBase,\n id: ChainId.BASE,\n name: \"base\",\n custom: {\n morpho: { address: \"0x0000000000000000000000000000000000000000\", blockCreated: 0 },\n morphoBlue: { address: \"0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb\", blockCreated: 0 },\n mempool: {\n address: \"0x0000000000000000000000000000000000000000\",\n blockCreated: 35449942,\n },\n vaults: {\n factories: {\n v1_0: {\n address: \"0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101\",\n blockCreated: 13978134,\n },\n v1_1: {\n address: \"0xFf62A7c278C62eD665133147129245053Bbf5918\",\n blockCreated: 23928808,\n },\n },\n },\n callbacks: [],\n },\n },\n \"ethereum-virtual-testnet\": {\n ...viemEthereum,\n id: ChainId[\"ETHEREUM-VIRTUAL-TESTNET\"],\n name: \"ethereum-virtual-testnet\",\n custom: {\n morpho: { address: \"0x634b095371e4e45feed94c1a45c37798e173ea50\", blockCreated: 23226700 },\n morphoBlue: { address: \"0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb\", blockCreated: 0 },\n mempool: {\n address: \"0x5b06224f736a57635b5bcb50b8ef178b189107cb\",\n blockCreated: 23224302,\n },\n vaults: {\n factories: {\n v1_0: {\n address: \"0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101\", //v1.0\n blockCreated: 18925584,\n },\n v1_1: {\n address: \"0x1897A8997241C1cD4bD0698647e4EB7213535c24\", //v1.1\n blockCreated: 21439510,\n },\n },\n },\n callbacks: [],\n },\n },\n anvil: {\n ...viemAnvil,\n id: ChainId.ANVIL,\n name: \"anvil\",\n custom: {\n morpho: { address: \"0x23DFBc4B8B80C14CC5e25011B8491f268395BAd6\", blockCreated: 0 },\n morphoBlue: { address: \"0x0000000000000000000000000000000000000000\", blockCreated: 0 }, // Set dynamically in tests\n mempool: {\n address: \"0xD946246695A9259F3B33a78629026F61B3Ab40aF\",\n blockCreated: 23223727,\n },\n vaults: {\n factories: {\n v1_0: {\n address: \"0x0000000000000000000000000000000000000000\",\n blockCreated: 0,\n },\n v1_1: {\n address: \"0x0000000000000000000000000000000000000000\",\n blockCreated: 0,\n },\n },\n },\n callbacks: [],\n },\n },\n};\n\n// thresholds are set to align with Alchemy's thresholds\n//https://www.alchemy.com/docs/deep-dive-into-eth_getlogs#making-a-request-to-eth_getlogs\nconst MAX_BATCH_SIZE = 10_000;\nconst DEFAULT_BATCH_SIZE = 2_500;\nconst MAX_BLOCK_WINDOW = 10_000;\nconst DEFAULT_BLOCK_WINDOW = 8_000;\n\nexport async function* streamLogs<abiEvent extends AbiEvent | undefined = undefined>(parameters: {\n client: PublicClient;\n contractAddress?: Address;\n event?: abiEvent;\n blockNumberGte?: number;\n blockNumberLte?: number;\n order: \"asc\" | \"desc\";\n options: {\n maxBatchSize?: number;\n blockWindow?: number;\n };\n}): AsyncGenerator<\n { logs: GetLogsReturnType<abiEvent | undefined>; blockNumber: number },\n void,\n void\n> {\n const {\n client,\n contractAddress,\n event,\n blockNumberGte,\n blockNumberLte,\n order = \"desc\",\n options: { maxBatchSize = DEFAULT_BATCH_SIZE, blockWindow = DEFAULT_BLOCK_WINDOW } = {},\n } = parameters;\n if (maxBatchSize > MAX_BATCH_SIZE) throw new InvalidBatchSizeError(maxBatchSize);\n if (blockWindow > MAX_BLOCK_WINDOW) throw new InvalidBlockWindowError(blockWindow);\n if (order === \"asc\" && blockNumberGte === undefined) throw new MissingBlockNumberError();\n\n const latestBlock = (await getBlock(client, { blockTag: \"latest\", includeTransactions: false }))\n .number;\n\n let toBlock = 0n;\n if (order === \"asc\")\n toBlock = BigMath.min(\n BigInt(blockNumberGte!) + BigInt(blockWindow),\n blockNumberLte ? BigInt(blockNumberLte!) : latestBlock,\n );\n if (order === \"desc\")\n toBlock =\n blockNumberLte === undefined\n ? latestBlock\n : BigMath.min(BigInt(blockNumberLte!), latestBlock);\n\n let fromBlock = 0n;\n if (order === \"asc\") fromBlock = BigMath.min(BigInt(blockNumberGte!), latestBlock);\n if (order === \"desc\")\n fromBlock = BigMath.max(BigInt(blockNumberGte || toBlock - BigInt(blockWindow)), 0n);\n\n if (order === \"asc\") toBlock = BigMath.min(toBlock, fromBlock + BigInt(blockWindow));\n if (order === \"desc\") fromBlock = BigMath.max(fromBlock, toBlock - BigInt(blockWindow));\n if (fromBlock > toBlock) throw new InvalidBlockRangeError(fromBlock, toBlock);\n\n let streaming = true;\n while (streaming) {\n const logs = await getLogs(client, {\n address: contractAddress,\n event,\n fromBlock,\n toBlock,\n });\n\n streaming =\n order === \"asc\"\n ? toBlock < (blockNumberLte || latestBlock)\n : fromBlock > (blockNumberGte || 0n);\n\n if (logs.length === 0 && !streaming) {\n break;\n }\n\n if (logs.length === 0 && streaming) {\n yield { logs: [], blockNumber: order === \"asc\" ? Number(toBlock) : Number(fromBlock) };\n }\n\n logs.sort((a, b) => {\n if (a.blockNumber !== b.blockNumber)\n return order === \"asc\"\n ? Number(a.blockNumber - b.blockNumber)\n : Number(b.blockNumber - a.blockNumber);\n if (a.transactionIndex !== b.transactionIndex)\n return order === \"asc\"\n ? a.transactionIndex - b.transactionIndex\n : b.transactionIndex - a.transactionIndex;\n return order === \"asc\" ? a.logIndex - b.logIndex : b.logIndex - a.logIndex;\n });\n\n for (const logBatch of batch(logs, maxBatchSize)) {\n yield {\n logs: logBatch,\n blockNumber:\n logBatch.length === maxBatchSize\n ? // if the batch is full, return the last block number, block numbers are always sorted\n Number(logBatch[logBatch.length - 1]?.blockNumber)\n : // if the batch is not full, return `toBlock` or `fromBlock` to indicate until which block the logs were fetched\n order === \"asc\"\n ? Number(toBlock)\n : Number(fromBlock),\n };\n }\n\n if (order === \"asc\") {\n const upperBound = BigInt(blockNumberLte || latestBlock);\n const nextFromBlock = BigMath.min(BigInt(toBlock) + 1n, upperBound);\n const nextToBlock = BigMath.min(toBlock + BigInt(blockWindow) + 1n, upperBound);\n fromBlock = nextFromBlock;\n toBlock = nextToBlock;\n }\n\n if (order === \"desc\") {\n const lowerBound = BigInt(blockNumberGte || 0);\n const nextToBlock = BigMath.max(fromBlock - 1n, lowerBound);\n const nextFromBlock = BigMath.max(fromBlock - BigInt(blockWindow) - 1n, lowerBound);\n toBlock = nextToBlock;\n fromBlock = nextFromBlock;\n }\n }\n\n yield { logs: [], blockNumber: order === \"asc\" ? Number(toBlock) : Number(fromBlock) };\n return;\n}\n\nexport class InvalidBlockRangeError extends Errors.BaseError {\n override name = \"Chain.InvalidBlockRangeError\";\n constructor(fromBlock: bigint, toBlock: bigint) {\n super(\n `Invalid block range while streaming data from chain. From block ${fromBlock} to block ${toBlock}.`,\n );\n }\n}\n\nexport class InvalidBlockWindowError extends Errors.BaseError {\n override name = \"Chain.InvalidBlockWindowError\";\n constructor(blockWindow: number) {\n super(\n `Invalid block window while streaming data from chain. Maximum is ${MAX_BLOCK_WINDOW}. Got ${blockWindow}.`,\n );\n }\n}\n\nexport class InvalidBatchSizeError extends Errors.BaseError {\n override name = \"Chain.InvalidBatchSizeError\";\n constructor(maxBatchSize: number) {\n super(\n `Invalid batch size while streaming data from chain. Maximum is ${MAX_BATCH_SIZE}. Got ${maxBatchSize}.`,\n );\n }\n}\n\nexport class MissingBlockNumberError extends Errors.BaseError {\n override name = \"Chain.MissingBlockNumberError\";\n constructor() {\n super(\"Missing block number when streaming data from chain in ascending order.\");\n }\n}\n","import type * as Chain from \"./Chain.ts\";\n\nexport type ChainRegistry = {\n getById: (chainId: Chain.Id) => Chain.Chain | undefined;\n list: () => Chain.Chain[];\n};\n\n/**\n * Creates a chain registry from a list of chains.\n * @param chains - Array of chain objects to register.\n * @returns A registry for looking up chains by ID. {@link ChainRegistry}\n */\nexport function create(chains: Chain.Chain[]): ChainRegistry {\n const byId = new Map<Chain.Id, Chain.Chain>();\n for (const chain of chains) {\n byId.set(chain.id, chain);\n }\n\n return {\n getById: (chainId: Chain.Id) => byId.get(chainId),\n list: () => Array.from(byId.values()),\n };\n}\n","import { type Address, type Hex, isAddress, isHex, numberToHex, pad } from \"viem\";\nimport * as z from \"zod\";\n\n/**\n * Converts a hex string to a padded bytes32.\n * Returns null if the value is not a valid hex string.\n */\nconst hexToBytes32 = (val: string): Hex | null => {\n if (!isHex(val)) return null;\n return pad(val as Hex, { size: 32 });\n};\n\n/**\n * Converts a numeric string to a padded bytes32.\n * @throws {Error} If parsing fails or value is negative.\n */\nconst numericStringToBytes32 = (val: string): Hex => {\n const num = BigInt(val);\n if (num < 0n) throw new Error(\"expected bigint to be >=0\");\n return pad(numberToHex(num), { size: 32 });\n};\n\n/**\n * Converts a number or bigint to a padded bytes32.\n * @throws {Error} If value is negative.\n */\nconst numericToBytes32 = (val: number | bigint): Hex => {\n const num = BigInt(val);\n if (num < 0n) throw new Error(\"expected bigint to be >=0\");\n return pad(numberToHex(num), { size: 32 });\n};\n\n/**\n * Transforms a value to a bytes32 hex string.\n * Accepts:\n * - Hex strings (0x...) - pads to 32 bytes if needed\n * - Numeric strings - converts to padded hex\n * - Numbers/bigints - converts to padded hex (must be non-negative)\n */\nexport const transformBytes32 = (val: string | number | bigint, ctx: z.RefinementCtx): Hex => {\n if (typeof val === \"string\") {\n const hexResult = hexToBytes32(val);\n if (hexResult !== null) return hexResult;\n\n try {\n return numericStringToBytes32(val);\n } catch (error) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Not a valid bytes32 value: ${error instanceof Error ? error.message : String(error)}`,\n });\n return z.NEVER;\n }\n }\n\n if (typeof val === \"number\" || typeof val === \"bigint\") {\n try {\n return numericToBytes32(val);\n } catch (error) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Too small: ${error instanceof Error ? error.message : String(error)}`,\n });\n return z.NEVER;\n }\n }\n\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: \"Not a valid bytes32 value\",\n });\n\n return z.NEVER;\n};\n\nexport const transformHex = (val: string, ctx: z.RefinementCtx) => {\n if (isHex(val)) return val;\n\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: \"Invalid hex\",\n });\n\n return z.NEVER;\n};\n\nexport const transformAddress = (val: string, ctx: z.RefinementCtx) => {\n if (isAddress(val.toLowerCase())) return val.toLowerCase() as Address;\n\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: \"Invalid address\",\n });\n\n return z.NEVER;\n};\n","import * as z from \"zod\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport type { Brand } from \"./types.ts\";\n\nexport type LLTV = bigint & Brand<\"LLTV\">;\n\nexport const Options = [0.385, 0.5, 0.625, 0.77, 0.86, 0.915, 0.945, 0.965, 0.98] as const;\nexport type Options = (typeof Options)[number];\nconst LLTV_SCALED = Options.map((lltv) => BigInt(lltv * 10 ** 18));\n\n/**\n * Convert a LLTV option or a scaled LLTV to a LLTV.\n * @param lltv - The LLTV option or the scaled LLTV.\n * @returns The LLTV.\n */\nexport function from(lltv: Options | bigint): LLTV {\n if (typeof lltv === \"bigint\" && !LLTV_SCALED.includes(lltv)) throw new InvalidLLTVError(lltv);\n if (typeof lltv === \"bigint\") return lltv as LLTV;\n if (typeof lltv === \"number\" && !Options.includes(lltv)) throw new InvalidOptionError(lltv);\n return BigInt(lltv * 10 ** 18) as LLTV;\n}\n\nexport declare namespace from {\n type ErrorType = InvalidOptionError | InvalidLLTVError;\n}\n\nexport class InvalidOptionError extends Errors.BaseError {\n override readonly name = \"LLTV.InvalidOptionError\";\n constructor(input: number) {\n super(\n `Invalid LLTV option. Input: \"${input}\". Accepted values are: ${Options.map(\n (option) => `\"${option}\"`,\n ).join(\", \")}.`,\n );\n }\n}\n\nexport class InvalidLLTVError extends Errors.BaseError {\n override readonly name = \"LLTV.InvalidLLTVError\";\n constructor(input: bigint) {\n super(\n `Invalid LLTV. Input: \"${input}\". Accepted values are: ${LLTV_SCALED.map(\n (option) => `\"${option}\"`,\n ).join(\", \")}.`,\n );\n }\n}\n\nexport const LLTVSchema = z\n .bigint({ coerce: true })\n .refine(\n (lltv) => {\n try {\n from(lltv);\n return true;\n } catch (_) {\n return false;\n }\n },\n {\n error: () => {\n return \"Invalid LLTV: must be one of 0.385, 0.625, 0.77, 0.86, 0.915, 0.945, 0.965 or 0.98 (scaled by 1e18)\";\n },\n },\n )\n .transform((lltv) => from(lltv));\n","import type { Address } from \"viem\";\nimport * as z from \"zod\";\nimport * as Random from \"#utils/Random.ts\";\nimport { transformAddress } from \"#utils/zod.ts\";\nimport * as LLTV from \"./LLTV.ts\";\n\nexport type Collateral = {\n /** Asset being used as collateral. */\n asset: Address;\n /** Liquidation Loan-to-Value of the collateral. */\n lltv: LLTV.LLTV;\n /** Oracle contract used to price the collateral. */\n oracle: Address;\n};\n\nexport const CollateralSchema = z.object({\n asset: z.string().transform(transformAddress),\n oracle: z.string().transform(transformAddress),\n lltv: LLTV.LLTVSchema,\n});\n\nexport const CollateralsSchema = z\n .array(CollateralSchema)\n .min(1, { message: \"At least one collateral is required\" })\n .refine(\n (collaterals) => {\n for (let i = 1; i < collaterals.length; i++) {\n if (collaterals[i - 1]!.asset.toLowerCase() > collaterals[i]!.asset.toLowerCase()) {\n return false;\n }\n }\n return true;\n },\n {\n message: \"Collaterals must be sorted alphabetically by address\",\n },\n )\n .refine(\n (collaterals) => {\n const uniqueAssets = new Set<string>();\n for (const collateral of collaterals) {\n const assetAddress = collateral.asset.toLowerCase();\n if (uniqueAssets.has(assetAddress)) {\n return false;\n }\n uniqueAssets.add(assetAddress);\n }\n return true;\n },\n {\n message: \"Collaterals must not contain duplicate assets\",\n },\n );\n\nexport const from = (parameters: from.Parameters): from.ReturnType => {\n return {\n asset: parameters.asset.toLowerCase() as Address,\n lltv: LLTV.from(parameters.lltv),\n oracle: parameters.oracle.toLowerCase() as Address,\n };\n};\n\nexport declare namespace from {\n type Parameters = {\n asset: Address;\n lltv: LLTV.Options | bigint;\n oracle: Address;\n };\n type ReturnType = Collateral;\n}\n\n/**\n * Generates a random collateral.\n * @returns A randomly generated collateral. {@link random.ReturnType}\n *\n * @example\n * ```ts\n * const collateral = Collateral.random();\n * ```\n */\nexport function random(): random.ReturnType {\n return from({\n asset: Random.address(),\n oracle: Random.address(),\n lltv: 0.965,\n });\n}\n\nexport declare namespace random {\n type ReturnType = Collateral;\n}\n","import * as Errors from \"#utils/Errors.ts\";\n\n/**\n * Calculate the decimals offset used by the ERC4626 implementation.\n * @param parameters - {@link decimalsOffset.Parameters}.\n * @returns The decimals offset.\n *\n * @example\n * ```ts\n * const decimalsOffset = decimalsOffset({ underlyingDecimals: 6 });\n * // decimalsOffset = 12\n * ```\n */\nexport function decimalsOffset(parameters: decimalsOffset.Parameters): number {\n return Math.max(0, 18 - parameters.underlyingDecimals);\n}\n\nexport declare namespace decimalsOffset {\n type Parameters = {\n /** The number of decimals of the underlying asset. */\n underlyingDecimals: number;\n };\n type ReturnType = number;\n}\n\n/**\n * Convert shares to assets.\n * @throws If the denominator is 0. {@link DenominatorIsZeroError}\n * @param parameters - {@link convertToAssets.Parameters}.\n * @returns The amount of assets.\n *\n * @example\n * ```ts\n * const assets = convertToAssets(100n, { totalAssets: 1000n, totalSupply: 1000n, decimalsOffset: 18 });\n * // assets = 100n\n * ```\n */\nexport function convertToAssets(\n parameters: convertToAssets.Parameters,\n): convertToAssets.ReturnType {\n const denominator = parameters.totalSupply + 10n ** BigInt(parameters.decimalsOffset);\n if (denominator === 0n) throw new DenominatorIsZeroError();\n\n return (parameters.shares * (parameters.totalAssets + 1n)) / denominator;\n}\n\nexport declare namespace convertToAssets {\n type Parameters = {\n /** The amount of shares to convert. */\n shares: bigint;\n /** Total amount of assets in the vault. */\n totalAssets: bigint;\n /** Total amount of shares in the vault. */\n totalSupply: bigint;\n /**\n * OpenZeppelin decimals offset used by the ERC4626 implementation.\n * Calculated to be `max(0, 18 - underlyingDecimals)` at construction, so the initial conversion rate maximizes\n * precision between shares and assets.\n */\n decimalsOffset: number;\n };\n type ReturnType = bigint;\n type ErrorType = DenominatorIsZeroError;\n}\n\n/**\n * Convert assets to shares.\n * @throws If the denominator is 0. {@link DenominatorIsZeroError}\n * @param parameters - {@link convertToShares.Parameters}.\n * @returns The amount of shares.\n *\n * @example\n * ```ts\n * const shares = convertToShares(100n, { totalAssets: 1000n, totalSupply: 1000n, decimalsOffset: 12 });\n * // shares = 100n\n * ```\n */\nexport function convertToShares(\n parameters: convertToShares.Parameters,\n): convertToShares.ReturnType {\n const denominator = parameters.totalAssets + 1n;\n if (denominator === 0n) throw new DenominatorIsZeroError();\n\n return (\n (parameters.assets * (parameters.totalSupply + 10n ** BigInt(parameters.decimalsOffset))) /\n denominator\n );\n}\n\nexport declare namespace convertToShares {\n type Parameters = {\n /** The amount of assets to convert. */\n assets: bigint;\n /** Total amount of assets in the vault. */\n totalAssets: bigint;\n /** Total amount of shares in the vault. */\n totalSupply: bigint;\n /**\n * OpenZeppelin decimals offset used by the ERC4626 implementation.\n * Calculated to be `max(0, 18 - underlyingDecimals)` at construction, so the initial conversion rate maximizes\n * precision between shares and assets.\n */\n decimalsOffset: number;\n };\n type ReturnType = bigint;\n type ErrorType = DenominatorIsZeroError;\n}\nexport class DenominatorIsZeroError extends Errors.BaseError {\n override readonly name = \"ERC4626.DenominatorIsZeroError\";\n constructor() {\n super(\"Denominator is 0.\");\n }\n}\n","import type { Address, Hex } from \"viem\";\nimport type { Chain } from \"#core\";\n\n/**\n * Represents a liquidity pool with a unique ID and amount.\n */\nexport type LiquidityPool = {\n id: string;\n amount: bigint;\n};\n\n/**\n * Represents a hierarchical relationship between two liquidity pools.\n */\nexport type LiquidityLink = {\n parentPoolId: string;\n childPoolId: string;\n priority: number;\n};\n\n/**\n * Represents the connection between an offer and its liquidity pools.\n */\nexport type OfferLiquidityPool = {\n offerHash: Hex;\n poolId: string;\n /**\n * The available capacity/liquidity from this pool for this offer.\n * Matches allowance amount from pool below.\n */\n amount: bigint;\n};\n\n/**\n * Calculate maximum debt capacity from collateral amount.\n * @param amount - Collateral amount\n * @param oraclePrice - Oracle price (scaled to 36 decimals)\n * @param lltv - Loan-to-value ratio (scaled to 18 decimals)\n * @returns Maximum debt capacity\n */\nexport function calculateMaxDebt(amount: bigint, oraclePrice: bigint, lltv: bigint): bigint {\n const ORACLE_PRICE_SCALE = 10n ** 36n; // Oracle prices are scaled to 36 decimals\n const PRECISION = 10n ** 18n; // LLTV ratios are scaled to 18 decimals (1e18 = 100%)\n\n const collateralQuoted = (amount * oraclePrice) / ORACLE_PRICE_SCALE;\n const maxDebt = (collateralQuoted * lltv) / PRECISION;\n\n return maxDebt;\n}\n\n/**\n * Generate pool ID for balance pools.\n */\nexport function generateBalancePoolId(parameters: {\n user: Address;\n chainId: Chain.Id;\n token: Address;\n}): string {\n const { user, chainId, token } = parameters;\n return `${user}-${chainId.toString()}-${token}-balance`.toLowerCase();\n}\n\n/**\n * Generate pool ID for allowance pools.\n */\nexport function generateAllowancePoolId(parameters: {\n user: Address;\n chainId: Chain.Id;\n token: Address;\n}): string {\n const { user, chainId, token } = parameters;\n return `${user}-${chainId.toString()}-${token}-allowance`.toLowerCase();\n}\n\n/**\n * Generate pool ID for obligation collateral pools.\n * Obligation collateral pools represent collateral already deposited in the obligation.\n * These pools are shared across all offers with the same obligation.\n */\nexport function generateObligationCollateralPoolId(parameters: {\n user: Address;\n chainId: Chain.Id;\n obligationId: Hex;\n token: Address;\n}): string {\n const { user, chainId, obligationId, token } = parameters;\n return `${user}-${chainId.toString()}-${obligationId}-${token}-obligation-collateral`.toLowerCase();\n}\n\n/**\n * Generate pool ID for debt pools.\n */\nexport function generateDebtPoolId(parameters: {\n user: Address;\n chainId: Chain.Id;\n obligationId: Hex;\n}): string {\n const { user, chainId, obligationId } = parameters;\n return `${user}-${chainId.toString()}-${obligationId}-debt`.toLowerCase();\n}\n\n/**\n * Generate pool ID for user position in a vault.\n */\nexport function generateUserVaultPositionPoolId(parameters: {\n user: Address;\n chainId: Chain.Id;\n vault: Address;\n}): string {\n const { user, chainId, vault } = parameters;\n return `${user}-${chainId.toString()}-${vault}-user-vault-position`.toLowerCase();\n}\n\n/**\n * Generate pool ID for vault position in a market.\n */\nexport function generateVaultPositionPoolId(parameters: {\n vault: Address;\n chainId: Chain.Id;\n marketId: string;\n}): string {\n const { vault, chainId, marketId } = parameters;\n return `${vault}-${chainId.toString()}-${marketId}-vault-position`.toLowerCase();\n}\n\n/**\n * Generate pool ID for market total liquidity.\n */\nexport function generateMarketLiquidityPoolId(parameters: {\n chainId: Chain.Id;\n marketId: string;\n}): string {\n const { chainId, marketId } = parameters;\n return `${chainId.toString()}-${marketId}-market-liquidity`.toLowerCase();\n}\n","import * as z from \"zod\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport type { Brand } from \"./types.ts\";\n\n/**\n * Maturity is a number that represents a date in seconds.\n */\nexport type Maturity = number & Brand<\"Maturity\">;\n\nexport const MaturitySchema = z\n .number()\n .int()\n .refine(\n (maturity) => {\n try {\n from(maturity);\n return true;\n } catch (_e) {\n return false;\n }\n },\n {\n error: (issue) => {\n try {\n const maturityDate = new Date((issue.input as number) * 1000);\n return `The maturity is set to ${maturityDate}. It must fall on the allowed settlement cycles (Friday 15:00 UTC at the end of week/month/quarter).`;\n } catch (_) {\n return `The maturity is set to ${issue.input}. It must fall on the allowed settlement cycles (Friday 15:00 UTC at the end of week/month/quarter).`;\n }\n },\n },\n )\n .transform((maturity) => maturity as Maturity);\n\nexport enum MaturityType {\n EndOfWeek = \"end_of_week\",\n EndOfNextWeek = \"end_of_next_week\",\n EndOfMonth = \"end_of_month\",\n EndOfNextMonth = \"end_of_next_month\",\n EndOfQuarter = \"end_of_quarter\",\n EndOfNextQuarter = \"end_of_next_quarter\",\n}\n\nconst MaturityOptions = {\n end_of_week: () => endOfWeek(),\n end_of_next_week: () => endOfNextWeek(),\n end_of_month: () => endOfMonth(),\n end_of_next_month: () => endOfNextMonth(),\n end_of_quarter: () => endOfQuarter(),\n end_of_next_quarter: () => endOfNextQuarter(),\n} as const;\n\nexport type MaturityOptions = keyof typeof MaturityOptions;\n\n/**\n * Creates a maturity from a timestamp in seconds or a maturity option.\n * @throws {InvalidFormatError} If the maturity is in milliseconds.\n * @throws {InvalidDateError} If the maturity is in seconds but not a valid date.\n * @throws {InvalidOptionError} If the maturity is not a valid option.\n */\nexport function from(ts: from.Parameters): Maturity {\n if (typeof ts === \"string\") {\n if (ts in MaturityOptions) return MaturityOptions[ts]();\n throw new InvalidOptionError(ts);\n }\n\n if (typeof ts === \"number\" && ts > 1e12) throw new InvalidFormatError();\n\n if (!Object.values(MaturityOptions).some((option) => option() === ts))\n throw new InvalidDateError(ts);\n\n return ts as Maturity;\n}\n\nexport declare namespace from {\n type Parameters = number | MaturityOptions;\n type ErrorType = InvalidFormatError | InvalidDateError | InvalidOptionError;\n}\n\n/** Returns the end of the current week (friday at 15:00:00 UTC) */\nconst endOfWeek = (): Maturity => fridayOfWeek(0);\n\n/** Returns the end of the next week (friday at 15:00:00 UTC) */\nconst endOfNextWeek = (): Maturity => fridayOfWeek(1);\n\n/** Returns the end of the current month (last friday of the month at 15:00:00 UTC)\n * Business rule: if we are after the last Friday of the month (strictly after 15:00 UTC\n * on that Friday), roll to the next month's last Friday.\n */\nconst endOfMonth = (): Maturity => {\n const now = new Date();\n const year = now.getUTCFullYear();\n const month = now.getUTCMonth();\n\n const endOfMonth = lastFridayOfMonth(year, month);\n\n // If strictly after 15:00 UTC on the last Friday, roll to next month's last Friday\n if (now.getTime() > endOfMonth * 1000) {\n return lastFridayOfMonth(year, month + 1);\n }\n\n return endOfMonth;\n};\n\n/** Returns the end of the next month (last friday of the next month at 15:00:00 UTC)\n * Business rule: if we are after the last Friday of the current month (strictly after 15:00 UTC\n * on that Friday), we consider being in the next month already, so \"next month\" becomes month+2.\n */\nconst endOfNextMonth = (): Maturity => {\n const now = new Date();\n const year = now.getUTCFullYear();\n const month = now.getUTCMonth();\n\n const endOfMonth = lastFridayOfMonth(year, month);\n\n if (now.getTime() > endOfMonth * 1000) {\n return lastFridayOfMonth(year, month + 2);\n }\n\n return lastFridayOfMonth(year, month + 1);\n};\n\n/** Returns the end of the current quarter (last friday of the quarter at 15:00:00 UTC) */\nconst endOfQuarter = (): Maturity => lastFridayOfQuarter(0);\n\n/** Returns the end of the next quarter (last friday of the next quarter at 15:00:00 UTC) */\nconst endOfNextQuarter = (): Maturity => lastFridayOfQuarter(1);\n\nconst fridayOfWeek = (weeksAhead = 0): Maturity => {\n const now = new Date();\n const today15H = new Date(\n Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), 15),\n );\n\n // Days until next Friday (5). Always non-negative in [0,6]\n let daysUntilFriday = (5 - today15H.getUTCDay() + 7) % 7;\n\n // If it's Friday and we're already past 15:00 UTC, roll to next Friday\n if (daysUntilFriday === 0 && now.getTime() >= today15H.getTime()) {\n daysUntilFriday = 7;\n }\n\n const friday = new Date(today15H);\n friday.setUTCDate(friday.getUTCDate() + daysUntilFriday + weeksAhead * 7);\n return (friday.getTime() / 1000) as Maturity;\n};\n\nconst lastFridayOfMonth = (year: number, month: number): Maturity => {\n const lastDayOfMonth15H = new Date(Date.UTC(year, month + 1, 0, 15));\n\n while (lastDayOfMonth15H.getUTCDay() !== 5) {\n lastDayOfMonth15H.setUTCDate(lastDayOfMonth15H.getUTCDate() - 1);\n }\n\n const maturity = lastDayOfMonth15H.setUTCDate(lastDayOfMonth15H.getUTCDate()) / 1000;\n\n return maturity as Maturity;\n};\n\nconst lastFridayOfQuarter = (quartersAhead = 0): Maturity => {\n const now = new Date();\n const quarterIndex = Math.floor(now.getUTCMonth() / 3) + quartersAhead;\n const year = now.getUTCFullYear() + Math.floor(quarterIndex / 4);\n const quarter = quarterIndex % 4;\n const lastMonth = quarter * 3 + 2; // 0-based\n return lastFridayOfMonth(year, lastMonth);\n};\n\nexport class InvalidFormatError extends Errors.BaseError {\n override readonly name = \"Maturity.InvalidFormatError\";\n constructor() {\n super(\"Invalid maturity format. Maturity should be expressed in seconds.\");\n }\n}\n\nexport class InvalidDateError extends Errors.BaseError {\n override readonly name = \"Maturity.InvalidDateError\";\n constructor(input: number) {\n super(\n `Invalid maturity date. Input: \"${input}\". Accepted values are: ${Object.values(\n MaturityOptions,\n )\n .map((option) => `\"${option()}\"`)\n .join(\", \")}.`,\n );\n }\n}\n\nexport class InvalidOptionError extends Errors.BaseError {\n override readonly name = \"Maturity.InvalidOptionError\";\n constructor(input: string) {\n super(\n `Invalid maturity option. Input: \"${input}\". Accepted values are: ${Object.keys(\n MaturityOptions,\n )\n .map((option) => `\"${option}\"`)\n .join(\", \")}.`,\n );\n }\n}\n","import { type Address, encodeAbiParameters, type Hex, keccak256 } from \"viem\";\nimport * as z from \"zod\";\nimport type { Offer } from \"#core\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport * as Format from \"#utils/Format.ts\";\nimport * as Random from \"#utils/Random.ts\";\nimport { transformAddress } from \"#utils/zod.ts\";\nimport type * as Chain from \"./Chain.ts\";\nimport * as Collateral from \"./Collateral.ts\";\nimport * as Maturity from \"./Maturity.ts\";\n\nexport type Obligation = {\n /** The chain id where the liquidity for this obligation is located. */\n chainId: Chain.Id;\n /** The token that is being borrowed for this obligation. */\n loanToken: Address;\n /** The exact set of collaterals required to borrow the loan token. */\n collaterals: Collateral.Collateral[];\n /** The maturity of the obligation. */\n maturity: Maturity.Maturity;\n};\n\nexport const ObligationSchema = z.object({\n chainId: z.number().min(0).max(Number.MAX_SAFE_INTEGER),\n loanToken: z.string().transform(transformAddress),\n collaterals: Collateral.CollateralsSchema,\n maturity: Maturity.MaturitySchema,\n});\n\n/**\n * Creates an obligation from the given parameters.\n * @constructor\n * @param parameters - {@link from.Parameters}\n * @returns The created obligation. {@link Obligation}\n * @throws If the collaterals are not sorted alphabetically by address. {@link CollateralsAreNotSortedError}\n *\n * @example\n * ```ts\n * const obligation = Obligation.from({\n * chainId: 1,\n * loanToken: privateKeyToAccount(generatePrivateKey()).address,\n * collaterals: [\n * Collateral.from({\n * asset: privateKeyToAccount(generatePrivateKey()).address,\n * oracle: privateKeyToAccount(generatePrivateKey()).address,\n * lltv: 0.965\n * }),\n * ],\n * maturity: Maturity.from(\"end_of_next_quarter\"),\n * });\n * ```\n */\nexport function from(parameters: from.Parameters): from.ReturnType {\n try {\n const parsedObligation = ObligationSchema.parse({\n ...parameters,\n maturity: Maturity.from(parameters.maturity),\n });\n\n return {\n chainId: parsedObligation.chainId as Chain.Id,\n loanToken: parsedObligation.loanToken.toLowerCase() as Address,\n collaterals: parsedObligation.collaterals.sort((a, b) => a.asset.localeCompare(b.asset)),\n maturity: parsedObligation.maturity,\n };\n } catch (error: unknown) {\n throw new InvalidObligationError(error as z.ZodError | Error);\n }\n}\n\nexport declare namespace from {\n type Parameters = {\n /** The chain id where the liquidity for this obligation is located. */\n chainId: number;\n /** The token that is being borrowed for this obligation. */\n loanToken: Address;\n /** The exact set of collaterals required to borrow the loan token. Must be sorted alphabetically by address. */\n collaterals: Collateral.from.Parameters[] | readonly Collateral.from.Parameters[];\n /** The maturity of the obligation. */\n maturity: Maturity.from.Parameters;\n };\n\n type ReturnType = Obligation;\n\n export type ErrorType = InvalidObligationError;\n}\n\n/**\n * Creates an obligation from a snake case object.\n * @throws If the obligation is invalid. {@link fromSnakeCase.ErrorType}\n * @param input - {@link fromSnakeCase.Parameters}\n * @returns The created obligation. {@link fromSnakeCase.ReturnType}\n */\nexport function fromSnakeCase(input: fromSnakeCase.Parameters): fromSnakeCase.ReturnType {\n return from(Format.fromSnakeCase<Omit<Obligation, \"chainId\"> & { chainId: number }>(input));\n}\n\nexport declare namespace fromSnakeCase {\n type Parameters = Format.Snake<Omit<Obligation, \"chainId\"> & { chainId: number }>;\n type ReturnType = Obligation;\n type ErrorType = InvalidObligationError;\n}\n\n/**\n * Calculates the obligation id based on the smart contract's Obligation struct.\n * The id is computed as keccak256(abi.encode(chainId, loanToken, collaterals, maturity)).\n * @throws If the collaterals are not sorted alphabetically by address. {@link CollateralsAreNotSortedError}\n * @param parameters - {@link id.Parameters}\n * @returns The obligation id as a 32-byte hex string. {@link id.ReturnType}\n *\n * @example\n * ```ts\n * const obligation = Obligation.random();\n * const id = Obligation.id(obligation);\n * console.log(id); // 0x1234567890123456789012345678901234567890123456789012345678901234\n * ```\n */\nexport function id(parameters: id.Parameters): id.ReturnType {\n let lastAsset = \"\";\n for (const collateral of parameters.collaterals) {\n const newAsset = collateral.asset.toLowerCase();\n if (newAsset.localeCompare(lastAsset) < 0) throw new CollateralsAreNotSortedError();\n lastAsset = newAsset;\n }\n\n return keccak256(\n encodeAbiParameters(\n [\n { type: \"uint256\" },\n { type: \"address\" },\n {\n type: \"tuple[]\",\n components: [\n { type: \"address\", name: \"token\" },\n { type: \"uint256\", name: \"lltv\" },\n { type: \"address\", name: \"oracle\" },\n ],\n },\n { type: \"uint256\" },\n ],\n [\n BigInt(parameters.chainId),\n parameters.loanToken.toLowerCase() as Address,\n parameters.collaterals.map((c) => ({\n token: c.asset.toLowerCase() as Address,\n lltv: c.lltv,\n oracle: c.oracle.toLowerCase() as Address,\n })),\n BigInt(parameters.maturity),\n ],\n ),\n );\n}\n\nexport declare namespace id {\n type Parameters = {\n chainId: number;\n loanToken: Address;\n collaterals: {\n asset: Address;\n lltv: bigint;\n oracle: Address;\n }[];\n maturity: number;\n };\n type ReturnType = Hex;\n type ErrorType = CollateralsAreNotSortedError;\n}\n\n/**\n * Generates a random obligation.\n * @returns A randomly generated obligation. {@link random.ReturnType}\n *\n * @example\n * ```ts\n * const obligation = Obligation.random();\n * ```\n */\nexport function random(): random.ReturnType {\n return from({\n chainId: 1,\n loanToken: Random.address(),\n collaterals: [Collateral.random()],\n maturity: Maturity.from(\"end_of_next_quarter\"),\n });\n}\n\nexport declare namespace random {\n type ReturnType = Obligation;\n}\n\n/**\n * Creates an obligation from an offer.\n * @constructor\n *\n * @param offer - The offer to create the obligation from.\n * @returns The created obligation. {@link fromOffer.ReturnType}\n */\nexport function fromOffer(offer: Offer.Offer): fromOffer.ReturnType {\n return from({\n chainId: offer.chainId,\n loanToken: offer.loanToken,\n collaterals: offer.collaterals,\n maturity: offer.maturity,\n });\n}\n\nexport declare namespace fromOffer {\n type Parameters = Offer.Offer;\n type ReturnType = Obligation;\n}\n\nexport class InvalidObligationError extends Errors.BaseError<z.ZodError | Error> {\n override readonly name = \"Obligation.InvalidObligationError\";\n constructor(error: z.ZodError | Error) {\n super(\"Invalid obligation.\", { cause: error });\n }\n}\n\nexport class CollateralsAreNotSortedError extends Errors.BaseError {\n override readonly name = \"Obligation.CollateralsAreNotSortedError\";\n constructor() {\n super(\"Collaterals are not sorted alphabetically by address.\");\n }\n}\n","import {\n type Address,\n type DecodeAbiParametersReturnType,\n decodeAbiParameters,\n encodeAbiParameters,\n type Hex,\n hashTypedData,\n maxUint256,\n zeroAddress,\n} from \"viem\";\nimport * as z from \"zod\";\nimport type { Compute } from \"#core\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport * as Format from \"#utils/Format.ts\";\nimport * as Random from \"#utils/Random.ts\";\nimport { transformAddress, transformBytes32, transformHex } from \"#utils/zod.ts\";\nimport * as Chain from \"./Chain.ts\";\nimport * as Collateral from \"./Collateral.ts\";\nimport * as LLTV from \"./LLTV.ts\";\nimport * as Maturity from \"./Maturity.ts\";\nimport * as Obligation from \"./Obligation.ts\";\n\n/** Internal symbol for caching the computed hash. */\nconst HASH_CACHE = Symbol(\"offer.hash\");\n\nexport type Offer = {\n /** The address that made the offer. */\n readonly maker: Address;\n /** The amount of assets offered. Mutually exclusive with obligationUnits and obligationShares. */\n readonly assets: bigint;\n /** The max debt units to trade. Mutually exclusive with assets and obligationShares. */\n readonly obligationUnits: bigint;\n /** The max lending shares to trade. Mutually exclusive with assets and obligationUnits. */\n readonly obligationShares: bigint;\n /** The price (18 decimals). */\n readonly price: bigint;\n /** The date at which all interests will be paid. */\n readonly maturity: Maturity.Maturity;\n /** The date at which the offer will expire. */\n readonly expiry: number;\n /** The date at which the offer will start. */\n readonly start: number;\n /** The group. Used for OCO (One-Cancelled-Other) mechanism. */\n readonly group: Hex;\n /** The session. Used for session-based offer management. */\n readonly session: Hex;\n /** The side of the offer. `true` for buy, `false` for sell. */\n readonly buy: boolean;\n /** The chain id where the liquidity for this offer is located. */\n readonly chainId: Chain.Id;\n /** The token that is being borrowed. */\n readonly loanToken: Address;\n /** The exact set of collaterals required to borrow the loan token. */\n readonly collaterals: readonly Collateral.Collateral[];\n /** The optional callback data to retrieve the maker funds. */\n readonly callback: {\n readonly address: Address;\n readonly data: Hex;\n };\n};\n\nexport enum Status {\n VALID = \"VALID\",\n SIMULATION_ERROR = \"SIMULATION_ERROR\",\n}\n\nexport type Validation = {\n offerHash: Hex;\n status: Status;\n};\n\nexport const OfferSchema = () => {\n return z\n .object({\n maker: z.string().transform(transformAddress),\n assets: z.bigint({ coerce: true }).min(0n).max(maxUint256),\n obligationUnits: z.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),\n obligationShares: z.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),\n price: z.bigint({ coerce: true }).min(0n).max(maxUint256),\n maturity: Maturity.MaturitySchema,\n expiry: z.number().int().max(Number.MAX_SAFE_INTEGER),\n start: z.number().int().max(Number.MAX_SAFE_INTEGER),\n group: z.union([z.string(), z.number(), z.bigint()]).transform(transformBytes32),\n session: z\n .union([z.string(), z.number(), z.bigint()])\n .optional()\n .default(\"0x0000000000000000000000000000000000000000000000000000000000000000\")\n .transform(transformBytes32),\n buy: z.boolean(),\n chainId: z.number().min(0).max(Number.MAX_SAFE_INTEGER),\n loanToken: z.string().transform(transformAddress),\n collaterals: Collateral.CollateralsSchema,\n callback: z.object({\n address: z.string().transform(transformAddress),\n data: z.string().transform(transformHex),\n }),\n })\n .refine((data) => data.start < data.expiry, {\n message: \"start must be before expiry\",\n path: [\"start\"],\n })\n .refine((data) => data.expiry <= data.maturity, {\n message: \"expiry must be before or equal to maturity\",\n path: [\"expiry\"],\n });\n};\n\n/**\n * Input type for creating offers. Accepts flexible group types that will be coerced to Hex.\n *\n * The `group` field accepts multiple input formats:\n * - **Hex string** (`0x...`): Padded to 32 bytes if needed\n * - **Numeric string**: Converted to hex (e.g., `\"123\"` -> `\"0x...7b\"`)\n * - **Number**: Non-negative safe integer, converted to hex\n * - **BigInt**: Non-negative, must fit in bytes32\n *\n * All values validated to be non-negative and within bytes32 range.\n */\nexport type OfferInput = Compute<\n Omit<Offer, \"chainId\" | \"group\" | \"session\" | \"obligationUnits\" | \"obligationShares\"> & {\n chainId: number;\n group: Hex | bigint | number | string;\n /** Optional: defaults to zero bytes32. */\n session?: Hex | bigint | number | string;\n /** Optional: defaults to 0n. Mutually exclusive with assets and obligationShares. */\n obligationUnits?: bigint;\n /** Optional: defaults to 0n. Mutually exclusive with assets and obligationUnits. */\n obligationShares?: bigint;\n }\n>;\n\n/**\n * Creates an offer from a plain object.\n * @throws {InvalidOfferError} If the offer is invalid.\n * @param input - The offer to create.\n * @returns The created offer.\n */\nexport function from(input: OfferInput): Offer {\n try {\n return OfferSchema().parse(input) as Offer;\n } catch (error: unknown) {\n throw new InvalidOfferError(error as z.ZodError | Error);\n }\n}\n\nexport declare namespace from {\n export type ErrorType = InvalidOfferError;\n}\n\n/**\n * Creates an offer from a snake case object.\n * @throws {InvalidOfferError} If the offer is invalid.\n * @param input - The offer to create.\n * @returns The created offer.\n */\nexport function fromSnakeCase(\n input: Format.Snake<Omit<Offer, \"chainId\" | \"session\"> & { chainId: number; session: string }>,\n): Offer {\n return from(\n Format.fromSnakeCase<Omit<Offer, \"chainId\" | \"session\"> & { chainId: number; session: string }>(\n input,\n ),\n );\n}\n\n/**\n * Converts an offer to a snake case object.\n * @param offer - The offer to convert.\n * @returns The converted offer.\n */\nexport function toSnakeCase(offer: Offer): Format.Snake<Offer> {\n return Format.toSnakeCase(offer);\n}\n\n/**\n * Serializes an offer for merkle tree encoding.\n * Converts BigInt fields to strings for JSON compatibility.\n *\n * @param offer - Offer to serialize\n * @returns JSON-serializable offer object\n */\nexport const serialize = (offer: Offer) => ({\n maker: offer.maker,\n assets: offer.assets.toString(),\n obligationUnits: offer.obligationUnits.toString(),\n obligationShares: offer.obligationShares.toString(),\n price: offer.price.toString(),\n maturity: Number(offer.maturity),\n expiry: Number(offer.expiry),\n start: Number(offer.start),\n group: offer.group,\n session: offer.session,\n buy: offer.buy,\n chainId: offer.chainId,\n loanToken: offer.loanToken,\n collaterals: offer.collaterals.map((c) => ({\n asset: c.asset,\n oracle: c.oracle,\n lltv: c.lltv.toString(),\n })),\n callback: {\n address: offer.callback.address,\n data: offer.callback.data,\n },\n hash: hash(offer),\n});\n\nexport type RandomConfig = {\n chains?: Chain.Chain[];\n loanTokens?: Address[];\n collateralTokens?: Address[];\n assetsDecimals?: Record<Address, number>;\n buy?: boolean;\n assets?: bigint;\n obligationUnits?: bigint;\n obligationShares?: bigint;\n maker?: Address;\n maturity?: Maturity.Maturity;\n start?: number;\n expiry?: number;\n group?: Hex | bigint | number | string;\n session?: Hex | bigint | number | string;\n price?: bigint;\n callback?: {\n address: Address;\n data: Hex;\n };\n collaterals?: readonly Collateral.Collateral[];\n};\n\n/**\n * Generates a random Offer.\n * The returned Offer contains randomly generated values.\n * @warning The generated Offer should not be used for production usage.\n * @returns {Offer} A randomly generated Offer object.\n */\nexport function random(config?: RandomConfig): Offer {\n const chain = config?.chains\n ? config.chains[Random.int(config.chains.length)]!\n : Chain.chains.ethereum;\n\n const loanToken = config?.loanTokens\n ? config.loanTokens[Random.int(config.loanTokens.length)]!\n : Random.address();\n\n const collateralCandidates = config?.collateralTokens\n ? config.collateralTokens.filter((a) => a !== loanToken)\n : [Random.address()];\n\n const _collateralAsset = collateralCandidates[Random.int(collateralCandidates.length)]!;\n\n const maturityOption = weightedChoice<Maturity.MaturityOptions>([\n [\"end_of_month\", 1],\n [\"end_of_next_month\", 1],\n ]);\n\n const maturity = config?.maturity ?? Maturity.from(maturityOption);\n\n const lltv = LLTV.from(\n weightedChoice<(typeof LLTV.Options)[number]>([\n [0.385, 1],\n [0.5, 1],\n [0.625, 2],\n [0.77, 8],\n [0.86, 10],\n [0.915, 8],\n [0.945, 6],\n [0.965, 4],\n [0.98, 2],\n ]),\n );\n\n const buy = config?.buy !== undefined ? config.buy : Random.bool();\n\n // Price spread grid with step 0.25, ranges by side:\n // - Buy: [4.00, 8.00]\n // - Sell: [1.00, 4.00]\n const ONE = 1000000000000000000n; // 1e18\n const qMin = buy ? 16 : 4; // quarters (4.00 => 16, 8.00 => 32, 1.00 => 4)\n const qMax = buy ? 32 : 16;\n const len = qMax - qMin + 1;\n const pricePairs: ReadonlyArray<readonly [bigint, number]> = Array.from(\n { length: len },\n (_, idx) => {\n const q = qMin + idx; // number of quarters (0.25)\n const scaledPrice = BigInt(q) * (ONE / 4n);\n // Make best prices rarer and worse prices more common (by side):\n // - Buy best is lower price => weight increases with idx (higher price)\n // - Sell best is higher price => weight decreases with idx\n const weight = buy ? 1 + idx : 1 + (len - 1 - idx);\n return [scaledPrice, weight] as const;\n },\n );\n const price = config?.price ?? weightedChoice<bigint>(pricePairs);\n\n const loanTokenDecimals = config?.assetsDecimals?.[loanToken] ?? 18;\n const unit = BigInt(10) ** BigInt(loanTokenDecimals);\n const amountBase = BigInt(100 + Random.int(1_000_000 - 100 + 1));\n const assetsScaled = config?.assets ?? amountBase * unit;\n\n const emptyCallback = { address: zeroAddress, data: \"0x\" as Hex } as const;\n\n const offer = from({\n maker: config?.maker ?? Random.address(),\n assets: assetsScaled,\n obligationUnits: config?.obligationUnits ?? 0n,\n obligationShares: config?.obligationShares ?? 0n,\n price,\n maturity: maturity,\n expiry: config?.expiry ?? maturity - 1,\n start: config?.start ?? maturity - 10,\n group: config?.group ?? Random.hex(32),\n session: config?.session ?? Random.hex(32),\n buy,\n chainId: chain.id,\n loanToken,\n collaterals:\n config?.collaterals ??\n Array.from({ length: Random.int(3) + 1 }, () => ({\n ...Collateral.random(),\n lltv,\n })).sort((a, b) => a.asset.localeCompare(b.asset)),\n callback: config?.callback ?? emptyCallback,\n });\n\n return offer;\n}\n\nconst weightedChoice = <T>(pairs: ReadonlyArray<readonly [T, number]>): T => {\n const total = pairs.reduce((sum, [, weight]) => sum + weight, 0);\n let roll = Random.float() * total;\n for (const [value, weight] of pairs) {\n roll -= weight;\n if (roll < 0) return value;\n }\n return pairs[0]![0];\n};\n\n/**\n * Creates an EIP-712 domain object.\n * @param chainId - The chain ID.\n * @returns The EIP-712 domain object.\n */\nexport const domain = (chainId: number) => ({\n chainId: BigInt(chainId),\n verifyingContract: zeroAddress,\n});\n\n/**\n * The EIP-712 types for the offer.\n * @warning The ordering of the types should NEVER be changed. The offer hash is computed based on the order of the types.\n * @returns The EIP-712 types.\n */\nexport const types = {\n EIP712Domain: [\n { name: \"chainId\", type: \"uint256\" },\n { name: \"verifyingContract\", type: \"address\" },\n ],\n Offer: [\n { name: \"maker\", type: \"address\" },\n { name: \"assets\", type: \"uint256\" },\n { name: \"obligationUnits\", type: \"uint256\" },\n { name: \"obligationShares\", type: \"uint256\" },\n { name: \"price\", type: \"uint256\" },\n { name: \"maturity\", type: \"uint256\" },\n { name: \"expiry\", type: \"uint256\" },\n { name: \"group\", type: \"bytes32\" },\n { name: \"session\", type: \"bytes32\" },\n { name: \"buy\", type: \"bool\" },\n { name: \"loanToken\", type: \"address\" },\n { name: \"collaterals\", type: \"Collateral[]\" },\n { name: \"callback\", type: \"Callback\" },\n ],\n Collateral: [\n { name: \"asset\", type: \"address\" },\n { name: \"oracle\", type: \"address\" },\n { name: \"lltv\", type: \"uint256\" },\n ],\n Callback: [\n { name: \"address\", type: \"address\" },\n { name: \"data\", type: \"bytes\" },\n ],\n} as const;\n\nexport function hash(offer: Offer): Hex {\n const cached = (offer as { [HASH_CACHE]?: Hex })[HASH_CACHE];\n if (cached) return cached;\n\n const computed = hashTypedData({\n domain: domain(offer.chainId),\n message: {\n maker: offer.maker.toLowerCase() as Address,\n assets: offer.assets,\n obligationUnits: offer.obligationUnits,\n obligationShares: offer.obligationShares,\n price: offer.price,\n maturity: BigInt(offer.maturity),\n expiry: BigInt(offer.expiry),\n group: offer.group,\n session: offer.session,\n buy: offer.buy,\n loanToken: offer.loanToken.toLowerCase() as Address,\n collaterals: offer.collaterals,\n callback: {\n address: offer.callback.address.toLowerCase() as Address,\n data: offer.callback.data,\n },\n },\n primaryType: \"Offer\",\n types,\n });\n\n (offer as { [HASH_CACHE]?: Hex })[HASH_CACHE] = computed;\n return computed;\n}\n\n/**\n * Calculates the obligation id for an offer based on the smart contract's Obligation struct.\n * The id is computed as keccak256(abi.encode(chainId, loanToken, collaterals (sorted by token address), maturity)).\n * @param offer - The offer to calculate the obligation id for.\n * @returns The obligation id as a 32-byte hex string.\n */\nexport function obligationId(offer: Offer): Hex {\n return Obligation.id(\n Obligation.from({\n chainId: offer.chainId,\n loanToken: offer.loanToken,\n collaterals: offer.collaterals as Collateral.Collateral[],\n maturity: offer.maturity,\n }),\n );\n}\n\nconst OfferAbi = [\n { name: \"maker\", type: \"address\" },\n { name: \"assets\", type: \"uint256\" },\n { name: \"obligationUnits\", type: \"uint256\" },\n { name: \"obligationShares\", type: \"uint256\" },\n { name: \"price\", type: \"uint256\" },\n { name: \"maturity\", type: \"uint256\" },\n { name: \"expiry\", type: \"uint256\" },\n { name: \"group\", type: \"bytes32\" },\n { name: \"session\", type: \"bytes32\" },\n { name: \"buy\", type: \"bool\" },\n { name: \"chainId\", type: \"uint256\" },\n { name: \"loanToken\", type: \"address\" },\n { name: \"start\", type: \"uint256\" },\n {\n name: \"collaterals\",\n type: \"tuple[]\",\n components: [\n { name: \"asset\", type: \"address\" },\n { name: \"oracle\", type: \"address\" },\n { name: \"lltv\", type: \"uint256\" },\n ],\n },\n {\n name: \"callback\",\n type: \"tuple\",\n components: [\n { name: \"address\", type: \"address\" },\n { name: \"data\", type: \"bytes\" },\n ],\n },\n] as const;\n\nexport function encode(offer: Offer) {\n return encodeAbiParameters(OfferAbi, [\n offer.maker,\n offer.assets,\n offer.obligationUnits,\n offer.obligationShares,\n offer.price,\n BigInt(offer.maturity),\n BigInt(offer.expiry),\n offer.group,\n offer.session,\n offer.buy,\n BigInt(offer.chainId),\n offer.loanToken,\n BigInt(offer.start),\n offer.collaterals,\n offer.callback,\n ]);\n}\n\nexport function decode(data: Hex): Offer {\n let decoded: DecodeAbiParametersReturnType<typeof OfferAbi>;\n try {\n decoded = decodeAbiParameters(OfferAbi, data);\n } catch (error) {\n throw new InvalidOfferError(error as Error);\n }\n\n const offer = from({\n maker: decoded[0],\n assets: decoded[1],\n obligationUnits: decoded[2],\n obligationShares: decoded[3],\n price: decoded[4],\n maturity: Maturity.from(Number(decoded[5])),\n expiry: Number(decoded[6]),\n group: decoded[7],\n session: decoded[8],\n buy: decoded[9],\n chainId: Number(decoded[10]),\n loanToken: decoded[11],\n start: Number(decoded[12]),\n collaterals: decoded[13].map((c) => {\n return Collateral.from({\n asset: c.asset,\n oracle: c.oracle,\n lltv: c.lltv,\n });\n }),\n callback: {\n address: decoded[14].address,\n data: decoded[14].data,\n },\n });\n\n return offer;\n}\n\nexport type OfferConsumed = {\n id: string;\n chainId: Chain.Id;\n maker: Address;\n group: Hex;\n amount: bigint;\n blockNumber: number;\n};\n\n/**\n * ABI for the Take event emitted by the Morpho V2 contract.\n */\nexport const takeEvent = {\n type: \"event\",\n name: \"Take\",\n inputs: [\n { name: \"caller\", type: \"address\", indexed: false, internalType: \"address\" },\n { name: \"id\", type: \"bytes32\", indexed: true, internalType: \"bytes32\" },\n { name: \"maker\", type: \"address\", indexed: true, internalType: \"address\" },\n { name: \"taker\", type: \"address\", indexed: true, internalType: \"address\" },\n { name: \"offerIsBuy\", type: \"bool\", indexed: false, internalType: \"bool\" },\n { name: \"buyerAssets\", type: \"uint256\", indexed: false, internalType: \"uint256\" },\n { name: \"sellerAssets\", type: \"uint256\", indexed: false, internalType: \"uint256\" },\n { name: \"obligationUnits\", type: \"uint256\", indexed: false, internalType: \"uint256\" },\n { name: \"obligationShares\", type: \"uint256\", indexed: false, internalType: \"uint256\" },\n { name: \"buyerIsLender\", type: \"bool\", indexed: false, internalType: \"bool\" },\n { name: \"sellerIsBorrower\", type: \"bool\", indexed: false, internalType: \"bool\" },\n { name: \"group\", type: \"bytes32\", indexed: false, internalType: \"bytes32\" },\n { name: \"consumed\", type: \"uint256\", indexed: false, internalType: \"uint256\" },\n ],\n anonymous: false,\n} as const;\n\n/**\n * ABI for the Consume event emitted by the Obligation contract.\n */\nexport const consumedEvent = {\n type: \"event\",\n name: \"Consume\",\n inputs: [\n { name: \"user\", type: \"address\", indexed: true, internalType: \"address\" },\n { name: \"group\", type: \"bytes32\", indexed: true, internalType: \"bytes32\" },\n { name: \"amount\", type: \"uint256\", indexed: false, internalType: \"uint256\" },\n ],\n anonymous: false,\n} as const;\n\nexport class InvalidOfferError extends Errors.BaseError<z.ZodError | Error> {\n override readonly name = \"Offer.InvalidOfferError\";\n\n constructor(error: z.ZodError | Error) {\n super(\"Invalid offer.\", {\n cause: error,\n });\n }\n\n /**\n * Formats ZodError issues into a human-readable string with line breaks.\n * @example\n * \"- 'assets': too small, expected >= 0\n * - 'start': must be before expiry\"\n */\n static formatDetails(error: z.ZodError | Error): string {\n if (!(error instanceof z.ZodError)) {\n return error.message;\n }\n\n return error.issues\n .map((issue) => {\n const path = issue.path.join(\".\");\n const normalized = issue.message.trim();\n return `'${path}': ${normalized.toLowerCase()}`;\n })\n .join(\". \");\n }\n\n /**\n * Returns the formatted human-readable message.\n */\n get formattedMessage(): string {\n return `Invalid offer. ${InvalidOfferError.formatDetails(this.cause)}`;\n }\n}\n","import type { Address } from \"viem\";\nimport type * as Chain from \"./Chain.ts\";\nimport type * as Collateral from \"./Collateral.ts\";\nimport type * as Offer from \"./Offer.ts\";\n\n/**\n * An oracle contract that provides price information for assets.\n */\nexport type Oracle = {\n /** The chain id where the oracle is deployed. */\n readonly chainId: Chain.Id;\n /** The address of the oracle contract. */\n readonly address: Address;\n /** The price returned by the oracle (in the oracle's native units), null if no price available. */\n readonly price: bigint | null;\n /** The block number at which the price was fetched. */\n readonly blockNumber: number;\n};\n\n/**\n * Create an Oracle from a plain object.\n * @param data - The data to create the oracle from.\n * @returns The created oracle.\n */\nexport function from(data: from.Parameters): from.ReturnType {\n return {\n chainId: data.chainId,\n address: data.address.toLowerCase() as Address,\n price: data.price ? BigInt(data.price) : null,\n blockNumber: data.blockNumber,\n };\n}\n\nexport declare namespace from {\n export type Parameters = {\n chainId: Chain.Id;\n address: Address;\n price: string | null;\n blockNumber: number;\n };\n\n export type ReturnType = Oracle;\n}\n\n/**\n * Creates an oracle from a collateral.\n * @constructor\n *\n * @param parameters - {@link fromCollateral.Parameters}\n * @returns The created oracle. {@link fromCollateral.ReturnType}\n */\nexport function fromCollateral(parameters: fromCollateral.Parameters): fromCollateral.ReturnType {\n const { chainId, collateral, blockNumber, price = null } = parameters;\n return {\n chainId,\n address: collateral.oracle.toLowerCase() as Address,\n price,\n blockNumber,\n };\n}\n\nexport declare namespace fromCollateral {\n export type Parameters = {\n chainId: Chain.Id;\n collateral: Collateral.Collateral;\n blockNumber: number;\n price?: bigint | null;\n };\n\n export type ReturnType = Oracle;\n}\n\n/**\n * Creates oracles from a single offer.\n * @constructor\n *\n * @param parameters - {@link fromOffer.Parameters}\n * @returns The created oracles. {@link fromOffer.ReturnType}\n */\nexport function fromOffer(parameters: fromOffer.Parameters): fromOffer.ReturnType {\n const { offer, blockNumber, price = null } = parameters;\n return fromOffers({ offers: [offer], blockNumber, price });\n}\n\nexport declare namespace fromOffer {\n export type Parameters = {\n offer: Offer.Offer;\n blockNumber: number;\n price?: bigint | null;\n };\n\n export type ReturnType = Oracle[];\n}\n\n/**\n * Creates oracles from a list of offers.\n * @constructor\n *\n * @param parameters - {@link fromOffers.Parameters}\n * @returns The created oracles. {@link fromOffers.ReturnType}\n */\nexport function fromOffers(parameters: fromOffers.Parameters): fromOffers.ReturnType {\n const { offers, blockNumber, price = null } = parameters;\n const rowsByKey = new Map<string, Oracle>();\n\n for (const offer of offers) {\n for (const collateral of offer.collaterals) {\n const key = `${offer.chainId}-${collateral.oracle}`.toLowerCase();\n if (rowsByKey.has(key)) continue;\n rowsByKey.set(\n key,\n fromCollateral({\n chainId: offer.chainId,\n collateral,\n blockNumber,\n price,\n }),\n );\n }\n }\n\n return Array.from(rowsByKey.values());\n}\n\nexport declare namespace fromOffers {\n export type Parameters = {\n offers: Offer.Offer[];\n blockNumber: number;\n price?: bigint | null;\n };\n\n export type ReturnType = Oracle[];\n}\n\n/**\n * Conversion utilities for converting between collateral and loan token amounts\n * using oracle prices and LLTV\n */\nexport namespace Conversion {\n /**\n * Converts a collateral amount to loan token\n * Uses the formula: (amount * price / 10^36) * lltv / 10^18\n *\n * @param amount - The collateral amount to convert\n * @param params - Conversion parameters containing price (36 decimals) and lltv (18 decimals)\n * @returns The equivalent loan token amount\n */\n export function collateralToLoan(\n amount: bigint,\n params: { price: bigint; lltv: bigint },\n ): bigint {\n return (((amount * params.price) / 10n ** 36n) * params.lltv) / 10n ** 18n;\n }\n\n /**\n * Converts a loan token amount to collateral\n * Uses the inverse formula: (amount * 10^36 / price) * 10^18 / lltv\n * Returns 0n if price or lltv is zero (invalid conversion).\n *\n * @param amount - The loan token amount to convert\n * @param params - Conversion parameters containing price (36 decimals) and lltv (18 decimals)\n * @returns The equivalent collateral amount, or 0n if conversion is invalid\n */\n export function loanToCollateral(\n amount: bigint,\n params: { price: bigint; lltv: bigint },\n ): bigint {\n if (params.price === 0n || params.lltv === 0n) return 0n;\n return (((amount * 10n ** 36n) / params.price) * 10n ** 18n) / params.lltv;\n }\n}\n","import type { Address } from \"viem\";\nimport type * as Chain from \"./Chain.ts\";\n\nexport type Position = {\n /** The chain id. */\n chainId: Chain.Id;\n /** The contract address from which the position is called.\n * While balances are obviously tracked on ERC20 contracts, we prefer to track which contract is called to know the balance.\n * For example, when depositing into a vault, we would specify the vault contract address as the contract not the underlying vault's ERC20 token address.\n */\n contract: Address;\n /** The user address. */\n user: Address;\n /** The type of position. */\n type: Type;\n /** The balance of the position. */\n balance?: bigint;\n /** The underlying asset of the position.\n * For ERC20 positions, this equals the contract address.\n * For vault positions, this is the vault's underlying asset.\n */\n asset?: Address;\n /** The block number at which the position was last updated. */\n blockNumber: number;\n};\n\nexport enum Type {\n ERC20 = \"erc20\",\n VAULT_V1 = \"vault_v1\",\n}\n\n/**\n * @constructor\n * Creates a Position.\n * @param parameters - {@link from.Parameters}\n * @returns The created Position. {@link from.ReturnType}\n */\nexport function from(parameters: from.Parameters): from.ReturnType {\n return {\n chainId: parameters.chainId,\n contract: parameters.contract.toLowerCase() as Address,\n user: parameters.user.toLowerCase() as Address,\n type: parameters.type,\n balance: parameters.balance,\n ...(parameters.asset !== undefined ? { asset: parameters.asset.toLowerCase() as Address } : {}),\n blockNumber: parameters.blockNumber,\n };\n}\n\nexport declare namespace from {\n type Parameters = {\n chainId: Chain.Id;\n contract: Address;\n user: Address;\n type: Type;\n balance?: bigint;\n asset?: Address;\n blockNumber: number;\n };\n type ReturnType = Position;\n}\n","import { type Hex, maxUint256 } from \"viem\";\nimport * as z from \"zod\";\nimport { Obligation } from \"#core\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport * as Format from \"#utils/Format.ts\";\nimport * as Random from \"#utils/Random.ts\";\nimport { transformHex } from \"#utils/zod.ts\";\n\nexport type Quote = {\n /** The obligation id. */\n obligationId: Hex;\n ask: {\n /** The ask price for the obligation. (18 decimals). */\n price: bigint;\n };\n bid: {\n /** The bid price for the obligation. (18 decimals). */\n price: bigint;\n };\n};\n\nexport const QuoteSchema = z.object({\n obligationId: z.string().transform(transformHex),\n ask: z.object({\n price: z.bigint({ coerce: true }).min(0n).max(maxUint256),\n }),\n bid: z.object({\n price: z.bigint({ coerce: true }).min(0n).max(maxUint256),\n }),\n});\n\n/**\n * Creates a quote for a given obligation.\n * @constructor\n * @param parameters - {@link from.Parameters}\n * @returns The created quote. {@link Quote}\n * @throws If the quote is invalid. {@link InvalidQuoteError}\n *\n * @example\n * ```ts\n * const quote = Quote.from({ obligationId: \"0x123\", ask: { price: 100n }, bid: { price: 100n } });\n * ```\n */\nexport function from(parameters: from.Parameters): from.ReturnType {\n try {\n const parsedQuote = QuoteSchema.parse(parameters);\n return {\n obligationId: parsedQuote.obligationId,\n ask: parsedQuote.ask,\n bid: parsedQuote.bid,\n };\n } catch (error: unknown) {\n throw new InvalidQuoteError(error as z.ZodError | Error);\n }\n}\n\nexport declare namespace from {\n type Parameters = Quote;\n type ReturnType = Quote;\n type ErrorType = InvalidQuoteError;\n}\n\n/**\n * Creates a quote from a snake case object.\n * @throws If the quote is invalid. {@link InvalidQuoteError}\n * @param snake - {@link fromSnakeCase.Parameters}\n * @returns The created quote. {@link fromSnakeCase.ReturnType}\n */\nexport function fromSnakeCase(snake: fromSnakeCase.Parameters): fromSnakeCase.ReturnType {\n return from(Format.fromSnakeCase<Quote>(snake));\n}\n\nexport declare namespace fromSnakeCase {\n type Parameters = Format.Snake<Quote>;\n type ReturnType = Quote;\n type ErrorType = from.ErrorType;\n}\n\n/**\n * Generates a random quote.\n * @returns A randomly generated quote. {@link random.ReturnType}\n *\n * @example\n * ```ts\n * const quote = Quote.random();\n * ```\n */\nexport function random(): random.ReturnType {\n return from({\n obligationId: Obligation.id(Obligation.random()),\n ask: {\n price: BigInt(Random.int(1_000_000)),\n },\n bid: {\n price: BigInt(Random.int(1_000_000)),\n },\n });\n}\n\nexport declare namespace random {\n type Parameters = never;\n type ReturnType = Quote;\n type ErrorType = from.ErrorType;\n}\n\nexport class InvalidQuoteError extends Errors.BaseError<z.ZodError | Error> {\n override readonly name = \"Quote.InvalidQuoteError\";\n constructor(error: z.ZodError | Error) {\n super(\"Invalid quote.\", { cause: error });\n }\n}\n","import * as Errors from \"#utils/Errors.ts\";\nimport type { Brand } from \"./types.ts\";\n\n/**\n * Time breakpoints in seconds for piecewise linear fee interpolation.\n * Matches on-chain constants: 0d, 1d, 7d, 30d, 90d, 180d.\n */\nexport const BREAKPOINTS = [\n 0n,\n 86400n, // 1 day\n 604800n, // 7 days\n 2592000n, // 30 days\n 7776000n, // 90 days\n 15552000n, // 180 days\n] as const;\n\n/** WAD constant (1e18) for fee scaling. */\nexport const WAD = 10n ** 18n;\n\n/** Tuple type for the 6 fee values at each breakpoint. */\nexport type Fees = readonly [bigint, bigint, bigint, bigint, bigint, bigint];\n\n/**\n * TradingFee represents a piecewise linear fee curve with 6 breakpoints.\n * The internal storage mimics on-chain bitmap behavior but uses a struct for clarity.\n */\nexport type TradingFee = {\n readonly _activated: boolean;\n readonly _fees: Fees;\n} & Brand<\"TradingFee\">;\n\n/**\n * Create a TradingFee from an activation flag and 6 fee values.\n * @param activated - Whether the fee is active.\n * @param fees - Tuple of 6 fee values in WAD (one per breakpoint: 0d, 1d, 7d, 30d, 90d, 180d).\n * @returns A new TradingFee instance.\n * @throws {@link InvalidFeeError} if any fee exceeds WAD (100%).\n * @throws {@link InvalidFeesLengthError} if fees array doesn't have exactly 6 elements.\n */\nexport function from(activated: boolean, fees: Fees): TradingFee {\n if (fees.length !== 6) {\n throw new InvalidFeesLengthError(fees.length);\n }\n for (let i = 0; i < 6; i++) {\n const fee = fees[i] as bigint;\n if (fee < 0n || fee > WAD) {\n throw new InvalidFeeError(fee, i);\n }\n }\n // Defensive copy and freeze to guarantee immutability\n const frozenFees = Object.freeze([...fees]) as Fees;\n return Object.freeze({\n _activated: activated,\n _fees: frozenFees,\n }) as TradingFee;\n}\n\nexport declare namespace from {\n type ErrorType = InvalidFeeError | InvalidFeesLengthError;\n}\n\n/**\n * Compute the trading fee for a given time to maturity using piecewise linear interpolation.\n * @param tradingFee - The TradingFee instance.\n * @param timeToMaturity - Time to maturity in seconds.\n * @returns The interpolated fee in WAD. Returns 0n if not activated.\n */\nexport function compute(tradingFee: TradingFee, timeToMaturity: number): bigint {\n if (!tradingFee._activated) {\n return 0n;\n }\n\n const time = BigInt(Math.max(0, Math.floor(timeToMaturity)));\n\n // If beyond 180 days, return the 180d fee\n if (time >= BREAKPOINTS[5]) {\n return tradingFee._fees[5];\n }\n\n // Find the segment for interpolation\n const { index, start, end } = getSegment(time);\n\n const feeLower = tradingFee._fees[index] as bigint;\n const feeUpper = tradingFee._fees[index + 1] as bigint;\n\n // Linear interpolation: (feeLower * (end - t) + feeUpper * (t - start)) / (end - start)\n const segmentLength = end - start;\n return (feeLower * (end - time) + feeUpper * (time - start)) / segmentLength;\n}\n\n/**\n * Check if the trading fee is activated.\n * @param tradingFee - The TradingFee instance.\n * @returns True if activated, false otherwise.\n */\nexport function isActivated(tradingFee: TradingFee): boolean {\n return tradingFee._activated;\n}\n\n/**\n * Create a new TradingFee with activation enabled.\n * @param tradingFee - The TradingFee instance.\n * @returns A new TradingFee with activated set to true.\n */\nexport function activate(tradingFee: TradingFee): TradingFee {\n return Object.freeze({\n _activated: true,\n _fees: tradingFee._fees, // Already frozen from construction\n }) as TradingFee;\n}\n\n/**\n * Create a new TradingFee with activation disabled.\n * @param tradingFee - The TradingFee instance.\n * @returns A new TradingFee with activated set to false.\n */\nexport function deactivate(tradingFee: TradingFee): TradingFee {\n return Object.freeze({\n _activated: false,\n _fees: tradingFee._fees, // Already frozen from construction\n }) as TradingFee;\n}\n\n/**\n * Get the fee values at each breakpoint.\n * @param tradingFee - The TradingFee instance.\n * @returns The tuple of 6 fee values.\n */\nexport function getFees(tradingFee: TradingFee): Fees {\n return tradingFee._fees;\n}\n\n/**\n * Determine which segment a timeToMaturity falls into for interpolation.\n * @param timeToMaturity - Time to maturity in seconds.\n * @returns Object with index, start, and end of the segment.\n */\nfunction getSegment(timeToMaturity: bigint): { index: number; start: bigint; end: bigint } {\n if (timeToMaturity < BREAKPOINTS[1]) {\n return { index: 0, start: BREAKPOINTS[0], end: BREAKPOINTS[1] };\n }\n if (timeToMaturity < BREAKPOINTS[2]) {\n return { index: 1, start: BREAKPOINTS[1], end: BREAKPOINTS[2] };\n }\n if (timeToMaturity < BREAKPOINTS[3]) {\n return { index: 2, start: BREAKPOINTS[2], end: BREAKPOINTS[3] };\n }\n if (timeToMaturity < BREAKPOINTS[4]) {\n return { index: 3, start: BREAKPOINTS[3], end: BREAKPOINTS[4] };\n }\n return { index: 4, start: BREAKPOINTS[4], end: BREAKPOINTS[5] };\n}\n\n/** Error thrown when a fee value is invalid (negative or exceeds WAD). */\nexport class InvalidFeeError extends Errors.BaseError {\n override readonly name = \"TradingFee.InvalidFeeError\";\n constructor(fee: bigint, index: number) {\n super(`Invalid fee at index ${index}: ${fee}. Fee must be between 0 and ${WAD} (WAD).`);\n }\n}\n\n/** Error thrown when fees array doesn't have exactly 6 elements. */\nexport class InvalidFeesLengthError extends Errors.BaseError {\n override readonly name = \"TradingFee.InvalidFeesLengthError\";\n constructor(length: number) {\n super(`Invalid fees length: ${length}. Expected exactly 6 fee values.`);\n }\n}\n","import type { Address } from \"viem\";\nimport type * as Chain from \"./Chain.ts\";\n\nexport type Transfer = {\n id: string;\n chainId: Chain.Id;\n contract: Address;\n from: Address;\n to: Address;\n value: bigint;\n blockNumber: number;\n};\n\n/**\n * @constructor\n *\n * Creates a {@link Transfer}.\n * @param parameters - {@link from.Parameters}\n * @returns The created Transfer. {@link from.ReturnType}\n *\n * @example\n * ```ts\n * const transfer = Transfer.from({ id: \"1\", chainId: 1, contract: \"0x123\", from: \"0x456\", to: \"0x789\", value: 100n, blockNumber: 100n });\n * ```\n */\nexport function from(parameters: from.Parameters): from.ReturnType {\n return {\n id: parameters.id,\n chainId: parameters.chainId,\n contract: parameters.contract.toLowerCase() as Address,\n from: parameters.from.toLowerCase() as Address,\n to: parameters.to.toLowerCase() as Address,\n value: parameters.value,\n blockNumber: parameters.blockNumber,\n };\n}\n\nexport declare namespace from {\n type Parameters = {\n id: string;\n chainId: Chain.Id;\n contract: Address;\n from: Address;\n to: Address;\n value: bigint;\n blockNumber: number;\n };\n\n type ReturnType = Transfer;\n}\n","import { StandardMerkleTree } from \"@openzeppelin/merkle-tree\";\nimport { gzip, ungzip } from \"pako\";\nimport {\n type Address,\n bytesToHex,\n type Hex,\n hashTypedData,\n hexToBytes,\n isAddress,\n isHex,\n recoverAddress,\n} from \"viem\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport * as Offer from \"./Offer.ts\";\nimport type { Compute } from \"./types.ts\";\n\n/**\n * A merkle tree of offers built from offer hashes.\n * Constructed via {@link from}. The tree root can be signed for onchain broadcast.\n */\nexport type Tree = Compute<\n StandardMerkleTree<[Hex]> & {\n /** The offers in the tree. */\n offers: Offer.Offer[];\n /** The root of the tree. */\n root: Hex;\n }\n>;\n\nexport type Proof = {\n /** The offer that the proof is for. */\n offer: Offer.Offer;\n /** The merkle proof path for the offer. */\n path: Hex[];\n};\n\nexport const VERSION = 1;\n\nexport type SignatureDomain = {\n /** Chain id used in the EIP-712 domain. */\n chainId: number | bigint;\n /** MorphoV2 contract address used as verifying contract. */\n verifyingContract: Address;\n};\n\n/** Normalized Root signature domain (BigInt chain id, lowercase address). */\nexport type NormalizedSignatureDomain = {\n chainId: bigint;\n verifyingContract: Address;\n};\n\n/**\n * EIP-712 types for signing the tree root (Root(bytes32 root)).\n */\nexport const signatureTypes = {\n EIP712Domain: [\n { name: \"chainId\", type: \"uint256\" },\n { name: \"verifyingContract\", type: \"address\" },\n ],\n Root: [{ name: \"root\", type: \"bytes32\" }],\n} as const;\n\nconst normalizeHash = (hash: Hex): Hex => hash.toLowerCase() as Hex;\n\n/**\n * Builds a Merkle tree from a list of offers.\n *\n * Leaves are the offer `hash` values as `bytes32` and are deterministically\n * ordered following the StandardMerkleTree leaf ordering so that the resulting\n * root is stable regardless of the input order.\n *\n * @param offers - Offers to include in the tree.\n * @returns A `StandardMerkleTree` of `bytes32` leaves representing the offers.\n * @throws {TreeError} If tree building fails due to offer inconsistencies.\n */\nexport const from = (offers: Offer.Offer[]): Tree => {\n const leaves = offers.map<[Hex]>((offer) => [Offer.hash(offer)]);\n const tree = StandardMerkleTree.of<[Hex]>(leaves, [\"bytes32\"]);\n const orderedOffers = orderOffers(tree, offers);\n return Object.assign(tree, { offers: orderedOffers }) as Tree;\n};\n\nconst orderOffers = (tree: StandardMerkleTree<[Hex]>, offers: Offer.Offer[]): Offer.Offer[] => {\n const offerByHash = new Map<Hex, Offer.Offer>();\n for (const offer of offers) {\n offerByHash.set(normalizeHash(Offer.hash(offer)), offer);\n }\n\n const entries = tree.dump().values.map((value) => {\n const hash = normalizeHash(value.value[0] as Hex);\n const offer = offerByHash.get(hash);\n if (!offer) {\n throw new TreeError(`missing offer for leaf ${hash}`);\n }\n return { offer, treeIndex: value.treeIndex };\n });\n\n entries.sort((a, b) => b.treeIndex - a.treeIndex);\n return entries.map((item) => item.offer);\n};\n\n/**\n * Generates merkle proofs for all offers in a tree.\n *\n * Each proof allows independent verification that an offer is included in the tree\n * without requiring the full tree. Proofs are ordered by StandardMerkleTree leaf ordering.\n *\n * @param tree - The {@link Tree} to generate proofs for.\n * @returns Array of proofs - {@link Proof}\n */\nexport const proofs = (tree: Tree): Proof[] => {\n return tree.offers.map((offer) => {\n const path = tree.getProof([Offer.hash(offer)] as [Hex]) as Hex[];\n return { offer, path };\n });\n};\n\n/**\n * Normalizes a Root signature domain (BigInt chain id, lowercase address).\n * @throws {SignatureDomainError} When the domain is invalid.\n */\nexport const signatureDomain = (domain: SignatureDomain): NormalizedSignatureDomain => {\n return normalizeSignatureDomain(domain, (reason) => new SignatureDomainError(reason));\n};\n\nconst normalizeSignatureDomain = (\n domain: SignatureDomain,\n errorFactory: (reason: string) => Errors.BaseError,\n): NormalizedSignatureDomain => {\n let chainId: bigint;\n try {\n chainId = typeof domain.chainId === \"bigint\" ? domain.chainId : BigInt(domain.chainId);\n } catch {\n throw errorFactory(\"invalid chainId\");\n }\n\n if (chainId < 0n) throw errorFactory(\"invalid chainId\");\n if (!isAddress(domain.verifyingContract)) throw errorFactory(\"invalid verifyingContract\");\n\n return {\n chainId,\n verifyingContract: domain.verifyingContract.toLowerCase() as Address,\n };\n};\n\nconst assertHex = (\n value: unknown,\n expectedBytes: number,\n name: string,\n errorFactory: (reason: string) => Errors.BaseError = (reason) => new DecodeError(reason),\n): void => {\n if (typeof value !== \"string\" || !isHex(value)) {\n throw errorFactory(`${name} is not a valid hex string`);\n }\n if (hexToBytes(value).length !== expectedBytes) {\n throw errorFactory(`${name}: expected ${expectedBytes} bytes`);\n }\n};\n\nconst verifySignatureAndRecoverAddress = async (params: {\n root: Hex;\n signature: Hex;\n domain: NormalizedSignatureDomain;\n errorFactory: (reason: string) => Errors.BaseError;\n}): Promise<Address> => {\n const { root, signature, domain, errorFactory } = params;\n assertHex(root, 32, \"root\", errorFactory);\n assertHex(signature, 65, \"signature\", errorFactory);\n const hash = hashTypedData({\n domain,\n types: signatureTypes,\n primaryType: \"Root\",\n message: { root },\n });\n try {\n return await recoverAddress({ hash, signature });\n } catch {\n throw errorFactory(\"signature recovery failed\");\n }\n};\n\n/**\n * Encodes a merkle tree with signature into hex calldata for onchain broadcast.\n *\n * Layout: `0x{vv}{gzip([...offers])}{root}{signature}` where:\n * - `{vv}`: 1-byte version (currently 0x01)\n * - `{gzip([...offers])}`: gzipped JSON array of serialized offers\n * - `{root}`: 32-byte merkle root\n * - `{signature}`: 65-byte EIP-712 signature over Root(bytes32 root)\n *\n * Validates signature authenticity and root integrity before encoding.\n *\n * @example\n * ```typescript\n * const tree = Tree.from(offers);\n * const signature = await wallet.signTypedData({\n * account: wallet.account,\n * domain: Tree.signatureDomain({ chainId, verifyingContract }),\n * types: Tree.signatureTypes,\n * primaryType: \"Root\",\n * message: { root: tree.root },\n * });\n * const calldata = await Tree.encode(tree, signature, { chainId, verifyingContract });\n * await broadcast(calldata);\n * ```\n *\n * @example\n * Manual construction (for advanced users):\n * ```typescript\n * const tree = Tree.from(offers);\n * const compressed = gzip(JSON.stringify(tree.offers.map(Offer.serialize)));\n * const partial = `0x01${bytesToHex(compressed)}${tree.root.slice(2)}`;\n * const signature = await wallet.signTypedData({\n * account: wallet.account,\n * domain: Tree.signatureDomain({ chainId, verifyingContract }),\n * types: Tree.signatureTypes,\n * primaryType: \"Root\",\n * message: { root: tree.root },\n * });\n * const calldata = `${partial}${signature.slice(2)}`;\n * ```\n *\n * @param tree - Merkle tree of offers\n * @param signature - EIP-712 signature over Root(bytes32 root)\n * @param domain - EIP-712 domain with chain id and verifying contract\n * @returns Hex-encoded calldata ready for onchain broadcast\n * @throws {EncodeError} If signature verification fails or root mismatch\n */\nexport const encode = async (tree: Tree, signature: Hex, domain: SignatureDomain): Promise<Hex> => {\n const errorFactory = (reason: string) => new EncodeError(reason);\n const normalizedDomain = normalizeSignatureDomain(domain, errorFactory);\n validateTreeForEncoding(tree, normalizedDomain);\n await verifySignatureAndRecoverAddress({\n root: tree.root,\n signature,\n domain: normalizedDomain,\n errorFactory,\n });\n\n const unsigned = encodeUnsignedBytes(tree);\n const sigBytes = hexToBytes(signature);\n const encoded = new Uint8Array(unsigned.length + sigBytes.length);\n encoded.set(unsigned, 0);\n encoded.set(sigBytes, unsigned.length);\n\n return bytesToHex(encoded);\n};\n\n/**\n * Encodes a merkle tree without a signature into hex payload for client-side signing.\n *\n * Layout: `0x{vv}{gzip([...offers])}{root}` where:\n * - `{vv}`: 1-byte version (currently 0x01)\n * - `{gzip([...offers])}`: gzipped JSON array of serialized offers\n * - `{root}`: 32-byte merkle root\n *\n * Validates root integrity before encoding.\n *\n * @param tree - Merkle tree of offers\n * @returns Hex-encoded unsigned payload\n * @throws {EncodeError} If root mismatch\n */\nexport const encodeUnsigned = (tree: Tree): Hex => {\n validateTreeForEncoding(tree);\n return bytesToHex(encodeUnsignedBytes(tree));\n};\n\nconst validateTreeForEncoding = (tree: Tree, domain?: NormalizedSignatureDomain): void => {\n if (VERSION > 0xff) throw new EncodeError(`version overflow: ${VERSION} exceeds 255`);\n\n const computed = from(tree.offers);\n if (tree.root !== computed.root)\n throw new EncodeError(`root mismatch: expected ${computed.root}, got ${tree.root}`);\n\n if (domain) {\n const mismatched = tree.offers.find((offer) => BigInt(offer.chainId) !== domain.chainId);\n if (mismatched) {\n throw new EncodeError(\n `chainId mismatch: expected ${domain.chainId}, got ${mismatched.chainId}`,\n );\n }\n }\n};\n\nconst encodeUnsignedBytes = (tree: Tree): Uint8Array => {\n const offersPayload = tree.offers.map(Offer.serialize);\n const compressed = gzip(JSON.stringify(offersPayload));\n const rootBytes = hexToBytes(tree.root);\n const encoded = new Uint8Array(1 + compressed.length + 32);\n encoded[0] = VERSION;\n encoded.set(compressed, 1);\n encoded.set(rootBytes, 1 + compressed.length);\n return encoded;\n};\n\n/**\n * Decodes hex calldata into a validated merkle tree.\n *\n * Validates signature before decompression for fail-fast rejection of invalid payloads.\n * Returns the tree with separately validated signature and recovered signer address.\n *\n * Validation order:\n * 1. Version check\n * 2. Signature verification (fail-fast, before decompression)\n * 3. Decompression (only if signature valid)\n * 4. Root verification (computed from offers vs embedded root)\n *\n * @example\n * ```typescript\n * const { tree, signature, signer } = await Tree.decode(calldata, { chainId, verifyingContract });\n * console.log(`Tree signed by ${signer} with ${tree.offers.length} offers`);\n * ```\n *\n * @param encoded - Hex calldata in format `0x{vv}{gzip}{root}{signature}`\n * @param domain - EIP-712 domain with chain id and verifying contract\n * @returns Validated tree, signature, and recovered signer address\n * @throws {DecodeError} If version invalid, signature invalid, or root mismatch\n */\nexport const decode = async (\n encoded: Hex,\n domain: SignatureDomain,\n): Promise<{\n tree: Tree;\n signature: Hex;\n signer: Address;\n}> => {\n const errorFactory = (reason: string) => new DecodeError(reason);\n const normalizedDomain = normalizeSignatureDomain(domain, errorFactory);\n const bytes = hexToBytes(encoded);\n if (bytes.length < 98) throw new DecodeError(\"payload too short\");\n\n const version = bytes[0];\n if (version !== (VERSION & 0xff))\n throw new DecodeError(`invalid version: expected ${VERSION}, got ${version ?? 0}`);\n\n // Parse from end: signature (last 65 bytes) + root (32 bytes before sig)\n const signature = bytesToHex(bytes.slice(-65));\n const root = bytesToHex(bytes.slice(-97, -65));\n assertHex(root, 32, \"root\");\n assertHex(signature, 65, \"signature\");\n\n const signer = await verifySignatureAndRecoverAddress({\n root,\n signature,\n domain: normalizedDomain,\n errorFactory,\n });\n\n const compressed = bytes.slice(1, -97);\n let decoded: string;\n try {\n decoded = ungzip(compressed, { to: \"string\" });\n } catch {\n throw new DecodeError(\"decompression failed\");\n }\n\n let rawOffers: unknown[];\n try {\n rawOffers = JSON.parse(decoded) as unknown[];\n } catch {\n throw new DecodeError(\"JSON parse failed\");\n }\n\n const offers = rawOffers.map(\n (o: unknown) => Offer.OfferSchema().parse(o) as unknown as Offer.Offer,\n );\n\n const tree = from(offers);\n if (root !== tree.root) {\n throw new DecodeError(`root mismatch: expected ${tree.root}, got ${root}`);\n }\n\n const chainIdMismatch = tree.offers.find(\n (offer) => BigInt(offer.chainId) !== normalizedDomain.chainId,\n );\n if (chainIdMismatch) {\n throw new DecodeError(\n `chainId mismatch: expected ${normalizedDomain.chainId}, got ${chainIdMismatch.chainId}`,\n );\n }\n\n return { tree, signature, signer };\n};\n\n/**\n * Error thrown during tree building operations.\n * Indicates structural issues with the tree (missing offers, inconsistent state).\n */\nexport class TreeError extends Errors.BaseError {\n override name = \"Tree.TreeError\";\n constructor(reason: string) {\n super(`Tree error: ${reason}`);\n }\n}\n\n/**\n * Error thrown during tree encoding.\n * Indicates validation failures (signature, root mismatch, mixed makers).\n */\nexport class EncodeError extends Errors.BaseError {\n override name = \"Tree.EncodeError\";\n constructor(reason: string) {\n super(`Failed to encode tree: ${reason}`);\n }\n}\n\n/**\n * Error thrown during tree decoding.\n * Indicates payload corruption, version mismatch, or validation failures.\n */\nexport class DecodeError extends Errors.BaseError {\n override name = \"Tree.DecodeError\";\n constructor(reason: string) {\n super(`Failed to decode tree: ${reason}`);\n }\n}\n\n/**\n * Error thrown when an invalid signature domain is supplied.\n */\nexport class SignatureDomainError extends Errors.BaseError {\n override name = \"Tree.SignatureDomainError\";\n constructor(reason: string) {\n super(`Invalid signature domain: ${reason}`);\n }\n}\n","/** Combines members of an intersection into a readable type. */\n// https://twitter.com/mattpocockuk/status/1622730173446557697?s=20&t=NdpAcmEFXY01xkqU3KO0Mg\nexport type Compute<type> = { [key in keyof type]: type[key] } & unknown;\n\n// https://effect.website/docs/code-style/branded-types/#generalizing-branded-types\nexport const BrandTypeId = Symbol.for(\"mempool/Brand\");\nexport type Brand<in out ID extends string | symbol> = {\n readonly [BrandTypeId]: {\n readonly [id in ID]: ID;\n };\n};\n","// Should be updated when the data should need to be re-synced from scratch\n// keep this version file isolated to reference it in tsdown config\nexport const VERSION = \"router_v1.6\" as const;\n","import {\n bigint,\n boolean,\n foreignKey,\n index,\n integer,\n numeric,\n pgSchema,\n primaryKey,\n serial,\n text,\n timestamp,\n uniqueIndex,\n varchar,\n} from \"drizzle-orm/pg-core\";\nimport { type Chain, Offer, Position } from \"#core/index.ts\";\nimport type { Collector } from \"#indexer/index.ts\";\nimport { VERSION } from \"./VERSION.ts\";\n\nconst s = pgSchema(VERSION);\n\nenum EnumTableName {\n OBLIGATIONS = \"obligations\",\n GROUPS = \"groups\",\n CONSUMED_EVENTS = \"consumed_events\",\n OBLIGATION_COLLATERALS_V2 = \"obligation_collaterals_v2\",\n ORACLES = \"oracles\",\n OFFERS = \"offers\",\n OFFERS_CALLBACKS = \"offers_callbacks\",\n CALLBACKS = \"callbacks\",\n POSITIONS = \"positions\",\n TRANSFERS = \"transfers\",\n VALIDATIONS = \"validations\",\n COLLECTORS = \"collectors\",\n CHAINS = \"chains\",\n LOTS = \"lots\",\n OFFSETS = \"offsets\",\n TREES = \"trees\",\n MERKLE_PATHS = \"merkle_paths\",\n}\n\nexport const TABLE_NAMES = Object.values(EnumTableName) as readonly EnumTableName[];\nexport const VERSIONED_TABLE_NAMES = TABLE_NAMES.map((table) => `\"${VERSION}\".\"${table}\"` as const);\n\nexport type TableName = (typeof TABLE_NAMES)[number];\nexport type VersionedTableName = `\"${typeof VERSION}\".\"${TableName}\"`;\n\nexport const obligations = s.table(EnumTableName.OBLIGATIONS, {\n obligationId: varchar(\"obligation_id\", { length: 66 }).primaryKey(),\n chainId: bigint(\"chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n loanToken: varchar(\"loan_token\", { length: 42 }).notNull(),\n maturity: integer(\"maturity\").notNull(),\n});\n\nexport const groups = s.table(\n EnumTableName.GROUPS,\n {\n chainId: bigint(\"chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n maker: varchar(\"maker\", { length: 42 }).notNull(),\n group: varchar(\"group\", { length: 66 }).notNull(),\n consumed: numeric(\"consumed\", { precision: 78, scale: 0 }).notNull(),\n blockNumber: bigint(\"block_number\", { mode: \"number\" }).notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.chainId, table.maker, table.group], name: \"groups_pk\" }),\n index(\"groups_chain_id_maker_group_consumed_idx\").on(\n table.chainId,\n table.maker,\n table.group,\n table.consumed,\n ),\n ],\n);\n\nexport const consumedEvents = s.table(\n EnumTableName.CONSUMED_EVENTS,\n {\n eventId: varchar(\"event_id\", { length: 128 }).primaryKey(),\n chainId: bigint(\"chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n maker: varchar(\"maker\", { length: 42 }).notNull(),\n group: varchar(\"group\", { length: 66 }).notNull(),\n amount: numeric(\"amount\", { precision: 78, scale: 0 }).notNull(),\n blockNumber: bigint(\"block_number\", { mode: \"number\" }).notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (t) => [\n foreignKey({\n columns: [t.chainId, t.maker, t.group],\n foreignColumns: [groups.chainId, groups.maker, groups.group],\n name: \"consumed_events_groups_fk\",\n }).onDelete(\"cascade\"),\n index(\"consumed_events_group_idx\").on(t.chainId, t.maker, t.group),\n index(\"consumed_events_block_number_idx\").on(t.blockNumber),\n ],\n);\n\nexport const obligationCollateralsV2 = s.table(\n EnumTableName.OBLIGATION_COLLATERALS_V2,\n {\n obligationId: varchar(\"obligation_id\", { length: 66 })\n .notNull()\n .references(() => obligations.obligationId, { onDelete: \"cascade\" }),\n asset: varchar(\"asset\", { length: 42 }).notNull(),\n oracleChainId: bigint(\"oracle_chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n oracleAddress: varchar(\"oracle_address\", { length: 42 }).notNull(),\n lltv: bigint(\"lltv\", { mode: \"bigint\" }).notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (table) => [\n primaryKey({\n columns: [table.obligationId, table.asset],\n name: \"obligation_collaterals_v2_pk\",\n }),\n foreignKey({\n columns: [table.oracleChainId, table.oracleAddress],\n foreignColumns: [oracles.chainId, oracles.address],\n name: \"obligation_collaterals_v2_oracles_fk\",\n }),\n index(\"obligation_collaterals_v2_obligation_id_idx\").on(table.obligationId),\n index(\"obligation_collaterals_v2_oracle_fk_idx\").on(table.oracleChainId, table.oracleAddress),\n ],\n);\n\nexport const oracles = s.table(\n EnumTableName.ORACLES,\n {\n chainId: bigint(\"chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n address: varchar(\"address\", { length: 42 }).notNull(),\n price: numeric(\"price\", { precision: 78, scale: 0 }),\n blockNumber: bigint(\"block_number\", { mode: \"number\" }).notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (table) => [primaryKey({ columns: [table.chainId, table.address], name: \"oracles_pk\" })],\n);\n\nexport const offers = s.table(\n EnumTableName.OFFERS,\n {\n hash: varchar(\"hash\", { length: 66 }).primaryKey(),\n obligationId: varchar(\"obligation_id\", { length: 66 })\n .notNull()\n .references(() => obligations.obligationId, { onDelete: \"cascade\" }),\n assets: numeric(\"assets\", { precision: 78, scale: 0 }).notNull(),\n obligationUnits: numeric(\"obligation_units\", { precision: 78, scale: 0 })\n .notNull()\n .default(\"0\"),\n obligationShares: numeric(\"obligation_shares\", { precision: 78, scale: 0 })\n .notNull()\n .default(\"0\"),\n price: numeric(\"price\", { precision: 78, scale: 0 }).notNull(),\n maturity: integer(\"maturity\").notNull(),\n expiry: integer(\"expiry\").notNull(),\n start: integer(\"start\").notNull(),\n groupChainId: bigint(\"group_chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n groupMaker: varchar(\"group_maker\", { length: 42 }).notNull(),\n group: varchar(\"group_group\", { length: 66 }).notNull(),\n session: varchar(\"session\", { length: 66 }).notNull(),\n buy: boolean(\"buy\").notNull(),\n callbackAddress: varchar(\"callback_address\", { length: 42 }).notNull(),\n callbackData: text(\"callback_data\").notNull(),\n blockNumber: bigint(\"block_number\", { mode: \"number\" }).notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (table) => [\n foreignKey({\n columns: [table.groupChainId, table.groupMaker, table.group],\n foreignColumns: [groups.chainId, groups.maker, groups.group],\n name: \"offers_groups_fk\",\n }).onDelete(\"cascade\"),\n\n index(\"offers_group_fk_idx\").on(table.groupChainId, table.groupMaker, table.group),\n index(\"offers_group_and_hash_idx\").on(\n table.groupChainId,\n table.groupMaker,\n table.group,\n table.hash,\n ),\n\n index(\"offers_obligation_id_side_idx\").on(table.obligationId, table.buy),\n ],\n);\n\nexport const offersCallbacks = s.table(\n EnumTableName.OFFERS_CALLBACKS,\n {\n offerHash: varchar(\"offer_hash\", { length: 66 })\n .notNull()\n .references(() => offers.hash, { onDelete: \"cascade\" }),\n callbackId: varchar(\"callback_id\", { length: 66 }),\n },\n (table) => [\n primaryKey({\n columns: [table.offerHash, table.callbackId],\n name: \"offers_callbacks_pk\",\n }),\n ],\n);\n\nexport const callbacks = s.table(\n EnumTableName.CALLBACKS,\n {\n id: varchar(\"id\", { length: 66 }).primaryKey(),\n positionChainId: bigint(\"position_chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n positionContract: varchar(\"position_contract\", { length: 42 }).notNull(),\n positionUser: varchar(\"position_user\", { length: 42 }).notNull(),\n amount: numeric(\"amount\", { precision: 78, scale: 0 }),\n },\n (table) => [\n foreignKey({\n columns: [table.positionChainId, table.positionContract, table.positionUser],\n foreignColumns: [positions.chainId, positions.contract, positions.user],\n name: \"callbacks_positions_fk\",\n }).onDelete(\"cascade\"),\n ],\n);\n\nexport const lots = s.table(\n EnumTableName.LOTS,\n {\n chainId: bigint(\"chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n user: varchar(\"user\", { length: 42 }).notNull(),\n contract: varchar(\"contract\", { length: 42 }).notNull(),\n group: varchar(\"group\", { length: 66 }).notNull(),\n lower: numeric(\"lower\", { precision: 78, scale: 0 }).notNull(),\n upper: numeric(\"upper\", { precision: 78, scale: 0 }).notNull(),\n },\n (table) => [\n primaryKey({\n columns: [table.chainId, table.user, table.contract, table.group],\n name: \"lots_pk\",\n }),\n foreignKey({\n columns: [table.chainId, table.contract, table.user],\n foreignColumns: [positions.chainId, positions.contract, positions.user],\n name: \"lots_positions_fk\",\n }).onDelete(\"cascade\"),\n foreignKey({\n columns: [table.chainId, table.user, table.group],\n foreignColumns: [groups.chainId, groups.maker, groups.group],\n name: \"lots_groups_fk\",\n }).onDelete(\"cascade\"),\n ],\n);\n\nexport const offsets = s.table(\n EnumTableName.OFFSETS,\n {\n chainId: bigint(\"chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n user: varchar(\"user\", { length: 42 }).notNull(),\n contract: varchar(\"contract\", { length: 42 }).notNull(),\n group: varchar(\"group\", { length: 66 }).notNull(),\n value: numeric(\"value\", { precision: 78, scale: 0 }).notNull(),\n },\n (table) => [\n primaryKey({\n columns: [table.chainId, table.user, table.contract, table.group],\n name: \"offsets_pk\",\n }),\n foreignKey({\n columns: [table.chainId, table.contract, table.user],\n foreignColumns: [positions.chainId, positions.contract, positions.user],\n name: \"offsets_positions_fk\",\n }).onDelete(\"cascade\"),\n ],\n);\n\nexport const PositionTypes = s.enum<Position.Type, [Position.Type, ...Position.Type[]]>(\n \"position_type\",\n Object.values(Position.Type) as [Position.Type, ...Position.Type[]],\n);\n\nexport const positionTypes = s.table(\"position_types\", {\n id: serial(\"id\").primaryKey(),\n type: PositionTypes(\"type\").notNull(),\n});\n\nexport const positions = s.table(\n EnumTableName.POSITIONS,\n {\n chainId: bigint(\"chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n contract: varchar(\"contract\", { length: 42 }).notNull(),\n user: varchar(\"user\", { length: 42 }).notNull(),\n positionTypeId: integer(\"position_type_id\")\n .notNull()\n .references(() => positionTypes.id, { onDelete: \"no action\" }),\n balance: numeric(\"balance\", { precision: 78, scale: 0 }),\n asset: varchar(\"asset\", { length: 42 }),\n blockNumber: bigint(\"block_number\", { mode: \"number\" }).notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (table) => [\n primaryKey({\n columns: [table.chainId, table.contract, table.user],\n name: \"positions_pk\",\n }),\n ],\n);\n\nexport const transfers = s.table(\n EnumTableName.TRANSFERS,\n {\n eventId: varchar(\"event_id\", { length: 128 }).primaryKey(),\n chainId: bigint(\"chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n contract: varchar(\"contract\", { length: 42 }).notNull(),\n from: varchar(\"from\", { length: 42 }).notNull(),\n to: varchar(\"to\", { length: 42 }).notNull(),\n value: numeric(\"value\", { precision: 78, scale: 0 }).notNull(),\n blockNumber: bigint(\"block_number\", { mode: \"number\" }).notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (table) => [\n foreignKey({\n columns: [table.chainId, table.contract, table.from],\n foreignColumns: [positions.chainId, positions.contract, positions.user],\n name: \"transfers_positions_from_fk\",\n }).onDelete(\"cascade\"),\n\n foreignKey({\n columns: [table.chainId, table.contract, table.to],\n foreignColumns: [positions.chainId, positions.contract, positions.user],\n name: \"transfers_positions_to_fk\",\n }).onDelete(\"cascade\"),\n\n index(\"transfers_chain_contract_user_idx\").on(\n table.chainId,\n table.contract,\n table.from,\n table.to,\n table.blockNumber,\n ),\n ],\n);\n\nexport const StatusCode = s.enum<Offer.Status, [Offer.Status, ...Offer.Status[]]>(\n \"status_code\",\n Object.values(Offer.Status) as [Offer.Status, ...Offer.Status[]],\n);\n\nexport const status = s.table(\"status\", {\n id: serial(\"id\").primaryKey(),\n code: StatusCode(\"code\").unique(),\n});\n\nexport const validations = s.table(\"validations\", {\n offerHash: varchar(\"offer_hash\", { length: 66 })\n .primaryKey()\n .references(() => offers.hash, { onDelete: \"cascade\" }),\n statusId: integer(\"status_id\")\n .notNull()\n .references(() => status.id, { onDelete: \"no action\" }),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n});\n\nexport const collectors = s.table(\n EnumTableName.COLLECTORS,\n {\n chainId: bigint(\"chain_id\", { mode: \"number\" })\n .$type<Chain.Id>()\n .notNull()\n .references(() => chains.chainId, { onDelete: \"no action\" }),\n name: text(\"name\").$type<Collector.Name>().notNull(),\n blockNumber: bigint(\"block_number\", { mode: \"number\" }).notNull(),\n // epoch is used as a fencing token to avoid race conditions when updating the block number\n epoch: numeric(\"epoch\", { precision: 78, scale: 0 }).default(\"0\").notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (table) => [uniqueIndex(\"collectors_chain_name_idx\").on(table.chainId, table.name)],\n);\n\nexport const chains = s.table(\n EnumTableName.CHAINS,\n {\n chainId: bigint(\"chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n blockNumber: bigint(\"block_number\", { mode: \"number\" }).notNull(),\n epoch: numeric(\"epoch\", { precision: 78, scale: 0 }).default(\"0\").notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (table) => [uniqueIndex(\"chains_chain_id_idx\").on(table.chainId)],\n);\n\nexport const trees = s.table(EnumTableName.TREES, {\n root: varchar(\"root\", { length: 66 }).primaryKey(),\n rootSignature: varchar(\"root_signature\", { length: 132 }).notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n});\n\nexport const merklePaths = s.table(\n EnumTableName.MERKLE_PATHS,\n {\n offerHash: varchar(\"offer_hash\", { length: 66 })\n .primaryKey()\n .references(() => offers.hash, { onDelete: \"cascade\" }),\n treeRoot: varchar(\"tree_root\", { length: 66 })\n .notNull()\n .references(() => trees.root, { onDelete: \"cascade\" }),\n proofNodes: text(\"proof_nodes\").notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (table) => [index(\"merkle_paths_tree_root_idx\").on(table.treeRoot)],\n);\n","import { sql } from \"drizzle-orm\";\nimport { type PublicClient, parseEventLogs, type Transport } from \"viem\";\nimport { Chain, Offer } from \"#core\";\nimport type * as Consumed from \"#database/domains/Consumed.ts\";\nimport {\n consumedEvents as consumedEventsTable,\n groups as groupsTable,\n} from \"#database/drizzle/schema.ts\";\nimport * as Logger from \"#logger/Logger.ts\";\nimport type * as Collector from \"../Collector.ts\";\n\nconst buildGroupKey = (parameters: { chainId: Chain.Id; maker: string; group: string }): string => {\n return `${parameters.chainId}-${parameters.maker.toLowerCase()}-${parameters.group.toLowerCase()}`;\n};\n\ntype NormalizedLog =\n | {\n kind: \"consume\";\n id: string;\n chainId: Chain.Id;\n maker: `0x${string}`;\n group: `0x${string}`;\n amount: bigint;\n blockNumber: number;\n }\n | {\n kind: \"take\";\n id: string;\n chainId: Chain.Id;\n maker: `0x${string}`;\n group: `0x${string}`;\n consumed: bigint;\n blockNumber: number;\n };\n\nexport async function* collectConsumedEvents<\n collector extends Collector.Name,\n client extends PublicClient<Transport, Chain.Chain> = PublicClient<Transport, Chain.Chain>,\n>(\n parameters: Collector.CollectParameters<collector, client> & {\n options?: {\n maxBatchSize?: number;\n blockWindow?: number;\n };\n },\n): AsyncGenerator<number, void, void> {\n let {\n db,\n collector,\n client,\n lastBlockNumber: blockNumber,\n epoch,\n options: { maxBatchSize = 1_000, blockWindow } = {},\n } = parameters;\n\n const logger = Logger.getLogger();\n let startBlock = blockNumber;\n let reorgDetected = false;\n\n const { blockNumber: latestBlockNumberChain } = await db.blocks.getChain(client.chain.id);\n\n const stream = Chain.streamLogs({\n client,\n contractAddress: client.chain.custom.morpho.address,\n blockNumberGte: blockNumber,\n blockNumberLte: latestBlockNumberChain,\n order: \"asc\",\n options: { maxBatchSize, blockWindow },\n });\n\n for await (const { logs, blockNumber: lastStreamBlockNumber } of stream) {\n const parsedLogs = parseEventLogs({\n abi: [Offer.consumedEvent, Offer.takeEvent],\n logs,\n strict: false,\n });\n const normalizedLogs: NormalizedLog[] = [];\n const groups = new Map<string, { chainId: Chain.Id; maker: string; group: string }>();\n const eventIds = new Set<string>();\n const recordLog = (log: NormalizedLog) => {\n normalizedLogs.push(log);\n eventIds.add(log.id);\n const groupKey = buildGroupKey({\n chainId: log.chainId,\n maker: log.maker,\n group: log.group,\n });\n if (!groups.has(groupKey)) {\n groups.set(groupKey, {\n chainId: log.chainId,\n maker: log.maker.toLowerCase(),\n group: log.group.toLowerCase(),\n });\n }\n };\n for (const rawLog of parsedLogs) {\n if (\n rawLog.blockNumber === null ||\n rawLog.logIndex === null ||\n rawLog.transactionHash === null\n ) {\n logger.debug({\n collector,\n chainId: client.chain.id,\n msg: \"Skipping log because it is missing required fields\",\n });\n continue;\n }\n\n if (rawLog.eventName === Offer.consumedEvent.name) {\n const consumeArgs = rawLog.args as {\n user?: `0x${string}`;\n group?: `0x${string}`;\n amount?: bigint;\n };\n if (\n consumeArgs.user === undefined ||\n consumeArgs.group === undefined ||\n consumeArgs.amount === undefined\n ) {\n logger.debug({\n collector,\n chainId: client.chain.id,\n msg: \"Skipping Consume log because it is missing required args\",\n });\n continue;\n }\n\n const log: NormalizedLog = {\n kind: \"consume\",\n id: `${rawLog.blockNumber.toString()}-${rawLog.logIndex.toString()}-${client.chain.id}-${rawLog.transactionHash}`,\n chainId: client.chain.id,\n maker: consumeArgs.user,\n group: consumeArgs.group,\n amount: consumeArgs.amount,\n blockNumber: Number(rawLog.blockNumber),\n };\n recordLog(log);\n continue;\n }\n\n if (rawLog.eventName === Offer.takeEvent.name) {\n const takeArgs = rawLog.args as {\n maker?: `0x${string}`;\n group?: `0x${string}`;\n consumed?: bigint;\n };\n if (\n takeArgs.maker === undefined ||\n takeArgs.group === undefined ||\n takeArgs.consumed === undefined\n ) {\n logger.debug({\n collector,\n chainId: client.chain.id,\n msg: \"Skipping Take log because it is missing required args\",\n });\n continue;\n }\n\n const log: NormalizedLog = {\n kind: \"take\",\n id: `${rawLog.blockNumber.toString()}-${rawLog.logIndex.toString()}-${client.chain.id}-${rawLog.transactionHash}`,\n chainId: client.chain.id,\n maker: takeArgs.maker,\n group: takeArgs.group,\n consumed: takeArgs.consumed,\n blockNumber: Number(rawLog.blockNumber),\n };\n recordLog(log);\n }\n }\n\n await db.transaction(async (dbTx) => {\n const existingEventIds = new Set<string>();\n if (eventIds.size > 0) {\n const ids = Array.from(eventIds);\n for (let index = 0; index < ids.length; index += 500) {\n const slice = ids.slice(index, index + 500);\n const { rows } = await dbTx.execute<{ event_id: string }>(sql`\n SELECT event_id\n FROM ${consumedEventsTable}\n WHERE event_id IN (${sql.join(\n slice.map((id) => sql`${id}`),\n sql`,`,\n )});\n `);\n\n for (const row of rows) {\n existingEventIds.add(row.event_id);\n }\n }\n }\n\n const consumedByGroup = new Map<string, bigint>();\n if (groups.size > 0) {\n const groupList = Array.from(groups.values());\n for (let index = 0; index < groupList.length; index += 500) {\n const slice = groupList.slice(index, index + 500);\n // Baseline group totals to compute incremental deltas for this batch.\n // Using a VALUES CTE keeps the lookup set bounded to this slice and avoids scanning\n // consumed_events for sums, which is both slower and order-dependent.\n const { rows } = await dbTx.execute<{\n chain_id: bigint;\n maker: string;\n group: string;\n consumed: string | null;\n }>(sql`\n WITH targets(chain_id, maker, \"group\") AS (\n VALUES ${sql.join(\n slice.map(\n (group) =>\n sql`(${group.chainId}::bigint, ${group.maker.toLowerCase()}::varchar(42), ${group.group.toLowerCase()}::varchar(66))`,\n ),\n sql`,`,\n )}\n )\n SELECT\n targets.chain_id,\n targets.maker,\n targets.\"group\",\n COALESCE(g.consumed, 0)::numeric AS consumed\n FROM targets\n LEFT JOIN ${groupsTable} g\n ON g.chain_id = targets.chain_id\n AND g.maker = targets.maker\n AND g.\"group\" = targets.\"group\";\n `);\n\n for (const row of rows) {\n const groupKey = buildGroupKey({\n chainId: Number(row.chain_id) as Chain.Id,\n maker: row.maker,\n group: row.group,\n });\n consumedByGroup.set(groupKey, BigInt(row.consumed ?? \"0\"));\n }\n }\n }\n\n const events: Consumed.Event[] = [];\n for (const log of normalizedLogs) {\n if (existingEventIds.has(log.id)) {\n continue;\n }\n const groupKey = buildGroupKey({\n chainId: log.chainId,\n maker: log.maker,\n group: log.group,\n });\n const previousConsumed = consumedByGroup.get(groupKey) ?? 0n;\n\n if (log.kind === \"consume\") {\n events.push({\n id: log.id,\n chainId: log.chainId,\n maker: log.maker,\n group: log.group,\n amount: log.amount,\n blockNumber: log.blockNumber,\n });\n\n consumedByGroup.set(groupKey, previousConsumed + log.amount);\n continue;\n }\n\n const delta = log.consumed - previousConsumed;\n if (delta <= 0n) {\n logger.debug({\n collector,\n chainId: client.chain.id,\n msg: \"Skipping Take log because consumed did not increase\",\n previous_consumed: previousConsumed.toString(),\n consumed: log.consumed.toString(),\n });\n continue;\n }\n\n events.push({\n id: log.id,\n chainId: log.chainId,\n maker: log.maker,\n group: log.group,\n amount: delta,\n blockNumber: log.blockNumber,\n });\n\n consumedByGroup.set(groupKey, log.consumed);\n }\n\n try {\n await dbTx.consumed.create(events);\n\n if (events.length > 0) {\n logger.info({\n msg: `Events indexed`,\n collector,\n count: events.length,\n chain_id: client.chain.id,\n block_range: [startBlock, lastStreamBlockNumber],\n });\n }\n } catch (err) {\n logger.error({ err, msg: \"Failed to process consumed events\" });\n }\n\n blockNumber = lastStreamBlockNumber;\n\n try {\n await dbTx.blocks.advanceCollector({\n collectorName: collector,\n chainId: client.chain.id,\n blockNumber,\n epoch,\n });\n } catch (_) {\n try {\n const ancestor = await dbTx.blocks.getCollector({\n collectorName: collector,\n chainId: client.chain.id,\n });\n\n blockNumber = ancestor.blockNumber;\n\n const deleted = await dbTx.consumed.delete({\n chainId: client.chain.id,\n blockNumberGte: blockNumber + 1,\n });\n\n logger.info({\n collector,\n chain_id: client.chain.id,\n msg: `Reorg detected, events deleted`,\n count: deleted,\n block_number: blockNumber,\n });\n\n await dbTx.blocks.advanceCollector({\n collectorName: collector,\n chainId: client.chain.id,\n blockNumber,\n epoch: ancestor.epoch,\n });\n\n reorgDetected = true;\n } catch (err) {\n const msg = \"Failed to delete consumed events when handling reorg.\";\n logger.error({\n collector,\n chainId: client.chain.id,\n msg,\n err,\n });\n\n throw new Error(msg, { cause: err as Error });\n }\n }\n });\n\n if (reorgDetected) return;\n yield blockNumber;\n startBlock = blockNumber;\n }\n\n return;\n}\n","import {\n type Address,\n decodeAbiParameters,\n type Hex,\n type PublicClient,\n type Transport,\n zeroAddress,\n} from \"viem\";\nimport { Callback, Chain, Obligation, Offer, Oracle, Position, Tree } from \"#core\";\nimport type * as CallbacksDomain from \"#database/domains/Callbacks.ts\";\nimport type * as GroupsDomain from \"#database/domains/Groups.ts\";\nimport type * as LotsDomain from \"#database/domains/Lots.ts\";\nimport type * as TreesDomain from \"#database/domains/Trees.ts\";\nimport type { GatekeeperClient } from \"#gatekeeper/Client.ts\";\nimport * as Logger from \"#logger/Logger.ts\";\nimport type * as Collector from \"../Collector.ts\";\n\n/**\n * Rejection reasons for merkle tree payloads.\n * Used for logging and metrics tracking.\n */\nexport type RejectionReason =\n | \"decode_failed\"\n | \"invalid_signature\"\n | \"signer_mismatch\"\n | \"mixed_maker\"\n | \"gatekeeper_rejected\"\n | \"block_window\";\n\n/**\n * Decoded tree with metadata for processing.\n */\ntype DecodedTree = {\n tree: Tree.Tree;\n signature: Hex;\n signer: Address;\n blockNumber: number;\n};\n\ntype OfferWithBlock = {\n offer: Offer.Offer;\n blockNumber: number;\n};\n\ntype OfferDependencies = {\n obligations: Obligation.Obligation[];\n oracles: Oracle.Oracle[];\n groups: GroupsDomain.GroupInput[];\n offerBatches: Array<{ blockNumber: number; offers: Offer.Offer[] }>;\n};\n\nexport async function* collectOffersV2<\n collector extends Collector.Name,\n client extends PublicClient<Transport, Chain.Chain> = PublicClient<Transport, Chain.Chain>,\n>(\n parameters: Collector.CollectParameters<collector, client> & {\n gatekeeper: GatekeeperClient;\n options: {\n maxBatchSize?: number;\n blockWindow?: number;\n };\n },\n): AsyncGenerator<number, void, void> {\n let {\n db,\n collector,\n client,\n lastBlockNumber: blockNumber,\n gatekeeper,\n options: { maxBatchSize = 1_000, blockWindow } = {},\n } = parameters;\n\n const logger = Logger.getLogger();\n let startBlock = blockNumber;\n let reorgDetected = false;\n\n if (client.chain.custom.morpho.address.toLowerCase() === zeroAddress) {\n const msg =\n \"Morpho V2 address is zero, signature verification will fail. Please set the Morpho V2 address in the chain configuration.\";\n logger.error({\n msg,\n chain_id: client.chain.id,\n });\n throw new Error(msg);\n }\n\n const signatureDomain = {\n chainId: client.chain.id,\n verifyingContract: client.chain.custom.morpho.address,\n };\n\n const { blockNumber: latestBlockNumberChain } = await db.blocks.getChain(client.chain.id);\n\n const stream = Chain.streamLogs({\n client,\n contractAddress: client.chain.custom.mempool.address,\n event: {\n type: \"event\",\n name: \"Event\",\n inputs: [{ name: \"data\", type: \"bytes\", indexed: false, internalType: \"bytes\" }],\n anonymous: false,\n } as const,\n blockNumberGte: blockNumber,\n blockNumberLte: latestBlockNumberChain,\n order: \"asc\",\n options: { maxBatchSize, blockWindow },\n });\n\n for await (const { logs, blockNumber: lastStreamBlockNumber } of stream) {\n blockNumber = lastStreamBlockNumber;\n const decodedTrees: DecodedTree[] = [];\n\n for (const log of logs) {\n if (!log) continue;\n const [payload] = decodeAbiParameters([{ type: \"bytes\" }], log.data);\n try {\n const { tree, signature, signer } = await Tree.decode(payload, signatureDomain);\n\n // Signer mismatch check: signer must equal maker address for all offers\n // This is an anti-attack invariant enforced at collector level\n const signerMismatch = tree.offers.find(\n (offer) => offer.maker.toLowerCase() !== signer.toLowerCase(),\n );\n\n if (signerMismatch) {\n logger.debug({\n msg: \"Tree rejected: signer mismatch\",\n reason: \"signer_mismatch\" as RejectionReason,\n signer,\n maker: signerMismatch.maker,\n chain_id: client.chain.id,\n });\n continue;\n }\n\n decodedTrees.push({\n tree,\n signature,\n signer,\n blockNumber: Number(log.blockNumber),\n });\n } catch (err) {\n // Decode failed - could be invalid signature, version mismatch, etc.\n const reason: RejectionReason =\n err instanceof Tree.DecodeError && err.message.includes(\"signature\")\n ? \"invalid_signature\"\n : \"decode_failed\";\n logger.debug({\n msg: \"Tree decode failed\",\n reason,\n chain_id: client.chain.id,\n err: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n await db.transaction(async (dbTx) => {\n const { epoch, blockNumber: latestBlockNumber } = await dbTx.blocks.getChain(client.chain.id);\n\n const treesToInsert: TreesDomain.CreateInput[] = [];\n let totalValidOffers = 0;\n const offersWithBlock: OfferWithBlock[] = [];\n\n for (const { tree, signature, blockNumber: treeBlockNumber } of decodedTrees) {\n try {\n const allowedResults = await gatekeeper.isAllowed(tree.offers);\n const hasBlockWindowViolation = treeBlockNumber > latestBlockNumber;\n const allOffersAllowed =\n allowedResults.issues.length === 0 &&\n allowedResults.valid.length === tree.offers.length;\n\n if (!allOffersAllowed || hasBlockWindowViolation) {\n if (allowedResults.issues.length > 0) {\n const hasMixedMaker = allowedResults.issues.some((i) => i.ruleName === \"mixed_maker\");\n logger.debug({\n msg: \"Tree offers rejected by gatekeeper\",\n reason: (hasMixedMaker ? \"mixed_maker\" : \"gatekeeper_rejected\") as RejectionReason,\n chain_id: client.chain.id,\n issues_count: allowedResults.issues.length,\n });\n } else if (hasBlockWindowViolation) {\n logger.debug({\n msg: \"Tree rejected: offers outside block window\",\n reason: \"block_window\" as RejectionReason,\n chain_id: client.chain.id,\n });\n }\n continue;\n }\n\n treesToInsert.push({ tree, signature });\n totalValidOffers += tree.offers.length;\n offersWithBlock.push(\n ...tree.offers.map((offer) => ({ offer, blockNumber: treeBlockNumber })),\n );\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n logger.error({\n err: error,\n msg: \"Gatekeeper validation failed\",\n chain_id: client.chain.id,\n });\n throw new Error(\"Gatekeeper validation failed\", { cause: error });\n }\n }\n\n const dependencies = buildOfferDependencies(offersWithBlock);\n\n await dbTx.oracles.upsert(dependencies.oracles);\n await dbTx.obligations.create(dependencies.obligations);\n await dbTx.groups.create(dependencies.groups);\n\n const insertedHashes = await dbTx.offers.create(dependencies.offerBatches);\n\n // Phase 3: Insert trees with merkle metadata\n if (treesToInsert.length > 0) {\n await dbTx.trees.create(treesToInsert);\n }\n\n const insertedOffers = filterInsertedOffers({\n offers: offersWithBlock,\n hashes: insertedHashes,\n });\n\n const { callbacks, positions, lots } = decodeCallbacks({\n chainId: client.chain.id,\n offers: insertedOffers,\n });\n\n if (positions.length > 0) {\n await dbTx.positions.upsert(positions);\n }\n\n if (callbacks.length > 0) {\n await dbTx.callbacks.upsert(callbacks);\n }\n\n if (lots.length > 0) {\n await dbTx.lots.create(lots);\n }\n\n try {\n await dbTx.blocks.advanceCollector({\n collectorName: collector,\n chainId: client.chain.id,\n blockNumber,\n epoch,\n });\n\n if (totalValidOffers > 0) {\n logger.info({\n msg: `New offers`,\n collector,\n count: totalValidOffers,\n trees_count: treesToInsert.length,\n chain_id: client.chain.id,\n block_range: [startBlock, lastStreamBlockNumber],\n });\n }\n } catch (_) {\n try {\n const ancestor = await dbTx.blocks.getCollector({\n collectorName: collector,\n chainId: client.chain.id,\n });\n\n blockNumber = ancestor.blockNumber;\n\n const deleted = await dbTx.offers.delete({\n blockNumberGte: blockNumber + 1,\n chainId: client.chain.id,\n });\n\n logger.info({\n collector,\n chain_id: client.chain.id,\n msg: `Reorg detected, offers deleted`,\n count: deleted,\n block_number: blockNumber,\n });\n\n await dbTx.blocks.advanceCollector({\n collectorName: collector,\n chainId: client.chain.id,\n blockNumber,\n epoch: ancestor.epoch,\n });\n\n reorgDetected = true;\n } catch (err) {\n const msg = \"Failed to delete offers when handling reorg.\";\n logger.error({\n collector,\n chainId: client.chain.id,\n msg,\n err,\n });\n\n throw new Error(msg);\n }\n }\n });\n\n if (reorgDetected) return;\n yield blockNumber;\n startBlock = blockNumber;\n }\n\n return;\n}\n\nfunction decodeCallbacks(parameters: { chainId: Chain.Id; offers: OfferWithBlock[] }): {\n callbacks: CallbacksDomain.OfferCallbacks[];\n positions: Position.Position[];\n lots: LotsDomain.create.OfferLotInfo[];\n} {\n const { offers } = parameters;\n if (offers.length === 0) {\n return { callbacks: [], positions: [], lots: [] };\n }\n\n const callbacks: CallbacksDomain.OfferCallbacks[] = [];\n const positions: Position.Position[] = [];\n const lots: LotsDomain.create.OfferLotInfo[] = [];\n\n for (const { offer, blockNumber: offerBlockNumber } of offers) {\n if (!offer.buy) continue;\n if (!Callback.isEmptyCallback(offer)) continue;\n\n const loanToken = offer.loanToken.toLowerCase() as Address;\n\n positions.push(\n Position.from({\n chainId: offer.chainId,\n contract: loanToken,\n user: offer.maker,\n type: Position.Type.ERC20,\n asset: loanToken,\n blockNumber: offerBlockNumber,\n }),\n );\n\n lots.push({\n positionChainId: offer.chainId,\n positionContract: loanToken,\n positionUser: offer.maker,\n group: offer.group,\n size: offer.assets,\n });\n\n callbacks.push({\n offerHash: Offer.hash(offer),\n callbacks: [\n {\n chainId: offer.chainId,\n contract: loanToken,\n user: offer.maker,\n amount: offer.assets,\n },\n ],\n });\n }\n\n return { callbacks, positions, lots };\n}\n\nfunction buildOfferDependencies(offers: OfferWithBlock[]): OfferDependencies {\n const obligationsById = new Map<Hex, Obligation.Obligation>();\n const oraclesByKey = new Map<string, Oracle.Oracle>();\n const groupsByKey = new Map<string, GroupsDomain.GroupInput>();\n const offersByBlock = new Map<number, Offer.Offer[]>();\n\n for (const { offer, blockNumber } of offers) {\n const list = offersByBlock.get(blockNumber) ?? [];\n list.push(offer);\n offersByBlock.set(blockNumber, list);\n\n const obligationId = Offer.obligationId(offer);\n const existing = obligationsById.get(obligationId);\n if (!existing) {\n obligationsById.set(\n obligationId,\n Obligation.from({\n chainId: offer.chainId,\n loanToken: offer.loanToken,\n maturity: offer.maturity,\n collaterals: offer.collaterals,\n }),\n );\n }\n\n for (const collateral of offer.collaterals) {\n const oracleKey = `${offer.chainId}-${collateral.oracle}`.toLowerCase();\n if (!oraclesByKey.has(oracleKey)) {\n oraclesByKey.set(\n oracleKey,\n Oracle.from({\n chainId: offer.chainId,\n address: collateral.oracle,\n price: null,\n blockNumber,\n }),\n );\n }\n }\n\n const groupKey = `${offer.chainId}-${offer.maker}-${offer.group}`.toLowerCase();\n if (!groupsByKey.has(groupKey)) {\n groupsByKey.set(groupKey, {\n chainId: offer.chainId,\n maker: offer.maker,\n group: offer.group,\n blockNumber,\n });\n }\n }\n\n return {\n obligations: Array.from(obligationsById.values()),\n oracles: Array.from(oraclesByKey.values()),\n groups: Array.from(groupsByKey.values()),\n offerBatches: Array.from(offersByBlock.entries()).map(([blockNumber, items]) => ({\n blockNumber,\n offers: items,\n })),\n };\n}\n\nfunction filterInsertedOffers(parameters: {\n offers: OfferWithBlock[];\n hashes: Hex[];\n}): OfferWithBlock[] {\n if (parameters.hashes.length === 0) return [];\n\n const inserted = new Set(parameters.hashes.map((hash) => hash.toLowerCase()));\n const seen = new Set<string>();\n const filtered: OfferWithBlock[] = [];\n\n for (const entry of parameters.offers) {\n const hash = Offer.hash(entry.offer).toLowerCase();\n if (!inserted.has(hash)) continue;\n if (seen.has(hash)) continue;\n seen.add(hash);\n filtered.push(entry);\n }\n\n return filtered;\n}\n","import type { Address, PublicActions, PublicClient, Transport } from \"viem\";\nimport { Abi, type Chain } from \"#core\";\nimport * as Utils from \"#utils/index.ts\";\n\n/**\n * Fetches prices from multiple oracle contracts using multicall.\n *\n * - Executes `price()` on {@link Abi.Oracle} for each {@link Address}.\n * - Requires a client supporting {@link PublicActions.multicall | multicall}.\n *\n * @param parameters - {@link fetchOraclePrices.Parameters} including the list of oracle\n * {@link Address | addresses}, fetch options, and the multicall-enabled client.\n * @returns {@link fetchOraclePrices.ReturnType} mapping {@link Address} to `bigint` price.\n */\nexport async function fetchOraclePrices(\n parameters: fetchOraclePrices.Parameters,\n): Promise<fetchOraclePrices.ReturnType> {\n const { client, oracles, options } = parameters;\n if (oracles.length === 0) return new Map();\n\n const batchSize = Math.max(1, options?.batchSize ?? 5000);\n const retryAttempts = Math.max(1, options?.retryAttempts ?? 3);\n const retryDelayMs = Math.max(0, options?.retryDelayMs ?? 50);\n const blockNumber = options?.blockNumber ? BigInt(options.blockNumber) : undefined;\n\n const out: Map<Address, bigint> = new Map();\n\n for (const oraclesBatch of Utils.batch(oracles, batchSize)) {\n const priceCalls: Array<{\n address: Address;\n abi: typeof Abi.Oracle;\n functionName: \"price\";\n args: [];\n }> = [];\n\n for (const oracle of oraclesBatch) {\n priceCalls.push({\n address: oracle,\n abi: Abi.Oracle,\n functionName: \"price\",\n args: [],\n });\n }\n const prices = await Utils.batchMulticall<bigint>({\n client,\n calls: priceCalls,\n batchSize,\n retryAttempts,\n retryDelayMs,\n blockNumber,\n });\n\n for (let i = 0; i < oraclesBatch.length; i++) {\n const oracle = oraclesBatch[i]!;\n const price = prices[i]! as bigint;\n out.set(oracle, price);\n }\n }\n\n return out;\n}\n\nexport declare namespace fetchOraclePrices {\n export type Parameters = {\n client: PublicClient<Transport, Chain.Chain>;\n oracles: Address[];\n options?: {\n batchSize?: number;\n retryAttempts?: number;\n retryDelayMs?: number;\n blockNumber?: number;\n };\n };\n\n export type ReturnType = Map<Address, bigint>;\n}\n","import { type Address, erc20Abi, type PublicClient, type Transport } from \"viem\";\nimport type { Chain, Position } from \"#core/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\n\n/**\n * Fetches ERC20 balances for positions at a given block number and returns the positions with the updated balances.\n * @notice This method does not mutate positions and returns a new array.\n *\n * @param parameters - {@link snapshotERC20Positions.Parameters}\n * @returns Positions - {@link snapshotERC20Positions.ReturnType}\n */\nexport async function snapshotERC20Positions(\n parameters: snapshotERC20Positions.Parameters,\n): Promise<snapshotERC20Positions.ReturnType> {\n const {\n positions: oldPositions,\n blockNumber,\n options: { maxBatchSize = 1_000, retryAttempts = 5, retryDelayMs = 500 } = {},\n } = parameters;\n\n if (oldPositions.length === 0) return [];\n\n const calls: Array<{\n address: Address;\n abi: typeof erc20Abi;\n functionName: \"balanceOf\";\n args: [Address];\n }> = [];\n\n for (const position of oldPositions) {\n calls.push({\n address: position.contract,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [position.user],\n });\n }\n\n const balances = await Utils.batchMulticall<bigint>({\n client: parameters.client,\n calls,\n blockNumber: BigInt(blockNumber),\n batchSize: maxBatchSize,\n retryAttempts,\n retryDelayMs,\n });\n\n const positions: Position.Position[] = [];\n for (let i = 0; i < balances.length; i++) {\n const oldPosition = oldPositions[i];\n if (!oldPosition) continue;\n\n positions.push({\n ...oldPosition,\n balance: balances[i]!,\n blockNumber,\n });\n }\n\n return positions;\n}\n\nexport declare namespace snapshotERC20Positions {\n export type Parameters = {\n client: PublicClient<Transport, Chain.Chain>;\n positions: Position.Position[];\n blockNumber: number;\n options?: {\n maxBatchSize?: number;\n retryAttempts?: number;\n retryDelayMs?: number;\n };\n };\n\n export type ReturnType = Position.Position[];\n}\n","import type { Address, PublicClient, Transport } from \"viem\";\nimport { Abi, type Chain, type Compute, ERC4626, type Position } from \"#core/index.ts\";\nimport { Logger } from \"#logger/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\n\ntype MetaMorphoCall = Compute<\n | {\n address: Address;\n abi: Abi.MetaMorpho;\n functionName: \"balanceOf\";\n args: [Address];\n convertToAssets: (shares: bigint) => void;\n }\n | {\n address: Address;\n abi: Abi.MetaMorpho;\n functionName: \"DECIMALS_OFFSET\" | \"totalAssets\" | \"totalSupply\" | \"asset\";\n args: [];\n }\n>;\n\n/**\n * Fetches vault shares for users at a given block number, converts them to assets and returns the positions with the updated balances.\n * @notice This method does not mutate positions and returns a new array.\n *\n * @param parameters - {@link snapshotVaultPositions.Parameters}\n * @returns Positions - {@link snapshotVaultPositions.ReturnType}\n */\nexport async function snapshotVaultPositions(\n parameters: snapshotVaultPositions.Parameters,\n): Promise<snapshotVaultPositions.ReturnType> {\n const logger = Logger.getLogger();\n const {\n client,\n positions: oldPositions,\n blockNumber,\n options: { maxBatchSize = 1_000, retryAttempts = 5, retryDelayMs = 500 } = {},\n } = parameters;\n\n const calls: MetaMorphoCall[] = [];\n const contracts = new Map<\n Address,\n {\n decimalsOffset: number | undefined;\n totalAssets: bigint | undefined;\n totalSupply: bigint | undefined;\n asset: Address | undefined;\n }\n >();\n\n // deep clone the positions to avoid mutating the original array\n const positions = structuredClone(oldPositions);\n\n for (const position of positions) {\n calls.push({\n address: position.contract,\n abi: Abi.MetaMorpho,\n functionName: \"balanceOf\",\n args: [position.user],\n convertToAssets: (shares: bigint) => {\n const contract = contracts.get(position.contract.toLowerCase() as Address);\n if (!contract) return;\n if (\n contract.decimalsOffset === undefined ||\n contract.totalAssets === undefined ||\n contract.totalSupply === undefined\n )\n return;\n\n try {\n position.balance = ERC4626.convertToAssets({\n shares,\n totalAssets: contract.totalAssets,\n totalSupply: contract.totalSupply,\n decimalsOffset: contract.decimalsOffset,\n });\n\n position.asset = contract.asset;\n position.blockNumber = blockNumber;\n } catch (err) {\n if (err instanceof ERC4626.DenominatorIsZeroError) {\n logger.error({\n msg: \"Failed to convert shares to assets\",\n chain_id: client.chain.id,\n block_number: blockNumber,\n position_contract: position.contract,\n position_user: position.user,\n shares,\n err,\n });\n return;\n }\n\n throw err;\n }\n },\n });\n\n if (contracts.has(position.contract.toLowerCase() as Address)) continue;\n\n calls.push(\n {\n address: position.contract,\n abi: Abi.MetaMorpho,\n functionName: \"DECIMALS_OFFSET\",\n args: [],\n },\n {\n address: position.contract,\n abi: Abi.MetaMorpho,\n functionName: \"totalAssets\",\n args: [],\n },\n {\n address: position.contract,\n abi: Abi.MetaMorpho,\n functionName: \"totalSupply\",\n args: [],\n },\n {\n address: position.contract,\n abi: Abi.MetaMorpho,\n functionName: \"asset\",\n args: [],\n },\n );\n\n contracts.set(position.contract.toLowerCase() as Address, {\n decimalsOffset: undefined,\n totalAssets: undefined,\n totalSupply: undefined,\n asset: undefined,\n });\n }\n\n const results = await Utils.batchMulticall<bigint | number | Address>({\n client,\n calls,\n blockNumber: BigInt(blockNumber),\n batchSize: maxBatchSize,\n retryAttempts: retryAttempts,\n retryDelayMs: retryDelayMs,\n });\n\n const convertToAssetsList: (() => void)[] = [];\n for (let i = 0; i < results.length; i++) {\n const call = calls[i]!;\n const value = results[i]!;\n\n const contract = contracts.get(call.address.toLowerCase() as Address);\n if (!contract) continue;\n\n switch (call.functionName) {\n case \"balanceOf\":\n convertToAssetsList.push(() => call.convertToAssets(value as bigint));\n break;\n case \"DECIMALS_OFFSET\":\n contract.decimalsOffset = value as number;\n break;\n case \"totalAssets\":\n contract.totalAssets = value as bigint;\n break;\n case \"totalSupply\":\n contract.totalSupply = value as bigint;\n break;\n case \"asset\":\n contract.asset = (value as Address).toLowerCase() as Address;\n break;\n }\n }\n\n for (const convertToAssets of convertToAssetsList) convertToAssets();\n return positions;\n}\n\nexport declare namespace snapshotVaultPositions {\n export type Parameters = {\n client: PublicClient<Transport, Chain.Chain>;\n positions: Position.Position[];\n blockNumber: number;\n options: {\n maxBatchSize?: number;\n retryAttempts?: number;\n retryDelayMs?: number;\n };\n };\n\n export type ReturnType = Position.Position[];\n}\n","import { type PublicClient, parseEventLogs, type Transport } from \"viem\";\nimport { Chain, Position, Transfer } from \"#core\";\nimport * as Logger from \"#logger/Logger.ts\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport type * as Collector from \"../Collector.ts\";\nimport * as Fetchers from \"../fetchers/index.ts\";\n\nexport async function* collectPositions<\n collector extends Collector.Name,\n client extends PublicClient<Transport, Chain.Chain> = PublicClient<Transport, Chain.Chain>,\n>(\n parameters: Collector.CollectParameters<collector, client> & {\n options: {\n maxBatchSize?: number;\n blockWindow?: number;\n retryAttempts?: number;\n retryDelayMs?: number;\n };\n },\n): AsyncGenerator<number, void, void> {\n let {\n db,\n collector,\n client,\n lastBlockNumber: blockNumber,\n epoch,\n options: { maxBatchSize = 1_000, retryAttempts = 5, retryDelayMs = 500, blockWindow } = {},\n } = parameters;\n\n const logger = Logger.getLogger();\n let startBlock = blockNumber;\n let reorgDetected = false;\n\n const TransferEvent = {\n type: \"event\",\n name: \"Transfer\",\n inputs: [\n { name: \"from\", type: \"address\", indexed: true },\n { name: \"to\", type: \"address\", indexed: true },\n { name: \"value\", type: \"uint256\", indexed: false },\n ],\n } as const;\n\n const { blockNumber: latestBlockNumberChain } = await db.blocks.getChain(client.chain.id);\n\n const stream = Chain.streamLogs({\n client,\n event: TransferEvent,\n blockNumberGte: blockNumber,\n blockNumberLte: latestBlockNumberChain,\n order: \"asc\",\n options: { maxBatchSize, blockWindow },\n });\n\n for await (const { logs, blockNumber: lastStreamBlockNumber } of stream) {\n blockNumber = lastStreamBlockNumber;\n const parsedLogs = parseEventLogs({ abi: [TransferEvent], logs });\n const transfers: Transfer.Transfer[] = [];\n for (const log of parsedLogs) {\n if (log.blockNumber === null || log.logIndex === null || log.transactionHash === null) {\n logger.debug({\n collector,\n chainId: client.chain.id,\n msg: \"Skipping log because it is missing required fields\",\n });\n\n continue;\n }\n\n transfers.push(\n Transfer.from({\n id: `${client.chain.id}-${log.blockNumber.toString()}-${log.transactionHash}-${log.logIndex.toString()}`,\n chainId: client.chain.id,\n contract: log.address,\n from: log.args.from,\n to: log.args.to,\n value: log.args.value,\n blockNumber: Number(log.blockNumber),\n }),\n );\n }\n\n const { positions } = await db.positions.get({ chainId: client.chain.id, filled: false });\n\n const newPositions: Position.Position[] = [];\n try {\n newPositions.push(\n ...(\n await _snapshot({\n positions,\n blockNumber: latestBlockNumberChain,\n client,\n maxBatchSize,\n retryAttempts,\n retryDelayMs,\n })\n )\n // bump block number to delete all events until the snapshot block number\n .map((p) => ({ ...p, blockNumber: p.blockNumber + 1 })),\n );\n } catch (err) {\n logger.error({\n msg: \"Failed to snapshot new empty positions\",\n collector,\n chain_id: client.chain.id,\n block_number: latestBlockNumberChain,\n err,\n });\n\n yield startBlock;\n return;\n }\n\n try {\n await db.transaction(async (dbTx) => {\n const insertPositions = async () => {\n if (newPositions.length === 0) return;\n try {\n const count = await dbTx.positions.upsert(newPositions);\n logger.info({\n msg: `New positions`,\n collector,\n count,\n chain_id: client.chain.id,\n block_number: latestBlockNumberChain,\n });\n } catch (err) {\n throw new InsertPositionsError(err as Error);\n }\n };\n\n const insertTransfers = async () => {\n if (transfers.length === 0) return;\n try {\n const created = await dbTx.transfers.create(transfers);\n logger.info({\n msg: `New transfers`,\n collector,\n count: created,\n chain_id: client.chain.id,\n block_range: [startBlock, blockNumber],\n });\n } catch (err) {\n throw new InsertTransfersError(err as Error);\n }\n };\n\n const saveBlockNumber = async () => {\n try {\n await dbTx.blocks.advanceCollector({\n collectorName: collector,\n chainId: client.chain.id,\n blockNumber,\n epoch,\n });\n } catch (_) {\n throw new Errors.ReorgError(blockNumber);\n }\n };\n\n // positions should be inserted before transfers\n // otherwise transfers could be dropped for new positions that are inserted with this call\n await insertPositions();\n await insertTransfers();\n // save block number should be done after the insertion of items\n // to be able to revert transaction if a reorg occurred\n await saveBlockNumber();\n });\n } catch (err) {\n if (err instanceof Errors.ReorgError) {\n logger.info({\n msg: \"Reorg detected, positions and transfers insertion aborted\",\n collector,\n count: newPositions.length,\n chain_id: client.chain.id,\n block_number: blockNumber,\n });\n reorgDetected = true;\n }\n\n if (err instanceof InsertPositionsError) {\n logger.error({\n msg: \"Failed to insert positions\",\n collector,\n count: newPositions.length,\n chain_id: client.chain.id,\n block_number: latestBlockNumberChain,\n err,\n });\n\n throw err.cause;\n }\n\n if (err instanceof InsertTransfersError) {\n logger.error({\n msg: \"Failed to insert transfers\",\n collector,\n count: transfers.length,\n chain_id: client.chain.id,\n block_number: blockNumber,\n err,\n });\n\n throw err.cause;\n }\n }\n\n if (!reorgDetected) {\n startBlock = blockNumber;\n // if no new positions or transfers and the last streamed block is not up to date yet, we want to continue iterating over the stream\n if (\n newPositions.length === 0 &&\n transfers.length === 0 &&\n lastStreamBlockNumber !== latestBlockNumberChain\n )\n continue;\n\n yield blockNumber;\n continue;\n }\n\n await db.transaction(async (dbTx) => {\n try {\n const ancestor = await dbTx.blocks.getCollector({\n collectorName: collector,\n chainId: client.chain.id,\n });\n\n blockNumber = ancestor.blockNumber;\n\n const emptied = await dbTx.positions.setEmptyAfter({\n chainId: client.chain.id,\n blockNumber: blockNumber + 1,\n });\n\n logger.info({\n msg: \"Reorg detected, positions set to empty\",\n collector,\n count: emptied,\n chain_id: client.chain.id,\n block_number_gte: blockNumber + 1,\n });\n\n await dbTx.blocks.advanceCollector({\n collectorName: collector,\n chainId: client.chain.id,\n blockNumber,\n epoch: ancestor.epoch,\n });\n } catch (err) {\n const msg = \"Failed to revert to ancestor block when handling reorg.\";\n logger.error({\n collector,\n chainId: client.chain.id,\n msg,\n err,\n });\n\n throw new Error(msg);\n }\n });\n\n return;\n }\n\n return;\n}\n\n/**\n * @internal\n *\n * Snapshots positions and returns the new positions.\n * @param parameters - {@link _snapshot.Parameters}\n * @returns The new positions. {@link _snapshot.ReturnType}\n */\nasync function _snapshot(parameters: _snapshot.Parameters): Promise<_snapshot.ReturnType> {\n const { positions, blockNumber, client, maxBatchSize, retryAttempts, retryDelayMs } = parameters;\n\n const vaultV1Positions: Position.Position[] = [];\n const erc20Positions: Position.Position[] = [];\n for (const position of positions) {\n switch (position.type) {\n case Position.Type.VAULT_V1:\n vaultV1Positions.push(position);\n break;\n case Position.Type.ERC20:\n erc20Positions.push(position);\n break;\n default:\n throw new Error(\"Invalid position type\");\n }\n }\n\n const promises: Promise<Position.Position[]>[] = [\n Fetchers.snapshotVaultPositions({\n client,\n positions: vaultV1Positions,\n blockNumber,\n options: { maxBatchSize, retryAttempts, retryDelayMs },\n }),\n Fetchers.snapshotERC20Positions({\n client,\n positions: erc20Positions,\n blockNumber,\n options: { maxBatchSize, retryAttempts, retryDelayMs },\n }),\n ];\n\n return (await Promise.all(promises)).flat();\n}\n\ndeclare namespace _snapshot {\n export type Parameters = {\n positions: Position.Position[];\n blockNumber: number;\n client: PublicClient<Transport, Chain.Chain>;\n maxBatchSize?: number;\n retryAttempts?: number;\n retryDelayMs?: number;\n };\n\n export type ReturnType = Position.Position[];\n}\n\nclass InsertPositionsError extends Errors.BaseError<Error> {\n override name = \"InsertPositionsError\";\n constructor(err: Error) {\n super(\"Failed to insert positions\", { cause: err });\n }\n}\n\nclass InsertTransfersError extends Errors.BaseError<Error> {\n override name = \"InsertTransfersError\";\n constructor(err: Error) {\n super(\"Failed to insert transfers\", { cause: err });\n }\n}\n","import type { PublicActions, PublicClient, Transport } from \"viem\";\nimport type { Chain, Oracle } from \"#core\";\nimport * as Logger from \"#logger/Logger.ts\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport type * as Collector from \"../Collector.ts\";\nimport { fetchOraclePrices } from \"../fetchers/fetchOraclePrices.ts\";\n\n/**\n * Collects oracle prices from on-chain oracles and persists them.\n *\n * - Reads oracle definitions as {@link Oracle.Oracle}.\n * - Uses chain metadata from {@link Chain.Chain}.\n *\n * @param parameters - {@link collectPrices.Parameters} (extends {@link Collector.CollectParameters})\n * with a client supporting {@link PublicActions.multicall | multicall}.\n * @yields Latest processed block number after each successful update.\n */\nexport async function* collectPrices<\n collector extends Collector.Name,\n client extends PublicClient<Transport, Chain.Chain> = PublicClient<Transport, Chain.Chain>,\n>(parameters: collectPrices.Parameters<collector, client>): collectPrices.ReturnType {\n const {\n db,\n collector,\n client,\n options: { maxBatchSize = 5_000, retryAttempts = 5, retryDelayMs = 500 } = {},\n } = parameters;\n\n const logger = Logger.getLogger();\n let blockNumber = parameters.lastBlockNumber;\n\n const [oracles, { blockNumber: latestBlockNumberChain, epoch }] = await Promise.all([\n db.oracles.get({ chainId: client.chain.id }),\n db.blocks.getChain(client.chain.id),\n ]);\n\n const updatedOracles: Oracle.Oracle[] = [];\n try {\n const pricesMap = await fetchOraclePrices({\n client,\n oracles: oracles.map((oracle) => oracle.address),\n options: {\n batchSize: maxBatchSize,\n blockNumber: latestBlockNumberChain,\n retryAttempts,\n retryDelayMs,\n },\n });\n\n for (const oracle of oracles) {\n const price = pricesMap.get(oracle.address);\n if (price !== undefined) {\n updatedOracles.push({\n chainId: client.chain.id,\n address: oracle.address,\n price,\n blockNumber: latestBlockNumberChain,\n });\n }\n }\n } catch (err) {\n logger.error({\n msg: \"Failed to fetch oracle prices\",\n collector,\n chain_id: client.chain.id,\n block_number: latestBlockNumberChain,\n err,\n });\n yield blockNumber;\n return;\n }\n\n let reorgDetected = false;\n try {\n await db.transaction(async (dbTx) => {\n if (updatedOracles.length > 0) {\n await dbTx.oracles.upsert(updatedOracles);\n logger.info({\n msg: \"Oracle prices updated\",\n collector,\n count: updatedOracles.length,\n chain_id: client.chain.id,\n block_number: latestBlockNumberChain,\n });\n }\n\n try {\n await dbTx.blocks.advanceCollector({\n collectorName: collector,\n chainId: client.chain.id,\n blockNumber: latestBlockNumberChain,\n epoch,\n });\n } catch (_) {\n throw new Errors.ReorgError(latestBlockNumberChain);\n }\n\n blockNumber = latestBlockNumberChain;\n });\n } catch (err) {\n if (err instanceof Errors.ReorgError) {\n logger.info({\n msg: \"Reorg detected, prices update aborted\",\n collector,\n count: updatedOracles.length,\n chain_id: client.chain.id,\n block_number: latestBlockNumberChain,\n });\n reorgDetected = true;\n } else {\n throw new Error(\"Failed to collect oracle prices\", { cause: err });\n }\n }\n\n if (!reorgDetected) {\n yield blockNumber;\n return;\n }\n\n await db.transaction(async (dbTx) => {\n try {\n const ancestor = await dbTx.blocks.getCollector({\n collectorName: collector,\n chainId: client.chain.id,\n });\n\n blockNumber = ancestor.blockNumber;\n\n await dbTx.blocks.advanceCollector({\n collectorName: collector,\n chainId: client.chain.id,\n blockNumber,\n epoch: ancestor.epoch,\n });\n } catch (err) {\n const msg = \"Failed to revert to ancestor block when handling reorg.\";\n logger.error({\n collector,\n chainId: client.chain.id,\n msg,\n err,\n });\n\n throw new Error(msg);\n }\n });\n\n yield blockNumber;\n}\n\nexport declare namespace collectPrices {\n export type Parameters<\n collector extends Collector.Name,\n client extends PublicClient<Transport, Chain.Chain> = PublicClient<Transport, Chain.Chain>,\n > = Collector.CollectParameters<collector, client> & {\n options?: {\n maxBatchSize?: number;\n retryAttempts?: number;\n retryDelayMs?: number;\n };\n };\n\n export type ReturnType = AsyncGenerator<number, void, void>;\n}\n","import type { PublicClient, Transport } from \"viem\";\nimport type { Chain } from \"#core\";\nimport type { Database } from \"#database/index.ts\";\nimport type { GatekeeperClient } from \"#gatekeeper/Client.ts\";\nimport * as CollectFunctions from \"./CollectFunctions/index.ts\";\nimport * as Collector from \"./Collector.ts\";\n\nexport type Builder<client extends PublicClient<Transport, Chain.Chain>> = {\n buildOffersCollector: (parameters: {\n options?: { maxBatchSize?: number };\n }) => Collector.Collector<\"offers\", client>;\n\n buildConsumedEventsCollector: (parameters?: {\n options?: { maxBatchSize?: number };\n }) => Collector.Collector<\"consumed_events\", client>;\n\n buildPricesCollector: (parameters?: {\n options?: { maxBatchSize?: number; retryAttempts?: number; retryDelayMs?: number };\n }) => Collector.Collector<\"prices\", client>;\n\n buildPositionsCollector: (parameters: {\n options?: { maxBatchSize?: number; retryAttempts?: number; retryDelayMs?: number };\n }) => Collector.Collector<\"positions\", client>;\n};\n\nexport function createBuilder<client extends PublicClient<Transport, Chain.Chain>>(parameters: {\n client: client;\n db: Database.Database;\n gatekeeper: GatekeeperClient;\n options: {\n maxBlockNumber?: number;\n blockWindow?: number;\n interval?: number;\n };\n}): Builder<client> {\n const {\n client,\n db,\n gatekeeper,\n options: { maxBlockNumber, blockWindow, interval } = {},\n } = parameters;\n\n const createCollector = <name extends Collector.Name>(\n name: name,\n collect: Collector.CollectFn<name, client>,\n ): Collector.Collector<name, client> =>\n Collector.create<name, client>({\n name,\n collect,\n client,\n db,\n options: { maxBlockNumber, interval },\n });\n\n return {\n buildOffersCollector: ({ options: { maxBatchSize = 1_000 } = {} }) => {\n return createCollector(\"offers\", (p) =>\n CollectFunctions.collectOffersV2<\"offers\">({\n ...p,\n gatekeeper,\n collector: \"offers\",\n client,\n options: { maxBatchSize, blockWindow },\n }),\n );\n },\n\n buildConsumedEventsCollector: ({ options: { maxBatchSize = 1_000 } = {} } = {}) => {\n return createCollector(\"consumed_events\", (p) =>\n CollectFunctions.collectConsumedEvents<\"consumed_events\">({\n ...p,\n collector: \"consumed_events\",\n options: { maxBatchSize, blockWindow },\n }),\n );\n },\n\n buildPricesCollector: ({\n options: { maxBatchSize = 5_000, retryAttempts, retryDelayMs } = {},\n } = {}) => {\n return createCollector(\"prices\", (p) =>\n CollectFunctions.collectPrices<\"prices\">({\n ...p,\n collector: \"prices\",\n options: { maxBatchSize, retryAttempts, retryDelayMs },\n }),\n );\n },\n\n buildPositionsCollector: ({\n options: { maxBatchSize = 1_000, retryAttempts, retryDelayMs } = {},\n } = {}) => {\n return createCollector(\"positions\", (p) =>\n CollectFunctions.collectPositions<\"positions\">({\n ...p,\n collector: \"positions\",\n options: { maxBatchSize, retryAttempts, retryDelayMs, blockWindow },\n }),\n );\n },\n };\n}\n","import type { PublicClient, Transport } from \"viem\";\nimport type { Chain } from \"#core\";\nimport type { Database } from \"#database/index.ts\";\nimport type { GatekeeperClient } from \"../../gatekeeper/Client.ts\";\nimport type * as Collector from \"./Collector.ts\";\nimport { CollectorBuilder } from \"./index.ts\";\n\ntype CollectorsResult = {\n offersCollector: Collector.Collector<\"offers\", PublicClient<Transport, Chain.Chain>>;\n consumedEventsCollector: Collector.Collector<\n \"consumed_events\",\n PublicClient<Transport, Chain.Chain>\n >;\n pricesCollector: Collector.Collector<\"prices\", PublicClient<Transport, Chain.Chain>>;\n positionsCollector: Collector.Collector<\"positions\", PublicClient<Transport, Chain.Chain>>;\n};\n\nexport const from = (parameters: {\n client: PublicClient<Transport, Chain.Chain>;\n db: Database.Database;\n gatekeeper: GatekeeperClient;\n maxBatchSize?: number;\n maxBlockNumber?: number;\n blockWindow?: number;\n interval?: number;\n retryAttempts?: number;\n retryDelayMs?: number;\n}): CollectorsResult => {\n const {\n client,\n db,\n gatekeeper,\n maxBatchSize,\n maxBlockNumber,\n blockWindow,\n interval,\n retryAttempts,\n retryDelayMs,\n } = parameters;\n\n const collectorBuilder = CollectorBuilder.createBuilder({\n client,\n db,\n gatekeeper,\n options: { maxBlockNumber, blockWindow, interval },\n });\n\n const offersCollector = collectorBuilder.buildOffersCollector({ options: { maxBatchSize } });\n\n const consumedEventsCollector = collectorBuilder.buildConsumedEventsCollector({\n options: { maxBatchSize },\n });\n\n const pricesCollector = collectorBuilder.buildPricesCollector({\n options: { maxBatchSize, retryAttempts, retryDelayMs },\n });\n\n const positionsCollector = collectorBuilder.buildPositionsCollector({\n options: { maxBatchSize, retryAttempts, retryDelayMs },\n });\n\n return {\n offersCollector,\n consumedEventsCollector,\n pricesCollector,\n positionsCollector,\n };\n};\n","import type { Account, PublicClient, Transport } from \"viem\";\nimport type * as Chain from \"#core/Chain.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport type { GatekeeperClient } from \"#gatekeeper/Client.ts\";\nimport { Tracer } from \"#tracer/index.ts\";\nimport * as Collector from \"./collectors/Collector.ts\";\nimport * as Collectors from \"./collectors/Collectors.ts\";\n\nexport type Indexer = {\n start: () => () => void;\n next: () => Promise<void>;\n return: () => Promise<void>;\n};\n\nexport type IndexerConfig<\n client extends PublicClient<Transport, Chain.Chain, Account | undefined>,\n> = {\n client: client;\n db: Database.Database;\n gatekeeper: GatekeeperClient;\n interval?: number;\n maxBatchSize?: number;\n maxBlockNumber?: number;\n blockWindow?: number;\n retryAttempts?: number;\n retryDelayMs?: number;\n};\n\nexport function from<client extends PublicClient<Transport, Chain.Chain, Account | undefined>>(\n config: IndexerConfig<client>,\n): Indexer {\n const {\n client,\n gatekeeper,\n db,\n interval = 10_000,\n maxBatchSize = 1000,\n maxBlockNumber,\n blockWindow,\n retryAttempts,\n retryDelayMs,\n } = config;\n\n const { offersCollector, consumedEventsCollector, positionsCollector, pricesCollector } =\n Collectors.from({\n client: client as PublicClient<Transport, Chain.Chain>,\n db,\n gatekeeper,\n maxBatchSize,\n maxBlockNumber,\n blockWindow,\n interval,\n retryAttempts,\n retryDelayMs,\n });\n\n return create({\n client,\n collectors: [offersCollector, consumedEventsCollector, positionsCollector, pricesCollector],\n });\n}\n\nexport function create<\n client extends PublicClient<Transport, Chain.Chain, Account | undefined>,\n>(params: { collectors: Collector.Collector[]; client: client }): Indexer {\n const { collectors, client } = params;\n const indexerId = `${client.chain.id.toString()}.indexer`;\n const tracer = Tracer.getTracer(`router.${indexerId}`);\n const iterators = collectors.map((collector) => collector.collect());\n\n const next = async () => {\n await Tracer.startActiveSpan(tracer, `${indexerId}.next`, async () => {\n await Promise.all(iterators.map((iterator) => iterator.next()));\n });\n };\n\n const _return = async () => {\n await Promise.all(iterators.map(async (iterator) => iterator.return()));\n };\n\n return {\n start: () => {\n const stops = collectors.map((collector) => Collector.start(collector));\n return () => {\n stops.forEach((stop) => {\n stop();\n });\n };\n },\n\n next,\n return: _return,\n };\n}\n","import type { Client } from \"viem\";\nimport { getBlockNumber } from \"viem/actions\";\nimport type { Chain } from \"#core\";\nimport type * as ChainRegistry from \"#core/ChainRegistry.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport { Collector } from \"#indexer/index.ts\";\nimport { retry } from \"#utils/retry.ts\";\n\nexport type CollectorHealthStatus = \"live\" | \"lagging\" | \"unknown\";\nexport type RouterStatus = \"live\" | \"syncing\";\n\nexport type CollectorHealth = {\n name: Collector.Name;\n chainId: Chain.Id;\n blockNumber: number | null;\n updatedAt: string | null;\n lag: number | null;\n status: CollectorHealthStatus;\n initialized: boolean;\n};\n\nexport type ChainHealth = {\n chainId: Chain.Id;\n localBlockNumber: number | null;\n remoteBlockNumber: number | null;\n epoch: string | null;\n updatedAt: string | null;\n initialized: boolean;\n};\n\nexport type MissingCollector = {\n chainId: Chain.Id;\n name: Collector.Name;\n};\n\nexport type RouterHealth = {\n status: RouterStatus;\n initialized: boolean;\n missingChains: Chain.Id[];\n missingCollectors: MissingCollector[];\n};\n\nexport type HealthService = {\n getSnapshot: () => Promise<Snapshot>;\n getStatus: () => Promise<RouterHealth>;\n getCollectors: () => Promise<CollectorHealth[]>;\n getChains: () => Promise<ChainHealth[]>;\n};\n\nexport type HealthServiceParameters = {\n db: Database.Database;\n /** Maximum number of blocks a collector can lag behind its chain before being considered lagging. */\n maxAllowedLag?: number;\n /** Map of chainId to client for fetching remote block numbers. */\n healthClients?: Map<Chain.Id, Client>;\n /** Chain registry for deriving expected initialization state. */\n chainRegistry?: ChainRegistry.ChainRegistry;\n};\n\nconst DEFAULT_MAX_ALLOWED_LAG = 5;\n\ntype Snapshot = {\n status: RouterStatus;\n initialized: boolean;\n missingChains: Chain.Id[];\n missingCollectors: MissingCollector[];\n collectors: CollectorHealth[];\n chains: ChainHealth[];\n};\n\n/**\n * Create a health service that exposes collector and chain block numbers.\n */\nexport function create(parameters: HealthServiceParameters): HealthService {\n const { db, maxAllowedLag = DEFAULT_MAX_ALLOWED_LAG, healthClients, chainRegistry } = parameters;\n\n const loadSnapshot = async (): Promise<Snapshot> => {\n const [collectorRows, chainRows, remoteBlockByChainId] = await Promise.all([\n db.blocks.getCollectors(),\n db.blocks.getChains(),\n getRemoteBlockNumbers(healthClients),\n ]);\n\n const chainById = new Map<Chain.Id, { blockNumber: number; epoch: bigint; updatedAt: Date }>();\n for (const chain of chainRows) {\n chainById.set(chain.chainId, {\n blockNumber: chain.blockNumber,\n epoch: chain.epoch,\n updatedAt: chain.updatedAt,\n });\n }\n\n const configuredChainIds = chainRegistry?.list().map((chain) => chain.id) ?? [];\n const knownChainIds = new Set<Chain.Id>(configuredChainIds);\n for (const chain of chainRows) knownChainIds.add(chain.chainId);\n\n const collectorKey = (chainId: Chain.Id, name: Collector.Name) => `${chainId}:${name}`;\n const collectorsByKey = new Map<\n string,\n {\n name: Collector.Name;\n chainId: Chain.Id;\n blockNumber: number;\n updatedAt: Date;\n }\n >();\n\n for (const row of collectorRows) {\n collectorsByKey.set(collectorKey(row.chainId, row.collectorName), {\n name: row.collectorName,\n chainId: row.chainId,\n blockNumber: row.blockNumber,\n updatedAt: row.updatedAt,\n });\n }\n\n for (const row of collectorRows) knownChainIds.add(row.chainId);\n\n const expectedChainIds =\n configuredChainIds.length > 0 ? configuredChainIds : Array.from(knownChainIds);\n\n const missingChains = expectedChainIds\n .filter((chainId) => !chainById.has(chainId))\n .sort((a, b) => (a - b > 0 ? 1 : -1));\n\n const missingCollectors = expectedChainIds\n .flatMap((chainId) =>\n [...Collector.names]\n .sort()\n .filter((name) => !collectorsByKey.has(collectorKey(chainId, name)))\n .map((name) => ({ chainId, name })),\n )\n .sort((a, b) =>\n a.chainId === b.chainId ? a.name.localeCompare(b.name) : a.chainId - b.chainId,\n );\n\n const initialized =\n knownChainIds.size > 0 && missingChains.length === 0 && missingCollectors.length === 0;\n\n const collectors: CollectorHealth[] = Array.from(knownChainIds)\n .sort((a, b) => (a - b > 0 ? 1 : -1))\n .flatMap((chainId) =>\n [...Collector.names].sort().map((name) => {\n const row = collectorsByKey.get(collectorKey(chainId, name));\n const chain = chainById.get(chainId);\n\n const blockNumber = row?.blockNumber ?? null;\n const chainBlockNumber = chain?.blockNumber ?? null;\n const lag =\n blockNumber !== null && chainBlockNumber !== null\n ? Math.max(chainBlockNumber - blockNumber, 0)\n : null;\n\n let status: CollectorHealthStatus = \"unknown\";\n if (lag !== null) {\n status = lag <= maxAllowedLag ? \"live\" : \"lagging\";\n } else if (chainBlockNumber !== null) {\n status = \"lagging\";\n }\n\n return {\n name,\n chainId,\n blockNumber,\n updatedAt: row ? row.updatedAt.toISOString() : null,\n lag,\n status,\n initialized: row !== undefined,\n } satisfies CollectorHealth;\n }),\n );\n\n const chains: ChainHealth[] = Array.from(knownChainIds)\n .sort((a, b) => (a - b > 0 ? 1 : -1))\n .map((chainId) => {\n const chain = chainById.get(chainId);\n return {\n chainId,\n localBlockNumber: chain?.blockNumber ?? null,\n remoteBlockNumber: remoteBlockByChainId.get(chainId) ?? null,\n epoch: chain ? chain.epoch.toString() : null,\n updatedAt: chain ? chain.updatedAt.toISOString() : null,\n initialized: chain !== undefined,\n };\n });\n\n const status: RouterStatus =\n collectors.length > 0 && collectors.every((collector) => collector.status === \"live\")\n ? \"live\"\n : \"syncing\";\n\n return {\n status,\n initialized,\n missingChains,\n missingCollectors,\n collectors,\n chains,\n };\n };\n\n return {\n async getSnapshot(): Promise<Snapshot> {\n return loadSnapshot();\n },\n\n async getStatus(): Promise<RouterHealth> {\n const snapshot = await loadSnapshot();\n return {\n status: snapshot.status,\n initialized: snapshot.initialized,\n missingChains: snapshot.missingChains,\n missingCollectors: snapshot.missingCollectors,\n };\n },\n\n async getCollectors(): Promise<CollectorHealth[]> {\n const snapshot = await loadSnapshot();\n return snapshot.collectors;\n },\n\n async getChains(): Promise<ChainHealth[]> {\n const snapshot = await loadSnapshot();\n return snapshot.chains;\n },\n };\n}\n\n/**\n * Fetch the latest block number from all remote clients.\n * Each RPC call is retried up to 3 times; failures yield null for that chain.\n * @param healthClients - The map of chainId to client.\n * @returns The map of chainId to remote block number or null on failure.\n */\nasync function getRemoteBlockNumbers(\n healthClients?: Map<Chain.Id, Client>,\n): Promise<Map<Chain.Id, number | null>> {\n const remoteBlockPromises = Array.from(healthClients ?? new Map<Chain.Id, Client>()).map(\n async ([chainId, client]) => {\n const remoteBlock =\n (await retry(() => getBlockNumber(client).then(Number), 3).catch(() =>\n Promise.resolve(),\n )) ?? null;\n return { chainId, remoteBlock };\n },\n );\n\n const results = await Promise.all(remoteBlockPromises);\n return new Map(results.map((r) => [r.chainId, r.remoteBlock]));\n}\n","export type BookLevelResponse = {\n price: string;\n assets: string;\n count: number;\n};\n\nexport function from(level: { price: bigint; assets: bigint; count: number }): BookLevelResponse {\n return {\n price: level.price.toString(),\n assets: level.assets.toString(),\n count: level.count,\n };\n}\n","import { z } from \"zod/v4\";\n\nexport const CollectorHealth = z.object({\n name: z.string(),\n chain_id: z.number(),\n block_number: z.number().nullable(),\n updated_at: z.string().nullable(),\n lag: z.number().nullable(),\n status: z.enum([\"live\", \"lagging\", \"unknown\"]),\n initialized: z.boolean(),\n});\n\nexport const CollectorsHealthResponse = z.array(CollectorHealth);\n\nexport const ChainHealth = z.object({\n chain_id: z.number(),\n local_block_number: z.number().nullable(),\n remote_block_number: z.number().nullable(),\n updated_at: z.string().nullable(),\n initialized: z.boolean(),\n});\n\nexport const ChainsHealthResponse = z.array(ChainHealth);\n\nexport const RouterStatusResponse = z.object({\n status: z.enum([\"live\", \"syncing\"]),\n initialized: z.boolean(),\n missing_chains: z.array(z.number()),\n missing_collectors: z.array(\n z.object({\n chain_id: z.number(),\n name: z.string(),\n }),\n ),\n});\n\nexport type CollectorsHealthResponse = z.infer<typeof CollectorsHealthResponse>;\nexport type ChainsHealthResponse = z.infer<typeof ChainsHealthResponse>;\nexport type RouterStatusResponse = z.infer<typeof RouterStatusResponse>;\n","import type { Obligation, Quote } from \"#core\";\nimport type * as OpenApiSchema from \"./generated/swagger.d.ts\";\n\nexport type ObligationResponse =\n OpenApiSchema.paths[\"/v1/obligations\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"][\"data\"][number];\n\n/**\n * Creates an `ObligationResponse` from a `Obligation`.\n * @constructor\n * @param obligation - {@link Obligation}\n * @returns The created `ObligationResponse`. {@link ObligationResponse}\n */\nexport function from(obligation: Obligation.Obligation, quote: Quote.Quote): ObligationResponse {\n return {\n id: quote.obligationId,\n chain_id: obligation.chainId,\n loan_token: obligation.loanToken,\n collaterals: obligation.collaterals.map((c) => ({\n token: c.asset,\n lltv: c.lltv.toString(),\n oracle: c.oracle,\n })),\n maturity: obligation.maturity,\n ask: { price: quote.ask.price.toString() },\n bid: { price: quote.bid.price.toString() },\n };\n}\n","import type { Address, Hex } from \"viem\";\nimport { Obligation } from \"#core\";\nimport type * as OpenApiSchema from \"./generated/swagger.d.ts\";\n\nexport type OfferResponse =\n OpenApiSchema.paths[\"/v1/offers\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"][\"data\"][number];\n\nexport type Input = Readonly<{\n hash: Hex;\n maker: Address;\n assets: bigint;\n obligationUnits: bigint;\n obligationShares: bigint;\n price: bigint;\n maturity: number;\n expiry: number;\n start: number;\n group: Hex;\n session: Hex;\n buy: boolean;\n chainId: number;\n loanToken: Address;\n collaterals: Readonly<\n {\n asset: Address;\n lltv: bigint;\n oracle: Address;\n }[]\n >;\n callback: {\n address: Address;\n data: Hex;\n };\n root?: Hex | undefined;\n proof?: Hex[] | undefined;\n signature?: Hex | undefined;\n consumed: bigint;\n takeable: bigint;\n blockNumber: number;\n}>;\n\nfunction normalizeChainId(chainId: Input[\"chainId\"]): number {\n const parsedChainId = Number(chainId);\n if (!Number.isInteger(parsedChainId) || parsedChainId <= 0) {\n throw new Error(`Invalid chain id: ${String(chainId)}`);\n }\n return parsedChainId;\n}\n\nfunction normalizeBlockNumber(blockNumber: Input[\"blockNumber\"]): number {\n const parsedBlockNumber = Number(blockNumber);\n if (!Number.isInteger(parsedBlockNumber) || parsedBlockNumber < 0) {\n throw new Error(`Invalid block number: ${String(blockNumber)}`);\n }\n return parsedBlockNumber;\n}\n\n/**\n * Creates an `OfferResponse` matching the Solidity Offer struct layout.\n * @constructor\n * @param input - {@link Input}\n * @returns The created `OfferResponse`. {@link OfferResponse}\n */\nexport function from(input: Input): OfferResponse {\n const chainId = normalizeChainId(input.chainId);\n const blockNumber = normalizeBlockNumber(input.blockNumber);\n\n const offer = {\n obligation: {\n loan_token: input.loanToken,\n collaterals: input.collaterals.map((c) => ({\n token: c.asset,\n lltv: c.lltv.toString(),\n oracle: c.oracle,\n })),\n maturity: input.maturity,\n },\n buy: input.buy,\n maker: input.maker,\n assets: input.assets.toString(),\n obligation_units: input.obligationUnits.toString(),\n obligation_shares: input.obligationShares.toString(),\n start: input.start,\n expiry: input.expiry,\n price: input.price.toString(),\n group: input.group,\n session: input.session,\n callback: input.callback.address,\n callback_data: input.callback.data,\n };\n\n const base = {\n offer,\n offer_hash: input.hash,\n obligation_id: Obligation.id({\n chainId,\n loanToken: input.loanToken,\n collaterals: [...input.collaterals],\n maturity: input.maturity,\n }),\n chain_id: chainId,\n consumed: input.consumed.toString(),\n takeable: input.takeable.toString(),\n block_number: blockNumber,\n };\n\n if (!input.proof || !input.root || !input.signature) {\n return {\n ...base,\n root: null,\n proof: null,\n signature: null,\n } as OfferResponse;\n }\n\n return {\n ...base,\n root: input.root.toLowerCase(),\n proof: input.proof.map((p) => p.toLowerCase()),\n signature: input.signature.toLowerCase(),\n } as OfferResponse;\n}\n","import * as z from \"zod\";\nimport type { Compute } from \"#core\";\n\nexport const API_ERROR_CODES = [\n \"VALIDATION_ERROR\",\n \"NOT_FOUND\",\n \"INTERNAL_SERVER_ERROR\",\n \"BAD_REQUEST\",\n] as const;\n\ntype APIErrorCode = (typeof API_ERROR_CODES)[number];\n\nexport enum STATUS_CODE {\n SUCCESS = 200,\n BAD_REQUEST = 400,\n NOT_FOUND = 404,\n INTERNAL_SERVER_ERROR = 500,\n}\n\nexport class APIError<Code extends STATUS_CODE = STATUS_CODE> extends Error {\n constructor(\n public statusCode: Code,\n message: string,\n public code: APIErrorCode,\n public details?: unknown,\n ) {\n super(message);\n this.name = \"APIError\";\n }\n}\n\nexport class ValidationError extends APIError<STATUS_CODE.BAD_REQUEST> {\n constructor(message: string, details?: unknown) {\n super(STATUS_CODE.BAD_REQUEST, message, \"VALIDATION_ERROR\", details);\n }\n}\n\nexport class NotFoundError extends APIError<STATUS_CODE.NOT_FOUND> {\n constructor(message: string) {\n super(STATUS_CODE.NOT_FOUND, message, \"NOT_FOUND\");\n }\n}\n\nexport class InternalServerError extends APIError<STATUS_CODE.INTERNAL_SERVER_ERROR> {\n constructor(message = \"Internal server error\") {\n super(STATUS_CODE.INTERNAL_SERVER_ERROR, message, \"INTERNAL_SERVER_ERROR\");\n }\n}\n\nexport class BadRequestError extends APIError<STATUS_CODE.BAD_REQUEST> {\n constructor(message = \"Invalid JSON format\", details?: unknown) {\n super(STATUS_CODE.BAD_REQUEST, message, \"BAD_REQUEST\", details);\n }\n}\n\ntype Meta = {\n timestamp: string;\n checksum?: string;\n};\n\ntype ErrorDetail = {\n code: APIErrorCode;\n message: string;\n details?: unknown;\n};\n\nexport type SuccessPayload<T> = Compute<{\n statusCode: STATUS_CODE.SUCCESS;\n body: {\n cursor: string | null;\n data: T;\n meta: Meta;\n };\n}>;\n\nexport type ErrorPayload<\n statusCode extends Exclude<STATUS_CODE, STATUS_CODE.SUCCESS> = Exclude<\n STATUS_CODE,\n STATUS_CODE.SUCCESS\n >,\n> = Compute<{\n statusCode: statusCode;\n body: {\n meta: Meta;\n error: ErrorDetail;\n };\n}>;\n\nexport type Payload<T> = SuccessPayload<T> | ErrorPayload;\n\nexport function success<T>(args: { data: T; cursor?: string | null }): SuccessPayload<T> {\n const { data, cursor } = args;\n return {\n statusCode: STATUS_CODE.SUCCESS as const,\n body: {\n meta: { timestamp: new Date().toISOString() },\n cursor: cursor ?? null,\n data,\n },\n };\n}\n\n/**\n * Generic failure builder. Preserves the concrete status code when the input is an APIError.\n * If not an APIError, maps to INTERNAL_SERVER_ERROR. Zod & SyntaxError are mapped to BAD_REQUEST.\n */\nexport function failure<\n Code extends Exclude<STATUS_CODE, STATUS_CODE.SUCCESS> = Exclude<\n STATUS_CODE,\n STATUS_CODE.SUCCESS\n >,\n>(err: unknown): ErrorPayload<Code> {\n if (err instanceof APIError) {\n // Capture the exact status type from the error instance\n return handleAPIError(err) as ErrorPayload<Code>;\n }\n\n if (err instanceof SyntaxError) {\n return handleAPIError(new BadRequestError(err.message)) as ErrorPayload<Code>;\n }\n\n if (err instanceof z.ZodError) {\n return handleAPIError(handleZodError(err)) as ErrorPayload<Code>;\n }\n\n return handleAPIError(new InternalServerError()) as ErrorPayload<Code>;\n}\n\nfunction handleAPIError<Code extends Exclude<STATUS_CODE, STATUS_CODE.SUCCESS>>(\n error: APIError<Code>,\n): ErrorPayload<Code> {\n return {\n statusCode: error.statusCode,\n body: {\n meta: { timestamp: new Date().toISOString() },\n error: {\n code: error.code,\n message: error.message,\n ...(error.details && typeof error.details === \"object\" ? { details: error.details } : {}),\n },\n },\n };\n}\n\nexport function handleZodError(error: z.ZodError): ValidationError {\n const formattedErrors = error.issues.map((issue) => {\n const field = issue.path.join(\".\");\n let msg = issue.message;\n\n switch (issue.code) {\n case \"invalid_type\":\n if (issue.message.includes(\"received undefined\")) {\n msg = `${field} is required`;\n }\n break;\n case \"invalid_format\":\n msg = issue.format === \"regex\" ? issue.message : `${field} has an invalid format`;\n break;\n default:\n break;\n }\n\n return { field, issue: msg };\n });\n\n return new ValidationError(\"Validation failed\", formattedErrors);\n}\n","import \"reflect-metadata\";\nimport { generateDocument, type OpenAPIDocument } from \"openapi-metadata\";\nimport {\n ApiBody,\n ApiOperation,\n ApiParam,\n ApiProperty,\n ApiQuery,\n ApiResponse,\n ApiTags,\n} from \"openapi-metadata/decorators\";\nimport type { Address, Hex } from \"viem\";\nimport * as Payload from \"../Controllers/Payload.ts\";\n\nconst timestampExample = \"2024-01-01T12:00:00.000Z\";\nconst offerCursorExample = \"eyJvZmZzZXQiOjEwMH0\";\nconst obligationCursorExample =\n \"0x25690ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9abc\";\n\nconst offerExample = {\n offer: {\n obligation: {\n loan_token: \"0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078\",\n collaterals: [\n {\n token: \"0x34Cf890dB685FC536E05652FB41f02090c3fb751\",\n lltv: \"860000000000000000\",\n oracle: \"0x45093658BE7f90B63D7c359e8f408e503c2D9401\",\n },\n ],\n maturity: 1761922799,\n },\n buy: false,\n maker: \"0x7b093658BE7f90B63D7c359e8f408e503c2D9401\",\n assets: \"369216000000000000000000\",\n obligation_units: \"0\",\n obligation_shares: \"0\",\n start: 1761922790,\n expiry: 1761922799,\n price: \"2750000000000000000\",\n group: \"0x000000000000000000000000000000000000000000000000000000000008b8f4\",\n session: \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n callback: \"0x0000000000000000000000000000000000000000\",\n callback_data: \"0x\",\n },\n // Additional API fields (inlined at top level)\n offer_hash: \"0xac4bd8318ec914f89f8af913f162230575b0ac0696a19256bc12138c5cfe1427\",\n obligation_id: \"0x25690ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9abc\",\n chain_id: 1,\n consumed: \"0\",\n takeable: \"369216000000000000000000\",\n block_number: 2942933377146801,\n root: \"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef\",\n proof: [\n \"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890\",\n \"0x9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba\",\n ],\n signature:\n \"0x1234567890123456789012345678901234567890123456789012345678901234123456789012345678901234567890123456789012345678901234567890123400\",\n} as const;\n\nconst collectorsHealthExample = {\n name: \"offers\",\n chain_id: 1,\n block_number: 21345678,\n updated_at: timestampExample,\n lag: 0,\n status: \"live\",\n initialized: true,\n} as const;\n\nconst chainsHealthExample = {\n chain_id: 1,\n local_block_number: 21345678,\n remote_block_number: 21345690,\n updated_at: timestampExample,\n initialized: true,\n} as const;\n\nconst missingCollectorExample = {\n chain_id: 1,\n name: \"offers\",\n} as const;\n\n// Example for validate offer request\nconst validateOfferExample = {\n maker: \"0x7b093658BE7f90B63D7c359e8f408e503c2D9401\",\n assets: \"369216000000000000000000\",\n obligation_units: \"0\",\n obligation_shares: \"0\",\n price: \"2750000000000000000\",\n maturity: 1761922799,\n expiry: 1761922799,\n start: 1761922790,\n group: \"0x000000000000000000000000000000000000000000000000000000000008b8f4\",\n session: \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n buy: false,\n chain_id: 1,\n loan_token: \"0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078\",\n collaterals: [\n {\n asset: \"0x34Cf890dB685FC536E05652FB41f02090c3fb751\",\n oracle: \"0x45093658BE7f90B63D7c359e8f408e503c2D9401\",\n lltv: \"860000000000000000\",\n },\n ],\n callback: {\n address: \"0x0000000000000000000000000000000000000000\",\n data: \"0x\",\n },\n} as const;\n\nconst routerStatusExample = {\n status: \"live\",\n initialized: true,\n missing_chains: [],\n missing_collectors: [],\n} as const;\n\nclass Meta {\n @ApiProperty({ type: \"string\", example: timestampExample })\n declare timestamp: string;\n}\n\nclass SuccessResponse {\n @ApiProperty({ type: () => Meta })\n declare meta: Meta;\n}\n\nclass ErrorResponse {\n @ApiProperty({ type: \"string\", enum: Payload.API_ERROR_CODES, example: \"VALIDATION_ERROR\" })\n declare code: string;\n\n @ApiProperty({\n type: \"string\",\n example: \"Limit must be greater than 0.\",\n })\n declare message: string;\n\n @ApiProperty({\n type: \"object\",\n example: [\n {\n field: \"limit\",\n issue: \"Limit must be greater than 0.\",\n },\n ],\n })\n declare details: unknown;\n}\n\nclass BadRequestResponse {\n @ApiProperty({ type: () => ErrorResponse })\n declare error: ErrorResponse;\n\n @ApiProperty({ type: () => Meta })\n declare meta: Meta;\n}\n\nclass CollateralResponse {\n @ApiProperty({ type: \"string\", example: \"0x34Cf890dB685FC536E05652FB41f02090c3fb751\" })\n declare token: Address;\n\n @ApiProperty({ type: \"string\", example: \"860000000000000000\" })\n declare lltv: string;\n\n @ApiProperty({ type: \"string\", example: \"0x45093658BE7f90B63D7c359e8f408e503c2D9401\" })\n declare oracle: Address;\n}\n\n// Classes for validate request (input format - uses asset, not token)\nclass ValidateCollateralRequest {\n @ApiProperty({ type: \"string\", example: validateOfferExample.collaterals[0].asset })\n declare asset: Address;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.collaterals[0].oracle })\n declare oracle: Address;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.collaterals[0].lltv })\n declare lltv: string;\n}\n\nclass ValidateCallbackRequest {\n @ApiProperty({ type: \"string\", example: validateOfferExample.callback.address })\n declare address: Address;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.callback.data })\n declare data: Hex;\n}\n\nclass AskResponse {\n @ApiProperty({ type: \"string\", example: \"1000000000000000000\" })\n declare price: string;\n}\n\nclass BidResponse {\n @ApiProperty({ type: \"string\", example: \"1000000000000000000\" })\n declare price: string;\n}\n\nclass ObligationOfferResponse {\n @ApiProperty({ type: \"string\", example: offerExample.offer.obligation.loan_token })\n declare loan_token: Address;\n\n @ApiProperty({\n type: () => [CollateralResponse],\n example: offerExample.offer.obligation.collaterals,\n })\n declare collaterals: CollateralResponse[];\n\n @ApiProperty({ type: \"number\", example: offerExample.offer.obligation.maturity })\n declare maturity: number;\n}\n\nclass OfferDataResponse {\n @ApiProperty({ type: () => ObligationOfferResponse, example: offerExample.offer.obligation })\n declare obligation: ObligationOfferResponse;\n\n @ApiProperty({ type: \"boolean\", example: offerExample.offer.buy })\n declare buy: boolean;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer.maker })\n declare maker: Address;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer.assets })\n declare assets: string;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer.obligation_units })\n declare obligation_units: string;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer.obligation_shares })\n declare obligation_shares: string;\n\n @ApiProperty({ type: \"number\", example: offerExample.offer.start })\n declare start: number;\n\n @ApiProperty({ type: \"number\", example: offerExample.offer.expiry })\n declare expiry: number;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer.price })\n declare price: string;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer.group })\n declare group: string;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer.session })\n declare session: string;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer.callback })\n declare callback: Address;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer.callback_data })\n declare callback_data: Hex;\n}\n\nclass OfferListItemResponse {\n @ApiProperty({ type: () => OfferDataResponse, example: offerExample.offer })\n declare offer: OfferDataResponse;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer_hash })\n declare offer_hash: Hex;\n\n @ApiProperty({ type: \"string\", example: offerExample.obligation_id })\n declare obligation_id: Hex;\n\n @ApiProperty({ type: \"number\", example: offerExample.chain_id })\n declare chain_id: number;\n\n @ApiProperty({ type: \"string\", example: offerExample.consumed })\n declare consumed: string;\n\n @ApiProperty({ type: \"string\", example: offerExample.takeable })\n declare takeable: string;\n\n @ApiProperty({ type: \"number\", example: offerExample.block_number })\n declare block_number: number;\n\n @ApiProperty({ type: \"string\", nullable: true, example: offerExample.root })\n declare root: Hex | null;\n\n @ApiProperty({ type: [String], nullable: true, example: offerExample.proof })\n declare proof: Hex[] | null;\n\n @ApiProperty({ type: \"string\", nullable: true, example: offerExample.signature })\n declare signature: Hex | null;\n}\n\nclass ObligationResponse {\n @ApiProperty({\n type: \"string\",\n example: \"0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67\",\n })\n declare id: Hex;\n\n @ApiProperty({ type: \"number\", example: 1 })\n declare chain_id: number;\n\n @ApiProperty({ type: \"string\", example: \"0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078\" })\n declare loan_token: Address;\n\n @ApiProperty({ type: () => [CollateralResponse] })\n declare collaterals: CollateralResponse[];\n\n @ApiProperty({ type: \"number\", example: 1761922800 })\n declare maturity: number;\n\n @ApiProperty({ type: () => AskResponse })\n declare ask: AskResponse;\n\n @ApiProperty({ type: () => BidResponse })\n declare bid: BidResponse;\n}\nclass ObligationListResponse extends SuccessResponse {\n @ApiProperty({ type: \"string\", nullable: true, example: obligationCursorExample })\n declare cursor: string | null;\n\n @ApiProperty({\n type: () => [ObligationResponse],\n description: \"List of obligations with takable offers.\",\n })\n declare data: ObligationResponse[];\n}\n\nclass ObligationSingleSuccessResponse extends SuccessResponse {\n @ApiProperty({ type: \"string\", nullable: true, example: null })\n declare cursor: string | null;\n\n @ApiProperty({ type: () => ObligationResponse, description: \"Obligation details.\" })\n declare data: ObligationResponse;\n}\n\nclass OfferListResponse extends SuccessResponse {\n @ApiProperty({\n type: \"string\",\n nullable: true,\n example: offerCursorExample,\n description:\n \"Pagination cursor. Offer hash (0x...) for maker queries; base64url-encoded cursor for obligation queries.\",\n })\n declare cursor: string | null;\n\n @ApiProperty({\n type: () => [OfferListItemResponse],\n description: \"Offers matching the provided filters.\",\n example: [offerExample],\n })\n declare data: OfferListItemResponse[];\n}\n\nclass MissingCollectorResponse {\n @ApiProperty({ type: \"number\", example: missingCollectorExample.chain_id })\n declare chain_id: number;\n\n @ApiProperty({ type: \"string\", example: missingCollectorExample.name })\n declare name: string;\n}\n\nclass RouterStatusDataResponse {\n @ApiProperty({ type: \"string\", enum: [\"live\", \"syncing\"], example: routerStatusExample.status })\n declare status: \"live\" | \"syncing\";\n\n @ApiProperty({ type: \"boolean\", example: routerStatusExample.initialized })\n declare initialized: boolean;\n\n @ApiProperty({\n type: () => [Number],\n example: routerStatusExample.missing_chains,\n description: \"Configured chain ids missing initialization rows.\",\n })\n declare missing_chains: number[];\n\n @ApiProperty({\n type: () => [MissingCollectorResponse],\n example: routerStatusExample.missing_collectors,\n description: \"Collectors missing initialization rows.\",\n })\n declare missing_collectors: MissingCollectorResponse[];\n}\n\nclass RouterStatusSuccessResponse extends SuccessResponse {\n @ApiProperty({\n type: () => RouterStatusDataResponse,\n description: \"Aggregated router status.\",\n example: routerStatusExample,\n })\n declare data: RouterStatusDataResponse;\n}\n\nclass CollectorHealthResponse {\n @ApiProperty({ type: \"string\", example: collectorsHealthExample.name })\n declare name: string;\n\n @ApiProperty({ type: \"number\", example: collectorsHealthExample.chain_id })\n declare chain_id: number;\n\n @ApiProperty({ type: \"number\", nullable: true, example: collectorsHealthExample.block_number })\n declare block_number: number | null;\n\n @ApiProperty({ type: \"string\", nullable: true, example: collectorsHealthExample.updated_at })\n declare updated_at: string | null;\n\n @ApiProperty({ type: \"number\", nullable: true, example: collectorsHealthExample.lag })\n declare lag: number | null;\n\n @ApiProperty({\n type: \"string\",\n enum: [\"live\", \"lagging\", \"unknown\"],\n example: collectorsHealthExample.status,\n })\n declare status: \"live\" | \"lagging\" | \"unknown\";\n\n @ApiProperty({ type: \"boolean\", example: collectorsHealthExample.initialized })\n declare initialized: boolean;\n}\n\nclass CollectorsHealthSuccessResponse extends SuccessResponse {\n @ApiProperty({\n type: () => [CollectorHealthResponse],\n description: \"Collectors health details and sync status.\",\n example: [collectorsHealthExample],\n })\n declare data: CollectorHealthResponse[];\n}\n\nclass ChainHealthResponse {\n @ApiProperty({ type: \"number\", example: chainsHealthExample.chain_id })\n declare chain_id: number;\n\n @ApiProperty({\n type: \"number\",\n nullable: true,\n example: chainsHealthExample.local_block_number,\n })\n declare local_block_number: number | null;\n\n @ApiProperty({ type: \"number\", nullable: true, example: chainsHealthExample.remote_block_number })\n declare remote_block_number: number | null;\n\n @ApiProperty({ type: \"string\", nullable: true, example: chainsHealthExample.updated_at })\n declare updated_at: string | null;\n\n @ApiProperty({ type: \"boolean\", example: chainsHealthExample.initialized })\n declare initialized: boolean;\n}\n\nclass ChainsHealthSuccessResponse extends SuccessResponse {\n @ApiProperty({\n type: () => [ChainHealthResponse],\n description: \"Latest processed block per chain.\",\n example: [chainsHealthExample],\n })\n declare data: ChainHealthResponse[];\n}\n\nclass ValidateOfferRequest {\n @ApiProperty({ type: \"string\", example: validateOfferExample.maker })\n declare maker: Address;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.assets })\n declare assets: string;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.obligation_units, required: false })\n declare obligation_units: string;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.obligation_shares, required: false })\n declare obligation_shares: string;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.price })\n declare price: string;\n\n @ApiProperty({ type: \"number\", example: validateOfferExample.maturity })\n declare maturity: number;\n\n @ApiProperty({ type: \"number\", example: validateOfferExample.expiry })\n declare expiry: number;\n\n @ApiProperty({ type: \"number\", example: validateOfferExample.start })\n declare start: number;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.group })\n declare group: string;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.session })\n declare session: string;\n\n @ApiProperty({ type: \"boolean\", example: validateOfferExample.buy })\n declare buy: boolean;\n\n @ApiProperty({ type: \"number\", example: validateOfferExample.chain_id })\n declare chain_id: number;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.loan_token })\n declare loan_token: Address;\n\n @ApiProperty({\n type: () => [ValidateCollateralRequest],\n example: validateOfferExample.collaterals,\n })\n declare collaterals: ValidateCollateralRequest[];\n\n @ApiProperty({ type: () => ValidateCallbackRequest, example: validateOfferExample.callback })\n declare callback: ValidateCallbackRequest;\n}\n\nclass ValidateOffersRequest {\n @ApiProperty({\n type: () => [ValidateOfferRequest],\n description: \"Array of offers in snake_case format. Required, non-empty.\",\n required: true,\n })\n declare offers: ValidateOfferRequest[];\n}\n\nclass ValidationSuccessDataResponse {\n @ApiProperty({\n type: \"string\",\n description: \"Unsigned payload: version (1B) + gzip(offers) + root (32B).\",\n example: \"0x01789c...\",\n })\n declare payload: Hex;\n\n @ApiProperty({\n type: \"string\",\n description: \"Merkle tree root to sign with EIP-191.\",\n example: \"0xac4bd8318ec914f89f8af913f162230575b0ac0696a19256bc12138c5cfe1427\",\n })\n declare root: Hex;\n}\n\nclass ValidationSuccessResponse extends SuccessResponse {\n @ApiProperty({ type: \"string\", nullable: true, example: null })\n declare cursor: string | null;\n\n @ApiProperty({\n type: () => ValidationSuccessDataResponse,\n description: \"Payload and root for client-side signing.\",\n })\n declare data: ValidationSuccessDataResponse;\n}\n\nclass ValidationIssueResponse {\n @ApiProperty({\n type: \"number\",\n description: \"0-indexed position of the failed offer in the request array.\",\n example: 0,\n })\n declare index: number;\n\n @ApiProperty({\n type: \"string\",\n description: \"Gatekeeper rule name that rejected the offer.\",\n example: \"no_buy\",\n })\n declare rule: string;\n\n @ApiProperty({\n type: \"string\",\n description: \"Human-readable rejection reason.\",\n example: \"Buy offers are not supported\",\n })\n declare message: string;\n}\n\nclass ValidationFailureDataResponse {\n @ApiProperty({\n type: () => [ValidationIssueResponse],\n description: \"List of validation issues. Returned when any offer fails validation.\",\n })\n declare issues: ValidationIssueResponse[];\n}\n\nclass ValidationFailureResponse extends SuccessResponse {\n @ApiProperty({ type: \"string\", nullable: true, example: null })\n declare cursor: string | null;\n\n @ApiProperty({\n type: () => ValidationFailureDataResponse,\n description: \"List of validation issues. Returned when any offer fails validation.\",\n })\n declare data: ValidationFailureDataResponse;\n}\n\nclass BookLevelResponse {\n @ApiProperty({ type: \"string\", example: \"2750000000000000000\" })\n declare price: string;\n\n @ApiProperty({ type: \"string\", example: \"369216000000000000000000\" })\n declare assets: string;\n\n @ApiProperty({ type: \"number\", example: 5 })\n declare count: number;\n}\n\nconst positionExample = {\n chain_id: 1,\n contract: \"0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078\",\n user: \"0x7b093658BE7f90B63D7c359e8f408e503c2D9401\",\n reserved: \"200000000000000000000\",\n block_number: 21345678,\n} as const;\n\nclass PositionListItemResponse {\n @ApiProperty({ type: \"number\", example: positionExample.chain_id })\n declare chain_id: number;\n\n @ApiProperty({ type: \"string\", example: positionExample.contract })\n declare contract: string;\n\n @ApiProperty({ type: \"string\", example: positionExample.user })\n declare user: string;\n\n @ApiProperty({ type: \"string\", example: positionExample.reserved })\n declare reserved: string;\n\n @ApiProperty({ type: \"number\", example: positionExample.block_number })\n declare block_number: number;\n}\n\nclass PositionListResponse extends SuccessResponse {\n @ApiProperty({ type: \"string\", nullable: true, example: offerCursorExample })\n declare cursor: string | null;\n\n @ApiProperty({\n type: () => [PositionListItemResponse],\n description: \"User positions with reserved balances from active offers.\",\n example: [positionExample],\n })\n declare data: PositionListItemResponse[];\n}\n\nclass BookListResponse extends SuccessResponse {\n @ApiProperty({ type: \"string\", nullable: true, example: offerCursorExample })\n declare cursor: string | null;\n\n @ApiProperty({\n type: () => [BookLevelResponse],\n description: \"Aggregated book levels grouped by computed price.\",\n })\n declare data: BookLevelResponse[];\n}\n\n@ApiTags(\"Markets\")\n@ApiResponse({ status: 400, description: \"Bad Request\", type: BadRequestResponse })\nexport class BooksController {\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/books/{obligationId}/{side}\",\n summary: \"Get aggregated book\",\n description:\n \"Returns aggregated book data for a given obligation and side. Offers are grouped by computed price with summed takeable amounts. Book levels are sorted by price (ascending for buy side, descending for sell side).\",\n })\n @ApiParam({\n name: \"obligationId\",\n type: \"string\",\n example: \"0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67\",\n description: \"Obligation id.\",\n })\n @ApiParam({\n name: \"side\",\n type: \"string\",\n enum: [\"buy\", \"sell\"],\n example: \"buy\",\n description: \"Book side (buy or sell).\",\n })\n @ApiQuery({\n name: \"cursor\",\n type: \"string\",\n example: offerCursorExample,\n description: \"Pagination cursor in base64url-encoded format.\",\n })\n @ApiQuery({\n name: \"limit\",\n type: \"number\",\n example: 10,\n description: \"Maximum number of price levels to return.\",\n })\n @ApiResponse({ status: 200, description: \"Success\", type: BookListResponse })\n async getBook() {}\n}\n\n@ApiTags(\"Make\")\n@ApiResponse({ status: 400, description: \"Bad Request\", type: BadRequestResponse })\nexport class ValidateController {\n @ApiOperation({\n methods: [\"post\"],\n path: \"/v1/validate\",\n summary: \"Validate offers\",\n description:\n \"Validates offers against router validation rules. Only empty callbacks (zero address, 0x data) are accepted. Returns unsigned payload + root on success, or issues only on validation failure.\",\n })\n @ApiBody({ type: ValidateOffersRequest })\n @ApiResponse({ status: 200, description: \"Success\", type: ValidationSuccessResponse })\n @ApiResponse({ status: 200, description: \"Validation issues\", type: ValidationFailureResponse })\n async validateOffers() {}\n}\n\n@ApiTags(\"Markets\")\n@ApiResponse({ status: 400, description: \"Bad Request\", type: BadRequestResponse })\nexport class OffersController {\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/offers\",\n summary: \"List all offers\",\n description:\n \"Returns offers. Provide either `obligation_id` + `side` (order book) or `maker` (by maker address).\",\n })\n @ApiQuery({\n name: \"side\",\n type: \"string\",\n required: false,\n enum: [\"buy\", \"sell\"],\n example: \"buy\",\n description: \"Side of the offer. Required when using obligation_id.\",\n })\n @ApiQuery({\n name: \"obligation_id\",\n type: \"string\",\n required: false,\n example: \"0x1234567890123456789012345678901234567890123456789012345678901234\",\n description: \"Obligation id used to filter offers. Required when not using maker.\",\n })\n @ApiQuery({\n name: \"maker\",\n type: \"string\",\n required: false,\n example: \"0x7b093658BE7f90B63D7c359e8f408e503c2D9401\",\n description: \"Maker address to filter offers by. Alternative to obligation_id + side.\",\n })\n @ApiQuery({\n name: \"cursor\",\n type: \"string\",\n example: offerCursorExample,\n description: \"Pagination cursor in base64url-encoded format.\",\n })\n @ApiQuery({\n name: \"limit\",\n type: \"number\",\n example: 10,\n description: \"Maximum number of offers to return.\",\n })\n @ApiResponse({ status: 200, description: \"Success\", type: OfferListResponse })\n async getOffers() {}\n}\n\n@ApiTags(\"System\")\nexport class HealthController {\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/health\",\n summary: \"Retrieve global health\",\n description: \"Returns the aggregated status of the router.\",\n })\n @ApiQuery({\n name: \"strict\",\n type: \"boolean\",\n required: false,\n example: true,\n description: \"Fail the request if initialization is incomplete.\",\n })\n @ApiResponse({ status: 200, description: \"Success\", type: RouterStatusSuccessResponse })\n async getRouterStatus() {}\n\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/health/collectors\",\n summary: \"Retrieve collectors health\",\n description: \"Returns the latest block numbers processed by collectors and their sync status.\",\n })\n @ApiQuery({\n name: \"strict\",\n type: \"boolean\",\n required: false,\n example: true,\n description: \"Fail the request if initialization is incomplete.\",\n })\n @ApiResponse({ status: 200, description: \"Success\", type: CollectorsHealthSuccessResponse })\n async getCollectorsHealth() {}\n\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/health/chains\",\n summary: \"Retrieve chains health\",\n description: \"Returns the latest block that can be processed by collectors for each chain.\",\n })\n @ApiQuery({\n name: \"strict\",\n type: \"boolean\",\n required: false,\n example: true,\n description: \"Fail the request if initialization is incomplete.\",\n })\n @ApiResponse({ status: 200, description: \"Success\", type: ChainsHealthSuccessResponse })\n async getChainsHealth() {}\n}\n\nconst configContractsExample = {\n chain_id: 505050505,\n address: \"0xD946246695A9259F3B33a78629026F61B3Ab40aF\",\n name: \"mempool\",\n} as const;\n\nconst configContractsPayloadExample = [\n {\n chain_id: 505050505,\n address: \"0xD946246695A9259F3B33a78629026F61B3Ab40aF\",\n name: \"mempool\",\n },\n {\n chain_id: 505050505,\n address: \"0x8A409D5D6394fC197c596d4E6E2c35e5d13f8a4d\",\n name: \"multicall\",\n },\n {\n chain_id: 505050505,\n address: \"0x23DFBc4B8B80C14CC5e25011B8491f268395BAd6\",\n name: \"v2\",\n },\n] as const;\n\nconst configRulesMaturityExample = {\n type: \"maturity\",\n chain_id: 1,\n name: \"end_of_next_month\",\n timestamp: 1730415600,\n} as const;\n\nconst configRulesLoanTokenExample = {\n type: \"loan_token\",\n chain_id: 1,\n address: \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\",\n} as const;\n\nconst configRulesOracleExample = {\n type: \"oracle\",\n chain_id: 1,\n address: \"0xDddd770BADd886dF3864029e4B377B5F6a2B6b83\",\n} as const;\n\nconst configRulesChecksumExample = \"f1d2d2f924e986ac86fdf7b36c94bcdf\" as const;\nconst configRulesPayloadExample = [\n configRulesMaturityExample,\n configRulesLoanTokenExample,\n configRulesOracleExample,\n] as const;\n\nconst configContractNames = [\"mempool\", \"multicall\", \"v2\"] as const;\nconst configContractsCursorExample = \"505050505:0xd946246695a9259f3b33a78629026f61b3ab40af\";\n\nclass ConfigContractResponse {\n @ApiProperty({ type: \"number\", example: configContractsExample.chain_id })\n declare chain_id: number;\n\n @ApiProperty({ type: \"string\", example: configContractsExample.address })\n declare address: Address;\n\n @ApiProperty({\n type: \"string\",\n enum: configContractNames,\n example: configContractsExample.name,\n })\n declare name: (typeof configContractNames)[number];\n}\n\nclass ConfigContractsSuccessResponse extends SuccessResponse {\n @ApiProperty({ type: \"string\", nullable: true, example: null })\n declare cursor: string | null;\n\n @ApiProperty({\n type: () => [ConfigContractResponse],\n description: \"Indexer contract configuration for all indexed chains.\",\n example: configContractsPayloadExample,\n })\n declare data: ConfigContractResponse[];\n}\n\nclass ConfigRulesMeta {\n @ApiProperty({ type: \"string\", example: timestampExample })\n declare timestamp: string;\n\n @ApiProperty({ type: \"string\", example: configRulesChecksumExample })\n declare checksum: string;\n}\n\nclass ConfigRulesRuleResponse {\n @ApiProperty({ type: \"string\", example: configRulesMaturityExample.type })\n declare type: string;\n\n @ApiProperty({ type: \"number\", example: configRulesMaturityExample.chain_id })\n declare chain_id: number;\n\n @ApiProperty({ type: \"string\", example: configRulesMaturityExample.name, required: false })\n declare name?: string;\n\n @ApiProperty({ type: \"number\", example: configRulesMaturityExample.timestamp, required: false })\n declare timestamp?: number;\n\n @ApiProperty({ type: \"string\", example: configRulesLoanTokenExample.address, required: false })\n declare address?: Address;\n}\n\nclass ConfigRulesSuccessResponse {\n @ApiProperty({ type: () => ConfigRulesMeta })\n declare meta: ConfigRulesMeta;\n\n @ApiProperty({ type: \"string\", nullable: true, example: null })\n declare cursor: string | null;\n\n @ApiProperty({\n type: () => [ConfigRulesRuleResponse],\n description: \"Configured rules returned by the router API.\",\n example: configRulesPayloadExample,\n })\n declare data: ConfigRulesRuleResponse[];\n}\n\n@ApiTags(\"System\")\nexport class ConfigContractsController {\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/config/contracts\",\n summary: \"Get indexer contract configuration\",\n description:\n \"Returns contract addresses used by indexers (mempool, v2) and multicall for indexed chains.\",\n })\n @ApiQuery({\n name: \"cursor\",\n type: \"string\",\n required: false,\n example: configContractsCursorExample,\n description: \"Pagination cursor in chain_id:address format (lowercase address).\",\n })\n @ApiQuery({\n name: \"limit\",\n type: \"number\",\n required: false,\n example: 1000,\n description: \"Maximum number of contracts to return (max 1000).\",\n })\n @ApiQuery({\n name: \"chains\",\n type: [\"number\"],\n required: false,\n example: \"1,8453\",\n description: \"Filter by chain IDs (comma-separated).\",\n style: \"form\",\n explode: false,\n })\n @ApiResponse({ status: 200, description: \"Success\", type: ConfigContractsSuccessResponse })\n async getConfigContracts() {}\n}\n\n@ApiTags(\"System\")\nexport class ConfigRulesController {\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/config/rules\",\n summary: \"Get config rules\",\n description:\n \"Returns configured rules (maturities, loan tokens, oracles) for supported chains.\",\n })\n @ApiQuery({\n name: \"cursor\",\n type: \"string\",\n required: false,\n example: \"maturity:1:1730415600:end_of_next_month\",\n description: \"Pagination cursor in type:chain_id:<value> format.\",\n })\n @ApiQuery({\n name: \"limit\",\n type: \"number\",\n required: false,\n example: 100,\n description: \"Maximum number of rules to return (max 1000).\",\n })\n @ApiQuery({\n name: \"types\",\n type: [\"string\"],\n required: false,\n example: \"maturity,loan_token,oracle\",\n description: \"Filter by rule types (comma-separated).\",\n style: \"form\",\n explode: false,\n })\n @ApiQuery({\n name: \"chains\",\n type: [\"number\"],\n required: false,\n example: \"1,8453\",\n description: \"Filter by chain IDs (comma-separated).\",\n style: \"form\",\n explode: false,\n })\n @ApiResponse({ status: 200, description: \"Success\", type: ConfigRulesSuccessResponse })\n async getConfigRules() {}\n}\n\n@ApiTags(\"Markets\")\n@ApiResponse({ status: 400, description: \"Bad Request\", type: BadRequestResponse })\nexport class ObligationsController {\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/obligations\",\n summary: \"List all obligations\",\n description:\n \"Returns a list of obligations with their current best ask and bid. Obligations are sorted by their id in ascending order by default.\",\n })\n @ApiQuery({\n name: \"cursor\",\n type: \"string\",\n example: obligationCursorExample,\n description: \"Obligation id cursor for pagination.\",\n })\n @ApiQuery({\n name: \"limit\",\n type: \"number\",\n example: 10,\n description: \"Maximum number of obligations to return.\",\n })\n @ApiQuery({\n name: \"chains\",\n type: [\"number\"],\n required: false,\n example: \"1,8453\",\n description: \"Filter by chain IDs (comma-separated).\",\n style: \"form\",\n explode: false,\n })\n @ApiQuery({\n name: \"loan_tokens\",\n type: [\"string\"],\n required: false,\n example:\n \"0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078,0x34Cf890dB685FC536E05652FB41f02090c3fb751\",\n description: \"Filter by loan token addresses (comma-separated).\",\n style: \"form\",\n explode: false,\n })\n @ApiQuery({\n name: \"collateral_tokens\",\n type: [\"string\"],\n required: false,\n example:\n \"0x34Cf890dB685FC536E05652FB41f02090c3fb751,0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078\",\n description: \"Filter by collateral tokens (comma-separated, matches any collateral).\",\n style: \"form\",\n explode: false,\n })\n @ApiQuery({\n name: \"maturities\",\n type: [\"number\"],\n required: false,\n example: \"1761922800,1764524800\",\n description: \"Filter by exact maturity timestamps (comma-separated, unix seconds).\",\n style: \"form\",\n explode: false,\n })\n @ApiResponse({ status: 200, description: \"Success\", type: ObligationListResponse })\n async getObligations() {}\n\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/obligations/{obligationId}\",\n summary: \"Get an obligation\",\n description: \"Returns an obligation by its id.\",\n })\n @ApiParam({\n name: \"obligationId\",\n type: \"string\",\n example: \"0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67\",\n description: \"Obligation id.\",\n })\n @ApiResponse({ status: 200, description: \"Success\", type: ObligationSingleSuccessResponse })\n async getObligation() {}\n}\n\n@ApiTags(\"Make\")\n@ApiResponse({ status: 400, description: \"Bad Request\", type: BadRequestResponse })\nexport class UsersController {\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/users/{userAddress}/positions\",\n summary: \"Get user positions\",\n description:\n \"Returns positions for a user with reserved balance. The reserved balance is the amount locked by active offers (max lot upper - offset - consumed).\",\n })\n @ApiParam({\n name: \"userAddress\",\n type: \"string\",\n example: \"0x7b093658BE7f90B63D7c359e8f408e503c2D9401\",\n description: \"User address to get positions for.\",\n })\n @ApiQuery({\n name: \"cursor\",\n type: \"string\",\n example: offerCursorExample,\n description: \"Pagination cursor in base64url-encoded format.\",\n })\n @ApiQuery({\n name: \"limit\",\n type: \"number\",\n example: 10,\n description: \"Maximum number of positions to return.\",\n })\n @ApiResponse({ status: 200, description: \"Success\", type: PositionListResponse })\n async getUserPositions() {}\n}\n\nexport const OpenApi = async (): Promise<OpenAPIDocument> => {\n const document = await generateDocument({\n controllers: [\n BooksController,\n ConfigContractsController,\n ConfigRulesController,\n OffersController,\n ObligationsController,\n HealthController,\n UsersController,\n ValidateController,\n ],\n document: {\n openapi: \"3.1.0\",\n info: {\n title: \"Router API\",\n version: \"1.0.0\",\n description: \"API for the Morpho Router\",\n },\n servers: [\n {\n url: \"https://router.morpho.dev\",\n description: \"Production server\",\n },\n {\n url: \"http://localhost:7891\",\n description: \"Local development server\",\n },\n ],\n tags: [\n {\n name: \"Markets\",\n description:\n \"Read-only endpoints to discover markets, order books and fetch current offers.\",\n },\n {\n name: \"Make\",\n description: \"Utilities to ease making offers.\",\n },\n {\n name: \"System\",\n description: \"Router configuration and health monitoring.\",\n },\n ],\n },\n });\n\n return document;\n};\n","import type { Address } from \"viem\";\nimport type { Chain } from \"#core\";\nimport type { getByUser } from \"#database/domains/Positions.ts\";\n\nexport type PositionResponse = {\n chain_id: Chain.Id;\n contract: Address;\n user: Address;\n reserved: string;\n block_number: number;\n};\n\nexport type PositionWithReserved = getByUser.PositionWithReserved;\n\n/**\n * Creates a `PositionResponse` from a `PositionWithReserved`.\n * @param position - {@link PositionWithReserved}\n * @returns The created `PositionResponse`. {@link PositionResponse}\n */\nexport function from(position: PositionWithReserved): PositionResponse {\n return {\n chain_id: position.chainId,\n contract: position.contract,\n user: position.user,\n reserved: position.reserved.toString(),\n block_number: position.blockNumber,\n };\n}\n","import type { Address, Hex } from \"viem\";\nimport * as z from \"zod\";\n\nconst MAX_LIMIT = 100;\nconst DEFAULT_LIMIT = 20;\nconst CONFIG_RULES_MAX_LIMIT = 1000;\nconst CONFIG_RULES_DEFAULT_LIMIT = 100;\nconst CONFIG_CONTRACTS_MAX_LIMIT = 1000;\nconst CONFIG_CONTRACTS_DEFAULT_LIMIT = 1000;\n\n/** Validate cursor is a valid base64url-encoded JSON object.\n * Domain layer handles semantic validation of cursor fields. */\nfunction isValidBase64urlJson(val: string): boolean {\n try {\n const decoded = Buffer.from(val, \"base64url\").toString(\"utf8\");\n JSON.parse(decoded);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isValidOfferHashCursor(val: string): boolean {\n return /^0x[a-f0-9]{64}$/i.test(val);\n}\n\nconst csvArray = <T extends z.ZodTypeAny>(schema: T) =>\n z\n .preprocess((value) => {\n if (value === undefined) return undefined;\n if (Array.isArray(value)) {\n if (value.some((item) => typeof item !== \"string\")) return value;\n return value\n .flatMap((item) => item.split(\",\"))\n .map((item) => item.trim())\n .filter((item) => item.length > 0);\n }\n if (typeof value === \"string\") {\n return value\n .split(\",\")\n .map((item) => item.trim())\n .filter((item) => item.length > 0);\n }\n return value;\n }, z.array(schema))\n .optional();\n\nconst PaginationQueryParams = z.object({\n cursor: z\n .string()\n .optional()\n .refine(\n (val) => {\n if (!val) return true; // Optional field\n // Accept any valid base64url-encoded JSON object\n // Domain layer handles semantic validation of cursor fields\n return isValidBase64urlJson(val);\n },\n {\n message: \"Invalid cursor format. Must be a valid base64url-encoded cursor object\",\n },\n )\n .meta({\n description: \"Pagination cursor in base64url-encoded format\",\n example:\n \"eyJzaWRlIjoic2VsbCIsImN1cnJlbnRQcmljZSI6IjEwMDAwMDAwMDAwMDAwMDAwMDAiLCJibG9ja051bWJlciI6MSwiYXNzZXRzIjoiMTAwMDAwMDAwMDAwMDAwMDAwMCIsImhhc2giOiIweGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIiLCJ0b3RhbFJldHVybmVkIjoxMCwibm93IjoxNjAwMDAwMDAwfQ\",\n }),\n limit: z\n .string()\n .regex(/^[1-9]\\d*$/, {\n message: \"Limit must be a positive integer\",\n })\n .transform((val) => Number.parseInt(val, 10))\n .pipe(\n z.number().max(MAX_LIMIT, {\n message: `Limit cannot exceed ${MAX_LIMIT}`,\n }),\n )\n .optional()\n .default(DEFAULT_LIMIT)\n .meta({\n description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT}`,\n example: 10,\n }),\n});\n\nconst ConfigRuleTypes = z.enum([\"maturity\", \"callback\", \"loan_token\", \"oracle\"]);\n\nexport const GetConfigRulesQueryParams = z.object({\n cursor: z\n .string()\n .regex(/^(maturity|callback|loan_token|oracle):[1-9]\\d*:.+$/, {\n message: \"Cursor must be in the format type:chain_id:<value>\",\n })\n .optional()\n .meta({\n description: \"Pagination cursor in type:chain_id:<value> format\",\n example: \"maturity:1:1730415600:end_of_next_month\",\n }),\n limit: z\n .string()\n .regex(/^[1-9]\\d*$/, {\n message: \"Limit must be a positive integer\",\n })\n .transform((val) => Number.parseInt(val, 10))\n .pipe(\n z.number().max(CONFIG_RULES_MAX_LIMIT, {\n message: `Limit cannot exceed ${CONFIG_RULES_MAX_LIMIT}`,\n }),\n )\n .optional()\n .default(CONFIG_RULES_DEFAULT_LIMIT)\n .meta({\n description: `Limit maximum: ${CONFIG_RULES_MAX_LIMIT}. Default: ${CONFIG_RULES_DEFAULT_LIMIT}`,\n example: 100,\n }),\n types: csvArray(ConfigRuleTypes).meta({\n description: \"Filter by rule types (comma-separated).\",\n example: \"maturity,loan_token,oracle\",\n }),\n chains: csvArray(\n z\n .string()\n .regex(/^[1-9]\\d*$/, { message: \"Chain must be a positive integer\" })\n .transform((val) => Number.parseInt(val, 10)),\n ).meta({\n description: \"Filter by chain IDs (comma-separated).\",\n example: \"1,8453\",\n }),\n});\n\nexport const GetConfigContractsQueryParams = z.object({\n cursor: z\n .string()\n .regex(/^[1-9]\\d*:0x[a-fA-F0-9]{40}$/, {\n message: \"Cursor must be in the format chain_id:0x...\",\n })\n .optional()\n .meta({\n description: \"Pagination cursor in chain_id:address format (lowercase address).\",\n example: \"1:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48\",\n }),\n limit: z\n .string()\n .regex(/^[1-9]\\d*$/, {\n message: \"Limit must be a positive integer\",\n })\n .transform((val) => Number.parseInt(val, 10))\n .pipe(\n z.number().max(CONFIG_CONTRACTS_MAX_LIMIT, {\n message: `Limit cannot exceed ${CONFIG_CONTRACTS_MAX_LIMIT}`,\n }),\n )\n .optional()\n .default(CONFIG_CONTRACTS_DEFAULT_LIMIT)\n .meta({\n description: `Limit maximum: ${CONFIG_CONTRACTS_MAX_LIMIT}. Default: ${CONFIG_CONTRACTS_DEFAULT_LIMIT}`,\n example: 1000,\n }),\n chains: csvArray(\n z\n .string()\n .regex(/^[1-9]\\d*$/, { message: \"Chain must be a positive integer\" })\n .transform((val) => Number.parseInt(val, 10)),\n ).meta({\n description: \"Filter by chain IDs (comma-separated).\",\n example: \"1,8453\",\n }),\n});\n\nexport const GetOffersQueryParams = PaginationQueryParams.omit({ cursor: true })\n .extend({\n cursor: z.string().optional().meta({\n description:\n \"Pagination cursor. Use offer hash (0x...) for maker queries, base64url for obligation queries.\",\n example:\n \"eyJzaWRlIjoic2VsbCIsImN1cnJlbnRQcmljZSI6IjEwMDAwMDAwMDAwMDAwMDAwMDAiLCJibG9ja051bWJlciI6MSwiYXNzZXRzIjoiMTAwMDAwMDAwMDAwMDAwMDAwMCIsImhhc2giOiIweGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIiLCJ0b3RhbFJldHVybmVkIjoxMCwibm93IjoxNjAwMDAwMDAwfQ\",\n }),\n side: z.enum([\"buy\", \"sell\"]).optional().meta({\n description: \"Side of the offer. Required when using obligation_id.\",\n example: \"buy\",\n }),\n obligation_id: z\n .string()\n .regex(/^0x[a-fA-F0-9]{64}$/, { error: \"Obligation id must be a valid 32-byte hex string\" })\n .transform<Hex>((val) => val.toLowerCase() as Hex)\n .optional()\n .meta({\n description: \"Offers obligation id. Required when not using maker.\",\n example: \"0x1234567890123456789012345678901234567890123456789012345678901234\",\n }),\n maker: z\n .string()\n .regex(/^0x[a-fA-F0-9]{40}$/, { error: \"Maker must be a valid 20-byte address\" })\n .transform<Address>((val) => val.toLowerCase() as Address)\n .optional()\n .meta({\n description: \"Maker address to filter offers by. Alternative to obligation_id + side.\",\n example: \"0x7b093658BE7f90B63D7c359e8f408e503c2D9401\",\n }),\n })\n .superRefine((val, ctx) => {\n const hasObligation = val.obligation_id !== undefined;\n const hasSide = val.side !== undefined;\n const hasMaker = val.maker !== undefined;\n\n if (hasMaker && (hasObligation || hasSide)) {\n ctx.addIssue({\n code: \"custom\",\n message: \"Cannot use both maker and obligation_id/side parameters\",\n });\n return;\n }\n\n if (hasMaker) {\n if (val.cursor !== undefined && !isValidOfferHashCursor(val.cursor)) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"cursor\"],\n message: \"Cursor must be a 32-byte hex offer hash when filtering by maker\",\n });\n }\n return;\n }\n\n if (!hasObligation || !hasSide) {\n ctx.addIssue({\n code: \"custom\",\n message: \"Must provide either maker or both obligation_id and side\",\n });\n }\n\n if (val.cursor !== undefined && !isValidBase64urlJson(val.cursor)) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"cursor\"],\n message: \"Invalid cursor format. Must be a valid base64url-encoded cursor object\",\n });\n }\n })\n .transform((val) => {\n if (val.maker && val.cursor) {\n return {\n ...val,\n cursor: val.cursor.toLowerCase(),\n };\n }\n return val;\n });\n\nexport const GetObligationsQueryParams = z.object({\n ...PaginationQueryParams.shape,\n cursor: z.string().optional().meta({\n description: \"Obligation id cursor\",\n example: \"0x1234567890123456789012345678901234567890123456789012345678901234\",\n }),\n chains: csvArray(\n z\n .string()\n .regex(/^[1-9]\\d*$/, { message: \"Chain must be a positive integer\" })\n .transform((val) => Number.parseInt(val, 10)),\n ).meta({\n description: \"Filter by chain IDs (comma-separated).\",\n example: \"1,8453\",\n }),\n loan_tokens: csvArray(\n z\n .string()\n .regex(/^0x[a-fA-F0-9]{40}$/, { error: \"Loan token must be a valid 20-byte address\" })\n .transform<Address>((val) => val.toLowerCase() as Address),\n ).meta({\n description: \"Filter by loan token addresses (comma-separated).\",\n example:\n \"0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078,0x34Cf890dB685FC536E05652FB41f02090c3fb751\",\n }),\n collateral_tokens: csvArray(\n z\n .string()\n .regex(/^0x[a-fA-F0-9]{40}$/, { error: \"Collateral token must be a valid 20-byte address\" })\n .transform<Address>((val) => val.toLowerCase() as Address),\n ).meta({\n description: \"Filter by collateral tokens (comma-separated, matches any collateral).\",\n example:\n \"0x34Cf890dB685FC536E05652FB41f02090c3fb751,0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078\",\n }),\n maturities: csvArray(\n z\n .string()\n .regex(/^[1-9]\\d*$/, { message: \"Maturity must be a positive integer\" })\n .transform((val) => Number.parseInt(val, 10)),\n ).meta({\n description: \"Filter by exact maturity timestamps (comma-separated, unix seconds).\",\n example: \"1761922800,1764524800\",\n }),\n});\n\nexport const GetObligationParams = z.object({\n obligation_id: z\n .string({ error: \"Obligation id is required and must be a valid 32-byte hex string\" })\n .regex(/^0x[a-fA-F0-9]{64}$/, { error: \"Obligation id must be a valid 32-byte hex string\" })\n .transform<Hex>((val) => val.toLowerCase() as Hex)\n .meta({\n description: \"Obligation id\",\n example: \"0x1234567890123456789012345678901234567890123456789012345678901234\",\n }),\n});\n\n/** Validate a book cursor format: {side, lastPrice, offersCursor} */\nfunction isValidBookCursor(cursorString: string): boolean {\n const isNumericString = (value: unknown): value is string =>\n typeof value === \"string\" && /^-?\\d+$/.test(value);\n\n try {\n const v = JSON.parse(Buffer.from(cursorString, \"base64url\").toString(\"utf8\"));\n return (\n (v?.side === \"buy\" || v?.side === \"sell\") &&\n isNumericString(v?.lastPrice) &&\n (v?.offersCursor === null || typeof v?.offersCursor === \"string\")\n );\n } catch {\n return false;\n }\n}\n\nconst BookPaginationQueryParams = z.object({\n cursor: z\n .string()\n .optional()\n .refine(\n (value) => {\n if (!value) return true; // Optional field\n return isValidBookCursor(value);\n },\n {\n message: \"Invalid cursor format. Must be a valid base64url-encoded book cursor object\",\n },\n )\n .meta({\n description: \"Pagination cursor in base64url-encoded format for book levels\",\n example:\n \"eyJzaWRlIjoiYnV5IiwibGFzdFJhdGUiOiIxMDAwMDAwMDAwMDAwMDAwMDAwIiwib2ZmZXJzQ3Vyc29yIjpudWxsfQ\",\n }),\n limit: z\n .string()\n .regex(/^[1-9]\\d*$/, {\n message: \"Limit must be a positive integer\",\n })\n .transform((val) => Number.parseInt(val, 10))\n .pipe(\n z.number().max(MAX_LIMIT, {\n message: `Limit cannot exceed ${MAX_LIMIT}`,\n }),\n )\n .optional()\n .default(DEFAULT_LIMIT)\n .meta({\n description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT}`,\n example: 10,\n }),\n});\n\nconst HealthQueryParams = z.object({\n strict: z\n .enum([\"true\", \"false\", \"1\", \"0\"])\n .transform((value) => value === \"true\" || value === \"1\")\n .optional()\n .meta({\n description: \"Enable strict mode to fail health checks when initialization is incomplete.\",\n example: \"true\",\n }),\n});\n\nexport const GetBookParams = z.object({\n ...BookPaginationQueryParams.shape,\n obligation_id: z\n .string({ error: \"Obligation id is required and must be a valid 32-byte hex string\" })\n .regex(/^0x[a-fA-F0-9]{64}$/, { error: \"Obligation id must be a valid 32-byte hex string\" })\n .transform<Hex>((val) => val.toLowerCase() as Hex)\n .meta({\n description: \"Obligation id\",\n example: \"0x1234567890123456789012345678901234567890123456789012345678901234\",\n }),\n side: z.enum([\"buy\", \"sell\"]).meta({\n description: \"Side of the book (buy or sell).\",\n example: \"buy\",\n }),\n});\n\nconst ValidateOffersBody = z\n .object({\n offers: z.array(z.unknown()).min(1, { message: \"'offers' must contain at least 1 offer\" }),\n })\n .strict();\n\nexport const GetUserPositionsParams = z.object({\n ...PaginationQueryParams.shape,\n user_address: z\n .string()\n .regex(/^0x[a-fA-F0-9]{40}$/, { error: \"User address must be a valid 20-byte address\" })\n .transform<Address>((val) => val.toLowerCase() as Address)\n .meta({\n description: \"User address to get positions for\",\n example: \"0x7b093658BE7f90B63D7c359e8f408e503c2D9401\",\n }),\n});\n\nconst schemas = {\n get_health: HealthQueryParams,\n get_health_collectors: HealthQueryParams,\n get_health_chains: HealthQueryParams,\n get_config_contracts: GetConfigContractsQueryParams,\n get_config_rules: GetConfigRulesQueryParams,\n get_offers: GetOffersQueryParams,\n get_obligations: GetObligationsQueryParams,\n get_obligation: GetObligationParams,\n get_book: GetBookParams,\n validate_offers: ValidateOffersBody,\n get_user_positions: GetUserPositionsParams,\n} as const;\n\ntype Action = keyof typeof schemas;\n\nexport function parse<A extends Action>(action: A, query: unknown): z.infer<(typeof schemas)[A]> {\n return schemas[action].parse(query) as z.infer<(typeof schemas)[A]>;\n}\n\nexport function safeParse<A extends Action>(\n action: A,\n query: unknown,\n error?: z.core.$ZodErrorMap<z.core.$ZodIssue>,\n): z.ZodSafeParseResult<z.infer<(typeof schemas)[A]>> {\n return schemas[action].safeParse(query, {\n error,\n }) as z.ZodSafeParseResult<z.infer<(typeof schemas)[A]>>;\n}\n","import type { Database } from \"#database/index.ts\";\nimport { Logger } from \"#logger/index.ts\";\nimport * as ApiSchema from \"../Schema/index.ts\";\nimport * as ApiPayload from \"./Payload.ts\";\n\nexport async function getBook(\n params: object,\n db: Database.Database,\n): Promise<ApiPayload.Payload<ApiSchema.BookResponse.BookLevelResponse[]>> {\n const logger = Logger.getLogger();\n const result = ApiSchema.safeParse(\"get_book\", params, (issue) => issue.message);\n\n if (!result.success) return ApiPayload.failure(result.error);\n const query = result.data;\n\n try {\n logger.debug({\n service: \"api_controller\",\n endpoint: \"get_book\",\n msg: \"Loading book levels\",\n obligation_id: query.obligation_id,\n side: query.side,\n limit: query.limit ?? null,\n has_cursor: query.cursor != null,\n });\n\n const { levels, nextCursor } = await db.book.get({\n side: query.side,\n obligationId: query.obligation_id,\n cursor: query.cursor,\n limit: query.limit,\n });\n\n const firstLevel = levels[0];\n logger.debug({\n service: \"api_controller\",\n endpoint: \"get_book\",\n msg: \"Loaded book levels\",\n obligation_id: query.obligation_id,\n side: query.side,\n levels_count: levels.length,\n has_next_cursor: nextCursor != null,\n first_level_price: firstLevel?.price.toString() ?? null,\n first_level_assets: firstLevel?.assets.toString() ?? null,\n first_level_count: firstLevel?.count ?? null,\n });\n\n return ApiPayload.success({\n data: levels.map(ApiSchema.BookResponse.from),\n cursor: nextCursor,\n });\n } catch (err) {\n logger.error({\n err,\n msg: \"Error get book\",\n errorMessage: err instanceof Error ? err.message : String(err),\n errorStack: err instanceof Error ? err.stack : undefined,\n });\n return ApiPayload.failure(err);\n }\n}\n","import type { Address } from \"viem\";\nimport type * as Chain from \"#core/Chain.ts\";\nimport type * as ChainRegistry from \"#core/ChainRegistry.ts\";\nimport * as ApiSchema from \"../Schema/index.ts\";\nimport * as ApiPayload from \"./Payload.ts\";\n\nexport const CONFIG_CONTRACT_NAMES = [\"mempool\", \"multicall\", \"v2\"] as const;\nexport type ConfigContractName = (typeof CONFIG_CONTRACT_NAMES)[number];\n\nexport type ConfigContract = {\n chain_id: Chain.Id;\n address: Address;\n name: ConfigContractName;\n};\n\ntype Cursor = {\n chain_id: Chain.Id;\n address: Address;\n};\n\n/**\n * Returns contract addresses used by indexers (mempool, v2) plus multicall per chain.\n * @param query - Raw query parameters containing optional chain filters.\n * @param chainRegistry - The chain registry instance. {@link ChainRegistry.ChainRegistry}\n * @returns The indexer contract configuration. {@link ApiPayload.Payload<ConfigContract[]>}\n */\nexport async function getConfigContracts(\n query: unknown,\n chainRegistry: ChainRegistry.ChainRegistry,\n): Promise<ApiPayload.Payload<ConfigContract[]>> {\n const parsed = ApiSchema.safeParse(\"get_config_contracts\", query ?? {});\n if (!parsed.success) {\n return ApiPayload.failure(parsed.error);\n }\n\n const { chains: chainsFilter, cursor, limit } = parsed.data;\n const chainFilter = chainsFilter?.length ? new Set(chainsFilter) : null;\n const contracts: ConfigContract[] = [];\n const seenAddresses = new Set<string>();\n\n for (const chain of chainRegistry.list()) {\n if (chainFilter && !chainFilter.has(chain.id)) continue;\n\n const mempool = chain.custom?.mempool?.address;\n if (!mempool) {\n return ApiPayload.failure(\n new ApiPayload.InternalServerError(`Missing mempool address for chain ${chain.id}.`),\n );\n }\n\n const multicall = chain.contracts?.multicall3?.address;\n if (!multicall) {\n return ApiPayload.failure(\n new ApiPayload.InternalServerError(`Missing multicall3 address for chain ${chain.id}.`),\n );\n }\n\n const v2 = chain.custom?.morpho?.address;\n if (!v2) {\n return ApiPayload.failure(\n new ApiPayload.InternalServerError(`Missing morpho address for chain ${chain.id}.`),\n );\n }\n\n const chainContracts: ConfigContract[] = [\n { chain_id: chain.id, name: \"mempool\", address: mempool },\n { chain_id: chain.id, name: \"multicall\", address: multicall },\n { chain_id: chain.id, name: \"v2\", address: v2 },\n ];\n\n for (const contract of chainContracts) {\n const cursorKey = `${contract.chain_id}:${contract.address.toLowerCase()}`;\n if (seenAddresses.has(cursorKey)) {\n return ApiPayload.failure(\n new ApiPayload.InternalServerError(\n `Duplicate contract address ${contract.address} for chain ${chain.id}.`,\n ),\n );\n }\n seenAddresses.add(cursorKey);\n contracts.push(contract);\n }\n }\n\n contracts.sort((a, b) => {\n if (a.chain_id !== b.chain_id) return a.chain_id - b.chain_id;\n const addressCompare = a.address.toLowerCase().localeCompare(b.address.toLowerCase());\n if (addressCompare !== 0) return addressCompare;\n return a.name.localeCompare(b.name);\n });\n\n let cursorContract: Cursor | null = null;\n if (cursor) {\n try {\n cursorContract = parseCursor(cursor);\n } catch (err) {\n return ApiPayload.failure(err);\n }\n }\n\n const startIndex = cursorContract ? findStartIndex(contracts, cursorContract) : 0;\n const page = contracts.slice(startIndex, startIndex + limit);\n const nextCursor =\n startIndex + limit < contracts.length && page.length > 0 ? formatCursor(page.at(-1)!) : null;\n\n return ApiPayload.success({ data: page, cursor: nextCursor });\n}\n\nfunction parseCursor(cursor: string): Cursor {\n const [chain, address] = cursor.split(\":\", 2);\n if (!chain || !address) {\n throw new ApiPayload.BadRequestError(\"Cursor must be in the format chain_id:0x...\");\n }\n const chain_id = Number.parseInt(chain, 10) as Chain.Id;\n return {\n chain_id,\n address: address.toLowerCase() as Address,\n };\n}\n\nfunction formatCursor(contract: ConfigContract): string {\n return `${contract.chain_id}:${contract.address.toLowerCase()}`;\n}\n\nfunction findStartIndex(contracts: ConfigContract[], cursor: Cursor): number {\n let low = 0;\n let high = contracts.length;\n while (low < high) {\n const mid = Math.floor((low + high) / 2);\n const current = contracts[mid]!;\n const cmp = compareContract(current, cursor);\n if (cmp <= 0) {\n low = mid + 1;\n } else {\n high = mid;\n }\n }\n return low;\n}\n\nfunction compareContract(contract: ConfigContract, cursor: Cursor): number {\n if (contract.chain_id !== cursor.chain_id) return contract.chain_id - cursor.chain_id;\n return contract.address.toLowerCase().localeCompare(cursor.address.toLowerCase());\n}\n","import type { Address } from \"viem\";\nimport * as Callback from \"../core/Callback.ts\";\nimport * as Chain from \"../core/Chain.ts\";\nimport * as Maturity from \"../core/Maturity.ts\";\n\nexport type GateConfig = {\n callbacks?: CallbackConfig[];\n maturities?: Maturity.MaturityType[];\n};\n\nexport type CallbackConfig =\n | {\n type: Callback.Type.BuyWithEmptyCallback;\n }\n | {\n type: Callback.Type.SellWithEmptyCallback;\n };\n\n/**\n * Returns the callback configuration for a given chain and callback type, if it exists.\n *\n * @param chain - Chain name for which to read the validation configuration\n * @param type - Callback type to retrieve\n * @returns The matching callback configuration or undefined if not configured\n */\nexport function getCallback(chain: Chain.Name, type: Callback.Type): CallbackConfig | undefined {\n return configs[chain].callbacks?.find((c) => c.type === type);\n}\n\n/**\n * Returns the list of allowed non-empty callback addresses for a chain.\n *\n * @param chain - Chain name\n * @returns Empty array (no non-empty callbacks supported)\n */\nexport const getCallbackAddresses = (_chain: Chain.Name): Address[] => {\n return [];\n};\n\nexport const assets: Record<string, Address[]> = {\n [Chain.ChainId.ETHEREUM.toString()]: [\n \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\", // USDC\n \"0x6B175474E89094C44Da98b954EedeAC495271d0F\", // DAI\n \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\", // WETH\n \"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599\", // WBTC\n \"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c\", // EURC\n \"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0\", // wstETH\n ],\n [Chain.ChainId.BASE.toString()]: [\n \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\", // USDC\n \"0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb\", // DAI\n \"0x4200000000000000000000000000000000000006\", // WETH\n \"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599\", // WBTC\n \"0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf\", // cbBTC\n \"0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452\", // wstETH\n \"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42\", // EURC\n ],\n [Chain.ChainId[\"ETHEREUM-VIRTUAL-TESTNET\"].toString()]: [\n \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\", // USDC\n \"0x6B175474E89094C44Da98b954EedeAC495271d0F\", // DAI\n \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\", // WETH\n \"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599\", // WBTC\n \"0xce79ddb3152d52ff8fe65a4c7e058b035fcb560a\", // test token\n ],\n [Chain.ChainId.ANVIL.toString()]: [\n \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\", // USDC\n \"0x6B175474E89094C44Da98b954EedeAC495271d0F\", // DAI\n \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\", // WETH\n \"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599\", // WBTC\n ],\n};\n\nexport const oracles: Record<string, Address[]> = {\n [Chain.ChainId.ETHEREUM.toString()]: [\n \"0xDddd770BADd886dF3864029e4B377B5F6a2B6b83\",\n \"0x9CB3f4276bcD149b3668e1a645a964bC12877b89\",\n \"0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2\",\n \"0x6Eb9F4128CeBc8B885A4d8562Db1Addf097f7348\",\n \"0xbD60A6770b27E084E8617335ddE769241B0e71D8\",\n \"0xAe12416c1F21B0698c27fe042D9309C83baC6597\",\n ],\n [Chain.ChainId.BASE.toString()]: [\n \"0xD09048c8B568Dbf5f189302beA26c9edABFC4858\",\n \"0xFEa2D58cEfCb9fcb597723c6bAE66fFE4193aFE4\",\n \"0x05D2618404668D725B66c0f32B39e4EC15B393dC\",\n \"0xE1bb8E5b4930eC9FeC7f7943FCF6227649F14B37\",\n \"0x663BECd10daE6C4A3Dcd89F1d76c1174199639B9\",\n \"0x10b95702a0ce895972C91e432C4f7E19811D320E\",\n \"0x8C87DbD7A0c647A4291592Bc2994dbF95880fE2F\",\n \"0x4A11590e5326138B514E08A9B52202D42077Ca65\",\n \"0xa54122f0E0766258377Ffe732e454A3248f454F4\",\n ],\n [Chain.ChainId[\"ETHEREUM-VIRTUAL-TESTNET\"].toString()]: [\n \"0xDddd770BADd886dF3864029e4B377B5F6a2B6b83\",\n \"0x9CB3f4276bcD149b3668e1a645a964bC12877b89\",\n \"0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2\",\n \"0x6Eb9F4128CeBc8B885A4d8562Db1Addf097f7348\",\n \"0xbD60A6770b27E084E8617335ddE769241B0e71D8\",\n \"0xAe12416c1F21B0698c27fe042D9309C83baC6597\",\n ],\n [Chain.ChainId.ANVIL.toString()]: [\n \"0xDddd770BADd886dF3864029e4B377B5F6a2B6b83\",\n \"0x9CB3f4276bcD149b3668e1a645a964bC12877b89\",\n \"0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2\",\n \"0x6Eb9F4128CeBc8B885A4d8562Db1Addf097f7348\",\n \"0xbD60A6770b27E084E8617335ddE769241B0e71D8\",\n \"0xAe12416c1F21B0698c27fe042D9309C83baC6597\",\n ],\n};\n\nexport const configs: Record<Chain.Name, GateConfig> = {\n ethereum: {\n callbacks: [\n { type: Callback.Type.BuyWithEmptyCallback },\n { type: Callback.Type.SellWithEmptyCallback },\n ],\n maturities: [Maturity.MaturityType.EndOfMonth, Maturity.MaturityType.EndOfNextMonth],\n },\n base: {\n callbacks: [\n { type: Callback.Type.BuyWithEmptyCallback },\n { type: Callback.Type.SellWithEmptyCallback },\n ],\n maturities: [Maturity.MaturityType.EndOfMonth, Maturity.MaturityType.EndOfNextMonth],\n },\n \"ethereum-virtual-testnet\": {\n callbacks: [\n { type: Callback.Type.BuyWithEmptyCallback },\n { type: Callback.Type.SellWithEmptyCallback },\n ],\n maturities: [Maturity.MaturityType.EndOfMonth, Maturity.MaturityType.EndOfNextMonth],\n },\n anvil: {\n callbacks: [\n { type: Callback.Type.BuyWithEmptyCallback },\n { type: Callback.Type.SellWithEmptyCallback },\n ],\n maturities: [Maturity.MaturityType.EndOfMonth, Maturity.MaturityType.EndOfNextMonth],\n },\n};\n","import { createHash } from \"node:crypto\";\nimport type { Address } from \"viem\";\nimport type * as Chain from \"#core/Chain.ts\";\nimport * as Maturity from \"#core/Maturity.ts\";\nimport * as GateConfig from \"./GateConfig.ts\";\nimport type { ConfigRule } from \"./types.ts\";\n\n/**\n * Build the configured rules (maturities + callback addresses + loan tokens + oracles) for the provided chains.\n * @param chains - Chains to include in the configured rules.\n * @returns Sorted list of config rules.\n */\nexport function buildConfigRules(chains: Chain.Chain[]): ConfigRule[] {\n const rules: ConfigRule[] = [];\n\n for (const chain of chains) {\n const config = GateConfig.configs[chain.name];\n\n const maturities = config.maturities ?? [];\n for (const maturityName of maturities) {\n rules.push({\n type: \"maturity\",\n chain_id: chain.id,\n name: maturityName,\n timestamp: Maturity.from(maturityName),\n });\n }\n\n const loanTokens = GateConfig.assets[chain.id.toString()] ?? [];\n for (const address of loanTokens) {\n rules.push({\n type: \"loan_token\",\n chain_id: chain.id,\n address: normalizeAddress(address),\n });\n }\n\n const oracles = GateConfig.oracles[chain.id.toString()] ?? [];\n for (const address of oracles) {\n rules.push({\n type: \"oracle\",\n chain_id: chain.id,\n address: normalizeAddress(address),\n });\n }\n }\n\n rules.sort(compareConfigRules);\n return rules;\n}\n\n/**\n * Compute a stable checksum for the provided configured rules.\n * @param rules - Configured rules to checksum.\n * @returns MD5 checksum.\n */\nexport function buildConfigRulesChecksum(rules: ConfigRule[]): string {\n const hash = createHash(\"md5\");\n const orderedRules = [...rules].sort(compareConfigRules);\n\n for (const rule of orderedRules) {\n if (rule.type === \"maturity\") {\n hash.update(`maturity:${rule.chain_id}:${rule.name}:${rule.timestamp}\\n`);\n continue;\n }\n if (rule.type === \"callback\") {\n hash.update(`callback:${rule.chain_id}:${rule.callback_type}:${rule.address}\\n`);\n continue;\n }\n if (rule.type === \"oracle\") {\n hash.update(`oracle:${rule.chain_id}:${rule.address}\\n`);\n continue;\n }\n hash.update(`loan_token:${rule.chain_id}:${rule.address}\\n`);\n }\n\n return hash.digest(\"hex\");\n}\n\nfunction normalizeAddress(address: Address): Address {\n return address.toLowerCase() as Address;\n}\n\nexport function compareConfigRules(left: ConfigRule, right: ConfigRule): number {\n if (left.chain_id !== right.chain_id) return left.chain_id - right.chain_id;\n\n if (left.type !== right.type) return left.type.localeCompare(right.type);\n\n if (left.type === \"maturity\" && right.type === \"maturity\") {\n return left.timestamp - right.timestamp;\n }\n\n if (left.type === \"callback\" && right.type === \"callback\") {\n if (left.callback_type !== right.callback_type) {\n const leftType: string = left.callback_type;\n return leftType.localeCompare(right.callback_type);\n }\n return left.address.localeCompare(right.address);\n }\n\n if (left.type === \"loan_token\" && right.type === \"loan_token\") {\n return left.address.localeCompare(right.address);\n }\n\n if (left.type === \"oracle\" && right.type === \"oracle\") {\n return left.address.localeCompare(right.address);\n }\n\n return 0;\n}\n","import type { Address } from \"viem\";\nimport * as Callback from \"#core/Callback.ts\";\nimport type * as Chain from \"#core/Chain.ts\";\nimport * as Maturity from \"#core/Maturity.ts\";\nimport {\n buildConfigRules,\n buildConfigRulesChecksum,\n compareConfigRules,\n} from \"#gatekeeper/ConfigRules.ts\";\nimport type { ConfigRule } from \"#gatekeeper/types.ts\";\nimport * as ApiSchema from \"../Schema/index.ts\";\nimport * as ApiPayload from \"./Payload.ts\";\n\ntype Cursor = ConfigRule;\n\ntype ConfigRuleType = ConfigRule[\"type\"];\ntype CallbackRule = Extract<ConfigRule, { type: \"callback\" }>;\n\n/**\n * Returns configured rules for the configured chains.\n * @param query - Raw query parameters containing filters/cursor/limit.\n * @param chains - Chains to include in the configured rules.\n * @returns Config rules response payload. {@link ApiPayload.Payload}\n */\nexport async function getConfigRules(\n query: unknown,\n chains: Chain.Chain[],\n): Promise<ApiPayload.Payload<ConfigRule[]>> {\n const parsed = ApiSchema.safeParse(\"get_config_rules\", query ?? {});\n if (!parsed.success) {\n return ApiPayload.failure(parsed.error);\n }\n\n const { cursor, limit, types, chains: chainIds } = parsed.data;\n const typeFilter = types?.length ? new Set(types) : null;\n const chainFilter = chainIds?.length ? new Set(chainIds) : null;\n\n const rules = buildConfigRules(chains);\n const filteredRules = rules.filter((rule) => {\n if (chainFilter && !chainFilter.has(rule.chain_id)) return false;\n if (typeFilter && !typeFilter.has(rule.type)) return false;\n return true;\n });\n const checksum = buildConfigRulesChecksum(filteredRules);\n\n let cursorRule: Cursor | null = null;\n if (cursor) {\n try {\n cursorRule = parseCursor(cursor);\n } catch (err) {\n return ApiPayload.failure(err);\n }\n }\n if (cursorRule && typeFilter && !typeFilter.has(cursorRule.type)) {\n return ApiPayload.failure(\n new ApiPayload.BadRequestError(\"Cursor type must match requested rule types\"),\n );\n }\n if (cursorRule && chainFilter && !chainFilter.has(cursorRule.chain_id)) {\n return ApiPayload.failure(\n new ApiPayload.BadRequestError(\"Cursor chain_id must match requested chains\"),\n );\n }\n\n const startIndex = cursorRule ? findStartIndex(filteredRules, cursorRule) : 0;\n const page = filteredRules.slice(startIndex, startIndex + limit);\n const nextCursor =\n startIndex + limit < filteredRules.length && page.length > 0\n ? formatCursor(page.at(-1)!)\n : null;\n\n const response = ApiPayload.success({ data: page, cursor: nextCursor });\n response.body.meta.checksum = checksum;\n return response;\n}\n\nfunction formatCursor(rule: ConfigRule): string {\n if (rule.type === \"maturity\") {\n return `maturity:${rule.chain_id}:${rule.timestamp}:${rule.name}`;\n }\n if (rule.type === \"callback\") {\n return `callback:${rule.chain_id}:${rule.callback_type}:${rule.address.toLowerCase()}`;\n }\n if (rule.type === \"oracle\") {\n return `oracle:${rule.chain_id}:${rule.address.toLowerCase()}`;\n }\n return `loan_token:${rule.chain_id}:${rule.address.toLowerCase()}`;\n}\n\nfunction parseCursor(cursor: string): Cursor {\n const [type, chain, ...rest] = cursor.split(\":\");\n if (!type || !chain || rest.length === 0) {\n throw new ApiPayload.BadRequestError(\"Cursor must be in the format type:chain_id:<value>\");\n }\n if (!isConfigRuleType(type)) {\n throw new ApiPayload.BadRequestError(\"Cursor has an invalid rule type\");\n }\n const chain_id = Number.parseInt(chain, 10) as Chain.Id;\n if (!Number.isFinite(chain_id)) {\n throw new ApiPayload.BadRequestError(\"Cursor has an invalid chain_id\");\n }\n\n if (type === \"maturity\") {\n const timestampValue = Number.parseInt(rest[0] ?? \"\", 10);\n const nameValue = rest.slice(1).join(\":\");\n if (!Number.isFinite(timestampValue) || nameValue.length === 0) {\n throw new ApiPayload.BadRequestError(\n \"Cursor must be in the format maturity:chain_id:timestamp:name\",\n );\n }\n if (!isMaturityType(nameValue)) {\n throw new ApiPayload.BadRequestError(\"Cursor has an invalid maturity name\");\n }\n const timestamp = parseMaturity(timestampValue);\n return { type, chain_id, timestamp, name: nameValue };\n }\n\n if (type === \"callback\") {\n const callbackTypeValue = rest[0] ?? \"\";\n const addressValue = rest.slice(1).join(\":\");\n if (!callbackTypeValue || !addressValue) {\n throw new ApiPayload.BadRequestError(\n \"Cursor must be in the format callback:chain_id:callback_type:address\",\n );\n }\n if (!isCallbackType(callbackTypeValue)) {\n throw new ApiPayload.BadRequestError(\"Cursor has an invalid callback type\");\n }\n return {\n type,\n chain_id,\n callback_type: callbackTypeValue,\n address: parseAddress(addressValue, \"Cursor address\"),\n };\n }\n\n if (type === \"loan_token\" || type === \"oracle\") {\n const addressValue = rest.join(\":\");\n if (!addressValue) {\n throw new ApiPayload.BadRequestError(`Cursor must be in the format ${type}:chain_id:address`);\n }\n return {\n type,\n chain_id,\n address: parseAddress(addressValue, \"Cursor address\"),\n };\n }\n\n throw new ApiPayload.BadRequestError(\"Cursor has an invalid rule type\");\n}\n\nfunction findStartIndex(rules: ConfigRule[], cursor: Cursor): number {\n let low = 0;\n let high = rules.length;\n while (low < high) {\n const mid = Math.floor((low + high) / 2);\n const current = rules[mid]!;\n const cmp = compareConfigRules(current, cursor);\n if (cmp <= 0) {\n low = mid + 1;\n } else {\n high = mid;\n }\n }\n return low;\n}\n\nfunction parseAddress(address: string, label: string): Address {\n if (!/^0x[a-fA-F0-9]{40}$/.test(address)) {\n throw new ApiPayload.BadRequestError(`${label} must be a valid 20-byte address`);\n }\n return address.toLowerCase() as Address;\n}\n\nfunction isConfigRuleType(value: string): value is ConfigRuleType {\n return (\n value === \"maturity\" || value === \"callback\" || value === \"loan_token\" || value === \"oracle\"\n );\n}\n\nfunction isMaturityType(value: string): value is Maturity.MaturityType {\n return (Object.values(Maturity.MaturityType) as string[]).includes(value);\n}\n\nfunction parseMaturity(value: number): Maturity.Maturity {\n try {\n return Maturity.from(value);\n } catch (err) {\n throw new ApiPayload.BadRequestError(\n err instanceof Error ? err.message : \"Invalid maturity timestamp\",\n );\n }\n}\n\nfunction isCallbackType(value: string): value is CallbackRule[\"callback_type\"] {\n if (value === Callback.Type.BuyWithEmptyCallback) return false;\n return (Object.values(Callback.Type) as string[]).includes(value);\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { marked } from \"marked\";\nimport type { OpenAPIDocument } from \"openapi-metadata\";\nimport { OpenApi } from \"../Schema/openapi.ts\";\n\n// ESM: use import.meta.url; Lambda/CJS bundled code: fallback to process.cwd()\nconst __dirname = (() => {\n try {\n // import.meta.url is only available in ESM\n return dirname(fileURLToPath(import.meta.url));\n } catch {\n return process.cwd();\n }\n})();\n\n/**\n * Build the OpenAPI document for the router.\n * @returns OpenAPI document. {@link OpenAPIDocument}\n */\nexport async function getSwaggerJson(): Promise<OpenAPIDocument> {\n return OpenApi();\n}\n\n/**\n * Render the API documentation HTML page.\n * @returns HTML page as string.\n */\nexport async function getDocsHtml(): Promise<string> {\n const spec = await OpenApi();\n const html = `<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"UTF-8\">\n <title>Router API Docs (Scalar)</title>\n <script src=\"https://cdn.jsdelivr.net/npm/@scalar/api-reference\"></script>\n <style>\n html, body { margin: 0; height: 100%; }\n api-reference { height: 100%; width: 100%; }\n </style>\n </head>\n <body>\n <div id=\"api-container\" style=\"height:100%;width:100%;\"></div>\n <script>\n window.addEventListener('load', function () {\n const spec = ${JSON.stringify(spec)};\n Scalar.createApiReference('#api-container', { spec: { content: spec, hideModels: true } });\n });\n </script>\n </body>\n</html>`;\n\n return html;\n}\n\n/**\n * Finds the integrator.md file.\n * Handles source, bundled CLI, and Lambda scenarios.\n */\nfunction findIntegratorMd(): string {\n const candidates = [\n resolve(__dirname, \"../../../docs/integrator.md\"), // from source: src/api/Controllers/\n resolve(__dirname, \"../docs/integrator.md\"), // from dist/\n resolve(process.cwd(), \"docs/integrator.md\"), // Lambda: cwd is /var/task\n ];\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n throw new Error(`integrator.md not found. Tried: ${candidates.join(\", \")}`);\n}\n\n/**\n * Renders the integrator documentation as HTML.\n * @returns HTML page with the rendered markdown documentation.\n */\nexport async function getIntegratorDocsHtml(): Promise<string> {\n const mdPath = findIntegratorMd();\n const markdown = await readFile(mdPath, \"utf-8\");\n const content = await marked(markdown);\n\n return `<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"UTF-8\">\n <title>Documentation</title>\n <style>\n body { font-family: system-ui, sans-serif; max-width: 800px; margin: 0 auto; padding: 2rem; line-height: 1.6; }\n pre { background: #f4f4f4; padding: 1rem; overflow-x: auto; }\n code { background: #f4f4f4; padding: 0.2rem 0.4rem; }\n a { color: #0066cc; }\n </style>\n </head>\n <body>\n <nav><a href=\"/docs/api\">API Reference →</a></nav>\n ${content}\n </body>\n</html>`;\n}\n","import type { Client } from \"viem\";\nimport type { Chain } from \"#core\";\nimport type * as ChainRegistry from \"#core/ChainRegistry.ts\";\nimport type * as Database from \"#database/Database.ts\";\nimport * as Logger from \"#logger/Logger.ts\";\nimport * as Format from \"#utils/Format.ts\";\nimport * as Health from \"../Health.ts\";\nimport type * as OpenApiSchema from \"../Schema/generated/swagger.d.ts\";\nimport * as Schema from \"../Schema/requests.ts\";\nimport * as ApiPayload from \"./Payload.ts\";\n\nexport async function getHealth(\n query: unknown,\n db: Database.Database,\n chainRegistry?: ChainRegistry.ChainRegistry,\n): Promise<\n ApiPayload.Payload<\n OpenApiSchema.paths[\"/v1/health\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"][\"data\"]\n >\n> {\n const logger = Logger.getLogger();\n try {\n const parsed = Schema.safeParse(\"get_health\", query);\n if (!parsed.success) return ApiPayload.failure(parsed.error);\n\n const healthService = Health.create({ db, chainRegistry });\n const snapshot = await healthService.getSnapshot();\n\n if (parsed.data.strict && !snapshot.initialized) {\n return ApiPayload.failure(\n new ApiPayload.APIError(\n ApiPayload.STATUS_CODE.INTERNAL_SERVER_ERROR,\n \"Indexer block state is not initialized\",\n \"INTERNAL_SERVER_ERROR\",\n Format.toSnakeCase({\n missingChains: snapshot.missingChains,\n missingCollectors: snapshot.missingCollectors,\n }),\n ),\n );\n }\n\n return ApiPayload.success({\n data: Format.toSnakeCase({\n status: snapshot.status,\n initialized: snapshot.initialized,\n missingChains: snapshot.missingChains,\n missingCollectors: snapshot.missingCollectors,\n }),\n });\n } catch (err) {\n logger.error({\n err,\n msg: \"Error getting health status\",\n errorMessage: err instanceof Error ? err.message : String(err),\n errorStack: err instanceof Error ? err.stack : undefined,\n });\n return ApiPayload.failure(err);\n }\n}\n\nexport async function getHealthChains(\n query: unknown,\n db: Database.Database,\n healthClients?: Map<Chain.Id, Client>,\n chainRegistry?: ChainRegistry.ChainRegistry,\n): Promise<\n ApiPayload.Payload<\n OpenApiSchema.paths[\"/v1/health/chains\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"][\"data\"]\n >\n> {\n const logger = Logger.getLogger();\n try {\n const parsed = Schema.safeParse(\"get_health_chains\", query);\n if (!parsed.success) return ApiPayload.failure(parsed.error);\n\n const healthService = Health.create({ db, healthClients, chainRegistry });\n const snapshot = await healthService.getSnapshot();\n\n if (parsed.data.strict && !snapshot.initialized) {\n return ApiPayload.failure(\n new ApiPayload.APIError(\n ApiPayload.STATUS_CODE.INTERNAL_SERVER_ERROR,\n \"Indexer block state is not initialized\",\n \"INTERNAL_SERVER_ERROR\",\n Format.toSnakeCase({\n missingChains: snapshot.missingChains,\n missingCollectors: snapshot.missingCollectors,\n }),\n ),\n );\n }\n\n const chains = snapshot.chains;\n return ApiPayload.success({\n data: chains.map(({ chainId, localBlockNumber, remoteBlockNumber, updatedAt, initialized }) =>\n Format.toSnakeCase({\n chainId,\n localBlockNumber,\n remoteBlockNumber,\n updatedAt,\n initialized,\n }),\n ),\n });\n } catch (err) {\n logger.error({\n err,\n msg: \"Error getting health status for chains\",\n errorMessage: err instanceof Error ? err.message : String(err),\n errorStack: err instanceof Error ? err.stack : undefined,\n });\n return ApiPayload.failure(err);\n }\n}\n\nexport async function getHealthCollectors(\n query: unknown,\n db: Database.Database,\n chainRegistry?: ChainRegistry.ChainRegistry,\n): Promise<\n ApiPayload.Payload<\n OpenApiSchema.paths[\"/v1/health/collectors\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"][\"data\"]\n >\n> {\n const logger = Logger.getLogger();\n try {\n const parsed = Schema.safeParse(\"get_health_collectors\", query);\n if (!parsed.success) return ApiPayload.failure(parsed.error);\n\n const healthService = Health.create({ db, chainRegistry });\n const snapshot = await healthService.getSnapshot();\n\n if (parsed.data.strict && !snapshot.initialized) {\n return ApiPayload.failure(\n new ApiPayload.APIError(\n ApiPayload.STATUS_CODE.INTERNAL_SERVER_ERROR,\n \"Indexer block state is not initialized\",\n \"INTERNAL_SERVER_ERROR\",\n Format.toSnakeCase({\n missingChains: snapshot.missingChains,\n missingCollectors: snapshot.missingCollectors,\n }),\n ),\n );\n }\n\n const collectors = snapshot.collectors;\n return ApiPayload.success({\n data: collectors.map(({ name, chainId, blockNumber, updatedAt, lag, status, initialized }) =>\n Format.toSnakeCase({\n name,\n chainId,\n blockNumber,\n updatedAt,\n lag,\n status,\n initialized,\n }),\n ),\n });\n } catch (err) {\n logger.error({\n err,\n msg: \"Error getting health status for collectors\",\n errorMessage: err instanceof Error ? err.message : String(err),\n errorStack: err instanceof Error ? err.stack : undefined,\n });\n return ApiPayload.failure(err);\n }\n}\n","import { Obligation } from \"#core\";\nimport type { Database } from \"#database/index.ts\";\nimport { Logger } from \"#logger/index.ts\";\nimport * as ApiSchema from \"../Schema/index.ts\";\nimport * as ApiPayload from \"./Payload.ts\";\n\nexport async function getObligation(\n params: object,\n db: Database.Database,\n): Promise<ApiPayload.Payload<ApiSchema.ObligationResponse.ObligationResponse>> {\n const logger = Logger.getLogger();\n const result = ApiSchema.safeParse(\"get_obligation\", params, (issue) => issue.message);\n\n if (!result.success) return ApiPayload.failure(result.error);\n const query = result.data;\n\n try {\n const { obligations } = await db.offers.getObligations({ ids: [query.obligation_id] });\n if (obligations.length === 0) {\n return ApiPayload.failure(new ApiPayload.NotFoundError(\"Obligation not found\"));\n }\n\n const obligation = obligations[0]!;\n const [quote] = await db.offers.getQuotes({ obligationIds: [Obligation.id(obligation)] });\n\n return ApiPayload.success({\n data: ApiSchema.ObligationResponse.from(\n obligation,\n quote ?? {\n obligationId: Obligation.id(obligation),\n ask: { price: 0n },\n bid: { price: 0n },\n },\n ),\n cursor: null,\n });\n } catch (err) {\n logger.error({\n err,\n msg: \"Error get obligation\",\n errorMessage: err instanceof Error ? err.message : String(err),\n errorStack: err instanceof Error ? err.stack : undefined,\n });\n return ApiPayload.failure(err);\n }\n}\n","import { type Chain, Obligation } from \"#core\";\nimport type { Database } from \"#database/index.ts\";\nimport { Logger } from \"#logger/index.ts\";\nimport * as ApiSchema from \"../Schema/index.ts\";\nimport * as ApiPayload from \"./Payload.ts\";\n\nexport async function getObligations(\n queryParameters: object,\n db: Database.Database,\n): Promise<ApiPayload.Payload<ApiSchema.ObligationResponse.ObligationResponse[]>> {\n const logger = Logger.getLogger();\n const result = ApiSchema.safeParse(\"get_obligations\", queryParameters, (issue) => issue.message);\n\n if (!result.success) return ApiPayload.failure(result.error);\n const query = result.data;\n\n try {\n const chainIds = query.chains?.length ? (query.chains as Chain.Id[]) : undefined;\n const loanTokens = query.loan_tokens?.length ? query.loan_tokens : undefined;\n const collateralTokens = query.collateral_tokens?.length ? query.collateral_tokens : undefined;\n const maturities = query.maturities?.length ? query.maturities : undefined;\n\n const { obligations, nextCursor } = await db.offers.getObligations({\n cursor: query.cursor,\n limit: query.limit,\n chainId: chainIds,\n loanToken: loanTokens,\n collateralToken: collateralTokens,\n maturity: maturities,\n });\n\n const quotes = await db.offers.getQuotes({\n obligationIds: obligations.map((o) => Obligation.id(o)),\n });\n\n return ApiPayload.success({\n data: obligations.map((o) =>\n ApiSchema.ObligationResponse.from(\n o,\n quotes.find((q) => q.obligationId === Obligation.id(o)) ?? {\n obligationId: Obligation.id(o),\n ask: { price: 0n },\n bid: { price: 0n },\n },\n ),\n ),\n cursor: nextCursor ?? null,\n });\n } catch (err) {\n logger.error({\n err,\n msg: \"Error get obligations\",\n errorMessage: err instanceof Error ? err.message : String(err),\n errorStack: err instanceof Error ? err.stack : undefined,\n });\n\n return ApiPayload.failure(err);\n }\n}\n","/**\n * Default batch size for bulk database inserts.\n *\n * PostgreSQL limits a single query to at most 65,535 parameters\n * (e.g. $1, $2, ...). In bulk inserts, each row consumes one\n * parameter per column, so inserting too many rows at once can\n * exceed this limit.\n *\n * Our largest batched insert is into the `offers` table with 15 columns.\n * 15 cols × 4,000 rows = 60,000 parameters, safely under 65,535.\n */\nexport const DEFAULT_BATCH_SIZE = 4000;\n","import { and, asc, eq, gt, gte, inArray, lte, sql } from \"drizzle-orm\";\nimport type { Address, Hex } from \"viem\";\nimport { Collateral, LLTV, Maturity, Obligation, Offer, Quote } from \"#core\";\nimport type * as Chain from \"#core/Chain.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\nimport { Time } from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\nimport {\n groups as groupsTable,\n obligationCollateralsV2 as obligationCollateralsTable,\n obligations as obligationsTable,\n offers as offersTable,\n oracles as oraclesTable,\n status as statusTable,\n validations as validationsTable,\n} from \"../drizzle/schema.ts\";\n\nexport type CreateBatch = Readonly<{\n blockNumber: number;\n offers: Offer.Offer[];\n}>;\n\n/**\n * Raw row returned by database queries.\n * Built from primitives; no domain constructors in the DB layer.\n */\nexport type Row = {\n hash: Hex;\n maker: Address;\n assets: bigint;\n obligationUnits: bigint;\n obligationShares: bigint;\n price: bigint;\n maturity: Maturity.Maturity;\n expiry: number;\n start: number;\n group: Hex;\n session: Hex;\n buy: boolean;\n chainId: Chain.Id;\n loanToken: Address;\n collaterals: Collateral.Collateral[];\n callback: {\n address: Address;\n data: Hex;\n };\n consumed: bigint;\n available: bigint;\n takeable: bigint;\n blockNumber: number;\n};\n\nexport type OffersDomain = {\n /** Insert offers (insert-only). */\n create: (batches: CreateBatch[]) => Promise<Hex[]>;\n\n /** Delete multiple offers by hashes or block number greater than or equal to the given value on a given chain.\n * @returns the number of offers deleted.\n */\n delete: (\n parameters: { hashes: Hex[] } | { blockNumberGte: number; chainId: Chain.Id },\n ) => Promise<number>;\n\n /** Get offers with collaterals only (no availability/takeable computation). */\n get: (parameters?: GetOffersParams) => Promise<{ rows: Row[]; nextCursor: string | null }>;\n\n /** Get obligations */\n getObligations: (parameters?: {\n ids?: Hex[];\n chainId?: Chain.Id[];\n loanToken?: Address[];\n collateralToken?: Address[];\n maturity?: number[];\n cursor?: string;\n limit?: number;\n }) => Promise<{\n obligations: Obligation.Obligation[];\n nextCursor: string | null;\n }>;\n\n /** Get quotes for given obligations. */\n getQuotes: (parameters: { obligationIds: Hex[] }) => Promise<Quote.Quote[]>;\n};\n\nexport const DEFAULT_LIMIT = 100;\nexport type PaginationParams = {\n /** Cursor string returned by a previous call, for pagination */\n cursor?: string;\n /** Page size; defaults to {@link DEFAULT_LIMIT} */\n limit?: number;\n};\n\nexport type GetOffersParams = {\n /** Filter by maker address */\n maker?: Address;\n} & PaginationParams;\n\nexport function create(config: { db: Database.Core }): OffersDomain {\n const { db } = config;\n\n return {\n create: async (batches: CreateBatch[]): Promise<Hex[]> => {\n if (batches.length === 0) return [];\n const offersRows = batches.flatMap(({ blockNumber, offers }) =>\n offers.map((offer) => ({\n ...Offer.serialize(offer),\n obligationId: Offer.obligationId(offer),\n groupChainId: offer.chainId,\n groupMaker: offer.maker.toLowerCase(),\n callbackAddress: offer.callback.address.toLowerCase(),\n callbackData: offer.callback.data,\n blockNumber,\n })),\n );\n if (offersRows.length === 0) return [];\n\n try {\n return await db.transaction(async (dbTx) => {\n // allow to check that the offer was not deleted immediately after insertion (for example by a consumed event)\n const selectExisting = async (hashes: string[]) => {\n if (hashes.length === 0) return new Set<string>();\n const existing = new Set<string>();\n for (const batch of Utils.batch(hashes, DEFAULT_BATCH_SIZE)) {\n const rows = await dbTx\n .select({ hash: offersTable.hash })\n .from(offersTable)\n .where(inArray(offersTable.hash, batch));\n for (const row of rows) existing.add(String(row.hash).toLowerCase());\n }\n return existing;\n };\n\n const inserted: Hex[] = [];\n for (const batch of Utils.batch(offersRows, DEFAULT_BATCH_SIZE)) {\n const rows = await dbTx\n .insert(offersTable)\n .values(batch)\n .onConflictDoNothing()\n .returning();\n inserted.push(...rows.map((row) => row.hash as Hex));\n }\n\n const existing = await selectExisting(inserted);\n return inserted.filter((hash) => existing.has(hash));\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n throw new Error(\n \"Offers.create failed. Ensure obligations and groups exist before inserting offers.\",\n { cause: error },\n );\n }\n },\n\n get: async (\n parameters?: GetOffersParams,\n ): Promise<{ rows: Row[]; nextCursor: string | null }> => {\n const limit = parameters?.limit ?? DEFAULT_LIMIT;\n const cursor = parameters?.cursor;\n const maker = parameters?.maker;\n\n if (cursor !== null && cursor !== undefined) {\n if (!cursor.startsWith(\"0x\") || cursor.length !== 66) {\n throw new Error(\"Invalid cursor format\");\n }\n }\n\n const collateralsLateral = db\n .select({\n collaterals: sql<Array<{ asset: string; oracle: string; lltv: string }>>`COALESCE(\n jsonb_agg(\n jsonb_build_object(\n 'asset', ${obligationCollateralsTable.asset},\n 'oracle', ${oraclesTable.address},\n 'lltv', ${obligationCollateralsTable.lltv}\n )\n ),\n '[]'::jsonb\n )`.as(\"collaterals\"),\n })\n .from(obligationCollateralsTable)\n .innerJoin(\n oraclesTable,\n sql`${obligationCollateralsTable.oracleChainId} = ${oraclesTable.chainId}\n AND ${obligationCollateralsTable.oracleAddress} = ${oraclesTable.address}`,\n )\n .where(eq(obligationCollateralsTable.obligationId, offersTable.obligationId))\n .as(\"collaterals_lateral\");\n\n const results = await db\n .select({\n hash: offersTable.hash,\n maker: offersTable.groupMaker,\n assets: offersTable.assets,\n obligationUnits: offersTable.obligationUnits,\n obligationShares: offersTable.obligationShares,\n price: offersTable.price,\n maturity: offersTable.maturity,\n expiry: offersTable.expiry,\n start: offersTable.start,\n group: offersTable.group,\n session: offersTable.session,\n buy: offersTable.buy,\n chainId: obligationsTable.chainId,\n loanToken: obligationsTable.loanToken,\n callbackAddress: offersTable.callbackAddress,\n callbackData: offersTable.callbackData,\n collaterals: collateralsLateral.collaterals,\n blockNumber: offersTable.blockNumber,\n })\n .from(offersTable)\n .innerJoin(obligationsTable, eq(offersTable.obligationId, obligationsTable.obligationId))\n .innerJoinLateral(collateralsLateral, sql`true`)\n .where(\n and(\n cursor !== null && cursor !== undefined ? gt(offersTable.hash, cursor) : undefined,\n maker !== undefined ? eq(offersTable.groupMaker, maker.toLowerCase()) : undefined,\n ),\n )\n .orderBy(asc(offersTable.hash))\n .limit(limit);\n\n const rows: Row[] = results.map((row) => {\n return {\n hash: row.hash as Hex,\n maker: row.maker as Address,\n assets: BigInt(row.assets),\n obligationUnits: BigInt(row.obligationUnits),\n obligationShares: BigInt(row.obligationShares),\n price: BigInt(row.price),\n maturity: Maturity.from(row.maturity),\n expiry: row.expiry,\n start: row.start,\n group: row.group as Hex,\n session: row.session as Hex,\n buy: row.buy,\n chainId: row.chainId,\n loanToken: row.loanToken as Address,\n collaterals: row.collaterals\n .map((c) => ({\n asset: c.asset as Address,\n oracle: c.oracle as Address,\n lltv: BigInt(c.lltv) as Offer.OfferInput[\"collaterals\"][number][\"lltv\"],\n }))\n .sort((a, b) => a.asset.toLowerCase().localeCompare(b.asset.toLowerCase())),\n callback: {\n address: row.callbackAddress as Address,\n data: row.callbackData as Hex,\n },\n consumed: 0n,\n available: 0n,\n takeable: 0n,\n blockNumber: row.blockNumber,\n };\n });\n\n const nextCursor = rows.length === limit ? rows[rows.length - 1]!.hash : null;\n return { rows, nextCursor };\n },\n\n delete: async (\n parameters:\n | {\n hashes: Hex[];\n }\n | {\n blockNumberGte: number;\n chainId: Chain.Id;\n },\n ): Promise<number> => {\n if (\"hashes\" in parameters) {\n const { hashes } = parameters;\n if (hashes.length === 0) return 0;\n const normalizedHashes = hashes.map((hash) => hash.toLowerCase());\n const result = await db\n .delete(offersTable)\n .where(inArray(offersTable.hash, normalizedHashes));\n return (result as { affectedRows: number }).affectedRows;\n }\n\n if (\"blockNumberGte\" in parameters) {\n const { blockNumberGte, chainId } = parameters;\n const result = await db\n .delete(offersTable)\n .where(\n sql`${offersTable.blockNumber} >= ${blockNumberGte} AND ${offersTable.groupChainId} = ${chainId}`,\n );\n return (result as { affectedRows: number }).affectedRows;\n }\n\n throw new Error(\"Invalid parameters\");\n },\n\n getObligations: async (\n parameters?: {\n ids?: Hex[];\n chainId?: Chain.Id[];\n loanToken?: Address[];\n collateralToken?: Address[];\n maturity?: number[];\n } & PaginationParams,\n ): Promise<{\n obligations: Obligation.Obligation[];\n nextCursor: string | null;\n }> => {\n const {\n ids,\n chainId: chainIds,\n loanToken: loanTokens,\n collateralToken: collateralTokens,\n maturity: maturities,\n cursor,\n limit = DEFAULT_LIMIT,\n } = parameters ?? {};\n\n const now = Time.now();\n\n const loanTokenFilter =\n loanTokens !== undefined && loanTokens.length > 0\n ? sql`(${sql.join(\n loanTokens.map(\n (token) => sql`LOWER(${obligationsTable.loanToken}) = ${token.toLowerCase()}`,\n ),\n sql` OR `,\n )})`\n : undefined;\n\n // Subquery for collateral token filter\n const collateralFilter =\n collateralTokens !== undefined && collateralTokens.length > 0\n ? sql`EXISTS (\n SELECT 1 FROM ${obligationCollateralsTable} oc\n WHERE oc.obligation_id = ${obligationsTable.obligationId}\n AND (${sql.join(\n collateralTokens.map((token) => sql`LOWER(oc.asset) = ${token.toLowerCase()}`),\n sql` OR `,\n )})\n )`\n : undefined;\n\n const result = await db\n .select({\n obligationId: obligationsTable.obligationId,\n chainId: obligationsTable.chainId,\n loanToken: obligationsTable.loanToken,\n collaterals: sql<\n { asset: Address; oracle: Address; lltv: string }[]\n >`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsTable.asset}, 'oracle', ${oraclesTable.address}, 'lltv', ${obligationCollateralsTable.lltv}))`.as(\n \"collaterals\",\n ),\n maturity: obligationsTable.maturity,\n })\n .from(obligationsTable)\n .innerJoin(\n obligationCollateralsTable,\n eq(obligationsTable.obligationId, obligationCollateralsTable.obligationId),\n )\n .innerJoin(\n oraclesTable,\n sql`${obligationCollateralsTable.oracleChainId} = ${oraclesTable.chainId}\n AND ${obligationCollateralsTable.oracleAddress} = ${oraclesTable.address}`,\n )\n .groupBy(obligationsTable.obligationId)\n .where(\n and(\n cursor !== null && cursor !== undefined\n ? gt(obligationsTable.obligationId, cursor)\n : sql`true`,\n ids !== undefined && ids.length > 0\n ? inArray(obligationsTable.obligationId, ids)\n : undefined,\n chainIds !== undefined && chainIds.length > 0\n ? inArray(obligationsTable.chainId, chainIds)\n : undefined,\n loanTokenFilter,\n maturities !== undefined && maturities.length > 0\n ? inArray(obligationsTable.maturity, maturities)\n : gte(obligationsTable.maturity, now),\n collateralFilter,\n ),\n )\n .orderBy(asc(obligationsTable.obligationId))\n .limit(limit);\n\n const items: Obligation.Obligation[] = [];\n for (const row of result) {\n items.push(\n Obligation.from({\n chainId: row.chainId,\n loanToken: row.loanToken as Address,\n collaterals: row.collaterals\n .sort((a, b) => a.asset.localeCompare(b.asset))\n .map((c) =>\n Collateral.from({\n asset: c.asset as Address,\n oracle: c.oracle as Address,\n lltv: LLTV.from(BigInt(c.lltv)),\n }),\n ),\n maturity: row.maturity,\n }),\n );\n }\n\n const returnedItems = Array.from(items.values());\n const nextCursor =\n returnedItems.length === limit && returnedItems.length > 0\n ? result[result.length - 1]!.obligationId\n : null;\n\n return { obligations: returnedItems, nextCursor };\n },\n\n getQuotes: async (parameters: { obligationIds: Hex[] }): Promise<Quote.Quote[]> => {\n const { obligationIds } = parameters;\n if (obligationIds.length === 0) return [];\n\n const now = Time.now();\n\n const query = ({ side }: { side: \"buy\" | \"sell\" }) =>\n db\n .selectDistinctOn([offersTable.obligationId], {\n obligationId: offersTable.obligationId,\n price: offersTable.price,\n })\n .from(offersTable)\n .innerJoin(\n groupsTable,\n and(\n eq(offersTable.groupChainId, groupsTable.chainId),\n eq(offersTable.groupMaker, groupsTable.maker),\n eq(offersTable.group, groupsTable.group),\n ),\n )\n .leftJoin(validationsTable, eq(offersTable.hash, validationsTable.offerHash))\n .leftJoin(statusTable, eq(validationsTable.statusId, statusTable.id))\n .where(\n and(\n inArray(offersTable.obligationId, obligationIds),\n eq(offersTable.buy, side === \"buy\"),\n gte(offersTable.expiry, now),\n gte(offersTable.maturity, now),\n lte(offersTable.start, now),\n sql`(${statusTable.code} IS NULL OR ${statusTable.code} = ${Offer.Status.VALID})`,\n ),\n )\n .orderBy(\n offersTable.obligationId,\n // lower prices first for buy, higher prices first for sell\n side === \"buy\"\n ? sql`${offersTable.price}::numeric ASC`\n : sql`${offersTable.price}::numeric DESC`,\n );\n\n const [bestBuys, bestSells] = await Promise.all([\n query({ side: \"buy\" }),\n query({ side: \"sell\" }),\n ]);\n\n const quotes = new Map<string, { ask: Quote.Quote[\"ask\"]; bid: Quote.Quote[\"bid\"] }>();\n\n for (const row of bestSells) {\n quotes.set(row.obligationId, {\n ask: { price: BigInt(row.price) },\n bid: { price: 0n },\n });\n }\n\n for (const row of bestBuys) {\n const quote = quotes.get(row.obligationId);\n\n if (!quote) {\n quotes.set(row.obligationId, {\n ask: { price: 0n },\n bid: { price: BigInt(row.price) },\n });\n continue;\n }\n\n quote.bid = { price: BigInt(row.price) };\n }\n\n return Array.from(quotes.entries())\n .map(([id, quote]) => {\n return Quote.from({ obligationId: id as Hex, ask: quote.ask, bid: quote.bid });\n })\n .sort((a, b) => {\n return a.obligationId.localeCompare(b.obligationId);\n });\n },\n };\n}\n","import { and, asc, eq, gt, gte, sql } from \"drizzle-orm\";\nimport type { Address, Hex } from \"viem\";\nimport { Maturity, Offer } from \"#core\";\nimport * as OffersDomain from \"#database/domains/Offers.ts\";\nimport {\n callbacks as callbacksTable,\n groups as groupsTable,\n lots as lotsTable,\n obligationCollateralsV2 as obligationCollateralsTable,\n obligations as obligationsTable,\n offersCallbacks as offersCallbacksTable,\n offers as offersTable,\n offsets as offsetsTable,\n oracles as oraclesTable,\n positions as positionsTable,\n} from \"#database/drizzle/schema.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport { Logger } from \"#logger/index.ts\";\nimport * as ApiSchema from \"../Schema/index.ts\";\nimport * as ApiPayload from \"./Payload.ts\";\n\nexport type GetOffersQueryParams = {\n /** Filter by maker address */\n maker?: Address;\n /** Cursor string returned by a previous call, for pagination */\n cursor?: string;\n /** Page size; defaults to {@link OffersDomain.DEFAULT_LIMIT} */\n limit?: number;\n};\n\ntype OffersRowsResult = {\n rows: OffersDomain.Row[];\n nextCursor: string | null;\n};\n\n/**\n * Query offers with computed consumed/available/takeable values.\n * @param db - The database client. {@link Database.Core}\n * @param parameters - {@link GetOffersQueryParams}\n * @returns The offers with pagination cursor.\n */\nexport async function getOffersQuery(\n db: Database.Core,\n parameters?: GetOffersQueryParams,\n): Promise<OffersRowsResult> {\n const limit = parameters?.limit ?? OffersDomain.DEFAULT_LIMIT;\n const cursor = parameters?.cursor;\n const maker = parameters?.maker;\n\n if (cursor !== null && cursor !== undefined) {\n if (!cursor.startsWith(\"0x\") || cursor.length !== 66) {\n throw new Error(\"Invalid cursor format\");\n }\n }\n\n // Subtract 1ms before flooring to keep the current second inclusive.\n const now = Math.floor((Date.now() - 1) / 1000);\n\n const collateralsLateral = db\n .select({\n collaterals: sql<Array<{ asset: string; oracle: string; lltv: string }>>`COALESCE(\n jsonb_agg(\n jsonb_build_object(\n 'asset', ${obligationCollateralsTable.asset},\n 'oracle', ${oraclesTable.address},\n 'lltv', ${obligationCollateralsTable.lltv}\n )\n ),\n '[]'::jsonb\n )`.as(\"collaterals\"),\n })\n .from(obligationCollateralsTable)\n .innerJoin(\n oraclesTable,\n sql`${obligationCollateralsTable.oracleChainId} = ${oraclesTable.chainId}\n AND ${obligationCollateralsTable.oracleAddress} = ${oraclesTable.address}`,\n )\n .where(eq(obligationCollateralsTable.obligationId, offersTable.obligationId))\n .as(\"collaterals_lateral\");\n\n const lotBalanceExpr = sql<string>`GREATEST(0, LEAST(\n COALESCE(${positionsTable.balance}, 0)::numeric\n + COALESCE((\n SELECT SUM(${offsetsTable.value}::numeric)\n FROM ${offsetsTable}\n WHERE ${offsetsTable.chainId} = ${callbacksTable.positionChainId}\n AND LOWER(${offsetsTable.contract}) = LOWER(${callbacksTable.positionContract})\n AND LOWER(${offsetsTable.user}) = LOWER(${callbacksTable.positionUser})\n ), 0)\n - COALESCE(${lotsTable.lower}::numeric, 0),\n (COALESCE(${lotsTable.upper}::numeric, 0) - COALESCE(${lotsTable.lower}::numeric, 0))\n - CASE\n WHEN ${offersTable.assets}::numeric > 0\n THEN COALESCE(${groupsTable.consumed}::numeric, 0)\n * (COALESCE(${lotsTable.upper}::numeric, 0) - COALESCE(${lotsTable.lower}::numeric, 0))\n / ${offersTable.assets}::numeric\n ELSE 0\n END\n ))`;\n\n const contributionExpr = sql<string>`CASE\n WHEN ${positionsTable.asset} IS NULL OR ${lotsTable.lower} IS NULL THEN 0\n ELSE LEAST(COALESCE(${callbacksTable.amount}::numeric, ${lotBalanceExpr}), ${lotBalanceExpr})\n END`;\n\n const availableExpr = sql<string>`COALESCE((\n SELECT SUM(deduped.contribution)\n FROM (\n SELECT DISTINCT ON (\n ${callbacksTable.positionChainId},\n LOWER(${callbacksTable.positionContract}),\n LOWER(${callbacksTable.positionUser})\n )\n ${contributionExpr} AS contribution\n FROM ${offersCallbacksTable}\n INNER JOIN ${callbacksTable} ON ${offersCallbacksTable.callbackId} = ${callbacksTable.id}\n LEFT JOIN ${positionsTable}\n ON ${positionsTable.chainId} = ${callbacksTable.positionChainId}\n AND LOWER(${positionsTable.contract}) = LOWER(${callbacksTable.positionContract})\n AND LOWER(${positionsTable.user}) = LOWER(${callbacksTable.positionUser})\n LEFT JOIN ${lotsTable}\n ON ${lotsTable.chainId} = ${callbacksTable.positionChainId}\n AND LOWER(${lotsTable.contract}) = LOWER(${callbacksTable.positionContract})\n AND LOWER(${lotsTable.user}) = LOWER(${callbacksTable.positionUser})\n AND LOWER(${lotsTable.group}) = LOWER(${offersTable.group})\n WHERE ${offersCallbacksTable.offerHash} = ${offersTable.hash}\n ORDER BY\n ${callbacksTable.positionChainId},\n LOWER(${callbacksTable.positionContract}),\n LOWER(${callbacksTable.positionUser}),\n ${contributionExpr} DESC\n ) deduped\n ), 0)`;\n\n const results = await db\n .select({\n hash: offersTable.hash,\n maker: offersTable.groupMaker,\n assets: offersTable.assets,\n obligationUnits: offersTable.obligationUnits,\n obligationShares: offersTable.obligationShares,\n consumed: groupsTable.consumed,\n price: offersTable.price,\n maturity: offersTable.maturity,\n expiry: offersTable.expiry,\n start: offersTable.start,\n group: offersTable.group,\n session: offersTable.session,\n buy: offersTable.buy,\n chainId: obligationsTable.chainId,\n loanToken: obligationsTable.loanToken,\n callbackAddress: offersTable.callbackAddress,\n callbackData: offersTable.callbackData,\n collaterals: collateralsLateral.collaterals,\n blockNumber: offersTable.blockNumber,\n available: sql<string>`${availableExpr}::numeric`.as(\"available\"),\n takeable: sql<string>`FLOOR(GREATEST(0,\n CASE WHEN ${offersTable.buy} = false\n THEN ${offersTable.assets}::numeric - ${groupsTable.consumed}::numeric\n ELSE LEAST(\n ${offersTable.assets}::numeric - ${groupsTable.consumed}::numeric,\n ${availableExpr}::numeric\n )\n END\n ))`.as(\"takeable\"),\n })\n .from(offersTable)\n .innerJoin(obligationsTable, eq(offersTable.obligationId, obligationsTable.obligationId))\n .innerJoin(\n groupsTable,\n and(\n eq(offersTable.groupChainId, groupsTable.chainId),\n eq(offersTable.groupMaker, groupsTable.maker),\n eq(offersTable.group, groupsTable.group),\n ),\n )\n .innerJoinLateral(collateralsLateral, sql`true`)\n .where(\n and(\n cursor !== null && cursor !== undefined ? gt(offersTable.hash, cursor) : undefined,\n maker !== undefined ? eq(offersTable.groupMaker, maker.toLowerCase()) : undefined,\n gte(offersTable.expiry, now),\n gte(offersTable.maturity, now),\n maker === undefined\n ? sql`GREATEST(0,\n CASE WHEN ${offersTable.buy} = false\n THEN ${offersTable.assets}::numeric - ${groupsTable.consumed}::numeric\n ELSE LEAST(\n ${offersTable.assets}::numeric - ${groupsTable.consumed}::numeric,\n ${availableExpr}::numeric\n )\n END\n ) > 0`\n : undefined,\n ),\n )\n .orderBy(asc(offersTable.hash))\n .limit(limit);\n\n const rows: OffersRowsResult[\"rows\"] = results.map((row) => {\n return {\n hash: row.hash as Hex,\n maker: row.maker as Address,\n assets: BigInt(row.assets),\n obligationUnits: BigInt(row.obligationUnits),\n obligationShares: BigInt(row.obligationShares),\n price: BigInt(row.price),\n maturity: Maturity.from(row.maturity),\n expiry: row.expiry,\n start: row.start,\n group: row.group as Hex,\n session: row.session as Hex,\n buy: row.buy,\n chainId: row.chainId,\n loanToken: row.loanToken as Address,\n collaterals: row.collaterals\n .map((c) => ({\n asset: c.asset as Address,\n oracle: c.oracle as Address,\n lltv: BigInt(c.lltv) as Offer.OfferInput[\"collaterals\"][number][\"lltv\"],\n }))\n .sort((a, b) => a.asset.toLowerCase().localeCompare(b.asset.toLowerCase())),\n callback: {\n address: row.callbackAddress as Address,\n data: row.callbackData as Hex,\n },\n consumed: BigInt(row.consumed),\n available: BigInt(String(row.available ?? \"0\").split(\".\")[0] ?? \"0\"),\n takeable: BigInt(String(row.takeable ?? \"0\").split(\".\")[0] ?? \"0\"),\n blockNumber: row.blockNumber,\n };\n });\n\n const nextCursor = rows.length === limit ? rows[rows.length - 1]!.hash : null;\n return { rows, nextCursor };\n}\n\nexport async function getOffers(\n queryParameters: object,\n db: Database.Database,\n): Promise<ApiPayload.Payload<ApiSchema.OfferResponse.OfferResponse[]>> {\n const logger = Logger.getLogger();\n\n const result = ApiSchema.safeParse(\"get_offers\", queryParameters, (issue) => issue.message);\n\n if (!result.success) return ApiPayload.failure(result.error);\n const query = result.data;\n\n try {\n const { rows, nextCursor }: OffersRowsResult = query.maker\n ? await getOffersQuery(db, {\n maker: query.maker,\n cursor: query.cursor,\n limit: query.limit,\n })\n : await db.book.getOffers({\n side: query.side!,\n obligationId: query.obligation_id!,\n cursor: query.cursor,\n limit: query.limit,\n });\n\n const hashes = rows.map((row) => row.hash);\n const attestationMap = await db.trees.getAttestations(hashes);\n\n return ApiPayload.success({\n data: rows.map((row) => {\n const hash = Offer.hash(row);\n const attestation = attestationMap.get(hash);\n return ApiSchema.OfferResponse.from({\n ...row,\n ...attestation,\n });\n }),\n cursor: nextCursor ?? null,\n });\n } catch (err) {\n logger.error({\n err,\n msg: \"Error get offers\",\n errorMessage: err instanceof Error ? err.message : String(err),\n errorStack: err instanceof Error ? err.stack : undefined,\n });\n\n return ApiPayload.failure(err);\n }\n}\n","import type { Database } from \"#database/index.ts\";\nimport { Logger } from \"#logger/index.ts\";\nimport * as ApiSchema from \"../Schema/index.ts\";\nimport * as ApiPayload from \"./Payload.ts\";\n\n/**\n * Get positions for a user with remaining balance calculation.\n * @param queryParameters - Request parameters including user address and pagination.\n * @param db - Database instance.\n * @returns Paginated list of positions with remaining balances.\n */\nexport async function getUserPositions(\n queryParameters: object,\n db: Database.Database,\n): Promise<ApiPayload.Payload<ApiSchema.PositionResponse.PositionResponse[]>> {\n const logger = Logger.getLogger();\n\n const result = ApiSchema.safeParse(\n \"get_user_positions\",\n queryParameters,\n (issue) => issue.message,\n );\n\n if (!result.success) return ApiPayload.failure(result.error);\n const query = result.data;\n\n try {\n const { positions, nextCursor } = await db.positions.getByUser({\n user: query.user_address,\n cursor: query.cursor,\n limit: query.limit,\n });\n\n return ApiPayload.success({\n data: positions.map((position) => ApiSchema.PositionResponse.from(position)),\n cursor: nextCursor ?? null,\n });\n } catch (err) {\n logger.error({\n err,\n msg: \"Error get user positions\",\n errorMessage: err instanceof Error ? err.message : String(err),\n errorStack: err instanceof Error ? err.stack : undefined,\n });\n\n return ApiPayload.failure(err);\n }\n}\n","import type { Hex } from \"viem\";\nimport { Offer, Tree } from \"#core\";\nimport type { Gatekeeper } from \"#gatekeeper/Gatekeeper.ts\";\nimport { Logger } from \"#logger/index.ts\";\nimport * as ApiSchema from \"../Schema/index.ts\";\nimport * as ApiPayload from \"./Payload.ts\";\n\nexport type ValidationIssue = {\n index: number;\n rule: string;\n message: string;\n};\n\ntype ValidateOffersSuccessPayload = ApiPayload.SuccessPayload<{\n payload: Hex;\n root: Hex;\n}>;\n\ntype ValidateOffersIssuesPayload = ApiPayload.SuccessPayload<{\n issues: ValidationIssue[];\n}>;\n\ntype ValidateOffersResponse = ValidateOffersSuccessPayload | ValidateOffersIssuesPayload;\ntype OfferInput = Parameters<typeof Offer.fromSnakeCase>[0];\n\nexport async function validateOffers(\n body: object,\n gatekeeper: Gatekeeper,\n): Promise<ValidateOffersResponse | ApiPayload.ErrorPayload> {\n const logger = Logger.getLogger();\n\n const result = ApiSchema.safeParse(\"validate_offers\", body, (issue) => issue.message);\n if (!result.success)\n return ApiPayload.failure(\n new ApiPayload.BadRequestError(result.error.issues[0]?.message ?? \"Invalid request body\"),\n );\n const { offers: rawOffers } = result.data;\n const parsedOffers: Offer.Offer[] = [];\n const offerIndexByHash = new Map<Hex, number>();\n\n for (let i = 0; i < rawOffers.length; i++) {\n const rawOffer = rawOffers[i] as OfferInput;\n try {\n const offer = Offer.fromSnakeCase(rawOffer);\n const hash = Offer.hash(offer);\n if (!offerIndexByHash.has(hash)) {\n offerIndexByHash.set(hash, i);\n parsedOffers.push(offer);\n }\n } catch (err) {\n let message = err instanceof Error ? err.message : String(err);\n if (err instanceof Offer.InvalidOfferError) {\n message = err.formattedMessage;\n }\n return ApiPayload.failure(\n new ApiPayload.BadRequestError(`Offer at index ${i} failed to parse: ${message}`),\n );\n }\n }\n\n try {\n const { issues } = await gatekeeper.isAllowed(parsedOffers);\n\n if (issues.length > 0) {\n const mappedIssues = issues\n .map((issue): ValidationIssue | null => {\n const index = offerIndexByHash.get(Offer.hash(issue.item));\n if (index === undefined) return null;\n return { index, rule: issue.ruleName, message: issue.message };\n })\n .filter((issue): issue is ValidationIssue => issue !== null);\n\n return ApiPayload.success({\n data: { issues: mappedIssues },\n cursor: null,\n });\n }\n\n const tree = Tree.from(parsedOffers);\n const payload = Tree.encodeUnsigned(tree);\n return ApiPayload.success({\n data: { payload, root: tree.root },\n cursor: null,\n });\n } catch (err) {\n logger.error({\n err,\n msg: \"Error validating offers\",\n errorMessage: err instanceof Error ? err.message : String(err),\n errorStack: err instanceof Error ? err.stack : undefined,\n });\n return ApiPayload.failure(err);\n }\n}\n","export * from \"./getBook.ts\";\nexport * from \"./getConfigContracts.ts\";\nexport * from \"./getConfigRules.ts\";\nexport * from \"./getDocs.ts\";\nexport * from \"./getHealth.ts\";\nexport * from \"./getObligation.ts\";\nexport * from \"./getObligations.ts\";\nexport * from \"./getOffers.ts\";\nexport * from \"./getUserPositions.ts\";\nexport * from \"./validateOffers.ts\";\n","import { serve as serveHono } from \"@hono/node-server\";\nimport { SpanStatusCode } from \"@opentelemetry/api\";\nimport { type Context, Hono } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport type * as ChainRegistry from \"#core/ChainRegistry.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport type { GatekeeperClient } from \"#gatekeeper/Client.ts\";\nimport { Tracer } from \"#tracer/index.ts\";\nimport * as Controllers from \"./Controllers/index.ts\";\nimport * as ApiPayload from \"./Controllers/Payload.ts\";\n\nexport type RouterApi = {\n serve: () => void;\n};\n\nexport type ApiConfig = {\n db: Database.Database;\n gatekeeper: GatekeeperClient;\n port: number;\n chainRegistry: ChainRegistry.ChainRegistry;\n};\n\nexport function from(config: ApiConfig): RouterApi {\n const { db, gatekeeper, port, chainRegistry } = config;\n\n return create({\n port,\n db,\n gatekeeper,\n chainRegistry,\n });\n}\n\ntype CreateParameters = {\n db: Database.Database;\n gatekeeper: GatekeeperClient;\n port: number;\n chainRegistry: ChainRegistry.ChainRegistry;\n};\n\nexport function create(params: CreateParameters): RouterApi {\n return {\n serve: () => serve(params),\n };\n}\n\n/**\n * Start a local router server.\n * @example\n * ```ts\n * import { RouterApi } from \"@morpho-dev/router\";\n * RouterApi.serve({ port: 8081 }); // local router API server running on http://localhost:8081\n * ```\n */\nfunction serve(parameters: CreateParameters) {\n const { db, gatekeeper, chainRegistry } = parameters;\n const tracer = Tracer.getTracer(\"router.api\");\n\n const app = new Hono();\n app.use(\"*\", cors());\n\n app.use(\"*\", async (c: Context, next) => {\n const {\n req: { path, method },\n } = c;\n\n const spanName = `${method} ${path}`;\n\n return Tracer.startActiveSpan(tracer, spanName, async (span) => {\n const res = await next();\n\n span.setAttribute(\"http.method\", method);\n span.setAttribute(\"http.target\", path);\n span.setAttribute(\"http.route\", path);\n span.setAttribute(\"http.status_code\", c.res.status);\n\n if (c.res.status >= 500) {\n span.setStatus({ code: SpanStatusCode.ERROR });\n }\n\n return res;\n });\n });\n\n app.get(\"/v1/offers\", async (c: Context) => {\n const { statusCode, body } = await Controllers.getOffers(c.req.query(), db);\n return c.json(body, statusCode);\n });\n\n app.get(\"/v1/obligations\", async (c: Context) => {\n const { statusCode, body } = await Controllers.getObligations(c.req.query(), db);\n return c.json(body, statusCode);\n });\n\n app.get(\"/v1/obligations/:obligationId\", async (c: Context) => {\n const id = c.req.param(\"obligationId\");\n const { statusCode, body } = await Controllers.getObligation({ obligation_id: id }, db);\n return c.json(body, statusCode);\n });\n\n app.get(\"/v1/books/:obligationId/:side\", async (c: Context) => {\n const q = c.req.query();\n const { statusCode, body } = await Controllers.getBook(\n {\n obligation_id: c.req.param(\"obligationId\"),\n side: c.req.param(\"side\"),\n cursor: q.cursor,\n limit: q.limit,\n },\n db,\n );\n return c.json(body, statusCode);\n });\n\n app.post(\"/v1/validate\", async (c: Context) => {\n try {\n const reqBody = await c.req.json();\n const { statusCode, body } = await gatekeeper.validate(reqBody);\n return c.json(body, statusCode as ApiPayload.STATUS_CODE);\n } catch (err) {\n const failure = ApiPayload.failure(err);\n return c.json(failure.body, failure.statusCode);\n }\n });\n\n app.get(\"/v1/users/:userAddress/positions\", async (c: Context) => {\n const query = c.req.query();\n const { statusCode, body } = await Controllers.getUserPositions(\n { user_address: c.req.param(\"userAddress\"), cursor: query.cursor, limit: query.limit },\n db,\n );\n return c.json(body, statusCode);\n });\n\n app.get(\"/v1/health\", async (c: Context) => {\n const { statusCode, body } = await Controllers.getHealth(c.req.query(), db, chainRegistry);\n return c.json(body, statusCode);\n });\n\n app.get(\"/v1/health/collectors\", async (c: Context) => {\n const { statusCode, body } = await Controllers.getHealthCollectors(\n c.req.query(),\n db,\n chainRegistry,\n );\n return c.json(body, statusCode);\n });\n\n app.get(\"/v1/health/chains\", async (c: Context) => {\n const { statusCode, body } = await Controllers.getHealthChains(\n c.req.query(),\n db,\n undefined,\n chainRegistry,\n );\n return c.json(body, statusCode);\n });\n\n app.get(\"/v1/config/contracts\", async (c: Context) => {\n const { statusCode, body } = await Controllers.getConfigContracts(c.req.query(), chainRegistry);\n return c.json(body, statusCode);\n });\n\n app.get(\"/v1/config/rules\", async (c: Context) => {\n try {\n const { statusCode, body } = await gatekeeper.getConfigRules(c.req.query());\n return c.json(body, statusCode as ApiPayload.STATUS_CODE);\n } catch (err) {\n const failure = ApiPayload.failure(err);\n return c.json(failure.body, failure.statusCode);\n }\n });\n\n app.get(\"/docs/openapi\", async (c: Context) =>\n c.text(JSON.stringify(await Controllers.getSwaggerJson()), 200, {\n \"Content-Type\": \"application/json; charset=utf-8\",\n }),\n );\n app.get(\"/docs/api\", async (c: Context) => c.html(await Controllers.getDocsHtml(), 200));\n app.get(\"/docs\", async (c: Context) => c.html(await Controllers.getIntegratorDocsHtml(), 200));\n\n serveHono({\n fetch: app.fetch,\n port: parameters.port,\n });\n}\n","export * from \"./Api.ts\";\nexport * as Controllers from \"./Controllers/index.ts\";\nexport * from \"./Schema/index.ts\";\n","import createOpenApiFetchClient, { type Client as OpenApiFetchClient } from \"openapi-fetch\";\nimport type { Address, Hex } from \"viem\";\nimport { type Compute, Maturity, Obligation, Offer, Quote } from \"#core\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport type * as GeneratedApiSchema from \"../api/Schema/generated/swagger.d.ts\";\n\ntype RouterClientConfig = {\n /** The URL of the router. */\n readonly url: URL;\n /** The default headers to use for each request. */\n readonly headers: Headers;\n};\n\nexport type Client = Compute<\n RouterClientConfig & {\n /**\n * Get offers from the router.\n * @param parameters - {@link getOffers.Parameters}\n * @returns The offers with pagination cursor. {@link getOffers.ReturnType}\n * @throws If the request fails - {@link getOffers.ErrorType}\n *\n * @example\n * ```ts\n * const router = RouterClient.connect({ url: \"https://router.morpho.dev\" });\n * const { offers, cursor } = await router.getOffers({ side: \"buy\", obligationId: \"0xa1c...d2f\" });\n * console.log(offers);\n * ```\n */\n getOffers: (parameters: getOffers.Parameters) => Promise<getOffers.ReturnType>;\n\n /**\n * Get obligations from the router.\n * @param parameters - {@link getObligations.Parameters}\n * @returns The obligations with pagination cursor. {@link getObligations.ReturnType}\n * @throws If the request fails - {@link getObligations.ErrorType}\n *\n * @example\n * ```ts\n * const router = RouterClient.connect({ url: \"https://router.morpho.dev\" });\n * const { obligations, cursor } = await router.getObligations();\n * console.log(obligations[0].id()); // 0x123...456\n * ```\n */\n getObligations: (parameters?: getObligations.Parameters) => Promise<getObligations.ReturnType>;\n }\n>;\n\nexport type ConnectOptions = {\n /** The URL of the router to interact with.\n * @default \"https://router.morpho.dev\"\n */\n url?: string;\n /** The API key to use for the router API. */\n apiKey?: string;\n /** The default headers to use for each request. */\n headers?: Headers;\n};\n\n/**\n * Creates an instance of a router client.\n * @constructor\n * @param parameters - {@link connect.Parameters}\n * @returns A Router Client. {@link connect.ReturnType}\n *\n * @example\n * ```typescript\n * const router = RouterClient.connect({ url: \"https://router.morpho.dev\" });\n * ```\n */\nexport function connect(parameters?: connect.Parameters): connect.ReturnType {\n const u = new URL(parameters?.url || \"https://router.morpho.dev\");\n if (u.protocol !== \"http:\" && u.protocol !== \"https:\") throw new InvalidUrlError(u.toString());\n\n const headers = parameters?.headers ?? new Headers();\n headers.set(\"Content-Type\", \"application/json\");\n parameters?.apiKey !== undefined ? headers.set(\"X-API-Key\", parameters.apiKey) : null;\n\n const config: RouterClientConfig = { url: u, headers };\n\n const apiClient = createOpenApiFetchClient<GeneratedApiSchema.paths>({\n baseUrl: config.url.toString(),\n headers: config.headers,\n querySerializer: { array: { style: \"form\", explode: false } },\n });\n\n return {\n ...config,\n getOffers: (parameters) => getOffers(apiClient, parameters),\n getObligations: (parameters) => getObligations(apiClient, parameters),\n };\n}\n\nexport declare namespace connect {\n export type Parameters = ConnectOptions;\n export type ReturnType = Client;\n export type ErrorType = InvalidUrlError;\n}\n\nexport async function getOffers(\n apiClient: OpenApiFetchClient<GeneratedApiSchema.paths>,\n parameters: getOffers.Parameters,\n): Promise<getOffers.ReturnType> {\n const { data, error, response } = await apiClient.GET(\"/v1/offers\", {\n params: {\n query: {\n side: parameters.side,\n obligation_id: parameters.obligationId,\n cursor: parameters.cursor,\n limit: parameters.limit,\n },\n },\n });\n\n if (error !== undefined) {\n switch (response.status) {\n case 401:\n throw new HttpUnauthorizedError();\n case 403:\n throw new HttpForbiddenError();\n case 429:\n throw new HttpRateLimitError();\n }\n throw new HttpGetApiFailedError(`GET request returned ${response.status}`, {\n details: JSON.stringify(error),\n });\n }\n\n const offers =\n data?.data.map((item) => {\n const { root, proof, signature, offer: offerData } = item;\n // Transform new API structure (with nested offer object) to Offer.fromSnakeCase format\n const offer = Offer.fromSnakeCase({\n maker: offerData.maker as Address,\n assets: offerData.assets,\n obligation_units: offerData.obligation_units,\n obligation_shares: offerData.obligation_shares,\n price: offerData.price,\n maturity: Maturity.from(offerData.obligation.maturity),\n expiry: offerData.expiry,\n start: offerData.start,\n group: offerData.group,\n session: offerData.session,\n buy: offerData.buy,\n chain_id: item.chain_id,\n loan_token: offerData.obligation.loan_token as Address,\n collaterals: offerData.obligation.collaterals.map((collateral) => ({\n asset: collateral.token as Address,\n oracle: collateral.oracle as Address,\n lltv: collateral.lltv,\n })),\n callback: {\n address: offerData.callback as Address,\n data: offerData.callback_data as Hex,\n },\n });\n\n return {\n ...offer,\n hash: item.offer_hash as Hex,\n consumed: BigInt(item.consumed),\n takeable: BigInt(item.takeable),\n blockNumber: Number(item.block_number),\n root: (root as Hex) || undefined,\n proof: (proof as Hex[]) || undefined,\n signature: signature ? (signature as Hex) : undefined,\n };\n }) ?? [];\n\n return {\n cursor: data?.cursor ?? null,\n offers,\n };\n}\n\nexport declare namespace getOffers {\n export type Parameters = {\n /** The desired side of the match: 'buy' if you want to buy, 'sell' if you want to sell */\n side: \"buy\" | \"sell\";\n /** The offers obligation id */\n obligationId: Hex;\n /** Pagination cursor in base64url-encoded format */\n cursor?: string;\n /** Maximum number of offers to return. @default 20 */\n limit?: number;\n };\n\n export type ReturnType = {\n offers: Compute<\n Offer.Offer & {\n hash: Hex;\n blockNumber: number;\n consumed: bigint;\n takeable: bigint;\n } & {\n /** 32-byte merkle root. */\n root?: Hex;\n /** Sibling hashes for the merkle proof. */\n proof?: Hex[];\n /** Offer signature from the Merkle tree. */\n signature?: Hex;\n }\n >[];\n /** The pagination cursor. */\n cursor: string | null;\n };\n\n export type ErrorType = GetApiErrorType;\n}\n\nexport async function getObligations(\n apiClient: OpenApiFetchClient<GeneratedApiSchema.paths>,\n parameters?: getObligations.Parameters,\n): Promise<getObligations.ReturnType> {\n const { data, error, response } = await apiClient.GET(\"/v1/obligations\", {\n params: {\n query: {\n cursor: parameters?.cursor,\n limit: parameters?.limit,\n chains: parameters?.chainIds,\n loan_tokens: parameters?.loanTokens,\n collateral_tokens: parameters?.collateralTokens,\n maturities: parameters?.maturities,\n },\n },\n });\n\n if (error !== undefined) {\n switch (response.status) {\n case 401:\n throw new HttpUnauthorizedError();\n case 403:\n throw new HttpForbiddenError();\n case 429:\n throw new HttpRateLimitError();\n }\n throw new HttpGetApiFailedError(`GET request returned ${response.status}`, {\n details: JSON.stringify(error),\n });\n }\n\n const obligations =\n data?.data.map((item) => {\n const obligation = Obligation.fromSnakeCase({\n chain_id: item.chain_id,\n loan_token: item.loan_token as Address,\n collaterals: item.collaterals.map((collateral) => ({\n asset: collateral.token as Address,\n oracle: collateral.oracle as Address,\n lltv: collateral.lltv,\n })),\n maturity: Maturity.from(item.maturity),\n });\n\n const { obligationId: _, ...returned } = {\n id: () => Obligation.id(obligation),\n ...obligation,\n ...Quote.fromSnakeCase({ obligation_id: item.id as Hex, ask: item.ask, bid: item.bid }),\n };\n return returned;\n }) ?? [];\n\n return {\n cursor: data?.cursor ?? null,\n obligations,\n };\n}\n\nexport declare namespace getObligations {\n export type Parameters = {\n /** Pagination cursor is a 32-byte hex string. */\n cursor?: Hex;\n /** Maximum number of obligations to return. @default 20 */\n limit?: number;\n /** Filter by chain IDs (comma-separated). */\n chainIds?: number[];\n /** Filter by loan token addresses (comma-separated). */\n loanTokens?: Address[];\n /** Filter by collateral tokens (comma-separated, matches any collateral). */\n collateralTokens?: Address[];\n /** Filter by exact maturity timestamps (comma-separated, unix seconds). */\n maturities?: number[];\n };\n\n export type ReturnType = {\n obligations: Compute<\n {\n /** The obligation id. Uses {@link Obligation.id} to calculate the id.*/\n id: () => Hex;\n } & Obligation.Obligation &\n Omit<Quote.Quote, \"obligationId\">\n >[];\n /** The pagination cursor. */\n cursor: string | null;\n };\n\n export type ErrorType = GetApiErrorType;\n}\n\ntype GetApiErrorType =\n | HttpGetApiFailedError\n | HttpUnauthorizedError\n | HttpForbiddenError\n | HttpRateLimitError;\n\nexport class InvalidUrlError extends Errors.BaseError {\n override name = \"Router.InvalidUrlError\";\n constructor(url: string) {\n super(`URL \"${url}\" is not http/https.`);\n }\n}\n\nexport class HttpUnauthorizedError extends Errors.BaseError {\n override name = \"Router.HttpUnauthorizedError\";\n constructor() {\n super(\"Unauthorized.\", {\n metaMessages: [\"Ensure that an API key is provided.\"],\n });\n }\n}\n\nexport class HttpForbiddenError extends Errors.BaseError {\n override name = \"Router.HttpForbiddenError\";\n constructor() {\n super(\"Forbidden.\", {\n metaMessages: [\"Ensure that the API key is valid.\"],\n });\n }\n}\n\nexport class HttpRateLimitError extends Errors.BaseError {\n override name = \"Router.HttpRateLimitError\";\n constructor() {\n super(\"Rate limit exceeded.\", {\n metaMessages: [\n \"The number of allowed requests has been exceeded. You must wait for the rate limit to reset.\",\n ],\n });\n }\n}\n\nexport class HttpGetApiFailedError extends Errors.BaseError {\n override name = \"Router.HttpGetApiFailedError\";\n constructor(message: string, { details }: { details?: string } = {}) {\n super(message, {\n metaMessages: [details],\n });\n }\n}\n","export * from \"./schema.ts\";\nexport * from \"./VERSION.ts\";\n","import { and, asc, eq, gt, gte, lte, sql } from \"drizzle-orm\";\nimport type * as Chain from \"#core/Chain.ts\";\nimport type * as ChainRegistry from \"#core/ChainRegistry.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport * as Collector from \"#indexer/collectors/Collector.ts\";\nimport { chains, collectors } from \"../drizzle/schema.ts\";\n\nexport type ChainState = {\n chainId: Chain.Id;\n blockNumber: number;\n epoch: bigint;\n};\n\nexport type CollectorState = {\n collectorName: Collector.Name;\n chainId: Chain.Id;\n blockNumber: number;\n epoch: bigint;\n};\n\nexport type ChainSnapshot = ChainState & {\n updatedAt: Date;\n};\n\nexport type CollectorSnapshot = CollectorState & {\n updatedAt: Date;\n};\n\nexport type InitParameters = {\n chainId: Chain.Id;\n collectorName: Collector.Name;\n};\n\nexport type AdvanceChainParameters = {\n chainId: Chain.Id;\n blockNumber: number;\n epoch: bigint;\n};\n\nexport type AdvanceCollectorParameters = {\n collectorName: Collector.Name;\n chainId: Chain.Id;\n blockNumber: number;\n epoch: bigint;\n};\n\nexport type HandleReorgParameters = {\n chainId: Chain.Id;\n blockNumber: number;\n epoch: bigint;\n collectorNames?: Collector.Name[];\n};\n\nexport type BlocksDomain = {\n /** Initialize and return chain + collector state, seeding rows when missing. */\n init: (parameters: InitParameters) => Promise<{\n chain: ChainState;\n collector: CollectorState;\n }>;\n /** Return chain state, failing if it has not been initialized yet. */\n getChain: (chainId: Chain.Id) => Promise<ChainState>;\n /** Return collector state, failing if it has not been initialized yet. */\n getCollector: (parameters: {\n chainId: Chain.Id;\n collectorName: Collector.Name;\n }) => Promise<CollectorState>;\n /** Return chain state rows, optionally filtered by chain id. */\n getChains: (parameters?: { chainId?: Chain.Id }) => Promise<ChainSnapshot[]>;\n /** Return collector state rows, optionally filtered by chain id. */\n getCollectors: (parameters?: { chainId?: Chain.Id }) => Promise<CollectorSnapshot[]>;\n /** Persist chain block state updates. */\n advanceChain: (parameters: AdvanceChainParameters) => Promise<void>;\n /** Persist collector block state updates and enforce invariants via storage CAS. */\n advanceCollector: (parameters: AdvanceCollectorParameters) => Promise<void>;\n /** Apply a reorg by advancing the chain epoch and fencing collectors. */\n handleReorg: (parameters: HandleReorgParameters) => Promise<void>;\n};\n\n/** Postgres implementation. */\nexport const create = (config: {\n db: Database.Core;\n chainRegistry: ChainRegistry.ChainRegistry;\n}): BlocksDomain => {\n const { db, chainRegistry } = config;\n\n const getChain = async (chainId: Chain.Id): Promise<ChainState> => {\n const rows = await db\n .select({\n chainId: chains.chainId,\n blockNumber: chains.blockNumber,\n epoch: chains.epoch,\n })\n .from(chains)\n .where(eq(chains.chainId, chainId))\n .limit(1);\n\n if (rows.length === 0) {\n throw new Error(`Chain state not initialized for chain ${chainId}. Call blocks.init first.`);\n }\n\n const row = rows[0]!;\n return {\n chainId: row.chainId,\n blockNumber: Number(row.blockNumber),\n epoch: BigInt(row.epoch),\n };\n };\n\n const getCollector = async (parameters: {\n chainId: Chain.Id;\n collectorName: Collector.Name;\n }): Promise<CollectorState> => {\n const name = parameters.collectorName.toLowerCase() as Collector.Name;\n\n const rows = await db\n .select({\n collectorName: collectors.name,\n chainId: collectors.chainId,\n blockNumber: collectors.blockNumber,\n epoch: collectors.epoch,\n })\n .from(collectors)\n .where(and(eq(collectors.chainId, parameters.chainId), eq(collectors.name, name)))\n .limit(1);\n\n if (rows.length === 0) {\n throw new Error(\n `Collector state not initialized for ${name} on chain ${parameters.chainId}. Call blocks.init first.`,\n );\n }\n\n const row = rows[0]!;\n return {\n collectorName: row.collectorName.toLowerCase() as Collector.Name,\n chainId: row.chainId,\n blockNumber: Number(row.blockNumber),\n epoch: BigInt(row.epoch),\n };\n };\n\n const getChains = async (parameters?: { chainId?: Chain.Id }): Promise<ChainSnapshot[]> => {\n const rows = await db\n .select({\n chainId: chains.chainId,\n blockNumber: chains.blockNumber,\n epoch: chains.epoch,\n updatedAt: chains.updatedAt,\n })\n .from(chains)\n .where(parameters?.chainId !== undefined ? eq(chains.chainId, parameters.chainId) : sql`TRUE`)\n .orderBy(asc(chains.chainId));\n\n return rows.map((row) => ({\n chainId: row.chainId,\n blockNumber: Number(row.blockNumber),\n epoch: BigInt(row.epoch),\n updatedAt: row.updatedAt,\n }));\n };\n\n const getCollectors = async (parameters?: {\n chainId?: Chain.Id;\n }): Promise<CollectorSnapshot[]> => {\n const rows = await db\n .select({\n collectorName: collectors.name,\n chainId: collectors.chainId,\n blockNumber: collectors.blockNumber,\n epoch: collectors.epoch,\n updatedAt: collectors.updatedAt,\n })\n .from(collectors)\n .where(\n parameters?.chainId !== undefined ? eq(collectors.chainId, parameters.chainId) : sql`TRUE`,\n )\n .orderBy(asc(collectors.chainId), asc(collectors.name));\n\n return rows.map((row) => ({\n collectorName: row.collectorName.toLowerCase() as Collector.Name,\n chainId: row.chainId,\n blockNumber: Number(row.blockNumber),\n epoch: BigInt(row.epoch),\n updatedAt: row.updatedAt,\n }));\n };\n\n const init = async (\n parameters: InitParameters,\n ): Promise<{\n chain: ChainState;\n collector: CollectorState;\n }> => {\n const name = parameters.collectorName.toLowerCase() as Collector.Name;\n const deploymentBlock =\n chainRegistry.getById(parameters.chainId)?.custom?.mempool.blockCreated ?? 0;\n\n const { chain, collector } = await db.transaction(async (dbTx) => {\n const chainRows = await dbTx\n .insert(chains)\n .values({\n chainId: parameters.chainId,\n blockNumber: deploymentBlock,\n })\n .onConflictDoUpdate({\n target: chains.chainId,\n set: {\n blockNumber: sql`${chains.blockNumber}`,\n epoch: sql`${chains.epoch}`,\n },\n })\n .returning();\n\n if (chainRows.length === 0) {\n throw new Error(`Failed to initialize chain state for chain ${parameters.chainId}`);\n }\n\n const collectorRows = await dbTx\n .insert(collectors)\n .values({\n chainId: parameters.chainId,\n name,\n blockNumber: deploymentBlock,\n })\n .onConflictDoUpdate({\n target: [collectors.chainId, collectors.name],\n set: {\n blockNumber: sql`${collectors.blockNumber}`,\n epoch: sql`${collectors.epoch}`,\n },\n })\n .returning();\n\n if (collectorRows.length === 0) {\n throw new Error(\n `Failed to initialize collector state for ${name} on chain ${parameters.chainId}`,\n );\n }\n\n const chainRow = chainRows[0]!;\n const collectorRow = collectorRows[0]!;\n\n return {\n chain: {\n chainId: chainRow.chainId,\n blockNumber: Number(chainRow.blockNumber),\n epoch: BigInt(chainRow.epoch),\n },\n collector: {\n collectorName: collectorRow.name.toLowerCase() as Collector.Name,\n chainId: collectorRow.chainId,\n blockNumber: Number(collectorRow.blockNumber),\n epoch: BigInt(collectorRow.epoch),\n },\n };\n });\n\n return { chain, collector };\n };\n\n const advanceChain = async (parameters: AdvanceChainParameters): Promise<void> => {\n if (parameters.blockNumber < 0) throw new Error(\"Block number cannot be negative\");\n if (parameters.epoch < 0n) throw new Error(\"Epoch cannot be negative\");\n const rows = await db\n .update(chains)\n .set({\n blockNumber: parameters.blockNumber,\n epoch: parameters.epoch.toString(),\n updatedAt: sql`now()`,\n })\n .where(eq(chains.chainId, parameters.chainId))\n .returning();\n\n if (rows.length === 0) {\n throw new Error(\n `Chain state not initialized for chain ${parameters.chainId}. Call blocks.init first.`,\n );\n }\n };\n\n const advanceCollector = async (parameters: AdvanceCollectorParameters): Promise<void> => {\n if (parameters.blockNumber < 0) throw new Error(\"Block number cannot be negative\");\n if (parameters.epoch < 0n) throw new Error(\"Epoch cannot be negative\");\n const name = parameters.collectorName.toLowerCase() as Collector.Name;\n\n const chain = db\n .select({\n chainId: chains.chainId,\n currentEpoch: chains.epoch,\n currentBlockNumber: chains.blockNumber,\n })\n .from(chains)\n .where(eq(chains.chainId, parameters.chainId))\n .as(\"chain\");\n\n const hasReorgHappened =\n (\n await db\n .select()\n .from(collectors)\n .leftJoin(chain, eq(collectors.chainId, chain.chainId))\n .where(\n and(\n eq(collectors.chainId, parameters.chainId),\n eq(collectors.name, name),\n gt(chain.currentEpoch, collectors.epoch),\n eq(chain.currentEpoch, parameters.epoch.toString()),\n gte(collectors.blockNumber, parameters.blockNumber),\n ),\n )\n .limit(1)\n ).length > 0;\n\n const rows = await db\n .update(collectors)\n .set({\n blockNumber: parameters.blockNumber,\n epoch: parameters.epoch.toString(),\n updatedAt: sql`now()`,\n })\n .from(chain)\n .where(\n and(\n eq(collectors.chainId, parameters.chainId),\n eq(collectors.name, name),\n eq(chain.currentEpoch, parameters.epoch.toString()),\n gte(chain.currentBlockNumber, parameters.blockNumber),\n // ensures that block numbers are strictly increasing unless a reorg advanced the epoch\n ...(hasReorgHappened ? [] : [lte(collectors.blockNumber, parameters.blockNumber)]),\n ),\n )\n .returning();\n\n if (rows.length > 0) return;\n\n const chainRows = await db\n .select({ chainId: chains.chainId })\n .from(chains)\n .where(eq(chains.chainId, parameters.chainId))\n .limit(1);\n\n if (chainRows.length === 0) {\n throw new Error(\n `Chain state not initialized for chain ${parameters.chainId}. Call blocks.init first.`,\n );\n }\n\n const collectorRows = await db\n .select({ chainId: collectors.chainId })\n .from(collectors)\n .where(and(eq(collectors.chainId, parameters.chainId), eq(collectors.name, name)))\n .limit(1);\n\n if (collectorRows.length === 0) {\n throw new Error(\n `Collector state not initialized for ${name} on chain ${parameters.chainId}. Call blocks.init first.`,\n );\n }\n\n throw new Error(\n `A chain reorg has happened on chain ${parameters.chainId}, update of the collector ${name} is aborted`,\n );\n };\n\n const handleReorg = async (parameters: HandleReorgParameters): Promise<void> => {\n if (parameters.blockNumber < 0) throw new Error(\"Block number cannot be negative\");\n if (parameters.epoch < 0n) throw new Error(\"Epoch cannot be negative\");\n const { chainId, blockNumber, epoch } = parameters;\n const collectorNames = parameters.collectorNames ?? Collector.names;\n\n await advanceChain({ chainId, blockNumber, epoch });\n\n const collectorStates = await Promise.all(\n collectorNames.map(async (collectorName) => {\n const { blockNumber, epoch } = await getCollector({ chainId, collectorName });\n return { collectorName, blockNumber, epoch };\n }),\n );\n\n await Promise.all(\n collectorStates.map(({ collectorName, blockNumber }) =>\n advanceCollector({\n collectorName,\n chainId,\n blockNumber: Math.min(blockNumber, parameters.blockNumber),\n epoch: parameters.epoch,\n }),\n ),\n );\n };\n\n return {\n init,\n getChain,\n getCollector,\n getChains,\n getCollectors,\n advanceChain,\n advanceCollector,\n handleReorg,\n };\n};\n","import { sql } from \"drizzle-orm\";\nimport { type Address, type Hex, isHex } from \"viem\";\nimport { type Chain, Offer } from \"#core\";\nimport type { Database } from \"#database/index.ts\";\nimport { Logger } from \"#logger/index.ts\";\nimport {\n callbacks as callbacksTable,\n groups as groupsTable,\n lots as lotsTable,\n obligationCollateralsV2 as obligationCollateralsTable,\n obligations as obligationsTable,\n offersCallbacks as offersCallbacksTable,\n offers as offersTable,\n offsets as offsetsTable,\n oracles as oraclesTable,\n positions as positionsTable,\n status as statusTable,\n validations as validationsTable,\n} from \"../drizzle/schema.ts\";\nimport type * as OffersDomain from \"./Offers.ts\";\n\nexport type BookDomain = {\n /** Get aggregated book levels for a given obligation side. */\n get: (parameters: get.Parameters) => Promise<get.ReturnType>;\n /** Get all offers for a given obligation side with cross-invalidation. */\n getOffers: (parameters: getOffers.Parameters) => Promise<getOffers.ReturnType>;\n};\n\nexport declare namespace get {\n export type Parameters = {\n /** The side of the offer. */\n side: \"buy\" | \"sell\";\n /** The obligationId of the offer. */\n obligationId: Hex;\n /** Cursor string returned by a previous call, for pagination */\n cursor?: string;\n /** Page size; defaults to {@link DEFAULT_LIMIT} */\n limit?: number;\n };\n\n export type Level = {\n /** The computed price for this level (interpolated at query time) */\n price: bigint;\n /** Sum of takeable amounts at this price */\n assets: bigint;\n /** Number of offers at this price */\n count: number;\n };\n\n export type ReturnType = {\n levels: Level[];\n nextCursor: string | null;\n };\n}\n\nexport declare namespace getOffers {\n export type Parameters = {\n /** The side of the offer. */\n side: \"buy\" | \"sell\";\n /** The obligationId of the offer. */\n obligationId: Hex;\n /** Cursor string returned by a previous call, for pagination */\n cursor?: string;\n /** Page size; defaults to {@link DEFAULT_LIMIT} */\n limit?: number;\n };\n export type ReturnType = {\n rows: OffersDomain.Row[];\n nextCursor: string | null;\n };\n}\n\nconst DEFAULT_LIMIT = 100;\nconst MAX_TOTAL_OFFERS = 500;\n\nexport function create(config: { db: Database.Core }): BookDomain {\n const db = config.db;\n const logger = Logger.getLogger();\n\n const getOffers = async (parameters: getOffers.Parameters): Promise<getOffers.ReturnType> => {\n const { side, obligationId, cursor: cursorString } = parameters;\n const requestedLimit = parameters.limit ?? DEFAULT_LIMIT;\n const priceSortDirection: \"asc\" | \"desc\" = side === \"sell\" ? \"asc\" : \"desc\";\n\n const inputCursor = Cursor.decode(cursorString, logger);\n if (cursorString != null && inputCursor === null) {\n return { rows: [], nextCursor: null };\n }\n if (inputCursor != null && inputCursor.side !== side) {\n throw new Error(\"Cursor does not match the current sort parameters\");\n }\n\n const now = inputCursor?.now ?? Math.floor(Date.now() / 1000);\n\n const previouslyReturned = inputCursor?.totalReturned ?? 0;\n if (previouslyReturned >= MAX_TOTAL_OFFERS) {\n return { rows: [], nextCursor: null };\n }\n\n const effectiveLimit = Math.min(requestedLimit, MAX_TOTAL_OFFERS - previouslyReturned);\n\n const { rows, hasMore } = await _getOffers(db, {\n obligationId,\n side,\n now,\n priceSortDirection,\n cursor: inputCursor,\n limit: effectiveLimit,\n });\n\n const lastReturnedOffer = rows[rows.length - 1];\n const newTotalReturned = previouslyReturned + rows.length;\n const hasHitHardLimit = newTotalReturned >= MAX_TOTAL_OFFERS;\n\n const nextCursor =\n rows.length > 0 && lastReturnedOffer && !hasHitHardLimit && hasMore\n ? Cursor.encode(lastReturnedOffer, newTotalReturned, now, side)\n : null;\n\n return { rows, nextCursor };\n };\n\n return {\n get: async (parameters: get.Parameters): Promise<get.ReturnType> => {\n const { side, obligationId, cursor: cursorString, limit = DEFAULT_LIMIT } = parameters;\n\n const inputCursor = LevelCursor.decode(cursorString, logger);\n if (cursorString != null && inputCursor === null) {\n return { levels: [], nextCursor: null };\n }\n if (inputCursor != null && inputCursor.side !== side) {\n throw new Error(\"Cursor does not match the current sort parameters\");\n }\n\n const now = inputCursor?.now ?? Math.floor(Date.now() / 1000);\n const fetchLimit = limit * 10;\n const { rows, nextCursor: offersNextCursor } = await getOffers({\n side,\n obligationId,\n cursor: inputCursor?.offersCursor ?? undefined,\n limit: fetchLimit,\n });\n\n const priceMap = new Map<string, { assets: bigint; count: number }>();\n for (const row of rows) {\n const priceKey = row.price.toString();\n const existing = priceMap.get(priceKey);\n if (existing) {\n existing.assets += row.takeable;\n existing.count += 1;\n } else {\n priceMap.set(priceKey, { assets: row.takeable, count: 1 });\n }\n }\n\n const levels: get.Level[] = Array.from(priceMap.entries()).map(([price, data]) => ({\n price: BigInt(price),\n assets: data.assets,\n count: data.count,\n }));\n\n const paginatedLevels = levels.slice(0, limit);\n const hasMore = levels.length > limit || offersNextCursor !== null;\n\n const lastLevel = paginatedLevels[paginatedLevels.length - 1];\n const nextCursor =\n hasMore && lastLevel ? LevelCursor.encode(lastLevel, offersNextCursor, side, now) : null;\n\n return { levels: paginatedLevels, nextCursor };\n },\n getOffers,\n };\n}\n\n/** Get offers with computed takeable based on lot balance. */\nasync function _getOffers(\n db: Database.Core,\n params: {\n obligationId: Hex;\n side: \"buy\" | \"sell\";\n now: number;\n priceSortDirection: \"asc\" | \"desc\";\n cursor: Cursor.Cursor | null;\n limit: number;\n },\n): Promise<{ rows: OffersDomain.Row[]; hasMore: boolean }> {\n const { obligationId, side, now, priceSortDirection, cursor, limit } = params;\n\n const raw = await db.execute<{\n hash: Hex;\n group_maker: Address;\n assets: string;\n obligation_units: string | null;\n obligation_shares: string | null;\n consumed: string;\n price: string;\n maturity: number;\n expiry: number;\n start: number;\n group: string;\n buy: boolean;\n chain_id: Chain.Id;\n loan_token: Address;\n callback_address: Address;\n callback_data: Hex;\n block_number: number;\n collaterals: Array<{ asset: Address; oracle: Address; lltv: string }>;\n available: string | number | null;\n takeable: string;\n session: Hex;\n }>(sql`\n WITH collats AS MATERIALIZED (\n SELECT oc.obligation_id,\n COALESCE(jsonb_agg(jsonb_build_object(\n 'asset', oc.asset,\n 'oracle', oracle.address,\n 'lltv', oc.lltv\n ) ORDER BY oc.asset), '[]'::jsonb) AS collaterals\n FROM ${obligationCollateralsTable} oc\n JOIN ${oraclesTable} oracle\n ON oracle.chain_id = oc.oracle_chain_id\n AND oracle.address = oc.oracle_address\n WHERE oc.obligation_id = ${obligationId}\n GROUP BY oc.obligation_id\n ),\n winners AS (\n SELECT DISTINCT ON (o.group_chain_id, o.group_maker, o.\"group_group\")\n o.*\n FROM ${offersTable} o\n LEFT JOIN ${validationsTable} v\n ON v.offer_hash = o.hash\n LEFT JOIN ${statusTable} s\n ON s.id = v.status_id\n WHERE o.obligation_id = ${obligationId}\n AND o.buy = ${side === \"buy\"}\n AND o.expiry > ${now}\n AND o.maturity > ${now}\n AND o.start <= ${now}\n AND (s.code IS NULL OR s.code = ${Offer.Status.VALID})\n ORDER BY\n o.group_chain_id, o.group_maker, o.\"group_group\",\n o.price::numeric ${priceSortDirection === \"asc\" ? sql`ASC` : sql`DESC`}, o.block_number ASC, o.assets DESC, o.hash ASC\n ),\n enriched AS (\n SELECT\n w.*,\n g.consumed, g.chain_id, obl.loan_token,\n CASE WHEN ${priceSortDirection === \"asc\" ? sql`TRUE` : sql`FALSE`}\n THEN w.price::numeric ELSE -w.price::numeric END AS price_norm,\n w.block_number AS block_norm,\n -w.assets AS assets_norm,\n w.hash AS hash_norm\n FROM winners w\n JOIN ${groupsTable} g\n ON g.chain_id = w.group_chain_id\n AND g.maker = w.group_maker\n AND g.\"group\" = w.\"group_group\"\n JOIN ${obligationsTable} obl\n ON obl.obligation_id = w.obligation_id\n ),\n paged AS (\n SELECT e.*\n FROM enriched e\n ${\n cursor != null\n ? sql`\n WHERE\n (e.price_norm, e.block_norm, e.assets_norm, e.hash_norm)\n > (\n CASE WHEN ${priceSortDirection === \"asc\" ? sql`TRUE` : sql`FALSE`}\n THEN ${cursor.price}::numeric ELSE -${cursor.price}::numeric END,\n ${cursor.blockNumber},\n -${cursor.assets}::numeric,\n ${cursor.hash}\n )`\n : sql``\n }\n ORDER BY e.price::numeric ${priceSortDirection === \"asc\" ? sql`ASC` : sql`DESC`}, e.block_number ASC, e.assets DESC, e.hash ASC\n LIMIT ${limit}\n ),\n -- Compute sum of offsets per position\n position_offsets AS (\n SELECT\n chain_id,\n \"user\",\n contract,\n SUM(value::numeric) AS total_offset\n FROM ${offsetsTable}\n GROUP BY chain_id, \"user\", contract\n ),\n -- Compute position_consumed: sum of consumed from all groups with lots on each position (converted to lot terms)\n position_consumed AS (\n SELECT\n l.chain_id,\n l.contract,\n l.\"user\",\n SUM(\n CASE\n WHEN wo.assets::numeric > 0\n THEN COALESCE(g.consumed::numeric, 0) * (l.upper::numeric - l.lower::numeric) / wo.assets::numeric\n ELSE 0\n END\n ) AS consumed\n FROM ${lotsTable} l\n JOIN ${groupsTable} g\n ON g.chain_id = l.chain_id\n AND LOWER(g.maker) = LOWER(l.\"user\")\n AND g.\"group\" = l.\"group\"\n JOIN winners wo\n ON wo.group_chain_id = g.chain_id\n AND LOWER(wo.group_maker) = LOWER(g.maker)\n AND wo.group_group = g.\"group\"\n GROUP BY l.chain_id, l.contract, l.\"user\"\n ),\n -- Compute callback contributions with lot balance\n callback_contributions AS (\n SELECT\n p.hash,\n p.obligation_id,\n p.assets,\n p.price,\n p.obligation_units,\n p.obligation_shares,\n p.maturity,\n p.expiry,\n p.start,\n p.group_group,\n p.buy,\n p.callback_address,\n p.callback_data,\n p.block_number,\n p.group_chain_id,\n p.group_maker,\n p.consumed,\n p.chain_id,\n p.loan_token,\n p.session,\n c.id AS callback_id,\n c.position_chain_id,\n c.position_contract,\n c.position_user,\n c.amount AS callback_amount,\n pos.balance AS position_balance,\n pos.asset AS position_asset,\n l.lower AS lot_lower,\n l.upper AS lot_upper,\n -- Compute lot_balance: min(position_balance + offset + position_consumed - lot.lower, lot.size - lot_consumed)\n -- lot_consumed is converted from loan token to lot terms: consumed * lot_size / assets\n GREATEST(0, LEAST(\n COALESCE(pos.balance::numeric, 0) + COALESCE(pos_offsets.total_offset, 0) + COALESCE(pc.consumed, 0) - COALESCE(l.lower::numeric, 0),\n (COALESCE(l.upper::numeric, 0) - COALESCE(l.lower::numeric, 0)) -\n CASE\n WHEN p.assets::numeric > 0\n THEN COALESCE(p.consumed::numeric, 0) * (COALESCE(l.upper::numeric, 0) - COALESCE(l.lower::numeric, 0)) / p.assets::numeric\n ELSE 0\n END\n )) AS lot_balance\n FROM paged p\n LEFT JOIN ${offersCallbacksTable} oc ON oc.offer_hash = p.hash\n LEFT JOIN ${callbacksTable} c ON c.id = oc.callback_id\n LEFT JOIN ${lotsTable} l\n ON l.chain_id = c.position_chain_id\n AND LOWER(l.contract) = LOWER(c.position_contract)\n AND LOWER(l.\"user\") = LOWER(c.position_user)\n AND l.\"group\" = p.group_group\n LEFT JOIN ${positionsTable} pos\n ON pos.chain_id = c.position_chain_id\n AND LOWER(pos.contract) = LOWER(c.position_contract)\n AND LOWER(pos.\"user\") = LOWER(c.position_user)\n LEFT JOIN position_offsets pos_offsets\n ON pos_offsets.chain_id = c.position_chain_id\n AND LOWER(pos_offsets.contract) = LOWER(c.position_contract)\n AND LOWER(pos_offsets.\"user\") = LOWER(c.position_user)\n LEFT JOIN position_consumed pc\n ON pc.chain_id = c.position_chain_id\n AND LOWER(pc.contract) = LOWER(c.position_contract)\n AND LOWER(pc.\"user\") = LOWER(c.position_user)\n ),\n -- Compute contribution per callback in loan terms (loan token only — collateral positions are not indexed)\n callback_loan_contribution AS (\n SELECT\n cc.*,\n CASE\n WHEN cc.lot_lower IS NULL THEN 0\n ELSE LEAST(cc.lot_balance, COALESCE(cc.callback_amount::numeric, cc.lot_balance))\n END AS contribution_in_loan\n FROM callback_contributions cc\n ),\n -- Aggregate contributions per offer, deduplicating by position using DISTINCT ON\n offer_contributions AS (\n SELECT\n hash,\n obligation_id,\n assets,\n price,\n obligation_units,\n obligation_shares,\n maturity,\n expiry,\n start,\n group_group,\n buy,\n callback_address,\n callback_data,\n block_number,\n group_chain_id,\n group_maker,\n consumed,\n chain_id,\n loan_token,\n session,\n SUM(contribution_in_loan) AS total_available\n FROM (\n -- Take max contribution per position using DISTINCT ON (idiomatic PostgreSQL)\n SELECT DISTINCT ON (clc.hash, clc.position_chain_id, clc.position_contract, clc.position_user)\n clc.*\n FROM callback_loan_contribution clc\n WHERE clc.callback_id IS NOT NULL\n ORDER BY clc.hash, clc.position_chain_id, clc.position_contract, clc.position_user, clc.contribution_in_loan DESC\n ) deduped\n GROUP BY hash, obligation_id, assets, price, obligation_units, obligation_shares, maturity, expiry, start, group_group, buy,\n callback_address, callback_data, block_number, group_chain_id, group_maker,\n consumed, chain_id, loan_token, session\n UNION ALL\n -- Sell offers without callbacks: collateral positions not indexed, takeable = assets - consumed\n SELECT\n p.hash, p.obligation_id, p.assets, p.price,\n p.obligation_units, p.obligation_shares,\n p.maturity, p.expiry, p.start, p.group_group,\n p.buy, p.callback_address, p.callback_data,\n p.block_number, p.group_chain_id, p.group_maker,\n p.consumed, p.chain_id, p.loan_token, p.session,\n 0 AS total_available\n FROM paged p\n WHERE p.buy = false\n AND NOT EXISTS (\n SELECT 1 FROM ${offersCallbacksTable} oc2\n WHERE oc2.offer_hash = p.hash\n )\n )\n -- Final SELECT with inline takeable computation\n SELECT\n oc.hash,\n oc.group_maker,\n oc.assets,\n oc.obligation_units,\n oc.obligation_shares,\n oc.consumed,\n oc.price,\n oc.maturity,\n oc.expiry,\n oc.start,\n oc.group_group AS \"group\",\n oc.buy,\n oc.chain_id,\n oc.loan_token,\n oc.callback_address,\n oc.callback_data,\n oc.block_number,\n oc.session,\n COALESCE(oc.total_available, 0) AS available,\n -- takeable: sell offers use assets - consumed directly (collateral positions not indexed yet)\n CASE WHEN oc.buy = false\n THEN GREATEST(0, oc.assets::numeric - oc.consumed::numeric)\n ELSE GREATEST(0, LEAST(\n oc.assets::numeric - oc.consumed::numeric,\n COALESCE(oc.total_available, 0)\n ))\n END AS takeable,\n c.collaterals\n FROM offer_contributions oc\n LEFT JOIN collats c ON c.obligation_id = oc.obligation_id\n WHERE CASE WHEN oc.buy = false\n THEN GREATEST(0, oc.assets::numeric - oc.consumed::numeric)\n ELSE GREATEST(0, LEAST(\n oc.assets::numeric - oc.consumed::numeric,\n COALESCE(oc.total_available, 0)\n ))\n END > 0\n ORDER BY\n oc.price::numeric ${priceSortDirection === \"asc\" ? sql`ASC` : sql`DESC`},\n oc.block_number ASC,\n oc.assets DESC,\n oc.hash ASC;\n `);\n\n const rows: OffersDomain.Row[] = raw.rows.map((row) => {\n return {\n hash: row.hash,\n maker: row.group_maker,\n assets: BigInt(row.assets),\n obligationUnits: BigInt(row.obligation_units ?? 0),\n obligationShares: BigInt(row.obligation_shares ?? 0),\n price: BigInt(row.price),\n maturity: row.maturity as Offer.OfferInput[\"maturity\"],\n expiry: row.expiry,\n start: row.start,\n group: row.group as Hex,\n buy: row.buy,\n chainId: row.chain_id,\n loanToken: row.loan_token,\n session: row.session as Hex,\n collaterals: row.collaterals.map((c) => ({\n asset: c.asset as Address,\n oracle: c.oracle as Address,\n lltv: BigInt(c.lltv) as Offer.OfferInput[\"collaterals\"][number][\"lltv\"],\n })),\n callback: {\n address: row.callback_address as Address,\n data: row.callback_data as Hex,\n },\n blockNumber: row.block_number,\n consumed: BigInt(row.consumed ?? 0),\n available: BigInt(String(row.available ?? \"0\").split(\".\")[0] ?? \"0\"),\n takeable: BigInt(String(row.takeable).split(\".\")[0] ?? \"0\"),\n };\n });\n\n return { rows, hasMore: raw.rows.length === limit };\n}\n\nexport namespace Cursor {\n export type Cursor = {\n /** The side of offers this cursor was created for */\n side: \"buy\" | \"sell\";\n /** The offer price */\n price: string;\n blockNumber: number;\n assets: string;\n hash: string;\n /** Cumulative count of offers returned across all pages (for hard limit enforcement) */\n totalReturned: number;\n /** Timestamp (seconds) when the first page was requested */\n now: number;\n };\n\n /** Encode an offer into a base64url cursor string. */\n export function encode(\n row: OffersDomain.Row,\n totalReturned: number,\n now: number,\n side: \"buy\" | \"sell\",\n ): string {\n return Buffer.from(\n JSON.stringify({\n side,\n price: row.price.toString(),\n blockNumber: row.blockNumber,\n assets: row.assets.toString(),\n hash: row.hash,\n totalReturned,\n now,\n }),\n ).toString(\"base64url\");\n }\n\n /** Decode a cursor string. Returns null if invalid. */\n export function decode(\n cursorString: string | undefined,\n logger: ReturnType<typeof Logger.getLogger>,\n ): Cursor | null {\n if (cursorString == null) return null;\n\n const isNumericString = (value: unknown): value is string =>\n typeof value === \"string\" && /^-?\\d+$/.test(value);\n\n try {\n const v = JSON.parse(Buffer.from(cursorString, \"base64url\").toString(\"utf8\"));\n if (\n (v?.side === \"buy\" || v?.side === \"sell\") &&\n isNumericString(v?.price) &&\n typeof v?.blockNumber === \"number\" &&\n Number.isInteger(v.blockNumber) &&\n isNumericString(v?.assets) &&\n isHex(v?.hash) &&\n typeof v?.totalReturned === \"number\" &&\n Number.isInteger(v.totalReturned) &&\n typeof v?.now === \"number\" &&\n Number.isInteger(v.now)\n ) {\n return v as Cursor;\n }\n throw new Error(\"Invalid cursor\");\n } catch {\n logger.error({ service: \"book_domain\", msg: \"Invalid cursor\", cursor: cursorString });\n return null;\n }\n }\n}\n\nexport namespace LevelCursor {\n type Cursor = {\n /** The side of offers this cursor was created for */\n side: \"buy\" | \"sell\";\n /** The last price returned */\n lastPrice: string;\n /** Timestamp (seconds) when the first page was requested */\n now: number;\n /** The cursor for the underlying offers query */\n offersCursor: string | null;\n };\n\n /** Encode a book level into a base64url cursor string. */\n export function encode(\n lastLevel: get.Level,\n offersCursor: string | null,\n side: \"buy\" | \"sell\",\n now: number,\n ): string {\n return Buffer.from(\n JSON.stringify({\n side,\n lastPrice: lastLevel.price.toString(),\n now,\n offersCursor,\n }),\n ).toString(\"base64url\");\n }\n\n /** Decode a cursor string. Returns null if invalid. */\n export function decode(\n cursorString: string | undefined,\n logger: ReturnType<typeof Logger.getLogger>,\n ): Cursor | null {\n if (cursorString == null) return null;\n\n const isNumericString = (value: unknown): value is string =>\n typeof value === \"string\" && /^-?\\d+$/.test(value);\n\n try {\n const v = JSON.parse(Buffer.from(cursorString, \"base64url\").toString(\"utf8\"));\n if (\n (v?.side === \"buy\" || v?.side === \"sell\") &&\n isNumericString(v?.lastPrice) &&\n typeof v?.now === \"number\" &&\n Number.isInteger(v.now) &&\n (v?.offersCursor === null || typeof v?.offersCursor === \"string\")\n ) {\n return v as Cursor;\n }\n throw new Error(\"Invalid book cursor\");\n } catch {\n logger.error({ service: \"book_domain\", msg: \"Invalid book cursor\", cursor: cursorString });\n return null;\n }\n }\n}\n","import { inArray } from \"drizzle-orm\";\nimport { type Address, type Hex, keccak256 } from \"viem\";\nimport type * as Chain from \"#core/Chain.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\nimport {\n callbacks as callbacksTable,\n offersCallbacks as offersCallbacksTable,\n} from \"../drizzle/schema.ts\";\n\nexport type CallbackInput = {\n chainId: Chain.Id;\n contract: Address;\n user: Address;\n amount: bigint;\n};\n\nexport type OfferCallbacks = {\n offerHash: Hex;\n callbacks: CallbackInput[];\n};\n\nexport type CallbacksDomain = {\n /**\n * Upsert callbacks and their offer associations.\n * @param inputs - Callback associations grouped by offer hash. {@link OfferCallbacks}\n */\n upsert: (inputs: OfferCallbacks[]) => Promise<void>;\n\n /**\n * Delete callback associations by offer hashes.\n * @param parameters - Offer hashes to delete. {@link DeleteParameters}\n * @returns Number of rows deleted. {@link DeleteReturnType}\n */\n delete: (parameters: DeleteParameters) => Promise<DeleteReturnType>;\n};\n\nexport type DeleteParameters = { offers: Hex[] };\nexport type DeleteReturnType = number;\n\n/**\n * Create a callbacks domain instance.\n * @param db - Database core instance.\n * @returns Callbacks domain. {@link CallbacksDomain}\n */\nexport function create(db: Database.Core): CallbacksDomain {\n return {\n upsert: async (inputs: OfferCallbacks[]): Promise<void> => {\n if (inputs.length === 0) return;\n\n const idCache = new Map<string, string>();\n const seenCallbackIds = new Set<string>();\n const callbacksRows: Array<{\n id: string;\n positionChainId: Chain.Id;\n positionContract: Address;\n positionUser: Address;\n amount: string;\n }> = [];\n const offersCallbacksRows: Array<{ offerHash: Hex; callbackId: string }> = [];\n\n const callbackId = (input: CallbackInput): string => {\n const preimage =\n `0x${input.chainId}${input.contract}${input.user}${input.amount.toString()}`.toLowerCase() as `0x${string}`;\n const id = idCache.get(preimage) ?? keccak256(preimage);\n idCache.set(preimage, id);\n return id;\n };\n\n for (const { offerHash, callbacks } of inputs) {\n const normalizedOfferHash = offerHash.toLowerCase() as Hex;\n for (const callback of callbacks) {\n const normalized: CallbackInput = {\n chainId: callback.chainId,\n contract: callback.contract.toLowerCase() as Address,\n user: callback.user.toLowerCase() as Address,\n amount: callback.amount,\n };\n\n const id = callbackId(normalized);\n offersCallbacksRows.push({\n offerHash: normalizedOfferHash,\n callbackId: id,\n });\n\n if (seenCallbackIds.has(id)) continue;\n seenCallbackIds.add(id);\n callbacksRows.push({\n id,\n positionChainId: normalized.chainId,\n positionContract: normalized.contract,\n positionUser: normalized.user,\n amount: normalized.amount.toString(),\n });\n }\n }\n\n if (offersCallbacksRows.length === 0) return;\n\n await db.transaction(async (dbTx) => {\n for (const batch of Utils.batch(callbacksRows, DEFAULT_BATCH_SIZE)) {\n await dbTx.insert(callbacksTable).values(batch).onConflictDoNothing();\n }\n\n for (const batch of Utils.batch(offersCallbacksRows, DEFAULT_BATCH_SIZE)) {\n await dbTx.insert(offersCallbacksTable).values(batch).onConflictDoNothing();\n }\n });\n },\n\n delete: async ({ offers }: DeleteParameters): Promise<DeleteReturnType> => {\n if (offers.length === 0) return 0;\n const normalized = offers.map((offer) => offer.toLowerCase() as Hex);\n const result = await db\n .delete(offersCallbacksTable)\n .where(inArray(offersCallbacksTable.offerHash, normalized));\n return (result as { affectedRows: number }).affectedRows;\n },\n };\n}\n","import { sql } from \"drizzle-orm\";\nimport type { Address, Hex } from \"viem\";\nimport type { Chain } from \"#core\";\nimport * as Utils from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\nimport type * as Database from \"../Database.ts\";\nimport { consumedEvents as consumedEventsTable, groups as groupsTable } from \"../drizzle/schema.ts\";\n\nexport type Event = {\n id: string;\n chainId: Chain.Id;\n maker: Address;\n group: Hex;\n amount: bigint;\n blockNumber: number;\n};\n\nexport type Group = {\n chainId: Chain.Id;\n maker: Address;\n group: Hex;\n blockNumber: number;\n};\n\nexport type ConsumedDomain = {\n /** Create new consumed events. */\n create: (parameters: Event[]) => Promise<void>;\n\n /** Delete multiple consumed events by chain and block number greater than or equal to the given value. */\n delete: (parameters: { chainId: Chain.Id; blockNumberGte: number }) => Promise<number>;\n};\n\nexport function create(db: Database.Core): ConsumedDomain {\n return {\n create: async (events: Event[]): Promise<void> => {\n if (events.length === 0) return;\n\n const groups: Map<string, Group> = new Map();\n for (const event of events) {\n const groupId = `${event.chainId}-${event.maker}-${event.group}`.toLowerCase();\n groups.set(groupId, {\n chainId: event.chainId,\n maker: event.maker,\n group: event.group,\n blockNumber: event.blockNumber,\n });\n }\n\n await db.transaction(async (dbTx) => {\n const groupsRows = Array.from(groups.values()).map((group) => ({\n chainId: group.chainId,\n maker: group.maker.toLowerCase(),\n group: group.group.toLowerCase(),\n consumed: \"0\",\n blockNumber: group.blockNumber,\n }));\n for (const batch of Utils.batch(groupsRows, DEFAULT_BATCH_SIZE)) {\n await dbTx.insert(groupsTable).values(batch).onConflictDoNothing();\n }\n\n const eventsRows = events.map((event) => ({\n eventId: event.id,\n chainId: event.chainId,\n maker: event.maker.toLowerCase(),\n group: event.group.toLowerCase(),\n amount: event.amount.toString(),\n blockNumber: event.blockNumber,\n }));\n for (const batch of Utils.batch(eventsRows, DEFAULT_BATCH_SIZE)) {\n await dbTx.insert(consumedEventsTable).values(batch).onConflictDoNothing();\n }\n });\n },\n\n delete: async (parameters: { chainId: Chain.Id; blockNumberGte: number }): Promise<number> => {\n const { chainId, blockNumberGte } = parameters;\n const result = await db\n .delete(consumedEventsTable)\n .where(\n sql`${consumedEventsTable.blockNumber} >= ${blockNumberGte} AND ${consumedEventsTable.chainId} = ${chainId}`,\n );\n return (result as { affectedRows: number }).affectedRows;\n },\n };\n}\n","import type { Address, Hex } from \"viem\";\nimport type * as Chain from \"#core/Chain.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\nimport { groups as groupsTable } from \"../drizzle/schema.ts\";\n\nexport type GroupInput = {\n chainId: Chain.Id;\n maker: Address;\n group: Hex;\n blockNumber: number;\n consumed?: bigint;\n};\n\nexport type GroupsDomain = {\n /**\n * Insert groups (insert-only).\n * @param groups - Groups to insert. {@link GroupInput}\n */\n create: (groups: GroupInput[]) => Promise<void>;\n};\n\n/**\n * Create a groups domain instance.\n * @param db - Database core instance.\n * @returns Groups domain. {@link GroupsDomain}\n */\nexport function create(db: Database.Core): GroupsDomain {\n return {\n create: async (groups) => {\n if (groups.length === 0) return;\n\n const rows = groups.map((group) => ({\n chainId: group.chainId,\n maker: group.maker.toLowerCase(),\n group: group.group.toLowerCase(),\n consumed: (group.consumed ?? 0n).toString(),\n blockNumber: group.blockNumber,\n }));\n\n for (const batch of Utils.batch(rows, DEFAULT_BATCH_SIZE)) {\n await db.insert(groupsTable).values(batch).onConflictDoNothing();\n }\n },\n };\n}\n","import { and, eq, sql } from \"drizzle-orm\";\nimport type { Address } from \"viem\";\nimport type { Chain } from \"#core\";\nimport type * as Database from \"../Database.ts\";\nimport { lots as lotsTable } from \"../drizzle/schema.ts\";\n\nexport type Lot = {\n chainId: Chain.Id;\n user: Address;\n contract: Address;\n group: string;\n lower: bigint;\n upper: bigint;\n};\n\nexport type LotsDomain = {\n /**\n * Create or update lots for offers.\n * Called when offers are created to reserve liquidity on positions.\n * For each (position, group), keeps only the biggest offer by assets.\n * If lot exists and new offer is bigger, grows the lot and shifts higher lots.\n */\n create: (parameters: create.Parameters) => Promise<void>;\n\n /**\n * Get lots with optional filtering.\n */\n get: (parameters?: get.Parameters) => Promise<Lot[]>;\n};\n\nexport declare namespace create {\n export type OfferLotInfo = {\n positionChainId: Chain.Id;\n positionContract: Address;\n positionUser: Address;\n group: string;\n size: bigint;\n };\n export type Parameters = OfferLotInfo[];\n export type ReturnType = undefined;\n}\n\nexport declare namespace get {\n export type Parameters = {\n chainId?: Chain.Id;\n user?: Address;\n contract?: Address;\n group?: string;\n };\n export type ReturnType = Lot[];\n}\n\nexport function create(db: Database.Core): LotsDomain {\n return {\n get: async (parameters?: get.Parameters): Promise<Lot[]> => {\n const { chainId, user, contract, group } = parameters ?? {};\n\n const conditions = [];\n if (chainId !== undefined) conditions.push(eq(lotsTable.chainId, chainId));\n if (user !== undefined) conditions.push(eq(lotsTable.user, user.toLowerCase()));\n if (contract !== undefined) conditions.push(eq(lotsTable.contract, contract.toLowerCase()));\n if (group !== undefined) conditions.push(eq(lotsTable.group, group));\n\n const rows = await db\n .select()\n .from(lotsTable)\n .where(conditions.length > 0 ? and(...conditions) : undefined);\n\n return rows.map((row) => ({\n chainId: row.chainId,\n user: row.user as Address,\n contract: row.contract as Address,\n group: row.group,\n lower: BigInt(row.lower),\n upper: BigInt(row.upper),\n }));\n },\n\n create: async (parameters: create.Parameters): Promise<void> => {\n if (parameters.length === 0) return;\n\n const lotsByPositionGroup = new Map<string, create.OfferLotInfo>();\n\n for (const offer of parameters) {\n const key =\n `${offer.positionChainId}-${offer.positionContract}-${offer.positionUser}-${offer.group}`.toLowerCase();\n const existing = lotsByPositionGroup.get(key);\n\n if (!existing || offer.size > existing.size) {\n lotsByPositionGroup.set(key, offer);\n }\n }\n\n for (const offer of lotsByPositionGroup.values()) {\n const existingLot = await db\n .select()\n .from(lotsTable)\n .where(\n and(\n eq(lotsTable.chainId, offer.positionChainId),\n eq(lotsTable.contract, offer.positionContract.toLowerCase()),\n eq(lotsTable.user, offer.positionUser.toLowerCase()),\n eq(lotsTable.group, offer.group.toLowerCase()),\n ),\n )\n .limit(1);\n\n if (existingLot.length === 0) {\n // No existing lot - create new one\n // Find the highest upper bound on this position\n const maxUpperResult = await db\n .select({ maxUpper: sql<string>`COALESCE(MAX(${lotsTable.upper}::numeric), 0)` })\n .from(lotsTable)\n .where(\n and(\n eq(lotsTable.chainId, offer.positionChainId),\n eq(lotsTable.contract, offer.positionContract.toLowerCase()),\n eq(lotsTable.user, offer.positionUser.toLowerCase()),\n ),\n );\n\n const maxUpper = BigInt(maxUpperResult[0]?.maxUpper ?? \"0\");\n const newLower = maxUpper;\n const newUpper = newLower + offer.size;\n\n await db.insert(lotsTable).values({\n chainId: offer.positionChainId,\n user: offer.positionUser.toLowerCase(),\n contract: offer.positionContract.toLowerCase(),\n group: offer.group.toLowerCase(),\n lower: newLower.toString(),\n upper: newUpper.toString(),\n });\n }\n // Existing lot - lots are immutable, no updates allowed\n }\n },\n };\n}\n","import { Obligation } from \"#core\";\nimport type { Database } from \"#database/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\nimport {\n obligationCollateralsV2 as obligationCollateralsTable,\n obligations as obligationsTable,\n} from \"../drizzle/schema.ts\";\n\nexport type ObligationsDomain = {\n /**\n * Insert obligations (insert-only).\n * @param obligations - Obligations to insert. {@link Obligation.Obligation}\n */\n create: (obligations: Obligation.Obligation[]) => Promise<void>;\n};\n\n/**\n * Create an obligations domain instance.\n * @param db - Database core instance.\n * @returns Obligations domain. {@link ObligationsDomain}\n */\nexport function create(db: Database.Core): ObligationsDomain {\n return {\n create: async (obligations) => {\n if (obligations.length === 0) return;\n\n const obligationsById = new Map<string, Obligation.Obligation>();\n for (const obligation of obligations) {\n const id = Obligation.id(obligation).toLowerCase();\n const existing = obligationsById.get(id);\n if (!existing) obligationsById.set(id, obligation);\n }\n\n try {\n await db.transaction(async (dbTx) => {\n const obligationRows = obligations.map((obligation) => ({\n obligationId: Obligation.id(obligation),\n chainId: obligation.chainId,\n loanToken: obligation.loanToken.toLowerCase(),\n maturity: obligation.maturity,\n }));\n\n for (const batch of Utils.batch(obligationRows, DEFAULT_BATCH_SIZE)) {\n await dbTx.insert(obligationsTable).values(batch).onConflictDoNothing();\n }\n\n const collateralRows = obligations.flatMap((obligation) => {\n return obligation.collaterals.map((collateral) => ({\n obligationId: Obligation.id(obligation),\n asset: collateral.asset.toLowerCase(),\n oracleChainId: obligation.chainId,\n oracleAddress: collateral.oracle.toLowerCase(),\n lltv: collateral.lltv,\n }));\n });\n\n for (const batch of Utils.batch(collateralRows, DEFAULT_BATCH_SIZE)) {\n await dbTx.insert(obligationCollateralsTable).values(batch).onConflictDoNothing();\n }\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n throw new Error(\n \"Obligations.create failed. Ensure oracles exist before inserting obligations.\",\n { cause: error },\n );\n }\n },\n };\n}\n","import { and, eq } from \"drizzle-orm\";\nimport type { Address } from \"viem\";\nimport type { Chain } from \"#core\";\nimport type * as Database from \"../Database.ts\";\nimport { offsets as offsetsTable } from \"../drizzle/schema.ts\";\n\nexport type Offset = {\n chainId: Chain.Id;\n user: Address;\n contract: Address;\n group: string;\n value: bigint;\n};\n\nexport type OffsetsDomain = {\n /**\n * Get offsets with optional filtering.\n */\n get: (parameters?: get.Parameters) => Promise<Offset[]>;\n};\n\nexport declare namespace get {\n export type Parameters = {\n chainId?: Chain.Id;\n user?: Address;\n contract?: Address;\n group?: string;\n };\n export type ReturnType = Offset[];\n}\n\nexport function create(db: Database.Core): OffsetsDomain {\n return {\n get: async (parameters?: get.Parameters): Promise<Offset[]> => {\n const { chainId, user, contract, group } = parameters ?? {};\n\n const conditions = [];\n if (chainId !== undefined) conditions.push(eq(offsetsTable.chainId, chainId));\n if (user !== undefined) conditions.push(eq(offsetsTable.user, user.toLowerCase()));\n if (contract !== undefined)\n conditions.push(eq(offsetsTable.contract, contract.toLowerCase()));\n if (group !== undefined) conditions.push(eq(offsetsTable.group, group));\n\n const rows = await db\n .select()\n .from(offsetsTable)\n .where(conditions.length > 0 ? and(...conditions) : undefined);\n\n return rows.map((row) => ({\n chainId: row.chainId,\n user: row.user as Address,\n contract: row.contract as Address,\n group: row.group,\n value: BigInt(row.value),\n }));\n },\n };\n}\n","import { eq, sql } from \"drizzle-orm\";\nimport type { Address } from \"viem\";\nimport { type Chain, Oracle } from \"#core\";\nimport * as Utils from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\nimport type * as Database from \"../Database.ts\";\nimport { oracles as oraclesTable } from \"../drizzle/schema.ts\";\n\nexport type OraclesDomain = {\n /**\n * Get all oracles for a specific chain.\n * @returns An array of oracles with their current state.\n */\n get: (parameters: { chainId: Chain.Id }) => Promise<Oracle.Oracle[]>;\n\n /**\n * Upsert oracles\n *\n * @param oracles - Array of oracles to upsert\n */\n upsert: (oracles: Oracle.Oracle[]) => Promise<void>;\n};\n\nexport function create(db: Database.Core): OraclesDomain {\n return {\n get: async ({ chainId }: { chainId: Chain.Id }): Promise<Oracle.Oracle[]> => {\n const result = await db\n .select({\n address: oraclesTable.address,\n price: oraclesTable.price,\n blockNumber: oraclesTable.blockNumber,\n chainId: oraclesTable.chainId,\n })\n .from(oraclesTable)\n .where(eq(oraclesTable.chainId, chainId));\n\n return result.map((r) =>\n Oracle.from({\n chainId: r.chainId,\n address: r.address as Address,\n price: r.price,\n blockNumber: r.blockNumber,\n }),\n );\n },\n\n upsert: async (oracles: Oracle.Oracle[]): Promise<void> => {\n if (oracles.length === 0) return;\n\n const rows = oracles.map((o) => ({\n chainId: o.chainId,\n address: o.address.toLowerCase(),\n price: o.price !== null ? o.price.toString() : null,\n blockNumber: o.blockNumber,\n }));\n\n await db.transaction(async (dbTx) => {\n for (const batch of Utils.batch(rows, DEFAULT_BATCH_SIZE)) {\n await dbTx\n .insert(oraclesTable)\n .values(batch)\n .onConflictDoUpdate({\n target: [oraclesTable.chainId, oraclesTable.address],\n set: {\n price: sql`COALESCE(EXCLUDED.price, ${oraclesTable.price})`,\n blockNumber: sql`CASE\n WHEN EXCLUDED.price IS NULL THEN ${oraclesTable.blockNumber}\n ELSE EXCLUDED.block_number\n END`,\n updatedAt: sql`NOW()`,\n },\n });\n }\n });\n },\n };\n}\n","import { and, asc, eq, ne, sql } from \"drizzle-orm\";\nimport { type Address, zeroAddress } from \"viem\";\nimport { type Chain, Position } from \"#core/index.ts\";\nimport {\n groups as groupsTable,\n lots as lotsTable,\n offers as offersTable,\n offsets as offsetsTable,\n positions as positionsTable,\n transfers as transfersTable,\n} from \"#database/drizzle/schema.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\n\nexport const DEFAULT_LIMIT = 100;\nexport type PaginationParams = {\n /** Cursor string returned by a previous call, for pagination */\n cursor?: string;\n /** Page size; defaults to {@link DEFAULT_LIMIT} */\n limit?: number;\n};\n\nexport type PositionsDomain = {\n /**\n * Upsert positions.\n * @notice A position can only be updated if its balance is `null` and the block number is greater than the previous position snapshot.\n * Once a position has a non `null` balance, transfers are the only way to update the balance.\n *\n * @param positions - {@link upsert.Parameters}\n * @returns The number of positions upserted. {@link upsert.ReturnType}\n */\n upsert(positions: upsert.Parameters): Promise<upsert.ReturnType>;\n\n /**\n * Returns positions.\n * @param parameters - {@link get.Parameters}\n * @returns The positions. {@link get.ReturnType}\n */\n get: (parameters?: get.Parameters) => Promise<get.ReturnType>;\n\n /**\n * Returns positions for a specific user with remaining balance calculation.\n * @param parameters - {@link getByUser.Parameters}\n * @returns The user's positions with remaining balances. {@link getByUser.ReturnType}\n */\n getByUser: (parameters: getByUser.Parameters) => Promise<getByUser.ReturnType>;\n\n /**\n * Set all positions to empty after a given block number (inclusive), deletes all transfers linked to the positions.\n * @param parameters - {@link setEmptyAfter.Parameters}\n * @returns The number of positions set to empty. {@link setEmptyAfter.ReturnType}\n */\n setEmptyAfter(parameters: setEmptyAfter.Parameters): Promise<setEmptyAfter.ReturnType>;\n};\n\nexport declare namespace upsert {\n export type Parameters = Position.Position[];\n export type ReturnType = number;\n}\n\nexport declare namespace get {\n type Parameters = PaginationParams & {\n /** The chain id to get positions for. Default is all chains. */\n chainId?: Chain.Id;\n /** The type of position to get. Default is all types. */\n type?: Position.Type;\n /** If true, only return positions that have a balance. */\n filled?: boolean;\n };\n\n type ReturnType = { positions: Position.Position[]; nextCursor: string | null };\n}\n\nexport declare namespace getByUser {\n type Parameters = PaginationParams & {\n /** The user address to get positions for. */\n user: Address;\n };\n\n type PositionWithReserved = {\n chainId: Chain.Id;\n contract: Address;\n user: Address;\n blockNumber: number;\n /** The amount reserved by active offers: max(lot.upper) - offset - consumed */\n reserved: bigint;\n };\n\n type ReturnType = { positions: PositionWithReserved[]; nextCursor: string | null };\n}\n\nexport declare namespace setEmptyAfter {\n type Parameters = {\n /** The chain id . */\n chainId: Chain.Id;\n /** The block number after which all positions should be set to empty. (inclusive) */\n blockNumber: number;\n };\n\n type ReturnType = number;\n}\n\nexport const create = (db: Database.Core): PositionsDomain => {\n return {\n upsert: async (positions) => {\n const positionsMap = new Map<string, Position.Position>();\n for (const p of positions) {\n const key = `${p.chainId}-${p.contract}-${p.user}`.toLowerCase();\n const zeroKey = `${p.chainId}-${p.contract}-${zeroAddress}`.toLowerCase();\n if (!positionsMap.has(zeroKey)) {\n positionsMap.set(zeroKey, {\n chainId: p.chainId,\n contract: p.contract,\n user: zeroAddress,\n balance: 0n,\n type: p.type,\n blockNumber: p.blockNumber,\n });\n }\n\n if (!positionsMap.has(key)) {\n positionsMap.set(key, p);\n continue;\n }\n\n if (p.blockNumber > positionsMap.get(key)!.blockNumber) positionsMap.set(key, p);\n }\n\n if (positionsMap.size === 0) return 0;\n\n const rows = Array.from(positionsMap.values()).map((p) => {\n const positionTypeId = Object.values(Position.Type).indexOf(p.type) + 1;\n return {\n chainId: p.chainId,\n contract: p.contract.toLowerCase(),\n user: p.user.toLowerCase(),\n positionTypeId,\n ...(p.balance !== undefined ? { balance: p.balance.toString() } : {}),\n ...(p.asset !== undefined ? { asset: p.asset.toLowerCase() } : {}),\n blockNumber: p.blockNumber,\n };\n });\n\n let totalUpdated = 0;\n for (const batch of Utils.batch(rows, DEFAULT_BATCH_SIZE)) {\n const updated = await db\n .insert(positionsTable)\n .values(batch)\n .onConflictDoUpdate({\n target: [positionsTable.chainId, positionsTable.contract, positionsTable.user],\n set: {\n balance: sql`EXCLUDED.balance`,\n asset: sql`COALESCE(EXCLUDED.asset, ${positionsTable.asset})`,\n blockNumber: sql`EXCLUDED.block_number`,\n updatedAt: sql`NOW()`,\n },\n where: sql`${positionsTable.blockNumber} < EXCLUDED.block_number AND ${positionsTable.balance} IS NULL`,\n })\n .returning();\n totalUpdated += updated.length;\n }\n\n return totalUpdated;\n },\n\n get: async (parameters) => {\n const {\n limit = DEFAULT_LIMIT,\n cursor: encodedCursor,\n chainId,\n type,\n filled,\n } = parameters ?? {};\n\n let cursor: { chainId: Chain.Id; contract: string; user: string } | null = null;\n if (encodedCursor !== null && encodedCursor !== undefined) {\n const parsed = JSON.parse(Buffer.from(encodedCursor, \"base64url\").toString(\"utf8\"));\n if (!parsed.chainId || !parsed.contract || !parsed.user) {\n throw new Error(\"Invalid cursor format\");\n }\n cursor = {\n chainId: parsed.chainId as Chain.Id,\n contract: parsed.contract,\n user: parsed.user,\n };\n }\n\n const positions = await db\n .select()\n .from(positionsTable)\n .where(\n and(\n ne(positionsTable.user, zeroAddress),\n filled === undefined\n ? sql`true`\n : sql`${positionsTable.balance} IS ${filled === true ? sql`NOT` : sql``} NULL`,\n type !== undefined\n ? eq(positionsTable.positionTypeId, Object.values(Position.Type).indexOf(type) + 1)\n : sql`true`,\n chainId !== undefined ? eq(positionsTable.chainId, chainId) : sql`true`,\n (() => {\n if (cursor === null || cursor === undefined) return sql`true`;\n // dont include chainId comparison if chainId is defined in the parameters\n // filtering is already done above\n return sql`\n (${chainId === undefined ? sql`\"chain_id\", ` : sql``}\"contract\", \"user\") > (${chainId === undefined ? sql`${cursor.chainId}, ` : sql``}${cursor.contract}, ${cursor.user})\n `;\n })(),\n ),\n )\n .orderBy(\n asc(positionsTable.chainId),\n asc(positionsTable.contract),\n asc(positionsTable.user),\n asc(positionsTable.blockNumber),\n )\n .limit(limit);\n\n const nextCursor =\n positions.length === limit\n ? Buffer.from(\n JSON.stringify({\n chainId: positions[positions.length - 1]!.chainId.toString(),\n contract: positions[positions.length - 1]!.contract,\n user: positions[positions.length - 1]!.user,\n blockNumber: positions[positions.length - 1]!.blockNumber.toString(),\n }),\n ).toString(\"base64url\")\n : null;\n\n return {\n positions: positions.map((p) => ({\n chainId: p.chainId,\n contract: p.contract as Address,\n user: p.user as Address,\n type: Object.values(Position.Type)[p.positionTypeId - 1] as Position.Type,\n balance: p.balance !== null ? BigInt(p.balance) : undefined,\n ...(p.asset !== null ? { asset: p.asset as Address } : {}),\n blockNumber: p.blockNumber,\n })),\n nextCursor,\n };\n },\n\n getByUser: async (parameters) => {\n const { user, limit = DEFAULT_LIMIT, cursor: encodedCursor } = parameters;\n\n let cursor: { chainId: Chain.Id; contract: string } | null = null;\n if (encodedCursor !== null && encodedCursor !== undefined) {\n const parsed = JSON.parse(Buffer.from(encodedCursor, \"base64url\").toString(\"utf8\"));\n if (!parsed.chainId || !parsed.contract) {\n throw new Error(\"Invalid cursor format\");\n }\n cursor = {\n chainId: parsed.chainId as Chain.Id,\n contract: parsed.contract,\n };\n }\n\n const raw = await db.execute<{\n chain_id: Chain.Id;\n contract: string;\n user: string;\n block_number: number;\n reserved_balance: string;\n }>(sql`\n WITH position_offsets AS (\n SELECT\n chain_id,\n \"user\",\n contract,\n SUM(value::numeric) AS total_offset\n FROM ${offsetsTable}\n WHERE LOWER(\"user\") = LOWER(${user})\n GROUP BY chain_id, \"user\", contract\n ),\n position_consumed AS (\n SELECT\n l.chain_id,\n l.contract,\n l.\"user\",\n SUM(\n CASE\n WHEN offer_agg.assets > 0\n THEN COALESCE(g.consumed::numeric, 0) * (l.upper::numeric - l.lower::numeric) / offer_agg.assets\n ELSE 0\n END\n ) AS consumed\n FROM ${lotsTable} l\n JOIN ${groupsTable} g\n ON g.chain_id = l.chain_id\n AND LOWER(g.maker) = LOWER(l.\"user\")\n AND g.\"group\" = l.\"group\"\n JOIN (\n SELECT\n group_chain_id,\n group_maker,\n \"group_group\",\n MAX(assets::numeric) AS assets\n FROM ${offersTable}\n GROUP BY group_chain_id, group_maker, \"group_group\"\n ) offer_agg\n ON offer_agg.group_chain_id = g.chain_id\n AND LOWER(offer_agg.group_maker) = LOWER(g.maker)\n AND offer_agg.\"group_group\" = g.\"group\"\n WHERE LOWER(l.\"user\") = LOWER(${user})\n GROUP BY l.chain_id, l.contract, l.\"user\"\n ),\n position_max_lot AS (\n SELECT\n chain_id,\n contract,\n \"user\",\n MAX(upper::numeric) AS max_upper\n FROM ${lotsTable}\n WHERE LOWER(\"user\") = LOWER(${user})\n GROUP BY chain_id, contract, \"user\"\n )\n SELECT\n p.chain_id,\n p.contract,\n p.\"user\",\n p.block_number,\n GREATEST(0,\n COALESCE(pml.max_upper, 0)\n - COALESCE(po.total_offset, 0)\n - COALESCE(pc.consumed, 0)\n )::text AS reserved_balance\n FROM ${positionsTable} p\n LEFT JOIN position_offsets po\n ON po.chain_id = p.chain_id\n AND LOWER(po.contract) = LOWER(p.contract)\n AND LOWER(po.\"user\") = LOWER(p.\"user\")\n LEFT JOIN position_consumed pc\n ON pc.chain_id = p.chain_id\n AND LOWER(pc.contract) = LOWER(p.contract)\n AND LOWER(pc.\"user\") = LOWER(p.\"user\")\n LEFT JOIN position_max_lot pml\n ON pml.chain_id = p.chain_id\n AND LOWER(pml.contract) = LOWER(p.contract)\n AND LOWER(pml.\"user\") = LOWER(p.\"user\")\n WHERE LOWER(p.\"user\") = LOWER(${user})\n AND p.\"user\" != ${zeroAddress}\n ${cursor !== null ? sql`AND (p.chain_id, p.contract) > (${cursor.chainId}, ${cursor.contract})` : sql``}\n ORDER BY p.chain_id ASC, p.contract ASC\n LIMIT ${limit}\n `);\n\n const nextCursor =\n raw.rows.length === limit\n ? Buffer.from(\n JSON.stringify({\n chainId: raw.rows[raw.rows.length - 1]!.chain_id.toString(),\n contract: raw.rows[raw.rows.length - 1]!.contract,\n }),\n ).toString(\"base64url\")\n : null;\n\n return {\n positions: raw.rows.map((row) => ({\n chainId: row.chain_id,\n contract: row.contract as Address,\n user: row.user as Address,\n blockNumber: row.block_number,\n reserved: BigInt(row.reserved_balance.split(\".\")[0] ?? \"0\"),\n })),\n nextCursor,\n };\n },\n\n setEmptyAfter: async (parameters) => {\n const { chainId, blockNumber } = parameters;\n\n const affected = await db.transaction(async (tx) => {\n const updatedPositions = await tx\n .update(positionsTable)\n .set({\n balance: null,\n blockNumber,\n updatedAt: sql`NOW()`,\n })\n .where(\n and(\n eq(positionsTable.chainId, chainId),\n sql`${positionsTable.blockNumber} >= ${blockNumber}`,\n ),\n )\n .returning();\n\n if (updatedPositions.length === 0) return 0;\n\n await tx.execute(sql`\n DELETE FROM ${transfersTable} t\n USING (VALUES ${sql.join(\n updatedPositions.map(\n (u) =>\n sql`(${u.chainId}::bigint, ${u.contract}::varchar(42), ${u.user}::varchar(42))`,\n ),\n sql`,`,\n )}) AS s(chain_id, \"contract\", \"user\")\n WHERE\n t.chain_id = s.chain_id\n AND t.\"contract\" = s.\"contract\"\n AND (t.\"from\" = s.\"user\" OR t.\"to\" = s.\"user\")\n `);\n\n return updatedPositions.length;\n });\n\n return affected;\n },\n };\n};\n","import { sql } from \"drizzle-orm\";\nimport type { Transfer } from \"#core/index.ts\";\nimport {\n positions as positionsTable,\n transfers as transfersTable,\n} from \"#database/drizzle/schema.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\n\nexport type TransfersDomain = {\n /**\n * Inserts transfers and updates positions balances with `blockNumber` less than or equal to transfers `blockNumber`.\n * @param transfers - {@link create.Parameters}\n * @returns The number of transfers created. {@link create.ReturnType}\n */\n create: (transfers: create.Parameters) => Promise<create.ReturnType>;\n};\n\nexport declare namespace create {\n export type Parameters = Transfer.Transfer[];\n export type ReturnType = number;\n}\n\nexport const create = (db: Database.Core): TransfersDomain => ({\n create: async (transfers) => {\n if (transfers.length === 0) return 0;\n\n const created = await db.transaction(async (dbTx) => {\n let totalInserted = 0;\n\n for (const transfersBatch of Utils.batch(transfers, DEFAULT_BATCH_SIZE)) {\n const { rows: inserted } = await dbTx.execute<{\n event_id: string;\n chain_id: bigint;\n contract: string;\n from: string;\n to: string;\n value: string;\n block_number: number;\n }>(sql`\n INSERT INTO ${transfersTable} (event_id, chain_id, \"contract\", \"from\", \"to\", \"value\", block_number)\n SELECT * FROM (VALUES ${sql.join(\n transfersBatch.map(\n (transfer) =>\n sql`(${transfer.id}::varchar(128), ${transfer.chainId}::bigint, ${transfer.contract.toLowerCase()}::varchar(42), ${transfer.from.toLowerCase()}::varchar(42), ${transfer.to.toLowerCase()}::varchar(42), ${transfer.value.toString()}::numeric(78, 0), ${transfer.blockNumber}::bigint)`,\n ),\n sql`,`,\n )}) AS v(event_id, chain_id, \"contract\", \"from\", \"to\", \"value\", block_number)\n WHERE\n EXISTS (\n SELECT 1 FROM ${positionsTable} p\n WHERE p.chain_id = v.chain_id AND p.\"contract\" = v.\"contract\" AND p.\"user\" = v.\"from\" AND p.balance IS NOT NULL\n )\n AND\n EXISTS (\n SELECT 1 FROM ${positionsTable} p\n WHERE p.chain_id = v.chain_id AND p.\"contract\" = v.\"contract\" AND p.\"user\" = v.\"to\" AND p.balance IS NOT NULL\n )\n ON CONFLICT DO NOTHING\n RETURNING *;\n `);\n\n if (inserted.length === 0) continue;\n\n await dbTx.execute(sql`\n WITH inserted AS (\n VALUES ${sql.join(\n inserted.map((t) => {\n return sql`(${t.chain_id}::bigint, ${t.contract}::varchar(42), ${t.from}::varchar(42), ${t.to}::varchar(42), ${t.value}::numeric(78, 0), ${t.block_number}::bigint)`;\n }),\n sql`,`,\n )}\n ),\n new_transfers AS (\n SELECT\n column1 AS chain_id,\n column2 AS \"contract\",\n column3 AS \"from\",\n column4 AS \"to\",\n column5 AS \"value\",\n column6 AS block_number\n FROM inserted\n ),\n diffs AS (\n SELECT\n nt.chain_id,\n nt.\"contract\",\n nt.\"from\" AS \"user\",\n -nt.\"value\" AS delta,\n nt.block_number\n FROM new_transfers nt\n UNION ALL\n SELECT\n nt.chain_id,\n nt.\"contract\",\n nt.\"to\" AS \"user\",\n nt.\"value\" AS delta,\n nt.block_number\n FROM new_transfers nt\n ),\n valid_diffs AS (\n SELECT\n d.chain_id,\n d.\"contract\",\n d.\"user\",\n d.delta,\n d.block_number\n FROM diffs d\n JOIN ${positionsTable} p\n ON p.chain_id = d.chain_id\n AND p.\"contract\" = d.\"contract\"\n AND p.\"user\" = d.\"user\"\n -- Only keep per-event diffs that are at or after the current position block\n WHERE d.block_number >= p.block_number\n ),\n aggregated AS (\n SELECT\n chain_id,\n \"contract\",\n \"user\",\n SUM(delta) AS sum_delta,\n MAX(block_number) AS max_block\n FROM valid_diffs\n GROUP BY 1,2,3\n )\n UPDATE ${positionsTable} AS p\n SET\n balance = (COALESCE(p.balance, 0) + a.sum_delta),\n block_number = a.max_block,\n updated_at = NOW()\n FROM aggregated a\n WHERE\n p.chain_id = a.chain_id\n AND p.\"contract\" = a.\"contract\"\n AND p.\"user\" = a.\"user\"\n `);\n\n totalInserted += inserted.length;\n }\n\n return totalInserted;\n });\n\n return created;\n },\n});\n","import { eq, inArray, sql } from \"drizzle-orm\";\nimport type { Hex } from \"viem\";\nimport { Offer, Tree } from \"#core/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\nimport type * as Database from \"../Database.ts\";\nimport { merklePaths as merklePathsTable, trees as treesTable } from \"../drizzle/schema.ts\";\n\n/**\n * Attestation data for a single offer, containing the merkle root, signature, and proof.\n */\nexport type Attestation = {\n root: Hex;\n signature: Hex;\n proof: Hex[];\n};\n\n/**\n * Input for creating trees with their signatures.\n */\nexport type CreateInput = {\n tree: Tree.Tree;\n signature: Hex;\n};\n\nexport type TreesDomain = {\n /**\n * Creates trees and attestation links in a single transaction.\n *\n * @param trees - Array of decoded trees with signatures (batch insertion)\n * @returns Array of tree roots that were created/upserted\n */\n create: (trees: CreateInput[]) => Promise<Hex[]>;\n\n /**\n * Retrieves merkle attestations for execution flow.\n *\n * @param hashes - Array of offer hashes to look up\n * @returns Map of offer hash to attestation (only entries with attestations are included)\n */\n getAttestations: (hashes: Hex[]) => Promise<Map<Hex, Attestation>>;\n};\n\n/**\n * Creates a Trees domain instance for managing merkle tree metadata.\n *\n * @param config - Configuration with database instance\n * @returns TreesDomain instance\n */\nexport function create(config: { db: Database.Core }): TreesDomain {\n const db = config.db;\n\n return {\n create: async (trees: CreateInput[]): Promise<Hex[]> => {\n if (trees.length === 0) return [];\n\n try {\n return await db.transaction(async (dbTx) => {\n const roots: Hex[] = [];\n\n for (const { tree, signature } of trees) {\n const root = tree.root.toLowerCase() as Hex;\n roots.push(root);\n\n await dbTx\n .insert(treesTable)\n .values({\n root,\n rootSignature: signature.toLowerCase(),\n })\n .onConflictDoUpdate({\n target: [treesTable.root],\n set: {\n rootSignature: signature.toLowerCase(),\n createdAt: sql`NOW()`,\n },\n });\n\n const pathRows = Tree.proofs(tree).map((proof) => ({\n offerHash: Offer.hash(proof.offer).toLowerCase(),\n treeRoot: root,\n proofNodes: concatenateProofs(proof.path),\n }));\n\n for (const batch of Utils.batch(pathRows, DEFAULT_BATCH_SIZE)) {\n await dbTx\n .insert(merklePathsTable)\n .values(batch)\n .onConflictDoUpdate({\n target: [merklePathsTable.offerHash],\n set: {\n treeRoot: sql`excluded.tree_root`,\n proofNodes: sql`excluded.proof_nodes`,\n createdAt: sql`NOW()`,\n },\n });\n }\n }\n\n return roots;\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n throw new Error(\"Trees.create failed. Ensure offers exist before inserting merkle paths.\", {\n cause: error,\n });\n }\n },\n\n getAttestations: async (hashes: Hex[]): Promise<Map<Hex, Attestation>> => {\n if (hashes.length === 0) return new Map();\n\n const normalizedHashes = hashes.map((h) => h.toLowerCase());\n\n const results = await db\n .select({\n offerHash: merklePathsTable.offerHash,\n treeRoot: merklePathsTable.treeRoot,\n proofNodes: merklePathsTable.proofNodes,\n rootSignature: treesTable.rootSignature,\n })\n .from(merklePathsTable)\n .innerJoin(treesTable, eq(merklePathsTable.treeRoot, treesTable.root))\n .where(inArray(merklePathsTable.offerHash, normalizedHashes));\n\n const attestationMap = new Map<Hex, Attestation>();\n\n for (const row of results) {\n attestationMap.set(row.offerHash as Hex, {\n root: row.treeRoot as Hex,\n signature: row.rootSignature as Hex,\n proof: splitProofs(row.proofNodes),\n });\n }\n\n return attestationMap;\n },\n };\n}\n\n/**\n * Concatenates an array of 32-byte hex hashes into a single hex string.\n * Empty arrays return \"0x\".\n */\nfunction concatenateProofs(proofs: Hex[]): string {\n if (proofs.length === 0) return \"0x\";\n return `0x${proofs.map((p) => p.slice(2)).join(\"\")}`;\n}\n\n/**\n * Splits a concatenated hex string back into an array of 32-byte hex hashes.\n * Returns empty array for \"0x\" or empty string.\n */\nfunction splitProofs(concatenated: string): Hex[] {\n if (!concatenated || concatenated === \"0x\" || concatenated.length <= 2) {\n return [];\n }\n const hex = concatenated.slice(2);\n const proofs: Hex[] = [];\n for (let i = 0; i < hex.length; i += 64) {\n proofs.push(`0x${hex.slice(i, i + 64)}` as Hex);\n }\n return proofs;\n}\n","import { and, asc, eq, gt, inArray, sql } from \"drizzle-orm\";\nimport type { Hex } from \"viem\";\nimport * as Offer from \"#core/Offer.ts\";\nimport * as Utils from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\nimport type * as Database from \"../Database.ts\";\nimport { status as statusTable, validations as validationsTable } from \"../drizzle/schema.ts\";\n\nconst DEFAULT_LIMIT = 100;\n\nexport type GetParams = {\n status?: Offer.Status;\n cursor?: string;\n limit?: number;\n};\n\nexport type ValidationsDomain = {\n /**\n * Get validation statuses with optional filtering and pagination.\n *\n * @param params - Optional parameters for filtering and pagination\n * @returns Array of validation statuses and next cursor for pagination\n */\n get: (params?: GetParams) => Promise<{\n validations: Offer.Validation[];\n nextCursor: string | null;\n }>;\n\n /**\n * Upsert validations\n *\n * @param validations - Array of validations to upsert\n */\n upsert: (validations: Offer.Validation[]) => Promise<void>;\n};\n\nexport function create(db: Database.Core): ValidationsDomain {\n return {\n get: async (params) => {\n const { status, cursor, limit = DEFAULT_LIMIT } = params ?? {};\n\n if (cursor !== null && cursor !== undefined) {\n if (!cursor.startsWith(\"0x\") || cursor.length !== 66) {\n throw new Error(\"Invalid cursor format\");\n }\n }\n\n let query = db\n .select({\n offerHash: validationsTable.offerHash,\n code: statusTable.code,\n })\n .from(validationsTable)\n .innerJoin(statusTable, eq(validationsTable.statusId, statusTable.id));\n\n if (status !== undefined) {\n query = query.where(eq(statusTable.code, status)) as typeof query;\n }\n\n if (cursor !== null && cursor !== undefined) {\n const cursorCondition = gt(validationsTable.offerHash, cursor.toLowerCase());\n if (status !== undefined) {\n query = query.where(and(eq(statusTable.code, status), cursorCondition)) as typeof query;\n } else {\n query = query.where(cursorCondition) as typeof query;\n }\n }\n\n const results = await query.orderBy(asc(validationsTable.offerHash)).limit(limit);\n\n const mapped: Offer.Validation[] = results.map((row) => ({\n offerHash: row.offerHash as Hex,\n status: row.code as Offer.Status,\n }));\n\n const nextCursor = mapped.length === limit ? mapped[mapped.length - 1]!.offerHash : null;\n\n return { validations: mapped, nextCursor };\n },\n\n upsert: async (results) => {\n if (results.length === 0) return;\n\n const allowedStatuses = new Set(Object.values(Offer.Status));\n const invalidStatuses = Array.from(\n new Set(results.map((r) => r.status).filter((s) => !allowedStatuses.has(s))),\n );\n if (invalidStatuses.length > 0) {\n throw new Error(`Unknown validation status: ${invalidStatuses.join(\", \")}`);\n }\n\n const normalized = results.map((r) => ({\n offerHash: r.offerHash.toLowerCase(),\n status: r.status,\n }));\n\n const uniqueStatuses = Array.from(new Set(normalized.map((r) => r.status)));\n const statusRows = await db\n .select({ id: statusTable.id, code: statusTable.code })\n .from(statusTable)\n .where(inArray(statusTable.code, uniqueStatuses as Offer.Status[]));\n\n const statusMap = new Map(statusRows.map((row) => [row.code, row.id] as const));\n\n for (const status of uniqueStatuses) {\n if (!statusMap.has(status)) {\n throw new Error(`Unknown validation status: ${status}`);\n }\n }\n\n const values = normalized.map((row) => ({\n offerHash: row.offerHash,\n statusId: statusMap.get(row.status)!,\n }));\n\n for (const batch of Utils.batch(values, DEFAULT_BATCH_SIZE)) {\n await db\n .insert(validationsTable)\n .values(batch)\n .onConflictDoUpdate({\n target: [validationsTable.offerHash],\n set: {\n statusId: sql`excluded.status_id`,\n updatedAt: sql`NOW()`,\n },\n });\n }\n },\n };\n}\n","import crypto from \"node:crypto\";\nimport { PGlite } from \"@electric-sql/pglite\";\nimport { drizzle } from \"drizzle-orm/node-postgres\";\nimport { migrate as migratePostgres } from \"drizzle-orm/node-postgres/migrator\";\nimport { drizzle as drizzleLite } from \"drizzle-orm/pglite\";\nimport { migrate as migratePGLite } from \"drizzle-orm/pglite/migrator\";\nimport { Pool } from \"pg\";\nimport type * as ChainRegistry from \"#core/ChainRegistry.ts\";\nimport { Offer, Position } from \"#core/index.ts\";\nimport { Tracer } from \"#tracer/index.ts\";\nimport {\n BlocksDomain,\n BookDomain,\n CallbacksDomain,\n ConsumedDomain,\n GroupsDomain,\n LotsDomain,\n ObligationsDomain,\n OffersDomain,\n OffsetsDomain,\n OraclesDomain,\n PositionsDomain,\n TransfersDomain,\n TreesDomain,\n ValidationsDomain,\n} from \"./domains/index.ts\";\nimport * as offersSchema from \"./drizzle/schema.ts\";\nimport { VERSION } from \"./drizzle/VERSION.ts\";\n\nexport type Driver = ReturnType<typeof drizzle> | ReturnType<typeof drizzleLite>;\n\ntype Domains = {\n book: BookDomain.BookDomain;\n blocks: BlocksDomain.BlocksDomain;\n callbacks: CallbacksDomain.CallbacksDomain;\n offers: OffersDomain.OffersDomain;\n consumed: ConsumedDomain.ConsumedDomain;\n groups: GroupsDomain.GroupsDomain;\n lots: LotsDomain.LotsDomain;\n obligations: ObligationsDomain.ObligationsDomain;\n offsets: OffsetsDomain.OffsetsDomain;\n oracles: OraclesDomain.OraclesDomain;\n trees: TreesDomain.TreesDomain;\n validations: ValidationsDomain.ValidationsDomain;\n positions: PositionsDomain.PositionsDomain;\n transfers: TransfersDomain.TransfersDomain;\n};\n\nexport type WithDomains<D extends Driver> = D & Domains;\n\nexport type Core = Omit<WithDomains<Driver>, \"transaction\"> & {\n transaction<T>(fn: (tx: WithDomains<Driver>) => Promise<T>): Promise<T>;\n};\n\nexport type Database = Core & {\n name: \"pg\" | \"pglite\";\n pool: Pool | PGlite;\n applyMigrations: (folderPath: string) => Promise<void>;\n clean: () => Promise<void>;\n};\n\nfunction createDomains<core extends Core>(\n core: core,\n chainRegistry: ChainRegistry.ChainRegistry,\n): Domains {\n const domains = {\n book: BookDomain.create({ db: core }),\n blocks: BlocksDomain.create({ db: core, chainRegistry }),\n callbacks: CallbacksDomain.create(core),\n offers: OffersDomain.create({ db: core }),\n consumed: ConsumedDomain.create(core),\n groups: GroupsDomain.create(core),\n lots: LotsDomain.create(core),\n obligations: ObligationsDomain.create(core),\n offsets: OffsetsDomain.create(core),\n oracles: OraclesDomain.create(core),\n trees: TreesDomain.create({ db: core }),\n validations: ValidationsDomain.create(core),\n positions: PositionsDomain.create(core),\n transfers: TransfersDomain.create(core),\n };\n\n return domains;\n}\n\n// One wrapper per original driver/tx and chain registry\nconst AUGMENT_CACHE: WeakMap<object, WeakMap<ChainRegistry.ChainRegistry, Core>> = new WeakMap();\nfunction augmentWithDomains(base: Driver, chainRegistry: ChainRegistry.ChainRegistry): Core {\n const cached = AUGMENT_CACHE.get(base)?.get(chainRegistry);\n if (cached) return cached;\n\n // Create a wrapper that delegates to the driver\n const wrapped = Object.create(base) as Core;\n\n // Override transaction: wrap the tx with domains as well\n wrapped.transaction = async <T>(fn: (tx: WithDomains<Driver>) => Promise<T>): Promise<T> => {\n return base.transaction(async (tx) => {\n const txWithDomains = augmentWithDomains(tx as unknown as Driver, chainRegistry);\n return fn(txWithDomains as unknown as WithDomains<Driver>);\n });\n };\n\n const dms = createDomains(wrapped, chainRegistry);\n\n Object.defineProperties(wrapped, {\n book: { value: dms.book, enumerable: true },\n blocks: { value: dms.blocks, enumerable: true },\n callbacks: { value: dms.callbacks, enumerable: true },\n offers: { value: dms.offers, enumerable: true },\n consumed: { value: dms.consumed, enumerable: true },\n groups: { value: dms.groups, enumerable: true },\n lots: { value: dms.lots, enumerable: true },\n obligations: { value: dms.obligations, enumerable: true },\n offsets: { value: dms.offsets, enumerable: true },\n oracles: { value: dms.oracles, enumerable: true },\n trees: { value: dms.trees, enumerable: true },\n validations: { value: dms.validations, enumerable: true },\n positions: { value: dms.positions, enumerable: true },\n transfers: { value: dms.transfers, enumerable: true },\n });\n\n const chainRegistryMap = AUGMENT_CACHE.get(base);\n if (!chainRegistryMap) {\n AUGMENT_CACHE.set(base, new Map([[chainRegistry, wrapped]]));\n } else {\n chainRegistryMap.set(chainRegistry, wrapped);\n }\n\n return wrapped;\n}\n\nconst InMemoryDbMap: Map<string, Database> = new Map();\n\n/**\n * Connect to the database.\n * @notice If no connection string is provided, an in-process PGLite database is created.\n * @param {string=} [connectionString] - The optional connection string for the Postgres database.\n * @returns The database client {@link connect.ReturnType}\n */\nexport function connect(\n chainRegistry: ChainRegistry.ChainRegistry,\n connectionString?: string,\n): Database {\n const clean = async (driver: Driver) => {\n if (offersSchema.TABLE_NAMES.length === 0) return;\n await driver.execute(\n `TRUNCATE TABLE ${offersSchema.VERSIONED_TABLE_NAMES.join(\", \")} RESTART IDENTITY CASCADE;`,\n );\n };\n\n if (connectionString !== undefined) {\n const pool = new Pool({ connectionString });\n const driver = drizzle(pool, { schema: offersSchema });\n const core = augmentWithDomains(driver, chainRegistry);\n\n const db = Object.assign(core, {\n name: \"pg\" as const,\n pool,\n applyMigrations: applyMigrations(\"pg\", driver),\n clean: async () => await clean(driver),\n } as const);\n\n return db;\n }\n\n // Include VITEST_POOL_ID in cache key to isolate PGLite instances per test worker\n // This prevents lock contention when multiple workers run migrations simultaneously\n const poolId = process.env.VITEST_POOL_ID ?? \"\";\n const key = crypto\n .createHash(\"md5\")\n .update(JSON.stringify(chainRegistry.list()) + poolId)\n .digest(\"hex\");\n const cached = InMemoryDbMap.get(key);\n if (cached) return cached;\n\n const pool = new PGlite();\n const driver = drizzleLite(pool, { schema: offersSchema });\n const core = augmentWithDomains(driver, chainRegistry);\n\n InMemoryDbMap.set(\n key,\n Object.assign(core, {\n name: \"pglite\" as const,\n pool,\n applyMigrations: applyMigrations(\"pglite\", driver),\n clean: async () => await clean(driver),\n } as const),\n );\n\n return InMemoryDbMap.get(key)!;\n}\n\nconst MIGRATED_DRIVERS = new WeakSet<Driver>();\nfunction applyMigrations(\n kind: \"pg\" | \"pglite\",\n driver: Driver,\n): (folderPath: string) => Promise<void> {\n return async (folderPath: string) => {\n if (MIGRATED_DRIVERS.has(driver)) return;\n\n const tracer = Tracer.getTracer(\"db.applyMigrations\");\n await Tracer.startActiveSpan(tracer, \"db.applyMigrations\", async () => {\n await preMigrate(driver);\n\n if (kind === \"pg\") {\n await migratePostgres(driver as ReturnType<typeof drizzle>, {\n migrationsFolder: folderPath,\n });\n } else {\n await migratePGLite(driver as ReturnType<typeof drizzleLite>, {\n migrationsFolder: folderPath,\n });\n }\n\n await postMigrate(driver);\n });\n\n MIGRATED_DRIVERS.add(driver);\n };\n}\n\nasync function preMigrate(driver: Driver) {\n const tracer = Tracer.getTracer(\"db.preMigrate\");\n await Tracer.startActiveSpan(tracer, \"db.preMigrate\", async () => {\n await driver.execute(`create schema if not exists \"${VERSION}\"`);\n });\n}\n\nasync function postMigrate(driver: Driver) {\n const tracer = Tracer.getTracer(\"db.postMigrate\");\n await Tracer.startActiveSpan(tracer, \"db.postMigrate\", async () => {\n await driver.execute(\n `INSERT INTO \"${VERSION}\".\"status\" (\"code\") VALUES ('${Offer.Status.VALID}'), ('${Offer.Status.SIMULATION_ERROR}') ON CONFLICT DO NOTHING;`,\n );\n await driver.execute(\n `INSERT INTO \"${VERSION}\".\"position_types\" (\"type\") VALUES ('${Position.Type.ERC20}'), ('${Position.Type.VAULT_V1}') ON CONFLICT DO NOTHING;`,\n );\n\n await driver.execute(`\n CREATE OR REPLACE FUNCTION apply_group_consumed_stmt_ins()\n RETURNS trigger\n LANGUAGE plpgsql AS $$\n BEGIN\n WITH deltas AS (\n SELECT chain_id, maker, \"group\", SUM(amount)::numeric AS delta\n FROM new_rows\n GROUP BY 1,2,3\n )\n UPDATE \"${VERSION}\".\"groups\" g\n SET consumed = g.consumed + d.delta\n FROM deltas d\n WHERE g.chain_id = d.chain_id\n AND g.maker = d.maker\n AND g.\"group\" = d.\"group\";\n RETURN NULL;\n END;\n $$;`);\n\n await driver.execute(`\n CREATE OR REPLACE FUNCTION apply_group_consumed_stmt_del()\n RETURNS trigger\n LANGUAGE plpgsql AS $$\n BEGIN\n -- Apply negative deltas per touched group\n WITH deltas AS (\n SELECT chain_id, maker, \"group\", -SUM(amount)::numeric AS delta\n FROM old_rows\n GROUP BY 1,2,3\n )\n UPDATE \"${VERSION}\".\"groups\" g\n SET consumed = g.consumed + d.delta\n FROM deltas d\n WHERE g.chain_id = d.chain_id\n AND g.maker = d.maker\n AND g.\"group\" = d.\"group\";\n RETURN NULL;\n END;\n $$;\n `);\n\n // UPDATE (handles same-group changes and “moves”)\n await driver.execute(`\n CREATE OR REPLACE FUNCTION apply_group_consumed_stmt_upd()\n RETURNS trigger\n LANGUAGE plpgsql AS $$\n BEGIN\n -- 1) Compute deltas (new - old) per logical group and apply\n WITH new_agg AS (\n SELECT chain_id, maker, \"group\", SUM(amount)::numeric AS sum_amt\n FROM new_rows\n GROUP BY 1,2,3\n ),\n old_agg AS (\n SELECT chain_id, maker, \"group\", SUM(amount)::numeric AS sum_amt\n FROM old_rows\n GROUP BY 1,2,3\n ),\n deltas AS (\n SELECT\n COALESCE(n.chain_id, o.chain_id) AS chain_id,\n COALESCE(n.maker, o.maker) AS maker,\n COALESCE(n.\"group\", o.\"group\") AS \"group\",\n COALESCE(n.sum_amt, 0) - COALESCE(o.sum_amt, 0) AS delta\n FROM new_agg n\n FULL JOIN old_agg o\n ON n.chain_id = o.chain_id AND n.maker = o.maker AND n.\"group\" = o.\"group\"\n WHERE COALESCE(n.sum_amt, 0) <> COALESCE(o.sum_amt, 0)\n )\n UPDATE \"${VERSION}\".\"groups\" g\n SET consumed = g.consumed + d.delta\n FROM deltas d\n WHERE g.chain_id = d.chain_id\n AND g.maker = d.maker\n AND g.\"group\" = d.\"group\";\n RETURN NULL;\n END;\n $$;\n `);\n\n // Triggers (statement-level with transition tables)\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_consumed_events_apply_insert_stmt\n AFTER INSERT ON \"${VERSION}\".\"consumed_events\"\n REFERENCING NEW TABLE AS new_rows\n FOR EACH STATEMENT\n EXECUTE FUNCTION apply_group_consumed_stmt_ins();`);\n\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_consumed_events_apply_delete_stmt\n AFTER DELETE ON \"${VERSION}\".\"consumed_events\"\n REFERENCING OLD TABLE AS old_rows\n FOR EACH STATEMENT\n EXECUTE FUNCTION apply_group_consumed_stmt_del();\n `);\n\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_consumed_events_apply_update_stmt\n AFTER UPDATE ON \"${VERSION}\".\"consumed_events\"\n REFERENCING NEW TABLE AS new_rows OLD TABLE AS old_rows\n FOR EACH STATEMENT\n EXECUTE FUNCTION apply_group_consumed_stmt_upd();\n `);\n\n await driver.execute(`\n CREATE OR REPLACE FUNCTION oco_on_groups_consumed_update()\n RETURNS trigger\n LANGUAGE plpgsql AS $$\n BEGIN\n WITH touched AS (\n SELECT DISTINCT chain_id, maker, \"group\", consumed FROM new_groups\n )\n DELETE FROM \"${VERSION}\".\"offers\" o\n USING touched t\n WHERE o.group_chain_id = t.chain_id\n AND o.group_maker = t.maker\n AND o.group_group = t.\"group\"\n AND o.assets <= t.consumed;\n RETURN NULL;\n END;\n $$;\n `);\n\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_groups_oco_after_update\n AFTER UPDATE ON \"${VERSION}\".\"groups\"\n REFERENCING NEW TABLE AS new_groups\n FOR EACH STATEMENT\n EXECUTE FUNCTION oco_on_groups_consumed_update();\n `);\n\n await driver.execute(`\n CREATE OR REPLACE FUNCTION oco_on_offers_insert()\n RETURNS trigger\n LANGUAGE plpgsql AS $$\n BEGIN\n WITH touched AS (\n SELECT DISTINCT group_chain_id, group_maker, group_group AS \"group\"\n FROM new_rows\n )\n DELETE FROM \"${VERSION}\".\"offers\" o\n USING touched t, \"${VERSION}\".\"groups\" g\n WHERE o.group_chain_id = t.group_chain_id\n AND o.group_maker = t.group_maker\n AND o.group_group = t.\"group\"\n AND o.assets <= g.consumed;\n RETURN NULL;\n END;\n $$;`);\n\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_offers_oco_insert_stmt\n AFTER INSERT ON \"${VERSION}\".\"offers\"\n REFERENCING NEW TABLE AS new_rows\n FOR EACH STATEMENT\n EXECUTE FUNCTION oco_on_offers_insert();\n `);\n\n await driver.execute(`\n CREATE OR REPLACE FUNCTION cleanup_orphan_positions()\n RETURNS TRIGGER AS $$\n BEGIN\n DELETE FROM \"${VERSION}\".\"positions\" p\n USING (\n SELECT DISTINCT c.position_chain_id, c.position_contract, c.position_user\n FROM deleted_rows d\n JOIN \"${VERSION}\".\"callbacks\" c ON c.id = d.callback_id\n ) AS affected\n WHERE p.chain_id = affected.position_chain_id\n AND p.contract = affected.position_contract\n AND p.\"user\" = affected.position_user\n AND NOT EXISTS (\n SELECT 1 FROM \"${VERSION}\".\"callbacks\" c2\n JOIN \"${VERSION}\".\"offers_callbacks\" oc ON oc.callback_id = c2.id\n WHERE c2.position_chain_id = p.chain_id\n AND c2.position_contract = p.contract\n AND c2.position_user = p.\"user\"\n );\n RETURN NULL;\n END;\n $$ LANGUAGE plpgsql;\n `);\n\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_cleanup_orphan_positions\n AFTER DELETE ON \"${VERSION}\".\"offers_callbacks\"\n REFERENCING OLD TABLE AS deleted_rows\n FOR EACH STATEMENT\n EXECUTE FUNCTION cleanup_orphan_positions();\n `);\n\n await driver.execute(`\n CREATE OR REPLACE FUNCTION cleanup_orphan_groups()\n RETURNS TRIGGER AS $$\n BEGIN\n DELETE FROM \"${VERSION}\".\"groups\" g\n USING (\n SELECT DISTINCT group_chain_id, group_maker, group_group\n FROM deleted_rows\n ) AS affected\n WHERE g.chain_id = affected.group_chain_id\n AND g.maker = affected.group_maker\n AND g.\"group\" = affected.group_group\n AND NOT EXISTS (\n SELECT 1 FROM \"${VERSION}\".\"offers\" o\n WHERE o.group_chain_id = g.chain_id\n AND o.group_maker = g.maker\n AND o.group_group = g.\"group\"\n );\n RETURN NULL;\n END;\n $$ LANGUAGE plpgsql;\n `);\n\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_cleanup_orphan_groups\n AFTER DELETE ON \"${VERSION}\".\"offers\"\n REFERENCING OLD TABLE AS deleted_rows\n FOR EACH STATEMENT\n EXECUTE FUNCTION cleanup_orphan_groups();\n `);\n\n await driver.execute(`\n CREATE OR REPLACE FUNCTION cleanup_orphan_obligations_and_oracles()\n RETURNS TRIGGER AS $$\n DECLARE\n orphan_obligation_ids TEXT[];\n candidate_oracles RECORD;\n BEGIN\n -- 1. Find orphan obligation IDs\n SELECT ARRAY_AGG(DISTINCT obligation_id) INTO orphan_obligation_ids\n FROM deleted_rows d\n WHERE NOT EXISTS (\n SELECT 1 FROM \"${VERSION}\".\"offers\" ov\n WHERE ov.obligation_id = d.obligation_id\n );\n\n -- 2. If no orphan obligations, exit early\n IF orphan_obligation_ids IS NULL OR array_length(orphan_obligation_ids, 1) IS NULL THEN\n RETURN NULL;\n END IF;\n\n -- 3. Capture candidate oracles (from collaterals of orphan obligations)\n CREATE TEMP TABLE _candidate_oracles ON COMMIT DROP AS\n SELECT DISTINCT oc.oracle_chain_id, oc.oracle_address\n FROM \"${VERSION}\".\"obligation_collaterals_v2\" oc\n WHERE oc.obligation_id = ANY(orphan_obligation_ids);\n\n -- 4. Delete orphan obligations (cascades to collaterals)\n DELETE FROM \"${VERSION}\".\"obligations\" ob\n WHERE ob.obligation_id = ANY(orphan_obligation_ids);\n\n -- 5. Delete oracles that are now orphaned (no remaining collateral references)\n DELETE FROM \"${VERSION}\".\"oracles\" o\n USING _candidate_oracles co\n WHERE o.chain_id = co.oracle_chain_id\n AND o.address = co.oracle_address\n AND NOT EXISTS (\n SELECT 1 FROM \"${VERSION}\".\"obligation_collaterals_v2\" oc\n WHERE oc.oracle_chain_id = o.chain_id\n AND oc.oracle_address = o.address\n );\n\n RETURN NULL;\n END;\n $$ LANGUAGE plpgsql;\n `);\n\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_cleanup_orphan_obligations_and_oracles\n AFTER DELETE ON \"${VERSION}\".\"offers\"\n REFERENCING OLD TABLE AS deleted_rows\n FOR EACH STATEMENT\n EXECUTE FUNCTION cleanup_orphan_obligations_and_oracles();\n `);\n\n // Create offset when lot is deleted (before delete to capture lot data)\n await driver.execute(`\n CREATE OR REPLACE FUNCTION create_offset_on_lot_delete()\n RETURNS trigger\n LANGUAGE plpgsql AS $$\n BEGIN\n INSERT INTO \"${VERSION}\".\"offsets\" (chain_id, \"user\", contract, \"group\", value)\n VALUES (\n OLD.chain_id,\n OLD.\"user\",\n OLD.contract,\n OLD.\"group\",\n OLD.upper::numeric - OLD.lower::numeric\n )\n ON CONFLICT (chain_id, \"user\", contract, \"group\") DO NOTHING;\n RETURN OLD;\n END;\n $$;\n `);\n\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_lots_create_offset_before_delete\n BEFORE DELETE ON \"${VERSION}\".\"lots\"\n FOR EACH ROW\n EXECUTE FUNCTION create_offset_on_lot_delete();\n `);\n\n // Delete position if no lots remain after lot deletion\n await driver.execute(`\n CREATE OR REPLACE FUNCTION delete_position_if_no_lots()\n RETURNS trigger\n LANGUAGE plpgsql AS $$\n BEGIN\n -- Check if any lots remain on this position\n IF NOT EXISTS (\n SELECT 1 FROM \"${VERSION}\".\"lots\" l\n WHERE l.chain_id = OLD.chain_id\n AND l.contract = OLD.contract\n AND l.\"user\" = OLD.\"user\"\n ) THEN\n -- No lots remain, delete the position (cascades to offsets)\n DELETE FROM \"${VERSION}\".\"positions\" p\n WHERE p.chain_id = OLD.chain_id\n AND p.contract = OLD.contract\n AND p.\"user\" = OLD.\"user\";\n END IF;\n RETURN NULL;\n END;\n $$;\n `);\n\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_lots_delete_position_if_empty\n AFTER DELETE ON \"${VERSION}\".\"lots\"\n FOR EACH ROW\n EXECUTE FUNCTION delete_position_if_no_lots();\n `);\n });\n}\n","import type { Offer } from \"#core\";\nimport * as OfferCore from \"#core/Offer.ts\";\nimport type * as Gate from \"./Gate.ts\";\nimport type {\n ConfigRule,\n ConfigRulesPayload,\n ErrorPayload,\n SuccessPayload,\n ValidateOffersData,\n} from \"./types.ts\";\n\nexport type GatekeeperClient = {\n /** Validate offers and return the raw response payload. */\n validate: (body: unknown) => Promise<{ statusCode: number; body: unknown }>;\n /** Get configured rules for supported chains. */\n getConfigRules: (query?: {\n cursor?: string;\n limit?: number | string;\n types?: Array<ConfigRule[\"type\"]> | ConfigRule[\"type\"];\n }) => Promise<{ statusCode: number; body: ConfigRulesPayload }>;\n /** Validate offers and return decision results. */\n isAllowed: (offers: Offer.Offer[]) => Promise<Gate.Result<Offer.Offer, string>>;\n /** Base URL for the gatekeeper service. */\n baseUrl: string;\n};\n\nexport type ClientConfig = {\n baseUrl: string;\n timeoutMs?: number;\n fetchFn?: typeof fetch;\n originSecret?: string;\n};\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\n/**\n * Create an HTTP client for a gatekeeper service.\n * @param config - Gatekeeper client configuration. {@link ClientConfig}\n * @returns An HTTP-backed gatekeeper client. {@link GatekeeperClient}\n */\nexport function createHttpClient(config: ClientConfig): GatekeeperClient {\n const fetchFn = config.fetchFn ?? fetch;\n const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const baseUrl = normalizeBaseUrl(config.baseUrl);\n const baseHeaders = config.originSecret ? { \"x-origin-verify\": config.originSecret } : undefined;\n\n const request = async (path: string, init: RequestInit): Promise<Response> => {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n try {\n return await fetchFn(`${baseUrl}${path}`, {\n ...init,\n headers: mergeHeaders(baseHeaders, init.headers),\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timeout);\n }\n };\n\n const validate = async (body: unknown): Promise<{ statusCode: number; body: unknown }> => {\n const response = await request(\"/v1/validate\", {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n const json = (await response.json()) as unknown;\n return { statusCode: response.status, body: json };\n };\n\n const getConfigRules = async (query?: {\n cursor?: string;\n limit?: number | string;\n types?: Array<ConfigRule[\"type\"]> | ConfigRule[\"type\"];\n }): Promise<{ statusCode: number; body: ConfigRulesPayload }> => {\n const params = new URLSearchParams();\n if (query?.cursor) params.set(\"cursor\", query.cursor);\n if (query?.limit !== undefined) params.set(\"limit\", query.limit.toString());\n if (query?.types !== undefined) {\n const typesValue = Array.isArray(query.types) ? query.types.join(\",\") : query.types;\n if (typesValue.length > 0) params.set(\"types\", typesValue);\n }\n const path = params.size > 0 ? `/v1/config/rules?${params.toString()}` : \"/v1/config/rules\";\n const response = await request(path, { method: \"GET\" });\n const json = (await response.json()) as ConfigRulesPayload;\n return { statusCode: response.status, body: json };\n };\n\n const isAllowed = async (offers: Offer.Offer[]): Promise<Gate.Result<Offer.Offer, string>> => {\n const payload = {\n offers: offers.map((offer) => OfferCore.toSnakeCase(offer)),\n };\n\n const { statusCode, body } = await validate(payload);\n if (statusCode !== 200) {\n const errorMessage = extractErrorMessage(body);\n throw new Error(`Gatekeeper validation failed: ${errorMessage ?? `status ${statusCode}`}`);\n }\n\n const data = (body as SuccessPayload<ValidateOffersData>).data;\n if (!data || typeof data !== \"object\") {\n throw new Error(\"Gatekeeper validation response is invalid.\");\n }\n\n if (\"issues\" in data) {\n const issues = data.issues.map((issue) => ({\n ruleName: issue.rule,\n message: issue.message,\n item: offers[issue.index]!,\n }));\n const invalidIndices = new Set(data.issues.map((issue) => issue.index));\n const valid = offers.filter((_, index) => !invalidIndices.has(index));\n\n return { valid, issues };\n }\n\n if (!(\"payload\" in data) || !(\"root\" in data)) {\n throw new Error(\"Gatekeeper validation response is missing payload data.\");\n }\n\n return { valid: offers.slice(), issues: [] };\n };\n\n return {\n baseUrl,\n validate,\n getConfigRules,\n isAllowed,\n };\n}\n\nfunction mergeHeaders(\n base: RequestInit[\"headers\"] | undefined,\n extra: RequestInit[\"headers\"] | undefined,\n): RequestInit[\"headers\"] | undefined {\n if (!base && !extra) return undefined;\n const merged = new Headers(base ?? undefined);\n if (extra) {\n for (const [key, value] of new Headers(extra).entries()) {\n merged.set(key, value);\n }\n }\n return merged;\n}\n\nfunction normalizeBaseUrl(url: string): string {\n const trimmed = url.trim().replace(/\\/+$/, \"\");\n return trimmed;\n}\n\nfunction extractErrorMessage(payload: unknown): string | undefined {\n if (!payload || typeof payload !== \"object\") return undefined;\n const error = (payload as ErrorPayload).error;\n if (!error || typeof error !== \"object\") return undefined;\n return typeof error.message === \"string\" ? error.message : undefined;\n}\n","/**\n * A validation rule.\n */\nexport type Rule<T, Name extends string = string> =\n | { kind: \"single\"; name: Name; description: string; run: Single<T, Name> }\n | { kind: \"batch\"; name: Name; description: string; run: Batch<T, Name> };\n\nexport type RuleNames<Rules extends readonly { name: string }[]> = Rules[number][\"name\"];\n\n/**\n * A single item validation rule.\n * @param item - The item to validate.\n * @returns The issue that was found. If the item is valid, this will be undefined.\n */\nexport type Single<T, RuleName extends string> = (\n item: T,\n) =>\n | Omit<Issue<T, RuleName>, \"ruleName\" | \"item\">\n | undefined\n | Promise<Omit<Issue<T, RuleName>, \"ruleName\" | \"item\"> | undefined>;\n\n/**\n * A batch item validation rule.\n * @param items - The items to validate.\n * @returns A map of the items to the issue that was found.\n */\nexport type Batch<T, RuleName extends string> = (\n items: T[],\n) =>\n | Map<number, Omit<Issue<T, RuleName>, \"ruleName\" | \"item\"> | undefined>\n | Promise<Map<number, Omit<Issue<T, RuleName>, \"ruleName\" | \"item\"> | undefined>>;\n\n/**\n * Create a validation rule iterating over a single item at a time.\n * @param name - The name of the rule.\n * @param description - A human-readable description of the rule.\n * @param run - The function that validates the rule.\n * @returns The created rule.\n */\nexport function single<Name extends string, T>(\n name: Name,\n description: string,\n run: Single<T, Name>,\n): Rule<T, Name> {\n return { kind: \"single\", name, description, run } as const satisfies Rule<T, Name>;\n}\n\n/**\n * Create a validation rule iterating over a batch of items at a time.\n * @param name - The name of the rule.\n * @param description - A human-readable description of the rule.\n * @param run - The function that validates the rule.\n * @returns The created rule.\n */\nexport function batch<Name extends string, T>(\n name: Name,\n description: string,\n run: Batch<T, Name>,\n): Rule<T, Name> {\n return { kind: \"batch\", name, description, run } as const satisfies Rule<T, Name>;\n}\n\n/**\n * A validation issue.\n */\nexport type Issue<T, RuleName extends string = string> = {\n /** The name of the rule that caused the issue. */\n ruleName: RuleName;\n /** The message of the issue. */\n message: string;\n /** The item that was not valid. */\n item: T;\n};\n\n/**\n * The result of a validation.\n */\nexport type Result<T, RuleName extends string = string> = {\n /** The items that were valid. */\n valid: T[];\n /** The reports of the failed validations. */\n issues: Issue<T, RuleName>[];\n};\n\nexport async function run<\n T,\n Name extends string,\n Rules extends readonly Rule<T, Name>[],\n>(parameters: {\n items: T[];\n rules: Rules;\n chunkSize?: number;\n}): Promise<Result<T, RuleNames<Rules>>> {\n const { items, rules, chunkSize } = parameters;\n\n const issues: Issue<T, RuleNames<Rules>>[] = [];\n let validItems: T[] = items.slice();\n\n for (const rule of rules) {\n if (validItems.length === 0) return { valid: [], issues };\n\n const indicesToRemove: Set<number> = new Set();\n if (rule.kind === \"single\") {\n for (let i = 0; i < validItems.length; i++) {\n const item = validItems[i]!;\n const issue = await rule.run(item);\n if (issue) {\n issues.push({ ...issue, ruleName: rule.name, item });\n indicesToRemove.add(i);\n }\n }\n } else if (rule.kind === \"batch\") {\n const exec = async (slice: T[], offset: number) => {\n const map = await rule.run(slice);\n for (let i = 0; i < slice.length; i++) {\n const issue = map.get(i);\n if (issue !== undefined) {\n issues.push({ ...issue, ruleName: rule.name, item: slice[i]! });\n indicesToRemove.add(offset + i);\n }\n }\n };\n\n if (!chunkSize) await exec(validItems, 0);\n else {\n for (let i = 0; i < validItems.length; i += chunkSize) {\n await exec(validItems.slice(i, i + chunkSize), i);\n }\n }\n }\n\n validItems = validItems.filter((_, i) => !indicesToRemove.has(i));\n }\n\n return {\n valid: validItems,\n issues,\n };\n}\n","import type { Offer } from \"#core\";\nimport * as Gate from \"./Gate.ts\";\n\nexport type Rules = readonly Gate.Rule<Offer.Offer, string>[];\n\nexport type Gatekeeper = {\n isAllowed: (offers: Offer.Offer[]) => Promise<Gate.Result<Offer.Offer, string>>;\n};\n\ntype GatekeeperParameters = {\n rules: Rules;\n};\n\n/**\n * Create a gatekeeper instance with the provided rules.\n * @param parameters - Gatekeeper parameters. {@link GatekeeperParameters}\n * @returns Gatekeeper instance. {@link Gatekeeper}\n */\nexport function create(parameters: GatekeeperParameters): Gatekeeper {\n const { rules } = parameters;\n return {\n isAllowed: async (offers: Offer.Offer[]) => {\n return await Gate.run({\n items: offers,\n rules,\n });\n },\n };\n}\n","import type { Address, PublicClient, Transport } from \"viem\";\nimport { Callback, type Chain, Maturity, type Offer } from \"#core\";\nimport * as BigMath from \"#utils/BigMath.ts\";\nimport type * as Validation from \"./Gate.ts\";\nimport { batch, single } from \"./Gate.ts\";\n\nexport type ValidityParameters = {\n client: PublicClient<Transport, Chain.Chain>;\n};\n\n/**\n * set of rules to validate offers.\n *\n * @param _parameters - Validity parameters with chain and client\n * @returns Array of validation rules to evaluate against offers\n */\nexport function validity(_parameters: ValidityParameters) {\n const expiry = single(\"expiry\", \"Validates that offer has not expired\", (offer: Offer.Offer) => {\n if (offer.expiry < Math.floor(Date.now() / 1000)) {\n return { message: \"Expiry mismatch\" };\n }\n });\n\n return [expiry];\n}\n\nexport const chains = ({ chains }: { chains: Chain.Chain[] }) =>\n single(\n \"chain_ids\",\n `Validates that offer chain is one of: [${chains.map((c) => c.id).join(\", \")}]`,\n (offer: Offer.Offer) => {\n const allowedChainIds = chains.map((c) => c.id);\n if (!allowedChainIds.some((id) => id === offer.chainId)) {\n return {\n message: `Chain ID ${offer.chainId} is not in the allowed chains (${allowedChainIds.join(\", \")})`,\n };\n }\n },\n );\n\nexport const maturity = ({ maturities }: { maturities: Maturity.MaturityType[] }) =>\n single(\n \"maturity\",\n `Validates that offer maturity is one of: [${maturities!.join(\", \")}]`,\n (offer: Offer.Offer) => {\n const allowedMaturities = maturities!.map((m) => Maturity.from(m));\n if (!allowedMaturities.includes(offer.maturity)) {\n return {\n message: `Maturity must be end of current month (${allowedMaturities[0]}) or end of next month (${allowedMaturities[1]}). Got: ${offer.maturity}`,\n };\n }\n },\n );\n\nexport const callback = ({\n callbacks,\n}: {\n callbacks: Callback.Type[];\n allowedAddresses: Address[];\n}) =>\n single(\n \"callback\",\n `Validates callbacks: buy empty callback is ${callbacks.includes(Callback.Type.BuyWithEmptyCallback) ? \"allowed\" : \"not allowed\"}; sell empty callback is ${callbacks.includes(Callback.Type.SellWithEmptyCallback) ? \"allowed\" : \"not allowed\"}; non-empty callbacks are rejected`,\n (offer: Offer.Offer) => {\n if (!Callback.isEmptyCallback(offer)) {\n return {\n message: \"Non-empty callbacks are not supported.\",\n };\n }\n if (\n Callback.isEmptyCallback(offer) &&\n offer.buy &&\n !callbacks.includes(Callback.Type.BuyWithEmptyCallback)\n ) {\n return {\n message: \"Buy offers with empty callback not allowed.\",\n };\n }\n if (\n Callback.isEmptyCallback(offer) &&\n !offer.buy &&\n !callbacks.includes(Callback.Type.SellWithEmptyCallback)\n ) {\n return {\n message: \"Sell offers with empty callback not allowed.\",\n };\n }\n },\n );\n\n/**\n * A validation rule that checks if the offer's tokens are allowed for its chain.\n * @param assetsByChainId - Allowed assets indexed by chain id.\n * @returns The issue that was found. If the offer is valid, this will be undefined.\n */\nexport const token = ({\n assetsByChainId,\n}: {\n assetsByChainId: Partial<Record<Chain.Id, Address[]>>;\n}) =>\n single(\n \"token\",\n \"Validates that offer loan token and collateral tokens are in the allowed assets list for the offer chain\",\n (offer: Offer.Offer) => {\n const allowedAssets = assetsByChainId[offer.chainId]?.map((asset) => asset.toLowerCase());\n if (!allowedAssets || allowedAssets.length === 0) {\n return { message: `No allowed assets for chain ${offer.chainId}` };\n }\n if (!allowedAssets.includes(offer.loanToken.toLowerCase())) {\n return { message: \"Loan token is not allowed\" };\n }\n if (\n offer.collaterals.some(\n (collateral) => !allowedAssets.includes(collateral.asset.toLowerCase()),\n )\n ) {\n return { message: \"Collateral is not allowed\" };\n }\n return undefined;\n },\n );\n\n/**\n * A validation rule that checks if the offer's oracle addresses are allowed for its chain.\n * @param oraclesByChainId - Allowed oracles indexed by chain id.\n * @returns The issue that was found. If the offer is valid, this will be undefined.\n */\nexport const oracle = ({\n oraclesByChainId,\n}: {\n oraclesByChainId: Partial<Record<Chain.Id, Address[]>>;\n}) =>\n single(\n \"oracle\",\n \"Validates that offer collateral oracles are in the allowed oracle list for the offer chain\",\n (offer: Offer.Offer) => {\n const allowedOracles = oraclesByChainId[offer.chainId]?.map((oracle) => oracle.toLowerCase());\n if (!allowedOracles || allowedOracles.length === 0) {\n return { message: `No allowed oracles for chain ${offer.chainId}` };\n }\n if (\n offer.collaterals.some(\n (collateral) => !allowedOracles.includes(collateral.oracle.toLowerCase()),\n )\n ) {\n return { message: \"Oracle is not allowed\" };\n }\n return undefined;\n },\n );\n\n/**\n * A batch validation rule that ensures all offers in a tree have the same maker address.\n * Returns an issue only for the first non-conforming offer.\n * This rule is signing-agnostic; signer verification is handled at the collector level.\n */\nexport const sameMaker = () =>\n batch(\n \"mixed_maker\",\n \"Validates that all offers in a batch have the same maker address\",\n (offers: Offer.Offer[]) => {\n const issues = new Map<\n number,\n Omit<Validation.Issue<Offer.Offer, \"mixed_maker\">, \"ruleName\" | \"item\"> | undefined\n >();\n\n if (offers.length === 0) return issues;\n\n const firstMaker = offers[0]!.maker.toLowerCase();\n\n for (let i = 1; i < offers.length; i++) {\n const offer = offers[i]!;\n if (offer.maker.toLowerCase() !== firstMaker) {\n issues.set(i, {\n message: `Offer has different maker ${offer.maker} than first offer ${offers[0]!.maker}`,\n });\n // Return only the first non-conforming offer\n // tree should be dropped entirely when only one offer is invalid\n return issues;\n }\n }\n\n return issues;\n },\n );\n\n/**\n * A validation rule that ensures mutual exclusivity of offer amount fields.\n * At most one of (assets, obligationUnits, obligationShares) can be non-zero.\n * Matches contract requirement: `atMostOneNonZero(offer.assets, offer.obligationUnits, offer.obligationShares)`.\n */\nexport const amountMutualExclusivity = () =>\n single(\n \"amount_mutual_exclusivity\",\n \"Validates that at most one of (assets, obligationUnits, obligationShares) is non-zero\",\n (offer: Offer.Offer) => {\n if (!BigMath.atMostOneNonZero(offer.assets, offer.obligationUnits, offer.obligationShares)) {\n return {\n message:\n \"Inconsistent offer input: at most one of (assets, obligationUnits, obligationShares) must be non-zero\",\n };\n }\n },\n );\n","import type { Address } from \"viem\";\nimport * as Callback from \"../core/Callback.ts\";\nimport type * as Chain from \"../core/Chain.ts\";\nimport * as Maturity from \"../core/Maturity.ts\";\nimport * as GateConfig from \"./GateConfig.ts\";\nimport * as Rules from \"./Rules.ts\";\n\nexport const morphoRules = (chains: Chain.Chain[]) => {\n const assetsByChainId: Partial<Record<Chain.Id, Address[]>> = {};\n const oraclesByChainId: Partial<Record<Chain.Id, Address[]>> = {};\n for (const chain of chains) {\n assetsByChainId[chain.id] = GateConfig.assets[chain.id.toString()] ?? [];\n oraclesByChainId[chain.id] = GateConfig.oracles[chain.id.toString()] ?? [];\n }\n\n return [\n Rules.sameMaker(),\n Rules.amountMutualExclusivity(),\n Rules.chains({ chains }),\n Rules.maturity({\n maturities: [Maturity.MaturityType.EndOfMonth, Maturity.MaturityType.EndOfNextMonth],\n }),\n Rules.callback({\n callbacks: [Callback.Type.BuyWithEmptyCallback, Callback.Type.SellWithEmptyCallback],\n allowedAddresses: [],\n }),\n Rules.token({ assetsByChainId }),\n Rules.oracle({ oraclesByChainId }),\n ];\n};\n","import {\n type Address,\n decodeAbiParameters,\n type Hex,\n type PublicClient,\n publicActions,\n type WalletClient as ViemClient,\n zeroAddress,\n} from \"viem\";\nimport type { Compute } from \"#core\";\nimport { Chain, Offer, Tree } from \"#core\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport type * as Client from \"./MempoolClient.ts\";\n\nconst DEFAULT_BATCH_SIZE = 100;\n\ntype MempoolEVMClientConfig = {\n readonly client: ViemClient;\n readonly mempoolAddress: Address;\n readonly morphoAddress?: Address;\n readonly blockWindow?: number;\n};\n\nexport function from(parameters: from.Parameters): from.ReturnType {\n const config: MempoolEVMClientConfig = {\n client: parameters.client,\n mempoolAddress: parameters.mempoolAddress,\n morphoAddress: parameters.morphoAddress,\n blockWindow: parameters.blockWindow,\n };\n\n return {\n add: (parameters) => add(config, parameters),\n get: (parameters) => get(config, parameters),\n stream: (parameters) => streamOffers(config, parameters),\n };\n}\n\nexport declare namespace from {\n type Parameters = {\n /** The viem client to use. */\n client: ViemClient;\n /** The mempool address. */\n mempoolAddress: Address;\n /** The MorphoV2 contract address used for signature verification. */\n morphoAddress?: Address;\n /** The block window to use for the mempool. Defaults to 100. */\n blockWindow?: number;\n };\n\n type ReturnType = Client.Client;\n\n type ErrorType = null;\n}\n\n/**\n * Add an offer to the mempool.\n * @returns The created offer with its hash.\n * @throws WalletAccountNotSetError if the wallet account is not set.\n * @throws ViemClientError if the viem client throws an error.\n * @throws Offer.InvalidOfferError if the offer is invalid.\n */\nexport async function add(\n config: MempoolEVMClientConfig,\n offers: Client.AddParameters,\n): Promise<Hex> {\n if (!config.client.account) throw new WalletAccountNotSetError();\n\n const tree = Tree.from(offers.map((o) => Offer.from(o)));\n const chainId = await getChainId(config.client);\n for (const offer of tree.offers) {\n if (chainId !== offer.chainId) throw new ChainIdMismatchError(offer.chainId, chainId);\n }\n\n const signatureDomain = resolveSignatureDomain(config, chainId);\n const signature = await config.client.signTypedData({\n account: config.client.account,\n domain: Tree.signatureDomain(signatureDomain),\n types: Tree.signatureTypes,\n primaryType: \"Root\",\n message: { root: tree.root },\n });\n const encoded = await Tree.encode(tree, signature, signatureDomain);\n try {\n return await config.client.sendTransaction({\n chain: config.client.chain,\n account: config.client.account!,\n to: config.mempoolAddress,\n data: encoded,\n });\n } catch (error) {\n throw new ViemClientError(error instanceof Error ? error.message : \"Unknown error\");\n }\n}\n\nexport declare namespace add {\n export type ErrorType =\n | WalletAccountNotSetError\n | ViemClientError\n | Offer.InvalidOfferError\n | ChainIdMismatchError\n | MissingMorphoAddressError;\n}\n\nexport async function* get(\n config: MempoolEVMClientConfig,\n parameters?: Client.GetParameters,\n): AsyncGenerator<{ offers: Offer.Offer[]; blockNumber: number }, void, void> {\n const {\n loanToken,\n blockNumberGte,\n blockNumberLte,\n order = \"desc\",\n options: { maxBatchSize = DEFAULT_BATCH_SIZE } = {},\n } = parameters || {};\n\n yield* streamOffers(config, {\n loanToken,\n order,\n blockNumberGte,\n blockNumberLte,\n options: { maxBatchSize, blockWindow: config.blockWindow },\n });\n}\n\nexport declare namespace get {\n export type ErrorType = streamOffersReturnType;\n}\n\nconst chainIdCache = new Map<string, Chain.Id>();\n/**\n * Caches the chain id of a viem client.\n * @param client - The viem client.\n * @returns The chain id.\n */\nconst getChainId = async (client: ViemClient): Promise<Chain.Id> => {\n if (chainIdCache.has(client.uid)) return chainIdCache.get(client.uid)!;\n const chainId = await client.getChainId();\n chainIdCache.set(client.uid, chainId as Chain.Id);\n return chainId as Chain.Id;\n};\n\ntype streamOffersReturnType =\n | WalletAccountNotSetError\n | ChainIdMismatchError\n | MissingMorphoAddressError;\n\nasync function* streamOffers(\n config: MempoolEVMClientConfig,\n parameters: Compute<\n Omit<Client.GetParameters, \"options\"> & {\n options: Client.GetParameters[\"options\"] & { blockWindow?: number };\n }\n >,\n): AsyncGenerator<{ offers: Offer.Offer[]; blockNumber: number }, void, void> {\n const {\n loanToken,\n blockNumberGte,\n blockNumberLte,\n order = \"desc\",\n options: { maxBatchSize = DEFAULT_BATCH_SIZE, blockWindow = config.blockWindow } = {},\n } = parameters;\n\n const signatureDomain = resolveSignatureDomain(config, await getChainId(config.client));\n\n const stream = Chain.streamLogs({\n client: config.client.extend(publicActions) as PublicClient,\n contractAddress: config.mempoolAddress,\n event: {\n type: \"event\",\n name: \"Event\",\n inputs: [{ name: \"data\", type: \"bytes\", indexed: false, internalType: \"bytes\" }],\n anonymous: false,\n } as const,\n blockNumberGte,\n blockNumberLte,\n order,\n options: { maxBatchSize, blockWindow },\n });\n\n let blockNumber = order === \"asc\" ? blockNumberGte : blockNumberLte;\n for await (const { logs, blockNumber: newBlockNumber } of stream) {\n blockNumber = newBlockNumber;\n if (logs.length === 0) continue;\n\n const offers: Offer.Offer[] = [];\n for (const log of logs) {\n if (!log) continue;\n const [payload] = decodeAbiParameters([{ type: \"bytes\" }], log.data);\n try {\n const { tree } = await Tree.decode(payload, signatureDomain);\n for (const offer of tree.offers) {\n if (loanToken && offer.loanToken.toLowerCase() !== loanToken.toLowerCase()) continue;\n offers.push(offer);\n }\n } catch (_) {}\n }\n\n yield {\n offers,\n blockNumber,\n };\n }\n\n yield { offers: [], blockNumber: blockNumber! };\n return;\n}\n\nexport class WalletAccountNotSetError extends Errors.BaseError {\n override name = \"Mempool.WalletAccountNotSetError\";\n constructor() {\n super(\"Wallet account is not set.\");\n }\n}\n\nexport class ViemClientError extends Errors.BaseError {\n override name = \"Mempool.ViemClientError\";\n}\n\nexport class ChainIdMismatchError extends Errors.BaseError {\n override name = \"Mempool.ChainIdMismatchError\";\n constructor(expected: Chain.Id, actual: Chain.Id) {\n super(`Chain ID mismatch. Offer chain ID is ${expected}, network chain ID is ${actual}.`);\n }\n}\n\nconst resolveSignatureDomain = (\n config: MempoolEVMClientConfig,\n chainId: Chain.Id,\n): Tree.SignatureDomain => {\n const chain = config.client.chain as Chain.Chain | undefined;\n const verifyingContract =\n config.morphoAddress ??\n chain?.custom?.morpho?.address ??\n Chain.getChain(chainId)?.custom.morpho.address;\n if (!verifyingContract || verifyingContract.toLowerCase() === zeroAddress) {\n throw new MissingMorphoAddressError();\n }\n return { chainId, verifyingContract };\n};\n\nexport class MissingMorphoAddressError extends Errors.BaseError {\n override name = \"Mempool.MissingMorphoAddressError\";\n constructor() {\n super(\"Morpho address is required to verify root signatures (zero address is invalid).\");\n }\n}\n","import type { Hex } from \"viem\";\nimport type { Compute, Offer } from \"#core\";\nimport * as EVMClient from \"./MempoolEVMClient.ts\";\n\nexport type AddParameters = Compute<Omit<Offer.Offer, \"createdAt\">[]>;\n\nexport type GetParameters = {\n /** The block number to get offers from. */\n blockNumberGte?: number;\n /** The block number to get offers to. */\n blockNumberLte?: number;\n /** The loan asset to get offers from. */\n loanToken?: string;\n /** The order to get offers. Defaults to \"desc\". */\n order?: \"asc\" | \"desc\";\n /** The options to get offers from. */\n options?: {\n /** The maximum number of offers to return. Defaults to 100. Maximum is 1000. */\n maxBatchSize?: number;\n };\n};\n\n/**\n * Mempool client interface.\n */\nexport type Client = {\n /**\n * Add an offer to the mempool.\n * @returns The created offer with its hash.\n */\n add: (parameters: AddParameters) => Promise<Hex>;\n /** Get offers from the mempool. */\n get: (parameters?: GetParameters) => AsyncGenerator<{\n offers: Offer.Offer[];\n /** The block number of the last processed offer. Depends on the `order` parameter, block numbers will ascend or descend. */\n blockNumber: number;\n }>;\n\n /**\n * Stream offers from the mempool.\n * @returns A generator of offers alongside the last block number processed.\n */\n stream: (\n parameters: Compute<\n Omit<GetParameters, \"options\"> & {\n options: GetParameters[\"options\"] & { blockWindow?: number };\n }\n >,\n ) => AsyncGenerator<{\n offers: Offer.Offer[];\n blockNumber: number;\n }>;\n};\n\n/**\n * Client to interact with the Mempool contract on a specific chain.\n */\nexport function connect(parameters: EVMClient.from.Parameters): Client {\n return EVMClient.from(parameters);\n}\n\nexport declare namespace connect {\n export type ErrorType = EVMClient.from.ErrorType;\n}\n","export * from \"./MempoolClient.ts\";\nexport * from \"./MempoolEVMClient.ts\";\n"],"mappings":"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CA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;;;ACVF,MAAa,oBAAoB,SAAS,CACxC,uLACA,qDACD,CAAC;;;;ACHF,MAAa,WAAW,SAAS;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;;;;;;;;;;;ACjDF,MAAa,SAAS,CACpB;CACE,MAAM;CACN,MAAM;CACN,QAAQ,EAAE;CACV,SAAS,CAAC;EAAE,MAAM;EAAI,MAAM;EAAW,CAAC;CACxC,iBAAiB;CAClB,CACF;AAED,MAAa,UAAU,CACrB;CACE,MAAM;CACN,MAAM;CACN,QAAQ,EAAE;CACV,SAAS,CAAC;EAAE,MAAM;EAAI,MAAM;EAAW,CAAC;CACxC,iBAAiB;CAClB,CACF;AAED,MAAa,SAAS;CACpB;EACE,MAAM;EACN,MAAM;EACN,QAAQ;GACN;IACE,MAAM;IACN,MAAM;IACN,cAAc;IACf;GACD;IACE,MAAM;IACN,MAAM;IACN,cAAc;IACf;GACD;IACE,MAAM;IACN,MAAM;IACN,cAAc;IACf;GACF;EACD,SAAS,CACP;GACE,MAAM;GACN,MAAM;GACN,cAAc;GACf,CACF;EACD,iBAAiB;EAClB;CACD;EACE,MAAM;EACN,MAAM;EACN,QAAQ,CACN;GACE,MAAM;GACN,MAAM;GACN,cAAc;GACf,EACD;GACE,MAAM;GACN,MAAM;GACN,cAAc;GACf,CACF;EACD,SAAS,CACP;GACE,MAAM;GACN,MAAM;GACN,cAAc;GACf,CACF;EACD,iBAAiB;EAClB;CACD;EACE,MAAM;EACN,MAAM;EACN,QAAQ,CACN;GACE,MAAM;GACN,MAAM;GACN,cAAc;GACf,CACF;EACD,SAAS;GACP;IACE,MAAM;IACN,MAAM;IACN,c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"}
|
|
1
|
+
{"version":3,"file":"index.node.mjs","names":["max","batch","batch","toSnakeCase","fromSnakeCase","create","Logger.getLogger","Utils.retry","create","Admin.create","Logger.getLogger","Tracer.getTracer","Tracer.startActiveSpan","Utils.wait","Type","chains","viemEthereum","viemBase","viemAnvil","DEFAULT_BATCH_SIZE","BigMath.min","BigMath.max","batch","Errors.BaseError","create","z","from","InvalidOptionError","Errors.BaseError","z","z","LLTV.LLTVSchema","from","LLTV.from","random","Random.address","Errors.BaseError","z","from","Errors.BaseError","z","Collateral.CollateralsSchema","Maturity.MaturitySchema","from","Maturity.from","fromSnakeCase","Format.fromSnakeCase","random","Random.address","Collateral.random","fromOffer","Errors.BaseError","z","Maturity.MaturitySchema","Collateral.CollateralsSchema","from","fromSnakeCase","Format.fromSnakeCase","Format.toSnakeCase","random","Random.int","Random.address","Maturity.from","LLTV.from","Random.bool","Random.hex","Collateral.random","Random.float","Obligation.id","Obligation.from","encode","decode","Collateral.from","Errors.BaseError","from","from","WAD","Errors.BaseError","z","Tick.TICK_RANGE","from","Format.fromSnakeCase","Obligation.id","Obligation.random","Random.int","Errors.BaseError","Tick.tickToPrice","from","Errors.BaseError","from","VERSION","from","Offer.hash","Offer.serialize","Offer.OfferSchema","Errors.BaseError","oracles","Position.Type","Offer.Status","chains","Logger.getLogger","Chain.streamLogs","Offer.consumedEvent","Offer.takeEvent","groups","consumedEventsTable","groupsTable","Logger.getLogger","Chain.streamLogs","Tree.decode","Tree.DecodeError","Callback.isEmptyCallback","Position.from","Offer.obligationId","Offer.hash","obligationId","Obligation.from","Oracle.from","hash","Utils.batch","Abi.Oracle","Utils.batchMulticall","Utils.batchMulticall","Logger.getLogger","Abi.MetaMorpho","ERC4626.convertToAssets","ERC4626.DenominatorIsZeroError","Utils.batchMulticall","Logger.getLogger","Chain.streamLogs","Transfer.from","Errors.ReorgError","Fetchers.snapshotVaultPositions","Fetchers.snapshotERC20Positions","Errors.BaseError","Logger.getLogger","Errors.ReorgError","Collector.create","CollectFunctions.collectOffersV2","CollectFunctions.collectConsumedEvents","CollectFunctions.collectPrices","CollectFunctions.collectPositions","from","CollectorBuilder.createBuilder","from","Collectors.from","create","Tracer.getTracer","Tracer.startActiveSpan","Collector.start","create","Collector.names","from","Tick.tickToPrice","from","from","Obligation.id","BadRequestError","z","Payload.API_ERROR_CODES","from","DEFAULT_LIMIT","z","Logger.getLogger","ApiSchema.safeParse","ApiPayload.failure","ApiPayload.success","ApiSchema.BookResponse.from","ApiSchema.safeParse","ApiPayload.failure","ApiPayload.InternalServerError","parseCursor","findStartIndex","formatCursor","ApiPayload.success","ApiPayload.BadRequestError","GateConfig.configs","Maturity.from","GateConfig.assets","GateConfig.collateralAssets","oracles","GateConfig.oracles","ApiSchema.safeParse","ApiPayload.failure","ApiPayload.BadRequestError","ApiPayload.success","Maturity.MaturityType","Maturity.from","Callback.Type","Logger.getLogger","Schema.safeParse","ApiPayload.failure","Health.create","ApiPayload.APIError","Format.toSnakeCase","ApiPayload.success","DEFAULT_LIMIT","create","now","Time.now","obligationsTable","obligationCollateralsTable","offersTable","groupsTable","validationsTable","statusTable","oraclesTable","Obligation.from","Collateral.from","LLTV.from","Quote.from","toPayloadError","ObligationsListingReader.BadRequestError","ApiPayload.BadRequestError","Logger.getLogger","ApiSchema.safeParse","ApiPayload.failure","ApiPayload.NotFoundError","ApiPayload.success","ApiSchema.ObligationResponse.from","ObligationsListingReader.BadRequestError","ApiPayload.BadRequestError","getObligations","Logger.getLogger","ApiSchema.safeParse","ApiPayload.failure","ApiPayload.success","ApiSchema.ObligationResponse.from","DEFAULT_BATCH_SIZE","DEFAULT_LIMIT","create","Offer.serialize","Offer.obligationId","Utils.batch","DEFAULT_BATCH_SIZE","offersTable","obligationCollateralsTable","oraclesTable","obligationsTable","Maturity.from","now","Time.now","groupsTable","validationsTable","statusTable","Quote.from","OffersDomain.DEFAULT_LIMIT","obligationCollateralsTable","oraclesTable","offersTable","positionsTable","offsetsTable","callbacksTable","lotsTable","groupsTable","offersCallbacksTable","obligationsTable","Maturity.from","getOffers","Logger.getLogger","ApiSchema.safeParse","ApiPayload.failure","ApiPayload.success","hash","Offer.hash","ApiSchema.OfferResponse.from","Logger.getLogger","ApiSchema.safeParse","ApiPayload.failure","ApiPayload.success","ApiSchema.PositionResponse.from","Logger.getLogger","ApiSchema.safeParse","ApiPayload.failure","ApiPayload.BadRequestError","Offer.fromSnakeCase","hash","Offer.hash","Offer.InvalidOfferError","ApiPayload.success","Tree.from","Tree.encodeUnsigned","from","create","serve","Tracer.getTracer","Tracer.startActiveSpan","Controllers.getOffers","Controllers.getObligations","Controllers.getObligation","Controllers.getBook","failure","ApiPayload.failure","Controllers.getUserPositions","Controllers.getHealth","Controllers.getHealthCollectors","Controllers.getHealthChains","Controllers.getConfigContracts","Controllers.getSwaggerJson","Controllers.getDocsHtml","Controllers.getIntegratorDocsHtml","connect","Offer.fromSnakeCase","Maturity.from","Obligation.fromSnakeCase","Obligation.id","Quote.from","Errors.BaseError","create","chains","Collector.names","DEFAULT_LIMIT","create","Logger.getLogger","obligationCollateralsTable","oraclesTable","offersTable","validationsTable","statusTable","groupsTable","obligationsTable","offsetsTable","lotsTable","offersCallbacksTable","callbacksTable","positionsTable","create","Utils.batch","DEFAULT_BATCH_SIZE","callbacksTable","offersCallbacksTable","create","groups","Utils.batch","DEFAULT_BATCH_SIZE","groupsTable","consumedEventsTable","create","groups","Utils.batch","DEFAULT_BATCH_SIZE","groupsTable","create","lotsTable","create","now","Time.now","obligationsTable","obligationCollateralsTable","oraclesTable","Obligation.from","Collateral.from","LLTV.from","obligations","id","Obligation.id","Utils.batch","DEFAULT_BATCH_SIZE","create","offsetsTable","create","oraclesTable","Oracle.from","Utils.batch","DEFAULT_BATCH_SIZE","DEFAULT_LIMIT","create","positions","Position.Type","Utils.batch","DEFAULT_BATCH_SIZE","positionsTable","offsetsTable","lotsTable","groupsTable","offersTable","transfersTable","create","transfers","Utils.batch","DEFAULT_BATCH_SIZE","transfersTable","positionsTable","create","trees","treesTable","Tree.proofs","Offer.hash","Utils.batch","DEFAULT_BATCH_SIZE","merklePathsTable","create","validationsTable","statusTable","status","Offer.Status","Utils.batch","DEFAULT_BATCH_SIZE","BookDomain.create","BlocksDomain.create","CallbacksDomain.create","OffersDomain.create","ConsumedDomain.create","GroupsDomain.create","LotsDomain.create","ObligationsDomain.create","OffsetsDomain.create","OraclesDomain.create","TreesDomain.create","ValidationsDomain.create","PositionsDomain.create","TransfersDomain.create","ObligationsListingReader.create","connect","offersSchema","drizzleLite","Tracer.getTracer","Tracer.startActiveSpan","migratePostgres","migratePGLite","OfferCore.toSnakeCase","Gate.run","Maturity.from","Callback.isEmptyCallback","BigMath.atMostOneNonZero","chains","GateConfig.assets","GateConfig.collateralAssets","GateConfig.oracles","Rules.sameMaker","Rules.amountMutualExclusivity","Rules.chains","Rules.maturity","Rules.callback","Rules.loanToken","Rules.collateralToken","Rules.oracle","Tree.from","Offer.from","signatureDomain","Tree.signatureDomain","Tree.signatureTypes","Tree.encode","Chain.streamLogs","Tree.decode","Errors.BaseError","Chain.getChain","EVMClient.from"],"sources":["../src/logger/Logger.ts","../src/tracer/Tracer.ts","../src/utils/BigMath.ts","../src/utils/batch.ts","../src/utils/retry.ts","../src/utils/batchMulticall.ts","../src/utils/Errors.ts","../src/utils/Format.ts","../src/utils/Group.ts","../src/utils/lazy.ts","../src/utils/wait.ts","../src/utils/poll.ts","../src/utils/Random.ts","../src/utils/time.ts","../src/utils/index.ts","../src/indexer/collectors/Admin.ts","../src/indexer/collectors/Collector.ts","../src/core/Abi/MetaMorpho.ts","../src/core/Abi/MetaMorphoFactory.ts","../src/core/Abi/MorphoV2.ts","../src/core/Abi/index.ts","../src/core/Callback.ts","../src/core/Chain.ts","../src/core/ChainRegistry.ts","../src/utils/zod.ts","../src/core/LLTV.ts","../src/core/Collateral.ts","../src/core/ERC4626.ts","../src/core/Liquidity.ts","../src/core/Maturity.ts","../src/core/Obligation.ts","../src/core/Offer.ts","../src/core/Oracle.ts","../src/core/Position.ts","../src/core/Tick.ts","../src/core/Quote.ts","../src/core/TradingFee.ts","../src/core/Transfer.ts","../src/core/Tree.ts","../src/core/types.ts","../src/database/drizzle/VERSION.ts","../src/database/drizzle/schema.ts","../src/indexer/collectors/CollectFunctions/collectConsumedEvents.ts","../src/indexer/collectors/CollectFunctions/collectOffers.ts","../src/indexer/collectors/fetchers/fetchOraclePrices.ts","../src/indexer/collectors/fetchers/snapshotERC20Positions.ts","../src/indexer/collectors/fetchers/snapshotVaultPositions.ts","../src/indexer/collectors/CollectFunctions/collectPositions.ts","../src/indexer/collectors/CollectFunctions/collectPrices.ts","../src/indexer/collectors/CollectorBuilder.ts","../src/indexer/collectors/Collectors.ts","../src/indexer/Indexer.ts","../src/api/Health.ts","../src/api/Schema/BookResponse.ts","../src/api/Schema/health.ts","../src/api/Schema/ObligationResponse.ts","../src/api/Schema/OfferResponse.ts","../src/api/Controllers/Payload.ts","../src/api/Schema/openapi.ts","../src/api/Schema/PositionResponse.ts","../src/api/Schema/requests.ts","../src/api/Controllers/getBook.ts","../src/api/Controllers/getConfigContracts.ts","../src/gatekeeper/GateConfig.ts","../src/gatekeeper/ConfigRules.ts","../src/api/Controllers/getConfigRules.ts","../src/api/Controllers/getDocs.ts","../src/api/Controllers/getHealth.ts","../src/database/readers/ObligationsListing.ts","../src/api/Controllers/getObligation.ts","../src/api/Controllers/getObligations.ts","../src/database/constants.ts","../src/database/domains/Offers.ts","../src/api/Controllers/getOffers.ts","../src/api/Controllers/getUserPositions.ts","../src/api/Controllers/validateOffers.ts","../src/api/Controllers/index.ts","../src/api/Api.ts","../src/api/RouterApi.ts","../src/client/Client.ts","../src/database/drizzle/index.ts","../src/database/domains/Blocks.ts","../src/database/domains/Book.ts","../src/database/domains/Callbacks.ts","../src/database/domains/Consumed.ts","../src/database/domains/Groups.ts","../src/database/domains/Lots.ts","../src/database/domains/Obligations.ts","../src/database/domains/Offsets.ts","../src/database/domains/Oracles.ts","../src/database/domains/Positions.ts","../src/database/domains/Transfers.ts","../src/database/domains/Trees.ts","../src/database/domains/Validations.ts","../src/database/Database.ts","../src/gatekeeper/Client.ts","../src/gatekeeper/Gate.ts","../src/gatekeeper/Gatekeeper.ts","../src/gatekeeper/Rules.ts","../src/gatekeeper/morphoRules.ts","../src/mempool/MempoolEVMClient.ts","../src/mempool/MempoolClient.ts","../src/mempool/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { stringify } from \"viem\";\nimport type { Compute } from \"#core\";\n\nexport const LogLevelValues = [\n \"trace\",\n \"debug\",\n \"info\",\n \"warn\",\n \"error\",\n \"fatal\",\n \"silent\",\n] as const;\nexport type LogLevel = (typeof LogLevelValues)[number];\ntype ActiveLogLevel = Exclude<LogLevel, \"silent\">;\n\nexport type LogEntry = Compute<{ msg: string } & Record<string, unknown>>;\nexport type LogFn = (entry: LogEntry) => void;\n\nexport type Logger = {\n trace: LogFn;\n debug: LogFn;\n info: LogFn;\n warn: LogFn;\n error: LogFn;\n fatal: LogFn;\n};\n\nexport function defaultLogger(minLevel?: LogLevel, pretty?: boolean): Logger {\n const threshold: LogLevel = minLevel ?? (process.env.ROUTER_LOG_LEVEL as LogLevel) ?? \"info\";\n const prettyEnabled: boolean =\n typeof pretty === \"boolean\"\n ? pretty\n : String(process.env.ROUTER_LOG_PRETTY ?? \"false\").toLowerCase() === \"true\";\n\n const levelIndexByName: Record<LogLevel, number> = LogLevelValues.reduce(\n (acc, lvl, idx) => {\n acc[lvl] = idx;\n return acc;\n },\n {} as Record<LogLevel, number>,\n );\n\n const isEnabled = (methodLevel: LogLevel): boolean =>\n levelIndexByName[methodLevel] >= levelIndexByName[threshold];\n\n const wrap = <L extends ActiveLogLevel>(\n consoleMethod: \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\",\n methodLevel: L,\n ): LogFn =>\n isEnabled(methodLevel)\n ? (entry: LogEntry) => {\n if (!prettyEnabled) {\n // biome-ignore lint/suspicious/noConsole: console is used for logging\n console[consoleMethod](stringify({ level: methodLevel, ...entry }));\n return;\n }\n\n const { msg, ...rest } = entry;\n const stack =\n typeof (rest as Record<string, unknown>).stack === \"string\"\n ? (rest as Record<string, unknown>).stack\n : undefined;\n if (stack) delete (rest as Record<string, unknown>).stack;\n const timestamp = new Date().toISOString();\n const level = methodLevel.toUpperCase();\n\n const extras: string = Object.entries(rest)\n .map(([k, v]) => `${k}=${formatValue(v)}`)\n .join(\" \");\n\n const line =\n extras.length > 0\n ? `${timestamp} [${level}] ${msg} ${extras}`\n : `${timestamp} [${level}] ${msg}`;\n // biome-ignore lint/suspicious/noConsole: console is used for logging\n console[consoleMethod](line);\n if (stack) {\n // biome-ignore lint/suspicious/noConsole: console is used for logging\n console[consoleMethod](stack);\n }\n }\n : () => {};\n\n return {\n trace: wrap(\"trace\", \"trace\"),\n debug: wrap(\"debug\", \"debug\"),\n info: wrap(\"info\", \"info\"),\n warn: wrap(\"warn\", \"warn\"),\n error: wrap(\"error\", \"error\"),\n fatal: wrap(\"error\", \"fatal\"),\n };\n}\n\nexport function silentLogger(): Logger {\n const noop = (() => {}) as LogFn;\n return { trace: noop, debug: noop, info: noop, warn: noop, error: noop, fatal: noop };\n}\n\nconst loggerContext = new AsyncLocalStorage<Logger>();\n\nexport function runWithLogger<T>(logger: Logger, fn: () => Promise<T>): Promise<T> {\n return loggerContext.run(logger, fn);\n}\n\nexport function getLogger(): Logger {\n return loggerContext.getStore() ?? defaultLogger();\n}\n\nfunction formatValue(value: unknown): string {\n if (\n value === null ||\n value === undefined ||\n typeof value === \"number\" ||\n typeof value === \"bigint\" ||\n typeof value === \"boolean\"\n ) {\n return String(value);\n }\n if (typeof value === \"string\") {\n if (value.includes(\" \")) return JSON.stringify(value);\n return value;\n }\n try {\n return stringify(value as unknown as Record<string, unknown>);\n } catch {\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n }\n}\n","import { type Tracer as OtelTracer, type Span, SpanStatusCode, trace } from \"@opentelemetry/api\";\nimport { OTLPTraceExporter } from \"@opentelemetry/exporter-trace-otlp-proto\";\nimport { AWSXRayIdGenerator } from \"@opentelemetry/id-generator-aws-xray\";\nimport { registerInstrumentations } from \"@opentelemetry/instrumentation\";\nimport { HttpInstrumentation } from \"@opentelemetry/instrumentation-http\";\nimport { PgInstrumentation } from \"@opentelemetry/instrumentation-pg\";\nimport { AWSXRayPropagator } from \"@opentelemetry/propagator-aws-xray\";\nimport { resourceFromAttributes } from \"@opentelemetry/resources\";\nimport { BatchSpanProcessor, NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\";\nimport { ATTR_SERVICE_NAME } from \"@opentelemetry/semantic-conventions\";\n\nexport type Tracer = OtelTracer;\n\nlet provider: NodeTracerProvider | null = null;\n\n/**\n * Instantiates a new tracer for the given service.\n *\n * @param serviceName - The name of the service to trace.\n *\n * @example\n * ```ts\n * Tracer.init(\"router\");\n * ```\n */\nexport function init(serviceName: string): void {\n if (provider) return;\n\n const exporter = new OTLPTraceExporter({\n url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT ?? \"http://localhost:4318/v1/traces\",\n });\n\n const useAwsXRay = (process.env.TRACE_EXPORTER ?? \"otlp\").toLowerCase() === \"xray\";\n\n provider = new NodeTracerProvider({\n resource: resourceFromAttributes({\n [ATTR_SERVICE_NAME]: serviceName,\n }),\n ...(useAwsXRay ? { idGenerator: new AWSXRayIdGenerator() } : {}),\n spanProcessors: [new BatchSpanProcessor(exporter)],\n });\n\n registerInstrumentations({\n tracerProvider: provider,\n instrumentations: [new HttpInstrumentation(), new PgInstrumentation()],\n });\n\n provider.register({\n propagator: useAwsXRay ? new AWSXRayPropagator() : undefined,\n });\n}\n\n/**\n * Returns the existing tracer.\n *\n * @returns The existing tracer. {@link Tracer}\n * @throws If the tracer is not initialized.\n *\n * @example\n * ```ts\n * const tracer = Tracer.getTracer(\"router.api\");\n * tracer.startSpan(\"indexer.next\", async (span) => {\n * span.end();\n * });\n * ```\n */\nexport function getTracer(name: string): Tracer {\n return trace.getTracer(name);\n}\n\n/**\n * Shuts down the tracer.\n *\n * @example\n * ```ts\n * await Tracer.shutdown();\n * ```\n */\nexport async function shutdown(): Promise<void> {\n if (!provider) return;\n await provider.shutdown();\n provider = null;\n}\n\n/**\n * Helper to run a function inside an active span.\n * Takes care of recording exceptions and setting the span status to ERROR.\n * @param tracer - The tracer to use. {@link Tracer}\n * @param name - The name of the span.\n * @param fn - The function to run inside the span.\n * @returns The result of the function.\n *\n * @example\n * ```ts\n * const tracer = Tracer.getTracer(\"router.api\");\n * const result = await Tracer.startActiveSpan(tracer, \"indexer.next\", async (span) => {\n * return await indexer.next();\n * });\n * ```\n */\nexport function startActiveSpan<T>(\n tracer: Tracer,\n name: string,\n fn: (span: Span) => Promise<T> | T,\n): Promise<T> {\n return tracer.startActiveSpan(name, async (span) => {\n try {\n return await fn(span);\n } catch (err) {\n span.recordException(err as Error);\n span.setStatus({ code: SpanStatusCode.ERROR });\n throw err;\n } finally {\n span.end();\n }\n });\n}\n","export function max(a: bigint, b: bigint): bigint {\n return a > b ? a : b;\n}\n\nexport function min(a: bigint, b: bigint): bigint {\n return a < b ? a : b;\n}\n\n/**\n * Checks if at most one of the given values is non-zero.\n * @param values - The bigint values to check.\n * @returns True if zero or one value is non-zero, false if two or more are non-zero.\n */\nexport function atMostOneNonZero(...values: bigint[]): boolean {\n let nonZeroCount = 0;\n for (const value of values) {\n if (value !== 0n) {\n nonZeroCount++;\n if (nonZeroCount > 1) return false;\n }\n }\n return true;\n}\n","/**\n * Splits an array into batches of a specified size.\n * @param array The array to split.\n * @param batchSize The size of each batch.\n * @returns An iterator that yields each batch.\n * @example\n * ```typescript\n * const array = [1, 2, 3, 4, 5];\n * for (const batch of batch(array, 2)) {\n * console.log(batch);\n * }\n * // Output:\n * // [1, 2]\n * // [3, 4]\n * // [5]\n * ```\n */\nexport function* batch<T>(\n array: T[] | readonly T[],\n batchSize: number,\n): Generator<T[], void, unknown> {\n for (let i = 0; i < array.length; i += batchSize) {\n yield array.slice(i, i + batchSize);\n }\n}\n","export const retry = async <T>(fn: () => Promise<T>, attempts = 3, delayMs = 50): Promise<T> => {\n let lastErr: unknown;\n for (let i = 0; i < attempts; i++) {\n try {\n return await fn();\n } catch (err) {\n lastErr = err;\n if (i < attempts - 1) await new Promise((r) => setTimeout(r, delayMs));\n }\n }\n throw lastErr;\n};\n","import type { MulticallParameters, PublicClient, Transport } from \"viem\";\nimport { multicall } from \"viem/actions\";\nimport type { Chain } from \"#core\";\nimport { batch } from \"#utils/batch.ts\";\nimport { retry } from \"#utils/retry.ts\";\n\n/**\n * Helper function to execute multicall in batches with retry logic.\n * Abstracts the common pattern of batching calls, retrying, and collecting results.\n *\n * @param parameters - Configuration for batched multicall\n * @returns Promise resolving to flattened array of results\n */\nexport async function batchMulticall<TResult>(parameters: {\n client: PublicClient<Transport, Chain.Chain>;\n calls: MulticallParameters[\"contracts\"];\n batchSize: number;\n retryAttempts: number;\n retryDelayMs: number;\n blockNumber?: bigint;\n}): Promise<TResult[]> {\n const { client, calls, batchSize, retryAttempts, retryDelayMs, blockNumber } = parameters;\n const results: TResult[] = [];\n\n for (const callsBatch of batch(calls, batchSize)) {\n const batchResults = await retry(\n () =>\n multicall(client, {\n allowFailure: false,\n contracts: callsBatch,\n ...(blockNumber ? { blockNumber } : {}),\n }),\n retryAttempts,\n retryDelayMs,\n );\n results.push(...(batchResults as TResult[]));\n }\n\n return results;\n}\n","export type GlobalErrorType<name extends string = \"Error\"> = Error & {\n name: name;\n};\n\n/**\n * Base error class inherited by all errors thrown by mempool.\n *\n * @example\n * ```ts\n * import { Errors } from 'mempool'\n * throw new Errors.BaseError('An error occurred')\n * ```\n */\nexport class BaseError<cause extends Error | undefined = undefined> extends Error {\n details: string;\n shortMessage: string;\n\n override cause: cause;\n override name = \"BaseError\";\n\n constructor(\n shortMessage: string,\n options: {\n cause?: cause | undefined;\n details?: string | undefined;\n metaMessages?: (string | undefined)[] | undefined;\n } = {},\n ) {\n const details = (() => {\n if (options.cause instanceof BaseError) {\n if (options.cause.details) return options.cause.details;\n if (options.cause.shortMessage) return options.cause.shortMessage;\n }\n if (options.cause && \"details\" in options.cause && typeof options.cause.details === \"string\")\n return options.cause.details;\n if (options.cause?.message) return options.cause.message;\n return options.details!;\n })();\n\n const message = [\n shortMessage || \"An error occurred.\",\n ...(options.metaMessages ? [\"\", ...options.metaMessages] : []),\n ...(details ? [\"\", details ? `Details: ${details}` : undefined] : []),\n ]\n .filter((x) => typeof x === \"string\")\n .join(\"\\n\");\n\n super(message, options.cause ? { cause: options.cause } : undefined);\n\n this.cause = options.cause as cause;\n this.details = details;\n this.shortMessage = shortMessage;\n }\n\n walk(): Error;\n walk(fn: (err: unknown) => boolean): Error | null;\n walk(fn?: ((err: unknown) => boolean) | undefined): unknown {\n return walk(this, fn);\n }\n}\n\n/** @internal */\nfunction walk(err: unknown, fn?: ((err: unknown) => boolean) | undefined): unknown {\n if (fn?.(err)) return err;\n if (err && typeof err === \"object\" && \"cause\" in err && err.cause) return walk(err.cause, fn);\n return fn ? null : err;\n}\n\nexport class ReorgError extends BaseError {\n override name = \"ReorgError\";\n constructor(blockNumber: number) {\n super(`Reorg detected at block number ${blockNumber}`);\n }\n}\n","import { getAddress, isAddress } from \"viem\";\n\n/** The snake case representation of a type with bigint values stringified. */\nexport type Snake<T> = DeepMutable<SnakeKeys<StringifiedBigint<T>>>;\n\n/** Make arrays/tuples and object props mutable, deeply. */\ntype DeepMutable<T> =\n // leave functions/primitives as-is\n T extends (...args: unknown[]) => unknown\n ? T\n : T extends number | string | boolean | symbol | bigint | null | undefined\n ? T\n : // handle tuples first (preserve length/element types)\n T extends readonly [...infer R]\n ? { -readonly [K in keyof R]: DeepMutable<R[K]> }\n : // then general readonly arrays\n T extends ReadonlyArray<infer U>\n ? Array<DeepMutable<U>>\n : // then objects: strip readonly from props and recurse\n T extends object\n ? { -readonly [K in keyof T]: DeepMutable<T[K]> }\n : T;\n\n/** Stringifies bigint values to strings and preserves branded primitives. */\ntype StringifiedBigint<T> =\n // non-distributive check so that `bigint & Brand<...>` is still caught here\n [T] extends [bigint]\n ? string\n : [T] extends [`0x${string}`]\n ? string\n : // Preserve branded primitives by matching the primitive first.\n T extends number\n ? T\n : T extends string\n ? T\n : T extends boolean\n ? T\n : T extends symbol\n ? T\n : T extends null | undefined\n ? T\n : T extends readonly (infer U)[]\n ? readonly StringifiedBigint<U>[]\n : T extends object\n ? { [K in keyof T]: StringifiedBigint<T[K]> }\n : T;\n\n/** Key remapping that also preserves branded primitives. */\ntype SnakeKeys<T> = T extends readonly (infer U)[]\n ? readonly SnakeKeys<U>[]\n : T extends number | string | boolean | symbol | null | undefined\n ? T\n : T extends object\n ? { [K in keyof T as ToSnakeCase<Extract<K, string>>]: SnakeKeys<T[K]> }\n : T;\n\ntype ToSnakeCase<S extends string> = S extends `${infer Head}${infer Tail}`\n ? Tail extends Uncapitalize<Tail>\n ? `${Lowercase<Head>}${ToSnakeCase<Tail>}`\n : `${Lowercase<Head>}_${ToSnakeCase<Uncapitalize<Tail>>}`\n : S;\n\n/**\n * Formats object keys to snake case.\n * Preserves ethereum addresses as is.\n * Converts ethereum addresses to checksummed if used as values.\n * Stringifies bigint values to strings.\n */\nexport function toSnakeCase<T>(obj: T): Snake<T> {\n return stringifyBigint(\n processObject(\n obj,\n (s: string) => s.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`),\n (value: unknown) =>\n typeof value === \"string\" && isAddress(value.toLowerCase())\n ? getAddress(value.toLowerCase())\n : value,\n ),\n ) as Snake<T>;\n}\n\n/**\n * Formats a snake case object to its camel case type.\n * Preserves ethereum addresses as is.\n * Converts checksummed ethereum addresses to lowercase if used as values.\n * @warning Does not unstringify bigint values.\n */\nexport function fromSnakeCase<T>(obj: Snake<T>): T {\n return processObject(\n obj,\n (s: string) =>\n isAddress(s.toLowerCase()) ? s : s.replace(/_([a-z])/g, (_, c) => c.toUpperCase()),\n (value: unknown) =>\n typeof value === \"string\" && isAddress(value.toLowerCase()) ? value.toLowerCase() : value,\n ) as T;\n}\n\nfunction processObject<T>(\n obj: T,\n fnKey: (str: string) => string,\n fnValue: (value: unknown) => unknown,\n): unknown {\n if (typeof obj !== \"object\" || obj === null) return obj;\n\n if (Array.isArray(obj)) return obj.map((item) => processObject(item, fnKey, fnValue));\n\n return Object.entries(obj as Record<string, unknown>).reduce(\n (acc, [key, value]) => {\n const newKey = fnKey(key);\n acc[newKey] =\n typeof value === \"object\" && value !== null\n ? processObject(value, fnKey, fnValue)\n : fnValue(value);\n\n return acc;\n },\n {} as Record<string, unknown>,\n );\n}\n\nexport function stringifyBigint<T>(value: T): StringifiedBigint<T> {\n if (typeof value === \"bigint\") return value.toString() as StringifiedBigint<T>;\n if (Array.isArray(value)) return value.map(stringifyBigint) as StringifiedBigint<T>;\n if (value && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) {\n out[k] = stringifyBigint(v);\n }\n return out as StringifiedBigint<T>;\n }\n\n return value as StringifiedBigint<T>;\n}\n","import { type Hex, pad } from \"viem\";\n\n/**\n * Creates a bytes32 group identifier from a number.\n * @param n - A non-negative integer.\n * @throws {Error} If n is negative or not an integer.\n */\nexport const fromNumber = (n: number): Hex => {\n if (!Number.isInteger(n)) {\n throw new Error(`Group.fromNumber: expected integer, got ${n}`);\n }\n if (n < 0) {\n throw new Error(`Group.fromNumber: expected non-negative, got ${n}`);\n }\n return pad(`0x${n.toString(16)}`, { size: 32 });\n};\n","/**\n * Transform a polling function into an async generator.\n * @param fn - The polling function to transform.\n * @returns An async generator.\n */\nexport function lazy<T>(\n pollFn: (emit: (value: T) => void, { stop }: { stop: () => void }) => () => boolean,\n) {\n return () =>\n (async function* () {\n let active = true;\n let resolveNext: (() => void) | null = null;\n const queue: T[] = [];\n\n const wait = () =>\n new Promise<void>((resolve) => {\n resolveNext = resolve;\n });\n\n const emit = (item: T) => {\n queue.push(item);\n resolveNext?.();\n resolveNext = null;\n };\n\n let unpoll: (() => boolean) | null = null;\n const stop = () => {\n active = false;\n // stop the poller immediately if we already have it\n unpoll?.();\n resolveNext?.();\n resolveNext = null;\n };\n\n unpoll = pollFn(emit, { stop });\n\n try {\n while (active) {\n if (queue.length === 0) await wait();\n while (queue.length > 0 && active) yield queue.shift()!;\n }\n } finally {\n stop();\n }\n })();\n}\n","export async function wait(time: number) {\n return new Promise((res) => setTimeout(res, time));\n}\n","import { wait } from \"./wait.ts\";\n/**\n * Polls a function at a specified interval.\n * Inspired by https://github.com/wevm/viem/blob/845994d20275d08ff892018e237a4b599eeefb6a/src/utils/poll.ts\n */\nexport function poll<data>(\n fn: ({ unpoll }: { unpoll: () => void }) => Promise<data | undefined>,\n { interval }: { interval: () => Promise<number> },\n) {\n let active = true;\n const unwatch = () => (active = false);\n\n const watch = async () => {\n while (active) {\n const delay = await interval();\n if (!active) break;\n await wait(delay);\n if (!active) break;\n await fn({ unpoll: unwatch });\n }\n };\n\n watch();\n\n return unwatch;\n}\n","import type { Address, Hex } from \"viem\";\n\ntype Rng = () => number;\n\nlet currentRng: Rng = Math.random;\n\nconst FNV_OFFSET_BASIS = 2166136261;\nconst FNV_PRIME = 16777619;\n\nconst hashSeed = (seed: string): number => {\n let hash = FNV_OFFSET_BASIS;\n for (let i = 0; i < seed.length; i += 1) {\n hash ^= seed.charCodeAt(i);\n hash = Math.imul(hash, FNV_PRIME);\n }\n return hash >>> 0;\n};\n\nconst createSeededRng = (seed: string): Rng => {\n let state = hashSeed(seed);\n return () => {\n state += 0x6d2b79f5;\n let t = Math.imul(state ^ (state >>> 15), state | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n};\n\n/**\n * Runs a function with a deterministic RNG derived from the given seed.\n */\nexport function withSeed<T>(seed: string, fn: () => T): T {\n const previous = currentRng;\n currentRng = createSeededRng(seed);\n try {\n return fn();\n } finally {\n currentRng = previous;\n }\n}\n\n/**\n * Seeds the global RNG for deterministic test runs.\n */\nexport function seed(seed: string): void {\n currentRng = createSeededRng(seed);\n}\n\n/**\n * Returns a deterministic random float in [0, 1).\n */\nexport function float(): number {\n return currentRng();\n}\n\n/**\n * Returns a deterministic random integer in [min, maxExclusive).\n */\nexport function int(maxExclusive: number, min = 0): number {\n return Math.floor(float() * (maxExclusive - min)) + min;\n}\n\n/**\n * Returns a deterministic random boolean.\n */\nexport function bool(probability = 0.5): boolean {\n return float() < probability;\n}\n\n/**\n * Returns deterministic random bytes.\n */\nexport function bytes(length: number): Uint8Array {\n const output = new Uint8Array(length);\n for (let i = 0; i < length; i += 1) {\n output[i] = int(256);\n }\n return output;\n}\n\n/**\n * Returns a deterministic random hex string for the given byte length.\n */\nexport function hex(byteLength: number): Hex {\n const output = bytes(byteLength);\n const hexParts = Array.from(output, (byte) => byte.toString(16).padStart(2, \"0\"));\n return `0x${hexParts.join(\"\")}` as Hex;\n}\n\n/**\n * Returns a deterministic random address.\n */\nexport function address(): Address {\n return hex(20) as Address;\n}\n","export function now(): number {\n return Math.floor(Date.now() / 1000);\n}\n\nexport function max(): number {\n return 8640000000000000000;\n}\n","export * from \"./BigMath.ts\";\nexport * from \"./batch.ts\";\nexport * from \"./batchMulticall.ts\";\nexport * from \"./Errors.ts\";\nexport * from \"./Format.ts\";\nexport * as Group from \"./Group.ts\";\nexport * from \"./lazy.ts\";\nexport * from \"./poll.ts\";\nexport * as Random from \"./Random.ts\";\nexport * from \"./retry.ts\";\nexport * as Time from \"./time.ts\";\nexport * from \"./wait.ts\";\n","import type { Block, Hex, PublicClient, Transport } from \"viem\";\nimport type { Chain } from \"#core\";\nimport type { Database } from \"#database/index.ts\";\nimport { Collector } from \"#indexer/index.ts\";\nimport * as Logger from \"#logger/Logger.ts\";\nimport * as Utils from \"#utils/index.ts\";\n\nexport type Admin = {\n /** Sync the block and return true if the max block number was reached. */\n syncBlock: () => Promise<boolean>;\n};\n\ntype LightBlock = {\n hash: Hex;\n number: bigint;\n parentHash: Hex;\n};\n\nexport function create<client extends PublicClient<Transport, Chain.Chain>>(parameters: {\n client: client;\n db: Database.Database;\n options?: {\n maxBatchSize?: number;\n maxBlockNumber?: number;\n };\n}): Admin {\n const collector = \"admin\";\n const { client, db, options: { maxBatchSize = 25, maxBlockNumber } = {} } = parameters;\n\n const maxBlockNumberBI = maxBlockNumber !== undefined ? BigInt(maxBlockNumber) : undefined;\n\n let finalizedBlock: LightBlock | null = null;\n let unfinalizedBlocks: LightBlock[] = [];\n let initialized = false;\n\n const logger = Logger.getLogger();\n let isMaxBlockNumberReached = false;\n let tick = 0;\n return {\n syncBlock: async () => {\n if (!initialized) {\n await Promise.all(\n Collector.names.map((collectorName) =>\n db.blocks.init({ chainId: client.chain.id, collectorName }),\n ),\n );\n initialized = true;\n }\n if (isMaxBlockNumberReached) return true;\n\n const head = await client.getBlock({\n blockTag: \"latest\",\n includeTransactions: false,\n });\n\n await db.transaction(async (dbTx) => {\n const { epoch, blockNumber: latestSavedBlockNumber } = await dbTx.blocks.getChain(\n client.chain.id,\n );\n\n if (maxBlockNumberBI !== undefined && head.number! >= maxBlockNumberBI) {\n logger.info({\n msg: `Head is greater than max block number`,\n collector,\n chainId: client.chain.id,\n block_number: head.number,\n max_block_number: maxBlockNumber,\n });\n\n await dbTx.blocks.handleReorg({\n chainId: client.chain.id,\n blockNumber: maxBlockNumber!,\n epoch: epoch + 1n,\n });\n\n isMaxBlockNumberReached = true;\n return isMaxBlockNumberReached;\n }\n\n finalizedBlock = await fetchFinalizedBlock({\n tick,\n client,\n logger,\n collector,\n unfinalizedBlocks,\n previousFinalizedBlock: finalizedBlock,\n });\n tick++;\n\n let {\n block: returnedBlock,\n didReorgHappened,\n unfinalizedBlocks: newUnfinalizedBlocks,\n } = await reconcile({\n client,\n block: head,\n unfinalizedBlocks,\n finalizedBlock,\n logger,\n collector,\n maxBatchSize,\n });\n\n unfinalizedBlocks = newUnfinalizedBlocks;\n const blockNumber = Number(returnedBlock.number);\n\n didReorgHappened = didReorgHappened || blockNumber < latestSavedBlockNumber;\n\n if (didReorgHappened) {\n await dbTx.blocks.handleReorg({\n chainId: client.chain.id,\n blockNumber,\n epoch: epoch + 1n,\n });\n } else {\n await dbTx.blocks.advanceChain({\n chainId: client.chain.id,\n blockNumber,\n epoch,\n });\n }\n });\n\n return isMaxBlockNumberReached;\n },\n };\n}\n\nconst commonAncestor = (block: Block, unfinalizedBlocks: LightBlock[]): LightBlock | null => {\n const parent = unfinalizedBlocks.find((b) => b.hash === block.parentHash);\n if (parent) return parent;\n return null;\n};\n\nconst fetchFinalizedBlock = async (parameters: {\n tick: number;\n client: PublicClient<Transport, Chain.Chain>;\n logger: Logger.Logger;\n collector: string;\n unfinalizedBlocks: LightBlock[];\n previousFinalizedBlock: LightBlock | null;\n}): Promise<LightBlock> => {\n let { tick, client, logger, collector, unfinalizedBlocks, previousFinalizedBlock } = parameters;\n let finalizedBlock: LightBlock | null = previousFinalizedBlock;\n if (tick % 20 === 0 || previousFinalizedBlock === null) {\n finalizedBlock = await client.getBlock({\n blockTag: \"finalized\",\n includeTransactions: false,\n });\n\n if (finalizedBlock === null || finalizedBlock.number === null) {\n const msg = \"Failed to get finalized block\";\n logger.fatal({ collector, chainId: client.chain.id, msg });\n throw new Error(msg);\n }\n\n unfinalizedBlocks = unfinalizedBlocks.filter((b) => b.number >= finalizedBlock!.number!);\n }\n\n if (\n finalizedBlock!.number === null ||\n finalizedBlock!.hash === null ||\n finalizedBlock!.parentHash === null\n ) {\n const msg = \"Failed to get finalized block\";\n logger.fatal({ collector, chainId: client.chain.id, msg });\n throw new Error(msg);\n }\n\n return {\n hash: finalizedBlock!.hash,\n number: finalizedBlock!.number,\n parentHash: finalizedBlock!.parentHash,\n };\n};\n\n// greatly inspired by Ponder `ReconcileBlock`\n// https://github.com/ponder-sh/ponder/blob/d0bdadee06ebd93f05903b5a692ad46fe95371b9/packages/core/src/sync-realtime/index.ts#L792\nconst reconcile = async (parameters: {\n block: Block;\n client: PublicClient<Transport, Chain.Chain>;\n collector: string;\n unfinalizedBlocks: LightBlock[];\n finalizedBlock: LightBlock;\n logger: Logger.Logger;\n maxBatchSize: number;\n}): Promise<{ block: LightBlock; didReorgHappened: boolean; unfinalizedBlocks: LightBlock[] }> => {\n let { client, block, unfinalizedBlocks, finalizedBlock, logger, collector, maxBatchSize } =\n parameters;\n\n const chain = client.chain;\n\n if (block.hash === null || block.number === null || block.parentHash === null)\n throw new Error(\"Failed to get block\");\n\n const latestBlock = unfinalizedBlocks[unfinalizedBlocks.length - 1];\n\n if (latestBlock === undefined) {\n const newBlock = {\n hash: block.hash,\n number: block.number,\n parentHash: block.parentHash,\n };\n unfinalizedBlocks.push(newBlock);\n return { block: newBlock, didReorgHappened: false, unfinalizedBlocks };\n }\n\n if (latestBlock.hash === block.hash)\n return { block: latestBlock, didReorgHappened: false, unfinalizedBlocks };\n\n if (latestBlock.number >= block.number) {\n const ancestor = commonAncestor(block, unfinalizedBlocks) || finalizedBlock;\n logger.info({\n msg: `Reorg detected, latestBlock.number >= block.number`,\n collector,\n chain_id: chain.id,\n ancestor: ancestor.number,\n latest_block_number: latestBlock.number,\n block_number: block.number,\n });\n unfinalizedBlocks = unfinalizedBlocks.filter((b) => b.number <= ancestor.number);\n return { block: ancestor, didReorgHappened: true, unfinalizedBlocks };\n }\n\n if (latestBlock.number + 1n < block.number) {\n logger.debug({\n collector,\n chain_id: chain.id,\n block_range: [latestBlock.number, block.number],\n msg: `Missing blocks`,\n });\n\n const missingBlockNumbers = (() => {\n const missingBlockNumbers = [];\n let start = latestBlock.number + 1n;\n const threshold =\n latestBlock.number + BigInt(maxBatchSize) > block.number\n ? block.number\n : latestBlock.number + BigInt(maxBatchSize);\n while (start < threshold) {\n missingBlockNumbers.push(start);\n start = start + 1n;\n }\n return missingBlockNumbers;\n })();\n\n const missingBlocks = await Promise.all(\n missingBlockNumbers.map((blockNumber) =>\n Utils.retry(async () => await client.getBlock({ blockNumber, includeTransactions: false })),\n ),\n );\n\n for (const missingBlock of missingBlocks) {\n const {\n block: returnedBlock,\n didReorgHappened,\n unfinalizedBlocks: newUnfinalizedBlocks,\n } = await reconcile({\n client,\n block: missingBlock,\n unfinalizedBlocks,\n finalizedBlock,\n logger,\n collector,\n maxBatchSize,\n });\n // if returned block is different from the missing block, return the block and stop the loop\n // this means that max block number was reached\n if (returnedBlock.number !== missingBlock.number)\n return { block: returnedBlock, didReorgHappened, unfinalizedBlocks: newUnfinalizedBlocks };\n }\n return reconcile({\n client,\n block,\n unfinalizedBlocks,\n finalizedBlock,\n logger,\n collector,\n maxBatchSize,\n });\n }\n\n if (block.parentHash !== latestBlock.hash) {\n const ancestor = commonAncestor(block, unfinalizedBlocks) || finalizedBlock;\n logger.info({\n msg: `Reorg detected, block parent hash !== latest block hash`,\n collector,\n chain_id: chain.id,\n ancestor: ancestor.number,\n latest_block_number: latestBlock.number,\n block_number: block.number,\n });\n unfinalizedBlocks = unfinalizedBlocks.filter((b) => b.number <= ancestor.number);\n return { block: ancestor, didReorgHappened: true, unfinalizedBlocks };\n }\n\n const newBlock = {\n hash: block.hash,\n number: block.number,\n parentHash: block.parentHash,\n };\n\n unfinalizedBlocks.push(newBlock);\n return { block: newBlock, didReorgHappened: false, unfinalizedBlocks };\n};\n","import type { PublicClient, Transport } from \"viem\";\nimport type { Chain } from \"#core\";\nimport type { Database } from \"#database/index.ts\";\nimport * as Logger from \"#logger/Logger.ts\";\nimport { Tracer } from \"#tracer/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\nimport * as Admin from \"./Admin.ts\";\n\nexport const names = [\"offers\", \"consumed_events\", \"positions\", \"prices\"] as const;\n\nexport type Name = (typeof names)[number];\n\n/** A general collector interface. */\nexport type Collector<\n name extends Name = Name,\n client extends PublicClient<Transport, Chain.Chain> = PublicClient<Transport, Chain.Chain>,\n> = {\n /** The name of the collector. */\n readonly name: name;\n\n /** The chain the collector is running on. */\n readonly chain: client[\"chain\"];\n\n /** The public client used to query chain head. */\n readonly client: client;\n\n /** The database connection for collector metadata. */\n readonly db: Database.Database;\n\n /** The normal polling interval (ms) for this collector. */\n readonly interval: number;\n\n /** Start collecting data from external sources.\n * @yields The last block number processed by the collector.\n */\n collect: () => AsyncGenerator<number, void, void>;\n};\n\n/** A collector’s collect function signature */\nexport type CollectFn<\n collector extends Name,\n client extends PublicClient<Transport, Chain.Chain> = PublicClient<Transport, Chain.Chain>,\n> = (parameters: CollectParameters<collector, client>) => AsyncGenerator<number, void, void>;\n\n/** Core parameters every collector gets at runtime */\nexport type CollectParameters<\n collector extends Name,\n client extends PublicClient<Transport, Chain.Chain> = PublicClient<Transport, Chain.Chain>,\n> = {\n /** A public viem client with a defined chain. */\n client: client;\n /** The collector name. */\n collector: collector;\n /** The epoch the collector is running on. */\n epoch: bigint;\n /** The last block number processed by the collector. */\n lastBlockNumber: number;\n /** The database connection. */\n db: Database.Database;\n};\n\nexport function create<\n name extends Name,\n client extends PublicClient<Transport, Chain.Chain> = PublicClient<Transport, Chain.Chain>,\n>({\n name,\n collect,\n client,\n db,\n options,\n}: {\n name: name;\n collect: CollectFn<name, client>;\n client: client;\n db: Database.Database;\n options: { maxBlockNumber?: number; interval?: number };\n}): Collector<name, client> {\n const admin = Admin.create({\n client,\n db,\n options,\n });\n\n const chain = client.chain;\n const interval = options.interval ?? 10_000;\n\n return {\n name,\n chain,\n client,\n db,\n interval,\n collect: async function* () {\n const collector = name;\n const chain = client.chain;\n const logger = Logger.getLogger();\n const collectorId = `${client.chain.id.toString()}.collector.${collector}`;\n const tracer = Tracer.getTracer(`router.${collectorId}`);\n\n logger.info({\n msg: `Collector started`,\n collector,\n chain_id: chain.id,\n });\n\n let iterator: AsyncGenerator<number, void, void> | null = null;\n let lastBlockNumber: number | undefined;\n while (true) {\n try {\n if (iterator === null) {\n iterator = await Tracer.startActiveSpan(tracer, `${collectorId}.init`, async () => {\n const { collector: collectorBlock } = await db.blocks.init({\n collectorName: name,\n chainId: chain.id,\n });\n\n lastBlockNumber = collectorBlock.blockNumber;\n\n return collect({\n client,\n collector: name,\n epoch: collectorBlock.epoch,\n lastBlockNumber,\n db,\n });\n });\n }\n\n // important to sync block before collecting in case of reorg\n // epoch will be updated by syncBlock and the collector will be blocked when trying to save block number\n const isMaxBlockNumberReached = await Tracer.startActiveSpan(\n tracer,\n `${collectorId}.syncBlock`,\n async (span) => {\n const isMaxBlockNumberReached = await admin.syncBlock();\n span.setAttribute(\"collector.is_max_block_reached\", isMaxBlockNumberReached);\n return isMaxBlockNumberReached;\n },\n );\n\n if (\n isMaxBlockNumberReached &&\n options.maxBlockNumber !== undefined &&\n lastBlockNumber !== undefined &&\n options.maxBlockNumber === lastBlockNumber\n )\n return;\n\n const { blockNumber, done } = await Tracer.startActiveSpan(\n tracer,\n `${collectorId}.next`,\n async () => {\n if (iterator === null) throw new Error(\"Iterator is not initialized\");\n const { value: blockNumber, done } = await iterator.next();\n return { blockNumber, done };\n },\n );\n\n if (done) {\n iterator = null;\n } else {\n lastBlockNumber = blockNumber!;\n yield blockNumber!;\n }\n } catch (err) {\n const isError = err instanceof Error;\n logger.error({\n msg: \"Collector error\",\n collector,\n chain_id: chain.id,\n error: isError ? err.message : String(err),\n stack: isError ? err.stack : undefined,\n });\n }\n }\n },\n };\n}\n\n/** Start a collector with its own polling cadence based on chain head lag.\n * @param collector - The collector to start.\n * @returns A function to stop the collector.\n */\nexport function start(collector: Collector): () => void {\n let stopped = false;\n const it = collector.collect();\n const logger = Logger.getLogger();\n const collectorId = `${collector.chain.id.toString()}.collector.${collector.name}`;\n const tracer = Tracer.getTracer(`router.${collectorId}`);\n const blocks = collector.db.blocks;\n let initialized = false;\n\n (async () => {\n while (!stopped) {\n try {\n await Tracer.startActiveSpan(tracer, `${collectorId}.poll`, async () => {\n if (!initialized) {\n await blocks.init({\n chainId: collector.chain.id,\n collectorName: collector.name,\n });\n initialized = true;\n }\n const [block, { blockNumber: collectorBlockNumber }] = await Promise.all([\n collector.client.getBlock({\n blockTag: \"latest\",\n includeTransactions: false,\n }),\n blocks.getCollector({\n collectorName: collector.name,\n chainId: collector.chain.id,\n }),\n ]);\n\n const chainBlockNumber = Number(block.number);\n const delay = chainBlockNumber > collectorBlockNumber + 10 ? 250 : collector.interval;\n\n const waitSpan = tracer.startSpan(`${collectorId}.wait`);\n try {\n await Utils.wait(delay);\n } finally {\n waitSpan.end();\n }\n\n await it.next();\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n logger.error({\n msg: \"Collector polling error\",\n collector: collector.name,\n chain_id: collector.chain.id,\n err: error,\n });\n }\n }\n await it.return();\n })();\n\n return () => {\n stopped = true;\n };\n}\n","import { parseAbi } from \"viem\";\n\nexport const MetaMorpho = parseAbi([\n \"function balanceOf(address account) view returns (uint256)\",\n \"function DECIMALS_OFFSET() view returns (uint8)\",\n \"function totalAssets() view returns (uint256)\",\n \"function totalSupply() view returns (uint256)\",\n \"function maxWithdraw(address owner) view returns (uint256 assets)\",\n \"function asset() view returns (address)\",\n \"event Transfer(address indexed from, address indexed to, uint256 value)\",\n \"function withdrawQueue(uint256 index) view returns (bytes32)\",\n \"function withdrawQueueLength() view returns (uint256)\",\n]);\nexport type MetaMorpho = typeof MetaMorpho;\n","import { parseAbi } from \"viem\";\n\nexport const MetaMorphoFactory = parseAbi([\n \"event CreateMetaMorpho(address indexed metaMorpho,address indexed caller,address initialOwner,uint256 initialTimelock,address indexed asset,string name,string symbol,bytes32 salt)\",\n \"function isMetaMorpho(address) view returns (bool)\",\n]);\nexport type MetaMorphoFactory = typeof MetaMorphoFactory;\n","import { parseAbi } from \"viem\";\n\nexport const MorphoV2 = parseAbi([\n \"constructor()\",\n \"function collateralOf(bytes32 id, address user, address collateralToken) view returns (uint256)\",\n \"function consume(bytes32 group, uint256 amount)\",\n \"function consumed(address user, bytes32 group) view returns (uint256)\",\n \"function debtOf(bytes32 id, address user) view returns (uint256)\",\n \"function defaultFees(address loanToken, uint256 index) view returns (uint16)\",\n \"function feeSetter() view returns (address)\",\n \"function fees(bytes32 id) view returns (uint16[6])\",\n \"function flashLoan(address token, uint256 assets, address callback, bytes data)\",\n \"function isHealthy((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, bytes32 id, address borrower) view returns (bool)\",\n \"function liquidate((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, (uint256 collateralIndex, uint256 repaid, uint256 seized)[] seizures, address borrower, bytes data) returns ((uint256 collateralIndex, uint256 repaid, uint256 seized)[])\",\n \"function multicall(bytes[] calls)\",\n \"function obligationCreated(bytes32 id) view returns (bool)\",\n \"function obligationState(bytes32 id) view returns (uint128 totalUnits, uint128 totalShares, uint256 withdrawable, bool created)\",\n \"function owner() view returns (address)\",\n \"function repay((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, uint256 obligationUnits, address onBehalf)\",\n \"function session(address user) view returns (bytes32)\",\n \"function setDefaultTradingFee(address loanToken, uint256 index, uint256 newTradingFee)\",\n \"function setFeeSetter(address newFeeSetter)\",\n \"function setObligationTradingFee(bytes32 id, uint256 index, uint256 newTradingFee)\",\n \"function setOwner(address newOwner)\",\n \"function setTradingFeeRecipient(address feeRecipient)\",\n \"function sharesOf(bytes32 id, address user) view returns (uint256)\",\n \"function shuffleSession()\",\n \"function supplyCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, address collateral, uint256 assets, address onBehalf)\",\n \"function take(uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, uint256 obligationShares, address taker, address takerCallback, bytes takerCallbackData, address receiverIfTakerIsSeller, ((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, bool buy, address maker, uint256 assets, uint256 obligationUnits, uint256 obligationShares, uint256 start, uint256 expiry, uint256 tick, bytes32 group, bytes32 session, address callback, bytes callbackData, address receiverIfMakerIsSeller) offer, (uint8 v, bytes32 r, bytes32 s) sig, bytes32 root, bytes32[] proof) returns (uint256, uint256, uint256, uint256)\",\n \"function totalShares(bytes32 id) view returns (uint256)\",\n \"function totalUnits(bytes32 id) view returns (uint256)\",\n \"function touchObligation((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation) returns (bytes32)\",\n \"function tradingFee(bytes32 id, uint256 timeToMaturity) view returns (uint256)\",\n \"function tradingFeeRecipient() view returns (address)\",\n \"function withdraw((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, uint256 obligationUnits, uint256 shares, address onBehalf, address receiver) returns (uint256, uint256)\",\n \"function withdrawCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, address collateral, uint256 assets, address onBehalf, address receiver)\",\n \"function withdrawable(bytes32 id) view returns (uint256)\",\n \"event Constructor(address indexed owner)\",\n \"event Consume(address indexed user, bytes32 indexed group, uint256 amount)\",\n \"event FlashLoan(address indexed caller, address indexed token, uint256 assets)\",\n \"event Liquidate(address indexed caller, bytes32 indexed id, (uint256 collateralIndex, uint256 repaid, uint256 seized)[] seizures, address indexed borrower, uint256 totalRepaid, uint256 badDebt)\",\n \"event ObligationCreated(bytes32 indexed id, (address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation)\",\n \"event Repay(address indexed caller, bytes32 indexed id, uint256 obligationUnits, address indexed onBehalf)\",\n \"event SetDefaultTradingFee(address indexed loanToken, uint256 indexed index, uint256 newTradingFee)\",\n \"event SetFeeSetter(address indexed feeSetter)\",\n \"event SetObligationTradingFee(bytes32 indexed id, uint256 indexed index, uint256 newTradingFee)\",\n \"event SetOwner(address indexed owner)\",\n \"event SetTradingFeeRecipient(address indexed feeRecipient)\",\n \"event ShuffleSession(address indexed user, bytes32 session)\",\n \"event SupplyCollateral(address caller, bytes32 indexed id, address indexed collateral, uint256 assets, address indexed onBehalf)\",\n \"event Take(address caller, bytes32 indexed id, address indexed maker, address indexed taker, bool offerIsBuy, uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, uint256 obligationShares, bool buyerIsLender, bool sellerIsBorrower, address sellerReceiver, bytes32 group, uint256 consumed)\",\n \"event Withdraw(address caller, bytes32 indexed id, uint256 obligationUnits, uint256 shares, address indexed onBehalf, address indexed receiver)\",\n \"event WithdrawCollateral(address caller, bytes32 indexed id, address indexed collateral, uint256 assets, address indexed onBehalf, address receiver)\",\n]);\nexport type MorphoV2 = typeof MorphoV2;\n","export * from \"./MetaMorpho.ts\";\nexport * from \"./MetaMorphoFactory.ts\";\nexport * from \"./MorphoV2.ts\";\n\nexport const Oracle = [\n {\n type: \"function\",\n name: \"price\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n },\n] as const;\n\nexport const ERC4626 = [\n {\n type: \"function\",\n name: \"asset\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\" }],\n stateMutability: \"view\",\n },\n] as const;\n\nexport const Morpho = [\n {\n type: \"function\",\n name: \"collateralOf\",\n inputs: [\n {\n name: \"\",\n type: \"address\",\n internalType: \"address\",\n },\n {\n name: \"\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n {\n name: \"\",\n type: \"address\",\n internalType: \"address\",\n },\n ],\n outputs: [\n {\n name: \"\",\n type: \"uint256\",\n internalType: \"uint256\",\n },\n ],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"debtOf\",\n inputs: [\n {\n name: \"\",\n type: \"address\",\n internalType: \"address\",\n },\n {\n name: \"\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n ],\n outputs: [\n {\n name: \"\",\n type: \"uint256\",\n internalType: \"uint256\",\n },\n ],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"market\",\n inputs: [\n {\n name: \"id\",\n type: \"bytes32\",\n internalType: \"Id\",\n },\n ],\n outputs: [\n {\n name: \"totalSupplyAssets\",\n type: \"uint128\",\n internalType: \"uint128\",\n },\n {\n name: \"totalSupplyShares\",\n type: \"uint128\",\n internalType: \"uint128\",\n },\n {\n name: \"totalBorrowAssets\",\n type: \"uint128\",\n internalType: \"uint128\",\n },\n {\n name: \"totalBorrowShares\",\n type: \"uint128\",\n internalType: \"uint128\",\n },\n {\n name: \"lastUpdate\",\n type: \"uint128\",\n internalType: \"uint128\",\n },\n {\n name: \"fee\",\n type: \"uint128\",\n internalType: \"uint128\",\n },\n ],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"position\",\n inputs: [\n {\n name: \"id\",\n type: \"bytes32\",\n internalType: \"Id\",\n },\n {\n name: \"user\",\n type: \"address\",\n internalType: \"address\",\n },\n ],\n outputs: [\n {\n name: \"supplyShares\",\n type: \"uint256\",\n internalType: \"uint256\",\n },\n {\n name: \"borrowShares\",\n type: \"uint128\",\n internalType: \"uint128\",\n },\n {\n name: \"collateral\",\n type: \"uint128\",\n internalType: \"uint128\",\n },\n ],\n stateMutability: \"view\",\n },\n] as const;\n","import type { Offer } from \"./index.ts\";\n\nexport type Callback = { type: Type.BuyWithEmptyCallback } | { type: Type.SellWithEmptyCallback };\n\nexport enum Type {\n BuyWithEmptyCallback = \"buy_with_empty_callback\",\n SellWithEmptyCallback = \"sell_with_empty_callback\",\n}\n\nexport const isEmptyCallback = (offer: Offer.Offer): boolean => offer.callback.data === \"0x\";\n","import type {\n AbiEvent,\n Address,\n ChainContract,\n ChainFormatters,\n GetLogsReturnType,\n PublicClient,\n} from \"viem\";\nimport { getBlock, getLogs } from \"viem/actions\";\nimport {\n type Chain as ViemChain,\n anvil as viemAnvil,\n base as viemBase,\n mainnet as viemEthereum,\n} from \"viem/chains\";\nimport type { Compute } from \"#core\";\nimport * as BigMath from \"#utils/BigMath.ts\";\nimport { batch } from \"#utils/batch.ts\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport type * as Callback from \"./Callback.ts\";\n\nexport type Chain = Compute<\n Omit<\n ViemChain<\n ChainFormatters,\n {\n morpho: ChainContract;\n morphoBlue: ChainContract;\n mempool: ChainContract;\n vaults: { factories: { v1_0: ChainContract; v1_1: ChainContract } };\n callbacks: Callback.Callback[];\n }\n >,\n \"custom\"\n > & {\n id: Id;\n name: Name;\n custom: {\n morpho: ChainContract;\n morphoBlue: ChainContract;\n mempool: ChainContract;\n vaults: { factories: { v1_0: ChainContract; v1_1: ChainContract } };\n callbacks: Callback.Callback[];\n };\n }\n>;\n\nexport const ChainId = {\n ETHEREUM: 1,\n BASE: 8453,\n \"ETHEREUM-VIRTUAL-TESTNET\": 109111114,\n ANVIL: 505050505, // random id to not clash with other chains\n} as const;\n\nexport type Name = Lowercase<keyof typeof ChainId>;\nexport const chainNames = Object.keys(ChainId).map((key) => key.toLowerCase()) as readonly Name[];\n\nexport type Id = (typeof ChainId)[Uppercase<Name>];\nexport const chainIds = Object.values(ChainId) as readonly Id[];\n\nconst chainNameLookup: Map<Id, Name> = new Map(\n Object.entries(ChainId).map(([key, value]) => [value, key.toLowerCase() as Name]),\n);\n\nexport function getChain(chainId: Id): Chain | undefined {\n const chainName = chainNameLookup.get(chainId);\n if (!chainName) return undefined;\n return chains[chainName];\n}\n\nexport const getWhitelistedChains = (): Chain[] => {\n return [chains.ethereum, chains.base, chains[\"ethereum-virtual-testnet\"], chains.anvil];\n};\n\nexport const chains: Record<Lowercase<Name>, Chain> = {\n ethereum: {\n ...viemEthereum,\n id: ChainId.ETHEREUM,\n name: \"ethereum\",\n custom: {\n morpho: { address: \"0x0000000000000000000000000000000000000000\", blockCreated: 0 },\n morphoBlue: { address: \"0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb\", blockCreated: 0 },\n mempool: {\n address: \"0x0000000000000000000000000000000000000000\",\n blockCreated: 23347674,\n },\n vaults: {\n factories: {\n v1_0: {\n address: \"0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101\",\n blockCreated: 18925584,\n },\n v1_1: {\n address: \"0x1897A8997241C1cD4bD0698647e4EB7213535c24\",\n blockCreated: 21439510,\n },\n },\n },\n callbacks: [],\n },\n },\n base: {\n ...viemBase,\n id: ChainId.BASE,\n name: \"base\",\n custom: {\n morpho: { address: \"0x0000000000000000000000000000000000000000\", blockCreated: 0 },\n morphoBlue: { address: \"0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb\", blockCreated: 0 },\n mempool: {\n address: \"0x0000000000000000000000000000000000000000\",\n blockCreated: 35449942,\n },\n vaults: {\n factories: {\n v1_0: {\n address: \"0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101\",\n blockCreated: 13978134,\n },\n v1_1: {\n address: \"0xFf62A7c278C62eD665133147129245053Bbf5918\",\n blockCreated: 23928808,\n },\n },\n },\n callbacks: [],\n },\n },\n \"ethereum-virtual-testnet\": {\n ...viemEthereum,\n id: ChainId[\"ETHEREUM-VIRTUAL-TESTNET\"],\n name: \"ethereum-virtual-testnet\",\n custom: {\n morpho: { address: \"0xc9f3c65996fc46b9500608b2c9a9152c01c540f7\", blockCreated: 23226871 },\n morphoBlue: { address: \"0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb\", blockCreated: 0 },\n mempool: {\n address: \"0x5b06224f736a57635b5bcb50b8ef178b189107cb\",\n blockCreated: 23224302,\n },\n vaults: {\n factories: {\n v1_0: {\n address: \"0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101\", //v1.0\n blockCreated: 18925584,\n },\n v1_1: {\n address: \"0x1897A8997241C1cD4bD0698647e4EB7213535c24\", //v1.1\n blockCreated: 21439510,\n },\n },\n },\n callbacks: [],\n },\n },\n anvil: {\n ...viemAnvil,\n id: ChainId.ANVIL,\n name: \"anvil\",\n custom: {\n morpho: { address: \"0x23DFBc4B8B80C14CC5e25011B8491f268395BAd6\", blockCreated: 0 },\n morphoBlue: { address: \"0x0000000000000000000000000000000000000000\", blockCreated: 0 }, // Set dynamically in tests\n mempool: {\n address: \"0xD946246695A9259F3B33a78629026F61B3Ab40aF\",\n blockCreated: 23223727,\n },\n vaults: {\n factories: {\n v1_0: {\n address: \"0x0000000000000000000000000000000000000000\",\n blockCreated: 0,\n },\n v1_1: {\n address: \"0x0000000000000000000000000000000000000000\",\n blockCreated: 0,\n },\n },\n },\n callbacks: [],\n },\n },\n};\n\n// thresholds are set to align with Alchemy's thresholds\n//https://www.alchemy.com/docs/deep-dive-into-eth_getlogs#making-a-request-to-eth_getlogs\nconst MAX_BATCH_SIZE = 10_000;\nconst DEFAULT_BATCH_SIZE = 2_500;\nconst MAX_BLOCK_WINDOW = 10_000;\nconst DEFAULT_BLOCK_WINDOW = 8_000;\n\nexport async function* streamLogs<abiEvent extends AbiEvent | undefined = undefined>(parameters: {\n client: PublicClient;\n contractAddress?: Address;\n event?: abiEvent;\n blockNumberGte?: number;\n blockNumberLte?: number;\n order: \"asc\" | \"desc\";\n options: {\n maxBatchSize?: number;\n blockWindow?: number;\n };\n}): AsyncGenerator<\n { logs: GetLogsReturnType<abiEvent | undefined>; blockNumber: number },\n void,\n void\n> {\n const {\n client,\n contractAddress,\n event,\n blockNumberGte,\n blockNumberLte,\n order = \"desc\",\n options: { maxBatchSize = DEFAULT_BATCH_SIZE, blockWindow = DEFAULT_BLOCK_WINDOW } = {},\n } = parameters;\n if (maxBatchSize > MAX_BATCH_SIZE) throw new InvalidBatchSizeError(maxBatchSize);\n if (blockWindow > MAX_BLOCK_WINDOW) throw new InvalidBlockWindowError(blockWindow);\n if (order === \"asc\" && blockNumberGte === undefined) throw new MissingBlockNumberError();\n\n const latestBlock = (await getBlock(client, { blockTag: \"latest\", includeTransactions: false }))\n .number;\n\n let toBlock = 0n;\n if (order === \"asc\")\n toBlock = BigMath.min(\n BigInt(blockNumberGte!) + BigInt(blockWindow),\n blockNumberLte ? BigInt(blockNumberLte!) : latestBlock,\n );\n if (order === \"desc\")\n toBlock =\n blockNumberLte === undefined\n ? latestBlock\n : BigMath.min(BigInt(blockNumberLte!), latestBlock);\n\n let fromBlock = 0n;\n if (order === \"asc\") fromBlock = BigMath.min(BigInt(blockNumberGte!), latestBlock);\n if (order === \"desc\")\n fromBlock = BigMath.max(BigInt(blockNumberGte || toBlock - BigInt(blockWindow)), 0n);\n\n if (order === \"asc\") toBlock = BigMath.min(toBlock, fromBlock + BigInt(blockWindow));\n if (order === \"desc\") fromBlock = BigMath.max(fromBlock, toBlock - BigInt(blockWindow));\n if (fromBlock > toBlock) throw new InvalidBlockRangeError(fromBlock, toBlock);\n\n let streaming = true;\n while (streaming) {\n const logs = await getLogs(client, {\n address: contractAddress,\n event,\n fromBlock,\n toBlock,\n });\n\n streaming =\n order === \"asc\"\n ? toBlock < (blockNumberLte || latestBlock)\n : fromBlock > (blockNumberGte || 0n);\n\n if (logs.length === 0 && !streaming) {\n break;\n }\n\n if (logs.length === 0 && streaming) {\n yield { logs: [], blockNumber: order === \"asc\" ? Number(toBlock) : Number(fromBlock) };\n }\n\n logs.sort((a, b) => {\n if (a.blockNumber !== b.blockNumber)\n return order === \"asc\"\n ? Number(a.blockNumber - b.blockNumber)\n : Number(b.blockNumber - a.blockNumber);\n if (a.transactionIndex !== b.transactionIndex)\n return order === \"asc\"\n ? a.transactionIndex - b.transactionIndex\n : b.transactionIndex - a.transactionIndex;\n return order === \"asc\" ? a.logIndex - b.logIndex : b.logIndex - a.logIndex;\n });\n\n for (const logBatch of batch(logs, maxBatchSize)) {\n yield {\n logs: logBatch,\n blockNumber:\n logBatch.length === maxBatchSize\n ? // if the batch is full, return the last block number, block numbers are always sorted\n Number(logBatch[logBatch.length - 1]?.blockNumber)\n : // if the batch is not full, return `toBlock` or `fromBlock` to indicate until which block the logs were fetched\n order === \"asc\"\n ? Number(toBlock)\n : Number(fromBlock),\n };\n }\n\n if (order === \"asc\") {\n const upperBound = BigInt(blockNumberLte || latestBlock);\n const nextFromBlock = BigMath.min(BigInt(toBlock) + 1n, upperBound);\n const nextToBlock = BigMath.min(toBlock + BigInt(blockWindow) + 1n, upperBound);\n fromBlock = nextFromBlock;\n toBlock = nextToBlock;\n }\n\n if (order === \"desc\") {\n const lowerBound = BigInt(blockNumberGte || 0);\n const nextToBlock = BigMath.max(fromBlock - 1n, lowerBound);\n const nextFromBlock = BigMath.max(fromBlock - BigInt(blockWindow) - 1n, lowerBound);\n toBlock = nextToBlock;\n fromBlock = nextFromBlock;\n }\n }\n\n yield { logs: [], blockNumber: order === \"asc\" ? Number(toBlock) : Number(fromBlock) };\n return;\n}\n\nexport class InvalidBlockRangeError extends Errors.BaseError {\n override name = \"Chain.InvalidBlockRangeError\";\n constructor(fromBlock: bigint, toBlock: bigint) {\n super(\n `Invalid block range while streaming data from chain. From block ${fromBlock} to block ${toBlock}.`,\n );\n }\n}\n\nexport class InvalidBlockWindowError extends Errors.BaseError {\n override name = \"Chain.InvalidBlockWindowError\";\n constructor(blockWindow: number) {\n super(\n `Invalid block window while streaming data from chain. Maximum is ${MAX_BLOCK_WINDOW}. Got ${blockWindow}.`,\n );\n }\n}\n\nexport class InvalidBatchSizeError extends Errors.BaseError {\n override name = \"Chain.InvalidBatchSizeError\";\n constructor(maxBatchSize: number) {\n super(\n `Invalid batch size while streaming data from chain. Maximum is ${MAX_BATCH_SIZE}. Got ${maxBatchSize}.`,\n );\n }\n}\n\nexport class MissingBlockNumberError extends Errors.BaseError {\n override name = \"Chain.MissingBlockNumberError\";\n constructor() {\n super(\"Missing block number when streaming data from chain in ascending order.\");\n }\n}\n","import type * as Chain from \"./Chain.ts\";\n\nexport type ChainRegistry = {\n getById: (chainId: Chain.Id) => Chain.Chain | undefined;\n list: () => Chain.Chain[];\n};\n\n/**\n * Creates a chain registry from a list of chains.\n * @param chains - Array of chain objects to register.\n * @returns A registry for looking up chains by ID. {@link ChainRegistry}\n */\nexport function create(chains: Chain.Chain[]): ChainRegistry {\n const byId = new Map<Chain.Id, Chain.Chain>();\n for (const chain of chains) {\n byId.set(chain.id, chain);\n }\n\n return {\n getById: (chainId: Chain.Id) => byId.get(chainId),\n list: () => Array.from(byId.values()),\n };\n}\n","import { type Address, type Hex, isAddress, isHex, numberToHex, pad } from \"viem\";\nimport * as z from \"zod\";\n\n/**\n * Converts a hex string to a padded bytes32.\n * Returns null if the value is not a valid hex string.\n */\nconst hexToBytes32 = (val: string): Hex | null => {\n if (!isHex(val)) return null;\n return pad(val as Hex, { size: 32 });\n};\n\n/**\n * Converts a numeric string to a padded bytes32.\n * @throws {Error} If parsing fails or value is negative.\n */\nconst numericStringToBytes32 = (val: string): Hex => {\n const num = BigInt(val);\n if (num < 0n) throw new Error(\"expected bigint to be >=0\");\n return pad(numberToHex(num), { size: 32 });\n};\n\n/**\n * Converts a number or bigint to a padded bytes32.\n * @throws {Error} If value is negative.\n */\nconst numericToBytes32 = (val: number | bigint): Hex => {\n const num = BigInt(val);\n if (num < 0n) throw new Error(\"expected bigint to be >=0\");\n return pad(numberToHex(num), { size: 32 });\n};\n\n/**\n * Transforms a value to a bytes32 hex string.\n * Accepts:\n * - Hex strings (0x...) - pads to 32 bytes if needed\n * - Numeric strings - converts to padded hex\n * - Numbers/bigints - converts to padded hex (must be non-negative)\n */\nexport const transformBytes32 = (val: string | number | bigint, ctx: z.RefinementCtx): Hex => {\n if (typeof val === \"string\") {\n const hexResult = hexToBytes32(val);\n if (hexResult !== null) return hexResult;\n\n try {\n return numericStringToBytes32(val);\n } catch (error) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Not a valid bytes32 value: ${error instanceof Error ? error.message : String(error)}`,\n });\n return z.NEVER;\n }\n }\n\n if (typeof val === \"number\" || typeof val === \"bigint\") {\n try {\n return numericToBytes32(val);\n } catch (error) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Too small: ${error instanceof Error ? error.message : String(error)}`,\n });\n return z.NEVER;\n }\n }\n\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: \"Not a valid bytes32 value\",\n });\n\n return z.NEVER;\n};\n\nexport const transformHex = (val: string, ctx: z.RefinementCtx) => {\n if (isHex(val)) return val;\n\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: \"Invalid hex\",\n });\n\n return z.NEVER;\n};\n\nexport const transformAddress = (val: string, ctx: z.RefinementCtx) => {\n if (isAddress(val.toLowerCase())) return val.toLowerCase() as Address;\n\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: \"Invalid address\",\n });\n\n return z.NEVER;\n};\n","import * as z from \"zod\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport type { Brand } from \"./types.ts\";\n\nexport type LLTV = bigint & Brand<\"LLTV\">;\n\nexport const Options = [0.385, 0.5, 0.625, 0.77, 0.86, 0.915, 0.945, 0.965, 0.98] as const;\nexport type Options = (typeof Options)[number];\nconst LLTV_SCALED = Options.map((lltv) => BigInt(lltv * 10 ** 18));\n\n/**\n * Convert a LLTV option or a scaled LLTV to a LLTV.\n * @param lltv - The LLTV option or the scaled LLTV.\n * @returns The LLTV.\n */\nexport function from(lltv: Options | bigint): LLTV {\n if (typeof lltv === \"bigint\" && !LLTV_SCALED.includes(lltv)) throw new InvalidLLTVError(lltv);\n if (typeof lltv === \"bigint\") return lltv as LLTV;\n if (typeof lltv === \"number\" && !Options.includes(lltv)) throw new InvalidOptionError(lltv);\n return BigInt(lltv * 10 ** 18) as LLTV;\n}\n\nexport declare namespace from {\n type ErrorType = InvalidOptionError | InvalidLLTVError;\n}\n\nexport class InvalidOptionError extends Errors.BaseError {\n override readonly name = \"LLTV.InvalidOptionError\";\n constructor(input: number) {\n super(\n `Invalid LLTV option. Input: \"${input}\". Accepted values are: ${Options.map(\n (option) => `\"${option}\"`,\n ).join(\", \")}.`,\n );\n }\n}\n\nexport class InvalidLLTVError extends Errors.BaseError {\n override readonly name = \"LLTV.InvalidLLTVError\";\n constructor(input: bigint) {\n super(\n `Invalid LLTV. Input: \"${input}\". Accepted values are: ${LLTV_SCALED.map(\n (option) => `\"${option}\"`,\n ).join(\", \")}.`,\n );\n }\n}\n\nexport const LLTVSchema = z\n .bigint({ coerce: true })\n .refine(\n (lltv) => {\n try {\n from(lltv);\n return true;\n } catch (_) {\n return false;\n }\n },\n {\n error: () => {\n return \"Invalid LLTV: must be one of 0.385, 0.625, 0.77, 0.86, 0.915, 0.945, 0.965 or 0.98 (scaled by 1e18)\";\n },\n },\n )\n .transform((lltv) => from(lltv));\n","import type { Address } from \"viem\";\nimport * as z from \"zod\";\nimport * as Random from \"#utils/Random.ts\";\nimport { transformAddress } from \"#utils/zod.ts\";\nimport * as LLTV from \"./LLTV.ts\";\n\nexport type Collateral = {\n /** Asset being used as collateral. */\n asset: Address;\n /** Liquidation Loan-to-Value of the collateral. */\n lltv: LLTV.LLTV;\n /** Oracle contract used to price the collateral. */\n oracle: Address;\n};\n\nexport const CollateralSchema = z.object({\n asset: z.string().transform(transformAddress),\n oracle: z.string().transform(transformAddress),\n lltv: LLTV.LLTVSchema,\n});\n\nexport const CollateralsSchema = z\n .array(CollateralSchema)\n .min(1, { message: \"At least one collateral is required\" })\n .refine(\n (collaterals) => {\n for (let i = 1; i < collaterals.length; i++) {\n if (collaterals[i - 1]!.asset.toLowerCase() > collaterals[i]!.asset.toLowerCase()) {\n return false;\n }\n }\n return true;\n },\n {\n message: \"Collaterals must be sorted alphabetically by address\",\n },\n )\n .refine(\n (collaterals) => {\n const uniqueAssets = new Set<string>();\n for (const collateral of collaterals) {\n const assetAddress = collateral.asset.toLowerCase();\n if (uniqueAssets.has(assetAddress)) {\n return false;\n }\n uniqueAssets.add(assetAddress);\n }\n return true;\n },\n {\n message: \"Collaterals must not contain duplicate assets\",\n },\n );\n\nexport const from = (parameters: from.Parameters): from.ReturnType => {\n return {\n asset: parameters.asset.toLowerCase() as Address,\n lltv: LLTV.from(parameters.lltv),\n oracle: parameters.oracle.toLowerCase() as Address,\n };\n};\n\nexport declare namespace from {\n type Parameters = {\n asset: Address;\n lltv: LLTV.Options | bigint;\n oracle: Address;\n };\n type ReturnType = Collateral;\n}\n\n/**\n * Generates a random collateral.\n * @returns A randomly generated collateral. {@link random.ReturnType}\n *\n * @example\n * ```ts\n * const collateral = Collateral.random();\n * ```\n */\nexport function random(): random.ReturnType {\n return from({\n asset: Random.address(),\n oracle: Random.address(),\n lltv: 0.965,\n });\n}\n\nexport declare namespace random {\n type ReturnType = Collateral;\n}\n","import * as Errors from \"#utils/Errors.ts\";\n\n/**\n * Calculate the decimals offset used by the ERC4626 implementation.\n * @param parameters - {@link decimalsOffset.Parameters}.\n * @returns The decimals offset.\n *\n * @example\n * ```ts\n * const decimalsOffset = decimalsOffset({ underlyingDecimals: 6 });\n * // decimalsOffset = 12\n * ```\n */\nexport function decimalsOffset(parameters: decimalsOffset.Parameters): number {\n return Math.max(0, 18 - parameters.underlyingDecimals);\n}\n\nexport declare namespace decimalsOffset {\n type Parameters = {\n /** The number of decimals of the underlying asset. */\n underlyingDecimals: number;\n };\n type ReturnType = number;\n}\n\n/**\n * Convert shares to assets.\n * @throws If the denominator is 0. {@link DenominatorIsZeroError}\n * @param parameters - {@link convertToAssets.Parameters}.\n * @returns The amount of assets.\n *\n * @example\n * ```ts\n * const assets = convertToAssets(100n, { totalAssets: 1000n, totalSupply: 1000n, decimalsOffset: 18 });\n * // assets = 100n\n * ```\n */\nexport function convertToAssets(\n parameters: convertToAssets.Parameters,\n): convertToAssets.ReturnType {\n const denominator = parameters.totalSupply + 10n ** BigInt(parameters.decimalsOffset);\n if (denominator === 0n) throw new DenominatorIsZeroError();\n\n return (parameters.shares * (parameters.totalAssets + 1n)) / denominator;\n}\n\nexport declare namespace convertToAssets {\n type Parameters = {\n /** The amount of shares to convert. */\n shares: bigint;\n /** Total amount of assets in the vault. */\n totalAssets: bigint;\n /** Total amount of shares in the vault. */\n totalSupply: bigint;\n /**\n * OpenZeppelin decimals offset used by the ERC4626 implementation.\n * Calculated to be `max(0, 18 - underlyingDecimals)` at construction, so the initial conversion rate maximizes\n * precision between shares and assets.\n */\n decimalsOffset: number;\n };\n type ReturnType = bigint;\n type ErrorType = DenominatorIsZeroError;\n}\n\n/**\n * Convert assets to shares.\n * @throws If the denominator is 0. {@link DenominatorIsZeroError}\n * @param parameters - {@link convertToShares.Parameters}.\n * @returns The amount of shares.\n *\n * @example\n * ```ts\n * const shares = convertToShares(100n, { totalAssets: 1000n, totalSupply: 1000n, decimalsOffset: 12 });\n * // shares = 100n\n * ```\n */\nexport function convertToShares(\n parameters: convertToShares.Parameters,\n): convertToShares.ReturnType {\n const denominator = parameters.totalAssets + 1n;\n if (denominator === 0n) throw new DenominatorIsZeroError();\n\n return (\n (parameters.assets * (parameters.totalSupply + 10n ** BigInt(parameters.decimalsOffset))) /\n denominator\n );\n}\n\nexport declare namespace convertToShares {\n type Parameters = {\n /** The amount of assets to convert. */\n assets: bigint;\n /** Total amount of assets in the vault. */\n totalAssets: bigint;\n /** Total amount of shares in the vault. */\n totalSupply: bigint;\n /**\n * OpenZeppelin decimals offset used by the ERC4626 implementation.\n * Calculated to be `max(0, 18 - underlyingDecimals)` at construction, so the initial conversion rate maximizes\n * precision between shares and assets.\n */\n decimalsOffset: number;\n };\n type ReturnType = bigint;\n type ErrorType = DenominatorIsZeroError;\n}\nexport class DenominatorIsZeroError extends Errors.BaseError {\n override readonly name = \"ERC4626.DenominatorIsZeroError\";\n constructor() {\n super(\"Denominator is 0.\");\n }\n}\n","import type { Address, Hex } from \"viem\";\nimport type { Chain } from \"#core\";\n\n/**\n * Represents a liquidity pool with a unique ID and amount.\n */\nexport type LiquidityPool = {\n id: string;\n amount: bigint;\n};\n\n/**\n * Represents a hierarchical relationship between two liquidity pools.\n */\nexport type LiquidityLink = {\n parentPoolId: string;\n childPoolId: string;\n priority: number;\n};\n\n/**\n * Represents the connection between an offer and its liquidity pools.\n */\nexport type OfferLiquidityPool = {\n offerHash: Hex;\n poolId: string;\n /**\n * The available capacity/liquidity from this pool for this offer.\n * Matches allowance amount from pool below.\n */\n amount: bigint;\n};\n\n/**\n * Calculate maximum debt capacity from collateral amount.\n * @param amount - Collateral amount\n * @param oraclePrice - Oracle price (scaled to 36 decimals)\n * @param lltv - Loan-to-value ratio (scaled to 18 decimals)\n * @returns Maximum debt capacity\n */\nexport function calculateMaxDebt(amount: bigint, oraclePrice: bigint, lltv: bigint): bigint {\n const ORACLE_PRICE_SCALE = 10n ** 36n; // Oracle prices are scaled to 36 decimals\n const PRECISION = 10n ** 18n; // LLTV ratios are scaled to 18 decimals (1e18 = 100%)\n\n const collateralQuoted = (amount * oraclePrice) / ORACLE_PRICE_SCALE;\n const maxDebt = (collateralQuoted * lltv) / PRECISION;\n\n return maxDebt;\n}\n\n/**\n * Generate pool ID for balance pools.\n */\nexport function generateBalancePoolId(parameters: {\n user: Address;\n chainId: Chain.Id;\n token: Address;\n}): string {\n const { user, chainId, token } = parameters;\n return `${user}-${chainId.toString()}-${token}-balance`.toLowerCase();\n}\n\n/**\n * Generate pool ID for allowance pools.\n */\nexport function generateAllowancePoolId(parameters: {\n user: Address;\n chainId: Chain.Id;\n token: Address;\n}): string {\n const { user, chainId, token } = parameters;\n return `${user}-${chainId.toString()}-${token}-allowance`.toLowerCase();\n}\n\n/**\n * Generate pool ID for obligation collateral pools.\n * Obligation collateral pools represent collateral already deposited in the obligation.\n * These pools are shared across all offers with the same obligation.\n */\nexport function generateObligationCollateralPoolId(parameters: {\n user: Address;\n chainId: Chain.Id;\n obligationId: Hex;\n token: Address;\n}): string {\n const { user, chainId, obligationId, token } = parameters;\n return `${user}-${chainId.toString()}-${obligationId}-${token}-obligation-collateral`.toLowerCase();\n}\n\n/**\n * Generate pool ID for debt pools.\n */\nexport function generateDebtPoolId(parameters: {\n user: Address;\n chainId: Chain.Id;\n obligationId: Hex;\n}): string {\n const { user, chainId, obligationId } = parameters;\n return `${user}-${chainId.toString()}-${obligationId}-debt`.toLowerCase();\n}\n\n/**\n * Generate pool ID for user position in a vault.\n */\nexport function generateUserVaultPositionPoolId(parameters: {\n user: Address;\n chainId: Chain.Id;\n vault: Address;\n}): string {\n const { user, chainId, vault } = parameters;\n return `${user}-${chainId.toString()}-${vault}-user-vault-position`.toLowerCase();\n}\n\n/**\n * Generate pool ID for vault position in a market.\n */\nexport function generateVaultPositionPoolId(parameters: {\n vault: Address;\n chainId: Chain.Id;\n marketId: string;\n}): string {\n const { vault, chainId, marketId } = parameters;\n return `${vault}-${chainId.toString()}-${marketId}-vault-position`.toLowerCase();\n}\n\n/**\n * Generate pool ID for market total liquidity.\n */\nexport function generateMarketLiquidityPoolId(parameters: {\n chainId: Chain.Id;\n marketId: string;\n}): string {\n const { chainId, marketId } = parameters;\n return `${chainId.toString()}-${marketId}-market-liquidity`.toLowerCase();\n}\n","import * as z from \"zod\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport type { Brand } from \"./types.ts\";\n\n/**\n * Maturity is a number that represents a date in seconds.\n */\nexport type Maturity = number & Brand<\"Maturity\">;\n\nexport const MaturitySchema = z\n .number()\n .int()\n .refine(\n (maturity) => {\n try {\n from(maturity);\n return true;\n } catch (_e) {\n return false;\n }\n },\n {\n error: (issue) => {\n try {\n const maturityDate = new Date((issue.input as number) * 1000);\n return `The maturity is set to ${maturityDate}. It must fall on the allowed settlement cycles (Friday 15:00 UTC at the end of week/month/quarter).`;\n } catch (_) {\n return `The maturity is set to ${issue.input}. It must fall on the allowed settlement cycles (Friday 15:00 UTC at the end of week/month/quarter).`;\n }\n },\n },\n )\n .transform((maturity) => maturity as Maturity);\n\nexport enum MaturityType {\n EndOfWeek = \"end_of_week\",\n EndOfNextWeek = \"end_of_next_week\",\n EndOfMonth = \"end_of_month\",\n EndOfNextMonth = \"end_of_next_month\",\n EndOfQuarter = \"end_of_quarter\",\n EndOfNextQuarter = \"end_of_next_quarter\",\n}\n\nconst MaturityOptions = {\n end_of_week: () => endOfWeek(),\n end_of_next_week: () => endOfNextWeek(),\n end_of_month: () => endOfMonth(),\n end_of_next_month: () => endOfNextMonth(),\n end_of_quarter: () => endOfQuarter(),\n end_of_next_quarter: () => endOfNextQuarter(),\n} as const;\n\nexport type MaturityOptions = keyof typeof MaturityOptions;\n\n/**\n * Creates a maturity from a timestamp in seconds or a maturity option.\n * @throws {InvalidFormatError} If the maturity is in milliseconds.\n * @throws {InvalidDateError} If the maturity is in seconds but not a valid date.\n * @throws {InvalidOptionError} If the maturity is not a valid option.\n */\nexport function from(ts: from.Parameters): Maturity {\n if (typeof ts === \"string\") {\n if (ts in MaturityOptions) return MaturityOptions[ts]();\n throw new InvalidOptionError(ts);\n }\n\n if (typeof ts === \"number\" && ts > 1e12) throw new InvalidFormatError();\n\n if (!Object.values(MaturityOptions).some((option) => option() === ts))\n throw new InvalidDateError(ts);\n\n return ts as Maturity;\n}\n\nexport declare namespace from {\n type Parameters = number | MaturityOptions;\n type ErrorType = InvalidFormatError | InvalidDateError | InvalidOptionError;\n}\n\n/** Returns the end of the current week (friday at 15:00:00 UTC) */\nconst endOfWeek = (): Maturity => fridayOfWeek(0);\n\n/** Returns the end of the next week (friday at 15:00:00 UTC) */\nconst endOfNextWeek = (): Maturity => fridayOfWeek(1);\n\n/** Returns the end of the current month (last friday of the month at 15:00:00 UTC)\n * Business rule: if we are after the last Friday of the month (strictly after 15:00 UTC\n * on that Friday), roll to the next month's last Friday.\n */\nconst endOfMonth = (): Maturity => {\n const now = new Date();\n const year = now.getUTCFullYear();\n const month = now.getUTCMonth();\n\n const endOfMonth = lastFridayOfMonth(year, month);\n\n // If strictly after 15:00 UTC on the last Friday, roll to next month's last Friday\n if (now.getTime() > endOfMonth * 1000) {\n return lastFridayOfMonth(year, month + 1);\n }\n\n return endOfMonth;\n};\n\n/** Returns the end of the next month (last friday of the next month at 15:00:00 UTC)\n * Business rule: if we are after the last Friday of the current month (strictly after 15:00 UTC\n * on that Friday), we consider being in the next month already, so \"next month\" becomes month+2.\n */\nconst endOfNextMonth = (): Maturity => {\n const now = new Date();\n const year = now.getUTCFullYear();\n const month = now.getUTCMonth();\n\n const endOfMonth = lastFridayOfMonth(year, month);\n\n if (now.getTime() > endOfMonth * 1000) {\n return lastFridayOfMonth(year, month + 2);\n }\n\n return lastFridayOfMonth(year, month + 1);\n};\n\n/** Returns the end of the current quarter (last friday of the quarter at 15:00:00 UTC) */\nconst endOfQuarter = (): Maturity => lastFridayOfQuarter(0);\n\n/** Returns the end of the next quarter (last friday of the next quarter at 15:00:00 UTC) */\nconst endOfNextQuarter = (): Maturity => lastFridayOfQuarter(1);\n\nconst fridayOfWeek = (weeksAhead = 0): Maturity => {\n const now = new Date();\n const today15H = new Date(\n Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), 15),\n );\n\n // Days until next Friday (5). Always non-negative in [0,6]\n let daysUntilFriday = (5 - today15H.getUTCDay() + 7) % 7;\n\n // If it's Friday and we're already past 15:00 UTC, roll to next Friday\n if (daysUntilFriday === 0 && now.getTime() >= today15H.getTime()) {\n daysUntilFriday = 7;\n }\n\n const friday = new Date(today15H);\n friday.setUTCDate(friday.getUTCDate() + daysUntilFriday + weeksAhead * 7);\n return (friday.getTime() / 1000) as Maturity;\n};\n\nconst lastFridayOfMonth = (year: number, month: number): Maturity => {\n const lastDayOfMonth15H = new Date(Date.UTC(year, month + 1, 0, 15));\n\n while (lastDayOfMonth15H.getUTCDay() !== 5) {\n lastDayOfMonth15H.setUTCDate(lastDayOfMonth15H.getUTCDate() - 1);\n }\n\n const maturity = lastDayOfMonth15H.setUTCDate(lastDayOfMonth15H.getUTCDate()) / 1000;\n\n return maturity as Maturity;\n};\n\nconst lastFridayOfQuarter = (quartersAhead = 0): Maturity => {\n const now = new Date();\n const quarterIndex = Math.floor(now.getUTCMonth() / 3) + quartersAhead;\n const year = now.getUTCFullYear() + Math.floor(quarterIndex / 4);\n const quarter = quarterIndex % 4;\n const lastMonth = quarter * 3 + 2; // 0-based\n return lastFridayOfMonth(year, lastMonth);\n};\n\nexport class InvalidFormatError extends Errors.BaseError {\n override readonly name = \"Maturity.InvalidFormatError\";\n constructor() {\n super(\"Invalid maturity format. Maturity should be expressed in seconds.\");\n }\n}\n\nexport class InvalidDateError extends Errors.BaseError {\n override readonly name = \"Maturity.InvalidDateError\";\n constructor(input: number) {\n super(\n `Invalid maturity date. Input: \"${input}\". Accepted values are: ${Object.values(\n MaturityOptions,\n )\n .map((option) => `\"${option()}\"`)\n .join(\", \")}.`,\n );\n }\n}\n\nexport class InvalidOptionError extends Errors.BaseError {\n override readonly name = \"Maturity.InvalidOptionError\";\n constructor(input: string) {\n super(\n `Invalid maturity option. Input: \"${input}\". Accepted values are: ${Object.keys(\n MaturityOptions,\n )\n .map((option) => `\"${option}\"`)\n .join(\", \")}.`,\n );\n }\n}\n","import { type Address, encodeAbiParameters, type Hex, keccak256 } from \"viem\";\nimport * as z from \"zod\";\nimport type { Offer } from \"#core\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport * as Format from \"#utils/Format.ts\";\nimport * as Random from \"#utils/Random.ts\";\nimport { transformAddress } from \"#utils/zod.ts\";\nimport type * as Chain from \"./Chain.ts\";\nimport * as Collateral from \"./Collateral.ts\";\nimport * as Maturity from \"./Maturity.ts\";\n\nexport type Obligation = {\n /** The chain id where the liquidity for this obligation is located. */\n chainId: Chain.Id;\n /** The token that is being borrowed for this obligation. */\n loanToken: Address;\n /** The exact set of collaterals required to borrow the loan token. */\n collaterals: Collateral.Collateral[];\n /** The maturity of the obligation. */\n maturity: Maturity.Maturity;\n};\n\nexport const ObligationSchema = z.object({\n chainId: z.number().min(0).max(Number.MAX_SAFE_INTEGER),\n loanToken: z.string().transform(transformAddress),\n collaterals: Collateral.CollateralsSchema,\n maturity: Maturity.MaturitySchema,\n});\n\n/**\n * Creates an obligation from the given parameters.\n * @constructor\n * @param parameters - {@link from.Parameters}\n * @returns The created obligation. {@link Obligation}\n * @throws If the collaterals are not sorted alphabetically by address. {@link CollateralsAreNotSortedError}\n *\n * @example\n * ```ts\n * const obligation = Obligation.from({\n * chainId: 1,\n * loanToken: privateKeyToAccount(generatePrivateKey()).address,\n * collaterals: [\n * Collateral.from({\n * asset: privateKeyToAccount(generatePrivateKey()).address,\n * oracle: privateKeyToAccount(generatePrivateKey()).address,\n * lltv: 0.965\n * }),\n * ],\n * maturity: Maturity.from(\"end_of_next_quarter\"),\n * });\n * ```\n */\nexport function from(parameters: from.Parameters): from.ReturnType {\n try {\n const parsedObligation = ObligationSchema.parse({\n ...parameters,\n maturity: Maturity.from(parameters.maturity),\n });\n\n return {\n chainId: parsedObligation.chainId as Chain.Id,\n loanToken: parsedObligation.loanToken.toLowerCase() as Address,\n collaterals: parsedObligation.collaterals.sort((a, b) => a.asset.localeCompare(b.asset)),\n maturity: parsedObligation.maturity,\n };\n } catch (error: unknown) {\n throw new InvalidObligationError(error as z.ZodError | Error);\n }\n}\n\nexport declare namespace from {\n type Parameters = {\n /** The chain id where the liquidity for this obligation is located. */\n chainId: number;\n /** The token that is being borrowed for this obligation. */\n loanToken: Address;\n /** The exact set of collaterals required to borrow the loan token. Must be sorted alphabetically by address. */\n collaterals: Collateral.from.Parameters[] | readonly Collateral.from.Parameters[];\n /** The maturity of the obligation. */\n maturity: Maturity.from.Parameters;\n };\n\n type ReturnType = Obligation;\n\n export type ErrorType = InvalidObligationError;\n}\n\n/**\n * Creates an obligation from a snake case object.\n * @throws If the obligation is invalid. {@link fromSnakeCase.ErrorType}\n * @param input - {@link fromSnakeCase.Parameters}\n * @returns The created obligation. {@link fromSnakeCase.ReturnType}\n */\nexport function fromSnakeCase(input: fromSnakeCase.Parameters): fromSnakeCase.ReturnType {\n return from(Format.fromSnakeCase<Omit<Obligation, \"chainId\"> & { chainId: number }>(input));\n}\n\nexport declare namespace fromSnakeCase {\n type Parameters = Format.Snake<Omit<Obligation, \"chainId\"> & { chainId: number }>;\n type ReturnType = Obligation;\n type ErrorType = InvalidObligationError;\n}\n\n/**\n * Calculates the obligation id based on the smart contract's Obligation struct.\n * The id is computed as keccak256(abi.encode(chainId, loanToken, collaterals, maturity)).\n * @throws If the collaterals are not sorted alphabetically by address. {@link CollateralsAreNotSortedError}\n * @param parameters - {@link id.Parameters}\n * @returns The obligation id as a 32-byte hex string. {@link id.ReturnType}\n *\n * @example\n * ```ts\n * const obligation = Obligation.random();\n * const id = Obligation.id(obligation);\n * console.log(id); // 0x1234567890123456789012345678901234567890123456789012345678901234\n * ```\n */\nexport function id(parameters: id.Parameters): id.ReturnType {\n let lastAsset = \"\";\n for (const collateral of parameters.collaterals) {\n const newAsset = collateral.asset.toLowerCase();\n if (newAsset.localeCompare(lastAsset) < 0) throw new CollateralsAreNotSortedError();\n lastAsset = newAsset;\n }\n\n return keccak256(\n encodeAbiParameters(\n [\n { type: \"uint256\" },\n { type: \"address\" },\n {\n type: \"tuple[]\",\n components: [\n { type: \"address\", name: \"token\" },\n { type: \"uint256\", name: \"lltv\" },\n { type: \"address\", name: \"oracle\" },\n ],\n },\n { type: \"uint256\" },\n ],\n [\n BigInt(parameters.chainId),\n parameters.loanToken.toLowerCase() as Address,\n parameters.collaterals.map((c) => ({\n token: c.asset.toLowerCase() as Address,\n lltv: c.lltv,\n oracle: c.oracle.toLowerCase() as Address,\n })),\n BigInt(parameters.maturity),\n ],\n ),\n );\n}\n\nexport declare namespace id {\n type Parameters = {\n chainId: number;\n loanToken: Address;\n collaterals: {\n asset: Address;\n lltv: bigint;\n oracle: Address;\n }[];\n maturity: number;\n };\n type ReturnType = Hex;\n type ErrorType = CollateralsAreNotSortedError;\n}\n\n/**\n * Generates a random obligation.\n * @returns A randomly generated obligation. {@link random.ReturnType}\n *\n * @example\n * ```ts\n * const obligation = Obligation.random();\n * ```\n */\nexport function random(): random.ReturnType {\n return from({\n chainId: 1,\n loanToken: Random.address(),\n collaterals: [Collateral.random()],\n maturity: Maturity.from(\"end_of_next_quarter\"),\n });\n}\n\nexport declare namespace random {\n type ReturnType = Obligation;\n}\n\n/**\n * Creates an obligation from an offer.\n * @constructor\n *\n * @param offer - The offer to create the obligation from.\n * @returns The created obligation. {@link fromOffer.ReturnType}\n */\nexport function fromOffer(offer: Offer.Offer): fromOffer.ReturnType {\n return from({\n chainId: offer.chainId,\n loanToken: offer.loanToken,\n collaterals: offer.collaterals,\n maturity: offer.maturity,\n });\n}\n\nexport declare namespace fromOffer {\n type Parameters = Offer.Offer;\n type ReturnType = Obligation;\n}\n\nexport class InvalidObligationError extends Errors.BaseError<z.ZodError | Error> {\n override readonly name = \"Obligation.InvalidObligationError\";\n constructor(error: z.ZodError | Error) {\n super(\"Invalid obligation.\", { cause: error });\n }\n}\n\nexport class CollateralsAreNotSortedError extends Errors.BaseError {\n override readonly name = \"Obligation.CollateralsAreNotSortedError\";\n constructor() {\n super(\"Collaterals are not sorted alphabetically by address.\");\n }\n}\n","import {\n type Address,\n type DecodeAbiParametersReturnType,\n decodeAbiParameters,\n encodeAbiParameters,\n type Hex,\n hashTypedData,\n maxUint256,\n zeroAddress,\n} from \"viem\";\nimport * as z from \"zod\";\nimport type { Compute } from \"#core\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport * as Format from \"#utils/Format.ts\";\nimport * as Random from \"#utils/Random.ts\";\nimport { transformAddress, transformBytes32, transformHex } from \"#utils/zod.ts\";\nimport * as Chain from \"./Chain.ts\";\nimport * as Collateral from \"./Collateral.ts\";\nimport * as LLTV from \"./LLTV.ts\";\nimport * as Maturity from \"./Maturity.ts\";\nimport * as Obligation from \"./Obligation.ts\";\n\n/** Internal symbol for caching the computed hash. */\nconst HASH_CACHE = Symbol(\"offer.hash\");\n\nexport type Offer = {\n /** The address that made the offer. */\n readonly maker: Address;\n /** The amount of assets offered. Mutually exclusive with obligationUnits and obligationShares. */\n readonly assets: bigint;\n /** The max debt units to trade. Mutually exclusive with assets and obligationShares. */\n readonly obligationUnits: bigint;\n /** The max lending shares to trade. Mutually exclusive with assets and obligationUnits. */\n readonly obligationShares: bigint;\n /** The offer tick. */\n readonly tick: number;\n /** The date at which all interests will be paid. */\n readonly maturity: Maturity.Maturity;\n /** The date at which the offer will expire. */\n readonly expiry: number;\n /** The date at which the offer will start. */\n readonly start: number;\n /** The group. Used for OCO (One-Cancelled-Other) mechanism. */\n readonly group: Hex;\n /** The session. Used for session-based offer management. */\n readonly session: Hex;\n /** The side of the offer. `true` for buy, `false` for sell. */\n readonly buy: boolean;\n /** The chain id where the liquidity for this offer is located. */\n readonly chainId: Chain.Id;\n /** The token that is being borrowed. */\n readonly loanToken: Address;\n /** The exact set of collaterals required to borrow the loan token. */\n readonly collaterals: readonly Collateral.Collateral[];\n /** The optional callback data to retrieve the maker funds. */\n readonly callback: {\n readonly address: Address;\n readonly data: Hex;\n };\n /** Receiver of loan token proceeds when maker is seller on `take()`. */\n readonly receiverIfMakerIsSeller: Address;\n};\n\nexport enum Status {\n VALID = \"VALID\",\n SIMULATION_ERROR = \"SIMULATION_ERROR\",\n}\n\nexport type Validation = {\n offerHash: Hex;\n status: Status;\n};\n\nexport const OfferSchema = () => {\n return z\n .object({\n maker: z.string().transform(transformAddress),\n assets: z.bigint({ coerce: true }).min(0n).max(maxUint256),\n obligationUnits: z.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),\n obligationShares: z.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),\n tick: z.coerce.number().int().min(0).max(990),\n maturity: Maturity.MaturitySchema,\n expiry: z.number().int().max(Number.MAX_SAFE_INTEGER),\n start: z.number().int().max(Number.MAX_SAFE_INTEGER),\n group: z.union([z.string(), z.number(), z.bigint()]).transform(transformBytes32),\n session: z\n .union([z.string(), z.number(), z.bigint()])\n .optional()\n .default(\"0x0000000000000000000000000000000000000000000000000000000000000000\")\n .transform(transformBytes32),\n buy: z.boolean(),\n chainId: z.number().min(0).max(Number.MAX_SAFE_INTEGER),\n loanToken: z.string().transform(transformAddress),\n collaterals: Collateral.CollateralsSchema,\n callback: z.object({\n address: z.string().transform(transformAddress),\n data: z.string().transform(transformHex),\n }),\n receiverIfMakerIsSeller: z.string().transform(transformAddress),\n })\n .refine((data) => data.start < data.expiry, {\n message: \"start must be before expiry\",\n path: [\"start\"],\n })\n .refine((data) => data.expiry <= data.maturity, {\n message: \"expiry must be before or equal to maturity\",\n path: [\"expiry\"],\n });\n};\n\n/**\n * Input type for creating offers. Accepts flexible group types that will be coerced to Hex.\n *\n * The `group` field accepts multiple input formats:\n * - **Hex string** (`0x...`): Padded to 32 bytes if needed\n * - **Numeric string**: Converted to hex (e.g., `\"123\"` -> `\"0x...7b\"`)\n * - **Number**: Non-negative safe integer, converted to hex\n * - **BigInt**: Non-negative, must fit in bytes32\n *\n * All values validated to be non-negative and within bytes32 range.\n */\nexport type OfferInput = Compute<\n Omit<\n Offer,\n | \"chainId\"\n | \"group\"\n | \"session\"\n | \"obligationUnits\"\n | \"obligationShares\"\n | \"receiverIfMakerIsSeller\"\n > & {\n chainId: number;\n group: Hex | bigint | number | string;\n /** Optional: defaults to zero bytes32. */\n session?: Hex | bigint | number | string;\n /** Optional: defaults to 0n. Mutually exclusive with assets and obligationShares. */\n obligationUnits?: bigint;\n /** Optional: defaults to 0n. Mutually exclusive with assets and obligationUnits. */\n obligationShares?: bigint;\n /** Optional: defaults to maker for backward compatibility. */\n receiverIfMakerIsSeller?: Address;\n }\n>;\n\n/**\n * Creates an offer from a plain object.\n * @throws {InvalidOfferError} If the offer is invalid.\n * @param input - The offer to create.\n * @returns The created offer.\n */\nexport function from(input: OfferInput): Offer {\n const normalizedInput: OfferInput = {\n ...input,\n receiverIfMakerIsSeller: input.receiverIfMakerIsSeller ?? input.maker,\n };\n try {\n return OfferSchema().parse(normalizedInput) as Offer;\n } catch (error: unknown) {\n throw new InvalidOfferError(error as z.ZodError | Error);\n }\n}\n\nexport declare namespace from {\n export type ErrorType = InvalidOfferError;\n}\n\n/**\n * Creates an offer from a snake case object.\n * @throws {InvalidOfferError} If the offer is invalid.\n * @param input - The offer to create.\n * @returns The created offer.\n */\nexport function fromSnakeCase(\n input: Format.Snake<\n Omit<Offer, \"session\" | \"receiverIfMakerIsSeller\"> & {\n session?: Hex;\n receiverIfMakerIsSeller?: Address;\n }\n >,\n): Offer {\n return from(Format.fromSnakeCase<OfferInput>(input as unknown as Format.Snake<OfferInput>));\n}\n\n/**\n * Converts an offer to a snake case object.\n * @param offer - The offer to convert.\n * @returns The converted offer.\n */\nexport function toSnakeCase(offer: Offer): Format.Snake<Offer> {\n return Format.toSnakeCase(offer);\n}\n\n/**\n * Serializes an offer for merkle tree encoding.\n * Converts BigInt fields to strings for JSON compatibility.\n *\n * @param offer - Offer to serialize\n * @returns JSON-serializable offer object\n */\nexport const serialize = (offer: Offer) => ({\n maker: offer.maker,\n assets: offer.assets.toString(),\n obligationUnits: offer.obligationUnits.toString(),\n obligationShares: offer.obligationShares.toString(),\n tick: offer.tick,\n maturity: Number(offer.maturity),\n expiry: Number(offer.expiry),\n start: Number(offer.start),\n group: offer.group,\n session: offer.session,\n buy: offer.buy,\n chainId: offer.chainId,\n loanToken: offer.loanToken,\n collaterals: offer.collaterals.map((c) => ({\n asset: c.asset,\n oracle: c.oracle,\n lltv: c.lltv.toString(),\n })),\n callback: {\n address: offer.callback.address,\n data: offer.callback.data,\n },\n receiverIfMakerIsSeller: offer.receiverIfMakerIsSeller,\n hash: hash(offer),\n});\n\nexport type RandomConfig = {\n chains?: Chain.Chain[];\n loanTokens?: Address[];\n collateralTokens?: Address[];\n assetsDecimals?: Record<Address, number>;\n buy?: boolean;\n assets?: bigint;\n obligationUnits?: bigint;\n obligationShares?: bigint;\n maker?: Address;\n maturity?: Maturity.Maturity;\n start?: number;\n expiry?: number;\n group?: Hex | bigint | number | string;\n session?: Hex | bigint | number | string;\n tick?: number;\n callback?: {\n address: Address;\n data: Hex;\n };\n receiverIfMakerIsSeller?: Address;\n collaterals?: readonly Collateral.Collateral[];\n};\n\n/**\n * Generates a random Offer.\n * The returned Offer contains randomly generated values.\n * @warning The generated Offer should not be used for production usage.\n * @returns {Offer} A randomly generated Offer object.\n */\nexport function random(config?: RandomConfig): Offer {\n const chain = config?.chains\n ? config.chains[Random.int(config.chains.length)]!\n : Chain.chains.ethereum;\n\n const loanToken = config?.loanTokens\n ? config.loanTokens[Random.int(config.loanTokens.length)]!\n : Random.address();\n\n const collateralCandidates = config?.collateralTokens\n ? config.collateralTokens.filter((a) => a !== loanToken)\n : [Random.address()];\n\n const _collateralAsset = collateralCandidates[Random.int(collateralCandidates.length)]!;\n\n const maturityOption = weightedChoice<Maturity.MaturityOptions>([\n [\"end_of_month\", 1],\n [\"end_of_next_month\", 1],\n ]);\n\n const maturity = config?.maturity ?? Maturity.from(maturityOption);\n\n const lltv = LLTV.from(\n weightedChoice<(typeof LLTV.Options)[number]>([\n [0.385, 1],\n [0.5, 1],\n [0.625, 2],\n [0.77, 8],\n [0.86, 10],\n [0.915, 8],\n [0.945, 6],\n [0.965, 4],\n [0.98, 2],\n ]),\n );\n\n const buy = config?.buy !== undefined ? config.buy : Random.bool();\n\n const tickMin = buy ? 0 : 495;\n const tickMax = buy ? 495 : 990;\n const len = tickMax - tickMin + 1;\n const tickPairs: ReadonlyArray<readonly [number, number]> = Array.from(\n { length: len },\n (_, idx) => {\n // Make best prices rarer and worse prices more common (by side):\n // - Buy best is lower tick => weight increases with idx (higher tick)\n // - Sell best is higher tick => weight decreases with idx\n const weight = buy ? 1 + idx : 1 + (len - 1 - idx);\n return [tickMin + idx, weight] as const;\n },\n );\n const tick = config?.tick ?? weightedChoice<number>(tickPairs);\n\n const loanTokenDecimals = config?.assetsDecimals?.[loanToken] ?? 18;\n const unit = BigInt(10) ** BigInt(loanTokenDecimals);\n const amountBase = BigInt(100 + Random.int(1_000_000 - 100 + 1));\n const assetsScaled = config?.assets ?? amountBase * unit;\n\n const emptyCallback = { address: zeroAddress, data: \"0x\" as Hex } as const;\n const maker = config?.maker ?? Random.address();\n\n const offer = from({\n maker,\n assets: assetsScaled,\n obligationUnits: config?.obligationUnits ?? 0n,\n obligationShares: config?.obligationShares ?? 0n,\n tick,\n maturity: maturity,\n expiry: config?.expiry ?? maturity - 1,\n start: config?.start ?? maturity - 10,\n group: config?.group ?? Random.hex(32),\n session: config?.session ?? Random.hex(32),\n buy,\n chainId: chain.id,\n loanToken,\n collaterals:\n config?.collaterals ??\n Array.from({ length: Random.int(3) + 1 }, () => ({\n ...Collateral.random(),\n lltv,\n })).sort((a, b) => a.asset.localeCompare(b.asset)),\n callback: config?.callback ?? emptyCallback,\n receiverIfMakerIsSeller: config?.receiverIfMakerIsSeller ?? maker,\n });\n\n return offer;\n}\n\nconst weightedChoice = <T>(pairs: ReadonlyArray<readonly [T, number]>): T => {\n const total = pairs.reduce((sum, [, weight]) => sum + weight, 0);\n let roll = Random.float() * total;\n for (const [value, weight] of pairs) {\n roll -= weight;\n if (roll < 0) return value;\n }\n return pairs[0]![0];\n};\n\n/**\n * Creates an EIP-712 domain object.\n * @param chainId - The chain ID.\n * @returns The EIP-712 domain object.\n */\nexport const domain = (chainId: number) => ({\n chainId: BigInt(chainId),\n verifyingContract: zeroAddress,\n});\n\n/**\n * The EIP-712 types for the offer.\n * @warning The ordering of the types should NEVER be changed. The offer hash is computed based on the order of the types.\n * @returns The EIP-712 types.\n */\nexport const types = {\n EIP712Domain: [\n { name: \"chainId\", type: \"uint256\" },\n { name: \"verifyingContract\", type: \"address\" },\n ],\n Offer: [\n { name: \"maker\", type: \"address\" },\n { name: \"assets\", type: \"uint256\" },\n { name: \"obligationUnits\", type: \"uint256\" },\n { name: \"obligationShares\", type: \"uint256\" },\n { name: \"tick\", type: \"uint256\" },\n { name: \"maturity\", type: \"uint256\" },\n { name: \"expiry\", type: \"uint256\" },\n { name: \"group\", type: \"bytes32\" },\n { name: \"session\", type: \"bytes32\" },\n { name: \"buy\", type: \"bool\" },\n { name: \"loanToken\", type: \"address\" },\n { name: \"collaterals\", type: \"Collateral[]\" },\n { name: \"callback\", type: \"Callback\" },\n { name: \"receiverIfMakerIsSeller\", type: \"address\" },\n ],\n Collateral: [\n { name: \"asset\", type: \"address\" },\n { name: \"oracle\", type: \"address\" },\n { name: \"lltv\", type: \"uint256\" },\n ],\n Callback: [\n { name: \"address\", type: \"address\" },\n { name: \"data\", type: \"bytes\" },\n ],\n} as const;\n\nexport function hash(offer: Offer): Hex {\n const cached = (offer as { [HASH_CACHE]?: Hex })[HASH_CACHE];\n if (cached) return cached;\n\n const computed = hashTypedData({\n domain: domain(offer.chainId),\n message: {\n maker: offer.maker.toLowerCase() as Address,\n assets: offer.assets,\n obligationUnits: offer.obligationUnits,\n obligationShares: offer.obligationShares,\n tick: BigInt(offer.tick),\n maturity: BigInt(offer.maturity),\n expiry: BigInt(offer.expiry),\n group: offer.group,\n session: offer.session,\n buy: offer.buy,\n loanToken: offer.loanToken.toLowerCase() as Address,\n collaterals: offer.collaterals,\n callback: {\n address: offer.callback.address.toLowerCase() as Address,\n data: offer.callback.data,\n },\n receiverIfMakerIsSeller: offer.receiverIfMakerIsSeller.toLowerCase() as Address,\n },\n primaryType: \"Offer\",\n types,\n });\n\n (offer as { [HASH_CACHE]?: Hex })[HASH_CACHE] = computed;\n return computed;\n}\n\n/**\n * Calculates the obligation id for an offer based on the smart contract's Obligation struct.\n * The id is computed as keccak256(abi.encode(chainId, loanToken, collaterals (sorted by token address), maturity)).\n * @param offer - The offer to calculate the obligation id for.\n * @returns The obligation id as a 32-byte hex string.\n */\nexport function obligationId(offer: Offer): Hex {\n return Obligation.id(\n Obligation.from({\n chainId: offer.chainId,\n loanToken: offer.loanToken,\n collaterals: offer.collaterals as Collateral.Collateral[],\n maturity: offer.maturity,\n }),\n );\n}\n\nconst OfferAbi = [\n { name: \"maker\", type: \"address\" },\n { name: \"assets\", type: \"uint256\" },\n { name: \"obligationUnits\", type: \"uint256\" },\n { name: \"obligationShares\", type: \"uint256\" },\n { name: \"tick\", type: \"uint256\" },\n { name: \"maturity\", type: \"uint256\" },\n { name: \"expiry\", type: \"uint256\" },\n { name: \"group\", type: \"bytes32\" },\n { name: \"session\", type: \"bytes32\" },\n { name: \"buy\", type: \"bool\" },\n { name: \"chainId\", type: \"uint256\" },\n { name: \"loanToken\", type: \"address\" },\n { name: \"start\", type: \"uint256\" },\n {\n name: \"collaterals\",\n type: \"tuple[]\",\n components: [\n { name: \"asset\", type: \"address\" },\n { name: \"oracle\", type: \"address\" },\n { name: \"lltv\", type: \"uint256\" },\n ],\n },\n {\n name: \"callback\",\n type: \"tuple\",\n components: [\n { name: \"address\", type: \"address\" },\n { name: \"data\", type: \"bytes\" },\n ],\n },\n { name: \"receiverIfMakerIsSeller\", type: \"address\" },\n] as const;\n\nexport function encode(offer: Offer) {\n return encodeAbiParameters(OfferAbi, [\n offer.maker,\n offer.assets,\n offer.obligationUnits,\n offer.obligationShares,\n BigInt(offer.tick),\n BigInt(offer.maturity),\n BigInt(offer.expiry),\n offer.group,\n offer.session,\n offer.buy,\n BigInt(offer.chainId),\n offer.loanToken,\n BigInt(offer.start),\n offer.collaterals,\n offer.callback,\n offer.receiverIfMakerIsSeller,\n ]);\n}\n\nexport function decode(data: Hex): Offer {\n let decoded: DecodeAbiParametersReturnType<typeof OfferAbi>;\n try {\n decoded = decodeAbiParameters(OfferAbi, data);\n } catch (error) {\n throw new InvalidOfferError(error as Error);\n }\n\n const offer = from({\n maker: decoded[0],\n assets: decoded[1],\n obligationUnits: decoded[2],\n obligationShares: decoded[3],\n tick: Number(decoded[4]),\n maturity: Maturity.from(Number(decoded[5])),\n expiry: Number(decoded[6]),\n group: decoded[7],\n session: decoded[8],\n buy: decoded[9],\n chainId: Number(decoded[10]),\n loanToken: decoded[11],\n start: Number(decoded[12]),\n collaterals: decoded[13].map((c) => {\n return Collateral.from({\n asset: c.asset,\n oracle: c.oracle,\n lltv: c.lltv,\n });\n }),\n callback: {\n address: decoded[14].address,\n data: decoded[14].data,\n },\n receiverIfMakerIsSeller: decoded[15],\n });\n\n return offer;\n}\n\nexport type OfferConsumed = {\n id: string;\n chainId: Chain.Id;\n maker: Address;\n group: Hex;\n amount: bigint;\n blockNumber: number;\n};\n\n/**\n * ABI for the Take event emitted by the Morpho V2 contract.\n */\nexport const takeEvent = {\n type: \"event\",\n name: \"Take\",\n inputs: [\n { name: \"caller\", type: \"address\", indexed: false, internalType: \"address\" },\n { name: \"id\", type: \"bytes32\", indexed: true, internalType: \"bytes32\" },\n { name: \"maker\", type: \"address\", indexed: true, internalType: \"address\" },\n { name: \"taker\", type: \"address\", indexed: true, internalType: \"address\" },\n { name: \"offerIsBuy\", type: \"bool\", indexed: false, internalType: \"bool\" },\n { name: \"buyerAssets\", type: \"uint256\", indexed: false, internalType: \"uint256\" },\n { name: \"sellerAssets\", type: \"uint256\", indexed: false, internalType: \"uint256\" },\n { name: \"obligationUnits\", type: \"uint256\", indexed: false, internalType: \"uint256\" },\n { name: \"obligationShares\", type: \"uint256\", indexed: false, internalType: \"uint256\" },\n { name: \"buyerIsLender\", type: \"bool\", indexed: false, internalType: \"bool\" },\n { name: \"sellerIsBorrower\", type: \"bool\", indexed: false, internalType: \"bool\" },\n { name: \"sellerReceiver\", type: \"address\", indexed: false, internalType: \"address\" },\n { name: \"group\", type: \"bytes32\", indexed: false, internalType: \"bytes32\" },\n { name: \"consumed\", type: \"uint256\", indexed: false, internalType: \"uint256\" },\n ],\n anonymous: false,\n} as const;\n\n/**\n * ABI for the Consume event emitted by the Obligation contract.\n */\nexport const consumedEvent = {\n type: \"event\",\n name: \"Consume\",\n inputs: [\n { name: \"user\", type: \"address\", indexed: true, internalType: \"address\" },\n { name: \"group\", type: \"bytes32\", indexed: true, internalType: \"bytes32\" },\n { name: \"amount\", type: \"uint256\", indexed: false, internalType: \"uint256\" },\n ],\n anonymous: false,\n} as const;\n\nexport class InvalidOfferError extends Errors.BaseError<z.ZodError | Error> {\n override readonly name = \"Offer.InvalidOfferError\";\n\n constructor(error: z.ZodError | Error) {\n super(\"Invalid offer.\", {\n cause: error,\n });\n }\n\n /**\n * Formats ZodError issues into a human-readable string with line breaks.\n * @example\n * \"- 'assets': too small, expected >= 0\n * - 'start': must be before expiry\"\n */\n static formatDetails(error: z.ZodError | Error): string {\n if (!(error instanceof z.ZodError)) {\n return error.message;\n }\n\n return error.issues\n .map((issue) => {\n const path = issue.path.join(\".\");\n const normalized = issue.message.trim();\n return `'${path}': ${normalized.toLowerCase()}`;\n })\n .join(\". \");\n }\n\n /**\n * Returns the formatted human-readable message.\n */\n get formattedMessage(): string {\n return `Invalid offer. ${InvalidOfferError.formatDetails(this.cause)}`;\n }\n}\n","import type { Address } from \"viem\";\nimport type * as Chain from \"./Chain.ts\";\nimport type * as Collateral from \"./Collateral.ts\";\nimport type * as Offer from \"./Offer.ts\";\n\n/**\n * An oracle contract that provides price information for assets.\n */\nexport type Oracle = {\n /** The chain id where the oracle is deployed. */\n readonly chainId: Chain.Id;\n /** The address of the oracle contract. */\n readonly address: Address;\n /** The price returned by the oracle (in the oracle's native units), null if no price available. */\n readonly price: bigint | null;\n /** The block number at which the price was fetched. */\n readonly blockNumber: number;\n};\n\n/**\n * Create an Oracle from a plain object.\n * @param data - The data to create the oracle from.\n * @returns The created oracle.\n */\nexport function from(data: from.Parameters): from.ReturnType {\n return {\n chainId: data.chainId,\n address: data.address.toLowerCase() as Address,\n price: data.price ? BigInt(data.price) : null,\n blockNumber: data.blockNumber,\n };\n}\n\nexport declare namespace from {\n export type Parameters = {\n chainId: Chain.Id;\n address: Address;\n price: string | null;\n blockNumber: number;\n };\n\n export type ReturnType = Oracle;\n}\n\n/**\n * Creates an oracle from a collateral.\n * @constructor\n *\n * @param parameters - {@link fromCollateral.Parameters}\n * @returns The created oracle. {@link fromCollateral.ReturnType}\n */\nexport function fromCollateral(parameters: fromCollateral.Parameters): fromCollateral.ReturnType {\n const { chainId, collateral, blockNumber, price = null } = parameters;\n return {\n chainId,\n address: collateral.oracle.toLowerCase() as Address,\n price,\n blockNumber,\n };\n}\n\nexport declare namespace fromCollateral {\n export type Parameters = {\n chainId: Chain.Id;\n collateral: Collateral.Collateral;\n blockNumber: number;\n price?: bigint | null;\n };\n\n export type ReturnType = Oracle;\n}\n\n/**\n * Creates oracles from a single offer.\n * @constructor\n *\n * @param parameters - {@link fromOffer.Parameters}\n * @returns The created oracles. {@link fromOffer.ReturnType}\n */\nexport function fromOffer(parameters: fromOffer.Parameters): fromOffer.ReturnType {\n const { offer, blockNumber, price = null } = parameters;\n return fromOffers({ offers: [offer], blockNumber, price });\n}\n\nexport declare namespace fromOffer {\n export type Parameters = {\n offer: Offer.Offer;\n blockNumber: number;\n price?: bigint | null;\n };\n\n export type ReturnType = Oracle[];\n}\n\n/**\n * Creates oracles from a list of offers.\n * @constructor\n *\n * @param parameters - {@link fromOffers.Parameters}\n * @returns The created oracles. {@link fromOffers.ReturnType}\n */\nexport function fromOffers(parameters: fromOffers.Parameters): fromOffers.ReturnType {\n const { offers, blockNumber, price = null } = parameters;\n const rowsByKey = new Map<string, Oracle>();\n\n for (const offer of offers) {\n for (const collateral of offer.collaterals) {\n const key = `${offer.chainId}-${collateral.oracle}`.toLowerCase();\n if (rowsByKey.has(key)) continue;\n rowsByKey.set(\n key,\n fromCollateral({\n chainId: offer.chainId,\n collateral,\n blockNumber,\n price,\n }),\n );\n }\n }\n\n return Array.from(rowsByKey.values());\n}\n\nexport declare namespace fromOffers {\n export type Parameters = {\n offers: Offer.Offer[];\n blockNumber: number;\n price?: bigint | null;\n };\n\n export type ReturnType = Oracle[];\n}\n\n/**\n * Conversion utilities for converting between collateral and loan token amounts\n * using oracle prices and LLTV\n */\nexport namespace Conversion {\n /**\n * Converts a collateral amount to loan token\n * Uses the formula: (amount * price / 10^36) * lltv / 10^18\n *\n * @param amount - The collateral amount to convert\n * @param params - Conversion parameters containing price (36 decimals) and lltv (18 decimals)\n * @returns The equivalent loan token amount\n */\n export function collateralToLoan(\n amount: bigint,\n params: { price: bigint; lltv: bigint },\n ): bigint {\n return (((amount * params.price) / 10n ** 36n) * params.lltv) / 10n ** 18n;\n }\n\n /**\n * Converts a loan token amount to collateral\n * Uses the inverse formula: (amount * 10^36 / price) * 10^18 / lltv\n * Returns 0n if price or lltv is zero (invalid conversion).\n *\n * @param amount - The loan token amount to convert\n * @param params - Conversion parameters containing price (36 decimals) and lltv (18 decimals)\n * @returns The equivalent collateral amount, or 0n if conversion is invalid\n */\n export function loanToCollateral(\n amount: bigint,\n params: { price: bigint; lltv: bigint },\n ): bigint {\n if (params.price === 0n || params.lltv === 0n) return 0n;\n return (((amount * 10n ** 36n) / params.price) * 10n ** 18n) / params.lltv;\n }\n}\n","import type { Address } from \"viem\";\nimport type * as Chain from \"./Chain.ts\";\n\nexport type Position = {\n /** The chain id. */\n chainId: Chain.Id;\n /** The contract address from which the position is called.\n * While balances are obviously tracked on ERC20 contracts, we prefer to track which contract is called to know the balance.\n * For example, when depositing into a vault, we would specify the vault contract address as the contract not the underlying vault's ERC20 token address.\n */\n contract: Address;\n /** The user address. */\n user: Address;\n /** The type of position. */\n type: Type;\n /** The balance of the position. */\n balance?: bigint;\n /** The underlying asset of the position.\n * For ERC20 positions, this equals the contract address.\n * For vault positions, this is the vault's underlying asset.\n */\n asset?: Address;\n /** The block number at which the position was last updated. */\n blockNumber: number;\n};\n\nexport enum Type {\n ERC20 = \"erc20\",\n VAULT_V1 = \"vault_v1\",\n}\n\n/**\n * @constructor\n * Creates a Position.\n * @param parameters - {@link from.Parameters}\n * @returns The created Position. {@link from.ReturnType}\n */\nexport function from(parameters: from.Parameters): from.ReturnType {\n return {\n chainId: parameters.chainId,\n contract: parameters.contract.toLowerCase() as Address,\n user: parameters.user.toLowerCase() as Address,\n type: parameters.type,\n balance: parameters.balance,\n ...(parameters.asset !== undefined ? { asset: parameters.asset.toLowerCase() as Address } : {}),\n blockNumber: parameters.blockNumber,\n };\n}\n\nexport declare namespace from {\n type Parameters = {\n chainId: Chain.Id;\n contract: Address;\n user: Address;\n type: Type;\n balance?: bigint;\n asset?: Address;\n blockNumber: number;\n };\n type ReturnType = Position;\n}\n","import * as Errors from \"#utils/Errors.ts\";\n\n/** ln(1 + 0.025), scaled by 1e18. Matches TickLib onchain constant. */\nconst LN_ONE_PLUS_DELTA = 24_692_612_590_371_501n;\n/** ln(2), scaled by 1e18. Matches TickLib onchain constant. */\nconst LN2 = 693_147_180_559_945_309n;\nconst WAD = 10n ** 18n;\nconst WAD_SQUARED = 10n ** 36n;\nconst PRICE_STEP = 10n ** 13n;\nconst HALF_TICK_RANGE = 495n;\n\n/** Tick domain supported by Morpho V2. */\nexport const TICK_RANGE = 990;\n/** Max allowed price (1e18 in wad). */\nexport const MAX_PRICE = WAD;\n\n/**\n * Converts a tick to a wad price using the same approximation and rounding as TickLib.\n * @param tick - Tick value in the inclusive range [0, 990].\n * @returns The price in wad units.\n * @throws {@link InvalidTickError} If tick is not an integer in range [0, 990].\n */\nexport function tickToPrice(tick: number): bigint {\n assertTick(tick);\n\n const exponent = LN_ONE_PLUS_DELTA * (HALF_TICK_RANGE - BigInt(tick));\n return (\n divHalfDownUnchecked(divHalfDownUnchecked(WAD_SQUARED, WAD + wExp(exponent)), PRICE_STEP) *\n PRICE_STEP\n );\n}\n\nexport declare namespace tickToPrice {\n type ErrorType = InvalidTickError;\n}\n\n/**\n * Returns the lowest tick with a higher-or-equal price.\n * @param price - Price in wad units.\n * @returns The first tick whose {@link tickToPrice} is greater than or equal to `price`.\n * @throws {@link InvalidPriceError} If price is outside [0, 1e18].\n */\nexport function priceToTick(price: bigint): number {\n assertPrice(price);\n\n let low = 0;\n let high = TICK_RANGE;\n while (low !== high) {\n const mid = Math.floor((low + high) / 2);\n if (tickToPrice(mid) < price) low = mid + 1;\n else high = mid;\n }\n\n return low;\n}\n\nexport declare namespace priceToTick {\n type ErrorType = InvalidPriceError;\n}\n\nfunction divHalfDownUnchecked(x: bigint, d: bigint): bigint {\n return (x + (d - 1n) / 2n) / d;\n}\n\nfunction wExp(x: bigint): bigint {\n if (x < 0n) {\n return WAD_SQUARED / wExp(-x);\n }\n\n const q = (x + LN2 / 2n) / LN2;\n const r = x - q * LN2;\n const secondTerm = (r * r) / (2n * WAD);\n const thirdTerm = (secondTerm * r) / (3n * WAD);\n const expR = WAD + r + secondTerm + thirdTerm;\n\n return expR << q;\n}\n\nfunction assertTick(tick: number): void {\n if (!Number.isInteger(tick) || tick < 0 || tick > TICK_RANGE) {\n throw new InvalidTickError(tick);\n }\n}\n\nfunction assertPrice(price: bigint): void {\n if (price < 0n || price > MAX_PRICE) {\n throw new InvalidPriceError(price);\n }\n}\n\nexport class InvalidTickError extends Errors.BaseError {\n override readonly name = \"Tick.InvalidTickError\";\n constructor(tick: number) {\n super(`Invalid tick: ${tick}. Tick must be an integer between 0 and ${TICK_RANGE}.`);\n }\n}\n\nexport class InvalidPriceError extends Errors.BaseError {\n override readonly name = \"Tick.InvalidPriceError\";\n constructor(price: bigint) {\n super(`Invalid price: ${price}. Price must be between 0 and ${MAX_PRICE}.`);\n }\n}\n","import type { Hex } from \"viem\";\nimport * as z from \"zod\";\nimport { Obligation } from \"#core\";\nimport * as Tick from \"#core/Tick.ts\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport * as Format from \"#utils/Format.ts\";\nimport * as Random from \"#utils/Random.ts\";\nimport { transformHex } from \"#utils/zod.ts\";\n\nexport type Side = {\n /** The best side tick, or null when no active quote exists. */\n tick: number | null;\n /** The side price for the obligation. (18 decimals). */\n price: bigint;\n};\n\nexport type QuoteInput = {\n /** The obligation id. */\n obligationId: Hex;\n ask: {\n /** The best ask tick, or null when there is no active ask quote. */\n tick: number | null;\n };\n bid: {\n /** The best bid tick, or null when there is no active bid quote. */\n tick: number | null;\n };\n};\n\nexport type Quote = {\n /** The obligation id. */\n obligationId: Hex;\n ask: Side;\n bid: Side;\n};\n\nconst SideInputSchema = z\n .object({\n tick: z.number().int().min(0).max(Tick.TICK_RANGE).nullable(),\n })\n .strict();\n\nconst QuoteInputSchema = z\n .object({\n obligationId: z.string().transform(transformHex),\n ask: SideInputSchema,\n bid: SideInputSchema,\n })\n .strict();\n\n/**\n * Creates a quote for a given obligation.\n * @constructor\n * @param parameters - {@link from.Parameters}\n * @returns The created quote. {@link Quote}\n * @throws If the quote is invalid. {@link InvalidQuoteError}\n *\n * @example\n * ```ts\n * const quote = Quote.from({ obligationId: \"0x123\", ask: { tick: 500 }, bid: { tick: 510 } });\n * ```\n */\nexport function from(parameters: from.Parameters): from.ReturnType {\n try {\n const parsedQuote = QuoteInputSchema.parse(parameters);\n return {\n obligationId: parsedQuote.obligationId,\n ask: sideFromTick(parsedQuote.ask),\n bid: sideFromTick(parsedQuote.bid),\n };\n } catch (error: unknown) {\n throw new InvalidQuoteError(error as z.ZodError | Error);\n }\n}\n\nexport declare namespace from {\n type Parameters = QuoteInput;\n type ReturnType = Quote;\n type ErrorType = InvalidQuoteError;\n}\n\n/**\n * Creates a quote from a snake case object.\n * @throws If the quote is invalid. {@link InvalidQuoteError}\n * @param snake - {@link fromSnakeCase.Parameters}\n * @returns The created quote. {@link fromSnakeCase.ReturnType}\n */\nexport function fromSnakeCase(snake: fromSnakeCase.Parameters): fromSnakeCase.ReturnType {\n return from(Format.fromSnakeCase<QuoteInput>(snake));\n}\n\nexport declare namespace fromSnakeCase {\n type Parameters = Format.Snake<QuoteInput>;\n type ReturnType = Quote;\n type ErrorType = from.ErrorType;\n}\n\n/**\n * Generates a random quote.\n * @returns A randomly generated quote. {@link random.ReturnType}\n *\n * @example\n * ```ts\n * const quote = Quote.random();\n * ```\n */\nexport function random(): random.ReturnType {\n return from({\n obligationId: Obligation.id(Obligation.random()),\n ask: {\n tick: Random.int(Tick.TICK_RANGE + 1),\n },\n bid: {\n tick: Random.int(Tick.TICK_RANGE + 1),\n },\n });\n}\n\nexport declare namespace random {\n type Parameters = never;\n type ReturnType = Quote;\n type ErrorType = from.ErrorType;\n}\n\nexport class InvalidQuoteError extends Errors.BaseError<z.ZodError | Error> {\n override readonly name = \"Quote.InvalidQuoteError\";\n constructor(error: z.ZodError | Error) {\n super(\"Invalid quote.\", { cause: error });\n }\n}\n\nfunction sideFromTick(side: z.infer<typeof SideInputSchema>): Side {\n return {\n tick: side.tick,\n price: side.tick === null ? 0n : Tick.tickToPrice(side.tick),\n };\n}\n","import * as Errors from \"#utils/Errors.ts\";\nimport type { Brand } from \"./types.ts\";\n\n/**\n * Time breakpoints in seconds for piecewise linear fee interpolation.\n * Matches on-chain constants: 0d, 1d, 7d, 30d, 90d, 180d.\n */\nexport const BREAKPOINTS = [\n 0n,\n 86400n, // 1 day\n 604800n, // 7 days\n 2592000n, // 30 days\n 7776000n, // 90 days\n 15552000n, // 180 days\n] as const;\n\n/** WAD constant (1e18) for fee scaling. */\nexport const WAD = 10n ** 18n;\n\n/** Tuple type for the 6 fee values at each breakpoint. */\nexport type Fees = readonly [bigint, bigint, bigint, bigint, bigint, bigint];\n\n/**\n * TradingFee represents a piecewise linear fee curve with 6 breakpoints.\n * The internal storage mimics on-chain bitmap behavior but uses a struct for clarity.\n */\nexport type TradingFee = {\n readonly _activated: boolean;\n readonly _fees: Fees;\n} & Brand<\"TradingFee\">;\n\n/**\n * Create a TradingFee from an activation flag and 6 fee values.\n * @param activated - Whether the fee is active.\n * @param fees - Tuple of 6 fee values in WAD (one per breakpoint: 0d, 1d, 7d, 30d, 90d, 180d).\n * @returns A new TradingFee instance.\n * @throws {@link InvalidFeeError} if any fee exceeds WAD (100%).\n * @throws {@link InvalidFeesLengthError} if fees array doesn't have exactly 6 elements.\n */\nexport function from(activated: boolean, fees: Fees): TradingFee {\n if (fees.length !== 6) {\n throw new InvalidFeesLengthError(fees.length);\n }\n for (let i = 0; i < 6; i++) {\n const fee = fees[i] as bigint;\n if (fee < 0n || fee > WAD) {\n throw new InvalidFeeError(fee, i);\n }\n }\n // Defensive copy and freeze to guarantee immutability\n const frozenFees = Object.freeze([...fees]) as Fees;\n return Object.freeze({\n _activated: activated,\n _fees: frozenFees,\n }) as TradingFee;\n}\n\nexport declare namespace from {\n type ErrorType = InvalidFeeError | InvalidFeesLengthError;\n}\n\n/**\n * Compute the trading fee for a given time to maturity using piecewise linear interpolation.\n * @param tradingFee - The TradingFee instance.\n * @param timeToMaturity - Time to maturity in seconds.\n * @returns The interpolated fee in WAD. Returns 0n if not activated.\n */\nexport function compute(tradingFee: TradingFee, timeToMaturity: number): bigint {\n if (!tradingFee._activated) {\n return 0n;\n }\n\n const time = BigInt(Math.max(0, Math.floor(timeToMaturity)));\n\n // If beyond 180 days, return the 180d fee\n if (time >= BREAKPOINTS[5]) {\n return tradingFee._fees[5];\n }\n\n // Find the segment for interpolation\n const { index, start, end } = getSegment(time);\n\n const feeLower = tradingFee._fees[index] as bigint;\n const feeUpper = tradingFee._fees[index + 1] as bigint;\n\n // Linear interpolation: (feeLower * (end - t) + feeUpper * (t - start)) / (end - start)\n const segmentLength = end - start;\n return (feeLower * (end - time) + feeUpper * (time - start)) / segmentLength;\n}\n\n/**\n * Check if the trading fee is activated.\n * @param tradingFee - The TradingFee instance.\n * @returns True if activated, false otherwise.\n */\nexport function isActivated(tradingFee: TradingFee): boolean {\n return tradingFee._activated;\n}\n\n/**\n * Create a new TradingFee with activation enabled.\n * @param tradingFee - The TradingFee instance.\n * @returns A new TradingFee with activated set to true.\n */\nexport function activate(tradingFee: TradingFee): TradingFee {\n return Object.freeze({\n _activated: true,\n _fees: tradingFee._fees, // Already frozen from construction\n }) as TradingFee;\n}\n\n/**\n * Create a new TradingFee with activation disabled.\n * @param tradingFee - The TradingFee instance.\n * @returns A new TradingFee with activated set to false.\n */\nexport function deactivate(tradingFee: TradingFee): TradingFee {\n return Object.freeze({\n _activated: false,\n _fees: tradingFee._fees, // Already frozen from construction\n }) as TradingFee;\n}\n\n/**\n * Get the fee values at each breakpoint.\n * @param tradingFee - The TradingFee instance.\n * @returns The tuple of 6 fee values.\n */\nexport function getFees(tradingFee: TradingFee): Fees {\n return tradingFee._fees;\n}\n\n/**\n * Determine which segment a timeToMaturity falls into for interpolation.\n * @param timeToMaturity - Time to maturity in seconds.\n * @returns Object with index, start, and end of the segment.\n */\nfunction getSegment(timeToMaturity: bigint): { index: number; start: bigint; end: bigint } {\n if (timeToMaturity < BREAKPOINTS[1]) {\n return { index: 0, start: BREAKPOINTS[0], end: BREAKPOINTS[1] };\n }\n if (timeToMaturity < BREAKPOINTS[2]) {\n return { index: 1, start: BREAKPOINTS[1], end: BREAKPOINTS[2] };\n }\n if (timeToMaturity < BREAKPOINTS[3]) {\n return { index: 2, start: BREAKPOINTS[2], end: BREAKPOINTS[3] };\n }\n if (timeToMaturity < BREAKPOINTS[4]) {\n return { index: 3, start: BREAKPOINTS[3], end: BREAKPOINTS[4] };\n }\n return { index: 4, start: BREAKPOINTS[4], end: BREAKPOINTS[5] };\n}\n\n/** Error thrown when a fee value is invalid (negative or exceeds WAD). */\nexport class InvalidFeeError extends Errors.BaseError {\n override readonly name = \"TradingFee.InvalidFeeError\";\n constructor(fee: bigint, index: number) {\n super(`Invalid fee at index ${index}: ${fee}. Fee must be between 0 and ${WAD} (WAD).`);\n }\n}\n\n/** Error thrown when fees array doesn't have exactly 6 elements. */\nexport class InvalidFeesLengthError extends Errors.BaseError {\n override readonly name = \"TradingFee.InvalidFeesLengthError\";\n constructor(length: number) {\n super(`Invalid fees length: ${length}. Expected exactly 6 fee values.`);\n }\n}\n","import type { Address } from \"viem\";\nimport type * as Chain from \"./Chain.ts\";\n\nexport type Transfer = {\n id: string;\n chainId: Chain.Id;\n contract: Address;\n from: Address;\n to: Address;\n value: bigint;\n blockNumber: number;\n};\n\n/**\n * @constructor\n *\n * Creates a {@link Transfer}.\n * @param parameters - {@link from.Parameters}\n * @returns The created Transfer. {@link from.ReturnType}\n *\n * @example\n * ```ts\n * const transfer = Transfer.from({ id: \"1\", chainId: 1, contract: \"0x123\", from: \"0x456\", to: \"0x789\", value: 100n, blockNumber: 100n });\n * ```\n */\nexport function from(parameters: from.Parameters): from.ReturnType {\n return {\n id: parameters.id,\n chainId: parameters.chainId,\n contract: parameters.contract.toLowerCase() as Address,\n from: parameters.from.toLowerCase() as Address,\n to: parameters.to.toLowerCase() as Address,\n value: parameters.value,\n blockNumber: parameters.blockNumber,\n };\n}\n\nexport declare namespace from {\n type Parameters = {\n id: string;\n chainId: Chain.Id;\n contract: Address;\n from: Address;\n to: Address;\n value: bigint;\n blockNumber: number;\n };\n\n type ReturnType = Transfer;\n}\n","import { StandardMerkleTree } from \"@openzeppelin/merkle-tree\";\nimport { gzip, ungzip } from \"pako\";\nimport {\n type Address,\n bytesToHex,\n type Hex,\n hashTypedData,\n hexToBytes,\n isAddress,\n isHex,\n recoverAddress,\n} from \"viem\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport * as Offer from \"./Offer.ts\";\nimport type { Compute } from \"./types.ts\";\n\n/**\n * A merkle tree of offers built from offer hashes.\n * Constructed via {@link from}. The tree root can be signed for onchain broadcast.\n */\nexport type Tree = Compute<\n StandardMerkleTree<[Hex]> & {\n /** The offers in the tree. */\n offers: Offer.Offer[];\n /** The root of the tree. */\n root: Hex;\n }\n>;\n\nexport type Proof = {\n /** The offer that the proof is for. */\n offer: Offer.Offer;\n /** The merkle proof path for the offer. */\n path: Hex[];\n};\n\nexport const VERSION = 1;\n\nexport type SignatureDomain = {\n /** Chain id used in the EIP-712 domain. */\n chainId: number | bigint;\n /** MorphoV2 contract address used as verifying contract. */\n verifyingContract: Address;\n};\n\n/** Normalized Root signature domain (BigInt chain id, lowercase address). */\nexport type NormalizedSignatureDomain = {\n chainId: bigint;\n verifyingContract: Address;\n};\n\n/**\n * EIP-712 types for signing the tree root (Root(bytes32 root)).\n */\nexport const signatureTypes = {\n EIP712Domain: [\n { name: \"chainId\", type: \"uint256\" },\n { name: \"verifyingContract\", type: \"address\" },\n ],\n Root: [{ name: \"root\", type: \"bytes32\" }],\n} as const;\n\nconst normalizeHash = (hash: Hex): Hex => hash.toLowerCase() as Hex;\n\n/**\n * Builds a Merkle tree from a list of offers.\n *\n * Leaves are the offer `hash` values as `bytes32` and are deterministically\n * ordered following the StandardMerkleTree leaf ordering so that the resulting\n * root is stable regardless of the input order.\n *\n * @param offers - Offers to include in the tree.\n * @returns A `StandardMerkleTree` of `bytes32` leaves representing the offers.\n * @throws {TreeError} If tree building fails due to offer inconsistencies.\n */\nexport const from = (offers: Offer.Offer[]): Tree => {\n const leaves = offers.map<[Hex]>((offer) => [Offer.hash(offer)]);\n const tree = StandardMerkleTree.of<[Hex]>(leaves, [\"bytes32\"]);\n const orderedOffers = orderOffers(tree, offers);\n return Object.assign(tree, { offers: orderedOffers }) as Tree;\n};\n\nconst orderOffers = (tree: StandardMerkleTree<[Hex]>, offers: Offer.Offer[]): Offer.Offer[] => {\n const offerByHash = new Map<Hex, Offer.Offer>();\n for (const offer of offers) {\n offerByHash.set(normalizeHash(Offer.hash(offer)), offer);\n }\n\n const entries = tree.dump().values.map((value) => {\n const hash = normalizeHash(value.value[0] as Hex);\n const offer = offerByHash.get(hash);\n if (!offer) {\n throw new TreeError(`missing offer for leaf ${hash}`);\n }\n return { offer, treeIndex: value.treeIndex };\n });\n\n entries.sort((a, b) => b.treeIndex - a.treeIndex);\n return entries.map((item) => item.offer);\n};\n\n/**\n * Generates merkle proofs for all offers in a tree.\n *\n * Each proof allows independent verification that an offer is included in the tree\n * without requiring the full tree. Proofs are ordered by StandardMerkleTree leaf ordering.\n *\n * @param tree - The {@link Tree} to generate proofs for.\n * @returns Array of proofs - {@link Proof}\n */\nexport const proofs = (tree: Tree): Proof[] => {\n return tree.offers.map((offer) => {\n const path = tree.getProof([Offer.hash(offer)] as [Hex]) as Hex[];\n return { offer, path };\n });\n};\n\n/**\n * Normalizes a Root signature domain (BigInt chain id, lowercase address).\n * @throws {SignatureDomainError} When the domain is invalid.\n */\nexport const signatureDomain = (domain: SignatureDomain): NormalizedSignatureDomain => {\n return normalizeSignatureDomain(domain, (reason) => new SignatureDomainError(reason));\n};\n\nconst normalizeSignatureDomain = (\n domain: SignatureDomain,\n errorFactory: (reason: string) => Errors.BaseError,\n): NormalizedSignatureDomain => {\n let chainId: bigint;\n try {\n chainId = typeof domain.chainId === \"bigint\" ? domain.chainId : BigInt(domain.chainId);\n } catch {\n throw errorFactory(\"invalid chainId\");\n }\n\n if (chainId < 0n) throw errorFactory(\"invalid chainId\");\n if (!isAddress(domain.verifyingContract)) throw errorFactory(\"invalid verifyingContract\");\n\n return {\n chainId,\n verifyingContract: domain.verifyingContract.toLowerCase() as Address,\n };\n};\n\nconst assertHex = (\n value: unknown,\n expectedBytes: number,\n name: string,\n errorFactory: (reason: string) => Errors.BaseError = (reason) => new DecodeError(reason),\n): void => {\n if (typeof value !== \"string\" || !isHex(value)) {\n throw errorFactory(`${name} is not a valid hex string`);\n }\n if (hexToBytes(value).length !== expectedBytes) {\n throw errorFactory(`${name}: expected ${expectedBytes} bytes`);\n }\n};\n\nconst verifySignatureAndRecoverAddress = async (params: {\n root: Hex;\n signature: Hex;\n domain: NormalizedSignatureDomain;\n errorFactory: (reason: string) => Errors.BaseError;\n}): Promise<Address> => {\n const { root, signature, domain, errorFactory } = params;\n assertHex(root, 32, \"root\", errorFactory);\n assertHex(signature, 65, \"signature\", errorFactory);\n const hash = hashTypedData({\n domain,\n types: signatureTypes,\n primaryType: \"Root\",\n message: { root },\n });\n try {\n return await recoverAddress({ hash, signature });\n } catch {\n throw errorFactory(\"signature recovery failed\");\n }\n};\n\n/**\n * Encodes a merkle tree with signature into hex calldata for onchain broadcast.\n *\n * Layout: `0x{vv}{gzip([...offers])}{root}{signature}` where:\n * - `{vv}`: 1-byte version (currently 0x01)\n * - `{gzip([...offers])}`: gzipped JSON array of serialized offers\n * - `{root}`: 32-byte merkle root\n * - `{signature}`: 65-byte EIP-712 signature over Root(bytes32 root)\n *\n * Validates signature authenticity and root integrity before encoding.\n *\n * @example\n * ```typescript\n * const tree = Tree.from(offers);\n * const signature = await wallet.signTypedData({\n * account: wallet.account,\n * domain: Tree.signatureDomain({ chainId, verifyingContract }),\n * types: Tree.signatureTypes,\n * primaryType: \"Root\",\n * message: { root: tree.root },\n * });\n * const calldata = await Tree.encode(tree, signature, { chainId, verifyingContract });\n * await broadcast(calldata);\n * ```\n *\n * @example\n * Manual construction (for advanced users):\n * ```typescript\n * const tree = Tree.from(offers);\n * const compressed = gzip(JSON.stringify(tree.offers.map(Offer.serialize)));\n * const partial = `0x01${bytesToHex(compressed)}${tree.root.slice(2)}`;\n * const signature = await wallet.signTypedData({\n * account: wallet.account,\n * domain: Tree.signatureDomain({ chainId, verifyingContract }),\n * types: Tree.signatureTypes,\n * primaryType: \"Root\",\n * message: { root: tree.root },\n * });\n * const calldata = `${partial}${signature.slice(2)}`;\n * ```\n *\n * @param tree - Merkle tree of offers\n * @param signature - EIP-712 signature over Root(bytes32 root)\n * @param domain - EIP-712 domain with chain id and verifying contract\n * @returns Hex-encoded calldata ready for onchain broadcast\n * @throws {EncodeError} If signature verification fails or root mismatch\n */\nexport const encode = async (tree: Tree, signature: Hex, domain: SignatureDomain): Promise<Hex> => {\n const errorFactory = (reason: string) => new EncodeError(reason);\n const normalizedDomain = normalizeSignatureDomain(domain, errorFactory);\n validateTreeForEncoding(tree, normalizedDomain);\n await verifySignatureAndRecoverAddress({\n root: tree.root,\n signature,\n domain: normalizedDomain,\n errorFactory,\n });\n\n const unsigned = encodeUnsignedBytes(tree);\n const sigBytes = hexToBytes(signature);\n const encoded = new Uint8Array(unsigned.length + sigBytes.length);\n encoded.set(unsigned, 0);\n encoded.set(sigBytes, unsigned.length);\n\n return bytesToHex(encoded);\n};\n\n/**\n * Encodes a merkle tree without a signature into hex payload for client-side signing.\n *\n * Layout: `0x{vv}{gzip([...offers])}{root}` where:\n * - `{vv}`: 1-byte version (currently 0x01)\n * - `{gzip([...offers])}`: gzipped JSON array of serialized offers\n * - `{root}`: 32-byte merkle root\n *\n * Validates root integrity before encoding.\n *\n * @param tree - Merkle tree of offers\n * @returns Hex-encoded unsigned payload\n * @throws {EncodeError} If root mismatch\n */\nexport const encodeUnsigned = (tree: Tree): Hex => {\n validateTreeForEncoding(tree);\n return bytesToHex(encodeUnsignedBytes(tree));\n};\n\nconst validateTreeForEncoding = (tree: Tree, domain?: NormalizedSignatureDomain): void => {\n if (VERSION > 0xff) throw new EncodeError(`version overflow: ${VERSION} exceeds 255`);\n\n const computed = from(tree.offers);\n if (tree.root !== computed.root)\n throw new EncodeError(`root mismatch: expected ${computed.root}, got ${tree.root}`);\n\n if (domain) {\n const mismatched = tree.offers.find((offer) => BigInt(offer.chainId) !== domain.chainId);\n if (mismatched) {\n throw new EncodeError(\n `chainId mismatch: expected ${domain.chainId}, got ${mismatched.chainId}`,\n );\n }\n }\n};\n\nconst encodeUnsignedBytes = (tree: Tree): Uint8Array => {\n const offersPayload = tree.offers.map(Offer.serialize);\n const compressed = gzip(JSON.stringify(offersPayload));\n const rootBytes = hexToBytes(tree.root);\n const encoded = new Uint8Array(1 + compressed.length + 32);\n encoded[0] = VERSION;\n encoded.set(compressed, 1);\n encoded.set(rootBytes, 1 + compressed.length);\n return encoded;\n};\n\n/**\n * Decodes hex calldata into a validated merkle tree.\n *\n * Validates signature before decompression for fail-fast rejection of invalid payloads.\n * Returns the tree with separately validated signature and recovered signer address.\n *\n * Validation order:\n * 1. Version check\n * 2. Signature verification (fail-fast, before decompression)\n * 3. Decompression (only if signature valid)\n * 4. Root verification (computed from offers vs embedded root)\n *\n * @example\n * ```typescript\n * const { tree, signature, signer } = await Tree.decode(calldata, { chainId, verifyingContract });\n * console.log(`Tree signed by ${signer} with ${tree.offers.length} offers`);\n * ```\n *\n * @param encoded - Hex calldata in format `0x{vv}{gzip}{root}{signature}`\n * @param domain - EIP-712 domain with chain id and verifying contract\n * @returns Validated tree, signature, and recovered signer address\n * @throws {DecodeError} If version invalid, signature invalid, or root mismatch\n */\nexport const decode = async (\n encoded: Hex,\n domain: SignatureDomain,\n): Promise<{\n tree: Tree;\n signature: Hex;\n signer: Address;\n}> => {\n const errorFactory = (reason: string) => new DecodeError(reason);\n const normalizedDomain = normalizeSignatureDomain(domain, errorFactory);\n const bytes = hexToBytes(encoded);\n if (bytes.length < 98) throw new DecodeError(\"payload too short\");\n\n const version = bytes[0];\n if (version !== (VERSION & 0xff))\n throw new DecodeError(`invalid version: expected ${VERSION}, got ${version ?? 0}`);\n\n // Parse from end: signature (last 65 bytes) + root (32 bytes before sig)\n const signature = bytesToHex(bytes.slice(-65));\n const root = bytesToHex(bytes.slice(-97, -65));\n assertHex(root, 32, \"root\");\n assertHex(signature, 65, \"signature\");\n\n const signer = await verifySignatureAndRecoverAddress({\n root,\n signature,\n domain: normalizedDomain,\n errorFactory,\n });\n\n const compressed = bytes.slice(1, -97);\n let decoded: string;\n try {\n decoded = ungzip(compressed, { to: \"string\" });\n } catch {\n throw new DecodeError(\"decompression failed\");\n }\n\n let rawOffers: unknown[];\n try {\n rawOffers = JSON.parse(decoded) as unknown[];\n } catch {\n throw new DecodeError(\"JSON parse failed\");\n }\n\n const offers = rawOffers.map(\n (o: unknown) => Offer.OfferSchema().parse(o) as unknown as Offer.Offer,\n );\n\n const tree = from(offers);\n if (root !== tree.root) {\n throw new DecodeError(`root mismatch: expected ${tree.root}, got ${root}`);\n }\n\n const chainIdMismatch = tree.offers.find(\n (offer) => BigInt(offer.chainId) !== normalizedDomain.chainId,\n );\n if (chainIdMismatch) {\n throw new DecodeError(\n `chainId mismatch: expected ${normalizedDomain.chainId}, got ${chainIdMismatch.chainId}`,\n );\n }\n\n return { tree, signature, signer };\n};\n\n/**\n * Error thrown during tree building operations.\n * Indicates structural issues with the tree (missing offers, inconsistent state).\n */\nexport class TreeError extends Errors.BaseError {\n override name = \"Tree.TreeError\";\n constructor(reason: string) {\n super(`Tree error: ${reason}`);\n }\n}\n\n/**\n * Error thrown during tree encoding.\n * Indicates validation failures (signature, root mismatch, mixed makers).\n */\nexport class EncodeError extends Errors.BaseError {\n override name = \"Tree.EncodeError\";\n constructor(reason: string) {\n super(`Failed to encode tree: ${reason}`);\n }\n}\n\n/**\n * Error thrown during tree decoding.\n * Indicates payload corruption, version mismatch, or validation failures.\n */\nexport class DecodeError extends Errors.BaseError {\n override name = \"Tree.DecodeError\";\n constructor(reason: string) {\n super(`Failed to decode tree: ${reason}`);\n }\n}\n\n/**\n * Error thrown when an invalid signature domain is supplied.\n */\nexport class SignatureDomainError extends Errors.BaseError {\n override name = \"Tree.SignatureDomainError\";\n constructor(reason: string) {\n super(`Invalid signature domain: ${reason}`);\n }\n}\n","/** Combines members of an intersection into a readable type. */\n// https://twitter.com/mattpocockuk/status/1622730173446557697?s=20&t=NdpAcmEFXY01xkqU3KO0Mg\nexport type Compute<type> = { [key in keyof type]: type[key] } & unknown;\n\n// https://effect.website/docs/code-style/branded-types/#generalizing-branded-types\nexport const BrandTypeId = Symbol.for(\"mempool/Brand\");\nexport type Brand<in out ID extends string | symbol> = {\n readonly [BrandTypeId]: {\n readonly [id in ID]: ID;\n };\n};\n","// Should be updated when the data should need to be re-synced from scratch\n// keep this version file isolated to reference it in tsdown config\nexport const VERSION = \"router_v1.8\" as const;\n","import {\n bigint,\n boolean,\n foreignKey,\n index,\n integer,\n numeric,\n pgSchema,\n primaryKey,\n serial,\n text,\n timestamp,\n uniqueIndex,\n varchar,\n} from \"drizzle-orm/pg-core\";\nimport { type Chain, Offer, Position } from \"#core/index.ts\";\nimport type { Collector } from \"#indexer/index.ts\";\nimport { VERSION } from \"./VERSION.ts\";\n\nconst s = pgSchema(VERSION);\n\nenum EnumTableName {\n OBLIGATIONS = \"obligations\",\n GROUPS = \"groups\",\n CONSUMED_EVENTS = \"consumed_events\",\n OBLIGATION_COLLATERALS_V2 = \"obligation_collaterals_v2\",\n ORACLES = \"oracles\",\n OFFERS = \"offers\",\n OFFERS_CALLBACKS = \"offers_callbacks\",\n CALLBACKS = \"callbacks\",\n POSITIONS = \"positions\",\n TRANSFERS = \"transfers\",\n VALIDATIONS = \"validations\",\n COLLECTORS = \"collectors\",\n CHAINS = \"chains\",\n LOTS = \"lots\",\n OFFSETS = \"offsets\",\n TREES = \"trees\",\n MERKLE_PATHS = \"merkle_paths\",\n}\n\nexport const TABLE_NAMES = Object.values(EnumTableName) as readonly EnumTableName[];\nexport const VERSIONED_TABLE_NAMES = TABLE_NAMES.map((table) => `\"${VERSION}\".\"${table}\"` as const);\n\nexport type TableName = (typeof TABLE_NAMES)[number];\nexport type VersionedTableName = `\"${typeof VERSION}\".\"${TableName}\"`;\n\nexport const obligations = s.table(EnumTableName.OBLIGATIONS, {\n obligationId: varchar(\"obligation_id\", { length: 66 }).primaryKey(),\n chainId: bigint(\"chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n loanToken: varchar(\"loan_token\", { length: 42 }).notNull(),\n maturity: integer(\"maturity\").notNull(),\n});\n\nexport const groups = s.table(\n EnumTableName.GROUPS,\n {\n chainId: bigint(\"chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n maker: varchar(\"maker\", { length: 42 }).notNull(),\n group: varchar(\"group\", { length: 66 }).notNull(),\n consumed: numeric(\"consumed\", { precision: 78, scale: 0 }).notNull(),\n blockNumber: bigint(\"block_number\", { mode: \"number\" }).notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.chainId, table.maker, table.group], name: \"groups_pk\" }),\n index(\"groups_chain_id_maker_group_consumed_idx\").on(\n table.chainId,\n table.maker,\n table.group,\n table.consumed,\n ),\n ],\n);\n\nexport const consumedEvents = s.table(\n EnumTableName.CONSUMED_EVENTS,\n {\n eventId: varchar(\"event_id\", { length: 128 }).primaryKey(),\n chainId: bigint(\"chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n maker: varchar(\"maker\", { length: 42 }).notNull(),\n group: varchar(\"group\", { length: 66 }).notNull(),\n amount: numeric(\"amount\", { precision: 78, scale: 0 }).notNull(),\n blockNumber: bigint(\"block_number\", { mode: \"number\" }).notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (t) => [\n foreignKey({\n columns: [t.chainId, t.maker, t.group],\n foreignColumns: [groups.chainId, groups.maker, groups.group],\n name: \"consumed_events_groups_fk\",\n }).onDelete(\"cascade\"),\n index(\"consumed_events_group_idx\").on(t.chainId, t.maker, t.group),\n index(\"consumed_events_block_number_idx\").on(t.blockNumber),\n ],\n);\n\nexport const obligationCollateralsV2 = s.table(\n EnumTableName.OBLIGATION_COLLATERALS_V2,\n {\n obligationId: varchar(\"obligation_id\", { length: 66 })\n .notNull()\n .references(() => obligations.obligationId, { onDelete: \"cascade\" }),\n asset: varchar(\"asset\", { length: 42 }).notNull(),\n oracleChainId: bigint(\"oracle_chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n oracleAddress: varchar(\"oracle_address\", { length: 42 }).notNull(),\n lltv: bigint(\"lltv\", { mode: \"bigint\" }).notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (table) => [\n primaryKey({\n columns: [table.obligationId, table.asset],\n name: \"obligation_collaterals_v2_pk\",\n }),\n foreignKey({\n columns: [table.oracleChainId, table.oracleAddress],\n foreignColumns: [oracles.chainId, oracles.address],\n name: \"obligation_collaterals_v2_oracles_fk\",\n }),\n index(\"obligation_collaterals_v2_obligation_id_idx\").on(table.obligationId),\n index(\"obligation_collaterals_v2_oracle_fk_idx\").on(table.oracleChainId, table.oracleAddress),\n ],\n);\n\nexport const oracles = s.table(\n EnumTableName.ORACLES,\n {\n chainId: bigint(\"chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n address: varchar(\"address\", { length: 42 }).notNull(),\n price: numeric(\"price\", { precision: 78, scale: 0 }),\n blockNumber: bigint(\"block_number\", { mode: \"number\" }).notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (table) => [primaryKey({ columns: [table.chainId, table.address], name: \"oracles_pk\" })],\n);\n\nexport const offers = s.table(\n EnumTableName.OFFERS,\n {\n hash: varchar(\"hash\", { length: 66 }).primaryKey(),\n obligationId: varchar(\"obligation_id\", { length: 66 })\n .notNull()\n .references(() => obligations.obligationId, { onDelete: \"cascade\" }),\n assets: numeric(\"assets\", { precision: 78, scale: 0 }).notNull(),\n obligationUnits: numeric(\"obligation_units\", { precision: 78, scale: 0 })\n .notNull()\n .default(\"0\"),\n obligationShares: numeric(\"obligation_shares\", { precision: 78, scale: 0 })\n .notNull()\n .default(\"0\"),\n tick: integer(\"tick\").notNull(),\n maturity: integer(\"maturity\").notNull(),\n expiry: integer(\"expiry\").notNull(),\n start: integer(\"start\").notNull(),\n groupChainId: bigint(\"group_chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n groupMaker: varchar(\"group_maker\", { length: 42 }).notNull(),\n group: varchar(\"group_group\", { length: 66 }).notNull(),\n session: varchar(\"session\", { length: 66 }).notNull(),\n buy: boolean(\"buy\").notNull(),\n callbackAddress: varchar(\"callback_address\", { length: 42 }).notNull(),\n callbackData: text(\"callback_data\").notNull(),\n receiverIfMakerIsSeller: varchar(\"receiver_if_maker_is_seller\", { length: 42 }),\n blockNumber: bigint(\"block_number\", { mode: \"number\" }).notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (table) => [\n foreignKey({\n columns: [table.groupChainId, table.groupMaker, table.group],\n foreignColumns: [groups.chainId, groups.maker, groups.group],\n name: \"offers_groups_fk\",\n }).onDelete(\"cascade\"),\n\n index(\"offers_group_fk_idx\").on(table.groupChainId, table.groupMaker, table.group),\n index(\"offers_group_and_hash_idx\").on(\n table.groupChainId,\n table.groupMaker,\n table.group,\n table.hash,\n ),\n\n index(\"offers_obligation_id_side_idx\").on(table.obligationId, table.buy),\n ],\n);\n\nexport const offersCallbacks = s.table(\n EnumTableName.OFFERS_CALLBACKS,\n {\n offerHash: varchar(\"offer_hash\", { length: 66 })\n .notNull()\n .references(() => offers.hash, { onDelete: \"cascade\" }),\n callbackId: varchar(\"callback_id\", { length: 66 }),\n },\n (table) => [\n primaryKey({\n columns: [table.offerHash, table.callbackId],\n name: \"offers_callbacks_pk\",\n }),\n ],\n);\n\nexport const callbacks = s.table(\n EnumTableName.CALLBACKS,\n {\n id: varchar(\"id\", { length: 66 }).primaryKey(),\n positionChainId: bigint(\"position_chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n positionContract: varchar(\"position_contract\", { length: 42 }).notNull(),\n positionUser: varchar(\"position_user\", { length: 42 }).notNull(),\n amount: numeric(\"amount\", { precision: 78, scale: 0 }),\n },\n (table) => [\n foreignKey({\n columns: [table.positionChainId, table.positionContract, table.positionUser],\n foreignColumns: [positions.chainId, positions.contract, positions.user],\n name: \"callbacks_positions_fk\",\n }).onDelete(\"cascade\"),\n ],\n);\n\nexport const lots = s.table(\n EnumTableName.LOTS,\n {\n chainId: bigint(\"chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n user: varchar(\"user\", { length: 42 }).notNull(),\n contract: varchar(\"contract\", { length: 42 }).notNull(),\n group: varchar(\"group\", { length: 66 }).notNull(),\n obligationId: varchar(\"obligation_id\", { length: 66 }).notNull(),\n lower: numeric(\"lower\", { precision: 78, scale: 0 }).notNull(),\n upper: numeric(\"upper\", { precision: 78, scale: 0 }).notNull(),\n },\n (table) => [\n primaryKey({\n columns: [table.chainId, table.user, table.contract, table.group, table.obligationId],\n name: \"lots_pk\",\n }),\n foreignKey({\n columns: [table.chainId, table.contract, table.user],\n foreignColumns: [positions.chainId, positions.contract, positions.user],\n name: \"lots_positions_fk\",\n }).onDelete(\"cascade\"),\n foreignKey({\n columns: [table.chainId, table.user, table.group],\n foreignColumns: [groups.chainId, groups.maker, groups.group],\n name: \"lots_groups_fk\",\n }).onDelete(\"cascade\"),\n ],\n);\n\nexport const offsets = s.table(\n EnumTableName.OFFSETS,\n {\n chainId: bigint(\"chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n user: varchar(\"user\", { length: 42 }).notNull(),\n contract: varchar(\"contract\", { length: 42 }).notNull(),\n group: varchar(\"group\", { length: 66 }).notNull(),\n obligationId: varchar(\"obligation_id\", { length: 66 }).notNull(),\n value: numeric(\"value\", { precision: 78, scale: 0 }).notNull(),\n },\n (table) => [\n primaryKey({\n columns: [table.chainId, table.user, table.contract, table.group, table.obligationId],\n name: \"offsets_pk\",\n }),\n foreignKey({\n columns: [table.chainId, table.contract, table.user],\n foreignColumns: [positions.chainId, positions.contract, positions.user],\n name: \"offsets_positions_fk\",\n }).onDelete(\"cascade\"),\n ],\n);\n\nexport const PositionTypes = s.enum<Position.Type, [Position.Type, ...Position.Type[]]>(\n \"position_type\",\n Object.values(Position.Type) as [Position.Type, ...Position.Type[]],\n);\n\nexport const positionTypes = s.table(\"position_types\", {\n id: serial(\"id\").primaryKey(),\n type: PositionTypes(\"type\").notNull(),\n});\n\nexport const positions = s.table(\n EnumTableName.POSITIONS,\n {\n chainId: bigint(\"chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n contract: varchar(\"contract\", { length: 42 }).notNull(),\n user: varchar(\"user\", { length: 42 }).notNull(),\n positionTypeId: integer(\"position_type_id\")\n .notNull()\n .references(() => positionTypes.id, { onDelete: \"no action\" }),\n balance: numeric(\"balance\", { precision: 78, scale: 0 }),\n asset: varchar(\"asset\", { length: 42 }),\n blockNumber: bigint(\"block_number\", { mode: \"number\" }).notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (table) => [\n primaryKey({\n columns: [table.chainId, table.contract, table.user],\n name: \"positions_pk\",\n }),\n ],\n);\n\nexport const transfers = s.table(\n EnumTableName.TRANSFERS,\n {\n eventId: varchar(\"event_id\", { length: 128 }).primaryKey(),\n chainId: bigint(\"chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n contract: varchar(\"contract\", { length: 42 }).notNull(),\n from: varchar(\"from\", { length: 42 }).notNull(),\n to: varchar(\"to\", { length: 42 }).notNull(),\n value: numeric(\"value\", { precision: 78, scale: 0 }).notNull(),\n blockNumber: bigint(\"block_number\", { mode: \"number\" }).notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (table) => [\n foreignKey({\n columns: [table.chainId, table.contract, table.from],\n foreignColumns: [positions.chainId, positions.contract, positions.user],\n name: \"transfers_positions_from_fk\",\n }).onDelete(\"cascade\"),\n\n foreignKey({\n columns: [table.chainId, table.contract, table.to],\n foreignColumns: [positions.chainId, positions.contract, positions.user],\n name: \"transfers_positions_to_fk\",\n }).onDelete(\"cascade\"),\n\n index(\"transfers_chain_contract_user_idx\").on(\n table.chainId,\n table.contract,\n table.from,\n table.to,\n table.blockNumber,\n ),\n ],\n);\n\nexport const StatusCode = s.enum<Offer.Status, [Offer.Status, ...Offer.Status[]]>(\n \"status_code\",\n Object.values(Offer.Status) as [Offer.Status, ...Offer.Status[]],\n);\n\nexport const status = s.table(\"status\", {\n id: serial(\"id\").primaryKey(),\n code: StatusCode(\"code\").unique(),\n});\n\nexport const validations = s.table(\"validations\", {\n offerHash: varchar(\"offer_hash\", { length: 66 })\n .primaryKey()\n .references(() => offers.hash, { onDelete: \"cascade\" }),\n statusId: integer(\"status_id\")\n .notNull()\n .references(() => status.id, { onDelete: \"no action\" }),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n});\n\nexport const collectors = s.table(\n EnumTableName.COLLECTORS,\n {\n chainId: bigint(\"chain_id\", { mode: \"number\" })\n .$type<Chain.Id>()\n .notNull()\n .references(() => chains.chainId, { onDelete: \"no action\" }),\n name: text(\"name\").$type<Collector.Name>().notNull(),\n blockNumber: bigint(\"block_number\", { mode: \"number\" }).notNull(),\n // epoch is used as a fencing token to avoid race conditions when updating the block number\n epoch: numeric(\"epoch\", { precision: 78, scale: 0 }).default(\"0\").notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (table) => [uniqueIndex(\"collectors_chain_name_idx\").on(table.chainId, table.name)],\n);\n\nexport const chains = s.table(\n EnumTableName.CHAINS,\n {\n chainId: bigint(\"chain_id\", { mode: \"number\" }).$type<Chain.Id>().notNull(),\n blockNumber: bigint(\"block_number\", { mode: \"number\" }).notNull(),\n epoch: numeric(\"epoch\", { precision: 78, scale: 0 }).default(\"0\").notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (table) => [uniqueIndex(\"chains_chain_id_idx\").on(table.chainId)],\n);\n\nexport const trees = s.table(EnumTableName.TREES, {\n root: varchar(\"root\", { length: 66 }).primaryKey(),\n rootSignature: varchar(\"root_signature\", { length: 132 }).notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n});\n\nexport const merklePaths = s.table(\n EnumTableName.MERKLE_PATHS,\n {\n offerHash: varchar(\"offer_hash\", { length: 66 })\n .primaryKey()\n .references(() => offers.hash, { onDelete: \"cascade\" }),\n treeRoot: varchar(\"tree_root\", { length: 66 })\n .notNull()\n .references(() => trees.root, { onDelete: \"cascade\" }),\n proofNodes: text(\"proof_nodes\").notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (table) => [index(\"merkle_paths_tree_root_idx\").on(table.treeRoot)],\n);\n","import { sql } from \"drizzle-orm\";\nimport { type PublicClient, parseEventLogs, type Transport } from \"viem\";\nimport { Chain, Offer } from \"#core\";\nimport type * as Consumed from \"#database/domains/Consumed.ts\";\nimport {\n consumedEvents as consumedEventsTable,\n groups as groupsTable,\n} from \"#database/drizzle/schema.ts\";\nimport * as Logger from \"#logger/Logger.ts\";\nimport type * as Collector from \"../Collector.ts\";\n\nconst buildGroupKey = (parameters: { chainId: Chain.Id; maker: string; group: string }): string => {\n return `${parameters.chainId}-${parameters.maker.toLowerCase()}-${parameters.group.toLowerCase()}`;\n};\n\ntype NormalizedLog =\n | {\n kind: \"consume\";\n id: string;\n chainId: Chain.Id;\n maker: `0x${string}`;\n group: `0x${string}`;\n amount: bigint;\n blockNumber: number;\n }\n | {\n kind: \"take\";\n id: string;\n chainId: Chain.Id;\n maker: `0x${string}`;\n group: `0x${string}`;\n consumed: bigint;\n blockNumber: number;\n };\n\nexport async function* collectConsumedEvents<\n collector extends Collector.Name,\n client extends PublicClient<Transport, Chain.Chain> = PublicClient<Transport, Chain.Chain>,\n>(\n parameters: Collector.CollectParameters<collector, client> & {\n options?: {\n maxBatchSize?: number;\n blockWindow?: number;\n };\n },\n): AsyncGenerator<number, void, void> {\n let {\n db,\n collector,\n client,\n lastBlockNumber: blockNumber,\n epoch,\n options: { maxBatchSize = 1_000, blockWindow } = {},\n } = parameters;\n\n const logger = Logger.getLogger();\n let startBlock = blockNumber;\n let reorgDetected = false;\n\n const { blockNumber: latestBlockNumberChain } = await db.blocks.getChain(client.chain.id);\n\n const stream = Chain.streamLogs({\n client,\n contractAddress: client.chain.custom.morpho.address,\n blockNumberGte: blockNumber,\n blockNumberLte: latestBlockNumberChain,\n order: \"asc\",\n options: { maxBatchSize, blockWindow },\n });\n\n for await (const { logs, blockNumber: lastStreamBlockNumber } of stream) {\n const parsedLogs = parseEventLogs({\n abi: [Offer.consumedEvent, Offer.takeEvent],\n logs,\n strict: false,\n });\n const normalizedLogs: NormalizedLog[] = [];\n const groups = new Map<string, { chainId: Chain.Id; maker: string; group: string }>();\n const eventIds = new Set<string>();\n const recordLog = (log: NormalizedLog) => {\n normalizedLogs.push(log);\n eventIds.add(log.id);\n const groupKey = buildGroupKey({\n chainId: log.chainId,\n maker: log.maker,\n group: log.group,\n });\n if (!groups.has(groupKey)) {\n groups.set(groupKey, {\n chainId: log.chainId,\n maker: log.maker.toLowerCase(),\n group: log.group.toLowerCase(),\n });\n }\n };\n for (const rawLog of parsedLogs) {\n if (\n rawLog.blockNumber === null ||\n rawLog.logIndex === null ||\n rawLog.transactionHash === null\n ) {\n logger.debug({\n collector,\n chainId: client.chain.id,\n msg: \"Skipping log because it is missing required fields\",\n });\n continue;\n }\n\n if (rawLog.eventName === Offer.consumedEvent.name) {\n const consumeArgs = rawLog.args as {\n user?: `0x${string}`;\n group?: `0x${string}`;\n amount?: bigint;\n };\n if (\n consumeArgs.user === undefined ||\n consumeArgs.group === undefined ||\n consumeArgs.amount === undefined\n ) {\n logger.debug({\n collector,\n chainId: client.chain.id,\n msg: \"Skipping Consume log because it is missing required args\",\n });\n continue;\n }\n\n const log: NormalizedLog = {\n kind: \"consume\",\n id: `${rawLog.blockNumber.toString()}-${rawLog.logIndex.toString()}-${client.chain.id}-${rawLog.transactionHash}`,\n chainId: client.chain.id,\n maker: consumeArgs.user,\n group: consumeArgs.group,\n amount: consumeArgs.amount,\n blockNumber: Number(rawLog.blockNumber),\n };\n recordLog(log);\n continue;\n }\n\n if (rawLog.eventName === Offer.takeEvent.name) {\n const takeArgs = rawLog.args as {\n maker?: `0x${string}`;\n group?: `0x${string}`;\n consumed?: bigint;\n };\n if (\n takeArgs.maker === undefined ||\n takeArgs.group === undefined ||\n takeArgs.consumed === undefined\n ) {\n logger.debug({\n collector,\n chainId: client.chain.id,\n msg: \"Skipping Take log because it is missing required args\",\n });\n continue;\n }\n\n const log: NormalizedLog = {\n kind: \"take\",\n id: `${rawLog.blockNumber.toString()}-${rawLog.logIndex.toString()}-${client.chain.id}-${rawLog.transactionHash}`,\n chainId: client.chain.id,\n maker: takeArgs.maker,\n group: takeArgs.group,\n consumed: takeArgs.consumed,\n blockNumber: Number(rawLog.blockNumber),\n };\n recordLog(log);\n }\n }\n\n await db.transaction(async (dbTx) => {\n const existingEventIds = new Set<string>();\n if (eventIds.size > 0) {\n const ids = Array.from(eventIds);\n for (let index = 0; index < ids.length; index += 500) {\n const slice = ids.slice(index, index + 500);\n const { rows } = await dbTx.execute<{ event_id: string }>(sql`\n SELECT event_id\n FROM ${consumedEventsTable}\n WHERE event_id IN (${sql.join(\n slice.map((id) => sql`${id}`),\n sql`,`,\n )});\n `);\n\n for (const row of rows) {\n existingEventIds.add(row.event_id);\n }\n }\n }\n\n const consumedByGroup = new Map<string, bigint>();\n if (groups.size > 0) {\n const groupList = Array.from(groups.values());\n for (let index = 0; index < groupList.length; index += 500) {\n const slice = groupList.slice(index, index + 500);\n // Baseline group totals to compute incremental deltas for this batch.\n // Using a VALUES CTE keeps the lookup set bounded to this slice and avoids scanning\n // consumed_events for sums, which is both slower and order-dependent.\n const { rows } = await dbTx.execute<{\n chain_id: bigint;\n maker: string;\n group: string;\n consumed: string | null;\n }>(sql`\n WITH targets(chain_id, maker, \"group\") AS (\n VALUES ${sql.join(\n slice.map(\n (group) =>\n sql`(${group.chainId}::bigint, ${group.maker.toLowerCase()}::varchar(42), ${group.group.toLowerCase()}::varchar(66))`,\n ),\n sql`,`,\n )}\n )\n SELECT\n targets.chain_id,\n targets.maker,\n targets.\"group\",\n COALESCE(g.consumed, 0)::numeric AS consumed\n FROM targets\n LEFT JOIN ${groupsTable} g\n ON g.chain_id = targets.chain_id\n AND g.maker = targets.maker\n AND g.\"group\" = targets.\"group\";\n `);\n\n for (const row of rows) {\n const groupKey = buildGroupKey({\n chainId: Number(row.chain_id) as Chain.Id,\n maker: row.maker,\n group: row.group,\n });\n consumedByGroup.set(groupKey, BigInt(row.consumed ?? \"0\"));\n }\n }\n }\n\n const events: Consumed.Event[] = [];\n for (const log of normalizedLogs) {\n if (existingEventIds.has(log.id)) {\n continue;\n }\n const groupKey = buildGroupKey({\n chainId: log.chainId,\n maker: log.maker,\n group: log.group,\n });\n const previousConsumed = consumedByGroup.get(groupKey) ?? 0n;\n\n if (log.kind === \"consume\") {\n events.push({\n id: log.id,\n chainId: log.chainId,\n maker: log.maker,\n group: log.group,\n amount: log.amount,\n blockNumber: log.blockNumber,\n });\n\n consumedByGroup.set(groupKey, previousConsumed + log.amount);\n continue;\n }\n\n const delta = log.consumed - previousConsumed;\n if (delta <= 0n) {\n logger.debug({\n collector,\n chainId: client.chain.id,\n msg: \"Skipping Take log because consumed did not increase\",\n previous_consumed: previousConsumed.toString(),\n consumed: log.consumed.toString(),\n });\n continue;\n }\n\n events.push({\n id: log.id,\n chainId: log.chainId,\n maker: log.maker,\n group: log.group,\n amount: delta,\n blockNumber: log.blockNumber,\n });\n\n consumedByGroup.set(groupKey, log.consumed);\n }\n\n try {\n await dbTx.consumed.create(events);\n\n if (events.length > 0) {\n logger.info({\n msg: `Events indexed`,\n collector,\n count: events.length,\n chain_id: client.chain.id,\n block_range: [startBlock, lastStreamBlockNumber],\n });\n }\n } catch (err) {\n logger.error({ err, msg: \"Failed to process consumed events\" });\n }\n\n blockNumber = lastStreamBlockNumber;\n\n try {\n await dbTx.blocks.advanceCollector({\n collectorName: collector,\n chainId: client.chain.id,\n blockNumber,\n epoch,\n });\n } catch (_) {\n try {\n const ancestor = await dbTx.blocks.getCollector({\n collectorName: collector,\n chainId: client.chain.id,\n });\n\n blockNumber = ancestor.blockNumber;\n\n const deleted = await dbTx.consumed.delete({\n chainId: client.chain.id,\n blockNumberGte: blockNumber + 1,\n });\n\n logger.info({\n collector,\n chain_id: client.chain.id,\n msg: `Reorg detected, events deleted`,\n count: deleted,\n block_number: blockNumber,\n });\n\n await dbTx.blocks.advanceCollector({\n collectorName: collector,\n chainId: client.chain.id,\n blockNumber,\n epoch: ancestor.epoch,\n });\n\n reorgDetected = true;\n } catch (err) {\n const msg = \"Failed to delete consumed events when handling reorg.\";\n logger.error({\n collector,\n chainId: client.chain.id,\n msg,\n err,\n });\n\n throw new Error(msg, { cause: err as Error });\n }\n }\n });\n\n if (reorgDetected) return;\n yield blockNumber;\n startBlock = blockNumber;\n }\n\n return;\n}\n","import {\n type Address,\n decodeAbiParameters,\n type Hex,\n type PublicClient,\n type Transport,\n zeroAddress,\n} from \"viem\";\nimport { Callback, Chain, Obligation, Offer, Oracle, Position, Tree } from \"#core\";\nimport type * as CallbacksDomain from \"#database/domains/Callbacks.ts\";\nimport type * as GroupsDomain from \"#database/domains/Groups.ts\";\nimport type * as LotsDomain from \"#database/domains/Lots.ts\";\nimport type * as TreesDomain from \"#database/domains/Trees.ts\";\nimport type { GatekeeperClient } from \"#gatekeeper/Client.ts\";\nimport * as Logger from \"#logger/Logger.ts\";\nimport type * as Collector from \"../Collector.ts\";\n\n/**\n * Rejection reasons for merkle tree payloads.\n * Used for logging and metrics tracking.\n */\nexport type RejectionReason =\n | \"decode_failed\"\n | \"invalid_signature\"\n | \"signer_mismatch\"\n | \"mixed_maker\"\n | \"gatekeeper_rejected\"\n | \"block_window\";\n\n/**\n * Decoded tree with metadata for processing.\n */\ntype DecodedTree = {\n tree: Tree.Tree;\n signature: Hex;\n signer: Address;\n blockNumber: number;\n};\n\ntype OfferWithBlock = {\n offer: Offer.Offer;\n blockNumber: number;\n};\n\ntype OfferDependencies = {\n obligations: Obligation.Obligation[];\n oracles: Oracle.Oracle[];\n groups: GroupsDomain.GroupInput[];\n offerBatches: Array<{ blockNumber: number; offers: Offer.Offer[] }>;\n};\n\nexport async function* collectOffersV2<\n collector extends Collector.Name,\n client extends PublicClient<Transport, Chain.Chain> = PublicClient<Transport, Chain.Chain>,\n>(\n parameters: Collector.CollectParameters<collector, client> & {\n gatekeeper: GatekeeperClient;\n options: {\n maxBatchSize?: number;\n blockWindow?: number;\n };\n },\n): AsyncGenerator<number, void, void> {\n let {\n db,\n collector,\n client,\n lastBlockNumber: blockNumber,\n gatekeeper,\n options: { maxBatchSize = 1_000, blockWindow } = {},\n } = parameters;\n\n const logger = Logger.getLogger();\n let startBlock = blockNumber;\n let reorgDetected = false;\n\n if (client.chain.custom.morpho.address.toLowerCase() === zeroAddress) {\n const msg =\n \"Morpho V2 address is zero, signature verification will fail. Please set the Morpho V2 address in the chain configuration.\";\n logger.error({\n msg,\n chain_id: client.chain.id,\n });\n throw new Error(msg);\n }\n\n const signatureDomain = {\n chainId: client.chain.id,\n verifyingContract: client.chain.custom.morpho.address,\n };\n\n const { blockNumber: latestBlockNumberChain } = await db.blocks.getChain(client.chain.id);\n\n const stream = Chain.streamLogs({\n client,\n contractAddress: client.chain.custom.mempool.address,\n event: {\n type: \"event\",\n name: \"Event\",\n inputs: [{ name: \"data\", type: \"bytes\", indexed: false, internalType: \"bytes\" }],\n anonymous: false,\n } as const,\n blockNumberGte: blockNumber,\n blockNumberLte: latestBlockNumberChain,\n order: \"asc\",\n options: { maxBatchSize, blockWindow },\n });\n\n for await (const { logs, blockNumber: lastStreamBlockNumber } of stream) {\n blockNumber = lastStreamBlockNumber;\n const decodedTrees: DecodedTree[] = [];\n\n for (const log of logs) {\n if (!log) continue;\n const [payload] = decodeAbiParameters([{ type: \"bytes\" }], log.data);\n try {\n const { tree, signature, signer } = await Tree.decode(payload, signatureDomain);\n\n // Signer mismatch check: signer must equal maker address for all offers\n // This is an anti-attack invariant enforced at collector level\n const signerMismatch = tree.offers.find(\n (offer) => offer.maker.toLowerCase() !== signer.toLowerCase(),\n );\n\n if (signerMismatch) {\n logger.debug({\n msg: \"Tree rejected: signer mismatch\",\n reason: \"signer_mismatch\" as RejectionReason,\n signer,\n maker: signerMismatch.maker,\n chain_id: client.chain.id,\n });\n continue;\n }\n\n decodedTrees.push({\n tree,\n signature,\n signer,\n blockNumber: Number(log.blockNumber),\n });\n } catch (err) {\n // Decode failed - could be invalid signature, version mismatch, etc.\n const reason: RejectionReason =\n err instanceof Tree.DecodeError && err.message.includes(\"signature\")\n ? \"invalid_signature\"\n : \"decode_failed\";\n logger.debug({\n msg: \"Tree decode failed\",\n reason,\n chain_id: client.chain.id,\n err: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n await db.transaction(async (dbTx) => {\n const { epoch, blockNumber: latestBlockNumber } = await dbTx.blocks.getChain(client.chain.id);\n\n const treesToInsert: TreesDomain.CreateInput[] = [];\n let totalValidOffers = 0;\n const offersWithBlock: OfferWithBlock[] = [];\n\n for (const { tree, signature, blockNumber: treeBlockNumber } of decodedTrees) {\n try {\n const allowedResults = await gatekeeper.isAllowed(tree.offers);\n const hasBlockWindowViolation = treeBlockNumber > latestBlockNumber;\n const allOffersAllowed =\n allowedResults.issues.length === 0 &&\n allowedResults.valid.length === tree.offers.length;\n\n if (!allOffersAllowed || hasBlockWindowViolation) {\n if (allowedResults.issues.length > 0) {\n const hasMixedMaker = allowedResults.issues.some((i) => i.ruleName === \"mixed_maker\");\n logger.debug({\n msg: \"Tree offers rejected by gatekeeper\",\n reason: (hasMixedMaker ? \"mixed_maker\" : \"gatekeeper_rejected\") as RejectionReason,\n chain_id: client.chain.id,\n issues_count: allowedResults.issues.length,\n });\n } else if (hasBlockWindowViolation) {\n logger.debug({\n msg: \"Tree rejected: offers outside block window\",\n reason: \"block_window\" as RejectionReason,\n chain_id: client.chain.id,\n });\n }\n continue;\n }\n\n treesToInsert.push({ tree, signature });\n totalValidOffers += tree.offers.length;\n offersWithBlock.push(\n ...tree.offers.map((offer) => ({ offer, blockNumber: treeBlockNumber })),\n );\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n logger.error({\n err: error,\n msg: \"Gatekeeper validation failed\",\n chain_id: client.chain.id,\n });\n throw new Error(\"Gatekeeper validation failed\", { cause: error });\n }\n }\n\n const dependencies = buildOfferDependencies(offersWithBlock);\n\n await dbTx.oracles.upsert(dependencies.oracles);\n await dbTx.obligations.create(dependencies.obligations);\n await dbTx.groups.create(dependencies.groups);\n\n const insertedHashes = await dbTx.offers.create(dependencies.offerBatches);\n\n // Phase 3: Insert trees with merkle metadata\n if (treesToInsert.length > 0) {\n await dbTx.trees.create(treesToInsert);\n }\n\n const insertedOffers = filterInsertedOffers({\n offers: offersWithBlock,\n hashes: insertedHashes,\n });\n\n const { callbacks, positions, lots } = decodeCallbacks({\n chainId: client.chain.id,\n offers: insertedOffers,\n });\n\n if (positions.length > 0) {\n await dbTx.positions.upsert(positions);\n }\n\n if (callbacks.length > 0) {\n await dbTx.callbacks.upsert(callbacks);\n }\n\n if (lots.length > 0) {\n await dbTx.lots.create(lots);\n }\n\n try {\n await dbTx.blocks.advanceCollector({\n collectorName: collector,\n chainId: client.chain.id,\n blockNumber,\n epoch,\n });\n\n if (totalValidOffers > 0) {\n logger.info({\n msg: `New offers`,\n collector,\n count: totalValidOffers,\n trees_count: treesToInsert.length,\n chain_id: client.chain.id,\n block_range: [startBlock, lastStreamBlockNumber],\n });\n }\n } catch (_) {\n try {\n const ancestor = await dbTx.blocks.getCollector({\n collectorName: collector,\n chainId: client.chain.id,\n });\n\n blockNumber = ancestor.blockNumber;\n\n const deleted = await dbTx.offers.delete({\n blockNumberGte: blockNumber + 1,\n chainId: client.chain.id,\n });\n\n logger.info({\n collector,\n chain_id: client.chain.id,\n msg: `Reorg detected, offers deleted`,\n count: deleted,\n block_number: blockNumber,\n });\n\n await dbTx.blocks.advanceCollector({\n collectorName: collector,\n chainId: client.chain.id,\n blockNumber,\n epoch: ancestor.epoch,\n });\n\n reorgDetected = true;\n } catch (err) {\n const msg = \"Failed to delete offers when handling reorg.\";\n logger.error({\n collector,\n chainId: client.chain.id,\n msg,\n err,\n });\n\n throw new Error(msg);\n }\n }\n });\n\n if (reorgDetected) return;\n yield blockNumber;\n startBlock = blockNumber;\n }\n\n return;\n}\n\nfunction decodeCallbacks(parameters: { chainId: Chain.Id; offers: OfferWithBlock[] }): {\n callbacks: CallbacksDomain.OfferCallbacks[];\n positions: Position.Position[];\n lots: LotsDomain.create.OfferLotInfo[];\n} {\n const { offers } = parameters;\n if (offers.length === 0) {\n return { callbacks: [], positions: [], lots: [] };\n }\n\n const callbacks: CallbacksDomain.OfferCallbacks[] = [];\n const positions: Position.Position[] = [];\n const lots: LotsDomain.create.OfferLotInfo[] = [];\n\n for (const { offer, blockNumber: offerBlockNumber } of offers) {\n if (!offer.buy) continue;\n if (!Callback.isEmptyCallback(offer)) continue;\n\n const loanToken = offer.loanToken.toLowerCase() as Address;\n\n positions.push(\n Position.from({\n chainId: offer.chainId,\n contract: loanToken,\n user: offer.maker,\n type: Position.Type.ERC20,\n asset: loanToken,\n blockNumber: offerBlockNumber,\n }),\n );\n\n lots.push({\n positionChainId: offer.chainId,\n positionContract: loanToken,\n positionUser: offer.maker,\n group: offer.group,\n obligationId: Offer.obligationId(offer),\n size: offer.assets,\n });\n\n callbacks.push({\n offerHash: Offer.hash(offer),\n callbacks: [\n {\n chainId: offer.chainId,\n contract: loanToken,\n user: offer.maker,\n amount: offer.assets,\n },\n ],\n });\n }\n\n return { callbacks, positions, lots };\n}\n\nfunction buildOfferDependencies(offers: OfferWithBlock[]): OfferDependencies {\n const obligationsById = new Map<Hex, Obligation.Obligation>();\n const oraclesByKey = new Map<string, Oracle.Oracle>();\n const groupsByKey = new Map<string, GroupsDomain.GroupInput>();\n const offersByBlock = new Map<number, Offer.Offer[]>();\n\n for (const { offer, blockNumber } of offers) {\n const list = offersByBlock.get(blockNumber) ?? [];\n list.push(offer);\n offersByBlock.set(blockNumber, list);\n\n const obligationId = Offer.obligationId(offer);\n const existing = obligationsById.get(obligationId);\n if (!existing) {\n obligationsById.set(\n obligationId,\n Obligation.from({\n chainId: offer.chainId,\n loanToken: offer.loanToken,\n maturity: offer.maturity,\n collaterals: offer.collaterals,\n }),\n );\n }\n\n for (const collateral of offer.collaterals) {\n const oracleKey = `${offer.chainId}-${collateral.oracle}`.toLowerCase();\n if (!oraclesByKey.has(oracleKey)) {\n oraclesByKey.set(\n oracleKey,\n Oracle.from({\n chainId: offer.chainId,\n address: collateral.oracle,\n price: null,\n blockNumber,\n }),\n );\n }\n }\n\n const groupKey = `${offer.chainId}-${offer.maker}-${offer.group}`.toLowerCase();\n if (!groupsByKey.has(groupKey)) {\n groupsByKey.set(groupKey, {\n chainId: offer.chainId,\n maker: offer.maker,\n group: offer.group,\n blockNumber,\n });\n }\n }\n\n return {\n obligations: Array.from(obligationsById.values()),\n oracles: Array.from(oraclesByKey.values()),\n groups: Array.from(groupsByKey.values()),\n offerBatches: Array.from(offersByBlock.entries()).map(([blockNumber, items]) => ({\n blockNumber,\n offers: items,\n })),\n };\n}\n\nfunction filterInsertedOffers(parameters: {\n offers: OfferWithBlock[];\n hashes: Hex[];\n}): OfferWithBlock[] {\n if (parameters.hashes.length === 0) return [];\n\n const inserted = new Set(parameters.hashes.map((hash) => hash.toLowerCase()));\n const seen = new Set<string>();\n const filtered: OfferWithBlock[] = [];\n\n for (const entry of parameters.offers) {\n const hash = Offer.hash(entry.offer).toLowerCase();\n if (!inserted.has(hash)) continue;\n if (seen.has(hash)) continue;\n seen.add(hash);\n filtered.push(entry);\n }\n\n return filtered;\n}\n","import type { Address, PublicActions, PublicClient, Transport } from \"viem\";\nimport { Abi, type Chain } from \"#core\";\nimport * as Utils from \"#utils/index.ts\";\n\n/**\n * Fetches prices from multiple oracle contracts using multicall.\n *\n * - Executes `price()` on {@link Abi.Oracle} for each {@link Address}.\n * - Requires a client supporting {@link PublicActions.multicall | multicall}.\n *\n * @param parameters - {@link fetchOraclePrices.Parameters} including the list of oracle\n * {@link Address | addresses}, fetch options, and the multicall-enabled client.\n * @returns {@link fetchOraclePrices.ReturnType} mapping {@link Address} to `bigint` price.\n */\nexport async function fetchOraclePrices(\n parameters: fetchOraclePrices.Parameters,\n): Promise<fetchOraclePrices.ReturnType> {\n const { client, oracles, options } = parameters;\n if (oracles.length === 0) return new Map();\n\n const batchSize = Math.max(1, options?.batchSize ?? 5000);\n const retryAttempts = Math.max(1, options?.retryAttempts ?? 3);\n const retryDelayMs = Math.max(0, options?.retryDelayMs ?? 50);\n const blockNumber = options?.blockNumber ? BigInt(options.blockNumber) : undefined;\n\n const out: Map<Address, bigint> = new Map();\n\n for (const oraclesBatch of Utils.batch(oracles, batchSize)) {\n const priceCalls: Array<{\n address: Address;\n abi: typeof Abi.Oracle;\n functionName: \"price\";\n args: [];\n }> = [];\n\n for (const oracle of oraclesBatch) {\n priceCalls.push({\n address: oracle,\n abi: Abi.Oracle,\n functionName: \"price\",\n args: [],\n });\n }\n const prices = await Utils.batchMulticall<bigint>({\n client,\n calls: priceCalls,\n batchSize,\n retryAttempts,\n retryDelayMs,\n blockNumber,\n });\n\n for (let i = 0; i < oraclesBatch.length; i++) {\n const oracle = oraclesBatch[i]!;\n const price = prices[i]! as bigint;\n out.set(oracle, price);\n }\n }\n\n return out;\n}\n\nexport declare namespace fetchOraclePrices {\n export type Parameters = {\n client: PublicClient<Transport, Chain.Chain>;\n oracles: Address[];\n options?: {\n batchSize?: number;\n retryAttempts?: number;\n retryDelayMs?: number;\n blockNumber?: number;\n };\n };\n\n export type ReturnType = Map<Address, bigint>;\n}\n","import { type Address, erc20Abi, type PublicClient, type Transport } from \"viem\";\nimport type { Chain, Position } from \"#core/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\n\n/**\n * Fetches ERC20 balances for positions at a given block number and returns the positions with the updated balances.\n * @notice This method does not mutate positions and returns a new array.\n *\n * @param parameters - {@link snapshotERC20Positions.Parameters}\n * @returns Positions - {@link snapshotERC20Positions.ReturnType}\n */\nexport async function snapshotERC20Positions(\n parameters: snapshotERC20Positions.Parameters,\n): Promise<snapshotERC20Positions.ReturnType> {\n const {\n positions: oldPositions,\n blockNumber,\n options: { maxBatchSize = 1_000, retryAttempts = 5, retryDelayMs = 500 } = {},\n } = parameters;\n\n if (oldPositions.length === 0) return [];\n\n const calls: Array<{\n address: Address;\n abi: typeof erc20Abi;\n functionName: \"balanceOf\";\n args: [Address];\n }> = [];\n\n for (const position of oldPositions) {\n calls.push({\n address: position.contract,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [position.user],\n });\n }\n\n const balances = await Utils.batchMulticall<bigint>({\n client: parameters.client,\n calls,\n blockNumber: BigInt(blockNumber),\n batchSize: maxBatchSize,\n retryAttempts,\n retryDelayMs,\n });\n\n const positions: Position.Position[] = [];\n for (let i = 0; i < balances.length; i++) {\n const oldPosition = oldPositions[i];\n if (!oldPosition) continue;\n\n positions.push({\n ...oldPosition,\n balance: balances[i]!,\n blockNumber,\n });\n }\n\n return positions;\n}\n\nexport declare namespace snapshotERC20Positions {\n export type Parameters = {\n client: PublicClient<Transport, Chain.Chain>;\n positions: Position.Position[];\n blockNumber: number;\n options?: {\n maxBatchSize?: number;\n retryAttempts?: number;\n retryDelayMs?: number;\n };\n };\n\n export type ReturnType = Position.Position[];\n}\n","import type { Address, PublicClient, Transport } from \"viem\";\nimport { Abi, type Chain, type Compute, ERC4626, type Position } from \"#core/index.ts\";\nimport { Logger } from \"#logger/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\n\ntype MetaMorphoCall = Compute<\n | {\n address: Address;\n abi: Abi.MetaMorpho;\n functionName: \"balanceOf\";\n args: [Address];\n convertToAssets: (shares: bigint) => void;\n }\n | {\n address: Address;\n abi: Abi.MetaMorpho;\n functionName: \"DECIMALS_OFFSET\" | \"totalAssets\" | \"totalSupply\" | \"asset\";\n args: [];\n }\n>;\n\n/**\n * Fetches vault shares for users at a given block number, converts them to assets and returns the positions with the updated balances.\n * @notice This method does not mutate positions and returns a new array.\n *\n * @param parameters - {@link snapshotVaultPositions.Parameters}\n * @returns Positions - {@link snapshotVaultPositions.ReturnType}\n */\nexport async function snapshotVaultPositions(\n parameters: snapshotVaultPositions.Parameters,\n): Promise<snapshotVaultPositions.ReturnType> {\n const logger = Logger.getLogger();\n const {\n client,\n positions: oldPositions,\n blockNumber,\n options: { maxBatchSize = 1_000, retryAttempts = 5, retryDelayMs = 500 } = {},\n } = parameters;\n\n const calls: MetaMorphoCall[] = [];\n const contracts = new Map<\n Address,\n {\n decimalsOffset: number | undefined;\n totalAssets: bigint | undefined;\n totalSupply: bigint | undefined;\n asset: Address | undefined;\n }\n >();\n\n // deep clone the positions to avoid mutating the original array\n const positions = structuredClone(oldPositions);\n\n for (const position of positions) {\n calls.push({\n address: position.contract,\n abi: Abi.MetaMorpho,\n functionName: \"balanceOf\",\n args: [position.user],\n convertToAssets: (shares: bigint) => {\n const contract = contracts.get(position.contract.toLowerCase() as Address);\n if (!contract) return;\n if (\n contract.decimalsOffset === undefined ||\n contract.totalAssets === undefined ||\n contract.totalSupply === undefined\n )\n return;\n\n try {\n position.balance = ERC4626.convertToAssets({\n shares,\n totalAssets: contract.totalAssets,\n totalSupply: contract.totalSupply,\n decimalsOffset: contract.decimalsOffset,\n });\n\n position.asset = contract.asset;\n position.blockNumber = blockNumber;\n } catch (err) {\n if (err instanceof ERC4626.DenominatorIsZeroError) {\n logger.error({\n msg: \"Failed to convert shares to assets\",\n chain_id: client.chain.id,\n block_number: blockNumber,\n position_contract: position.contract,\n position_user: position.user,\n shares,\n err,\n });\n return;\n }\n\n throw err;\n }\n },\n });\n\n if (contracts.has(position.contract.toLowerCase() as Address)) continue;\n\n calls.push(\n {\n address: position.contract,\n abi: Abi.MetaMorpho,\n functionName: \"DECIMALS_OFFSET\",\n args: [],\n },\n {\n address: position.contract,\n abi: Abi.MetaMorpho,\n functionName: \"totalAssets\",\n args: [],\n },\n {\n address: position.contract,\n abi: Abi.MetaMorpho,\n functionName: \"totalSupply\",\n args: [],\n },\n {\n address: position.contract,\n abi: Abi.MetaMorpho,\n functionName: \"asset\",\n args: [],\n },\n );\n\n contracts.set(position.contract.toLowerCase() as Address, {\n decimalsOffset: undefined,\n totalAssets: undefined,\n totalSupply: undefined,\n asset: undefined,\n });\n }\n\n const results = await Utils.batchMulticall<bigint | number | Address>({\n client,\n calls,\n blockNumber: BigInt(blockNumber),\n batchSize: maxBatchSize,\n retryAttempts: retryAttempts,\n retryDelayMs: retryDelayMs,\n });\n\n const convertToAssetsList: (() => void)[] = [];\n for (let i = 0; i < results.length; i++) {\n const call = calls[i]!;\n const value = results[i]!;\n\n const contract = contracts.get(call.address.toLowerCase() as Address);\n if (!contract) continue;\n\n switch (call.functionName) {\n case \"balanceOf\":\n convertToAssetsList.push(() => call.convertToAssets(value as bigint));\n break;\n case \"DECIMALS_OFFSET\":\n contract.decimalsOffset = value as number;\n break;\n case \"totalAssets\":\n contract.totalAssets = value as bigint;\n break;\n case \"totalSupply\":\n contract.totalSupply = value as bigint;\n break;\n case \"asset\":\n contract.asset = (value as Address).toLowerCase() as Address;\n break;\n }\n }\n\n for (const convertToAssets of convertToAssetsList) convertToAssets();\n return positions;\n}\n\nexport declare namespace snapshotVaultPositions {\n export type Parameters = {\n client: PublicClient<Transport, Chain.Chain>;\n positions: Position.Position[];\n blockNumber: number;\n options: {\n maxBatchSize?: number;\n retryAttempts?: number;\n retryDelayMs?: number;\n };\n };\n\n export type ReturnType = Position.Position[];\n}\n","import { type PublicClient, parseEventLogs, type Transport } from \"viem\";\nimport { Chain, Position, Transfer } from \"#core\";\nimport * as Logger from \"#logger/Logger.ts\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport type * as Collector from \"../Collector.ts\";\nimport * as Fetchers from \"../fetchers/index.ts\";\n\nexport async function* collectPositions<\n collector extends Collector.Name,\n client extends PublicClient<Transport, Chain.Chain> = PublicClient<Transport, Chain.Chain>,\n>(\n parameters: Collector.CollectParameters<collector, client> & {\n options: {\n maxBatchSize?: number;\n blockWindow?: number;\n retryAttempts?: number;\n retryDelayMs?: number;\n };\n },\n): AsyncGenerator<number, void, void> {\n let {\n db,\n collector,\n client,\n lastBlockNumber: blockNumber,\n epoch,\n options: { maxBatchSize = 1_000, retryAttempts = 5, retryDelayMs = 500, blockWindow } = {},\n } = parameters;\n\n const logger = Logger.getLogger();\n let startBlock = blockNumber;\n let reorgDetected = false;\n\n const TransferEvent = {\n type: \"event\",\n name: \"Transfer\",\n inputs: [\n { name: \"from\", type: \"address\", indexed: true },\n { name: \"to\", type: \"address\", indexed: true },\n { name: \"value\", type: \"uint256\", indexed: false },\n ],\n } as const;\n\n const { blockNumber: latestBlockNumberChain } = await db.blocks.getChain(client.chain.id);\n\n const stream = Chain.streamLogs({\n client,\n event: TransferEvent,\n blockNumberGte: blockNumber,\n blockNumberLte: latestBlockNumberChain,\n order: \"asc\",\n options: { maxBatchSize, blockWindow },\n });\n\n for await (const { logs, blockNumber: lastStreamBlockNumber } of stream) {\n blockNumber = lastStreamBlockNumber;\n const parsedLogs = parseEventLogs({ abi: [TransferEvent], logs });\n const transfers: Transfer.Transfer[] = [];\n for (const log of parsedLogs) {\n if (log.blockNumber === null || log.logIndex === null || log.transactionHash === null) {\n logger.debug({\n collector,\n chainId: client.chain.id,\n msg: \"Skipping log because it is missing required fields\",\n });\n\n continue;\n }\n\n transfers.push(\n Transfer.from({\n id: `${client.chain.id}-${log.blockNumber.toString()}-${log.transactionHash}-${log.logIndex.toString()}`,\n chainId: client.chain.id,\n contract: log.address,\n from: log.args.from,\n to: log.args.to,\n value: log.args.value,\n blockNumber: Number(log.blockNumber),\n }),\n );\n }\n\n const { positions } = await db.positions.get({ chainId: client.chain.id, filled: false });\n\n const newPositions: Position.Position[] = [];\n try {\n newPositions.push(\n ...(\n await _snapshot({\n positions,\n blockNumber: latestBlockNumberChain,\n client,\n maxBatchSize,\n retryAttempts,\n retryDelayMs,\n })\n )\n // bump block number to delete all events until the snapshot block number\n .map((p) => ({ ...p, blockNumber: p.blockNumber + 1 })),\n );\n } catch (err) {\n logger.error({\n msg: \"Failed to snapshot new empty positions\",\n collector,\n chain_id: client.chain.id,\n block_number: latestBlockNumberChain,\n err,\n });\n\n yield startBlock;\n return;\n }\n\n try {\n await db.transaction(async (dbTx) => {\n const insertPositions = async () => {\n if (newPositions.length === 0) return;\n try {\n const count = await dbTx.positions.upsert(newPositions);\n logger.info({\n msg: `New positions`,\n collector,\n count,\n chain_id: client.chain.id,\n block_number: latestBlockNumberChain,\n });\n } catch (err) {\n throw new InsertPositionsError(err as Error);\n }\n };\n\n const insertTransfers = async () => {\n if (transfers.length === 0) return;\n try {\n const created = await dbTx.transfers.create(transfers);\n logger.info({\n msg: `New transfers`,\n collector,\n count: created,\n chain_id: client.chain.id,\n block_range: [startBlock, blockNumber],\n });\n } catch (err) {\n throw new InsertTransfersError(err as Error);\n }\n };\n\n const saveBlockNumber = async () => {\n try {\n await dbTx.blocks.advanceCollector({\n collectorName: collector,\n chainId: client.chain.id,\n blockNumber,\n epoch,\n });\n } catch (_) {\n throw new Errors.ReorgError(blockNumber);\n }\n };\n\n // positions should be inserted before transfers\n // otherwise transfers could be dropped for new positions that are inserted with this call\n await insertPositions();\n await insertTransfers();\n // save block number should be done after the insertion of items\n // to be able to revert transaction if a reorg occurred\n await saveBlockNumber();\n });\n } catch (err) {\n if (err instanceof Errors.ReorgError) {\n logger.info({\n msg: \"Reorg detected, positions and transfers insertion aborted\",\n collector,\n count: newPositions.length,\n chain_id: client.chain.id,\n block_number: blockNumber,\n });\n reorgDetected = true;\n }\n\n if (err instanceof InsertPositionsError) {\n logger.error({\n msg: \"Failed to insert positions\",\n collector,\n count: newPositions.length,\n chain_id: client.chain.id,\n block_number: latestBlockNumberChain,\n err,\n });\n\n throw err.cause;\n }\n\n if (err instanceof InsertTransfersError) {\n logger.error({\n msg: \"Failed to insert transfers\",\n collector,\n count: transfers.length,\n chain_id: client.chain.id,\n block_number: blockNumber,\n err,\n });\n\n throw err.cause;\n }\n }\n\n if (!reorgDetected) {\n startBlock = blockNumber;\n // if no new positions or transfers and the last streamed block is not up to date yet, we want to continue iterating over the stream\n if (\n newPositions.length === 0 &&\n transfers.length === 0 &&\n lastStreamBlockNumber !== latestBlockNumberChain\n )\n continue;\n\n yield blockNumber;\n continue;\n }\n\n await db.transaction(async (dbTx) => {\n try {\n const ancestor = await dbTx.blocks.getCollector({\n collectorName: collector,\n chainId: client.chain.id,\n });\n\n blockNumber = ancestor.blockNumber;\n\n const emptied = await dbTx.positions.setEmptyAfter({\n chainId: client.chain.id,\n blockNumber: blockNumber + 1,\n });\n\n logger.info({\n msg: \"Reorg detected, positions set to empty\",\n collector,\n count: emptied,\n chain_id: client.chain.id,\n block_number_gte: blockNumber + 1,\n });\n\n await dbTx.blocks.advanceCollector({\n collectorName: collector,\n chainId: client.chain.id,\n blockNumber,\n epoch: ancestor.epoch,\n });\n } catch (err) {\n const msg = \"Failed to revert to ancestor block when handling reorg.\";\n logger.error({\n collector,\n chainId: client.chain.id,\n msg,\n err,\n });\n\n throw new Error(msg);\n }\n });\n\n return;\n }\n\n return;\n}\n\n/**\n * @internal\n *\n * Snapshots positions and returns the new positions.\n * @param parameters - {@link _snapshot.Parameters}\n * @returns The new positions. {@link _snapshot.ReturnType}\n */\nasync function _snapshot(parameters: _snapshot.Parameters): Promise<_snapshot.ReturnType> {\n const { positions, blockNumber, client, maxBatchSize, retryAttempts, retryDelayMs } = parameters;\n\n const vaultV1Positions: Position.Position[] = [];\n const erc20Positions: Position.Position[] = [];\n for (const position of positions) {\n switch (position.type) {\n case Position.Type.VAULT_V1:\n vaultV1Positions.push(position);\n break;\n case Position.Type.ERC20:\n erc20Positions.push(position);\n break;\n default:\n throw new Error(\"Invalid position type\");\n }\n }\n\n const promises: Promise<Position.Position[]>[] = [\n Fetchers.snapshotVaultPositions({\n client,\n positions: vaultV1Positions,\n blockNumber,\n options: { maxBatchSize, retryAttempts, retryDelayMs },\n }),\n Fetchers.snapshotERC20Positions({\n client,\n positions: erc20Positions,\n blockNumber,\n options: { maxBatchSize, retryAttempts, retryDelayMs },\n }),\n ];\n\n return (await Promise.all(promises)).flat();\n}\n\ndeclare namespace _snapshot {\n export type Parameters = {\n positions: Position.Position[];\n blockNumber: number;\n client: PublicClient<Transport, Chain.Chain>;\n maxBatchSize?: number;\n retryAttempts?: number;\n retryDelayMs?: number;\n };\n\n export type ReturnType = Position.Position[];\n}\n\nclass InsertPositionsError extends Errors.BaseError<Error> {\n override name = \"InsertPositionsError\";\n constructor(err: Error) {\n super(\"Failed to insert positions\", { cause: err });\n }\n}\n\nclass InsertTransfersError extends Errors.BaseError<Error> {\n override name = \"InsertTransfersError\";\n constructor(err: Error) {\n super(\"Failed to insert transfers\", { cause: err });\n }\n}\n","import type { PublicActions, PublicClient, Transport } from \"viem\";\nimport type { Chain, Oracle } from \"#core\";\nimport * as Logger from \"#logger/Logger.ts\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport type * as Collector from \"../Collector.ts\";\nimport { fetchOraclePrices } from \"../fetchers/fetchOraclePrices.ts\";\n\n/**\n * Collects oracle prices from on-chain oracles and persists them.\n *\n * - Reads oracle definitions as {@link Oracle.Oracle}.\n * - Uses chain metadata from {@link Chain.Chain}.\n *\n * @param parameters - {@link collectPrices.Parameters} (extends {@link Collector.CollectParameters})\n * with a client supporting {@link PublicActions.multicall | multicall}.\n * @yields Latest processed block number after each successful update.\n */\nexport async function* collectPrices<\n collector extends Collector.Name,\n client extends PublicClient<Transport, Chain.Chain> = PublicClient<Transport, Chain.Chain>,\n>(parameters: collectPrices.Parameters<collector, client>): collectPrices.ReturnType {\n const {\n db,\n collector,\n client,\n options: { maxBatchSize = 5_000, retryAttempts = 5, retryDelayMs = 500 } = {},\n } = parameters;\n\n const logger = Logger.getLogger();\n let blockNumber = parameters.lastBlockNumber;\n\n const [oracles, { blockNumber: latestBlockNumberChain, epoch }] = await Promise.all([\n db.oracles.get({ chainId: client.chain.id }),\n db.blocks.getChain(client.chain.id),\n ]);\n\n const updatedOracles: Oracle.Oracle[] = [];\n try {\n const pricesMap = await fetchOraclePrices({\n client,\n oracles: oracles.map((oracle) => oracle.address),\n options: {\n batchSize: maxBatchSize,\n blockNumber: latestBlockNumberChain,\n retryAttempts,\n retryDelayMs,\n },\n });\n\n for (const oracle of oracles) {\n const price = pricesMap.get(oracle.address);\n if (price !== undefined) {\n updatedOracles.push({\n chainId: client.chain.id,\n address: oracle.address,\n price,\n blockNumber: latestBlockNumberChain,\n });\n }\n }\n } catch (err) {\n logger.error({\n msg: \"Failed to fetch oracle prices\",\n collector,\n chain_id: client.chain.id,\n block_number: latestBlockNumberChain,\n err,\n });\n yield blockNumber;\n return;\n }\n\n let reorgDetected = false;\n try {\n await db.transaction(async (dbTx) => {\n if (updatedOracles.length > 0) {\n await dbTx.oracles.upsert(updatedOracles);\n logger.info({\n msg: \"Oracle prices updated\",\n collector,\n count: updatedOracles.length,\n chain_id: client.chain.id,\n block_number: latestBlockNumberChain,\n });\n }\n\n try {\n await dbTx.blocks.advanceCollector({\n collectorName: collector,\n chainId: client.chain.id,\n blockNumber: latestBlockNumberChain,\n epoch,\n });\n } catch (_) {\n throw new Errors.ReorgError(latestBlockNumberChain);\n }\n\n blockNumber = latestBlockNumberChain;\n });\n } catch (err) {\n if (err instanceof Errors.ReorgError) {\n logger.info({\n msg: \"Reorg detected, prices update aborted\",\n collector,\n count: updatedOracles.length,\n chain_id: client.chain.id,\n block_number: latestBlockNumberChain,\n });\n reorgDetected = true;\n } else {\n throw new Error(\"Failed to collect oracle prices\", { cause: err });\n }\n }\n\n if (!reorgDetected) {\n yield blockNumber;\n return;\n }\n\n await db.transaction(async (dbTx) => {\n try {\n const ancestor = await dbTx.blocks.getCollector({\n collectorName: collector,\n chainId: client.chain.id,\n });\n\n blockNumber = ancestor.blockNumber;\n\n await dbTx.blocks.advanceCollector({\n collectorName: collector,\n chainId: client.chain.id,\n blockNumber,\n epoch: ancestor.epoch,\n });\n } catch (err) {\n const msg = \"Failed to revert to ancestor block when handling reorg.\";\n logger.error({\n collector,\n chainId: client.chain.id,\n msg,\n err,\n });\n\n throw new Error(msg);\n }\n });\n\n yield blockNumber;\n}\n\nexport declare namespace collectPrices {\n export type Parameters<\n collector extends Collector.Name,\n client extends PublicClient<Transport, Chain.Chain> = PublicClient<Transport, Chain.Chain>,\n > = Collector.CollectParameters<collector, client> & {\n options?: {\n maxBatchSize?: number;\n retryAttempts?: number;\n retryDelayMs?: number;\n };\n };\n\n export type ReturnType = AsyncGenerator<number, void, void>;\n}\n","import type { PublicClient, Transport } from \"viem\";\nimport type { Chain } from \"#core\";\nimport type { Database } from \"#database/index.ts\";\nimport type { GatekeeperClient } from \"#gatekeeper/Client.ts\";\nimport * as CollectFunctions from \"./CollectFunctions/index.ts\";\nimport * as Collector from \"./Collector.ts\";\n\nexport type Builder<client extends PublicClient<Transport, Chain.Chain>> = {\n buildOffersCollector: (parameters: {\n options?: { maxBatchSize?: number };\n }) => Collector.Collector<\"offers\", client>;\n\n buildConsumedEventsCollector: (parameters?: {\n options?: { maxBatchSize?: number };\n }) => Collector.Collector<\"consumed_events\", client>;\n\n buildPricesCollector: (parameters?: {\n options?: { maxBatchSize?: number; retryAttempts?: number; retryDelayMs?: number };\n }) => Collector.Collector<\"prices\", client>;\n\n buildPositionsCollector: (parameters: {\n options?: { maxBatchSize?: number; retryAttempts?: number; retryDelayMs?: number };\n }) => Collector.Collector<\"positions\", client>;\n};\n\nexport function createBuilder<client extends PublicClient<Transport, Chain.Chain>>(parameters: {\n client: client;\n db: Database.Database;\n gatekeeper: GatekeeperClient;\n options: {\n maxBlockNumber?: number;\n blockWindow?: number;\n interval?: number;\n };\n}): Builder<client> {\n const {\n client,\n db,\n gatekeeper,\n options: { maxBlockNumber, blockWindow, interval } = {},\n } = parameters;\n\n const createCollector = <name extends Collector.Name>(\n name: name,\n collect: Collector.CollectFn<name, client>,\n ): Collector.Collector<name, client> =>\n Collector.create<name, client>({\n name,\n collect,\n client,\n db,\n options: { maxBlockNumber, interval },\n });\n\n return {\n buildOffersCollector: ({ options: { maxBatchSize = 1_000 } = {} }) => {\n return createCollector(\"offers\", (p) =>\n CollectFunctions.collectOffersV2<\"offers\">({\n ...p,\n gatekeeper,\n collector: \"offers\",\n client,\n options: { maxBatchSize, blockWindow },\n }),\n );\n },\n\n buildConsumedEventsCollector: ({ options: { maxBatchSize = 1_000 } = {} } = {}) => {\n return createCollector(\"consumed_events\", (p) =>\n CollectFunctions.collectConsumedEvents<\"consumed_events\">({\n ...p,\n collector: \"consumed_events\",\n options: { maxBatchSize, blockWindow },\n }),\n );\n },\n\n buildPricesCollector: ({\n options: { maxBatchSize = 5_000, retryAttempts, retryDelayMs } = {},\n } = {}) => {\n return createCollector(\"prices\", (p) =>\n CollectFunctions.collectPrices<\"prices\">({\n ...p,\n collector: \"prices\",\n options: { maxBatchSize, retryAttempts, retryDelayMs },\n }),\n );\n },\n\n buildPositionsCollector: ({\n options: { maxBatchSize = 1_000, retryAttempts, retryDelayMs } = {},\n } = {}) => {\n return createCollector(\"positions\", (p) =>\n CollectFunctions.collectPositions<\"positions\">({\n ...p,\n collector: \"positions\",\n options: { maxBatchSize, retryAttempts, retryDelayMs, blockWindow },\n }),\n );\n },\n };\n}\n","import type { PublicClient, Transport } from \"viem\";\nimport type { Chain } from \"#core\";\nimport type { Database } from \"#database/index.ts\";\nimport type { GatekeeperClient } from \"../../gatekeeper/Client.ts\";\nimport type * as Collector from \"./Collector.ts\";\nimport { CollectorBuilder } from \"./index.ts\";\n\ntype CollectorsResult = {\n offersCollector: Collector.Collector<\"offers\", PublicClient<Transport, Chain.Chain>>;\n consumedEventsCollector: Collector.Collector<\n \"consumed_events\",\n PublicClient<Transport, Chain.Chain>\n >;\n pricesCollector: Collector.Collector<\"prices\", PublicClient<Transport, Chain.Chain>>;\n positionsCollector: Collector.Collector<\"positions\", PublicClient<Transport, Chain.Chain>>;\n};\n\nexport const from = (parameters: {\n client: PublicClient<Transport, Chain.Chain>;\n db: Database.Database;\n gatekeeper: GatekeeperClient;\n maxBatchSize?: number;\n maxBlockNumber?: number;\n blockWindow?: number;\n interval?: number;\n retryAttempts?: number;\n retryDelayMs?: number;\n}): CollectorsResult => {\n const {\n client,\n db,\n gatekeeper,\n maxBatchSize,\n maxBlockNumber,\n blockWindow,\n interval,\n retryAttempts,\n retryDelayMs,\n } = parameters;\n\n const collectorBuilder = CollectorBuilder.createBuilder({\n client,\n db,\n gatekeeper,\n options: { maxBlockNumber, blockWindow, interval },\n });\n\n const offersCollector = collectorBuilder.buildOffersCollector({ options: { maxBatchSize } });\n\n const consumedEventsCollector = collectorBuilder.buildConsumedEventsCollector({\n options: { maxBatchSize },\n });\n\n const pricesCollector = collectorBuilder.buildPricesCollector({\n options: { maxBatchSize, retryAttempts, retryDelayMs },\n });\n\n const positionsCollector = collectorBuilder.buildPositionsCollector({\n options: { maxBatchSize, retryAttempts, retryDelayMs },\n });\n\n return {\n offersCollector,\n consumedEventsCollector,\n pricesCollector,\n positionsCollector,\n };\n};\n","import type { Account, PublicClient, Transport } from \"viem\";\nimport type * as Chain from \"#core/Chain.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport type { GatekeeperClient } from \"#gatekeeper/Client.ts\";\nimport { Tracer } from \"#tracer/index.ts\";\nimport * as Collector from \"./collectors/Collector.ts\";\nimport * as Collectors from \"./collectors/Collectors.ts\";\n\nexport type Indexer = {\n start: () => () => void;\n next: () => Promise<void>;\n return: () => Promise<void>;\n};\n\nexport type IndexerConfig<\n client extends PublicClient<Transport, Chain.Chain, Account | undefined>,\n> = {\n client: client;\n db: Database.Database;\n gatekeeper: GatekeeperClient;\n interval?: number;\n maxBatchSize?: number;\n maxBlockNumber?: number;\n blockWindow?: number;\n retryAttempts?: number;\n retryDelayMs?: number;\n};\n\nexport function from<client extends PublicClient<Transport, Chain.Chain, Account | undefined>>(\n config: IndexerConfig<client>,\n): Indexer {\n const {\n client,\n gatekeeper,\n db,\n interval = 10_000,\n maxBatchSize = 1000,\n maxBlockNumber,\n blockWindow,\n retryAttempts,\n retryDelayMs,\n } = config;\n\n const { offersCollector, consumedEventsCollector, positionsCollector, pricesCollector } =\n Collectors.from({\n client: client as PublicClient<Transport, Chain.Chain>,\n db,\n gatekeeper,\n maxBatchSize,\n maxBlockNumber,\n blockWindow,\n interval,\n retryAttempts,\n retryDelayMs,\n });\n\n return create({\n client,\n collectors: [offersCollector, consumedEventsCollector, positionsCollector, pricesCollector],\n });\n}\n\nexport function create<\n client extends PublicClient<Transport, Chain.Chain, Account | undefined>,\n>(params: { collectors: Collector.Collector[]; client: client }): Indexer {\n const { collectors, client } = params;\n const indexerId = `${client.chain.id.toString()}.indexer`;\n const tracer = Tracer.getTracer(`router.${indexerId}`);\n const iterators = collectors.map((collector) => collector.collect());\n\n const next = async () => {\n await Tracer.startActiveSpan(tracer, `${indexerId}.next`, async () => {\n await Promise.all(iterators.map((iterator) => iterator.next()));\n });\n };\n\n const _return = async () => {\n await Promise.all(iterators.map(async (iterator) => iterator.return()));\n };\n\n return {\n start: () => {\n const stops = collectors.map((collector) => Collector.start(collector));\n return () => {\n stops.forEach((stop) => {\n stop();\n });\n };\n },\n\n next,\n return: _return,\n };\n}\n","import type { Client } from \"viem\";\nimport { getBlockNumber } from \"viem/actions\";\nimport type { Chain } from \"#core\";\nimport type * as ChainRegistry from \"#core/ChainRegistry.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport { Collector } from \"#indexer/index.ts\";\nimport { retry } from \"#utils/retry.ts\";\n\nexport type CollectorHealthStatus = \"live\" | \"lagging\" | \"unknown\";\nexport type RouterStatus = \"live\" | \"syncing\";\n\nexport type CollectorHealth = {\n name: Collector.Name;\n chainId: Chain.Id;\n blockNumber: number | null;\n updatedAt: string | null;\n lag: number | null;\n status: CollectorHealthStatus;\n initialized: boolean;\n};\n\nexport type ChainHealth = {\n chainId: Chain.Id;\n localBlockNumber: number | null;\n remoteBlockNumber: number | null;\n epoch: string | null;\n updatedAt: string | null;\n initialized: boolean;\n};\n\nexport type MissingCollector = {\n chainId: Chain.Id;\n name: Collector.Name;\n};\n\nexport type RouterHealth = {\n status: RouterStatus;\n initialized: boolean;\n missingChains: Chain.Id[];\n missingCollectors: MissingCollector[];\n};\n\nexport type HealthService = {\n getSnapshot: () => Promise<Snapshot>;\n getStatus: () => Promise<RouterHealth>;\n getCollectors: () => Promise<CollectorHealth[]>;\n getChains: () => Promise<ChainHealth[]>;\n};\n\nexport type HealthServiceParameters = {\n db: Database.Database;\n /** Maximum number of blocks a collector can lag behind its chain before being considered lagging. */\n maxAllowedLag?: number;\n /** Map of chainId to client for fetching remote block numbers. */\n healthClients?: Map<Chain.Id, Client>;\n /** Chain registry for deriving expected initialization state. */\n chainRegistry?: ChainRegistry.ChainRegistry;\n};\n\nconst DEFAULT_MAX_ALLOWED_LAG = 5;\n\ntype Snapshot = {\n status: RouterStatus;\n initialized: boolean;\n missingChains: Chain.Id[];\n missingCollectors: MissingCollector[];\n collectors: CollectorHealth[];\n chains: ChainHealth[];\n};\n\n/**\n * Create a health service that exposes collector and chain block numbers.\n */\nexport function create(parameters: HealthServiceParameters): HealthService {\n const { db, maxAllowedLag = DEFAULT_MAX_ALLOWED_LAG, healthClients, chainRegistry } = parameters;\n\n const loadSnapshot = async (): Promise<Snapshot> => {\n const [collectorRows, chainRows, remoteBlockByChainId] = await Promise.all([\n db.blocks.getCollectors(),\n db.blocks.getChains(),\n getRemoteBlockNumbers(healthClients),\n ]);\n\n const chainById = new Map<Chain.Id, { blockNumber: number; epoch: bigint; updatedAt: Date }>();\n for (const chain of chainRows) {\n chainById.set(chain.chainId, {\n blockNumber: chain.blockNumber,\n epoch: chain.epoch,\n updatedAt: chain.updatedAt,\n });\n }\n\n const configuredChainIds = chainRegistry?.list().map((chain) => chain.id) ?? [];\n const knownChainIds = new Set<Chain.Id>(configuredChainIds);\n for (const chain of chainRows) knownChainIds.add(chain.chainId);\n\n const collectorKey = (chainId: Chain.Id, name: Collector.Name) => `${chainId}:${name}`;\n const collectorsByKey = new Map<\n string,\n {\n name: Collector.Name;\n chainId: Chain.Id;\n blockNumber: number;\n updatedAt: Date;\n }\n >();\n\n for (const row of collectorRows) {\n collectorsByKey.set(collectorKey(row.chainId, row.collectorName), {\n name: row.collectorName,\n chainId: row.chainId,\n blockNumber: row.blockNumber,\n updatedAt: row.updatedAt,\n });\n }\n\n for (const row of collectorRows) knownChainIds.add(row.chainId);\n\n const expectedChainIds =\n configuredChainIds.length > 0 ? configuredChainIds : Array.from(knownChainIds);\n\n const missingChains = expectedChainIds\n .filter((chainId) => !chainById.has(chainId))\n .sort((a, b) => (a - b > 0 ? 1 : -1));\n\n const missingCollectors = expectedChainIds\n .flatMap((chainId) =>\n [...Collector.names]\n .sort()\n .filter((name) => !collectorsByKey.has(collectorKey(chainId, name)))\n .map((name) => ({ chainId, name })),\n )\n .sort((a, b) =>\n a.chainId === b.chainId ? a.name.localeCompare(b.name) : a.chainId - b.chainId,\n );\n\n const initialized =\n knownChainIds.size > 0 && missingChains.length === 0 && missingCollectors.length === 0;\n\n const collectors: CollectorHealth[] = Array.from(knownChainIds)\n .sort((a, b) => (a - b > 0 ? 1 : -1))\n .flatMap((chainId) =>\n [...Collector.names].sort().map((name) => {\n const row = collectorsByKey.get(collectorKey(chainId, name));\n const chain = chainById.get(chainId);\n\n const blockNumber = row?.blockNumber ?? null;\n const chainBlockNumber = chain?.blockNumber ?? null;\n const lag =\n blockNumber !== null && chainBlockNumber !== null\n ? Math.max(chainBlockNumber - blockNumber, 0)\n : null;\n\n let status: CollectorHealthStatus = \"unknown\";\n if (lag !== null) {\n status = lag <= maxAllowedLag ? \"live\" : \"lagging\";\n } else if (chainBlockNumber !== null) {\n status = \"lagging\";\n }\n\n return {\n name,\n chainId,\n blockNumber,\n updatedAt: row ? row.updatedAt.toISOString() : null,\n lag,\n status,\n initialized: row !== undefined,\n } satisfies CollectorHealth;\n }),\n );\n\n const chains: ChainHealth[] = Array.from(knownChainIds)\n .sort((a, b) => (a - b > 0 ? 1 : -1))\n .map((chainId) => {\n const chain = chainById.get(chainId);\n return {\n chainId,\n localBlockNumber: chain?.blockNumber ?? null,\n remoteBlockNumber: remoteBlockByChainId.get(chainId) ?? null,\n epoch: chain ? chain.epoch.toString() : null,\n updatedAt: chain ? chain.updatedAt.toISOString() : null,\n initialized: chain !== undefined,\n };\n });\n\n const status: RouterStatus =\n collectors.length > 0 && collectors.every((collector) => collector.status === \"live\")\n ? \"live\"\n : \"syncing\";\n\n return {\n status,\n initialized,\n missingChains,\n missingCollectors,\n collectors,\n chains,\n };\n };\n\n return {\n async getSnapshot(): Promise<Snapshot> {\n return loadSnapshot();\n },\n\n async getStatus(): Promise<RouterHealth> {\n const snapshot = await loadSnapshot();\n return {\n status: snapshot.status,\n initialized: snapshot.initialized,\n missingChains: snapshot.missingChains,\n missingCollectors: snapshot.missingCollectors,\n };\n },\n\n async getCollectors(): Promise<CollectorHealth[]> {\n const snapshot = await loadSnapshot();\n return snapshot.collectors;\n },\n\n async getChains(): Promise<ChainHealth[]> {\n const snapshot = await loadSnapshot();\n return snapshot.chains;\n },\n };\n}\n\n/**\n * Fetch the latest block number from all remote clients.\n * Each RPC call is retried up to 3 times; failures yield null for that chain.\n * @param healthClients - The map of chainId to client.\n * @returns The map of chainId to remote block number or null on failure.\n */\nasync function getRemoteBlockNumbers(\n healthClients?: Map<Chain.Id, Client>,\n): Promise<Map<Chain.Id, number | null>> {\n const remoteBlockPromises = Array.from(healthClients ?? new Map<Chain.Id, Client>()).map(\n async ([chainId, client]) => {\n const remoteBlock =\n (await retry(() => getBlockNumber(client).then(Number), 3).catch(() =>\n Promise.resolve(),\n )) ?? null;\n return { chainId, remoteBlock };\n },\n );\n\n const results = await Promise.all(remoteBlockPromises);\n return new Map(results.map((r) => [r.chainId, r.remoteBlock]));\n}\n","import * as Tick from \"#core/Tick.ts\";\n\nexport type BookLevelResponse = {\n tick: number;\n price: string;\n assets: string;\n count: number;\n};\n\ntype Input = {\n tick: number;\n assets: bigint;\n count: number;\n};\n\nexport function from(level: Input): BookLevelResponse {\n const price = Tick.tickToPrice(level.tick);\n\n return {\n tick: level.tick,\n price: price.toString(),\n assets: level.assets.toString(),\n count: level.count,\n };\n}\n","import { z } from \"zod/v4\";\n\nexport const CollectorHealth = z.object({\n name: z.string(),\n chain_id: z.number(),\n block_number: z.number().nullable(),\n updated_at: z.string().nullable(),\n lag: z.number().nullable(),\n status: z.enum([\"live\", \"lagging\", \"unknown\"]),\n initialized: z.boolean(),\n});\n\nexport const CollectorsHealthResponse = z.array(CollectorHealth);\n\nexport const ChainHealth = z.object({\n chain_id: z.number(),\n local_block_number: z.number().nullable(),\n remote_block_number: z.number().nullable(),\n updated_at: z.string().nullable(),\n initialized: z.boolean(),\n});\n\nexport const ChainsHealthResponse = z.array(ChainHealth);\n\nexport const RouterStatusResponse = z.object({\n status: z.enum([\"live\", \"syncing\"]),\n initialized: z.boolean(),\n missing_chains: z.array(z.number()),\n missing_collectors: z.array(\n z.object({\n chain_id: z.number(),\n name: z.string(),\n }),\n ),\n});\n\nexport type CollectorsHealthResponse = z.infer<typeof CollectorsHealthResponse>;\nexport type ChainsHealthResponse = z.infer<typeof ChainsHealthResponse>;\nexport type RouterStatusResponse = z.infer<typeof RouterStatusResponse>;\n","import type { Obligation, Quote } from \"#core\";\nimport type * as OpenApiSchema from \"./generated/swagger.d.ts\";\n\nexport type ObligationResponse =\n OpenApiSchema.paths[\"/v1/obligations\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"][\"data\"][number];\n\n/**\n * Creates an `ObligationResponse` from a `Obligation`.\n * @constructor\n * @param obligation - {@link Obligation}\n * @param quote - {@link Quote}\n * @returns The created `ObligationResponse`. {@link ObligationResponse}\n */\nexport function from(obligation: Obligation.Obligation, quote: Quote.Quote): ObligationResponse {\n return {\n id: quote.obligationId,\n chain_id: obligation.chainId,\n loan_token: obligation.loanToken,\n collaterals: obligation.collaterals.map((c) => ({\n token: c.asset,\n lltv: c.lltv.toString(),\n oracle: c.oracle,\n })),\n maturity: obligation.maturity,\n ask: { tick: quote.ask.tick, price: quote.ask.price.toString() },\n bid: { tick: quote.bid.tick, price: quote.bid.price.toString() },\n };\n}\n","import type { Address, Hex } from \"viem\";\nimport { Obligation } from \"#core\";\nimport type * as OpenApiSchema from \"./generated/swagger.d.ts\";\n\nexport type OfferResponse =\n OpenApiSchema.paths[\"/v1/offers\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"][\"data\"][number];\n\nexport type Input = Readonly<{\n hash: Hex;\n maker: Address;\n assets: bigint;\n obligationUnits: bigint;\n obligationShares: bigint;\n tick: number;\n maturity: number;\n expiry: number;\n start: number;\n group: Hex;\n session: Hex;\n buy: boolean;\n chainId: number;\n loanToken: Address;\n collaterals: Readonly<\n {\n asset: Address;\n lltv: bigint;\n oracle: Address;\n }[]\n >;\n callback: {\n address: Address;\n data: Hex;\n };\n receiverIfMakerIsSeller: Address;\n root?: Hex | undefined;\n proof?: Hex[] | undefined;\n signature?: Hex | undefined;\n consumed: bigint;\n takeable: bigint;\n blockNumber: number;\n}>;\n\nfunction normalizeChainId(chainId: Input[\"chainId\"]): number {\n const parsedChainId = Number(chainId);\n if (!Number.isInteger(parsedChainId) || parsedChainId <= 0) {\n throw new Error(`Invalid chain id: ${String(chainId)}`);\n }\n return parsedChainId;\n}\n\nfunction normalizeBlockNumber(blockNumber: Input[\"blockNumber\"]): number {\n const parsedBlockNumber = Number(blockNumber);\n if (!Number.isInteger(parsedBlockNumber) || parsedBlockNumber < 0) {\n throw new Error(`Invalid block number: ${String(blockNumber)}`);\n }\n return parsedBlockNumber;\n}\n\n/**\n * Creates an `OfferResponse` matching the Solidity Offer struct layout.\n * @constructor\n * @param input - {@link Input}\n * @returns The created `OfferResponse`. {@link OfferResponse}\n */\nexport function from(input: Input): OfferResponse {\n const chainId = normalizeChainId(input.chainId);\n const blockNumber = normalizeBlockNumber(input.blockNumber);\n\n const offer = {\n obligation: {\n loan_token: input.loanToken,\n collaterals: input.collaterals.map((c) => ({\n token: c.asset,\n lltv: c.lltv.toString(),\n oracle: c.oracle,\n })),\n maturity: input.maturity,\n },\n buy: input.buy,\n maker: input.maker,\n assets: input.assets.toString(),\n obligation_units: input.obligationUnits.toString(),\n obligation_shares: input.obligationShares.toString(),\n start: input.start,\n expiry: input.expiry,\n tick: input.tick,\n group: input.group,\n session: input.session,\n callback: input.callback.address,\n callback_data: input.callback.data,\n receiver_if_maker_is_seller: input.receiverIfMakerIsSeller,\n };\n\n const base = {\n offer,\n offer_hash: input.hash,\n obligation_id: Obligation.id({\n chainId,\n loanToken: input.loanToken,\n collaterals: [...input.collaterals],\n maturity: input.maturity,\n }),\n chain_id: chainId,\n consumed: input.consumed.toString(),\n takeable: input.takeable.toString(),\n block_number: blockNumber,\n };\n\n if (!input.proof || !input.root || !input.signature) {\n return {\n ...base,\n root: null,\n proof: null,\n signature: null,\n } as OfferResponse;\n }\n\n return {\n ...base,\n root: input.root.toLowerCase(),\n proof: input.proof.map((p) => p.toLowerCase()),\n signature: input.signature.toLowerCase(),\n } as OfferResponse;\n}\n","import * as z from \"zod\";\nimport type { Compute } from \"#core\";\n\nexport const API_ERROR_CODES = [\n \"VALIDATION_ERROR\",\n \"NOT_FOUND\",\n \"INTERNAL_SERVER_ERROR\",\n \"BAD_REQUEST\",\n] as const;\n\ntype APIErrorCode = (typeof API_ERROR_CODES)[number];\n\nexport enum STATUS_CODE {\n SUCCESS = 200,\n BAD_REQUEST = 400,\n NOT_FOUND = 404,\n INTERNAL_SERVER_ERROR = 500,\n}\n\nexport class APIError<Code extends STATUS_CODE = STATUS_CODE> extends Error {\n constructor(\n public statusCode: Code,\n message: string,\n public code: APIErrorCode,\n public details?: unknown,\n ) {\n super(message);\n this.name = \"APIError\";\n }\n}\n\nexport class ValidationError extends APIError<STATUS_CODE.BAD_REQUEST> {\n constructor(message: string, details?: unknown) {\n super(STATUS_CODE.BAD_REQUEST, message, \"VALIDATION_ERROR\", details);\n }\n}\n\nexport class NotFoundError extends APIError<STATUS_CODE.NOT_FOUND> {\n constructor(message: string) {\n super(STATUS_CODE.NOT_FOUND, message, \"NOT_FOUND\");\n }\n}\n\nexport class InternalServerError extends APIError<STATUS_CODE.INTERNAL_SERVER_ERROR> {\n constructor(message = \"Internal server error\") {\n super(STATUS_CODE.INTERNAL_SERVER_ERROR, message, \"INTERNAL_SERVER_ERROR\");\n }\n}\n\nexport class BadRequestError extends APIError<STATUS_CODE.BAD_REQUEST> {\n constructor(message = \"Invalid JSON format\", details?: unknown) {\n super(STATUS_CODE.BAD_REQUEST, message, \"BAD_REQUEST\", details);\n }\n}\n\ntype Meta = {\n timestamp: string;\n checksum?: string;\n};\n\ntype ErrorDetail = {\n code: APIErrorCode;\n message: string;\n details?: unknown;\n};\n\nexport type SuccessPayload<T> = Compute<{\n statusCode: STATUS_CODE.SUCCESS;\n body: {\n cursor: string | null;\n data: T;\n meta: Meta;\n };\n}>;\n\nexport type ErrorPayload<\n statusCode extends Exclude<STATUS_CODE, STATUS_CODE.SUCCESS> = Exclude<\n STATUS_CODE,\n STATUS_CODE.SUCCESS\n >,\n> = Compute<{\n statusCode: statusCode;\n body: {\n meta: Meta;\n error: ErrorDetail;\n };\n}>;\n\nexport type Payload<T> = SuccessPayload<T> | ErrorPayload;\n\nexport function success<T>(args: { data: T; cursor?: string | null }): SuccessPayload<T> {\n const { data, cursor } = args;\n return {\n statusCode: STATUS_CODE.SUCCESS as const,\n body: {\n meta: { timestamp: new Date().toISOString() },\n cursor: cursor ?? null,\n data,\n },\n };\n}\n\n/**\n * Generic failure builder. Preserves the concrete status code when the input is an APIError.\n * If not an APIError, maps to INTERNAL_SERVER_ERROR. Zod & SyntaxError are mapped to BAD_REQUEST.\n */\nexport function failure<\n Code extends Exclude<STATUS_CODE, STATUS_CODE.SUCCESS> = Exclude<\n STATUS_CODE,\n STATUS_CODE.SUCCESS\n >,\n>(err: unknown): ErrorPayload<Code> {\n if (err instanceof APIError) {\n // Capture the exact status type from the error instance\n return handleAPIError(err) as ErrorPayload<Code>;\n }\n\n if (err instanceof SyntaxError) {\n return handleAPIError(new BadRequestError(err.message)) as ErrorPayload<Code>;\n }\n\n if (err instanceof z.ZodError) {\n return handleAPIError(handleZodError(err)) as ErrorPayload<Code>;\n }\n\n return handleAPIError(new InternalServerError()) as ErrorPayload<Code>;\n}\n\nfunction handleAPIError<Code extends Exclude<STATUS_CODE, STATUS_CODE.SUCCESS>>(\n error: APIError<Code>,\n): ErrorPayload<Code> {\n return {\n statusCode: error.statusCode,\n body: {\n meta: { timestamp: new Date().toISOString() },\n error: {\n code: error.code,\n message: error.message,\n ...(error.details && typeof error.details === \"object\" ? { details: error.details } : {}),\n },\n },\n };\n}\n\nexport function handleZodError(error: z.ZodError): ValidationError {\n const formattedErrors = error.issues.map((issue) => {\n const field = issue.path.join(\".\");\n let msg = issue.message;\n\n switch (issue.code) {\n case \"invalid_type\":\n if (issue.message.includes(\"received undefined\")) {\n msg = `${field} is required`;\n }\n break;\n case \"invalid_format\":\n msg = issue.format === \"regex\" ? issue.message : `${field} has an invalid format`;\n break;\n default:\n break;\n }\n\n return { field, issue: msg };\n });\n\n return new ValidationError(\"Validation failed\", formattedErrors);\n}\n","import \"reflect-metadata\";\nimport { generateDocument, type OpenAPIDocument } from \"openapi-metadata\";\nimport {\n ApiBody,\n ApiOperation,\n ApiParam,\n ApiProperty,\n ApiQuery,\n ApiResponse,\n ApiTags,\n} from \"openapi-metadata/decorators\";\nimport type { Address, Hex } from \"viem\";\nimport * as Payload from \"../Controllers/Payload.ts\";\n\nconst timestampExample = \"2024-01-01T12:00:00.000Z\";\nconst offerCursorExample = \"eyJvZmZzZXQiOjEwMH0\";\nconst obligationCursorExample =\n \"eyJzb3J0IjpbImlkIl0sImlkIjoiMHgxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAiLCJhc2siOiIwIiwiYmlkIjoiMCIsIm1hdHVyaXR5IjoxNzYxOTIyODAwfQ\";\n\nconst offerExample = {\n offer: {\n obligation: {\n loan_token: \"0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078\",\n collaterals: [\n {\n token: \"0x34Cf890dB685FC536E05652FB41f02090c3fb751\",\n lltv: \"860000000000000000\",\n oracle: \"0x45093658BE7f90B63D7c359e8f408e503c2D9401\",\n },\n ],\n maturity: 1761922799,\n },\n buy: false,\n maker: \"0x7b093658BE7f90B63D7c359e8f408e503c2D9401\",\n assets: \"369216000000000000000000\",\n obligation_units: \"0\",\n obligation_shares: \"0\",\n start: 1761922790,\n expiry: 1761922799,\n tick: 495,\n group: \"0x000000000000000000000000000000000000000000000000000000000008b8f4\",\n session: \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n callback: \"0x0000000000000000000000000000000000000000\",\n callback_data: \"0x\",\n receiver_if_maker_is_seller: \"0x7b093658BE7f90B63D7c359e8f408e503c2D9401\",\n },\n // Additional API fields (inlined at top level)\n offer_hash: \"0xac4bd8318ec914f89f8af913f162230575b0ac0696a19256bc12138c5cfe1427\",\n obligation_id: \"0x25690ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9abc\",\n chain_id: 1,\n consumed: \"0\",\n takeable: \"369216000000000000000000\",\n block_number: 2942933377146801,\n root: \"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef\",\n proof: [\n \"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890\",\n \"0x9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba\",\n ],\n signature:\n \"0x1234567890123456789012345678901234567890123456789012345678901234123456789012345678901234567890123456789012345678901234567890123400\",\n} as const;\n\nconst collectorsHealthExample = {\n name: \"offers\",\n chain_id: 1,\n block_number: 21345678,\n updated_at: timestampExample,\n lag: 0,\n status: \"live\",\n initialized: true,\n} as const;\n\nconst chainsHealthExample = {\n chain_id: 1,\n local_block_number: 21345678,\n remote_block_number: 21345690,\n updated_at: timestampExample,\n initialized: true,\n} as const;\n\nconst missingCollectorExample = {\n chain_id: 1,\n name: \"offers\",\n} as const;\n\n// Example for validate offer request\nconst validateOfferExample = {\n maker: \"0x7b093658BE7f90B63D7c359e8f408e503c2D9401\",\n assets: \"369216000000000000000000\",\n obligation_units: \"0\",\n obligation_shares: \"0\",\n tick: 495,\n maturity: 1761922799,\n expiry: 1761922799,\n start: 1761922790,\n group: \"0x000000000000000000000000000000000000000000000000000000000008b8f4\",\n session: \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n buy: false,\n chain_id: 1,\n loan_token: \"0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078\",\n collaterals: [\n {\n asset: \"0x34Cf890dB685FC536E05652FB41f02090c3fb751\",\n oracle: \"0x45093658BE7f90B63D7c359e8f408e503c2D9401\",\n lltv: \"860000000000000000\",\n },\n ],\n callback: {\n address: \"0x0000000000000000000000000000000000000000\",\n data: \"0x\",\n },\n receiver_if_maker_is_seller: \"0x7b093658BE7f90B63D7c359e8f408e503c2D9401\",\n} as const;\n\nconst routerStatusExample = {\n status: \"live\",\n initialized: true,\n missing_chains: [],\n missing_collectors: [],\n} as const;\n\nclass Meta {\n @ApiProperty({ type: \"string\", example: timestampExample })\n declare timestamp: string;\n}\n\nclass SuccessResponse {\n @ApiProperty({ type: () => Meta })\n declare meta: Meta;\n}\n\nclass ErrorResponse {\n @ApiProperty({ type: \"string\", enum: Payload.API_ERROR_CODES, example: \"VALIDATION_ERROR\" })\n declare code: string;\n\n @ApiProperty({\n type: \"string\",\n example: \"Limit must be greater than 0.\",\n })\n declare message: string;\n\n @ApiProperty({\n type: \"object\",\n example: [\n {\n field: \"limit\",\n issue: \"Limit must be greater than 0.\",\n },\n ],\n })\n declare details: unknown;\n}\n\nclass BadRequestResponse {\n @ApiProperty({ type: () => ErrorResponse })\n declare error: ErrorResponse;\n\n @ApiProperty({ type: () => Meta })\n declare meta: Meta;\n}\n\nclass CollateralResponse {\n @ApiProperty({ type: \"string\", example: \"0x34Cf890dB685FC536E05652FB41f02090c3fb751\" })\n declare token: Address;\n\n @ApiProperty({ type: \"string\", example: \"860000000000000000\" })\n declare lltv: string;\n\n @ApiProperty({ type: \"string\", example: \"0x45093658BE7f90B63D7c359e8f408e503c2D9401\" })\n declare oracle: Address;\n}\n\n// Classes for validate request (input format - uses asset, not token)\nclass ValidateCollateralRequest {\n @ApiProperty({ type: \"string\", example: validateOfferExample.collaterals[0].asset })\n declare asset: Address;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.collaterals[0].oracle })\n declare oracle: Address;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.collaterals[0].lltv })\n declare lltv: string;\n}\n\nclass ValidateCallbackRequest {\n @ApiProperty({ type: \"string\", example: validateOfferExample.callback.address })\n declare address: Address;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.callback.data })\n declare data: Hex;\n}\n\nclass AskResponse {\n @ApiProperty({\n type: \"number\",\n nullable: true,\n example: 500,\n description: \"Best ask tick. Null when there is no active ask quote.\",\n })\n declare tick: number | null;\n\n @ApiProperty({ type: \"string\", example: \"1000000000000000000\" })\n declare price: string;\n}\n\nclass BidResponse {\n @ApiProperty({\n type: \"number\",\n nullable: true,\n example: 500,\n description: \"Best bid tick. Null when there is no active bid quote.\",\n })\n declare tick: number | null;\n\n @ApiProperty({ type: \"string\", example: \"1000000000000000000\" })\n declare price: string;\n}\n\nclass ObligationOfferResponse {\n @ApiProperty({ type: \"string\", example: offerExample.offer.obligation.loan_token })\n declare loan_token: Address;\n\n @ApiProperty({\n type: () => [CollateralResponse],\n example: offerExample.offer.obligation.collaterals,\n })\n declare collaterals: CollateralResponse[];\n\n @ApiProperty({ type: \"number\", example: offerExample.offer.obligation.maturity })\n declare maturity: number;\n}\n\nclass OfferDataResponse {\n @ApiProperty({ type: () => ObligationOfferResponse, example: offerExample.offer.obligation })\n declare obligation: ObligationOfferResponse;\n\n @ApiProperty({ type: \"boolean\", example: offerExample.offer.buy })\n declare buy: boolean;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer.maker })\n declare maker: Address;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer.assets })\n declare assets: string;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer.obligation_units })\n declare obligation_units: string;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer.obligation_shares })\n declare obligation_shares: string;\n\n @ApiProperty({ type: \"number\", example: offerExample.offer.start })\n declare start: number;\n\n @ApiProperty({ type: \"number\", example: offerExample.offer.expiry })\n declare expiry: number;\n\n @ApiProperty({ type: \"number\", example: offerExample.offer.tick, minimum: 0, maximum: 990 })\n declare tick: number;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer.group })\n declare group: string;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer.session })\n declare session: string;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer.callback })\n declare callback: Address;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer.callback_data })\n declare callback_data: Hex;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer.receiver_if_maker_is_seller })\n declare receiver_if_maker_is_seller: Address;\n}\n\nclass OfferListItemResponse {\n @ApiProperty({ type: () => OfferDataResponse, example: offerExample.offer })\n declare offer: OfferDataResponse;\n\n @ApiProperty({ type: \"string\", example: offerExample.offer_hash })\n declare offer_hash: Hex;\n\n @ApiProperty({ type: \"string\", example: offerExample.obligation_id })\n declare obligation_id: Hex;\n\n @ApiProperty({ type: \"number\", example: offerExample.chain_id })\n declare chain_id: number;\n\n @ApiProperty({ type: \"string\", example: offerExample.consumed })\n declare consumed: string;\n\n @ApiProperty({ type: \"string\", example: offerExample.takeable })\n declare takeable: string;\n\n @ApiProperty({ type: \"number\", example: offerExample.block_number })\n declare block_number: number;\n\n @ApiProperty({ type: \"string\", nullable: true, example: offerExample.root })\n declare root: Hex | null;\n\n @ApiProperty({ type: [String], nullable: true, example: offerExample.proof })\n declare proof: Hex[] | null;\n\n @ApiProperty({ type: \"string\", nullable: true, example: offerExample.signature })\n declare signature: Hex | null;\n}\n\nclass ObligationResponse {\n @ApiProperty({\n type: \"string\",\n example: \"0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67\",\n })\n declare id: Hex;\n\n @ApiProperty({ type: \"number\", example: 1 })\n declare chain_id: number;\n\n @ApiProperty({ type: \"string\", example: \"0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078\" })\n declare loan_token: Address;\n\n @ApiProperty({ type: () => [CollateralResponse] })\n declare collaterals: CollateralResponse[];\n\n @ApiProperty({ type: \"number\", example: 1761922800 })\n declare maturity: number;\n\n @ApiProperty({ type: () => AskResponse })\n declare ask: AskResponse;\n\n @ApiProperty({ type: () => BidResponse })\n declare bid: BidResponse;\n}\nclass ObligationListResponse extends SuccessResponse {\n @ApiProperty({ type: \"string\", nullable: true, example: obligationCursorExample })\n declare cursor: string | null;\n\n @ApiProperty({\n type: () => [ObligationResponse],\n description: \"List of obligations with takable offers.\",\n })\n declare data: ObligationResponse[];\n}\n\nclass ObligationSingleSuccessResponse extends SuccessResponse {\n @ApiProperty({ type: \"string\", nullable: true, example: null })\n declare cursor: string | null;\n\n @ApiProperty({ type: () => ObligationResponse, description: \"Obligation details.\" })\n declare data: ObligationResponse;\n}\n\nclass OfferListResponse extends SuccessResponse {\n @ApiProperty({\n type: \"string\",\n nullable: true,\n example: offerCursorExample,\n description:\n \"Pagination cursor. Offer hash (0x...) for maker queries; base64url-encoded cursor for obligation queries.\",\n })\n declare cursor: string | null;\n\n @ApiProperty({\n type: () => [OfferListItemResponse],\n description: \"Offers matching the provided filters.\",\n example: [offerExample],\n })\n declare data: OfferListItemResponse[];\n}\n\nclass MissingCollectorResponse {\n @ApiProperty({ type: \"number\", example: missingCollectorExample.chain_id })\n declare chain_id: number;\n\n @ApiProperty({ type: \"string\", example: missingCollectorExample.name })\n declare name: string;\n}\n\nclass RouterStatusDataResponse {\n @ApiProperty({ type: \"string\", enum: [\"live\", \"syncing\"], example: routerStatusExample.status })\n declare status: \"live\" | \"syncing\";\n\n @ApiProperty({ type: \"boolean\", example: routerStatusExample.initialized })\n declare initialized: boolean;\n\n @ApiProperty({\n type: () => [Number],\n example: routerStatusExample.missing_chains,\n description: \"Configured chain ids missing initialization rows.\",\n })\n declare missing_chains: number[];\n\n @ApiProperty({\n type: () => [MissingCollectorResponse],\n example: routerStatusExample.missing_collectors,\n description: \"Collectors missing initialization rows.\",\n })\n declare missing_collectors: MissingCollectorResponse[];\n}\n\nclass RouterStatusSuccessResponse extends SuccessResponse {\n @ApiProperty({\n type: () => RouterStatusDataResponse,\n description: \"Aggregated router status.\",\n example: routerStatusExample,\n })\n declare data: RouterStatusDataResponse;\n}\n\nclass CollectorHealthResponse {\n @ApiProperty({ type: \"string\", example: collectorsHealthExample.name })\n declare name: string;\n\n @ApiProperty({ type: \"number\", example: collectorsHealthExample.chain_id })\n declare chain_id: number;\n\n @ApiProperty({ type: \"number\", nullable: true, example: collectorsHealthExample.block_number })\n declare block_number: number | null;\n\n @ApiProperty({ type: \"string\", nullable: true, example: collectorsHealthExample.updated_at })\n declare updated_at: string | null;\n\n @ApiProperty({ type: \"number\", nullable: true, example: collectorsHealthExample.lag })\n declare lag: number | null;\n\n @ApiProperty({\n type: \"string\",\n enum: [\"live\", \"lagging\", \"unknown\"],\n example: collectorsHealthExample.status,\n })\n declare status: \"live\" | \"lagging\" | \"unknown\";\n\n @ApiProperty({ type: \"boolean\", example: collectorsHealthExample.initialized })\n declare initialized: boolean;\n}\n\nclass CollectorsHealthSuccessResponse extends SuccessResponse {\n @ApiProperty({\n type: () => [CollectorHealthResponse],\n description: \"Collectors health details and sync status.\",\n example: [collectorsHealthExample],\n })\n declare data: CollectorHealthResponse[];\n}\n\nclass ChainHealthResponse {\n @ApiProperty({ type: \"number\", example: chainsHealthExample.chain_id })\n declare chain_id: number;\n\n @ApiProperty({\n type: \"number\",\n nullable: true,\n example: chainsHealthExample.local_block_number,\n })\n declare local_block_number: number | null;\n\n @ApiProperty({ type: \"number\", nullable: true, example: chainsHealthExample.remote_block_number })\n declare remote_block_number: number | null;\n\n @ApiProperty({ type: \"string\", nullable: true, example: chainsHealthExample.updated_at })\n declare updated_at: string | null;\n\n @ApiProperty({ type: \"boolean\", example: chainsHealthExample.initialized })\n declare initialized: boolean;\n}\n\nclass ChainsHealthSuccessResponse extends SuccessResponse {\n @ApiProperty({\n type: () => [ChainHealthResponse],\n description: \"Latest processed block per chain.\",\n example: [chainsHealthExample],\n })\n declare data: ChainHealthResponse[];\n}\n\nclass ValidateOfferRequest {\n @ApiProperty({ type: \"string\", example: validateOfferExample.maker })\n declare maker: Address;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.assets })\n declare assets: string;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.obligation_units, required: false })\n declare obligation_units: string;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.obligation_shares, required: false })\n declare obligation_shares: string;\n\n @ApiProperty({ type: \"number\", example: validateOfferExample.tick, minimum: 0, maximum: 990 })\n declare tick: number;\n\n @ApiProperty({ type: \"number\", example: validateOfferExample.maturity })\n declare maturity: number;\n\n @ApiProperty({ type: \"number\", example: validateOfferExample.expiry })\n declare expiry: number;\n\n @ApiProperty({ type: \"number\", example: validateOfferExample.start })\n declare start: number;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.group })\n declare group: string;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.session })\n declare session: string;\n\n @ApiProperty({ type: \"boolean\", example: validateOfferExample.buy })\n declare buy: boolean;\n\n @ApiProperty({ type: \"number\", example: validateOfferExample.chain_id })\n declare chain_id: number;\n\n @ApiProperty({ type: \"string\", example: validateOfferExample.loan_token })\n declare loan_token: Address;\n\n @ApiProperty({\n type: () => [ValidateCollateralRequest],\n example: validateOfferExample.collaterals,\n })\n declare collaterals: ValidateCollateralRequest[];\n\n @ApiProperty({ type: () => ValidateCallbackRequest, example: validateOfferExample.callback })\n declare callback: ValidateCallbackRequest;\n\n @ApiProperty({\n type: \"string\",\n example: validateOfferExample.receiver_if_maker_is_seller,\n })\n declare receiver_if_maker_is_seller: Address;\n}\n\nclass ValidateOffersRequest {\n @ApiProperty({\n type: () => [ValidateOfferRequest],\n description: \"Array of offers in snake_case format. Required, non-empty.\",\n required: true,\n })\n declare offers: ValidateOfferRequest[];\n}\n\nclass ValidationSuccessDataResponse {\n @ApiProperty({\n type: \"string\",\n description: \"Unsigned payload: version (1B) + gzip(offers) + root (32B).\",\n example: \"0x01789c...\",\n })\n declare payload: Hex;\n\n @ApiProperty({\n type: \"string\",\n description: \"Merkle tree root to sign with EIP-191.\",\n example: \"0xac4bd8318ec914f89f8af913f162230575b0ac0696a19256bc12138c5cfe1427\",\n })\n declare root: Hex;\n}\n\nclass ValidationSuccessResponse extends SuccessResponse {\n @ApiProperty({ type: \"string\", nullable: true, example: null })\n declare cursor: string | null;\n\n @ApiProperty({\n type: () => ValidationSuccessDataResponse,\n description: \"Payload and root for client-side signing.\",\n })\n declare data: ValidationSuccessDataResponse;\n}\n\nclass ValidationIssueResponse {\n @ApiProperty({\n type: \"number\",\n description: \"0-indexed position of the failed offer in the request array.\",\n example: 0,\n })\n declare index: number;\n\n @ApiProperty({\n type: \"string\",\n description: \"Gatekeeper rule name that rejected the offer.\",\n example: \"no_buy\",\n })\n declare rule: string;\n\n @ApiProperty({\n type: \"string\",\n description: \"Human-readable rejection reason.\",\n example: \"Buy offers are not supported\",\n })\n declare message: string;\n}\n\nclass ValidationFailureDataResponse {\n @ApiProperty({\n type: () => [ValidationIssueResponse],\n description: \"List of validation issues. Returned when any offer fails validation.\",\n })\n declare issues: ValidationIssueResponse[];\n}\n\nclass ValidationFailureResponse extends SuccessResponse {\n @ApiProperty({ type: \"string\", nullable: true, example: null })\n declare cursor: string | null;\n\n @ApiProperty({\n type: () => ValidationFailureDataResponse,\n description: \"List of validation issues. Returned when any offer fails validation.\",\n })\n declare data: ValidationFailureDataResponse;\n}\n\nclass BookLevelResponse {\n @ApiProperty({ type: \"number\", example: 495, minimum: 0, maximum: 990 })\n declare tick: number;\n\n @ApiProperty({\n type: \"string\",\n example: \"500000000000000000\",\n description: \"Price derived from tick, scaled by 1e18.\",\n })\n declare price: string;\n\n @ApiProperty({ type: \"string\", example: \"369216000000000000000000\" })\n declare assets: string;\n\n @ApiProperty({ type: \"number\", example: 5 })\n declare count: number;\n}\n\nconst positionExample = {\n chain_id: 1,\n contract: \"0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078\",\n user: \"0x7b093658BE7f90B63D7c359e8f408e503c2D9401\",\n obligation_id: \"0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67\",\n reserved: \"200000000000000000000\",\n block_number: 21345678,\n} as const;\n\nclass PositionListItemResponse {\n @ApiProperty({ type: \"number\", example: positionExample.chain_id })\n declare chain_id: number;\n\n @ApiProperty({ type: \"string\", example: positionExample.contract })\n declare contract: string;\n\n @ApiProperty({ type: \"string\", example: positionExample.user })\n declare user: string;\n\n @ApiProperty({\n type: \"string\",\n nullable: true,\n example: positionExample.obligation_id,\n description: \"Obligation id this reserved amount belongs to, or null if no lots exist.\",\n })\n declare obligation_id: string | null;\n\n @ApiProperty({ type: \"string\", example: positionExample.reserved })\n declare reserved: string;\n\n @ApiProperty({ type: \"number\", example: positionExample.block_number })\n declare block_number: number;\n}\n\nclass PositionListResponse extends SuccessResponse {\n @ApiProperty({ type: \"string\", nullable: true, example: offerCursorExample })\n declare cursor: string | null;\n\n @ApiProperty({\n type: () => [PositionListItemResponse],\n description: \"User positions with reserved balances from active offers.\",\n example: [positionExample],\n })\n declare data: PositionListItemResponse[];\n}\n\nclass BookListResponse extends SuccessResponse {\n @ApiProperty({ type: \"string\", nullable: true, example: offerCursorExample })\n declare cursor: string | null;\n\n @ApiProperty({\n type: () => [BookLevelResponse],\n description: \"Aggregated book levels grouped by offer tick.\",\n })\n declare data: BookLevelResponse[];\n}\n\n@ApiTags(\"Markets\")\n@ApiResponse({ status: 400, description: \"Bad Request\", type: BadRequestResponse })\nexport class BooksController {\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/books/{obligationId}/{side}\",\n summary: \"Get aggregated book\",\n description:\n \"Returns aggregated book data for a given obligation and side. Offers are grouped by tick with summed takeable amounts, and each level includes the corresponding wad-scaled price. Book levels are sorted by tick (ascending for sell side, descending for buy side).\",\n })\n @ApiParam({\n name: \"obligationId\",\n type: \"string\",\n example: \"0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67\",\n description: \"Obligation id.\",\n })\n @ApiParam({\n name: \"side\",\n type: \"string\",\n enum: [\"buy\", \"sell\"],\n example: \"buy\",\n description: \"Book side (buy or sell).\",\n })\n @ApiQuery({\n name: \"cursor\",\n type: \"string\",\n example: offerCursorExample,\n description: \"Pagination cursor in base64url-encoded format.\",\n })\n @ApiQuery({\n name: \"limit\",\n type: \"number\",\n example: 10,\n description: \"Maximum number of tick levels to return.\",\n })\n @ApiResponse({ status: 200, description: \"Success\", type: BookListResponse })\n async getBook() {}\n}\n\n@ApiTags(\"Make\")\n@ApiResponse({ status: 400, description: \"Bad Request\", type: BadRequestResponse })\nexport class ValidateController {\n @ApiOperation({\n methods: [\"post\"],\n path: \"/v1/validate\",\n summary: \"Validate offers\",\n description:\n \"Validates offers against router validation rules. Only empty callbacks (zero address, 0x data) are accepted. Returns unsigned payload + root on success, or issues only on validation failure.\",\n })\n @ApiBody({ type: ValidateOffersRequest })\n @ApiResponse({ status: 200, description: \"Success\", type: ValidationSuccessResponse })\n @ApiResponse({ status: 200, description: \"Validation issues\", type: ValidationFailureResponse })\n async validateOffers() {}\n}\n\n@ApiTags(\"Markets\")\n@ApiResponse({ status: 400, description: \"Bad Request\", type: BadRequestResponse })\nexport class OffersController {\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/offers\",\n summary: \"List all offers\",\n description:\n \"Returns offers. Provide either `obligation_id` + `side` (order book) or `maker` (by maker address).\",\n })\n @ApiQuery({\n name: \"side\",\n type: \"string\",\n required: false,\n enum: [\"buy\", \"sell\"],\n example: \"buy\",\n description: \"Side of the offer. Required when using obligation_id.\",\n })\n @ApiQuery({\n name: \"obligation_id\",\n type: \"string\",\n required: false,\n example: \"0x1234567890123456789012345678901234567890123456789012345678901234\",\n description: \"Obligation id used to filter offers. Required when not using maker.\",\n })\n @ApiQuery({\n name: \"maker\",\n type: \"string\",\n required: false,\n example: \"0x7b093658BE7f90B63D7c359e8f408e503c2D9401\",\n description: \"Maker address to filter offers by. Alternative to obligation_id + side.\",\n })\n @ApiQuery({\n name: \"cursor\",\n type: \"string\",\n example: offerCursorExample,\n description: \"Pagination cursor in base64url-encoded format.\",\n })\n @ApiQuery({\n name: \"limit\",\n type: \"number\",\n example: 10,\n description: \"Maximum number of offers to return.\",\n })\n @ApiResponse({ status: 200, description: \"Success\", type: OfferListResponse })\n async getOffers() {}\n}\n\n@ApiTags(\"System\")\nexport class HealthController {\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/health\",\n summary: \"Retrieve global health\",\n description: \"Returns the aggregated status of the router.\",\n })\n @ApiQuery({\n name: \"strict\",\n type: \"boolean\",\n required: false,\n example: true,\n description: \"Fail the request if initialization is incomplete.\",\n })\n @ApiResponse({ status: 200, description: \"Success\", type: RouterStatusSuccessResponse })\n async getRouterStatus() {}\n\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/health/collectors\",\n summary: \"Retrieve collectors health\",\n description: \"Returns the latest block numbers processed by collectors and their sync status.\",\n })\n @ApiQuery({\n name: \"strict\",\n type: \"boolean\",\n required: false,\n example: true,\n description: \"Fail the request if initialization is incomplete.\",\n })\n @ApiResponse({ status: 200, description: \"Success\", type: CollectorsHealthSuccessResponse })\n async getCollectorsHealth() {}\n\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/health/chains\",\n summary: \"Retrieve chains health\",\n description: \"Returns the latest block that can be processed by collectors for each chain.\",\n })\n @ApiQuery({\n name: \"strict\",\n type: \"boolean\",\n required: false,\n example: true,\n description: \"Fail the request if initialization is incomplete.\",\n })\n @ApiResponse({ status: 200, description: \"Success\", type: ChainsHealthSuccessResponse })\n async getChainsHealth() {}\n}\n\nconst configContractsExample = {\n chain_id: 505050505,\n address: \"0xD946246695A9259F3B33a78629026F61B3Ab40aF\",\n name: \"mempool\",\n} as const;\n\nconst configContractsPayloadExample = [\n {\n chain_id: 505050505,\n address: \"0xD946246695A9259F3B33a78629026F61B3Ab40aF\",\n name: \"mempool\",\n },\n {\n chain_id: 505050505,\n address: \"0x8A409D5D6394fC197c596d4E6E2c35e5d13f8a4d\",\n name: \"multicall\",\n },\n {\n chain_id: 505050505,\n address: \"0x23DFBc4B8B80C14CC5e25011B8491f268395BAd6\",\n name: \"v2\",\n },\n] as const;\n\nconst configRulesMaturityExample = {\n type: \"maturity\",\n chain_id: 1,\n name: \"end_of_next_month\",\n timestamp: 1730415600,\n} as const;\n\nconst configRulesLoanTokenExample = {\n type: \"loan_token\",\n chain_id: 1,\n address: \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\",\n} as const;\n\nconst configRulesCollateralTokenExample = {\n type: \"collateral_token\",\n chain_id: 1,\n address: \"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0\",\n} as const;\n\nconst configRulesOracleExample = {\n type: \"oracle\",\n chain_id: 1,\n address: \"0xDddd770BADd886dF3864029e4B377B5F6a2B6b83\",\n} as const;\n\nconst configRulesChecksumExample = \"f1d2d2f924e986ac86fdf7b36c94bcdf\" as const;\nconst configRulesPayloadExample = [\n configRulesMaturityExample,\n configRulesLoanTokenExample,\n configRulesCollateralTokenExample,\n configRulesOracleExample,\n] as const;\n\nconst configContractNames = [\"mempool\", \"multicall\", \"v2\"] as const;\nconst configContractsCursorExample = \"505050505:0xd946246695a9259f3b33a78629026f61b3ab40af\";\n\nclass ConfigContractResponse {\n @ApiProperty({ type: \"number\", example: configContractsExample.chain_id })\n declare chain_id: number;\n\n @ApiProperty({ type: \"string\", example: configContractsExample.address })\n declare address: Address;\n\n @ApiProperty({\n type: \"string\",\n enum: configContractNames,\n example: configContractsExample.name,\n })\n declare name: (typeof configContractNames)[number];\n}\n\nclass ConfigContractsSuccessResponse extends SuccessResponse {\n @ApiProperty({ type: \"string\", nullable: true, example: null })\n declare cursor: string | null;\n\n @ApiProperty({\n type: () => [ConfigContractResponse],\n description: \"Indexer contract configuration for all indexed chains.\",\n example: configContractsPayloadExample,\n })\n declare data: ConfigContractResponse[];\n}\n\nclass ConfigRulesMeta {\n @ApiProperty({ type: \"string\", example: timestampExample })\n declare timestamp: string;\n\n @ApiProperty({ type: \"string\", example: configRulesChecksumExample })\n declare checksum: string;\n}\n\nclass ConfigRulesRuleResponse {\n @ApiProperty({ type: \"string\", example: configRulesMaturityExample.type })\n declare type: string;\n\n @ApiProperty({ type: \"number\", example: configRulesMaturityExample.chain_id })\n declare chain_id: number;\n\n @ApiProperty({ type: \"string\", example: configRulesMaturityExample.name, required: false })\n declare name?: string;\n\n @ApiProperty({ type: \"number\", example: configRulesMaturityExample.timestamp, required: false })\n declare timestamp?: number;\n\n @ApiProperty({ type: \"string\", example: configRulesLoanTokenExample.address, required: false })\n declare address?: Address;\n}\n\nclass ConfigRulesSuccessResponse {\n @ApiProperty({ type: () => ConfigRulesMeta })\n declare meta: ConfigRulesMeta;\n\n @ApiProperty({ type: \"string\", nullable: true, example: null })\n declare cursor: string | null;\n\n @ApiProperty({\n type: () => [ConfigRulesRuleResponse],\n description: \"Configured rules returned by the router API.\",\n example: configRulesPayloadExample,\n })\n declare data: ConfigRulesRuleResponse[];\n}\n\n@ApiTags(\"System\")\nexport class ConfigContractsController {\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/config/contracts\",\n summary: \"Get indexer contract configuration\",\n description:\n \"Returns contract addresses used by indexers (mempool, v2) and multicall for indexed chains.\",\n })\n @ApiQuery({\n name: \"cursor\",\n type: \"string\",\n required: false,\n example: configContractsCursorExample,\n description: \"Pagination cursor in chain_id:address format (lowercase address).\",\n })\n @ApiQuery({\n name: \"limit\",\n type: \"number\",\n required: false,\n example: 1000,\n description: \"Maximum number of contracts to return (max 1000).\",\n })\n @ApiQuery({\n name: \"chains\",\n type: [\"number\"],\n required: false,\n example: \"1,8453\",\n description: \"Filter by chain IDs (comma-separated).\",\n style: \"form\",\n explode: false,\n })\n @ApiResponse({ status: 200, description: \"Success\", type: ConfigContractsSuccessResponse })\n async getConfigContracts() {}\n}\n\n@ApiTags(\"System\")\nexport class ConfigRulesController {\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/config/rules\",\n summary: \"Get config rules\",\n description:\n \"Returns configured rules (maturities, loan tokens, collateral tokens, oracles) for supported chains.\",\n })\n @ApiQuery({\n name: \"cursor\",\n type: \"string\",\n required: false,\n example: \"maturity:1:1730415600:end_of_next_month\",\n description: \"Pagination cursor in type:chain_id:<value> format.\",\n })\n @ApiQuery({\n name: \"limit\",\n type: \"number\",\n required: false,\n example: 100,\n description: \"Maximum number of rules to return (max 1000).\",\n })\n @ApiQuery({\n name: \"types\",\n type: [\"string\"],\n required: false,\n example: \"maturity,loan_token,collateral_token,oracle\",\n description: \"Filter by rule types (comma-separated).\",\n style: \"form\",\n explode: false,\n })\n @ApiQuery({\n name: \"chains\",\n type: [\"number\"],\n required: false,\n example: \"1,8453\",\n description: \"Filter by chain IDs (comma-separated).\",\n style: \"form\",\n explode: false,\n })\n @ApiResponse({ status: 200, description: \"Success\", type: ConfigRulesSuccessResponse })\n async getConfigRules() {}\n}\n\n@ApiTags(\"Markets\")\n@ApiResponse({ status: 400, description: \"Bad Request\", type: BadRequestResponse })\nexport class ObligationsController {\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/obligations\",\n summary: \"List all obligations\",\n description:\n \"Returns a list of obligations with their current best ask and bid. Sorting is customizable with the sort parameter and defaults to id ascending.\",\n })\n @ApiQuery({\n name: \"cursor\",\n type: \"string\",\n example: obligationCursorExample,\n description: \"Pagination cursor in base64url-encoded format.\",\n })\n @ApiQuery({\n name: \"limit\",\n type: \"number\",\n example: 10,\n description: \"Maximum number of obligations to return.\",\n })\n @ApiQuery({\n name: \"chains\",\n type: [\"number\"],\n required: false,\n example: \"1,8453\",\n description: \"Filter by chain IDs (comma-separated).\",\n style: \"form\",\n explode: false,\n })\n @ApiQuery({\n name: \"loan_tokens\",\n type: [\"string\"],\n required: false,\n example:\n \"0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078,0x34Cf890dB685FC536E05652FB41f02090c3fb751\",\n description: \"Filter by loan token addresses (comma-separated).\",\n style: \"form\",\n explode: false,\n })\n @ApiQuery({\n name: \"collateral_tokens\",\n type: [\"string\"],\n required: false,\n example:\n \"0x34Cf890dB685FC536E05652FB41f02090c3fb751,0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078\",\n description: \"Filter by collateral tokens (comma-separated, matches any collateral).\",\n style: \"form\",\n explode: false,\n })\n @ApiQuery({\n name: \"maturities\",\n type: [\"number\"],\n required: false,\n example: \"1761922800,1764524800\",\n description: \"Filter by exact maturity timestamps (comma-separated, unix seconds).\",\n style: \"form\",\n explode: false,\n })\n @ApiQuery({\n name: \"sort\",\n type: \"string\",\n required: false,\n example: \"-ask,bid,maturity\",\n description:\n \"Sort order as comma-separated fields (`id`, `ask`, `bid`, `maturity`). Prefix with `-` for descending order. Max 3 fields.\",\n style: \"form\",\n explode: false,\n })\n @ApiResponse({ status: 200, description: \"Success\", type: ObligationListResponse })\n async getObligations() {}\n\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/obligations/{obligationId}\",\n summary: \"Get an obligation\",\n description: \"Returns an obligation by its id.\",\n })\n @ApiParam({\n name: \"obligationId\",\n type: \"string\",\n example: \"0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67\",\n description: \"Obligation id.\",\n })\n @ApiResponse({ status: 200, description: \"Success\", type: ObligationSingleSuccessResponse })\n async getObligation() {}\n}\n\n@ApiTags(\"Make\")\n@ApiResponse({ status: 400, description: \"Bad Request\", type: BadRequestResponse })\nexport class UsersController {\n @ApiOperation({\n methods: [\"get\"],\n path: \"/v1/users/{userAddress}/positions\",\n summary: \"Get user positions\",\n description:\n \"Returns positions for a user with reserved balance per obligation. Each (position, obligation) pair is returned as a separate row. Positions with no lots return a single row with obligation_id = null and reserved = 0.\",\n })\n @ApiParam({\n name: \"userAddress\",\n type: \"string\",\n example: \"0x7b093658BE7f90B63D7c359e8f408e503c2D9401\",\n description: \"User address to get positions for.\",\n })\n @ApiQuery({\n name: \"cursor\",\n type: \"string\",\n example: offerCursorExample,\n description: \"Pagination cursor in base64url-encoded format.\",\n })\n @ApiQuery({\n name: \"limit\",\n type: \"number\",\n example: 10,\n description: \"Maximum number of positions to return.\",\n })\n @ApiResponse({ status: 200, description: \"Success\", type: PositionListResponse })\n async getUserPositions() {}\n}\n\nexport const OpenApi = async (): Promise<OpenAPIDocument> => {\n const document = await generateDocument({\n controllers: [\n BooksController,\n ConfigContractsController,\n ConfigRulesController,\n OffersController,\n ObligationsController,\n HealthController,\n UsersController,\n ValidateController,\n ],\n document: {\n openapi: \"3.1.0\",\n info: {\n title: \"Router API\",\n version: \"1.0.0\",\n description: \"API for the Morpho Router\",\n },\n servers: [\n {\n url: \"https://router.morpho.dev\",\n description: \"Production server\",\n },\n {\n url: \"http://localhost:7891\",\n description: \"Local development server\",\n },\n ],\n tags: [\n {\n name: \"Markets\",\n description:\n \"Read-only endpoints to discover markets, order books and fetch current offers.\",\n },\n {\n name: \"Make\",\n description: \"Utilities to ease making offers.\",\n },\n {\n name: \"System\",\n description: \"Router configuration and health monitoring.\",\n },\n ],\n },\n });\n\n return document;\n};\n","import type { Address } from \"viem\";\nimport type { Chain } from \"#core\";\nimport type { getByUser } from \"#database/domains/Positions.ts\";\n\nexport type PositionResponse = {\n chain_id: Chain.Id;\n contract: Address;\n user: Address;\n obligation_id: string | null;\n reserved: string;\n block_number: number;\n};\n\nexport type PositionWithReserved = getByUser.PositionWithReserved;\n\n/**\n * Creates a `PositionResponse` from a `PositionWithReserved`.\n * @param position - {@link PositionWithReserved}\n * @returns The created `PositionResponse`. {@link PositionResponse}\n */\nexport function from(position: PositionWithReserved): PositionResponse {\n return {\n chain_id: position.chainId,\n contract: position.contract,\n user: position.user,\n obligation_id: position.obligationId,\n reserved: position.reserved.toString(),\n block_number: position.blockNumber,\n };\n}\n","import type { Address, Hex } from \"viem\";\nimport * as z from \"zod\";\n\nconst MAX_LIMIT = 100;\nconst DEFAULT_LIMIT = 20;\nconst MAX_OBLIGATION_SORT_FIELDS = 3;\nconst CONFIG_RULES_MAX_LIMIT = 1000;\nconst CONFIG_RULES_DEFAULT_LIMIT = 100;\nconst CONFIG_CONTRACTS_MAX_LIMIT = 1000;\nconst CONFIG_CONTRACTS_DEFAULT_LIMIT = 1000;\nconst OBLIGATION_SORT_ENTRY_REGEX = /^-?(id|ask|bid|maturity)$/;\n\n/** Validate cursor is a valid base64url-encoded JSON object.\n * Domain layer handles semantic validation of cursor fields. */\nfunction isValidBase64urlJson(val: string): boolean {\n try {\n const decoded = Buffer.from(val, \"base64url\").toString(\"utf8\");\n JSON.parse(decoded);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isValidOfferHashCursor(val: string): boolean {\n return /^0x[a-f0-9]{64}$/i.test(val);\n}\n\nconst csvArray = <T extends z.ZodTypeAny>(schema: T) =>\n z\n .preprocess((value) => {\n if (value === undefined) return undefined;\n if (Array.isArray(value)) {\n if (value.some((item) => typeof item !== \"string\")) return value;\n return value\n .flatMap((item) => item.split(\",\"))\n .map((item) => item.trim())\n .filter((item) => item.length > 0);\n }\n if (typeof value === \"string\") {\n return value\n .split(\",\")\n .map((item) => item.trim())\n .filter((item) => item.length > 0);\n }\n return value;\n }, z.array(schema))\n .optional();\n\nconst PaginationQueryParams = z.object({\n cursor: z\n .string()\n .optional()\n .refine(\n (val) => {\n if (!val) return true; // Optional field\n // Accept any valid base64url-encoded JSON object\n // Domain layer handles semantic validation of cursor fields\n return isValidBase64urlJson(val);\n },\n {\n message: \"Invalid cursor format. Must be a valid base64url-encoded cursor object\",\n },\n )\n .meta({\n description: \"Pagination cursor in base64url-encoded format\",\n example:\n \"eyJzaWRlIjoic2VsbCIsImN1cnJlbnRQcmljZSI6IjEwMDAwMDAwMDAwMDAwMDAwMDAiLCJibG9ja051bWJlciI6MSwiYXNzZXRzIjoiMTAwMDAwMDAwMDAwMDAwMDAwMCIsImhhc2giOiIweGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIiLCJ0b3RhbFJldHVybmVkIjoxMCwibm93IjoxNjAwMDAwMDAwfQ\",\n }),\n limit: z\n .string()\n .regex(/^[1-9]\\d*$/, {\n message: \"Limit must be a positive integer\",\n })\n .transform((val) => Number.parseInt(val, 10))\n .pipe(\n z.number().max(MAX_LIMIT, {\n message: `Limit cannot exceed ${MAX_LIMIT}`,\n }),\n )\n .optional()\n .default(DEFAULT_LIMIT)\n .meta({\n description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT}`,\n example: 10,\n }),\n});\n\nconst ConfigRuleTypes = z.enum([\n \"maturity\",\n \"callback\",\n \"loan_token\",\n \"collateral_token\",\n \"oracle\",\n]);\n\nexport const GetConfigRulesQueryParams = z.object({\n cursor: z\n .string()\n .regex(/^(maturity|callback|loan_token|collateral_token|oracle):[1-9]\\d*:.+$/, {\n message: \"Cursor must be in the format type:chain_id:<value>\",\n })\n .optional()\n .meta({\n description: \"Pagination cursor in type:chain_id:<value> format\",\n example: \"maturity:1:1730415600:end_of_next_month\",\n }),\n limit: z\n .string()\n .regex(/^[1-9]\\d*$/, {\n message: \"Limit must be a positive integer\",\n })\n .transform((val) => Number.parseInt(val, 10))\n .pipe(\n z.number().max(CONFIG_RULES_MAX_LIMIT, {\n message: `Limit cannot exceed ${CONFIG_RULES_MAX_LIMIT}`,\n }),\n )\n .optional()\n .default(CONFIG_RULES_DEFAULT_LIMIT)\n .meta({\n description: `Limit maximum: ${CONFIG_RULES_MAX_LIMIT}. Default: ${CONFIG_RULES_DEFAULT_LIMIT}`,\n example: 100,\n }),\n types: csvArray(ConfigRuleTypes).meta({\n description: \"Filter by rule types (comma-separated).\",\n example: \"maturity,loan_token,collateral_token,oracle\",\n }),\n chains: csvArray(\n z\n .string()\n .regex(/^[1-9]\\d*$/, { message: \"Chain must be a positive integer\" })\n .transform((val) => Number.parseInt(val, 10)),\n ).meta({\n description: \"Filter by chain IDs (comma-separated).\",\n example: \"1,8453\",\n }),\n});\n\nexport const GetConfigContractsQueryParams = z.object({\n cursor: z\n .string()\n .regex(/^[1-9]\\d*:0x[a-fA-F0-9]{40}$/, {\n message: \"Cursor must be in the format chain_id:0x...\",\n })\n .optional()\n .meta({\n description: \"Pagination cursor in chain_id:address format (lowercase address).\",\n example: \"1:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48\",\n }),\n limit: z\n .string()\n .regex(/^[1-9]\\d*$/, {\n message: \"Limit must be a positive integer\",\n })\n .transform((val) => Number.parseInt(val, 10))\n .pipe(\n z.number().max(CONFIG_CONTRACTS_MAX_LIMIT, {\n message: `Limit cannot exceed ${CONFIG_CONTRACTS_MAX_LIMIT}`,\n }),\n )\n .optional()\n .default(CONFIG_CONTRACTS_DEFAULT_LIMIT)\n .meta({\n description: `Limit maximum: ${CONFIG_CONTRACTS_MAX_LIMIT}. Default: ${CONFIG_CONTRACTS_DEFAULT_LIMIT}`,\n example: 1000,\n }),\n chains: csvArray(\n z\n .string()\n .regex(/^[1-9]\\d*$/, { message: \"Chain must be a positive integer\" })\n .transform((val) => Number.parseInt(val, 10)),\n ).meta({\n description: \"Filter by chain IDs (comma-separated).\",\n example: \"1,8453\",\n }),\n});\n\nexport const GetOffersQueryParams = PaginationQueryParams.omit({ cursor: true })\n .extend({\n cursor: z.string().optional().meta({\n description:\n \"Pagination cursor. Use offer hash (0x...) for maker queries, base64url for obligation queries.\",\n example:\n \"eyJzaWRlIjoic2VsbCIsImN1cnJlbnRQcmljZSI6IjEwMDAwMDAwMDAwMDAwMDAwMDAiLCJibG9ja051bWJlciI6MSwiYXNzZXRzIjoiMTAwMDAwMDAwMDAwMDAwMDAwMCIsImhhc2giOiIweGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIiLCJ0b3RhbFJldHVybmVkIjoxMCwibm93IjoxNjAwMDAwMDAwfQ\",\n }),\n side: z.enum([\"buy\", \"sell\"]).optional().meta({\n description: \"Side of the offer. Required when using obligation_id.\",\n example: \"buy\",\n }),\n obligation_id: z\n .string()\n .regex(/^0x[a-fA-F0-9]{64}$/, { error: \"Obligation id must be a valid 32-byte hex string\" })\n .transform<Hex>((val) => val.toLowerCase() as Hex)\n .optional()\n .meta({\n description: \"Offers obligation id. Required when not using maker.\",\n example: \"0x1234567890123456789012345678901234567890123456789012345678901234\",\n }),\n maker: z\n .string()\n .regex(/^0x[a-fA-F0-9]{40}$/, { error: \"Maker must be a valid 20-byte address\" })\n .transform<Address>((val) => val.toLowerCase() as Address)\n .optional()\n .meta({\n description: \"Maker address to filter offers by. Alternative to obligation_id + side.\",\n example: \"0x7b093658BE7f90B63D7c359e8f408e503c2D9401\",\n }),\n })\n .superRefine((val, ctx) => {\n const hasObligation = val.obligation_id !== undefined;\n const hasSide = val.side !== undefined;\n const hasMaker = val.maker !== undefined;\n\n if (hasMaker && (hasObligation || hasSide)) {\n ctx.addIssue({\n code: \"custom\",\n message: \"Cannot use both maker and obligation_id/side parameters\",\n });\n return;\n }\n\n if (hasMaker) {\n if (val.cursor !== undefined && !isValidOfferHashCursor(val.cursor)) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"cursor\"],\n message: \"Cursor must be a 32-byte hex offer hash when filtering by maker\",\n });\n }\n return;\n }\n\n if (!hasObligation || !hasSide) {\n ctx.addIssue({\n code: \"custom\",\n message: \"Must provide either maker or both obligation_id and side\",\n });\n }\n\n if (val.cursor !== undefined && !isValidBase64urlJson(val.cursor)) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"cursor\"],\n message: \"Invalid cursor format. Must be a valid base64url-encoded cursor object\",\n });\n }\n })\n .transform((val) => {\n if (val.maker && val.cursor) {\n return {\n ...val,\n cursor: val.cursor.toLowerCase(),\n };\n }\n return val;\n });\n\nexport const GetObligationsQueryParams = z.object({\n ...PaginationQueryParams.shape,\n cursor: z\n .string()\n .optional()\n .refine(\n (val) => {\n if (!val) return true;\n return isValidBase64urlJson(val);\n },\n {\n message: \"Invalid cursor format. Must be a valid base64url-encoded cursor object\",\n },\n )\n .meta({\n description: \"Pagination cursor in base64url-encoded format.\",\n example:\n \"eyJzb3J0IjpbImlkIl0sImlkIjoiMHgxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAiLCJhc2siOiIwIiwiYmlkIjoiMCIsIm1hdHVyaXR5IjoxNzYxOTIyODAwfQ\",\n }),\n chains: csvArray(\n z\n .string()\n .regex(/^[1-9]\\d*$/, { message: \"Chain must be a positive integer\" })\n .transform((val) => Number.parseInt(val, 10)),\n ).meta({\n description: \"Filter by chain IDs (comma-separated).\",\n example: \"1,8453\",\n }),\n loan_tokens: csvArray(\n z\n .string()\n .regex(/^0x[a-fA-F0-9]{40}$/, { error: \"Loan token must be a valid 20-byte address\" })\n .transform<Address>((val) => val.toLowerCase() as Address),\n ).meta({\n description: \"Filter by loan token addresses (comma-separated).\",\n example:\n \"0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078,0x34Cf890dB685FC536E05652FB41f02090c3fb751\",\n }),\n collateral_tokens: csvArray(\n z\n .string()\n .regex(/^0x[a-fA-F0-9]{40}$/, { error: \"Collateral token must be a valid 20-byte address\" })\n .transform<Address>((val) => val.toLowerCase() as Address),\n ).meta({\n description: \"Filter by collateral tokens (comma-separated, matches any collateral).\",\n example:\n \"0x34Cf890dB685FC536E05652FB41f02090c3fb751,0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078\",\n }),\n maturities: csvArray(\n z\n .string()\n .regex(/^[1-9]\\d*$/, { message: \"Maturity must be a positive integer\" })\n .transform((val) => Number.parseInt(val, 10)),\n ).meta({\n description: \"Filter by exact maturity timestamps (comma-separated, unix seconds).\",\n example: \"1761922800,1764524800\",\n }),\n sort: csvArray(\n z.string().regex(OBLIGATION_SORT_ENTRY_REGEX, {\n message: \"Sort entries must be one of: id, ask, bid, maturity (optionally prefixed with '-')\",\n }),\n )\n .refine((entries) => entries === undefined || entries.length <= MAX_OBLIGATION_SORT_FIELDS, {\n message: `Sort cannot include more than ${MAX_OBLIGATION_SORT_FIELDS} fields`,\n })\n .superRefine((entries, ctx) => {\n if (!entries) return;\n const seen = new Set<string>();\n for (const entry of entries) {\n const field = entry.startsWith(\"-\") ? entry.slice(1) : entry;\n if (seen.has(field)) {\n ctx.addIssue({\n code: \"custom\",\n message: `Duplicate sort field: ${field}`,\n });\n return;\n }\n seen.add(field);\n }\n })\n .meta({\n description:\n \"Sort order as comma-separated fields. Prefix a field with '-' for descending order. Max 3 fields.\",\n example: \"-ask,bid,maturity\",\n }),\n});\n\nexport const GetObligationParams = z.object({\n obligation_id: z\n .string({ error: \"Obligation id is required and must be a valid 32-byte hex string\" })\n .regex(/^0x[a-fA-F0-9]{64}$/, { error: \"Obligation id must be a valid 32-byte hex string\" })\n .transform<Hex>((val) => val.toLowerCase() as Hex)\n .meta({\n description: \"Obligation id\",\n example: \"0x1234567890123456789012345678901234567890123456789012345678901234\",\n }),\n});\n\n/** Validate a book cursor format: {side, lastTick, offersCursor} */\nfunction isValidBookCursor(cursorString: string): boolean {\n try {\n const v = JSON.parse(Buffer.from(cursorString, \"base64url\").toString(\"utf8\"));\n return (\n (v?.side === \"buy\" || v?.side === \"sell\") &&\n typeof v?.lastTick === \"number\" &&\n Number.isInteger(v.lastTick) &&\n (v?.offersCursor === null || typeof v?.offersCursor === \"string\")\n );\n } catch {\n return false;\n }\n}\n\nconst BookPaginationQueryParams = z.object({\n cursor: z\n .string()\n .optional()\n .refine(\n (value) => {\n if (!value) return true; // Optional field\n return isValidBookCursor(value);\n },\n {\n message: \"Invalid cursor format. Must be a valid base64url-encoded book cursor object\",\n },\n )\n .meta({\n description: \"Pagination cursor in base64url-encoded format for book levels\",\n example:\n \"eyJzaWRlIjoiYnV5IiwibGFzdFJhdGUiOiIxMDAwMDAwMDAwMDAwMDAwMDAwIiwib2ZmZXJzQ3Vyc29yIjpudWxsfQ\",\n }),\n limit: z\n .string()\n .regex(/^[1-9]\\d*$/, {\n message: \"Limit must be a positive integer\",\n })\n .transform((val) => Number.parseInt(val, 10))\n .pipe(\n z.number().max(MAX_LIMIT, {\n message: `Limit cannot exceed ${MAX_LIMIT}`,\n }),\n )\n .optional()\n .default(DEFAULT_LIMIT)\n .meta({\n description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT}`,\n example: 10,\n }),\n});\n\nconst HealthQueryParams = z.object({\n strict: z\n .enum([\"true\", \"false\", \"1\", \"0\"])\n .transform((value) => value === \"true\" || value === \"1\")\n .optional()\n .meta({\n description: \"Enable strict mode to fail health checks when initialization is incomplete.\",\n example: \"true\",\n }),\n});\n\nexport const GetBookParams = z.object({\n ...BookPaginationQueryParams.shape,\n obligation_id: z\n .string({ error: \"Obligation id is required and must be a valid 32-byte hex string\" })\n .regex(/^0x[a-fA-F0-9]{64}$/, { error: \"Obligation id must be a valid 32-byte hex string\" })\n .transform<Hex>((val) => val.toLowerCase() as Hex)\n .meta({\n description: \"Obligation id\",\n example: \"0x1234567890123456789012345678901234567890123456789012345678901234\",\n }),\n side: z.enum([\"buy\", \"sell\"]).meta({\n description: \"Side of the book (buy or sell).\",\n example: \"buy\",\n }),\n});\n\nconst ValidateOffersBody = z\n .object({\n offers: z.array(z.unknown()).min(1, { message: \"'offers' must contain at least 1 offer\" }),\n })\n .strict();\n\nexport const GetUserPositionsParams = z.object({\n ...PaginationQueryParams.shape,\n user_address: z\n .string()\n .regex(/^0x[a-fA-F0-9]{40}$/, { error: \"User address must be a valid 20-byte address\" })\n .transform<Address>((val) => val.toLowerCase() as Address)\n .meta({\n description: \"User address to get positions for\",\n example: \"0x7b093658BE7f90B63D7c359e8f408e503c2D9401\",\n }),\n});\n\nconst schemas = {\n get_health: HealthQueryParams,\n get_health_collectors: HealthQueryParams,\n get_health_chains: HealthQueryParams,\n get_config_contracts: GetConfigContractsQueryParams,\n get_config_rules: GetConfigRulesQueryParams,\n get_offers: GetOffersQueryParams,\n get_obligations: GetObligationsQueryParams,\n get_obligation: GetObligationParams,\n get_book: GetBookParams,\n validate_offers: ValidateOffersBody,\n get_user_positions: GetUserPositionsParams,\n} as const;\n\ntype Action = keyof typeof schemas;\n\nexport function parse<A extends Action>(action: A, query: unknown): z.infer<(typeof schemas)[A]> {\n return schemas[action].parse(query) as z.infer<(typeof schemas)[A]>;\n}\n\nexport function safeParse<A extends Action>(\n action: A,\n query: unknown,\n error?: z.core.$ZodErrorMap<z.core.$ZodIssue>,\n): z.ZodSafeParseResult<z.infer<(typeof schemas)[A]>> {\n return schemas[action].safeParse(query, {\n error,\n }) as z.ZodSafeParseResult<z.infer<(typeof schemas)[A]>>;\n}\n","import type { Database } from \"#database/index.ts\";\nimport { Logger } from \"#logger/index.ts\";\nimport * as ApiSchema from \"../Schema/index.ts\";\nimport * as ApiPayload from \"./Payload.ts\";\n\nexport async function getBook(\n params: object,\n db: Database.Database,\n): Promise<ApiPayload.Payload<ApiSchema.BookResponse.BookLevelResponse[]>> {\n const logger = Logger.getLogger();\n const result = ApiSchema.safeParse(\"get_book\", params, (issue) => issue.message);\n\n if (!result.success) return ApiPayload.failure(result.error);\n const query = result.data;\n\n try {\n logger.debug({\n service: \"api_controller\",\n endpoint: \"get_book\",\n msg: \"Loading book levels\",\n obligation_id: query.obligation_id,\n side: query.side,\n limit: query.limit ?? null,\n has_cursor: query.cursor != null,\n });\n\n const { levels, nextCursor } = await db.book.get({\n side: query.side,\n obligationId: query.obligation_id,\n cursor: query.cursor,\n limit: query.limit,\n });\n\n const firstLevel = levels[0];\n logger.debug({\n service: \"api_controller\",\n endpoint: \"get_book\",\n msg: \"Loaded book levels\",\n obligation_id: query.obligation_id,\n side: query.side,\n levels_count: levels.length,\n has_next_cursor: nextCursor != null,\n first_level_tick: firstLevel?.tick ?? null,\n first_level_assets: firstLevel?.assets.toString() ?? null,\n first_level_count: firstLevel?.count ?? null,\n });\n\n return ApiPayload.success({\n data: levels.map(ApiSchema.BookResponse.from),\n cursor: nextCursor,\n });\n } catch (err) {\n logger.error({\n err,\n msg: \"Error get book\",\n errorMessage: err instanceof Error ? err.message : String(err),\n errorStack: err instanceof Error ? err.stack : undefined,\n });\n return ApiPayload.failure(err);\n }\n}\n","import type { Address } from \"viem\";\nimport type * as Chain from \"#core/Chain.ts\";\nimport type * as ChainRegistry from \"#core/ChainRegistry.ts\";\nimport * as ApiSchema from \"../Schema/index.ts\";\nimport * as ApiPayload from \"./Payload.ts\";\n\nexport const CONFIG_CONTRACT_NAMES = [\"mempool\", \"multicall\", \"v2\"] as const;\nexport type ConfigContractName = (typeof CONFIG_CONTRACT_NAMES)[number];\n\nexport type ConfigContract = {\n chain_id: Chain.Id;\n address: Address;\n name: ConfigContractName;\n};\n\ntype Cursor = {\n chain_id: Chain.Id;\n address: Address;\n};\n\n/**\n * Returns contract addresses used by indexers (mempool, v2) plus multicall per chain.\n * @param query - Raw query parameters containing optional chain filters.\n * @param chainRegistry - The chain registry instance. {@link ChainRegistry.ChainRegistry}\n * @returns The indexer contract configuration. {@link ApiPayload.Payload<ConfigContract[]>}\n */\nexport async function getConfigContracts(\n query: unknown,\n chainRegistry: ChainRegistry.ChainRegistry,\n): Promise<ApiPayload.Payload<ConfigContract[]>> {\n const parsed = ApiSchema.safeParse(\"get_config_contracts\", query ?? {});\n if (!parsed.success) {\n return ApiPayload.failure(parsed.error);\n }\n\n const { chains: chainsFilter, cursor, limit } = parsed.data;\n const chainFilter = chainsFilter?.length ? new Set(chainsFilter) : null;\n const contracts: ConfigContract[] = [];\n const seenAddresses = new Set<string>();\n\n for (const chain of chainRegistry.list()) {\n if (chainFilter && !chainFilter.has(chain.id)) continue;\n\n const mempool = chain.custom?.mempool?.address;\n if (!mempool) {\n return ApiPayload.failure(\n new ApiPayload.InternalServerError(`Missing mempool address for chain ${chain.id}.`),\n );\n }\n\n const multicall = chain.contracts?.multicall3?.address;\n if (!multicall) {\n return ApiPayload.failure(\n new ApiPayload.InternalServerError(`Missing multicall3 address for chain ${chain.id}.`),\n );\n }\n\n const v2 = chain.custom?.morpho?.address;\n if (!v2) {\n return ApiPayload.failure(\n new ApiPayload.InternalServerError(`Missing morpho address for chain ${chain.id}.`),\n );\n }\n\n const chainContracts: ConfigContract[] = [\n { chain_id: chain.id, name: \"mempool\", address: mempool },\n { chain_id: chain.id, name: \"multicall\", address: multicall },\n { chain_id: chain.id, name: \"v2\", address: v2 },\n ];\n\n for (const contract of chainContracts) {\n const cursorKey = `${contract.chain_id}:${contract.address.toLowerCase()}`;\n if (seenAddresses.has(cursorKey)) {\n return ApiPayload.failure(\n new ApiPayload.InternalServerError(\n `Duplicate contract address ${contract.address} for chain ${chain.id}.`,\n ),\n );\n }\n seenAddresses.add(cursorKey);\n contracts.push(contract);\n }\n }\n\n contracts.sort((a, b) => {\n if (a.chain_id !== b.chain_id) return a.chain_id - b.chain_id;\n const addressCompare = a.address.toLowerCase().localeCompare(b.address.toLowerCase());\n if (addressCompare !== 0) return addressCompare;\n return a.name.localeCompare(b.name);\n });\n\n let cursorContract: Cursor | null = null;\n if (cursor) {\n try {\n cursorContract = parseCursor(cursor);\n } catch (err) {\n return ApiPayload.failure(err);\n }\n }\n\n const startIndex = cursorContract ? findStartIndex(contracts, cursorContract) : 0;\n const page = contracts.slice(startIndex, startIndex + limit);\n const nextCursor =\n startIndex + limit < contracts.length && page.length > 0 ? formatCursor(page.at(-1)!) : null;\n\n return ApiPayload.success({ data: page, cursor: nextCursor });\n}\n\nfunction parseCursor(cursor: string): Cursor {\n const [chain, address] = cursor.split(\":\", 2);\n if (!chain || !address) {\n throw new ApiPayload.BadRequestError(\"Cursor must be in the format chain_id:0x...\");\n }\n const chain_id = Number.parseInt(chain, 10) as Chain.Id;\n return {\n chain_id,\n address: address.toLowerCase() as Address,\n };\n}\n\nfunction formatCursor(contract: ConfigContract): string {\n return `${contract.chain_id}:${contract.address.toLowerCase()}`;\n}\n\nfunction findStartIndex(contracts: ConfigContract[], cursor: Cursor): number {\n let low = 0;\n let high = contracts.length;\n while (low < high) {\n const mid = Math.floor((low + high) / 2);\n const current = contracts[mid]!;\n const cmp = compareContract(current, cursor);\n if (cmp <= 0) {\n low = mid + 1;\n } else {\n high = mid;\n }\n }\n return low;\n}\n\nfunction compareContract(contract: ConfigContract, cursor: Cursor): number {\n if (contract.chain_id !== cursor.chain_id) return contract.chain_id - cursor.chain_id;\n return contract.address.toLowerCase().localeCompare(cursor.address.toLowerCase());\n}\n","import type { Address } from \"viem\";\nimport * as Callback from \"../core/Callback.ts\";\nimport * as Chain from \"../core/Chain.ts\";\nimport * as Maturity from \"../core/Maturity.ts\";\n\nexport type GateConfig = {\n callbacks?: CallbackConfig[];\n maturities?: Maturity.MaturityType[];\n};\n\nexport type CallbackConfig =\n | {\n type: Callback.Type.BuyWithEmptyCallback;\n }\n | {\n type: Callback.Type.SellWithEmptyCallback;\n };\n\n/**\n * Returns the callback configuration for a given chain and callback type, if it exists.\n *\n * @param chain - Chain name for which to read the validation configuration\n * @param type - Callback type to retrieve\n * @returns The matching callback configuration or undefined if not configured\n */\nexport function getCallback(chain: Chain.Name, type: Callback.Type): CallbackConfig | undefined {\n return configs[chain].callbacks?.find((c) => c.type === type);\n}\n\n/**\n * Returns the list of allowed non-empty callback addresses for a chain.\n *\n * @param chain - Chain name\n * @returns Empty array (no non-empty callbacks supported)\n */\nexport const getCallbackAddresses = (_chain: Chain.Name): Address[] => {\n return [];\n};\n\nexport const assets: Record<string, Address[]> = {\n [Chain.ChainId.ETHEREUM.toString()]: [\n \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\", // USDC\n \"0x6B175474E89094C44Da98b954EedeAC495271d0F\", // DAI\n \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\", // WETH\n \"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599\", // WBTC\n \"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c\", // EURC\n \"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0\", // wstETH\n ],\n [Chain.ChainId.BASE.toString()]: [\n \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\", // USDC\n \"0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb\", // DAI\n \"0x4200000000000000000000000000000000000006\", // WETH\n \"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599\", // WBTC\n \"0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf\", // cbBTC\n \"0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452\", // wstETH\n \"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42\", // EURC\n ],\n [Chain.ChainId[\"ETHEREUM-VIRTUAL-TESTNET\"].toString()]: [\n \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\", // USDC\n \"0x6B175474E89094C44Da98b954EedeAC495271d0F\", // DAI\n \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\", // WETH\n \"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599\", // WBTC\n \"0xce79ddb3152d52ff8fe65a4c7e058b035fcb560a\", // test token\n ],\n [Chain.ChainId.ANVIL.toString()]: [\n \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\", // USDC\n \"0x6B175474E89094C44Da98b954EedeAC495271d0F\", // DAI\n \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\", // WETH\n \"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599\", // WBTC\n ],\n};\n\nexport const collateralAssets: Partial<Record<string, Address[]>> = {\n [Chain.ChainId.ETHEREUM.toString()]: [\n \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\", // USDC\n \"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c\", // EURC\n \"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599\", // WBTC\n \"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0\", // wstETH\n ],\n [Chain.ChainId.BASE.toString()]: [\n \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\", // USDC\n \"0x4200000000000000000000000000000000000006\", // WETH\n \"0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf\", // cbBTC\n \"0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452\", // wstETH\n \"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42\", // EURC\n ],\n [Chain.ChainId[\"ETHEREUM-VIRTUAL-TESTNET\"].toString()]: [\n \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\", // USDC\n \"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c\", // EURC\n \"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599\", // WBTC\n \"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0\", // wstETH\n ],\n [Chain.ChainId.ANVIL.toString()]: [\n \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\", // USDC\n \"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c\", // EURC\n \"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599\", // WBTC\n \"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0\", // wstETH\n ],\n};\n\nexport const oracles: Record<string, Address[]> = {\n [Chain.ChainId.ETHEREUM.toString()]: [\n \"0xDddd770BADd886dF3864029e4B377B5F6a2B6b83\",\n \"0x9CB3f4276bcD149b3668e1a645a964bC12877b89\",\n \"0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2\",\n \"0x6Eb9F4128CeBc8B885A4d8562Db1Addf097f7348\",\n \"0xbD60A6770b27E084E8617335ddE769241B0e71D8\",\n \"0xAe12416c1F21B0698c27fe042D9309C83baC6597\",\n ],\n [Chain.ChainId.BASE.toString()]: [\n \"0xD09048c8B568Dbf5f189302beA26c9edABFC4858\",\n \"0xFEa2D58cEfCb9fcb597723c6bAE66fFE4193aFE4\",\n \"0x05D2618404668D725B66c0f32B39e4EC15B393dC\",\n \"0xE1bb8E5b4930eC9FeC7f7943FCF6227649F14B37\",\n \"0x663BECd10daE6C4A3Dcd89F1d76c1174199639B9\",\n \"0x10b95702a0ce895972C91e432C4f7E19811D320E\",\n \"0x8C87DbD7A0c647A4291592Bc2994dbF95880fE2F\",\n \"0x4A11590e5326138B514E08A9B52202D42077Ca65\",\n \"0xa54122f0E0766258377Ffe732e454A3248f454F4\",\n ],\n [Chain.ChainId[\"ETHEREUM-VIRTUAL-TESTNET\"].toString()]: [\n \"0xDddd770BADd886dF3864029e4B377B5F6a2B6b83\",\n \"0x9CB3f4276bcD149b3668e1a645a964bC12877b89\",\n \"0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2\",\n \"0x6Eb9F4128CeBc8B885A4d8562Db1Addf097f7348\",\n \"0xbD60A6770b27E084E8617335ddE769241B0e71D8\",\n \"0xAe12416c1F21B0698c27fe042D9309C83baC6597\",\n ],\n [Chain.ChainId.ANVIL.toString()]: [\n \"0xDddd770BADd886dF3864029e4B377B5F6a2B6b83\",\n \"0x9CB3f4276bcD149b3668e1a645a964bC12877b89\",\n \"0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2\",\n \"0x6Eb9F4128CeBc8B885A4d8562Db1Addf097f7348\",\n \"0xbD60A6770b27E084E8617335ddE769241B0e71D8\",\n \"0xAe12416c1F21B0698c27fe042D9309C83baC6597\",\n ],\n};\n\nexport const configs: Record<Chain.Name, GateConfig> = {\n ethereum: {\n callbacks: [\n { type: Callback.Type.BuyWithEmptyCallback },\n { type: Callback.Type.SellWithEmptyCallback },\n ],\n maturities: [Maturity.MaturityType.EndOfWeek, Maturity.MaturityType.EndOfNextWeek],\n },\n base: {\n callbacks: [\n { type: Callback.Type.BuyWithEmptyCallback },\n { type: Callback.Type.SellWithEmptyCallback },\n ],\n maturities: [Maturity.MaturityType.EndOfWeek, Maturity.MaturityType.EndOfNextWeek],\n },\n \"ethereum-virtual-testnet\": {\n callbacks: [\n { type: Callback.Type.BuyWithEmptyCallback },\n { type: Callback.Type.SellWithEmptyCallback },\n ],\n maturities: [Maturity.MaturityType.EndOfWeek, Maturity.MaturityType.EndOfNextWeek],\n },\n anvil: {\n callbacks: [\n { type: Callback.Type.BuyWithEmptyCallback },\n { type: Callback.Type.SellWithEmptyCallback },\n ],\n maturities: [Maturity.MaturityType.EndOfWeek, Maturity.MaturityType.EndOfNextWeek],\n },\n};\n","import { createHash } from \"node:crypto\";\nimport type { Address } from \"viem\";\nimport type * as Chain from \"#core/Chain.ts\";\nimport * as Maturity from \"#core/Maturity.ts\";\nimport * as GateConfig from \"./GateConfig.ts\";\nimport type { ConfigRule } from \"./types.ts\";\n\n/**\n * Build the configured rules (maturities + callback addresses + loan tokens + collateral tokens + oracles) for the provided chains.\n * @param chains - Chains to include in the configured rules.\n * @returns Sorted list of config rules.\n */\nexport function buildConfigRules(chains: Chain.Chain[]): ConfigRule[] {\n const rules: ConfigRule[] = [];\n\n for (const chain of chains) {\n const config = GateConfig.configs[chain.name];\n\n const maturities = config.maturities ?? [];\n for (const maturityName of maturities) {\n rules.push({\n type: \"maturity\",\n chain_id: chain.id,\n name: maturityName,\n timestamp: Maturity.from(maturityName),\n });\n }\n\n const loanTokens = GateConfig.assets[chain.id.toString()] ?? [];\n for (const address of loanTokens) {\n rules.push({\n type: \"loan_token\",\n chain_id: chain.id,\n address: normalizeAddress(address),\n });\n }\n\n const collateralTokens = GateConfig.collateralAssets[chain.id.toString()] ?? [];\n for (const address of collateralTokens) {\n rules.push({\n type: \"collateral_token\",\n chain_id: chain.id,\n address: normalizeAddress(address),\n });\n }\n\n const oracles = GateConfig.oracles[chain.id.toString()] ?? [];\n for (const address of oracles) {\n rules.push({\n type: \"oracle\",\n chain_id: chain.id,\n address: normalizeAddress(address),\n });\n }\n }\n\n rules.sort(compareConfigRules);\n return rules;\n}\n\n/**\n * Compute a stable checksum for the provided configured rules.\n * @param rules - Configured rules to checksum.\n * @returns MD5 checksum.\n */\nexport function buildConfigRulesChecksum(rules: ConfigRule[]): string {\n const hash = createHash(\"md5\");\n const orderedRules = [...rules].sort(compareConfigRules);\n\n for (const rule of orderedRules) {\n if (rule.type === \"maturity\") {\n hash.update(`maturity:${rule.chain_id}:${rule.name}:${rule.timestamp}\\n`);\n continue;\n }\n if (rule.type === \"callback\") {\n hash.update(`callback:${rule.chain_id}:${rule.callback_type}:${rule.address}\\n`);\n continue;\n }\n if (rule.type === \"collateral_token\") {\n hash.update(`collateral_token:${rule.chain_id}:${rule.address}\\n`);\n continue;\n }\n if (rule.type === \"oracle\") {\n hash.update(`oracle:${rule.chain_id}:${rule.address}\\n`);\n continue;\n }\n hash.update(`loan_token:${rule.chain_id}:${rule.address}\\n`);\n }\n\n return hash.digest(\"hex\");\n}\n\nfunction normalizeAddress(address: Address): Address {\n return address.toLowerCase() as Address;\n}\n\nexport function compareConfigRules(left: ConfigRule, right: ConfigRule): number {\n if (left.chain_id !== right.chain_id) return left.chain_id - right.chain_id;\n\n if (left.type !== right.type) return left.type.localeCompare(right.type);\n\n if (left.type === \"maturity\" && right.type === \"maturity\") {\n return left.timestamp - right.timestamp;\n }\n\n if (left.type === \"callback\" && right.type === \"callback\") {\n if (left.callback_type !== right.callback_type) {\n const leftType: string = left.callback_type;\n return leftType.localeCompare(right.callback_type);\n }\n return left.address.localeCompare(right.address);\n }\n\n if (left.type === \"loan_token\" && right.type === \"loan_token\") {\n return left.address.localeCompare(right.address);\n }\n\n if (left.type === \"collateral_token\" && right.type === \"collateral_token\") {\n return left.address.localeCompare(right.address);\n }\n\n if (left.type === \"oracle\" && right.type === \"oracle\") {\n return left.address.localeCompare(right.address);\n }\n\n return 0;\n}\n","import type { Address } from \"viem\";\nimport * as Callback from \"#core/Callback.ts\";\nimport type * as Chain from \"#core/Chain.ts\";\nimport * as Maturity from \"#core/Maturity.ts\";\nimport {\n buildConfigRules,\n buildConfigRulesChecksum,\n compareConfigRules,\n} from \"#gatekeeper/ConfigRules.ts\";\nimport type { ConfigRule } from \"#gatekeeper/types.ts\";\nimport * as ApiSchema from \"../Schema/index.ts\";\nimport * as ApiPayload from \"./Payload.ts\";\n\ntype Cursor = ConfigRule;\n\ntype ConfigRuleType = ConfigRule[\"type\"];\ntype CallbackRule = Extract<ConfigRule, { type: \"callback\" }>;\n\n/**\n * Returns configured rules for the configured chains.\n * @param query - Raw query parameters containing filters/cursor/limit.\n * @param chains - Chains to include in the configured rules.\n * @returns Config rules response payload. {@link ApiPayload.Payload}\n */\nexport async function getConfigRules(\n query: unknown,\n chains: Chain.Chain[],\n): Promise<ApiPayload.Payload<ConfigRule[]>> {\n const parsed = ApiSchema.safeParse(\"get_config_rules\", query ?? {});\n if (!parsed.success) {\n return ApiPayload.failure(parsed.error);\n }\n\n const { cursor, limit, types, chains: chainIds } = parsed.data;\n const typeFilter = types?.length ? new Set(types) : null;\n const chainFilter = chainIds?.length ? new Set(chainIds) : null;\n\n const rules = buildConfigRules(chains);\n const filteredRules = rules.filter((rule) => {\n if (chainFilter && !chainFilter.has(rule.chain_id)) return false;\n if (typeFilter && !typeFilter.has(rule.type)) return false;\n return true;\n });\n const checksum = buildConfigRulesChecksum(filteredRules);\n\n let cursorRule: Cursor | null = null;\n if (cursor) {\n try {\n cursorRule = parseCursor(cursor);\n } catch (err) {\n return ApiPayload.failure(err);\n }\n }\n if (cursorRule && typeFilter && !typeFilter.has(cursorRule.type)) {\n return ApiPayload.failure(\n new ApiPayload.BadRequestError(\"Cursor type must match requested rule types\"),\n );\n }\n if (cursorRule && chainFilter && !chainFilter.has(cursorRule.chain_id)) {\n return ApiPayload.failure(\n new ApiPayload.BadRequestError(\"Cursor chain_id must match requested chains\"),\n );\n }\n\n const startIndex = cursorRule ? findStartIndex(filteredRules, cursorRule) : 0;\n const page = filteredRules.slice(startIndex, startIndex + limit);\n const nextCursor =\n startIndex + limit < filteredRules.length && page.length > 0\n ? formatCursor(page.at(-1)!)\n : null;\n\n const response = ApiPayload.success({ data: page, cursor: nextCursor });\n response.body.meta.checksum = checksum;\n return response;\n}\n\nfunction formatCursor(rule: ConfigRule): string {\n if (rule.type === \"maturity\") {\n return `maturity:${rule.chain_id}:${rule.timestamp}:${rule.name}`;\n }\n if (rule.type === \"callback\") {\n return `callback:${rule.chain_id}:${rule.callback_type}:${rule.address.toLowerCase()}`;\n }\n if (rule.type === \"oracle\") {\n return `oracle:${rule.chain_id}:${rule.address.toLowerCase()}`;\n }\n if (rule.type === \"collateral_token\") {\n return `collateral_token:${rule.chain_id}:${rule.address.toLowerCase()}`;\n }\n return `loan_token:${rule.chain_id}:${rule.address.toLowerCase()}`;\n}\n\nfunction parseCursor(cursor: string): Cursor {\n const [type, chain, ...rest] = cursor.split(\":\");\n if (!type || !chain || rest.length === 0) {\n throw new ApiPayload.BadRequestError(\"Cursor must be in the format type:chain_id:<value>\");\n }\n if (!isConfigRuleType(type)) {\n throw new ApiPayload.BadRequestError(\"Cursor has an invalid rule type\");\n }\n const chain_id = Number.parseInt(chain, 10) as Chain.Id;\n if (!Number.isFinite(chain_id)) {\n throw new ApiPayload.BadRequestError(\"Cursor has an invalid chain_id\");\n }\n\n if (type === \"maturity\") {\n const timestampValue = Number.parseInt(rest[0] ?? \"\", 10);\n const nameValue = rest.slice(1).join(\":\");\n if (!Number.isFinite(timestampValue) || nameValue.length === 0) {\n throw new ApiPayload.BadRequestError(\n \"Cursor must be in the format maturity:chain_id:timestamp:name\",\n );\n }\n if (!isMaturityType(nameValue)) {\n throw new ApiPayload.BadRequestError(\"Cursor has an invalid maturity name\");\n }\n const timestamp = parseMaturity(timestampValue);\n return { type, chain_id, timestamp, name: nameValue };\n }\n\n if (type === \"callback\") {\n const callbackTypeValue = rest[0] ?? \"\";\n const addressValue = rest.slice(1).join(\":\");\n if (!callbackTypeValue || !addressValue) {\n throw new ApiPayload.BadRequestError(\n \"Cursor must be in the format callback:chain_id:callback_type:address\",\n );\n }\n if (!isCallbackType(callbackTypeValue)) {\n throw new ApiPayload.BadRequestError(\"Cursor has an invalid callback type\");\n }\n return {\n type,\n chain_id,\n callback_type: callbackTypeValue,\n address: parseAddress(addressValue, \"Cursor address\"),\n };\n }\n\n if (type === \"loan_token\" || type === \"collateral_token\" || type === \"oracle\") {\n const addressValue = rest.join(\":\");\n if (!addressValue) {\n throw new ApiPayload.BadRequestError(`Cursor must be in the format ${type}:chain_id:address`);\n }\n return {\n type,\n chain_id,\n address: parseAddress(addressValue, \"Cursor address\"),\n };\n }\n\n throw new ApiPayload.BadRequestError(\"Cursor has an invalid rule type\");\n}\n\nfunction findStartIndex(rules: ConfigRule[], cursor: Cursor): number {\n let low = 0;\n let high = rules.length;\n while (low < high) {\n const mid = Math.floor((low + high) / 2);\n const current = rules[mid]!;\n const cmp = compareConfigRules(current, cursor);\n if (cmp <= 0) {\n low = mid + 1;\n } else {\n high = mid;\n }\n }\n return low;\n}\n\nfunction parseAddress(address: string, label: string): Address {\n if (!/^0x[a-fA-F0-9]{40}$/.test(address)) {\n throw new ApiPayload.BadRequestError(`${label} must be a valid 20-byte address`);\n }\n return address.toLowerCase() as Address;\n}\n\nfunction isConfigRuleType(value: string): value is ConfigRuleType {\n return (\n value === \"maturity\" ||\n value === \"callback\" ||\n value === \"loan_token\" ||\n value === \"collateral_token\" ||\n value === \"oracle\"\n );\n}\n\nfunction isMaturityType(value: string): value is Maturity.MaturityType {\n return (Object.values(Maturity.MaturityType) as string[]).includes(value);\n}\n\nfunction parseMaturity(value: number): Maturity.Maturity {\n try {\n return Maturity.from(value);\n } catch (err) {\n throw new ApiPayload.BadRequestError(\n err instanceof Error ? err.message : \"Invalid maturity timestamp\",\n );\n }\n}\n\nfunction isCallbackType(value: string): value is CallbackRule[\"callback_type\"] {\n if (value === Callback.Type.BuyWithEmptyCallback) return false;\n return (Object.values(Callback.Type) as string[]).includes(value);\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { marked } from \"marked\";\nimport type { OpenAPIDocument } from \"openapi-metadata\";\nimport { OpenApi } from \"../Schema/openapi.ts\";\n\n// ESM: use import.meta.url; Lambda/CJS bundled code: fallback to process.cwd()\nconst __dirname = (() => {\n try {\n // import.meta.url is only available in ESM\n return dirname(fileURLToPath(import.meta.url));\n } catch {\n return process.cwd();\n }\n})();\n\n/**\n * Build the OpenAPI document for the router.\n * @returns OpenAPI document. {@link OpenAPIDocument}\n */\nexport async function getSwaggerJson(): Promise<OpenAPIDocument> {\n return OpenApi();\n}\n\n/**\n * Render the API documentation HTML page.\n * @returns HTML page as string.\n */\nexport async function getDocsHtml(): Promise<string> {\n const spec = await OpenApi();\n const html = `<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"UTF-8\">\n <title>Router API Docs (Scalar)</title>\n <script src=\"https://cdn.jsdelivr.net/npm/@scalar/api-reference\"></script>\n <style>\n html, body { margin: 0; height: 100%; }\n api-reference { height: 100%; width: 100%; }\n </style>\n </head>\n <body>\n <div id=\"api-container\" style=\"height:100%;width:100%;\"></div>\n <script>\n window.addEventListener('load', function () {\n const spec = ${JSON.stringify(spec)};\n Scalar.createApiReference('#api-container', { spec: { content: spec, hideModels: true } });\n });\n </script>\n </body>\n</html>`;\n\n return html;\n}\n\n/**\n * Finds the integrator.md file.\n * Handles source, bundled CLI, and Lambda scenarios.\n */\nfunction findIntegratorMd(): string {\n const candidates = [\n resolve(__dirname, \"../../../docs/integrator.md\"), // from source: src/api/Controllers/\n resolve(__dirname, \"../docs/integrator.md\"), // from dist/\n resolve(process.cwd(), \"docs/integrator.md\"), // Lambda: cwd is /var/task\n ];\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n throw new Error(`integrator.md not found. Tried: ${candidates.join(\", \")}`);\n}\n\n/**\n * Renders the integrator documentation as HTML.\n * @returns HTML page with the rendered markdown documentation.\n */\nexport async function getIntegratorDocsHtml(): Promise<string> {\n const mdPath = findIntegratorMd();\n const markdown = await readFile(mdPath, \"utf-8\");\n const content = await marked(markdown);\n\n return `<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"UTF-8\">\n <title>Documentation</title>\n <style>\n body { font-family: system-ui, sans-serif; max-width: 800px; margin: 0 auto; padding: 2rem; line-height: 1.6; }\n pre { background: #f4f4f4; padding: 1rem; overflow-x: auto; }\n code { background: #f4f4f4; padding: 0.2rem 0.4rem; }\n a { color: #0066cc; }\n </style>\n </head>\n <body>\n <nav><a href=\"/docs/api\">API Reference →</a></nav>\n ${content}\n </body>\n</html>`;\n}\n","import type { Client } from \"viem\";\nimport type { Chain } from \"#core\";\nimport type * as ChainRegistry from \"#core/ChainRegistry.ts\";\nimport type * as Database from \"#database/Database.ts\";\nimport * as Logger from \"#logger/Logger.ts\";\nimport * as Format from \"#utils/Format.ts\";\nimport * as Health from \"../Health.ts\";\nimport type * as OpenApiSchema from \"../Schema/generated/swagger.d.ts\";\nimport * as Schema from \"../Schema/requests.ts\";\nimport * as ApiPayload from \"./Payload.ts\";\n\nexport async function getHealth(\n query: unknown,\n db: Database.Database,\n chainRegistry?: ChainRegistry.ChainRegistry,\n): Promise<\n ApiPayload.Payload<\n OpenApiSchema.paths[\"/v1/health\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"][\"data\"]\n >\n> {\n const logger = Logger.getLogger();\n try {\n const parsed = Schema.safeParse(\"get_health\", query);\n if (!parsed.success) return ApiPayload.failure(parsed.error);\n\n const healthService = Health.create({ db, chainRegistry });\n const snapshot = await healthService.getSnapshot();\n\n if (parsed.data.strict && !snapshot.initialized) {\n return ApiPayload.failure(\n new ApiPayload.APIError(\n ApiPayload.STATUS_CODE.INTERNAL_SERVER_ERROR,\n \"Indexer block state is not initialized\",\n \"INTERNAL_SERVER_ERROR\",\n Format.toSnakeCase({\n missingChains: snapshot.missingChains,\n missingCollectors: snapshot.missingCollectors,\n }),\n ),\n );\n }\n\n return ApiPayload.success({\n data: Format.toSnakeCase({\n status: snapshot.status,\n initialized: snapshot.initialized,\n missingChains: snapshot.missingChains,\n missingCollectors: snapshot.missingCollectors,\n }),\n });\n } catch (err) {\n logger.error({\n err,\n msg: \"Error getting health status\",\n errorMessage: err instanceof Error ? err.message : String(err),\n errorStack: err instanceof Error ? err.stack : undefined,\n });\n return ApiPayload.failure(err);\n }\n}\n\nexport async function getHealthChains(\n query: unknown,\n db: Database.Database,\n healthClients?: Map<Chain.Id, Client>,\n chainRegistry?: ChainRegistry.ChainRegistry,\n): Promise<\n ApiPayload.Payload<\n OpenApiSchema.paths[\"/v1/health/chains\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"][\"data\"]\n >\n> {\n const logger = Logger.getLogger();\n try {\n const parsed = Schema.safeParse(\"get_health_chains\", query);\n if (!parsed.success) return ApiPayload.failure(parsed.error);\n\n const healthService = Health.create({ db, healthClients, chainRegistry });\n const snapshot = await healthService.getSnapshot();\n\n if (parsed.data.strict && !snapshot.initialized) {\n return ApiPayload.failure(\n new ApiPayload.APIError(\n ApiPayload.STATUS_CODE.INTERNAL_SERVER_ERROR,\n \"Indexer block state is not initialized\",\n \"INTERNAL_SERVER_ERROR\",\n Format.toSnakeCase({\n missingChains: snapshot.missingChains,\n missingCollectors: snapshot.missingCollectors,\n }),\n ),\n );\n }\n\n const chains = snapshot.chains;\n return ApiPayload.success({\n data: chains.map(({ chainId, localBlockNumber, remoteBlockNumber, updatedAt, initialized }) =>\n Format.toSnakeCase({\n chainId,\n localBlockNumber,\n remoteBlockNumber,\n updatedAt,\n initialized,\n }),\n ),\n });\n } catch (err) {\n logger.error({\n err,\n msg: \"Error getting health status for chains\",\n errorMessage: err instanceof Error ? err.message : String(err),\n errorStack: err instanceof Error ? err.stack : undefined,\n });\n return ApiPayload.failure(err);\n }\n}\n\nexport async function getHealthCollectors(\n query: unknown,\n db: Database.Database,\n chainRegistry?: ChainRegistry.ChainRegistry,\n): Promise<\n ApiPayload.Payload<\n OpenApiSchema.paths[\"/v1/health/collectors\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"][\"data\"]\n >\n> {\n const logger = Logger.getLogger();\n try {\n const parsed = Schema.safeParse(\"get_health_collectors\", query);\n if (!parsed.success) return ApiPayload.failure(parsed.error);\n\n const healthService = Health.create({ db, chainRegistry });\n const snapshot = await healthService.getSnapshot();\n\n if (parsed.data.strict && !snapshot.initialized) {\n return ApiPayload.failure(\n new ApiPayload.APIError(\n ApiPayload.STATUS_CODE.INTERNAL_SERVER_ERROR,\n \"Indexer block state is not initialized\",\n \"INTERNAL_SERVER_ERROR\",\n Format.toSnakeCase({\n missingChains: snapshot.missingChains,\n missingCollectors: snapshot.missingCollectors,\n }),\n ),\n );\n }\n\n const collectors = snapshot.collectors;\n return ApiPayload.success({\n data: collectors.map(({ name, chainId, blockNumber, updatedAt, lag, status, initialized }) =>\n Format.toSnakeCase({\n name,\n chainId,\n blockNumber,\n updatedAt,\n lag,\n status,\n initialized,\n }),\n ),\n });\n } catch (err) {\n logger.error({\n err,\n msg: \"Error getting health status for collectors\",\n errorMessage: err instanceof Error ? err.message : String(err),\n errorStack: err instanceof Error ? err.stack : undefined,\n });\n return ApiPayload.failure(err);\n }\n}\n","import type { SQL, SQLWrapper } from \"drizzle-orm\";\nimport { and, asc, desc, eq, gte, inArray, lte, sql } from \"drizzle-orm\";\nimport type { Address, Hex } from \"viem\";\nimport { type Chain, Collateral, LLTV, Obligation, Offer, Quote } from \"#core\";\nimport {\n groups as groupsTable,\n obligationCollateralsV2 as obligationCollateralsTable,\n obligations as obligationsTable,\n offers as offersTable,\n oracles as oraclesTable,\n status as statusTable,\n validations as validationsTable,\n} from \"#database/drizzle/schema.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport { Time } from \"#utils/index.ts\";\n\nconst SORT_FIELDS = [\"id\", \"ask\", \"bid\", \"maturity\"] as const;\nconst CURSOR_ID_REGEX = /^0x[a-f0-9]{64}$/i;\nconst INT32_MIN = -2147483648;\nconst INT32_MAX = 2147483647;\nconst INT32_MAX_BIGINT = BigInt(INT32_MAX);\nconst MAX_SORT_FIELDS = 3;\nconst MAX_CURSOR_SORT_FIELDS = MAX_SORT_FIELDS + 1;\nconst DEFAULT_LIMIT = 20;\n\ntype SortField = (typeof SORT_FIELDS)[number];\ntype SortDirection = \"asc\" | \"desc\";\ntype SortEntry = { field: SortField; direction: SortDirection };\ntype SortToken = `${SortField}` | `-${SortField}`;\n\ntype CursorPayload = {\n sort: SortToken[];\n id: Hex;\n ask: string;\n bid: string;\n maturity: number;\n};\n\ntype CursorValues = {\n id: Hex;\n ask: bigint;\n bid: bigint;\n maturity: number;\n};\n\ntype ListedObligationRow = {\n obligation: Obligation.Obligation;\n quote: Quote.Quote;\n cursorValues: CursorValues;\n};\n\nexport type ListObligationsParameters = {\n ids?: Hex[];\n chainId?: Chain.Id[];\n loanToken?: Address[];\n collateralToken?: Address[];\n maturity?: number[];\n sort?: string[];\n cursor?: string;\n limit?: number;\n};\n\nexport type ListedObligation = {\n obligation: Obligation.Obligation;\n quote: Quote.Quote;\n};\n\nexport type ListObligationsResult = {\n obligations: ListedObligation[];\n nextCursor: string | null;\n};\n\nexport type ObligationsListingReader = {\n /**\n * Lists obligations with SQL keyset pagination and opaque cursor handling.\n * @param parameters - Optional filters, sorting, and pagination cursor.\n * @returns Listed obligations with associated quotes and a next cursor.\n */\n list: (parameters?: ListObligationsParameters) => Promise<ListObligationsResult>;\n};\n\nexport class BadRequestError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ObligationsListingBadRequestError\";\n }\n}\n\n/**\n * Creates the obligations listing reader facade.\n * @param parameters - Reader dependencies.\n * @returns Obligations listing reader.\n */\nexport function create(parameters: { db: Database.Core }): ObligationsListingReader {\n const { db } = parameters;\n\n return {\n list: async (queryParameters) => {\n const {\n ids,\n chainId: chainIds,\n loanToken: loanTokens,\n collateralToken: collateralTokens,\n maturity: maturities,\n sort: sortTokens,\n cursor: encodedCursor,\n limit: requestedLimit,\n } = queryParameters ?? {};\n\n const limit = requestedLimit ?? DEFAULT_LIMIT;\n if (!Number.isInteger(limit) || limit <= 0) {\n throw new BadRequestError(\"Limit must be a positive integer\");\n }\n\n const cursorPayload = encodedCursor ? decodeCursorPayload(encodedCursor) : undefined;\n const requestedSort = normalizeSort(sortTokens);\n const cursorSort = cursorPayload ? normalizeSort(cursorPayload.sort) : undefined;\n\n if (\n cursorSort !== undefined &&\n sortTokens !== undefined &&\n !hasSameSort(requestedSort, cursorSort)\n ) {\n throw new BadRequestError(\"Cursor sort does not match requested sort\");\n }\n\n const sort = sortTokens !== undefined ? requestedSort : (cursorSort ?? requestedSort);\n const cursorValues = cursorPayload ? cursorValuesFromPayload(cursorPayload) : undefined;\n\n const now = Time.now();\n\n const loanTokenFilter =\n loanTokens !== undefined && loanTokens.length > 0\n ? sql`(${sql.join(\n loanTokens.map(\n (token) => sql`LOWER(${obligationsTable.loanToken}) = ${token.toLowerCase()}`,\n ),\n sql` OR `,\n )})`\n : undefined;\n\n const collateralFilter =\n collateralTokens !== undefined && collateralTokens.length > 0\n ? sql`EXISTS (\n SELECT 1 FROM ${obligationCollateralsTable} oc\n WHERE oc.obligation_id = ${obligationsTable.obligationId}\n AND (${sql.join(\n collateralTokens.map((token) => sql`LOWER(oc.asset) = ${token.toLowerCase()}`),\n sql` OR `,\n )})\n )`\n : undefined;\n\n const bestAskTick = db\n .select({\n askTick: offersTable.tick,\n })\n .from(offersTable)\n .innerJoin(\n groupsTable,\n and(\n eq(offersTable.groupChainId, groupsTable.chainId),\n eq(offersTable.groupMaker, groupsTable.maker),\n eq(offersTable.group, groupsTable.group),\n ),\n )\n .leftJoin(validationsTable, eq(offersTable.hash, validationsTable.offerHash))\n .leftJoin(statusTable, eq(validationsTable.statusId, statusTable.id))\n .where(\n and(\n eq(offersTable.obligationId, obligationsTable.obligationId),\n eq(offersTable.buy, false),\n gte(offersTable.expiry, now),\n gte(offersTable.maturity, now),\n lte(offersTable.start, now),\n sql`(${statusTable.code} IS NULL OR ${statusTable.code} = ${Offer.Status.VALID})`,\n ),\n )\n .orderBy(desc(offersTable.tick))\n .limit(1)\n .as(\"best_ask_tick\");\n\n const bestBidTick = db\n .select({\n bidTick: offersTable.tick,\n })\n .from(offersTable)\n .innerJoin(\n groupsTable,\n and(\n eq(offersTable.groupChainId, groupsTable.chainId),\n eq(offersTable.groupMaker, groupsTable.maker),\n eq(offersTable.group, groupsTable.group),\n ),\n )\n .leftJoin(validationsTable, eq(offersTable.hash, validationsTable.offerHash))\n .leftJoin(statusTable, eq(validationsTable.statusId, statusTable.id))\n .where(\n and(\n eq(offersTable.obligationId, obligationsTable.obligationId),\n eq(offersTable.buy, true),\n gte(offersTable.expiry, now),\n gte(offersTable.maturity, now),\n lte(offersTable.start, now),\n sql`(${statusTable.code} IS NULL OR ${statusTable.code} = ${Offer.Status.VALID})`,\n ),\n )\n .orderBy(asc(offersTable.tick))\n .limit(1)\n .as(\"best_bid_tick\");\n\n const obligationsWithQuotes = db\n .select({\n obligationId: obligationsTable.obligationId,\n chainId: obligationsTable.chainId,\n loanToken: obligationsTable.loanToken,\n collaterals: sql<\n { asset: Address; oracle: Address; lltv: string }[]\n >`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsTable.asset}, 'oracle', ${oraclesTable.address}, 'lltv', ${obligationCollateralsTable.lltv}))`.as(\n \"collaterals\",\n ),\n maturity: obligationsTable.maturity,\n askTick: sql<number | null>`MAX(${bestAskTick.askTick})`.as(\"ask_tick\"),\n bidTick: sql<number | null>`MAX(${bestBidTick.bidTick})`.as(\"bid_tick\"),\n // Opaque cursor sort key: null tick -> 0, tick N -> N + 1.\n ask: sql<number>`COALESCE(MAX(${bestAskTick.askTick}) + 1, 0)`.as(\"ask\"),\n bid: sql<number>`COALESCE(MAX(${bestBidTick.bidTick}) + 1, 0)`.as(\"bid\"),\n })\n .from(obligationsTable)\n .innerJoin(\n obligationCollateralsTable,\n eq(obligationsTable.obligationId, obligationCollateralsTable.obligationId),\n )\n .innerJoin(\n oraclesTable,\n sql`${obligationCollateralsTable.oracleChainId} = ${oraclesTable.chainId}\n AND ${obligationCollateralsTable.oracleAddress} = ${oraclesTable.address}`,\n )\n .leftJoinLateral(bestAskTick, sql`true`)\n .leftJoinLateral(bestBidTick, sql`true`)\n .groupBy(obligationsTable.obligationId)\n .where(\n and(\n ids !== undefined && ids.length > 0\n ? inArray(obligationsTable.obligationId, ids)\n : undefined,\n chainIds !== undefined && chainIds.length > 0\n ? inArray(obligationsTable.chainId, chainIds)\n : undefined,\n loanTokenFilter,\n maturities !== undefined && maturities.length > 0\n ? inArray(obligationsTable.maturity, maturities)\n : gte(obligationsTable.maturity, now),\n collateralFilter,\n ),\n )\n .as(\"obligations_with_quotes\");\n\n const sortColumns = {\n id: obligationsWithQuotes.obligationId,\n ask: obligationsWithQuotes.ask,\n bid: obligationsWithQuotes.bid,\n maturity: obligationsWithQuotes.maturity,\n } satisfies Record<SortField, SQLWrapper>;\n\n const rows = await db\n .select({\n obligationId: obligationsWithQuotes.obligationId,\n chainId: obligationsWithQuotes.chainId,\n loanToken: obligationsWithQuotes.loanToken,\n collaterals: obligationsWithQuotes.collaterals,\n maturity: obligationsWithQuotes.maturity,\n askTick: obligationsWithQuotes.askTick,\n bidTick: obligationsWithQuotes.bidTick,\n ask: obligationsWithQuotes.ask,\n bid: obligationsWithQuotes.bid,\n })\n .from(obligationsWithQuotes)\n .where(buildCursorFilter(sortColumns, sort, cursorValues))\n .orderBy(...buildOrderBy(sortColumns, sort))\n .limit(limit + 1);\n\n const hasMore = rows.length > limit;\n const paginatedRows = hasMore ? rows.slice(0, limit) : rows;\n\n const listedRows = paginatedRows.map((row): ListedObligationRow => {\n const obligation = Obligation.from({\n chainId: row.chainId,\n loanToken: row.loanToken as Address,\n collaterals: row.collaterals\n .sort((left, right) => left.asset.localeCompare(right.asset))\n .map((collateral) =>\n Collateral.from({\n asset: collateral.asset as Address,\n oracle: collateral.oracle as Address,\n lltv: LLTV.from(BigInt(collateral.lltv)),\n }),\n ),\n maturity: row.maturity,\n });\n\n const quote = Quote.from({\n obligationId: row.obligationId as Hex,\n ask: { tick: row.askTick },\n bid: { tick: row.bidTick },\n });\n\n return {\n obligation,\n quote,\n cursorValues: {\n id: row.obligationId as Hex,\n ask: toBigInt(row.ask),\n bid: toBigInt(row.bid),\n maturity: row.maturity,\n },\n };\n });\n\n const nextCursor =\n hasMore && listedRows.length > 0\n ? encodeCursorPayload({\n sort: sortToTokens(sort),\n id: listedRows[listedRows.length - 1]!.cursorValues.id,\n ask: listedRows[listedRows.length - 1]!.cursorValues.ask.toString(),\n bid: listedRows[listedRows.length - 1]!.cursorValues.bid.toString(),\n maturity: listedRows[listedRows.length - 1]!.cursorValues.maturity,\n })\n : null;\n\n return {\n obligations: listedRows.map((row) => ({\n obligation: row.obligation,\n quote: row.quote,\n })),\n nextCursor,\n };\n },\n };\n}\n\nfunction isSortField(value: string): value is SortField {\n return (SORT_FIELDS as readonly string[]).includes(value);\n}\n\nfunction parseSortToken(token: string): SortEntry {\n const direction: SortDirection = token.startsWith(\"-\") ? \"desc\" : \"asc\";\n const rawField = token.startsWith(\"-\") ? token.slice(1) : token;\n if (!isSortField(rawField)) throw new BadRequestError(`Invalid sort field: ${rawField}`);\n return { field: rawField, direction };\n}\n\nfunction normalizeSort(sortTokens: string[] | undefined): SortEntry[] {\n const parsed: SortEntry[] = sortTokens?.length\n ? sortTokens.map(parseSortToken)\n : [{ field: \"id\", direction: \"asc\" }];\n return parsed.some((entry) => entry.field === \"id\")\n ? parsed\n : [...parsed, { field: \"id\", direction: \"asc\" }];\n}\n\nfunction sortToTokens(sortEntries: SortEntry[]): SortToken[] {\n return sortEntries.map(\n (entry) => (entry.direction === \"desc\" ? `-${entry.field}` : entry.field) as SortToken,\n );\n}\n\nfunction hasSameSort(left: SortEntry[], right: SortEntry[]): boolean {\n if (left.length !== right.length) return false;\n return left.every(\n (sortEntry, index) =>\n sortEntry.field === right[index]?.field && sortEntry.direction === right[index]?.direction,\n );\n}\n\nfunction decodeCursorPayload(cursor: string): CursorPayload {\n let decoded: unknown;\n try {\n decoded = JSON.parse(Buffer.from(cursor, \"base64url\").toString(\"utf8\"));\n } catch {\n throw new BadRequestError(\"Invalid cursor format\");\n }\n\n if (decoded === null || typeof decoded !== \"object\") {\n throw new BadRequestError(\"Invalid cursor payload\");\n }\n\n const payload = decoded as Record<string, unknown>;\n const sortTokens = parseCursorSortTokens(payload.sort);\n\n if (typeof payload.id !== \"string\" || !CURSOR_ID_REGEX.test(payload.id)) {\n throw new BadRequestError(\"Invalid cursor obligation id\");\n }\n\n const ask = parseCursorNonNegativeInt32(payload.ask, \"ask\");\n const bid = parseCursorNonNegativeInt32(payload.bid, \"bid\");\n if (!isInt32(payload.maturity)) {\n throw new BadRequestError(\"Invalid cursor maturity value\");\n }\n\n return {\n sort: sortTokens,\n id: payload.id as Hex,\n ask,\n bid,\n maturity: payload.maturity,\n };\n}\n\nfunction parseCursorSortTokens(value: unknown): SortToken[] {\n if (!Array.isArray(value) || value.length === 0 || value.length > MAX_CURSOR_SORT_FIELDS) {\n throw new BadRequestError(\"Invalid cursor sort\");\n }\n\n const sortEntries: SortEntry[] = value.map((token) => {\n if (typeof token !== \"string\") throw new BadRequestError(\"Invalid cursor sort\");\n try {\n return parseSortToken(token);\n } catch {\n throw new BadRequestError(\"Invalid cursor sort\");\n }\n });\n\n const uniqueFields = new Set(sortEntries.map((entry) => entry.field));\n if (uniqueFields.size !== sortEntries.length) {\n throw new BadRequestError(\"Invalid cursor sort\");\n }\n\n return sortToTokens(sortEntries);\n}\n\nfunction parseCursorNonNegativeInt32(value: unknown, field: \"ask\" | \"bid\"): string {\n if (typeof value !== \"string\" || !/^\\d+$/.test(value)) {\n throw new BadRequestError(`Invalid cursor ${field} value`);\n }\n\n if (BigInt(value) > INT32_MAX_BIGINT) {\n throw new BadRequestError(`Invalid cursor ${field} value`);\n }\n\n return value;\n}\n\nfunction isInt32(value: unknown): value is number {\n return (\n typeof value === \"number\" &&\n Number.isSafeInteger(value) &&\n value >= INT32_MIN &&\n value <= INT32_MAX\n );\n}\n\nfunction encodeCursorPayload(payload: CursorPayload): string {\n return Buffer.from(JSON.stringify(payload), \"utf8\").toString(\"base64url\");\n}\n\nfunction cursorValuesFromPayload(payload: CursorPayload): CursorValues {\n return {\n id: payload.id,\n ask: BigInt(payload.ask),\n bid: BigInt(payload.bid),\n maturity: payload.maturity,\n };\n}\n\nfunction cursorComparisonValue(cursorValues: CursorValues, field: SortField): string | number {\n switch (field) {\n case \"id\":\n return cursorValues.id;\n case \"maturity\":\n return cursorValues.maturity;\n case \"ask\":\n return cursorValues.ask.toString();\n case \"bid\":\n return cursorValues.bid.toString();\n }\n}\n\nfunction buildCursorFilter(\n columns: Record<SortField, SQLWrapper>,\n sortEntries: SortEntry[],\n cursorValues: CursorValues | undefined,\n): SQL | undefined {\n if (cursorValues === undefined) return undefined;\n\n const comparisons = sortEntries.map((sortEntry, index) => {\n const equals = sortEntries.slice(0, index).map((previous) => {\n return sql`${columns[previous.field]} = ${cursorComparisonValue(cursorValues, previous.field)}`;\n });\n\n const comparison =\n sortEntry.direction === \"asc\"\n ? sql`${columns[sortEntry.field]} > ${cursorComparisonValue(cursorValues, sortEntry.field)}`\n : sql`${columns[sortEntry.field]} < ${cursorComparisonValue(cursorValues, sortEntry.field)}`;\n\n return equals.length > 0\n ? sql`(${sql.join([...equals, comparison], sql` AND `)})`\n : sql`(${comparison})`;\n });\n\n return comparisons.length > 0 ? sql`(${sql.join(comparisons, sql` OR `)})` : undefined;\n}\n\nfunction buildOrderBy(columns: Record<SortField, SQLWrapper>, sortEntries: SortEntry[]): SQL[] {\n return sortEntries.map((sortEntry) =>\n sortEntry.direction === \"asc\" ? asc(columns[sortEntry.field]) : desc(columns[sortEntry.field]),\n );\n}\n\nfunction toBigInt(value: string | number | bigint): bigint {\n if (typeof value === \"bigint\") return value;\n if (typeof value === \"number\") return BigInt(value);\n return BigInt(value.split(\".\")[0] ?? \"0\");\n}\n","import type { Database } from \"#database/index.ts\";\nimport * as ObligationsListingReader from \"#database/readers/ObligationsListing.ts\";\nimport { Logger } from \"#logger/index.ts\";\nimport * as ApiSchema from \"../Schema/index.ts\";\nimport * as ApiPayload from \"./Payload.ts\";\n\nfunction toPayloadError(err: unknown): unknown {\n if (err instanceof ObligationsListingReader.BadRequestError) {\n return new ApiPayload.BadRequestError(err.message);\n }\n\n return err;\n}\n\nexport async function getObligation(\n params: object,\n db: Database.Database,\n): Promise<ApiPayload.Payload<ApiSchema.ObligationResponse.ObligationResponse>> {\n const logger = Logger.getLogger();\n const result = ApiSchema.safeParse(\"get_obligation\", params, (issue) => issue.message);\n\n if (!result.success) return ApiPayload.failure(result.error);\n const query = result.data;\n\n try {\n const listing = await db.readers.obligations.list({\n ids: [query.obligation_id],\n limit: 1,\n });\n\n if (listing.obligations.length === 0) {\n return ApiPayload.failure(new ApiPayload.NotFoundError(\"Obligation not found\"));\n }\n\n const obligation = listing.obligations[0]!;\n\n return ApiPayload.success({\n data: ApiSchema.ObligationResponse.from(obligation.obligation, obligation.quote),\n cursor: null,\n });\n } catch (err) {\n const payloadError = toPayloadError(err);\n logger.error({\n err: payloadError,\n msg: \"Error get obligation\",\n errorMessage: payloadError instanceof Error ? payloadError.message : String(payloadError),\n errorStack: payloadError instanceof Error ? payloadError.stack : undefined,\n });\n return ApiPayload.failure(payloadError);\n }\n}\n","import type { Chain } from \"#core\";\nimport type { Database } from \"#database/index.ts\";\nimport * as ObligationsListingReader from \"#database/readers/ObligationsListing.ts\";\nimport { Logger } from \"#logger/index.ts\";\nimport * as ApiSchema from \"../Schema/index.ts\";\nimport * as ApiPayload from \"./Payload.ts\";\n\nfunction toPayloadError(err: unknown): unknown {\n if (err instanceof ObligationsListingReader.BadRequestError) {\n return new ApiPayload.BadRequestError(err.message);\n }\n\n return err;\n}\n\nexport async function getObligations(\n queryParameters: object,\n db: Database.Database,\n): Promise<ApiPayload.Payload<ApiSchema.ObligationResponse.ObligationResponse[]>> {\n const logger = Logger.getLogger();\n const result = ApiSchema.safeParse(\"get_obligations\", queryParameters, (issue) => issue.message);\n\n if (!result.success) return ApiPayload.failure(result.error);\n const query = result.data;\n\n try {\n const chainIds = query.chains?.length ? (query.chains as Chain.Id[]) : undefined;\n const loanTokens = query.loan_tokens?.length ? query.loan_tokens : undefined;\n const collateralTokens = query.collateral_tokens?.length ? query.collateral_tokens : undefined;\n const maturities = query.maturities?.length ? query.maturities : undefined;\n\n const listing = await db.readers.obligations.list({\n chainId: chainIds,\n loanToken: loanTokens,\n collateralToken: collateralTokens,\n maturity: maturities,\n sort: query.sort,\n cursor: query.cursor,\n limit: query.limit,\n });\n\n return ApiPayload.success({\n data: listing.obligations.map((item) =>\n ApiSchema.ObligationResponse.from(item.obligation, item.quote),\n ),\n cursor: listing.nextCursor,\n });\n } catch (err) {\n const payloadError = toPayloadError(err);\n logger.error({\n err: payloadError,\n msg: \"Error get obligations\",\n errorMessage: payloadError instanceof Error ? payloadError.message : String(payloadError),\n errorStack: payloadError instanceof Error ? payloadError.stack : undefined,\n });\n\n return ApiPayload.failure(payloadError);\n }\n}\n","/**\n * Default batch size for bulk database inserts.\n *\n * PostgreSQL limits a single query to at most 65,535 parameters\n * (e.g. $1, $2, ...). In bulk inserts, each row consumes one\n * parameter per column, so inserting too many rows at once can\n * exceed this limit.\n *\n * Our largest batched insert is into the `offers` table with 15 columns.\n * 15 cols × 4,000 rows = 60,000 parameters, safely under 65,535.\n */\nexport const DEFAULT_BATCH_SIZE = 4000;\n","import { and, asc, eq, gt, gte, inArray, lte, sql } from \"drizzle-orm\";\nimport type { Address, Hex } from \"viem\";\nimport { type Collateral, Maturity, Offer, Quote } from \"#core\";\nimport type * as Chain from \"#core/Chain.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\nimport { Time } from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\nimport {\n groups as groupsTable,\n obligationCollateralsV2 as obligationCollateralsTable,\n obligations as obligationsTable,\n offers as offersTable,\n oracles as oraclesTable,\n status as statusTable,\n validations as validationsTable,\n} from \"../drizzle/schema.ts\";\n\nexport type CreateBatch = Readonly<{\n blockNumber: number;\n offers: Offer.Offer[];\n}>;\n\n/**\n * Raw row returned by database queries.\n * Built from primitives; no domain constructors in the DB layer.\n */\nexport type Row = {\n hash: Hex;\n maker: Address;\n assets: bigint;\n obligationUnits: bigint;\n obligationShares: bigint;\n tick: number;\n maturity: Maturity.Maturity;\n expiry: number;\n start: number;\n group: Hex;\n session: Hex;\n buy: boolean;\n chainId: Chain.Id;\n loanToken: Address;\n collaterals: Collateral.Collateral[];\n callback: {\n address: Address;\n data: Hex;\n };\n receiverIfMakerIsSeller: Address;\n consumed: bigint;\n available: bigint;\n takeable: bigint;\n blockNumber: number;\n};\n\nexport type OffersDomain = {\n /** Insert offers (insert-only). */\n create: (batches: CreateBatch[]) => Promise<Hex[]>;\n\n /** Delete multiple offers by hashes or block number greater than or equal to the given value on a given chain.\n * @returns the number of offers deleted.\n */\n delete: (\n parameters: { hashes: Hex[] } | { blockNumberGte: number; chainId: Chain.Id },\n ) => Promise<number>;\n\n /** Get offers with collaterals only (no availability/takeable computation). */\n get: (parameters?: GetOffersParams) => Promise<{ rows: Row[]; nextCursor: string | null }>;\n\n /** Get quotes for given obligations. */\n getQuotes: (parameters: { obligationIds: Hex[] }) => Promise<Quote.Quote[]>;\n};\n\nexport const DEFAULT_LIMIT = 100;\nexport type PaginationParams = {\n /** Cursor string returned by a previous call, for pagination */\n cursor?: string;\n /** Page size; defaults to {@link DEFAULT_LIMIT} */\n limit?: number;\n};\n\nexport type GetOffersParams = {\n /** Filter by maker address */\n maker?: Address;\n} & PaginationParams;\n\nexport function create(config: { db: Database.Core }): OffersDomain {\n const { db } = config;\n\n return {\n create: async (batches: CreateBatch[]): Promise<Hex[]> => {\n if (batches.length === 0) return [];\n const offersRows = batches.flatMap(({ blockNumber, offers }) =>\n offers.map((offer) => ({\n ...Offer.serialize(offer),\n obligationId: Offer.obligationId(offer),\n groupChainId: offer.chainId,\n groupMaker: offer.maker.toLowerCase(),\n callbackAddress: offer.callback.address.toLowerCase(),\n callbackData: offer.callback.data,\n receiverIfMakerIsSeller: offer.receiverIfMakerIsSeller.toLowerCase(),\n blockNumber,\n })),\n );\n if (offersRows.length === 0) return [];\n\n try {\n return await db.transaction(async (dbTx) => {\n // allow to check that the offer was not deleted immediately after insertion (for example by a consumed event)\n const selectExisting = async (hashes: string[]) => {\n if (hashes.length === 0) return new Set<string>();\n const existing = new Set<string>();\n for (const batch of Utils.batch(hashes, DEFAULT_BATCH_SIZE)) {\n const rows = await dbTx\n .select({ hash: offersTable.hash })\n .from(offersTable)\n .where(inArray(offersTable.hash, batch));\n for (const row of rows) existing.add(String(row.hash).toLowerCase());\n }\n return existing;\n };\n\n const inserted: Hex[] = [];\n for (const batch of Utils.batch(offersRows, DEFAULT_BATCH_SIZE)) {\n const rows = await dbTx\n .insert(offersTable)\n .values(batch)\n .onConflictDoNothing()\n .returning();\n inserted.push(...rows.map((row) => row.hash as Hex));\n }\n\n const existing = await selectExisting(inserted);\n return inserted.filter((hash) => existing.has(hash));\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n throw new Error(\n \"Offers.create failed. Ensure obligations and groups exist before inserting offers.\",\n { cause: error },\n );\n }\n },\n\n get: async (\n parameters?: GetOffersParams,\n ): Promise<{ rows: Row[]; nextCursor: string | null }> => {\n const limit = parameters?.limit ?? DEFAULT_LIMIT;\n const cursor = parameters?.cursor;\n const maker = parameters?.maker;\n\n if (cursor !== null && cursor !== undefined) {\n if (!cursor.startsWith(\"0x\") || cursor.length !== 66) {\n throw new Error(\"Invalid cursor format\");\n }\n }\n\n const collateralsLateral = db\n .select({\n collaterals: sql<Array<{ asset: string; oracle: string; lltv: string }>>`COALESCE(\n jsonb_agg(\n jsonb_build_object(\n 'asset', ${obligationCollateralsTable.asset},\n 'oracle', ${oraclesTable.address},\n 'lltv', ${obligationCollateralsTable.lltv}\n )\n ),\n '[]'::jsonb\n )`.as(\"collaterals\"),\n })\n .from(obligationCollateralsTable)\n .innerJoin(\n oraclesTable,\n sql`${obligationCollateralsTable.oracleChainId} = ${oraclesTable.chainId}\n AND ${obligationCollateralsTable.oracleAddress} = ${oraclesTable.address}`,\n )\n .where(eq(obligationCollateralsTable.obligationId, offersTable.obligationId))\n .as(\"collaterals_lateral\");\n\n const results = await db\n .select({\n hash: offersTable.hash,\n maker: offersTable.groupMaker,\n assets: offersTable.assets,\n obligationUnits: offersTable.obligationUnits,\n obligationShares: offersTable.obligationShares,\n tick: offersTable.tick,\n maturity: offersTable.maturity,\n expiry: offersTable.expiry,\n start: offersTable.start,\n group: offersTable.group,\n session: offersTable.session,\n buy: offersTable.buy,\n chainId: obligationsTable.chainId,\n loanToken: obligationsTable.loanToken,\n callbackAddress: offersTable.callbackAddress,\n callbackData: offersTable.callbackData,\n receiverIfMakerIsSeller: offersTable.receiverIfMakerIsSeller,\n collaterals: collateralsLateral.collaterals,\n blockNumber: offersTable.blockNumber,\n })\n .from(offersTable)\n .innerJoin(obligationsTable, eq(offersTable.obligationId, obligationsTable.obligationId))\n .innerJoinLateral(collateralsLateral, sql`true`)\n .where(\n and(\n cursor !== null && cursor !== undefined ? gt(offersTable.hash, cursor) : undefined,\n maker !== undefined ? eq(offersTable.groupMaker, maker.toLowerCase()) : undefined,\n ),\n )\n .orderBy(asc(offersTable.hash))\n .limit(limit);\n\n const rows: Row[] = results.map((row) => {\n const receiverIfMakerIsSeller = (\n row.receiverIfMakerIsSeller ?? row.maker\n ).toLowerCase() as Address;\n return {\n hash: row.hash as Hex,\n maker: row.maker as Address,\n assets: BigInt(row.assets),\n obligationUnits: BigInt(row.obligationUnits),\n obligationShares: BigInt(row.obligationShares),\n tick: row.tick,\n maturity: Maturity.from(row.maturity),\n expiry: row.expiry,\n start: row.start,\n group: row.group as Hex,\n session: row.session as Hex,\n buy: row.buy,\n chainId: row.chainId,\n loanToken: row.loanToken as Address,\n collaterals: row.collaterals\n .map((c) => ({\n asset: c.asset as Address,\n oracle: c.oracle as Address,\n lltv: BigInt(c.lltv) as Offer.OfferInput[\"collaterals\"][number][\"lltv\"],\n }))\n .sort((a, b) => a.asset.toLowerCase().localeCompare(b.asset.toLowerCase())),\n callback: {\n address: row.callbackAddress as Address,\n data: row.callbackData as Hex,\n },\n receiverIfMakerIsSeller,\n consumed: 0n,\n available: 0n,\n takeable: 0n,\n blockNumber: row.blockNumber,\n };\n });\n\n const nextCursor = rows.length === limit ? rows[rows.length - 1]!.hash : null;\n return { rows, nextCursor };\n },\n\n delete: async (\n parameters:\n | {\n hashes: Hex[];\n }\n | {\n blockNumberGte: number;\n chainId: Chain.Id;\n },\n ): Promise<number> => {\n if (\"hashes\" in parameters) {\n const { hashes } = parameters;\n if (hashes.length === 0) return 0;\n const normalizedHashes = hashes.map((hash) => hash.toLowerCase());\n const result = await db\n .delete(offersTable)\n .where(inArray(offersTable.hash, normalizedHashes));\n return (result as { affectedRows: number }).affectedRows;\n }\n\n if (\"blockNumberGte\" in parameters) {\n const { blockNumberGte, chainId } = parameters;\n const result = await db\n .delete(offersTable)\n .where(\n sql`${offersTable.blockNumber} >= ${blockNumberGte} AND ${offersTable.groupChainId} = ${chainId}`,\n );\n return (result as { affectedRows: number }).affectedRows;\n }\n\n throw new Error(\"Invalid parameters\");\n },\n\n getQuotes: async (parameters: { obligationIds: Hex[] }): Promise<Quote.Quote[]> => {\n const { obligationIds } = parameters;\n if (obligationIds.length === 0) return [];\n\n const now = Time.now();\n\n const query = ({ side }: { side: \"buy\" | \"sell\" }) =>\n db\n .selectDistinctOn([offersTable.obligationId], {\n obligationId: offersTable.obligationId,\n tick: offersTable.tick,\n })\n .from(offersTable)\n .innerJoin(\n groupsTable,\n and(\n eq(offersTable.groupChainId, groupsTable.chainId),\n eq(offersTable.groupMaker, groupsTable.maker),\n eq(offersTable.group, groupsTable.group),\n ),\n )\n .leftJoin(validationsTable, eq(offersTable.hash, validationsTable.offerHash))\n .leftJoin(statusTable, eq(validationsTable.statusId, statusTable.id))\n .where(\n and(\n inArray(offersTable.obligationId, obligationIds),\n eq(offersTable.buy, side === \"buy\"),\n gte(offersTable.expiry, now),\n gte(offersTable.maturity, now),\n lte(offersTable.start, now),\n sql`(${statusTable.code} IS NULL OR ${statusTable.code} = ${Offer.Status.VALID})`,\n ),\n )\n .orderBy(\n offersTable.obligationId,\n // lower ticks first for buy, higher ticks first for sell\n side === \"buy\" ? sql`${offersTable.tick} ASC` : sql`${offersTable.tick} DESC`,\n );\n\n const [bestBuys, bestSells] = await Promise.all([\n query({ side: \"buy\" }),\n query({ side: \"sell\" }),\n ]);\n\n const quotes = new Map<\n string,\n { ask: Quote.QuoteInput[\"ask\"]; bid: Quote.QuoteInput[\"bid\"] }\n >();\n\n for (const row of bestSells) {\n quotes.set(row.obligationId, {\n ask: { tick: row.tick },\n bid: { tick: null },\n });\n }\n\n for (const row of bestBuys) {\n const quote = quotes.get(row.obligationId);\n\n if (!quote) {\n quotes.set(row.obligationId, {\n ask: { tick: null },\n bid: { tick: row.tick },\n });\n continue;\n }\n\n quote.bid = { tick: row.tick };\n }\n\n return Array.from(quotes.entries())\n .map(([id, quote]) => {\n return Quote.from({ obligationId: id as Hex, ask: quote.ask, bid: quote.bid });\n })\n .sort((a, b) => {\n return a.obligationId.localeCompare(b.obligationId);\n });\n },\n };\n}\n","import { and, asc, eq, gt, gte, sql } from \"drizzle-orm\";\nimport type { Address, Hex } from \"viem\";\nimport { Maturity, Offer } from \"#core\";\nimport * as OffersDomain from \"#database/domains/Offers.ts\";\nimport {\n callbacks as callbacksTable,\n groups as groupsTable,\n lots as lotsTable,\n obligationCollateralsV2 as obligationCollateralsTable,\n obligations as obligationsTable,\n offersCallbacks as offersCallbacksTable,\n offers as offersTable,\n offsets as offsetsTable,\n oracles as oraclesTable,\n positions as positionsTable,\n} from \"#database/drizzle/schema.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport { Logger } from \"#logger/index.ts\";\nimport * as ApiSchema from \"../Schema/index.ts\";\nimport * as ApiPayload from \"./Payload.ts\";\n\nexport type GetOffersQueryParams = {\n /** Filter by maker address */\n maker?: Address;\n /** Cursor string returned by a previous call, for pagination */\n cursor?: string;\n /** Page size; defaults to {@link OffersDomain.DEFAULT_LIMIT} */\n limit?: number;\n};\n\ntype OffersRowsResult = {\n rows: OffersDomain.Row[];\n nextCursor: string | null;\n};\n\n/**\n * Query offers with computed consumed/available/takeable values.\n * @param db - The database client. {@link Database.Core}\n * @param parameters - {@link GetOffersQueryParams}\n * @returns The offers with pagination cursor.\n */\nexport async function getOffersQuery(\n db: Database.Core,\n parameters?: GetOffersQueryParams,\n): Promise<OffersRowsResult> {\n const limit = parameters?.limit ?? OffersDomain.DEFAULT_LIMIT;\n const cursor = parameters?.cursor;\n const maker = parameters?.maker;\n\n if (cursor !== null && cursor !== undefined) {\n if (!cursor.startsWith(\"0x\") || cursor.length !== 66) {\n throw new Error(\"Invalid cursor format\");\n }\n }\n\n // Subtract 1ms before flooring to keep the current second inclusive.\n const now = Math.floor((Date.now() - 1) / 1000);\n\n const collateralsLateral = db\n .select({\n collaterals: sql<Array<{ asset: string; oracle: string; lltv: string }>>`COALESCE(\n jsonb_agg(\n jsonb_build_object(\n 'asset', ${obligationCollateralsTable.asset},\n 'oracle', ${oraclesTable.address},\n 'lltv', ${obligationCollateralsTable.lltv}\n )\n ),\n '[]'::jsonb\n )`.as(\"collaterals\"),\n })\n .from(obligationCollateralsTable)\n .innerJoin(\n oraclesTable,\n sql`${obligationCollateralsTable.oracleChainId} = ${oraclesTable.chainId}\n AND ${obligationCollateralsTable.oracleAddress} = ${oraclesTable.address}`,\n )\n .where(eq(obligationCollateralsTable.obligationId, offersTable.obligationId))\n .as(\"collaterals_lateral\");\n\n const lotBalanceExpr = sql<string>`GREATEST(0, LEAST(\n COALESCE(${positionsTable.balance}, 0)::numeric\n + COALESCE((\n SELECT SUM(${offsetsTable.value}::numeric)\n FROM ${offsetsTable}\n WHERE ${offsetsTable.chainId} = ${callbacksTable.positionChainId}\n AND LOWER(${offsetsTable.contract}) = LOWER(${callbacksTable.positionContract})\n AND LOWER(${offsetsTable.user}) = LOWER(${callbacksTable.positionUser})\n ), 0)\n - COALESCE(${lotsTable.lower}::numeric, 0),\n (COALESCE(${lotsTable.upper}::numeric, 0) - COALESCE(${lotsTable.lower}::numeric, 0))\n - CASE\n WHEN ${offersTable.assets}::numeric > 0\n THEN COALESCE(${groupsTable.consumed}::numeric, 0)\n * (COALESCE(${lotsTable.upper}::numeric, 0) - COALESCE(${lotsTable.lower}::numeric, 0))\n / ${offersTable.assets}::numeric\n ELSE 0\n END\n ))`;\n\n const contributionExpr = sql<string>`CASE\n WHEN ${positionsTable.asset} IS NULL OR ${lotsTable.lower} IS NULL THEN 0\n ELSE LEAST(COALESCE(${callbacksTable.amount}::numeric, ${lotBalanceExpr}), ${lotBalanceExpr})\n END`;\n\n const availableExpr = sql<string>`COALESCE((\n SELECT SUM(deduped.contribution)\n FROM (\n SELECT DISTINCT ON (\n ${callbacksTable.positionChainId},\n LOWER(${callbacksTable.positionContract}),\n LOWER(${callbacksTable.positionUser})\n )\n ${contributionExpr} AS contribution\n FROM ${offersCallbacksTable}\n INNER JOIN ${callbacksTable} ON ${offersCallbacksTable.callbackId} = ${callbacksTable.id}\n LEFT JOIN ${positionsTable}\n ON ${positionsTable.chainId} = ${callbacksTable.positionChainId}\n AND LOWER(${positionsTable.contract}) = LOWER(${callbacksTable.positionContract})\n AND LOWER(${positionsTable.user}) = LOWER(${callbacksTable.positionUser})\n LEFT JOIN ${lotsTable}\n ON ${lotsTable.chainId} = ${callbacksTable.positionChainId}\n AND LOWER(${lotsTable.contract}) = LOWER(${callbacksTable.positionContract})\n AND LOWER(${lotsTable.user}) = LOWER(${callbacksTable.positionUser})\n AND LOWER(${lotsTable.group}) = LOWER(${offersTable.group})\n WHERE ${offersCallbacksTable.offerHash} = ${offersTable.hash}\n ORDER BY\n ${callbacksTable.positionChainId},\n LOWER(${callbacksTable.positionContract}),\n LOWER(${callbacksTable.positionUser}),\n ${contributionExpr} DESC\n ) deduped\n ), 0)`;\n\n const results = await db\n .select({\n hash: offersTable.hash,\n maker: offersTable.groupMaker,\n assets: offersTable.assets,\n obligationUnits: offersTable.obligationUnits,\n obligationShares: offersTable.obligationShares,\n consumed: groupsTable.consumed,\n tick: offersTable.tick,\n maturity: offersTable.maturity,\n expiry: offersTable.expiry,\n start: offersTable.start,\n group: offersTable.group,\n session: offersTable.session,\n buy: offersTable.buy,\n chainId: obligationsTable.chainId,\n loanToken: obligationsTable.loanToken,\n callbackAddress: offersTable.callbackAddress,\n callbackData: offersTable.callbackData,\n receiverIfMakerIsSeller: offersTable.receiverIfMakerIsSeller,\n collaterals: collateralsLateral.collaterals,\n blockNumber: offersTable.blockNumber,\n available: sql<string>`${availableExpr}::numeric`.as(\"available\"),\n takeable: sql<string>`FLOOR(GREATEST(0,\n CASE WHEN ${offersTable.buy} = false\n THEN ${offersTable.assets}::numeric - ${groupsTable.consumed}::numeric\n ELSE LEAST(\n ${offersTable.assets}::numeric - ${groupsTable.consumed}::numeric,\n ${availableExpr}::numeric\n )\n END\n ))`.as(\"takeable\"),\n })\n .from(offersTable)\n .innerJoin(obligationsTable, eq(offersTable.obligationId, obligationsTable.obligationId))\n .innerJoin(\n groupsTable,\n and(\n eq(offersTable.groupChainId, groupsTable.chainId),\n eq(offersTable.groupMaker, groupsTable.maker),\n eq(offersTable.group, groupsTable.group),\n ),\n )\n .innerJoinLateral(collateralsLateral, sql`true`)\n .where(\n and(\n cursor !== null && cursor !== undefined ? gt(offersTable.hash, cursor) : undefined,\n maker !== undefined ? eq(offersTable.groupMaker, maker.toLowerCase()) : undefined,\n gte(offersTable.expiry, now),\n gte(offersTable.maturity, now),\n maker === undefined\n ? sql`GREATEST(0,\n CASE WHEN ${offersTable.buy} = false\n THEN ${offersTable.assets}::numeric - ${groupsTable.consumed}::numeric\n ELSE LEAST(\n ${offersTable.assets}::numeric - ${groupsTable.consumed}::numeric,\n ${availableExpr}::numeric\n )\n END\n ) > 0`\n : undefined,\n ),\n )\n .orderBy(asc(offersTable.hash))\n .limit(limit);\n\n const rows: OffersRowsResult[\"rows\"] = results.map((row) => {\n const receiverIfMakerIsSeller = (\n row.receiverIfMakerIsSeller ?? row.maker\n ).toLowerCase() as Address;\n return {\n hash: row.hash as Hex,\n maker: row.maker as Address,\n assets: BigInt(row.assets),\n obligationUnits: BigInt(row.obligationUnits),\n obligationShares: BigInt(row.obligationShares),\n tick: row.tick,\n maturity: Maturity.from(row.maturity),\n expiry: row.expiry,\n start: row.start,\n group: row.group as Hex,\n session: row.session as Hex,\n buy: row.buy,\n chainId: row.chainId,\n loanToken: row.loanToken as Address,\n collaterals: row.collaterals\n .map((c) => ({\n asset: c.asset as Address,\n oracle: c.oracle as Address,\n lltv: BigInt(c.lltv) as Offer.OfferInput[\"collaterals\"][number][\"lltv\"],\n }))\n .sort((a, b) => a.asset.toLowerCase().localeCompare(b.asset.toLowerCase())),\n callback: {\n address: row.callbackAddress as Address,\n data: row.callbackData as Hex,\n },\n receiverIfMakerIsSeller,\n consumed: BigInt(row.consumed),\n available: BigInt(String(row.available ?? \"0\").split(\".\")[0] ?? \"0\"),\n takeable: BigInt(String(row.takeable ?? \"0\").split(\".\")[0] ?? \"0\"),\n blockNumber: row.blockNumber,\n };\n });\n\n const nextCursor = rows.length === limit ? rows[rows.length - 1]!.hash : null;\n return { rows, nextCursor };\n}\n\nexport async function getOffers(\n queryParameters: object,\n db: Database.Database,\n): Promise<ApiPayload.Payload<ApiSchema.OfferResponse.OfferResponse[]>> {\n const logger = Logger.getLogger();\n\n const result = ApiSchema.safeParse(\"get_offers\", queryParameters, (issue) => issue.message);\n\n if (!result.success) return ApiPayload.failure(result.error);\n const query = result.data;\n\n try {\n const { rows, nextCursor }: OffersRowsResult = query.maker\n ? await getOffersQuery(db, {\n maker: query.maker,\n cursor: query.cursor,\n limit: query.limit,\n })\n : await db.book.getOffers({\n side: query.side!,\n obligationId: query.obligation_id!,\n cursor: query.cursor,\n limit: query.limit,\n });\n\n const hashes = rows.map((row) => row.hash);\n const attestationMap = await db.trees.getAttestations(hashes);\n\n return ApiPayload.success({\n data: rows.map((row) => {\n const hash = Offer.hash(row);\n const attestation = attestationMap.get(hash);\n return ApiSchema.OfferResponse.from({\n ...row,\n ...attestation,\n });\n }),\n cursor: nextCursor ?? null,\n });\n } catch (err) {\n logger.error({\n err,\n msg: \"Error get offers\",\n errorMessage: err instanceof Error ? err.message : String(err),\n errorStack: err instanceof Error ? err.stack : undefined,\n });\n\n return ApiPayload.failure(err);\n }\n}\n","import type { Database } from \"#database/index.ts\";\nimport { Logger } from \"#logger/index.ts\";\nimport * as ApiSchema from \"../Schema/index.ts\";\nimport * as ApiPayload from \"./Payload.ts\";\n\n/**\n * Get positions for a user with remaining balance calculation.\n * @param queryParameters - Request parameters including user address and pagination.\n * @param db - Database instance.\n * @returns Paginated list of positions with remaining balances.\n */\nexport async function getUserPositions(\n queryParameters: object,\n db: Database.Database,\n): Promise<ApiPayload.Payload<ApiSchema.PositionResponse.PositionResponse[]>> {\n const logger = Logger.getLogger();\n\n const result = ApiSchema.safeParse(\n \"get_user_positions\",\n queryParameters,\n (issue) => issue.message,\n );\n\n if (!result.success) return ApiPayload.failure(result.error);\n const query = result.data;\n\n try {\n const { positions, nextCursor } = await db.positions.getByUser({\n user: query.user_address,\n cursor: query.cursor,\n limit: query.limit,\n });\n\n return ApiPayload.success({\n data: positions.map((position) => ApiSchema.PositionResponse.from(position)),\n cursor: nextCursor ?? null,\n });\n } catch (err) {\n logger.error({\n err,\n msg: \"Error get user positions\",\n errorMessage: err instanceof Error ? err.message : String(err),\n errorStack: err instanceof Error ? err.stack : undefined,\n });\n\n return ApiPayload.failure(err);\n }\n}\n","import type { Hex } from \"viem\";\nimport { Offer, Tree } from \"#core\";\nimport type { Gatekeeper } from \"#gatekeeper/Gatekeeper.ts\";\nimport { Logger } from \"#logger/index.ts\";\nimport * as ApiSchema from \"../Schema/index.ts\";\nimport * as ApiPayload from \"./Payload.ts\";\n\nexport type ValidationIssue = {\n index: number;\n rule: string;\n message: string;\n};\n\ntype ValidateOffersSuccessPayload = ApiPayload.SuccessPayload<{\n payload: Hex;\n root: Hex;\n}>;\n\ntype ValidateOffersIssuesPayload = ApiPayload.SuccessPayload<{\n issues: ValidationIssue[];\n}>;\n\ntype ValidateOffersResponse = ValidateOffersSuccessPayload | ValidateOffersIssuesPayload;\ntype OfferInput = Parameters<typeof Offer.fromSnakeCase>[0];\n\nexport async function validateOffers(\n body: object,\n gatekeeper: Gatekeeper,\n): Promise<ValidateOffersResponse | ApiPayload.ErrorPayload> {\n const logger = Logger.getLogger();\n\n const result = ApiSchema.safeParse(\"validate_offers\", body, (issue) => issue.message);\n if (!result.success)\n return ApiPayload.failure(\n new ApiPayload.BadRequestError(result.error.issues[0]?.message ?? \"Invalid request body\"),\n );\n const { offers: rawOffers } = result.data;\n const parsedOffers: Offer.Offer[] = [];\n const offerIndexByHash = new Map<Hex, number>();\n\n for (let i = 0; i < rawOffers.length; i++) {\n const rawOffer = rawOffers[i] as OfferInput;\n try {\n const offer = Offer.fromSnakeCase(rawOffer);\n const hash = Offer.hash(offer);\n if (!offerIndexByHash.has(hash)) {\n offerIndexByHash.set(hash, i);\n parsedOffers.push(offer);\n }\n } catch (err) {\n let message = err instanceof Error ? err.message : String(err);\n if (err instanceof Offer.InvalidOfferError) {\n message = err.formattedMessage;\n }\n return ApiPayload.failure(\n new ApiPayload.BadRequestError(`Offer at index ${i} failed to parse: ${message}`),\n );\n }\n }\n\n try {\n const { issues } = await gatekeeper.isAllowed(parsedOffers);\n\n if (issues.length > 0) {\n const mappedIssues = issues\n .map((issue): ValidationIssue | null => {\n const index = offerIndexByHash.get(Offer.hash(issue.item));\n if (index === undefined) return null;\n return { index, rule: issue.ruleName, message: issue.message };\n })\n .filter((issue): issue is ValidationIssue => issue !== null);\n\n return ApiPayload.success({\n data: { issues: mappedIssues },\n cursor: null,\n });\n }\n\n const tree = Tree.from(parsedOffers);\n const payload = Tree.encodeUnsigned(tree);\n return ApiPayload.success({\n data: { payload, root: tree.root },\n cursor: null,\n });\n } catch (err) {\n logger.error({\n err,\n msg: \"Error validating offers\",\n errorMessage: err instanceof Error ? err.message : String(err),\n errorStack: err instanceof Error ? err.stack : undefined,\n });\n return ApiPayload.failure(err);\n }\n}\n","export * from \"./getBook.ts\";\nexport * from \"./getConfigContracts.ts\";\nexport * from \"./getConfigRules.ts\";\nexport * from \"./getDocs.ts\";\nexport * from \"./getHealth.ts\";\nexport * from \"./getObligation.ts\";\nexport * from \"./getObligations.ts\";\nexport * from \"./getOffers.ts\";\nexport * from \"./getUserPositions.ts\";\nexport * from \"./validateOffers.ts\";\n","import { serve as serveHono } from \"@hono/node-server\";\nimport { SpanStatusCode } from \"@opentelemetry/api\";\nimport { type Context, Hono } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport type * as ChainRegistry from \"#core/ChainRegistry.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport type { GatekeeperClient } from \"#gatekeeper/Client.ts\";\nimport { Tracer } from \"#tracer/index.ts\";\nimport * as Controllers from \"./Controllers/index.ts\";\nimport * as ApiPayload from \"./Controllers/Payload.ts\";\n\nexport type RouterApi = {\n serve: () => void;\n};\n\nexport type ApiConfig = {\n db: Database.Database;\n gatekeeper: GatekeeperClient;\n port: number;\n chainRegistry: ChainRegistry.ChainRegistry;\n};\n\nexport function from(config: ApiConfig): RouterApi {\n const { db, gatekeeper, port, chainRegistry } = config;\n\n return create({\n port,\n db,\n gatekeeper,\n chainRegistry,\n });\n}\n\ntype CreateParameters = {\n db: Database.Database;\n gatekeeper: GatekeeperClient;\n port: number;\n chainRegistry: ChainRegistry.ChainRegistry;\n};\n\nexport function create(params: CreateParameters): RouterApi {\n return {\n serve: () => serve(params),\n };\n}\n\n/**\n * Start a local router server.\n * @example\n * ```ts\n * import { RouterApi } from \"@morpho-dev/router\";\n * RouterApi.serve({ port: 8081 }); // local router API server running on http://localhost:8081\n * ```\n */\nfunction serve(parameters: CreateParameters) {\n const { db, gatekeeper, chainRegistry } = parameters;\n const tracer = Tracer.getTracer(\"router.api\");\n\n const app = new Hono();\n app.use(\"*\", cors());\n\n app.use(\"*\", async (c: Context, next) => {\n const {\n req: { path, method },\n } = c;\n\n const spanName = `${method} ${path}`;\n\n return Tracer.startActiveSpan(tracer, spanName, async (span) => {\n const res = await next();\n\n span.setAttribute(\"http.method\", method);\n span.setAttribute(\"http.target\", path);\n span.setAttribute(\"http.route\", path);\n span.setAttribute(\"http.status_code\", c.res.status);\n\n if (c.res.status >= 500) {\n span.setStatus({ code: SpanStatusCode.ERROR });\n }\n\n return res;\n });\n });\n\n app.get(\"/v1/offers\", async (c: Context) => {\n const { statusCode, body } = await Controllers.getOffers(c.req.query(), db);\n return c.json(body, statusCode);\n });\n\n app.get(\"/v1/obligations\", async (c: Context) => {\n const { statusCode, body } = await Controllers.getObligations(c.req.query(), db);\n return c.json(body, statusCode);\n });\n\n app.get(\"/v1/obligations/:obligationId\", async (c: Context) => {\n const id = c.req.param(\"obligationId\");\n const { statusCode, body } = await Controllers.getObligation({ obligation_id: id }, db);\n return c.json(body, statusCode);\n });\n\n app.get(\"/v1/books/:obligationId/:side\", async (c: Context) => {\n const q = c.req.query();\n const { statusCode, body } = await Controllers.getBook(\n {\n obligation_id: c.req.param(\"obligationId\"),\n side: c.req.param(\"side\"),\n cursor: q.cursor,\n limit: q.limit,\n },\n db,\n );\n return c.json(body, statusCode);\n });\n\n app.post(\"/v1/validate\", async (c: Context) => {\n try {\n const reqBody = await c.req.json();\n const { statusCode, body } = await gatekeeper.validate(reqBody);\n return c.json(body, statusCode as ApiPayload.STATUS_CODE);\n } catch (err) {\n const failure = ApiPayload.failure(err);\n return c.json(failure.body, failure.statusCode);\n }\n });\n\n app.get(\"/v1/users/:userAddress/positions\", async (c: Context) => {\n const query = c.req.query();\n const { statusCode, body } = await Controllers.getUserPositions(\n { user_address: c.req.param(\"userAddress\"), cursor: query.cursor, limit: query.limit },\n db,\n );\n return c.json(body, statusCode);\n });\n\n app.get(\"/v1/health\", async (c: Context) => {\n const { statusCode, body } = await Controllers.getHealth(c.req.query(), db, chainRegistry);\n return c.json(body, statusCode);\n });\n\n app.get(\"/v1/health/collectors\", async (c: Context) => {\n const { statusCode, body } = await Controllers.getHealthCollectors(\n c.req.query(),\n db,\n chainRegistry,\n );\n return c.json(body, statusCode);\n });\n\n app.get(\"/v1/health/chains\", async (c: Context) => {\n const { statusCode, body } = await Controllers.getHealthChains(\n c.req.query(),\n db,\n undefined,\n chainRegistry,\n );\n return c.json(body, statusCode);\n });\n\n app.get(\"/v1/config/contracts\", async (c: Context) => {\n const { statusCode, body } = await Controllers.getConfigContracts(c.req.query(), chainRegistry);\n return c.json(body, statusCode);\n });\n\n app.get(\"/v1/config/rules\", async (c: Context) => {\n try {\n const { statusCode, body } = await gatekeeper.getConfigRules(c.req.query());\n return c.json(body, statusCode as ApiPayload.STATUS_CODE);\n } catch (err) {\n const failure = ApiPayload.failure(err);\n return c.json(failure.body, failure.statusCode);\n }\n });\n\n app.get(\"/docs/openapi\", async (c: Context) =>\n c.text(JSON.stringify(await Controllers.getSwaggerJson()), 200, {\n \"Content-Type\": \"application/json; charset=utf-8\",\n }),\n );\n app.get(\"/docs/api\", async (c: Context) => c.html(await Controllers.getDocsHtml(), 200));\n app.get(\"/docs\", async (c: Context) => c.html(await Controllers.getIntegratorDocsHtml(), 200));\n\n serveHono({\n fetch: app.fetch,\n port: parameters.port,\n });\n}\n","export * from \"./Api.ts\";\nexport * as Controllers from \"./Controllers/index.ts\";\nexport * from \"./Schema/index.ts\";\n","import createOpenApiFetchClient, { type Client as OpenApiFetchClient } from \"openapi-fetch\";\nimport type { Address, Hex } from \"viem\";\nimport { type Compute, Maturity, Obligation, Offer, Quote } from \"#core\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport type * as GeneratedApiSchema from \"../api/Schema/generated/swagger.d.ts\";\n\ntype RouterClientConfig = {\n /** The URL of the router. */\n readonly url: URL;\n /** The default headers to use for each request. */\n readonly headers: Headers;\n};\n\nexport type Client = Compute<\n RouterClientConfig & {\n /**\n * Get offers from the router.\n * @param parameters - {@link getOffers.Parameters}\n * @returns The offers with pagination cursor. {@link getOffers.ReturnType}\n * @throws If the request fails - {@link getOffers.ErrorType}\n *\n * @example\n * ```ts\n * const router = RouterClient.connect({ url: \"https://router.morpho.dev\" });\n * const { offers, cursor } = await router.getOffers({ side: \"buy\", obligationId: \"0xa1c...d2f\" });\n * console.log(offers);\n * ```\n */\n getOffers: (parameters: getOffers.Parameters) => Promise<getOffers.ReturnType>;\n\n /**\n * Get obligations from the router.\n * @param parameters - {@link getObligations.Parameters}\n * @returns The obligations with pagination cursor. {@link getObligations.ReturnType}\n * @throws If the request fails - {@link getObligations.ErrorType}\n *\n * @example\n * ```ts\n * const router = RouterClient.connect({ url: \"https://router.morpho.dev\" });\n * const { obligations, cursor } = await router.getObligations();\n * console.log(obligations[0].id()); // 0x123...456\n * ```\n */\n getObligations: (parameters?: getObligations.Parameters) => Promise<getObligations.ReturnType>;\n }\n>;\n\nexport type ConnectOptions = {\n /** The URL of the router to interact with.\n * @default \"https://router.morpho.dev\"\n */\n url?: string;\n /** The API key to use for the router API. */\n apiKey?: string;\n /** The default headers to use for each request. */\n headers?: Headers;\n};\n\n/**\n * Creates an instance of a router client.\n * @constructor\n * @param parameters - {@link connect.Parameters}\n * @returns A Router Client. {@link connect.ReturnType}\n *\n * @example\n * ```typescript\n * const router = RouterClient.connect({ url: \"https://router.morpho.dev\" });\n * ```\n */\nexport function connect(parameters?: connect.Parameters): connect.ReturnType {\n const u = new URL(parameters?.url || \"https://router.morpho.dev\");\n if (u.protocol !== \"http:\" && u.protocol !== \"https:\") throw new InvalidUrlError(u.toString());\n\n const headers = parameters?.headers ?? new Headers();\n headers.set(\"Content-Type\", \"application/json\");\n parameters?.apiKey !== undefined ? headers.set(\"X-API-Key\", parameters.apiKey) : null;\n\n const config: RouterClientConfig = { url: u, headers };\n\n const apiClient = createOpenApiFetchClient<GeneratedApiSchema.paths>({\n baseUrl: config.url.toString(),\n headers: config.headers,\n querySerializer: { array: { style: \"form\", explode: false } },\n });\n\n return {\n ...config,\n getOffers: (parameters) => getOffers(apiClient, parameters),\n getObligations: (parameters) => getObligations(apiClient, parameters),\n };\n}\n\nexport declare namespace connect {\n export type Parameters = ConnectOptions;\n export type ReturnType = Client;\n export type ErrorType = InvalidUrlError;\n}\n\nexport async function getOffers(\n apiClient: OpenApiFetchClient<GeneratedApiSchema.paths>,\n parameters: getOffers.Parameters,\n): Promise<getOffers.ReturnType> {\n const { data, error, response } = await apiClient.GET(\"/v1/offers\", {\n params: {\n query: {\n side: parameters.side,\n obligation_id: parameters.obligationId,\n cursor: parameters.cursor,\n limit: parameters.limit,\n },\n },\n });\n\n if (error !== undefined) {\n switch (response.status) {\n case 401:\n throw new HttpUnauthorizedError();\n case 403:\n throw new HttpForbiddenError();\n case 429:\n throw new HttpRateLimitError();\n }\n throw new HttpGetApiFailedError(`GET request returned ${response.status}`, {\n details: JSON.stringify(error),\n });\n }\n\n const offers =\n data?.data.map((item) => {\n const { root, proof, signature, offer: offerData } = item;\n // Transform new API structure (with nested offer object) to Offer.fromSnakeCase format\n const offer = Offer.fromSnakeCase({\n maker: offerData.maker as Address,\n assets: offerData.assets,\n obligation_units: offerData.obligation_units,\n obligation_shares: offerData.obligation_shares,\n tick: offerData.tick,\n maturity: Maturity.from(offerData.obligation.maturity),\n expiry: offerData.expiry,\n start: offerData.start,\n group: offerData.group,\n session: offerData.session as Hex,\n buy: offerData.buy,\n chain_id: item.chain_id as Offer.Offer[\"chainId\"],\n loan_token: offerData.obligation.loan_token as Address,\n collaterals: offerData.obligation.collaterals.map((collateral) => ({\n asset: collateral.token as Address,\n oracle: collateral.oracle as Address,\n lltv: collateral.lltv,\n })),\n callback: {\n address: offerData.callback as Address,\n data: offerData.callback_data as Hex,\n },\n receiver_if_maker_is_seller: offerData.receiver_if_maker_is_seller as Address | undefined,\n });\n\n return {\n ...offer,\n hash: item.offer_hash as Hex,\n consumed: BigInt(item.consumed),\n takeable: BigInt(item.takeable),\n blockNumber: Number(item.block_number),\n root: (root as Hex) || undefined,\n proof: (proof as Hex[]) || undefined,\n signature: signature ? (signature as Hex) : undefined,\n };\n }) ?? [];\n\n return {\n cursor: data?.cursor ?? null,\n offers,\n };\n}\n\nexport declare namespace getOffers {\n export type Parameters = {\n /** The desired side of the match: 'buy' if you want to buy, 'sell' if you want to sell */\n side: \"buy\" | \"sell\";\n /** The offers obligation id */\n obligationId: Hex;\n /** Pagination cursor in base64url-encoded format */\n cursor?: string;\n /** Maximum number of offers to return. @default 20 */\n limit?: number;\n };\n\n export type ReturnType = {\n offers: Compute<\n Offer.Offer & {\n hash: Hex;\n blockNumber: number;\n consumed: bigint;\n takeable: bigint;\n } & {\n /** 32-byte merkle root. */\n root?: Hex;\n /** Sibling hashes for the merkle proof. */\n proof?: Hex[];\n /** Offer signature from the Merkle tree. */\n signature?: Hex;\n }\n >[];\n /** The pagination cursor. */\n cursor: string | null;\n };\n\n export type ErrorType = GetApiErrorType;\n}\n\nexport async function getObligations(\n apiClient: OpenApiFetchClient<GeneratedApiSchema.paths>,\n parameters?: getObligations.Parameters,\n): Promise<getObligations.ReturnType> {\n const sort = parameters?.sort?.length ? parameters.sort.join(\",\") : undefined;\n\n const { data, error, response } = await apiClient.GET(\"/v1/obligations\", {\n params: {\n query: {\n cursor: parameters?.cursor,\n limit: parameters?.limit,\n chains: parameters?.chainIds,\n loan_tokens: parameters?.loanTokens,\n collateral_tokens: parameters?.collateralTokens,\n maturities: parameters?.maturities,\n sort,\n },\n },\n });\n\n if (error !== undefined) {\n switch (response.status) {\n case 401:\n throw new HttpUnauthorizedError();\n case 403:\n throw new HttpForbiddenError();\n case 429:\n throw new HttpRateLimitError();\n }\n throw new HttpGetApiFailedError(`GET request returned ${response.status}`, {\n details: JSON.stringify(error),\n });\n }\n\n const obligations =\n data?.data.map((item) => {\n const obligation = Obligation.fromSnakeCase({\n chain_id: item.chain_id,\n loan_token: item.loan_token as Address,\n collaterals: item.collaterals.map((collateral) => ({\n asset: collateral.token as Address,\n oracle: collateral.oracle as Address,\n lltv: collateral.lltv,\n })),\n maturity: Maturity.from(item.maturity),\n });\n\n const { obligationId: _, ...returned } = {\n id: () => Obligation.id(obligation),\n ...obligation,\n ...Quote.from({\n obligationId: item.id as Hex,\n ask: { tick: item.ask.tick },\n bid: { tick: item.bid.tick },\n }),\n };\n return returned;\n }) ?? [];\n\n return {\n cursor: data?.cursor ?? null,\n obligations,\n };\n}\n\nexport declare namespace getObligations {\n export type SortField = \"id\" | \"ask\" | \"bid\" | \"maturity\";\n export type SortEntry = SortField | `-${SortField}`;\n\n export type Parameters = {\n /** Pagination cursor in base64url-encoded format. */\n cursor?: string;\n /** Maximum number of obligations to return. @default 20 */\n limit?: number;\n /** Filter by chain IDs (comma-separated). */\n chainIds?: number[];\n /** Filter by loan token addresses (comma-separated). */\n loanTokens?: Address[];\n /** Filter by collateral tokens (comma-separated, matches any collateral). */\n collateralTokens?: Address[];\n /** Filter by exact maturity timestamps (comma-separated, unix seconds). */\n maturities?: number[];\n /** Sort order entries in priority order. Prefix with '-' for descending. Max 3 fields. */\n sort?: SortEntry[];\n };\n\n export type ReturnType = {\n obligations: Compute<\n {\n /** The obligation id. Uses {@link Obligation.id} to calculate the id.*/\n id: () => Hex;\n } & Obligation.Obligation &\n Omit<Quote.Quote, \"obligationId\">\n >[];\n /** The pagination cursor. */\n cursor: string | null;\n };\n\n export type ErrorType = GetApiErrorType;\n}\n\ntype GetApiErrorType =\n | HttpGetApiFailedError\n | HttpUnauthorizedError\n | HttpForbiddenError\n | HttpRateLimitError;\n\nexport class InvalidUrlError extends Errors.BaseError {\n override name = \"Router.InvalidUrlError\";\n constructor(url: string) {\n super(`URL \"${url}\" is not http/https.`);\n }\n}\n\nexport class HttpUnauthorizedError extends Errors.BaseError {\n override name = \"Router.HttpUnauthorizedError\";\n constructor() {\n super(\"Unauthorized.\", {\n metaMessages: [\"Ensure that an API key is provided.\"],\n });\n }\n}\n\nexport class HttpForbiddenError extends Errors.BaseError {\n override name = \"Router.HttpForbiddenError\";\n constructor() {\n super(\"Forbidden.\", {\n metaMessages: [\"Ensure that the API key is valid.\"],\n });\n }\n}\n\nexport class HttpRateLimitError extends Errors.BaseError {\n override name = \"Router.HttpRateLimitError\";\n constructor() {\n super(\"Rate limit exceeded.\", {\n metaMessages: [\n \"The number of allowed requests has been exceeded. You must wait for the rate limit to reset.\",\n ],\n });\n }\n}\n\nexport class HttpGetApiFailedError extends Errors.BaseError {\n override name = \"Router.HttpGetApiFailedError\";\n constructor(message: string, { details }: { details?: string } = {}) {\n super(message, {\n metaMessages: [details],\n });\n }\n}\n","export * from \"./schema.ts\";\nexport * from \"./VERSION.ts\";\n","import { and, asc, eq, gt, gte, lte, sql } from \"drizzle-orm\";\nimport type * as Chain from \"#core/Chain.ts\";\nimport type * as ChainRegistry from \"#core/ChainRegistry.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport * as Collector from \"#indexer/collectors/Collector.ts\";\nimport { chains, collectors } from \"../drizzle/schema.ts\";\n\nexport type ChainState = {\n chainId: Chain.Id;\n blockNumber: number;\n epoch: bigint;\n};\n\nexport type CollectorState = {\n collectorName: Collector.Name;\n chainId: Chain.Id;\n blockNumber: number;\n epoch: bigint;\n};\n\nexport type ChainSnapshot = ChainState & {\n updatedAt: Date;\n};\n\nexport type CollectorSnapshot = CollectorState & {\n updatedAt: Date;\n};\n\nexport type InitParameters = {\n chainId: Chain.Id;\n collectorName: Collector.Name;\n};\n\nexport type AdvanceChainParameters = {\n chainId: Chain.Id;\n blockNumber: number;\n epoch: bigint;\n};\n\nexport type AdvanceCollectorParameters = {\n collectorName: Collector.Name;\n chainId: Chain.Id;\n blockNumber: number;\n epoch: bigint;\n};\n\nexport type HandleReorgParameters = {\n chainId: Chain.Id;\n blockNumber: number;\n epoch: bigint;\n collectorNames?: Collector.Name[];\n};\n\nexport type BlocksDomain = {\n /** Initialize and return chain + collector state, seeding rows when missing. */\n init: (parameters: InitParameters) => Promise<{\n chain: ChainState;\n collector: CollectorState;\n }>;\n /** Return chain state, failing if it has not been initialized yet. */\n getChain: (chainId: Chain.Id) => Promise<ChainState>;\n /** Return collector state, failing if it has not been initialized yet. */\n getCollector: (parameters: {\n chainId: Chain.Id;\n collectorName: Collector.Name;\n }) => Promise<CollectorState>;\n /** Return chain state rows, optionally filtered by chain id. */\n getChains: (parameters?: { chainId?: Chain.Id }) => Promise<ChainSnapshot[]>;\n /** Return collector state rows, optionally filtered by chain id. */\n getCollectors: (parameters?: { chainId?: Chain.Id }) => Promise<CollectorSnapshot[]>;\n /** Persist chain block state updates. */\n advanceChain: (parameters: AdvanceChainParameters) => Promise<void>;\n /** Persist collector block state updates and enforce invariants via storage CAS. */\n advanceCollector: (parameters: AdvanceCollectorParameters) => Promise<void>;\n /** Apply a reorg by advancing the chain epoch and fencing collectors. */\n handleReorg: (parameters: HandleReorgParameters) => Promise<void>;\n};\n\n/** Postgres implementation. */\nexport const create = (config: {\n db: Database.Core;\n chainRegistry: ChainRegistry.ChainRegistry;\n}): BlocksDomain => {\n const { db, chainRegistry } = config;\n\n const getChain = async (chainId: Chain.Id): Promise<ChainState> => {\n const rows = await db\n .select({\n chainId: chains.chainId,\n blockNumber: chains.blockNumber,\n epoch: chains.epoch,\n })\n .from(chains)\n .where(eq(chains.chainId, chainId))\n .limit(1);\n\n if (rows.length === 0) {\n throw new Error(`Chain state not initialized for chain ${chainId}. Call blocks.init first.`);\n }\n\n const row = rows[0]!;\n return {\n chainId: row.chainId,\n blockNumber: Number(row.blockNumber),\n epoch: BigInt(row.epoch),\n };\n };\n\n const getCollector = async (parameters: {\n chainId: Chain.Id;\n collectorName: Collector.Name;\n }): Promise<CollectorState> => {\n const name = parameters.collectorName.toLowerCase() as Collector.Name;\n\n const rows = await db\n .select({\n collectorName: collectors.name,\n chainId: collectors.chainId,\n blockNumber: collectors.blockNumber,\n epoch: collectors.epoch,\n })\n .from(collectors)\n .where(and(eq(collectors.chainId, parameters.chainId), eq(collectors.name, name)))\n .limit(1);\n\n if (rows.length === 0) {\n throw new Error(\n `Collector state not initialized for ${name} on chain ${parameters.chainId}. Call blocks.init first.`,\n );\n }\n\n const row = rows[0]!;\n return {\n collectorName: row.collectorName.toLowerCase() as Collector.Name,\n chainId: row.chainId,\n blockNumber: Number(row.blockNumber),\n epoch: BigInt(row.epoch),\n };\n };\n\n const getChains = async (parameters?: { chainId?: Chain.Id }): Promise<ChainSnapshot[]> => {\n const rows = await db\n .select({\n chainId: chains.chainId,\n blockNumber: chains.blockNumber,\n epoch: chains.epoch,\n updatedAt: chains.updatedAt,\n })\n .from(chains)\n .where(parameters?.chainId !== undefined ? eq(chains.chainId, parameters.chainId) : sql`TRUE`)\n .orderBy(asc(chains.chainId));\n\n return rows.map((row) => ({\n chainId: row.chainId,\n blockNumber: Number(row.blockNumber),\n epoch: BigInt(row.epoch),\n updatedAt: row.updatedAt,\n }));\n };\n\n const getCollectors = async (parameters?: {\n chainId?: Chain.Id;\n }): Promise<CollectorSnapshot[]> => {\n const rows = await db\n .select({\n collectorName: collectors.name,\n chainId: collectors.chainId,\n blockNumber: collectors.blockNumber,\n epoch: collectors.epoch,\n updatedAt: collectors.updatedAt,\n })\n .from(collectors)\n .where(\n parameters?.chainId !== undefined ? eq(collectors.chainId, parameters.chainId) : sql`TRUE`,\n )\n .orderBy(asc(collectors.chainId), asc(collectors.name));\n\n return rows.map((row) => ({\n collectorName: row.collectorName.toLowerCase() as Collector.Name,\n chainId: row.chainId,\n blockNumber: Number(row.blockNumber),\n epoch: BigInt(row.epoch),\n updatedAt: row.updatedAt,\n }));\n };\n\n const init = async (\n parameters: InitParameters,\n ): Promise<{\n chain: ChainState;\n collector: CollectorState;\n }> => {\n const name = parameters.collectorName.toLowerCase() as Collector.Name;\n const deploymentBlock =\n chainRegistry.getById(parameters.chainId)?.custom?.mempool.blockCreated ?? 0;\n\n const { chain, collector } = await db.transaction(async (dbTx) => {\n const chainRows = await dbTx\n .insert(chains)\n .values({\n chainId: parameters.chainId,\n blockNumber: deploymentBlock,\n })\n .onConflictDoUpdate({\n target: chains.chainId,\n set: {\n blockNumber: sql`${chains.blockNumber}`,\n epoch: sql`${chains.epoch}`,\n },\n })\n .returning();\n\n if (chainRows.length === 0) {\n throw new Error(`Failed to initialize chain state for chain ${parameters.chainId}`);\n }\n\n const collectorRows = await dbTx\n .insert(collectors)\n .values({\n chainId: parameters.chainId,\n name,\n blockNumber: deploymentBlock,\n })\n .onConflictDoUpdate({\n target: [collectors.chainId, collectors.name],\n set: {\n blockNumber: sql`${collectors.blockNumber}`,\n epoch: sql`${collectors.epoch}`,\n },\n })\n .returning();\n\n if (collectorRows.length === 0) {\n throw new Error(\n `Failed to initialize collector state for ${name} on chain ${parameters.chainId}`,\n );\n }\n\n const chainRow = chainRows[0]!;\n const collectorRow = collectorRows[0]!;\n\n return {\n chain: {\n chainId: chainRow.chainId,\n blockNumber: Number(chainRow.blockNumber),\n epoch: BigInt(chainRow.epoch),\n },\n collector: {\n collectorName: collectorRow.name.toLowerCase() as Collector.Name,\n chainId: collectorRow.chainId,\n blockNumber: Number(collectorRow.blockNumber),\n epoch: BigInt(collectorRow.epoch),\n },\n };\n });\n\n return { chain, collector };\n };\n\n const advanceChain = async (parameters: AdvanceChainParameters): Promise<void> => {\n if (parameters.blockNumber < 0) throw new Error(\"Block number cannot be negative\");\n if (parameters.epoch < 0n) throw new Error(\"Epoch cannot be negative\");\n const rows = await db\n .update(chains)\n .set({\n blockNumber: parameters.blockNumber,\n epoch: parameters.epoch.toString(),\n updatedAt: sql`now()`,\n })\n .where(eq(chains.chainId, parameters.chainId))\n .returning();\n\n if (rows.length === 0) {\n throw new Error(\n `Chain state not initialized for chain ${parameters.chainId}. Call blocks.init first.`,\n );\n }\n };\n\n const advanceCollector = async (parameters: AdvanceCollectorParameters): Promise<void> => {\n if (parameters.blockNumber < 0) throw new Error(\"Block number cannot be negative\");\n if (parameters.epoch < 0n) throw new Error(\"Epoch cannot be negative\");\n const name = parameters.collectorName.toLowerCase() as Collector.Name;\n\n const chain = db\n .select({\n chainId: chains.chainId,\n currentEpoch: chains.epoch,\n currentBlockNumber: chains.blockNumber,\n })\n .from(chains)\n .where(eq(chains.chainId, parameters.chainId))\n .as(\"chain\");\n\n const hasReorgHappened =\n (\n await db\n .select()\n .from(collectors)\n .leftJoin(chain, eq(collectors.chainId, chain.chainId))\n .where(\n and(\n eq(collectors.chainId, parameters.chainId),\n eq(collectors.name, name),\n gt(chain.currentEpoch, collectors.epoch),\n eq(chain.currentEpoch, parameters.epoch.toString()),\n gte(collectors.blockNumber, parameters.blockNumber),\n ),\n )\n .limit(1)\n ).length > 0;\n\n const rows = await db\n .update(collectors)\n .set({\n blockNumber: parameters.blockNumber,\n epoch: parameters.epoch.toString(),\n updatedAt: sql`now()`,\n })\n .from(chain)\n .where(\n and(\n eq(collectors.chainId, parameters.chainId),\n eq(collectors.name, name),\n eq(chain.currentEpoch, parameters.epoch.toString()),\n gte(chain.currentBlockNumber, parameters.blockNumber),\n // ensures that block numbers are strictly increasing unless a reorg advanced the epoch\n ...(hasReorgHappened ? [] : [lte(collectors.blockNumber, parameters.blockNumber)]),\n ),\n )\n .returning();\n\n if (rows.length > 0) return;\n\n const chainRows = await db\n .select({ chainId: chains.chainId })\n .from(chains)\n .where(eq(chains.chainId, parameters.chainId))\n .limit(1);\n\n if (chainRows.length === 0) {\n throw new Error(\n `Chain state not initialized for chain ${parameters.chainId}. Call blocks.init first.`,\n );\n }\n\n const collectorRows = await db\n .select({ chainId: collectors.chainId })\n .from(collectors)\n .where(and(eq(collectors.chainId, parameters.chainId), eq(collectors.name, name)))\n .limit(1);\n\n if (collectorRows.length === 0) {\n throw new Error(\n `Collector state not initialized for ${name} on chain ${parameters.chainId}. Call blocks.init first.`,\n );\n }\n\n throw new Error(\n `A chain reorg has happened on chain ${parameters.chainId}, update of the collector ${name} is aborted`,\n );\n };\n\n const handleReorg = async (parameters: HandleReorgParameters): Promise<void> => {\n if (parameters.blockNumber < 0) throw new Error(\"Block number cannot be negative\");\n if (parameters.epoch < 0n) throw new Error(\"Epoch cannot be negative\");\n const { chainId, blockNumber, epoch } = parameters;\n const collectorNames = parameters.collectorNames ?? Collector.names;\n\n await advanceChain({ chainId, blockNumber, epoch });\n\n const collectorStates = await Promise.all(\n collectorNames.map(async (collectorName) => {\n const { blockNumber, epoch } = await getCollector({ chainId, collectorName });\n return { collectorName, blockNumber, epoch };\n }),\n );\n\n await Promise.all(\n collectorStates.map(({ collectorName, blockNumber }) =>\n advanceCollector({\n collectorName,\n chainId,\n blockNumber: Math.min(blockNumber, parameters.blockNumber),\n epoch: parameters.epoch,\n }),\n ),\n );\n };\n\n return {\n init,\n getChain,\n getCollector,\n getChains,\n getCollectors,\n advanceChain,\n advanceCollector,\n handleReorg,\n };\n};\n","import { sql } from \"drizzle-orm\";\nimport { type Address, type Hex, isHex } from \"viem\";\nimport { type Chain, Offer } from \"#core\";\nimport type { Database } from \"#database/index.ts\";\nimport { Logger } from \"#logger/index.ts\";\nimport {\n callbacks as callbacksTable,\n groups as groupsTable,\n lots as lotsTable,\n obligationCollateralsV2 as obligationCollateralsTable,\n obligations as obligationsTable,\n offersCallbacks as offersCallbacksTable,\n offers as offersTable,\n offsets as offsetsTable,\n oracles as oraclesTable,\n positions as positionsTable,\n status as statusTable,\n validations as validationsTable,\n} from \"../drizzle/schema.ts\";\nimport type * as OffersDomain from \"./Offers.ts\";\n\nexport type BookDomain = {\n /** Get aggregated book levels for a given obligation side. */\n get: (parameters: get.Parameters) => Promise<get.ReturnType>;\n /** Get all offers for a given obligation side with cross-invalidation. */\n getOffers: (parameters: getOffers.Parameters) => Promise<getOffers.ReturnType>;\n};\n\nexport declare namespace get {\n export type Parameters = {\n /** The side of the offer. */\n side: \"buy\" | \"sell\";\n /** The obligationId of the offer. */\n obligationId: Hex;\n /** Cursor string returned by a previous call, for pagination */\n cursor?: string;\n /** Page size; defaults to {@link DEFAULT_LIMIT} */\n limit?: number;\n };\n\n export type Level = {\n /** The offer tick for this level */\n tick: number;\n /** Sum of takeable amounts at this tick */\n assets: bigint;\n /** Number of offers at this tick */\n count: number;\n };\n\n export type ReturnType = {\n levels: Level[];\n nextCursor: string | null;\n };\n}\n\nexport declare namespace getOffers {\n export type Parameters = {\n /** The side of the offer. */\n side: \"buy\" | \"sell\";\n /** The obligationId of the offer. */\n obligationId: Hex;\n /** Cursor string returned by a previous call, for pagination */\n cursor?: string;\n /** Page size; defaults to {@link DEFAULT_LIMIT} */\n limit?: number;\n };\n export type ReturnType = {\n rows: OffersDomain.Row[];\n nextCursor: string | null;\n };\n}\n\nconst DEFAULT_LIMIT = 100;\nconst MAX_TOTAL_OFFERS = 500;\n\nexport function create(config: { db: Database.Core }): BookDomain {\n const db = config.db;\n const logger = Logger.getLogger();\n\n const getOffers = async (parameters: getOffers.Parameters): Promise<getOffers.ReturnType> => {\n const { side, obligationId, cursor: cursorString } = parameters;\n const requestedLimit = parameters.limit ?? DEFAULT_LIMIT;\n const priceSortDirection: \"asc\" | \"desc\" = side === \"sell\" ? \"asc\" : \"desc\";\n\n const inputCursor = Cursor.decode(cursorString, logger);\n if (cursorString != null && inputCursor === null) {\n return { rows: [], nextCursor: null };\n }\n if (inputCursor != null && inputCursor.side !== side) {\n throw new Error(\"Cursor does not match the current sort parameters\");\n }\n\n const now = inputCursor?.now ?? Math.floor(Date.now() / 1000);\n\n const previouslyReturned = inputCursor?.totalReturned ?? 0;\n if (previouslyReturned >= MAX_TOTAL_OFFERS) {\n return { rows: [], nextCursor: null };\n }\n\n const effectiveLimit = Math.min(requestedLimit, MAX_TOTAL_OFFERS - previouslyReturned);\n\n const { rows, hasMore } = await _getOffers(db, {\n obligationId,\n side,\n now,\n priceSortDirection,\n cursor: inputCursor,\n limit: effectiveLimit,\n });\n\n const lastReturnedOffer = rows[rows.length - 1];\n const newTotalReturned = previouslyReturned + rows.length;\n const hasHitHardLimit = newTotalReturned >= MAX_TOTAL_OFFERS;\n\n const nextCursor =\n rows.length > 0 && lastReturnedOffer && !hasHitHardLimit && hasMore\n ? Cursor.encode(lastReturnedOffer, newTotalReturned, now, side)\n : null;\n\n return { rows, nextCursor };\n };\n\n return {\n get: async (parameters: get.Parameters): Promise<get.ReturnType> => {\n const { side, obligationId, cursor: cursorString, limit = DEFAULT_LIMIT } = parameters;\n const tickSortDirection: \"asc\" | \"desc\" = side === \"sell\" ? \"asc\" : \"desc\";\n\n const inputCursor = LevelCursor.decode(cursorString, logger);\n if (cursorString != null && inputCursor === null) {\n return { levels: [], nextCursor: null };\n }\n if (inputCursor != null && inputCursor.side !== side) {\n throw new Error(\"Cursor does not match the current sort parameters\");\n }\n\n const now = inputCursor?.now ?? Math.floor(Date.now() / 1000);\n const fetchLimit = limit * 10;\n const { rows, nextCursor: offersNextCursor } = await getOffers({\n side,\n obligationId,\n cursor: inputCursor?.offersCursor ?? undefined,\n limit: fetchLimit,\n });\n\n const tickMap = new Map<number, { assets: bigint; count: number }>();\n for (const row of rows) {\n const existing = tickMap.get(row.tick);\n if (existing) {\n existing.assets += row.takeable;\n existing.count += 1;\n } else {\n tickMap.set(row.tick, { assets: row.takeable, count: 1 });\n }\n }\n\n const levels: get.Level[] = Array.from(tickMap.entries()).map(([tick, level]) => ({\n tick,\n assets: level.assets,\n count: level.count,\n }));\n\n levels.sort((a, b) => (tickSortDirection === \"asc\" ? a.tick - b.tick : b.tick - a.tick));\n\n const paginatedLevels = levels.slice(0, limit);\n const hasMore = levels.length > limit || offersNextCursor !== null;\n\n const lastLevel = paginatedLevels[paginatedLevels.length - 1];\n const nextCursor =\n hasMore && lastLevel ? LevelCursor.encode(lastLevel, offersNextCursor, side, now) : null;\n\n return { levels: paginatedLevels, nextCursor };\n },\n getOffers,\n };\n}\n\n/** Get offers with computed takeable based on lot balance. */\nasync function _getOffers(\n db: Database.Core,\n params: {\n obligationId: Hex;\n side: \"buy\" | \"sell\";\n now: number;\n priceSortDirection: \"asc\" | \"desc\";\n cursor: Cursor.Cursor | null;\n limit: number;\n },\n): Promise<{ rows: OffersDomain.Row[]; hasMore: boolean }> {\n const { obligationId, side, now, priceSortDirection, cursor, limit } = params;\n\n const raw = await db.execute<{\n hash: Hex;\n group_maker: Address;\n assets: string;\n obligation_units: string | null;\n obligation_shares: string | null;\n consumed: string;\n tick: number;\n maturity: number;\n expiry: number;\n start: number;\n group: string;\n buy: boolean;\n chain_id: Chain.Id;\n loan_token: Address;\n callback_address: Address;\n callback_data: Hex;\n receiver_if_maker_is_seller: Address | null;\n block_number: number;\n collaterals: Array<{ asset: Address; oracle: Address; lltv: string }>;\n available: string | number | null;\n takeable: string;\n session: Hex;\n }>(sql`\n WITH collats AS MATERIALIZED (\n SELECT oc.obligation_id,\n COALESCE(jsonb_agg(jsonb_build_object(\n 'asset', oc.asset,\n 'oracle', oracle.address,\n 'lltv', oc.lltv\n ) ORDER BY oc.asset), '[]'::jsonb) AS collaterals\n FROM ${obligationCollateralsTable} oc\n JOIN ${oraclesTable} oracle\n ON oracle.chain_id = oc.oracle_chain_id\n AND oracle.address = oc.oracle_address\n WHERE oc.obligation_id = ${obligationId}\n GROUP BY oc.obligation_id\n ),\n winners AS (\n SELECT DISTINCT ON (o.group_chain_id, o.group_maker, o.\"group_group\")\n o.*\n FROM ${offersTable} o\n LEFT JOIN ${validationsTable} v\n ON v.offer_hash = o.hash\n LEFT JOIN ${statusTable} s\n ON s.id = v.status_id\n WHERE o.obligation_id = ${obligationId}\n AND o.buy = ${side === \"buy\"}\n AND o.expiry > ${now}\n AND o.maturity > ${now}\n AND o.start <= ${now}\n AND (s.code IS NULL OR s.code = ${Offer.Status.VALID})\n ORDER BY\n o.group_chain_id, o.group_maker, o.\"group_group\",\n o.tick ${priceSortDirection === \"asc\" ? sql`ASC` : sql`DESC`}, o.block_number ASC, o.assets DESC, o.hash ASC\n ),\n enriched AS (\n SELECT\n w.*,\n g.consumed, g.chain_id, obl.loan_token,\n CASE WHEN ${priceSortDirection === \"asc\" ? sql`TRUE` : sql`FALSE`}\n THEN w.tick ELSE -w.tick END AS tick_norm,\n w.block_number AS block_norm,\n -w.assets AS assets_norm,\n w.hash AS hash_norm\n FROM winners w\n JOIN ${groupsTable} g\n ON g.chain_id = w.group_chain_id\n AND g.maker = w.group_maker\n AND g.\"group\" = w.\"group_group\"\n JOIN ${obligationsTable} obl\n ON obl.obligation_id = w.obligation_id\n ),\n paged AS (\n SELECT e.*\n FROM enriched e\n ${\n cursor != null\n ? sql`\n WHERE\n (e.tick_norm, e.block_norm, e.assets_norm, e.hash_norm)\n > (\n CASE WHEN ${priceSortDirection === \"asc\" ? sql`TRUE` : sql`FALSE`}\n THEN ${cursor.tick}::integer ELSE -${cursor.tick}::integer END,\n ${cursor.blockNumber},\n -${cursor.assets}::numeric,\n ${cursor.hash}\n )`\n : sql``\n }\n ORDER BY e.tick ${priceSortDirection === \"asc\" ? sql`ASC` : sql`DESC`}, e.block_number ASC, e.assets DESC, e.hash ASC\n LIMIT ${limit}\n ),\n -- Compute sum of offsets per position and obligation\n position_offsets AS (\n SELECT\n chain_id,\n \"user\",\n contract,\n obligation_id,\n SUM(value::numeric) AS total_offset\n FROM ${offsetsTable}\n GROUP BY chain_id, \"user\", contract, obligation_id\n ),\n -- Compute position_consumed: sum of consumed from all groups with lots on each position+obligation (converted to lot terms)\n position_consumed AS (\n SELECT\n l.chain_id,\n l.contract,\n l.\"user\",\n l.obligation_id,\n SUM(\n CASE\n WHEN wo.assets::numeric > 0\n THEN COALESCE(g.consumed::numeric, 0) * (l.upper::numeric - l.lower::numeric) / wo.assets::numeric\n ELSE 0\n END\n ) AS consumed\n FROM ${lotsTable} l\n JOIN ${groupsTable} g\n ON g.chain_id = l.chain_id\n AND LOWER(g.maker) = LOWER(l.\"user\")\n AND g.\"group\" = l.\"group\"\n JOIN winners wo\n ON wo.group_chain_id = g.chain_id\n AND LOWER(wo.group_maker) = LOWER(g.maker)\n AND wo.group_group = g.\"group\"\n GROUP BY l.chain_id, l.contract, l.\"user\", l.obligation_id\n ),\n -- Compute callback contributions with lot balance\n callback_contributions AS (\n SELECT\n p.hash,\n p.obligation_id,\n p.assets,\n p.tick,\n p.obligation_units,\n p.obligation_shares,\n p.maturity,\n p.expiry,\n p.start,\n p.group_group,\n p.buy,\n p.callback_address,\n p.callback_data,\n p.receiver_if_maker_is_seller,\n p.block_number,\n p.group_chain_id,\n p.group_maker,\n p.consumed,\n p.chain_id,\n p.loan_token,\n p.session,\n c.id AS callback_id,\n c.position_chain_id,\n c.position_contract,\n c.position_user,\n c.amount AS callback_amount,\n pos.balance AS position_balance,\n pos.asset AS position_asset,\n l.lower AS lot_lower,\n l.upper AS lot_upper,\n -- Compute lot_balance: min(position_balance + offset + position_consumed - lot.lower, lot.size - lot_consumed)\n -- lot_consumed is converted from loan token to lot terms: consumed * lot_size / assets\n GREATEST(0, LEAST(\n COALESCE(pos.balance::numeric, 0) + COALESCE(pos_offsets.total_offset, 0) + COALESCE(pc.consumed, 0) - COALESCE(l.lower::numeric, 0),\n (COALESCE(l.upper::numeric, 0) - COALESCE(l.lower::numeric, 0)) -\n CASE\n WHEN p.assets::numeric > 0\n THEN COALESCE(p.consumed::numeric, 0) * (COALESCE(l.upper::numeric, 0) - COALESCE(l.lower::numeric, 0)) / p.assets::numeric\n ELSE 0\n END\n )) AS lot_balance\n FROM paged p\n LEFT JOIN ${offersCallbacksTable} oc ON oc.offer_hash = p.hash\n LEFT JOIN ${callbacksTable} c ON c.id = oc.callback_id\n LEFT JOIN ${lotsTable} l\n ON l.chain_id = c.position_chain_id\n AND LOWER(l.contract) = LOWER(c.position_contract)\n AND LOWER(l.\"user\") = LOWER(c.position_user)\n AND l.\"group\" = p.group_group\n AND l.obligation_id = p.obligation_id\n LEFT JOIN ${positionsTable} pos\n ON pos.chain_id = c.position_chain_id\n AND LOWER(pos.contract) = LOWER(c.position_contract)\n AND LOWER(pos.\"user\") = LOWER(c.position_user)\n LEFT JOIN position_offsets pos_offsets\n ON pos_offsets.chain_id = c.position_chain_id\n AND LOWER(pos_offsets.contract) = LOWER(c.position_contract)\n AND LOWER(pos_offsets.\"user\") = LOWER(c.position_user)\n AND pos_offsets.obligation_id = p.obligation_id\n LEFT JOIN position_consumed pc\n ON pc.chain_id = c.position_chain_id\n AND LOWER(pc.contract) = LOWER(c.position_contract)\n AND LOWER(pc.\"user\") = LOWER(c.position_user)\n AND pc.obligation_id = p.obligation_id\n ),\n -- Compute contribution per callback in loan terms (loan token only — collateral positions are not indexed)\n callback_loan_contribution AS (\n SELECT\n cc.*,\n CASE\n WHEN cc.lot_lower IS NULL THEN 0\n ELSE LEAST(cc.lot_balance, COALESCE(cc.callback_amount::numeric, cc.lot_balance))\n END AS contribution_in_loan\n FROM callback_contributions cc\n ),\n -- Aggregate contributions per offer, deduplicating by position using DISTINCT ON\n offer_contributions AS (\n SELECT\n hash,\n obligation_id,\n assets,\n tick,\n obligation_units,\n obligation_shares,\n maturity,\n expiry,\n start,\n group_group,\n buy,\n callback_address,\n callback_data,\n receiver_if_maker_is_seller,\n block_number,\n group_chain_id,\n group_maker,\n consumed,\n chain_id,\n loan_token,\n session,\n SUM(contribution_in_loan) AS total_available\n FROM (\n -- Take max contribution per position using DISTINCT ON (idiomatic PostgreSQL)\n SELECT DISTINCT ON (clc.hash, clc.position_chain_id, clc.position_contract, clc.position_user)\n clc.*\n FROM callback_loan_contribution clc\n WHERE clc.callback_id IS NOT NULL\n ORDER BY clc.hash, clc.position_chain_id, clc.position_contract, clc.position_user, clc.contribution_in_loan DESC\n ) deduped\n GROUP BY hash, obligation_id, assets, tick, obligation_units, obligation_shares, maturity, expiry, start, group_group, buy,\n callback_address, callback_data, block_number, group_chain_id, group_maker,\n consumed, chain_id, loan_token, session, receiver_if_maker_is_seller\n UNION ALL\n -- Sell offers without callbacks: collateral positions not indexed, takeable = assets - consumed\n SELECT\n p.hash, p.obligation_id, p.assets, p.tick,\n p.obligation_units, p.obligation_shares,\n p.maturity, p.expiry, p.start, p.group_group,\n p.buy, p.callback_address, p.callback_data,\n p.receiver_if_maker_is_seller,\n p.block_number, p.group_chain_id, p.group_maker,\n p.consumed, p.chain_id, p.loan_token, p.session,\n 0 AS total_available\n FROM paged p\n WHERE p.buy = false\n AND NOT EXISTS (\n SELECT 1 FROM ${offersCallbacksTable} oc2\n WHERE oc2.offer_hash = p.hash\n )\n )\n -- Final SELECT with inline takeable computation\n SELECT\n oc.hash,\n oc.group_maker,\n oc.assets,\n oc.obligation_units,\n oc.obligation_shares,\n oc.consumed,\n oc.tick,\n oc.maturity,\n oc.expiry,\n oc.start,\n oc.group_group AS \"group\",\n oc.buy,\n oc.chain_id,\n oc.loan_token,\n oc.callback_address,\n oc.callback_data,\n oc.receiver_if_maker_is_seller,\n oc.block_number,\n oc.session,\n COALESCE(oc.total_available, 0) AS available,\n -- takeable: sell offers use assets - consumed directly (collateral positions not indexed yet)\n CASE WHEN oc.buy = false\n THEN GREATEST(0, oc.assets::numeric - oc.consumed::numeric)\n ELSE GREATEST(0, LEAST(\n oc.assets::numeric - oc.consumed::numeric,\n COALESCE(oc.total_available, 0)\n ))\n END AS takeable,\n c.collaterals\n FROM offer_contributions oc\n LEFT JOIN collats c ON c.obligation_id = oc.obligation_id\n WHERE CASE WHEN oc.buy = false\n THEN GREATEST(0, oc.assets::numeric - oc.consumed::numeric)\n ELSE GREATEST(0, LEAST(\n oc.assets::numeric - oc.consumed::numeric,\n COALESCE(oc.total_available, 0)\n ))\n END > 0\n ORDER BY\n oc.tick ${priceSortDirection === \"asc\" ? sql`ASC` : sql`DESC`},\n oc.block_number ASC,\n oc.assets DESC,\n oc.hash ASC;\n `);\n\n const rows: OffersDomain.Row[] = raw.rows.map((row) => {\n const receiverIfMakerIsSeller = (\n row.receiver_if_maker_is_seller ?? row.group_maker\n ).toLowerCase() as Address;\n return {\n hash: row.hash,\n maker: row.group_maker,\n assets: BigInt(row.assets),\n obligationUnits: BigInt(row.obligation_units ?? 0),\n obligationShares: BigInt(row.obligation_shares ?? 0),\n tick: row.tick,\n maturity: row.maturity as Offer.OfferInput[\"maturity\"],\n expiry: row.expiry,\n start: row.start,\n group: row.group as Hex,\n buy: row.buy,\n chainId: row.chain_id,\n loanToken: row.loan_token,\n session: row.session as Hex,\n collaterals: row.collaterals.map((c) => ({\n asset: c.asset as Address,\n oracle: c.oracle as Address,\n lltv: BigInt(c.lltv) as Offer.OfferInput[\"collaterals\"][number][\"lltv\"],\n })),\n callback: {\n address: row.callback_address as Address,\n data: row.callback_data as Hex,\n },\n receiverIfMakerIsSeller,\n blockNumber: row.block_number,\n consumed: BigInt(row.consumed ?? 0),\n available: BigInt(String(row.available ?? \"0\").split(\".\")[0] ?? \"0\"),\n takeable: BigInt(String(row.takeable).split(\".\")[0] ?? \"0\"),\n };\n });\n\n return { rows, hasMore: raw.rows.length === limit };\n}\n\nexport namespace Cursor {\n export type Cursor = {\n /** The side of offers this cursor was created for */\n side: \"buy\" | \"sell\";\n /** The offer tick */\n tick: number;\n blockNumber: number;\n assets: string;\n hash: string;\n /** Cumulative count of offers returned across all pages (for hard limit enforcement) */\n totalReturned: number;\n /** Timestamp (seconds) when the first page was requested */\n now: number;\n };\n\n /** Encode an offer into a base64url cursor string. */\n export function encode(\n row: OffersDomain.Row,\n totalReturned: number,\n now: number,\n side: \"buy\" | \"sell\",\n ): string {\n return Buffer.from(\n JSON.stringify({\n side,\n tick: row.tick,\n blockNumber: row.blockNumber,\n assets: row.assets.toString(),\n hash: row.hash,\n totalReturned,\n now,\n }),\n ).toString(\"base64url\");\n }\n\n /** Decode a cursor string. Returns null if invalid. */\n export function decode(\n cursorString: string | undefined,\n logger: ReturnType<typeof Logger.getLogger>,\n ): Cursor | null {\n if (cursorString == null) return null;\n\n try {\n const v = JSON.parse(Buffer.from(cursorString, \"base64url\").toString(\"utf8\"));\n if (\n (v?.side === \"buy\" || v?.side === \"sell\") &&\n typeof v?.tick === \"number\" &&\n Number.isInteger(v.tick) &&\n typeof v?.blockNumber === \"number\" &&\n Number.isInteger(v.blockNumber) &&\n typeof v?.assets === \"string\" &&\n /^-?\\d+$/.test(v.assets) &&\n isHex(v?.hash) &&\n typeof v?.totalReturned === \"number\" &&\n Number.isInteger(v.totalReturned) &&\n typeof v?.now === \"number\" &&\n Number.isInteger(v.now)\n ) {\n return v as Cursor;\n }\n throw new Error(\"Invalid cursor\");\n } catch {\n logger.error({ service: \"book_domain\", msg: \"Invalid cursor\", cursor: cursorString });\n return null;\n }\n }\n}\n\nexport namespace LevelCursor {\n type Cursor = {\n /** The side of offers this cursor was created for */\n side: \"buy\" | \"sell\";\n /** The last tick returned */\n lastTick: number;\n /** Timestamp (seconds) when the first page was requested */\n now: number;\n /** The cursor for the underlying offers query */\n offersCursor: string | null;\n };\n\n /** Encode a book level into a base64url cursor string. */\n export function encode(\n lastLevel: get.Level,\n offersCursor: string | null,\n side: \"buy\" | \"sell\",\n now: number,\n ): string {\n return Buffer.from(\n JSON.stringify({\n side,\n lastTick: lastLevel.tick,\n now,\n offersCursor,\n }),\n ).toString(\"base64url\");\n }\n\n /** Decode a cursor string. Returns null if invalid. */\n export function decode(\n cursorString: string | undefined,\n logger: ReturnType<typeof Logger.getLogger>,\n ): Cursor | null {\n if (cursorString == null) return null;\n\n try {\n const v = JSON.parse(Buffer.from(cursorString, \"base64url\").toString(\"utf8\"));\n if (\n (v?.side === \"buy\" || v?.side === \"sell\") &&\n typeof v?.lastTick === \"number\" &&\n Number.isInteger(v.lastTick) &&\n typeof v?.now === \"number\" &&\n Number.isInteger(v.now) &&\n (v?.offersCursor === null || typeof v?.offersCursor === \"string\")\n ) {\n return v as Cursor;\n }\n throw new Error(\"Invalid book cursor\");\n } catch {\n logger.error({ service: \"book_domain\", msg: \"Invalid book cursor\", cursor: cursorString });\n return null;\n }\n }\n}\n","import { inArray } from \"drizzle-orm\";\nimport { type Address, type Hex, keccak256 } from \"viem\";\nimport type * as Chain from \"#core/Chain.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\nimport {\n callbacks as callbacksTable,\n offersCallbacks as offersCallbacksTable,\n} from \"../drizzle/schema.ts\";\n\nexport type CallbackInput = {\n chainId: Chain.Id;\n contract: Address;\n user: Address;\n amount: bigint;\n};\n\nexport type OfferCallbacks = {\n offerHash: Hex;\n callbacks: CallbackInput[];\n};\n\nexport type CallbacksDomain = {\n /**\n * Upsert callbacks and their offer associations.\n * @param inputs - Callback associations grouped by offer hash. {@link OfferCallbacks}\n */\n upsert: (inputs: OfferCallbacks[]) => Promise<void>;\n\n /**\n * Delete callback associations by offer hashes.\n * @param parameters - Offer hashes to delete. {@link DeleteParameters}\n * @returns Number of rows deleted. {@link DeleteReturnType}\n */\n delete: (parameters: DeleteParameters) => Promise<DeleteReturnType>;\n};\n\nexport type DeleteParameters = { offers: Hex[] };\nexport type DeleteReturnType = number;\n\n/**\n * Create a callbacks domain instance.\n * @param db - Database core instance.\n * @returns Callbacks domain. {@link CallbacksDomain}\n */\nexport function create(db: Database.Core): CallbacksDomain {\n return {\n upsert: async (inputs: OfferCallbacks[]): Promise<void> => {\n if (inputs.length === 0) return;\n\n const idCache = new Map<string, string>();\n const seenCallbackIds = new Set<string>();\n const callbacksRows: Array<{\n id: string;\n positionChainId: Chain.Id;\n positionContract: Address;\n positionUser: Address;\n amount: string;\n }> = [];\n const offersCallbacksRows: Array<{ offerHash: Hex; callbackId: string }> = [];\n\n const callbackId = (input: CallbackInput): string => {\n const preimage =\n `0x${input.chainId}${input.contract}${input.user}${input.amount.toString()}`.toLowerCase() as `0x${string}`;\n const id = idCache.get(preimage) ?? keccak256(preimage);\n idCache.set(preimage, id);\n return id;\n };\n\n for (const { offerHash, callbacks } of inputs) {\n const normalizedOfferHash = offerHash.toLowerCase() as Hex;\n for (const callback of callbacks) {\n const normalized: CallbackInput = {\n chainId: callback.chainId,\n contract: callback.contract.toLowerCase() as Address,\n user: callback.user.toLowerCase() as Address,\n amount: callback.amount,\n };\n\n const id = callbackId(normalized);\n offersCallbacksRows.push({\n offerHash: normalizedOfferHash,\n callbackId: id,\n });\n\n if (seenCallbackIds.has(id)) continue;\n seenCallbackIds.add(id);\n callbacksRows.push({\n id,\n positionChainId: normalized.chainId,\n positionContract: normalized.contract,\n positionUser: normalized.user,\n amount: normalized.amount.toString(),\n });\n }\n }\n\n if (offersCallbacksRows.length === 0) return;\n\n await db.transaction(async (dbTx) => {\n for (const batch of Utils.batch(callbacksRows, DEFAULT_BATCH_SIZE)) {\n await dbTx.insert(callbacksTable).values(batch).onConflictDoNothing();\n }\n\n for (const batch of Utils.batch(offersCallbacksRows, DEFAULT_BATCH_SIZE)) {\n await dbTx.insert(offersCallbacksTable).values(batch).onConflictDoNothing();\n }\n });\n },\n\n delete: async ({ offers }: DeleteParameters): Promise<DeleteReturnType> => {\n if (offers.length === 0) return 0;\n const normalized = offers.map((offer) => offer.toLowerCase() as Hex);\n const result = await db\n .delete(offersCallbacksTable)\n .where(inArray(offersCallbacksTable.offerHash, normalized));\n return (result as { affectedRows: number }).affectedRows;\n },\n };\n}\n","import { sql } from \"drizzle-orm\";\nimport type { Address, Hex } from \"viem\";\nimport type { Chain } from \"#core\";\nimport * as Utils from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\nimport type * as Database from \"../Database.ts\";\nimport { consumedEvents as consumedEventsTable, groups as groupsTable } from \"../drizzle/schema.ts\";\n\nexport type Event = {\n id: string;\n chainId: Chain.Id;\n maker: Address;\n group: Hex;\n amount: bigint;\n blockNumber: number;\n};\n\nexport type Group = {\n chainId: Chain.Id;\n maker: Address;\n group: Hex;\n blockNumber: number;\n};\n\nexport type ConsumedDomain = {\n /** Create new consumed events. */\n create: (parameters: Event[]) => Promise<void>;\n\n /** Delete multiple consumed events by chain and block number greater than or equal to the given value. */\n delete: (parameters: { chainId: Chain.Id; blockNumberGte: number }) => Promise<number>;\n};\n\nexport function create(db: Database.Core): ConsumedDomain {\n return {\n create: async (events: Event[]): Promise<void> => {\n if (events.length === 0) return;\n\n const groups: Map<string, Group> = new Map();\n for (const event of events) {\n const groupId = `${event.chainId}-${event.maker}-${event.group}`.toLowerCase();\n groups.set(groupId, {\n chainId: event.chainId,\n maker: event.maker,\n group: event.group,\n blockNumber: event.blockNumber,\n });\n }\n\n await db.transaction(async (dbTx) => {\n const groupsRows = Array.from(groups.values()).map((group) => ({\n chainId: group.chainId,\n maker: group.maker.toLowerCase(),\n group: group.group.toLowerCase(),\n consumed: \"0\",\n blockNumber: group.blockNumber,\n }));\n for (const batch of Utils.batch(groupsRows, DEFAULT_BATCH_SIZE)) {\n await dbTx.insert(groupsTable).values(batch).onConflictDoNothing();\n }\n\n const eventsRows = events.map((event) => ({\n eventId: event.id,\n chainId: event.chainId,\n maker: event.maker.toLowerCase(),\n group: event.group.toLowerCase(),\n amount: event.amount.toString(),\n blockNumber: event.blockNumber,\n }));\n for (const batch of Utils.batch(eventsRows, DEFAULT_BATCH_SIZE)) {\n await dbTx.insert(consumedEventsTable).values(batch).onConflictDoNothing();\n }\n });\n },\n\n delete: async (parameters: { chainId: Chain.Id; blockNumberGte: number }): Promise<number> => {\n const { chainId, blockNumberGte } = parameters;\n const result = await db\n .delete(consumedEventsTable)\n .where(\n sql`${consumedEventsTable.blockNumber} >= ${blockNumberGte} AND ${consumedEventsTable.chainId} = ${chainId}`,\n );\n return (result as { affectedRows: number }).affectedRows;\n },\n };\n}\n","import type { Address, Hex } from \"viem\";\nimport type * as Chain from \"#core/Chain.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\nimport { groups as groupsTable } from \"../drizzle/schema.ts\";\n\nexport type GroupInput = {\n chainId: Chain.Id;\n maker: Address;\n group: Hex;\n blockNumber: number;\n consumed?: bigint;\n};\n\nexport type GroupsDomain = {\n /**\n * Insert groups (insert-only).\n * @param groups - Groups to insert. {@link GroupInput}\n */\n create: (groups: GroupInput[]) => Promise<void>;\n};\n\n/**\n * Create a groups domain instance.\n * @param db - Database core instance.\n * @returns Groups domain. {@link GroupsDomain}\n */\nexport function create(db: Database.Core): GroupsDomain {\n return {\n create: async (groups) => {\n if (groups.length === 0) return;\n\n const rows = groups.map((group) => ({\n chainId: group.chainId,\n maker: group.maker.toLowerCase(),\n group: group.group.toLowerCase(),\n consumed: (group.consumed ?? 0n).toString(),\n blockNumber: group.blockNumber,\n }));\n\n for (const batch of Utils.batch(rows, DEFAULT_BATCH_SIZE)) {\n await db.insert(groupsTable).values(batch).onConflictDoNothing();\n }\n },\n };\n}\n","import { and, eq, sql } from \"drizzle-orm\";\nimport type { Address } from \"viem\";\nimport type { Chain } from \"#core\";\nimport type * as Database from \"../Database.ts\";\nimport { lots as lotsTable } from \"../drizzle/schema.ts\";\n\nexport type Lot = {\n chainId: Chain.Id;\n user: Address;\n contract: Address;\n group: string;\n obligationId: string;\n lower: bigint;\n upper: bigint;\n};\n\nexport type LotsDomain = {\n /**\n * Create or update lots for offers.\n * Called when offers are created to reserve liquidity on positions.\n * For each (position, group), keeps only the biggest offer by assets.\n * If lot exists and new offer is bigger, grows the lot and shifts higher lots.\n */\n create: (parameters: create.Parameters) => Promise<void>;\n\n /**\n * Get lots with optional filtering.\n */\n get: (parameters?: get.Parameters) => Promise<Lot[]>;\n};\n\nexport declare namespace create {\n export type OfferLotInfo = {\n positionChainId: Chain.Id;\n positionContract: Address;\n positionUser: Address;\n group: string;\n obligationId: string;\n size: bigint;\n };\n export type Parameters = OfferLotInfo[];\n export type ReturnType = undefined;\n}\n\nexport declare namespace get {\n export type Parameters = {\n chainId?: Chain.Id;\n user?: Address;\n contract?: Address;\n group?: string;\n obligationId?: string;\n };\n export type ReturnType = Lot[];\n}\n\nexport function create(db: Database.Core): LotsDomain {\n return {\n get: async (parameters?: get.Parameters): Promise<Lot[]> => {\n const { chainId, user, contract, group, obligationId } = parameters ?? {};\n\n const conditions = [];\n if (chainId !== undefined) conditions.push(eq(lotsTable.chainId, chainId));\n if (user !== undefined) conditions.push(eq(lotsTable.user, user.toLowerCase()));\n if (contract !== undefined) conditions.push(eq(lotsTable.contract, contract.toLowerCase()));\n if (group !== undefined) conditions.push(eq(lotsTable.group, group));\n if (obligationId !== undefined) conditions.push(eq(lotsTable.obligationId, obligationId));\n\n const rows = await db\n .select()\n .from(lotsTable)\n .where(conditions.length > 0 ? and(...conditions) : undefined);\n\n return rows.map((row) => ({\n chainId: row.chainId,\n user: row.user as Address,\n contract: row.contract as Address,\n group: row.group,\n obligationId: row.obligationId,\n lower: BigInt(row.lower),\n upper: BigInt(row.upper),\n }));\n },\n\n create: async (parameters: create.Parameters): Promise<void> => {\n if (parameters.length === 0) return;\n\n const lotsByKey = new Map<string, create.OfferLotInfo>();\n\n for (const offer of parameters) {\n const key =\n `${offer.positionChainId}-${offer.positionContract}-${offer.positionUser}-${offer.group}-${offer.obligationId}`.toLowerCase();\n const existing = lotsByKey.get(key);\n\n if (!existing || offer.size > existing.size) {\n lotsByKey.set(key, offer);\n }\n }\n\n for (const offer of lotsByKey.values()) {\n const existingLot = await db\n .select()\n .from(lotsTable)\n .where(\n and(\n eq(lotsTable.chainId, offer.positionChainId),\n eq(lotsTable.contract, offer.positionContract.toLowerCase()),\n eq(lotsTable.user, offer.positionUser.toLowerCase()),\n eq(lotsTable.group, offer.group.toLowerCase()),\n eq(lotsTable.obligationId, offer.obligationId.toLowerCase()),\n ),\n )\n .limit(1);\n\n if (existingLot.length === 0) {\n // No existing lot - create new one\n // Find the highest upper bound on this position for this obligation\n const maxUpperResult = await db\n .select({ maxUpper: sql<string>`COALESCE(MAX(${lotsTable.upper}::numeric), 0)` })\n .from(lotsTable)\n .where(\n and(\n eq(lotsTable.chainId, offer.positionChainId),\n eq(lotsTable.contract, offer.positionContract.toLowerCase()),\n eq(lotsTable.user, offer.positionUser.toLowerCase()),\n eq(lotsTable.obligationId, offer.obligationId.toLowerCase()),\n ),\n );\n\n const maxUpper = BigInt(maxUpperResult[0]?.maxUpper ?? \"0\");\n const newLower = maxUpper;\n const newUpper = newLower + offer.size;\n\n await db.insert(lotsTable).values({\n chainId: offer.positionChainId,\n user: offer.positionUser.toLowerCase(),\n contract: offer.positionContract.toLowerCase(),\n group: offer.group.toLowerCase(),\n obligationId: offer.obligationId.toLowerCase(),\n lower: newLower.toString(),\n upper: newUpper.toString(),\n });\n }\n // Existing lot - lots are immutable, no updates allowed\n }\n },\n };\n}\n","import { and, asc, eq, gte, inArray, sql } from \"drizzle-orm\";\nimport type { Address } from \"viem\";\nimport { Collateral, LLTV, Obligation } from \"#core\";\nimport type * as Chain from \"#core/Chain.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\nimport { Time } from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\nimport {\n obligationCollateralsV2 as obligationCollateralsTable,\n obligations as obligationsTable,\n oracles as oraclesTable,\n} from \"../drizzle/schema.ts\";\n\nexport type ObligationsDomain = {\n /**\n * Insert obligations (insert-only).\n * @param obligations - Obligations to insert. {@link Obligation.Obligation}\n */\n create: (obligations: Obligation.Obligation[]) => Promise<void>;\n\n /**\n * Get active obligations with optional chain filters.\n * @param parameters - Optional chain filters.\n * @returns Matching obligations.\n */\n get: (parameters?: { chainId?: Chain.Id[] }) => Promise<Obligation.Obligation[]>;\n};\n\n/**\n * Create an obligations domain instance.\n * @param db - Database core instance.\n * @returns Obligations domain. {@link ObligationsDomain}\n */\nexport function create(db: Database.Core): ObligationsDomain {\n return {\n get: async (parameters) => {\n const chainIds = parameters?.chainId;\n const now = Time.now();\n\n const rows = await db\n .select({\n chainId: obligationsTable.chainId,\n loanToken: obligationsTable.loanToken,\n collaterals: sql<\n { asset: Address; oracle: Address; lltv: string }[]\n >`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsTable.asset}, 'oracle', ${oraclesTable.address}, 'lltv', ${obligationCollateralsTable.lltv}))`.as(\n \"collaterals\",\n ),\n maturity: obligationsTable.maturity,\n })\n .from(obligationsTable)\n .innerJoin(\n obligationCollateralsTable,\n eq(obligationsTable.obligationId, obligationCollateralsTable.obligationId),\n )\n .innerJoin(\n oraclesTable,\n sql`${obligationCollateralsTable.oracleChainId} = ${oraclesTable.chainId}\n AND ${obligationCollateralsTable.oracleAddress} = ${oraclesTable.address}`,\n )\n .groupBy(obligationsTable.obligationId)\n .where(\n and(\n chainIds !== undefined && chainIds.length > 0\n ? inArray(obligationsTable.chainId, chainIds)\n : undefined,\n gte(obligationsTable.maturity, now),\n ),\n )\n .orderBy(asc(obligationsTable.obligationId));\n\n return rows.map((row) =>\n Obligation.from({\n chainId: row.chainId,\n loanToken: row.loanToken as Address,\n collaterals: row.collaterals\n .sort((left, right) => left.asset.localeCompare(right.asset))\n .map((collateral) =>\n Collateral.from({\n asset: collateral.asset as Address,\n oracle: collateral.oracle as Address,\n lltv: LLTV.from(BigInt(collateral.lltv)),\n }),\n ),\n maturity: row.maturity,\n }),\n );\n },\n\n create: async (obligations) => {\n if (obligations.length === 0) return;\n\n const obligationsById = new Map<string, Obligation.Obligation>();\n for (const obligation of obligations) {\n const id = Obligation.id(obligation).toLowerCase();\n const existing = obligationsById.get(id);\n if (!existing) obligationsById.set(id, obligation);\n }\n\n try {\n await db.transaction(async (dbTx) => {\n const obligationRows = obligations.map((obligation) => ({\n obligationId: Obligation.id(obligation),\n chainId: obligation.chainId,\n loanToken: obligation.loanToken.toLowerCase(),\n maturity: obligation.maturity,\n }));\n\n for (const batch of Utils.batch(obligationRows, DEFAULT_BATCH_SIZE)) {\n await dbTx.insert(obligationsTable).values(batch).onConflictDoNothing();\n }\n\n const collateralRows = obligations.flatMap((obligation) => {\n return obligation.collaterals.map((collateral) => ({\n obligationId: Obligation.id(obligation),\n asset: collateral.asset.toLowerCase(),\n oracleChainId: obligation.chainId,\n oracleAddress: collateral.oracle.toLowerCase(),\n lltv: collateral.lltv,\n }));\n });\n\n for (const batch of Utils.batch(collateralRows, DEFAULT_BATCH_SIZE)) {\n await dbTx.insert(obligationCollateralsTable).values(batch).onConflictDoNothing();\n }\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n throw new Error(\n \"Obligations.create failed. Ensure oracles exist before inserting obligations.\",\n { cause: error },\n );\n }\n },\n };\n}\n","import { and, eq } from \"drizzle-orm\";\nimport type { Address } from \"viem\";\nimport type { Chain } from \"#core\";\nimport type * as Database from \"../Database.ts\";\nimport { offsets as offsetsTable } from \"../drizzle/schema.ts\";\n\nexport type Offset = {\n chainId: Chain.Id;\n user: Address;\n contract: Address;\n group: string;\n obligationId: string;\n value: bigint;\n};\n\nexport type OffsetsDomain = {\n /**\n * Get offsets with optional filtering.\n */\n get: (parameters?: get.Parameters) => Promise<Offset[]>;\n};\n\nexport declare namespace get {\n export type Parameters = {\n chainId?: Chain.Id;\n user?: Address;\n contract?: Address;\n group?: string;\n obligationId?: string;\n };\n export type ReturnType = Offset[];\n}\n\nexport function create(db: Database.Core): OffsetsDomain {\n return {\n get: async (parameters?: get.Parameters): Promise<Offset[]> => {\n const { chainId, user, contract, group, obligationId } = parameters ?? {};\n\n const conditions = [];\n if (chainId !== undefined) conditions.push(eq(offsetsTable.chainId, chainId));\n if (user !== undefined) conditions.push(eq(offsetsTable.user, user.toLowerCase()));\n if (contract !== undefined)\n conditions.push(eq(offsetsTable.contract, contract.toLowerCase()));\n if (group !== undefined) conditions.push(eq(offsetsTable.group, group));\n if (obligationId !== undefined) conditions.push(eq(offsetsTable.obligationId, obligationId));\n\n const rows = await db\n .select()\n .from(offsetsTable)\n .where(conditions.length > 0 ? and(...conditions) : undefined);\n\n return rows.map((row) => ({\n chainId: row.chainId,\n user: row.user as Address,\n contract: row.contract as Address,\n group: row.group,\n obligationId: row.obligationId,\n value: BigInt(row.value),\n }));\n },\n };\n}\n","import { eq, sql } from \"drizzle-orm\";\nimport type { Address } from \"viem\";\nimport { type Chain, Oracle } from \"#core\";\nimport * as Utils from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\nimport type * as Database from \"../Database.ts\";\nimport { oracles as oraclesTable } from \"../drizzle/schema.ts\";\n\nexport type OraclesDomain = {\n /**\n * Get all oracles for a specific chain.\n * @returns An array of oracles with their current state.\n */\n get: (parameters: { chainId: Chain.Id }) => Promise<Oracle.Oracle[]>;\n\n /**\n * Upsert oracles\n *\n * @param oracles - Array of oracles to upsert\n */\n upsert: (oracles: Oracle.Oracle[]) => Promise<void>;\n};\n\nexport function create(db: Database.Core): OraclesDomain {\n return {\n get: async ({ chainId }: { chainId: Chain.Id }): Promise<Oracle.Oracle[]> => {\n const result = await db\n .select({\n address: oraclesTable.address,\n price: oraclesTable.price,\n blockNumber: oraclesTable.blockNumber,\n chainId: oraclesTable.chainId,\n })\n .from(oraclesTable)\n .where(eq(oraclesTable.chainId, chainId));\n\n return result.map((r) =>\n Oracle.from({\n chainId: r.chainId,\n address: r.address as Address,\n price: r.price,\n blockNumber: r.blockNumber,\n }),\n );\n },\n\n upsert: async (oracles: Oracle.Oracle[]): Promise<void> => {\n if (oracles.length === 0) return;\n\n const rows = oracles.map((o) => ({\n chainId: o.chainId,\n address: o.address.toLowerCase(),\n price: o.price !== null ? o.price.toString() : null,\n blockNumber: o.blockNumber,\n }));\n\n await db.transaction(async (dbTx) => {\n for (const batch of Utils.batch(rows, DEFAULT_BATCH_SIZE)) {\n await dbTx\n .insert(oraclesTable)\n .values(batch)\n .onConflictDoUpdate({\n target: [oraclesTable.chainId, oraclesTable.address],\n set: {\n price: sql`COALESCE(EXCLUDED.price, ${oraclesTable.price})`,\n blockNumber: sql`CASE\n WHEN EXCLUDED.price IS NULL THEN ${oraclesTable.blockNumber}\n ELSE EXCLUDED.block_number\n END`,\n updatedAt: sql`NOW()`,\n },\n });\n }\n });\n },\n };\n}\n","import { and, asc, eq, ne, sql } from \"drizzle-orm\";\nimport { type Address, zeroAddress } from \"viem\";\nimport { type Chain, Position } from \"#core/index.ts\";\nimport {\n groups as groupsTable,\n lots as lotsTable,\n offers as offersTable,\n offsets as offsetsTable,\n positions as positionsTable,\n transfers as transfersTable,\n} from \"#database/drizzle/schema.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\n\nexport const DEFAULT_LIMIT = 100;\nexport type PaginationParams = {\n /** Cursor string returned by a previous call, for pagination */\n cursor?: string;\n /** Page size; defaults to {@link DEFAULT_LIMIT} */\n limit?: number;\n};\n\nexport type PositionsDomain = {\n /**\n * Upsert positions.\n * @notice A position can only be updated if its balance is `null` and the block number is greater than the previous position snapshot.\n * Once a position has a non `null` balance, transfers are the only way to update the balance.\n *\n * @param positions - {@link upsert.Parameters}\n * @returns The number of positions upserted. {@link upsert.ReturnType}\n */\n upsert(positions: upsert.Parameters): Promise<upsert.ReturnType>;\n\n /**\n * Returns positions.\n * @param parameters - {@link get.Parameters}\n * @returns The positions. {@link get.ReturnType}\n */\n get: (parameters?: get.Parameters) => Promise<get.ReturnType>;\n\n /**\n * Returns positions for a specific user with remaining balance calculation.\n * @param parameters - {@link getByUser.Parameters}\n * @returns The user's positions with remaining balances. {@link getByUser.ReturnType}\n */\n getByUser: (parameters: getByUser.Parameters) => Promise<getByUser.ReturnType>;\n\n /**\n * Set all positions to empty after a given block number (inclusive), deletes all transfers linked to the positions.\n * @param parameters - {@link setEmptyAfter.Parameters}\n * @returns The number of positions set to empty. {@link setEmptyAfter.ReturnType}\n */\n setEmptyAfter(parameters: setEmptyAfter.Parameters): Promise<setEmptyAfter.ReturnType>;\n};\n\nexport declare namespace upsert {\n export type Parameters = Position.Position[];\n export type ReturnType = number;\n}\n\nexport declare namespace get {\n type Parameters = PaginationParams & {\n /** The chain id to get positions for. Default is all chains. */\n chainId?: Chain.Id;\n /** The type of position to get. Default is all types. */\n type?: Position.Type;\n /** If true, only return positions that have a balance. */\n filled?: boolean;\n };\n\n type ReturnType = { positions: Position.Position[]; nextCursor: string | null };\n}\n\nexport declare namespace getByUser {\n type Parameters = PaginationParams & {\n /** The user address to get positions for. */\n user: Address;\n };\n\n type PositionWithReserved = {\n chainId: Chain.Id;\n contract: Address;\n user: Address;\n blockNumber: number;\n /** The obligation this reserved amount belongs to, or null if no lots exist */\n obligationId: string | null;\n /** The amount reserved by active offers: max(lot.upper) - offset - consumed */\n reserved: bigint;\n };\n\n type ReturnType = { positions: PositionWithReserved[]; nextCursor: string | null };\n}\n\nexport declare namespace setEmptyAfter {\n type Parameters = {\n /** The chain id . */\n chainId: Chain.Id;\n /** The block number after which all positions should be set to empty. (inclusive) */\n blockNumber: number;\n };\n\n type ReturnType = number;\n}\n\nexport const create = (db: Database.Core): PositionsDomain => {\n return {\n upsert: async (positions) => {\n const positionsMap = new Map<string, Position.Position>();\n for (const p of positions) {\n const key = `${p.chainId}-${p.contract}-${p.user}`.toLowerCase();\n const zeroKey = `${p.chainId}-${p.contract}-${zeroAddress}`.toLowerCase();\n if (!positionsMap.has(zeroKey)) {\n positionsMap.set(zeroKey, {\n chainId: p.chainId,\n contract: p.contract,\n user: zeroAddress,\n balance: 0n,\n type: p.type,\n blockNumber: p.blockNumber,\n });\n }\n\n if (!positionsMap.has(key)) {\n positionsMap.set(key, p);\n continue;\n }\n\n if (p.blockNumber > positionsMap.get(key)!.blockNumber) positionsMap.set(key, p);\n }\n\n if (positionsMap.size === 0) return 0;\n\n const rows = Array.from(positionsMap.values()).map((p) => {\n const positionTypeId = Object.values(Position.Type).indexOf(p.type) + 1;\n return {\n chainId: p.chainId,\n contract: p.contract.toLowerCase(),\n user: p.user.toLowerCase(),\n positionTypeId,\n ...(p.balance !== undefined ? { balance: p.balance.toString() } : {}),\n ...(p.asset !== undefined ? { asset: p.asset.toLowerCase() } : {}),\n blockNumber: p.blockNumber,\n };\n });\n\n let totalUpdated = 0;\n for (const batch of Utils.batch(rows, DEFAULT_BATCH_SIZE)) {\n const updated = await db\n .insert(positionsTable)\n .values(batch)\n .onConflictDoUpdate({\n target: [positionsTable.chainId, positionsTable.contract, positionsTable.user],\n set: {\n balance: sql`EXCLUDED.balance`,\n asset: sql`COALESCE(EXCLUDED.asset, ${positionsTable.asset})`,\n blockNumber: sql`EXCLUDED.block_number`,\n updatedAt: sql`NOW()`,\n },\n where: sql`${positionsTable.blockNumber} < EXCLUDED.block_number AND ${positionsTable.balance} IS NULL`,\n })\n .returning();\n totalUpdated += updated.length;\n }\n\n return totalUpdated;\n },\n\n get: async (parameters) => {\n const {\n limit = DEFAULT_LIMIT,\n cursor: encodedCursor,\n chainId,\n type,\n filled,\n } = parameters ?? {};\n\n let cursor: { chainId: Chain.Id; contract: string; user: string } | null = null;\n if (encodedCursor !== null && encodedCursor !== undefined) {\n const parsed = JSON.parse(Buffer.from(encodedCursor, \"base64url\").toString(\"utf8\"));\n if (!parsed.chainId || !parsed.contract || !parsed.user) {\n throw new Error(\"Invalid cursor format\");\n }\n cursor = {\n chainId: parsed.chainId as Chain.Id,\n contract: parsed.contract,\n user: parsed.user,\n };\n }\n\n const positions = await db\n .select()\n .from(positionsTable)\n .where(\n and(\n ne(positionsTable.user, zeroAddress),\n filled === undefined\n ? sql`true`\n : sql`${positionsTable.balance} IS ${filled === true ? sql`NOT` : sql``} NULL`,\n type !== undefined\n ? eq(positionsTable.positionTypeId, Object.values(Position.Type).indexOf(type) + 1)\n : sql`true`,\n chainId !== undefined ? eq(positionsTable.chainId, chainId) : sql`true`,\n (() => {\n if (cursor === null || cursor === undefined) return sql`true`;\n // dont include chainId comparison if chainId is defined in the parameters\n // filtering is already done above\n return sql`\n (${chainId === undefined ? sql`\"chain_id\", ` : sql``}\"contract\", \"user\") > (${chainId === undefined ? sql`${cursor.chainId}, ` : sql``}${cursor.contract}, ${cursor.user})\n `;\n })(),\n ),\n )\n .orderBy(\n asc(positionsTable.chainId),\n asc(positionsTable.contract),\n asc(positionsTable.user),\n asc(positionsTable.blockNumber),\n )\n .limit(limit);\n\n const nextCursor =\n positions.length === limit\n ? Buffer.from(\n JSON.stringify({\n chainId: positions[positions.length - 1]!.chainId.toString(),\n contract: positions[positions.length - 1]!.contract,\n user: positions[positions.length - 1]!.user,\n blockNumber: positions[positions.length - 1]!.blockNumber.toString(),\n }),\n ).toString(\"base64url\")\n : null;\n\n return {\n positions: positions.map((p) => ({\n chainId: p.chainId,\n contract: p.contract as Address,\n user: p.user as Address,\n type: Object.values(Position.Type)[p.positionTypeId - 1] as Position.Type,\n balance: p.balance !== null ? BigInt(p.balance) : undefined,\n ...(p.asset !== null ? { asset: p.asset as Address } : {}),\n blockNumber: p.blockNumber,\n })),\n nextCursor,\n };\n },\n\n getByUser: async (parameters) => {\n const { user, limit = DEFAULT_LIMIT, cursor: encodedCursor } = parameters;\n\n let cursor: {\n chainId: Chain.Id;\n contract: string;\n obligationId: string | null;\n } | null = null;\n if (encodedCursor !== null && encodedCursor !== undefined) {\n const parsed = JSON.parse(Buffer.from(encodedCursor, \"base64url\").toString(\"utf8\"));\n if (!parsed.chainId || !parsed.contract) {\n throw new Error(\"Invalid cursor format\");\n }\n cursor = {\n chainId: parsed.chainId as Chain.Id,\n contract: parsed.contract,\n obligationId: parsed.obligationId ?? null,\n };\n }\n\n const raw = await db.execute<{\n chain_id: Chain.Id;\n contract: string;\n user: string;\n block_number: number;\n obligation_id: string | null;\n reserved_balance: string;\n }>(sql`\n WITH position_offsets AS (\n SELECT\n chain_id,\n \"user\",\n contract,\n obligation_id,\n SUM(value::numeric) AS total_offset\n FROM ${offsetsTable}\n WHERE LOWER(\"user\") = LOWER(${user})\n GROUP BY chain_id, \"user\", contract, obligation_id\n ),\n position_consumed AS (\n SELECT\n l.chain_id,\n l.contract,\n l.\"user\",\n l.obligation_id,\n SUM(\n CASE\n WHEN offer_agg.assets > 0\n THEN COALESCE(g.consumed::numeric, 0) * (l.upper::numeric - l.lower::numeric) / offer_agg.assets\n ELSE 0\n END\n ) AS consumed\n FROM ${lotsTable} l\n JOIN ${groupsTable} g\n ON g.chain_id = l.chain_id\n AND LOWER(g.maker) = LOWER(l.\"user\")\n AND g.\"group\" = l.\"group\"\n JOIN (\n SELECT\n group_chain_id,\n group_maker,\n \"group_group\",\n MAX(assets::numeric) AS assets\n FROM ${offersTable}\n GROUP BY group_chain_id, group_maker, \"group_group\"\n ) offer_agg\n ON offer_agg.group_chain_id = g.chain_id\n AND LOWER(offer_agg.group_maker) = LOWER(g.maker)\n AND offer_agg.\"group_group\" = g.\"group\"\n WHERE LOWER(l.\"user\") = LOWER(${user})\n GROUP BY l.chain_id, l.contract, l.\"user\", l.obligation_id\n ),\n position_max_lot AS (\n SELECT\n chain_id,\n contract,\n \"user\",\n obligation_id,\n MAX(upper::numeric) AS max_upper\n FROM ${lotsTable}\n WHERE LOWER(\"user\") = LOWER(${user})\n GROUP BY chain_id, contract, \"user\", obligation_id\n ),\n per_obligation AS (\n SELECT\n pml.chain_id,\n pml.contract,\n pml.\"user\",\n pml.obligation_id,\n GREATEST(0,\n COALESCE(pml.max_upper, 0)\n - COALESCE(po.total_offset, 0)\n - COALESCE(pc.consumed, 0)\n )::text AS reserved_balance\n FROM position_max_lot pml\n LEFT JOIN position_offsets po\n ON po.chain_id = pml.chain_id\n AND LOWER(po.contract) = LOWER(pml.contract)\n AND LOWER(po.\"user\") = LOWER(pml.\"user\")\n AND po.obligation_id = pml.obligation_id\n LEFT JOIN position_consumed pc\n ON pc.chain_id = pml.chain_id\n AND LOWER(pc.contract) = LOWER(pml.contract)\n AND LOWER(pc.\"user\") = LOWER(pml.\"user\")\n AND pc.obligation_id = pml.obligation_id\n )\n SELECT\n p.chain_id,\n p.contract,\n p.\"user\",\n p.block_number,\n po.obligation_id,\n COALESCE(po.reserved_balance, '0') AS reserved_balance\n FROM ${positionsTable} p\n LEFT JOIN per_obligation po\n ON po.chain_id = p.chain_id\n AND LOWER(po.contract) = LOWER(p.contract)\n AND LOWER(po.\"user\") = LOWER(p.\"user\")\n WHERE LOWER(p.\"user\") = LOWER(${user})\n AND p.\"user\" != ${zeroAddress}\n ${cursor !== null ? sql`AND (p.chain_id, p.contract, COALESCE(po.obligation_id, '')) > (${cursor.chainId}, ${cursor.contract}, ${cursor.obligationId ?? \"\"})` : sql``}\n ORDER BY p.chain_id ASC, p.contract ASC, po.obligation_id ASC NULLS FIRST\n LIMIT ${limit}\n `);\n\n const nextCursor =\n raw.rows.length === limit\n ? Buffer.from(\n JSON.stringify({\n chainId: raw.rows[raw.rows.length - 1]!.chain_id.toString(),\n contract: raw.rows[raw.rows.length - 1]!.contract,\n obligationId: raw.rows[raw.rows.length - 1]!.obligation_id,\n }),\n ).toString(\"base64url\")\n : null;\n\n return {\n positions: raw.rows.map((row) => ({\n chainId: row.chain_id,\n contract: row.contract as Address,\n user: row.user as Address,\n blockNumber: row.block_number,\n obligationId: row.obligation_id,\n reserved: BigInt(row.reserved_balance.split(\".\")[0] ?? \"0\"),\n })),\n nextCursor,\n };\n },\n\n setEmptyAfter: async (parameters) => {\n const { chainId, blockNumber } = parameters;\n\n const affected = await db.transaction(async (tx) => {\n const updatedPositions = await tx\n .update(positionsTable)\n .set({\n balance: null,\n blockNumber,\n updatedAt: sql`NOW()`,\n })\n .where(\n and(\n eq(positionsTable.chainId, chainId),\n sql`${positionsTable.blockNumber} >= ${blockNumber}`,\n ),\n )\n .returning();\n\n if (updatedPositions.length === 0) return 0;\n\n await tx.execute(sql`\n DELETE FROM ${transfersTable} t\n USING (VALUES ${sql.join(\n updatedPositions.map(\n (u) =>\n sql`(${u.chainId}::bigint, ${u.contract}::varchar(42), ${u.user}::varchar(42))`,\n ),\n sql`,`,\n )}) AS s(chain_id, \"contract\", \"user\")\n WHERE\n t.chain_id = s.chain_id\n AND t.\"contract\" = s.\"contract\"\n AND (t.\"from\" = s.\"user\" OR t.\"to\" = s.\"user\")\n `);\n\n return updatedPositions.length;\n });\n\n return affected;\n },\n };\n};\n","import { sql } from \"drizzle-orm\";\nimport type { Transfer } from \"#core/index.ts\";\nimport {\n positions as positionsTable,\n transfers as transfersTable,\n} from \"#database/drizzle/schema.ts\";\nimport type { Database } from \"#database/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\n\nexport type TransfersDomain = {\n /**\n * Inserts transfers and updates positions balances with `blockNumber` less than or equal to transfers `blockNumber`.\n * @param transfers - {@link create.Parameters}\n * @returns The number of transfers created. {@link create.ReturnType}\n */\n create: (transfers: create.Parameters) => Promise<create.ReturnType>;\n};\n\nexport declare namespace create {\n export type Parameters = Transfer.Transfer[];\n export type ReturnType = number;\n}\n\nexport const create = (db: Database.Core): TransfersDomain => ({\n create: async (transfers) => {\n if (transfers.length === 0) return 0;\n\n const created = await db.transaction(async (dbTx) => {\n let totalInserted = 0;\n\n for (const transfersBatch of Utils.batch(transfers, DEFAULT_BATCH_SIZE)) {\n const { rows: inserted } = await dbTx.execute<{\n event_id: string;\n chain_id: bigint;\n contract: string;\n from: string;\n to: string;\n value: string;\n block_number: number;\n }>(sql`\n INSERT INTO ${transfersTable} (event_id, chain_id, \"contract\", \"from\", \"to\", \"value\", block_number)\n SELECT * FROM (VALUES ${sql.join(\n transfersBatch.map(\n (transfer) =>\n sql`(${transfer.id}::varchar(128), ${transfer.chainId}::bigint, ${transfer.contract.toLowerCase()}::varchar(42), ${transfer.from.toLowerCase()}::varchar(42), ${transfer.to.toLowerCase()}::varchar(42), ${transfer.value.toString()}::numeric(78, 0), ${transfer.blockNumber}::bigint)`,\n ),\n sql`,`,\n )}) AS v(event_id, chain_id, \"contract\", \"from\", \"to\", \"value\", block_number)\n WHERE\n EXISTS (\n SELECT 1 FROM ${positionsTable} p\n WHERE p.chain_id = v.chain_id AND p.\"contract\" = v.\"contract\" AND p.\"user\" = v.\"from\" AND p.balance IS NOT NULL\n )\n AND\n EXISTS (\n SELECT 1 FROM ${positionsTable} p\n WHERE p.chain_id = v.chain_id AND p.\"contract\" = v.\"contract\" AND p.\"user\" = v.\"to\" AND p.balance IS NOT NULL\n )\n ON CONFLICT DO NOTHING\n RETURNING *;\n `);\n\n if (inserted.length === 0) continue;\n\n await dbTx.execute(sql`\n WITH inserted AS (\n VALUES ${sql.join(\n inserted.map((t) => {\n return sql`(${t.chain_id}::bigint, ${t.contract}::varchar(42), ${t.from}::varchar(42), ${t.to}::varchar(42), ${t.value}::numeric(78, 0), ${t.block_number}::bigint)`;\n }),\n sql`,`,\n )}\n ),\n new_transfers AS (\n SELECT\n column1 AS chain_id,\n column2 AS \"contract\",\n column3 AS \"from\",\n column4 AS \"to\",\n column5 AS \"value\",\n column6 AS block_number\n FROM inserted\n ),\n diffs AS (\n SELECT\n nt.chain_id,\n nt.\"contract\",\n nt.\"from\" AS \"user\",\n -nt.\"value\" AS delta,\n nt.block_number\n FROM new_transfers nt\n UNION ALL\n SELECT\n nt.chain_id,\n nt.\"contract\",\n nt.\"to\" AS \"user\",\n nt.\"value\" AS delta,\n nt.block_number\n FROM new_transfers nt\n ),\n valid_diffs AS (\n SELECT\n d.chain_id,\n d.\"contract\",\n d.\"user\",\n d.delta,\n d.block_number\n FROM diffs d\n JOIN ${positionsTable} p\n ON p.chain_id = d.chain_id\n AND p.\"contract\" = d.\"contract\"\n AND p.\"user\" = d.\"user\"\n -- Only keep per-event diffs that are at or after the current position block\n WHERE d.block_number >= p.block_number\n ),\n aggregated AS (\n SELECT\n chain_id,\n \"contract\",\n \"user\",\n SUM(delta) AS sum_delta,\n MAX(block_number) AS max_block\n FROM valid_diffs\n GROUP BY 1,2,3\n )\n UPDATE ${positionsTable} AS p\n SET\n balance = (COALESCE(p.balance, 0) + a.sum_delta),\n block_number = a.max_block,\n updated_at = NOW()\n FROM aggregated a\n WHERE\n p.chain_id = a.chain_id\n AND p.\"contract\" = a.\"contract\"\n AND p.\"user\" = a.\"user\"\n `);\n\n totalInserted += inserted.length;\n }\n\n return totalInserted;\n });\n\n return created;\n },\n});\n","import { eq, inArray, sql } from \"drizzle-orm\";\nimport type { Hex } from \"viem\";\nimport { Offer, Tree } from \"#core/index.ts\";\nimport * as Utils from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\nimport type * as Database from \"../Database.ts\";\nimport { merklePaths as merklePathsTable, trees as treesTable } from \"../drizzle/schema.ts\";\n\n/**\n * Attestation data for a single offer, containing the merkle root, signature, and proof.\n */\nexport type Attestation = {\n root: Hex;\n signature: Hex;\n proof: Hex[];\n};\n\n/**\n * Input for creating trees with their signatures.\n */\nexport type CreateInput = {\n tree: Tree.Tree;\n signature: Hex;\n};\n\nexport type TreesDomain = {\n /**\n * Creates trees and attestation links in a single transaction.\n *\n * @param trees - Array of decoded trees with signatures (batch insertion)\n * @returns Array of tree roots that were created/upserted\n */\n create: (trees: CreateInput[]) => Promise<Hex[]>;\n\n /**\n * Retrieves merkle attestations for execution flow.\n *\n * @param hashes - Array of offer hashes to look up\n * @returns Map of offer hash to attestation (only entries with attestations are included)\n */\n getAttestations: (hashes: Hex[]) => Promise<Map<Hex, Attestation>>;\n};\n\n/**\n * Creates a Trees domain instance for managing merkle tree metadata.\n *\n * @param config - Configuration with database instance\n * @returns TreesDomain instance\n */\nexport function create(config: { db: Database.Core }): TreesDomain {\n const db = config.db;\n\n return {\n create: async (trees: CreateInput[]): Promise<Hex[]> => {\n if (trees.length === 0) return [];\n\n try {\n return await db.transaction(async (dbTx) => {\n const roots: Hex[] = [];\n\n for (const { tree, signature } of trees) {\n const root = tree.root.toLowerCase() as Hex;\n roots.push(root);\n\n await dbTx\n .insert(treesTable)\n .values({\n root,\n rootSignature: signature.toLowerCase(),\n })\n .onConflictDoUpdate({\n target: [treesTable.root],\n set: {\n rootSignature: signature.toLowerCase(),\n createdAt: sql`NOW()`,\n },\n });\n\n const pathRows = Tree.proofs(tree).map((proof) => ({\n offerHash: Offer.hash(proof.offer).toLowerCase(),\n treeRoot: root,\n proofNodes: concatenateProofs(proof.path),\n }));\n\n for (const batch of Utils.batch(pathRows, DEFAULT_BATCH_SIZE)) {\n await dbTx\n .insert(merklePathsTable)\n .values(batch)\n .onConflictDoUpdate({\n target: [merklePathsTable.offerHash],\n set: {\n treeRoot: sql`excluded.tree_root`,\n proofNodes: sql`excluded.proof_nodes`,\n createdAt: sql`NOW()`,\n },\n });\n }\n }\n\n return roots;\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n throw new Error(\"Trees.create failed. Ensure offers exist before inserting merkle paths.\", {\n cause: error,\n });\n }\n },\n\n getAttestations: async (hashes: Hex[]): Promise<Map<Hex, Attestation>> => {\n if (hashes.length === 0) return new Map();\n\n const normalizedHashes = hashes.map((h) => h.toLowerCase());\n\n const results = await db\n .select({\n offerHash: merklePathsTable.offerHash,\n treeRoot: merklePathsTable.treeRoot,\n proofNodes: merklePathsTable.proofNodes,\n rootSignature: treesTable.rootSignature,\n })\n .from(merklePathsTable)\n .innerJoin(treesTable, eq(merklePathsTable.treeRoot, treesTable.root))\n .where(inArray(merklePathsTable.offerHash, normalizedHashes));\n\n const attestationMap = new Map<Hex, Attestation>();\n\n for (const row of results) {\n attestationMap.set(row.offerHash as Hex, {\n root: row.treeRoot as Hex,\n signature: row.rootSignature as Hex,\n proof: splitProofs(row.proofNodes),\n });\n }\n\n return attestationMap;\n },\n };\n}\n\n/**\n * Concatenates an array of 32-byte hex hashes into a single hex string.\n * Empty arrays return \"0x\".\n */\nfunction concatenateProofs(proofs: Hex[]): string {\n if (proofs.length === 0) return \"0x\";\n return `0x${proofs.map((p) => p.slice(2)).join(\"\")}`;\n}\n\n/**\n * Splits a concatenated hex string back into an array of 32-byte hex hashes.\n * Returns empty array for \"0x\" or empty string.\n */\nfunction splitProofs(concatenated: string): Hex[] {\n if (!concatenated || concatenated === \"0x\" || concatenated.length <= 2) {\n return [];\n }\n const hex = concatenated.slice(2);\n const proofs: Hex[] = [];\n for (let i = 0; i < hex.length; i += 64) {\n proofs.push(`0x${hex.slice(i, i + 64)}` as Hex);\n }\n return proofs;\n}\n","import { and, asc, eq, gt, inArray, sql } from \"drizzle-orm\";\nimport type { Hex } from \"viem\";\nimport * as Offer from \"#core/Offer.ts\";\nimport * as Utils from \"#utils/index.ts\";\nimport { DEFAULT_BATCH_SIZE } from \"../constants.ts\";\nimport type * as Database from \"../Database.ts\";\nimport { status as statusTable, validations as validationsTable } from \"../drizzle/schema.ts\";\n\nconst DEFAULT_LIMIT = 100;\n\nexport type GetParams = {\n status?: Offer.Status;\n cursor?: string;\n limit?: number;\n};\n\nexport type ValidationsDomain = {\n /**\n * Get validation statuses with optional filtering and pagination.\n *\n * @param params - Optional parameters for filtering and pagination\n * @returns Array of validation statuses and next cursor for pagination\n */\n get: (params?: GetParams) => Promise<{\n validations: Offer.Validation[];\n nextCursor: string | null;\n }>;\n\n /**\n * Upsert validations\n *\n * @param validations - Array of validations to upsert\n */\n upsert: (validations: Offer.Validation[]) => Promise<void>;\n};\n\nexport function create(db: Database.Core): ValidationsDomain {\n return {\n get: async (params) => {\n const { status, cursor, limit = DEFAULT_LIMIT } = params ?? {};\n\n if (cursor !== null && cursor !== undefined) {\n if (!cursor.startsWith(\"0x\") || cursor.length !== 66) {\n throw new Error(\"Invalid cursor format\");\n }\n }\n\n let query = db\n .select({\n offerHash: validationsTable.offerHash,\n code: statusTable.code,\n })\n .from(validationsTable)\n .innerJoin(statusTable, eq(validationsTable.statusId, statusTable.id));\n\n if (status !== undefined) {\n query = query.where(eq(statusTable.code, status)) as typeof query;\n }\n\n if (cursor !== null && cursor !== undefined) {\n const cursorCondition = gt(validationsTable.offerHash, cursor.toLowerCase());\n if (status !== undefined) {\n query = query.where(and(eq(statusTable.code, status), cursorCondition)) as typeof query;\n } else {\n query = query.where(cursorCondition) as typeof query;\n }\n }\n\n const results = await query.orderBy(asc(validationsTable.offerHash)).limit(limit);\n\n const mapped: Offer.Validation[] = results.map((row) => ({\n offerHash: row.offerHash as Hex,\n status: row.code as Offer.Status,\n }));\n\n const nextCursor = mapped.length === limit ? mapped[mapped.length - 1]!.offerHash : null;\n\n return { validations: mapped, nextCursor };\n },\n\n upsert: async (results) => {\n if (results.length === 0) return;\n\n const allowedStatuses = new Set(Object.values(Offer.Status));\n const invalidStatuses = Array.from(\n new Set(results.map((r) => r.status).filter((s) => !allowedStatuses.has(s))),\n );\n if (invalidStatuses.length > 0) {\n throw new Error(`Unknown validation status: ${invalidStatuses.join(\", \")}`);\n }\n\n const normalized = results.map((r) => ({\n offerHash: r.offerHash.toLowerCase(),\n status: r.status,\n }));\n\n const uniqueStatuses = Array.from(new Set(normalized.map((r) => r.status)));\n const statusRows = await db\n .select({ id: statusTable.id, code: statusTable.code })\n .from(statusTable)\n .where(inArray(statusTable.code, uniqueStatuses as Offer.Status[]));\n\n const statusMap = new Map(statusRows.map((row) => [row.code, row.id] as const));\n\n for (const status of uniqueStatuses) {\n if (!statusMap.has(status)) {\n throw new Error(`Unknown validation status: ${status}`);\n }\n }\n\n const values = normalized.map((row) => ({\n offerHash: row.offerHash,\n statusId: statusMap.get(row.status)!,\n }));\n\n for (const batch of Utils.batch(values, DEFAULT_BATCH_SIZE)) {\n await db\n .insert(validationsTable)\n .values(batch)\n .onConflictDoUpdate({\n target: [validationsTable.offerHash],\n set: {\n statusId: sql`excluded.status_id`,\n updatedAt: sql`NOW()`,\n },\n });\n }\n },\n };\n}\n","import crypto from \"node:crypto\";\nimport { PGlite } from \"@electric-sql/pglite\";\nimport { drizzle } from \"drizzle-orm/node-postgres\";\nimport { migrate as migratePostgres } from \"drizzle-orm/node-postgres/migrator\";\nimport { drizzle as drizzleLite } from \"drizzle-orm/pglite\";\nimport { migrate as migratePGLite } from \"drizzle-orm/pglite/migrator\";\nimport { Pool } from \"pg\";\nimport type * as ChainRegistry from \"#core/ChainRegistry.ts\";\nimport { Offer, Position } from \"#core/index.ts\";\nimport { Tracer } from \"#tracer/index.ts\";\nimport {\n BlocksDomain,\n BookDomain,\n CallbacksDomain,\n ConsumedDomain,\n GroupsDomain,\n LotsDomain,\n ObligationsDomain,\n OffersDomain,\n OffsetsDomain,\n OraclesDomain,\n PositionsDomain,\n TransfersDomain,\n TreesDomain,\n ValidationsDomain,\n} from \"./domains/index.ts\";\nimport * as offersSchema from \"./drizzle/schema.ts\";\nimport { VERSION } from \"./drizzle/VERSION.ts\";\nimport { ObligationsListingReader } from \"./readers/index.ts\";\n\nexport type Driver = ReturnType<typeof drizzle> | ReturnType<typeof drizzleLite>;\n\ntype Domains = {\n book: BookDomain.BookDomain;\n blocks: BlocksDomain.BlocksDomain;\n callbacks: CallbacksDomain.CallbacksDomain;\n offers: OffersDomain.OffersDomain;\n consumed: ConsumedDomain.ConsumedDomain;\n groups: GroupsDomain.GroupsDomain;\n lots: LotsDomain.LotsDomain;\n obligations: ObligationsDomain.ObligationsDomain;\n offsets: OffsetsDomain.OffsetsDomain;\n oracles: OraclesDomain.OraclesDomain;\n trees: TreesDomain.TreesDomain;\n validations: ValidationsDomain.ValidationsDomain;\n positions: PositionsDomain.PositionsDomain;\n transfers: TransfersDomain.TransfersDomain;\n};\n\ntype Readers = {\n obligations: ObligationsListingReader.ObligationsListingReader;\n};\n\ntype DatabaseFacade = Domains & {\n readers: Readers;\n};\n\nexport type WithDomains<D extends Driver> = D & DatabaseFacade;\n\nexport type Core = Omit<WithDomains<Driver>, \"transaction\"> & {\n transaction<T>(fn: (tx: WithDomains<Driver>) => Promise<T>): Promise<T>;\n};\n\nexport type Database = Core & {\n name: \"pg\" | \"pglite\";\n pool: Pool | PGlite;\n applyMigrations: (folderPath: string) => Promise<void>;\n clean: () => Promise<void>;\n};\n\nfunction createDomains<core extends Core>(\n core: core,\n chainRegistry: ChainRegistry.ChainRegistry,\n): Domains {\n const domains = {\n book: BookDomain.create({ db: core }),\n blocks: BlocksDomain.create({ db: core, chainRegistry }),\n callbacks: CallbacksDomain.create(core),\n offers: OffersDomain.create({ db: core }),\n consumed: ConsumedDomain.create(core),\n groups: GroupsDomain.create(core),\n lots: LotsDomain.create(core),\n obligations: ObligationsDomain.create(core),\n offsets: OffsetsDomain.create(core),\n oracles: OraclesDomain.create(core),\n trees: TreesDomain.create({ db: core }),\n validations: ValidationsDomain.create(core),\n positions: PositionsDomain.create(core),\n transfers: TransfersDomain.create(core),\n };\n\n return domains;\n}\n\nfunction createReaders<core extends Core>(core: core): Readers {\n return {\n obligations: ObligationsListingReader.create({ db: core }),\n };\n}\n\n// One wrapper per original driver/tx and chain registry\nconst AUGMENT_CACHE: WeakMap<object, WeakMap<ChainRegistry.ChainRegistry, Core>> = new WeakMap();\nfunction augmentWithDomains(base: Driver, chainRegistry: ChainRegistry.ChainRegistry): Core {\n const cached = AUGMENT_CACHE.get(base)?.get(chainRegistry);\n if (cached) return cached;\n\n // Create a wrapper that delegates to the driver\n const wrapped = Object.create(base) as Core;\n\n // Override transaction: wrap the tx with domains as well\n wrapped.transaction = async <T>(fn: (tx: WithDomains<Driver>) => Promise<T>): Promise<T> => {\n return base.transaction(async (tx) => {\n const txWithDomains = augmentWithDomains(tx as unknown as Driver, chainRegistry);\n return fn(txWithDomains as unknown as WithDomains<Driver>);\n });\n };\n\n const dms = createDomains(wrapped, chainRegistry);\n const readers = createReaders(wrapped);\n\n Object.defineProperties(wrapped, {\n book: { value: dms.book, enumerable: true },\n blocks: { value: dms.blocks, enumerable: true },\n callbacks: { value: dms.callbacks, enumerable: true },\n offers: { value: dms.offers, enumerable: true },\n consumed: { value: dms.consumed, enumerable: true },\n groups: { value: dms.groups, enumerable: true },\n lots: { value: dms.lots, enumerable: true },\n obligations: { value: dms.obligations, enumerable: true },\n offsets: { value: dms.offsets, enumerable: true },\n oracles: { value: dms.oracles, enumerable: true },\n trees: { value: dms.trees, enumerable: true },\n validations: { value: dms.validations, enumerable: true },\n positions: { value: dms.positions, enumerable: true },\n transfers: { value: dms.transfers, enumerable: true },\n readers: { value: readers, enumerable: true },\n });\n\n const chainRegistryMap = AUGMENT_CACHE.get(base);\n if (!chainRegistryMap) {\n AUGMENT_CACHE.set(base, new Map([[chainRegistry, wrapped]]));\n } else {\n chainRegistryMap.set(chainRegistry, wrapped);\n }\n\n return wrapped;\n}\n\nconst InMemoryDbMap: Map<string, Database> = new Map();\nconst LEGACY_SCHEMA_START_MINOR = 7;\n\n/**\n * Connect to the database.\n * @notice If no connection string is provided, an in-process PGLite database is created.\n * @param {string=} [connectionString] - The optional connection string for the Postgres database.\n * @returns The database client {@link connect.ReturnType}\n */\nexport function connect(\n chainRegistry: ChainRegistry.ChainRegistry,\n connectionString?: string,\n): Database {\n const clean = async (driver: Driver) => {\n if (offersSchema.TABLE_NAMES.length === 0) return;\n await driver.execute(\n `TRUNCATE TABLE ${offersSchema.VERSIONED_TABLE_NAMES.join(\", \")} RESTART IDENTITY CASCADE;`,\n );\n };\n\n if (connectionString !== undefined) {\n const pool = new Pool({ connectionString });\n const driver = drizzle(pool, { schema: offersSchema });\n const core = augmentWithDomains(driver, chainRegistry);\n\n const db = Object.assign(core, {\n name: \"pg\" as const,\n pool,\n applyMigrations: applyMigrations(\"pg\", driver),\n clean: async () => await clean(driver),\n } as const);\n\n return db;\n }\n\n // Include VITEST_POOL_ID in cache key to isolate PGLite instances per test worker\n // This prevents lock contention when multiple workers run migrations simultaneously\n const poolId = process.env.VITEST_POOL_ID ?? \"\";\n const key = crypto\n .createHash(\"md5\")\n .update(JSON.stringify(chainRegistry.list()) + poolId)\n .digest(\"hex\");\n const cached = InMemoryDbMap.get(key);\n if (cached) return cached;\n\n const pool = new PGlite();\n const driver = drizzleLite(pool, { schema: offersSchema });\n const core = augmentWithDomains(driver, chainRegistry);\n\n InMemoryDbMap.set(\n key,\n Object.assign(core, {\n name: \"pglite\" as const,\n pool,\n applyMigrations: applyMigrations(\"pglite\", driver),\n clean: async () => await clean(driver),\n } as const),\n );\n\n return InMemoryDbMap.get(key)!;\n}\n\nconst MIGRATED_DRIVERS = new WeakSet<Driver>();\nfunction applyMigrations(\n kind: \"pg\" | \"pglite\",\n driver: Driver,\n): (folderPath: string) => Promise<void> {\n return async (folderPath: string) => {\n if (MIGRATED_DRIVERS.has(driver)) return;\n\n const tracer = Tracer.getTracer(\"db.applyMigrations\");\n await Tracer.startActiveSpan(tracer, \"db.applyMigrations\", async () => {\n await preMigrate(driver);\n\n if (kind === \"pg\") {\n await migratePostgres(driver as ReturnType<typeof drizzle>, {\n migrationsFolder: folderPath,\n });\n } else {\n await migratePGLite(driver as ReturnType<typeof drizzleLite>, {\n migrationsFolder: folderPath,\n });\n }\n\n await postMigrate(driver);\n });\n\n MIGRATED_DRIVERS.add(driver);\n };\n}\n\nasync function preMigrate(driver: Driver) {\n const tracer = Tracer.getTracer(\"db.preMigrate\");\n await Tracer.startActiveSpan(tracer, \"db.preMigrate\", async () => {\n const schemaNames = getSchemaNamesForMigration(VERSION);\n for (const schemaName of schemaNames) {\n await driver.execute(`create schema if not exists \"${schemaName}\"`);\n }\n });\n}\n\n/**\n * Build the list of router schemas that should exist before running migrations.\n * @param version - Current schema version (e.g. `router_v1.8`).\n * @returns Ordered schema names from `router_v1.7` to current, or just current if parsing fails.\n */\nexport function getSchemaNamesForMigration(version: string): string[] {\n const parsed = /^router_v(?<major>\\d+)\\.(?<minor>\\d+)$/.exec(version);\n if (!parsed?.groups?.major || !parsed.groups.minor) return [version];\n\n const major = Number.parseInt(parsed.groups.major, 10);\n const currentMinor = Number.parseInt(parsed.groups.minor, 10);\n\n if (!Number.isInteger(major) || !Number.isInteger(currentMinor)) return [version];\n if (currentMinor < LEGACY_SCHEMA_START_MINOR) return [version];\n\n const schemaNames: string[] = [];\n for (let minor = LEGACY_SCHEMA_START_MINOR; minor <= currentMinor; minor += 1) {\n schemaNames.push(`router_v${major}.${minor}`);\n }\n return schemaNames;\n}\n\nasync function postMigrate(driver: Driver) {\n const tracer = Tracer.getTracer(\"db.postMigrate\");\n await Tracer.startActiveSpan(tracer, \"db.postMigrate\", async () => {\n await driver.execute(\n `INSERT INTO \"${VERSION}\".\"status\" (\"code\") VALUES ('${Offer.Status.VALID}'), ('${Offer.Status.SIMULATION_ERROR}') ON CONFLICT DO NOTHING;`,\n );\n await driver.execute(\n `INSERT INTO \"${VERSION}\".\"position_types\" (\"type\") VALUES ('${Position.Type.ERC20}'), ('${Position.Type.VAULT_V1}') ON CONFLICT DO NOTHING;`,\n );\n\n await driver.execute(`\n CREATE OR REPLACE FUNCTION apply_group_consumed_stmt_ins()\n RETURNS trigger\n LANGUAGE plpgsql AS $$\n BEGIN\n WITH deltas AS (\n SELECT chain_id, maker, \"group\", SUM(amount)::numeric AS delta\n FROM new_rows\n GROUP BY 1,2,3\n )\n UPDATE \"${VERSION}\".\"groups\" g\n SET consumed = g.consumed + d.delta\n FROM deltas d\n WHERE g.chain_id = d.chain_id\n AND g.maker = d.maker\n AND g.\"group\" = d.\"group\";\n RETURN NULL;\n END;\n $$;`);\n\n await driver.execute(`\n CREATE OR REPLACE FUNCTION apply_group_consumed_stmt_del()\n RETURNS trigger\n LANGUAGE plpgsql AS $$\n BEGIN\n -- Apply negative deltas per touched group\n WITH deltas AS (\n SELECT chain_id, maker, \"group\", -SUM(amount)::numeric AS delta\n FROM old_rows\n GROUP BY 1,2,3\n )\n UPDATE \"${VERSION}\".\"groups\" g\n SET consumed = g.consumed + d.delta\n FROM deltas d\n WHERE g.chain_id = d.chain_id\n AND g.maker = d.maker\n AND g.\"group\" = d.\"group\";\n RETURN NULL;\n END;\n $$;\n `);\n\n // UPDATE (handles same-group changes and “moves”)\n await driver.execute(`\n CREATE OR REPLACE FUNCTION apply_group_consumed_stmt_upd()\n RETURNS trigger\n LANGUAGE plpgsql AS $$\n BEGIN\n -- 1) Compute deltas (new - old) per logical group and apply\n WITH new_agg AS (\n SELECT chain_id, maker, \"group\", SUM(amount)::numeric AS sum_amt\n FROM new_rows\n GROUP BY 1,2,3\n ),\n old_agg AS (\n SELECT chain_id, maker, \"group\", SUM(amount)::numeric AS sum_amt\n FROM old_rows\n GROUP BY 1,2,3\n ),\n deltas AS (\n SELECT\n COALESCE(n.chain_id, o.chain_id) AS chain_id,\n COALESCE(n.maker, o.maker) AS maker,\n COALESCE(n.\"group\", o.\"group\") AS \"group\",\n COALESCE(n.sum_amt, 0) - COALESCE(o.sum_amt, 0) AS delta\n FROM new_agg n\n FULL JOIN old_agg o\n ON n.chain_id = o.chain_id AND n.maker = o.maker AND n.\"group\" = o.\"group\"\n WHERE COALESCE(n.sum_amt, 0) <> COALESCE(o.sum_amt, 0)\n )\n UPDATE \"${VERSION}\".\"groups\" g\n SET consumed = g.consumed + d.delta\n FROM deltas d\n WHERE g.chain_id = d.chain_id\n AND g.maker = d.maker\n AND g.\"group\" = d.\"group\";\n RETURN NULL;\n END;\n $$;\n `);\n\n // Triggers (statement-level with transition tables)\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_consumed_events_apply_insert_stmt\n AFTER INSERT ON \"${VERSION}\".\"consumed_events\"\n REFERENCING NEW TABLE AS new_rows\n FOR EACH STATEMENT\n EXECUTE FUNCTION apply_group_consumed_stmt_ins();`);\n\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_consumed_events_apply_delete_stmt\n AFTER DELETE ON \"${VERSION}\".\"consumed_events\"\n REFERENCING OLD TABLE AS old_rows\n FOR EACH STATEMENT\n EXECUTE FUNCTION apply_group_consumed_stmt_del();\n `);\n\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_consumed_events_apply_update_stmt\n AFTER UPDATE ON \"${VERSION}\".\"consumed_events\"\n REFERENCING NEW TABLE AS new_rows OLD TABLE AS old_rows\n FOR EACH STATEMENT\n EXECUTE FUNCTION apply_group_consumed_stmt_upd();\n `);\n\n await driver.execute(`\n CREATE OR REPLACE FUNCTION oco_on_groups_consumed_update()\n RETURNS trigger\n LANGUAGE plpgsql AS $$\n BEGIN\n WITH touched AS (\n SELECT DISTINCT chain_id, maker, \"group\", consumed FROM new_groups\n )\n DELETE FROM \"${VERSION}\".\"offers\" o\n USING touched t\n WHERE o.group_chain_id = t.chain_id\n AND o.group_maker = t.maker\n AND o.group_group = t.\"group\"\n AND o.assets <= t.consumed;\n RETURN NULL;\n END;\n $$;\n `);\n\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_groups_oco_after_update\n AFTER UPDATE ON \"${VERSION}\".\"groups\"\n REFERENCING NEW TABLE AS new_groups\n FOR EACH STATEMENT\n EXECUTE FUNCTION oco_on_groups_consumed_update();\n `);\n\n await driver.execute(`\n CREATE OR REPLACE FUNCTION oco_on_offers_insert()\n RETURNS trigger\n LANGUAGE plpgsql AS $$\n BEGIN\n WITH touched AS (\n SELECT DISTINCT group_chain_id, group_maker, group_group AS \"group\"\n FROM new_rows\n )\n DELETE FROM \"${VERSION}\".\"offers\" o\n USING touched t, \"${VERSION}\".\"groups\" g\n WHERE o.group_chain_id = t.group_chain_id\n AND o.group_maker = t.group_maker\n AND o.group_group = t.\"group\"\n AND o.assets <= g.consumed;\n RETURN NULL;\n END;\n $$;`);\n\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_offers_oco_insert_stmt\n AFTER INSERT ON \"${VERSION}\".\"offers\"\n REFERENCING NEW TABLE AS new_rows\n FOR EACH STATEMENT\n EXECUTE FUNCTION oco_on_offers_insert();\n `);\n\n await driver.execute(`\n CREATE OR REPLACE FUNCTION cleanup_orphan_positions()\n RETURNS TRIGGER AS $$\n BEGIN\n DELETE FROM \"${VERSION}\".\"positions\" p\n USING (\n SELECT DISTINCT c.position_chain_id, c.position_contract, c.position_user\n FROM deleted_rows d\n JOIN \"${VERSION}\".\"callbacks\" c ON c.id = d.callback_id\n ) AS affected\n WHERE p.chain_id = affected.position_chain_id\n AND p.contract = affected.position_contract\n AND p.\"user\" = affected.position_user\n AND NOT EXISTS (\n SELECT 1 FROM \"${VERSION}\".\"callbacks\" c2\n JOIN \"${VERSION}\".\"offers_callbacks\" oc ON oc.callback_id = c2.id\n WHERE c2.position_chain_id = p.chain_id\n AND c2.position_contract = p.contract\n AND c2.position_user = p.\"user\"\n );\n RETURN NULL;\n END;\n $$ LANGUAGE plpgsql;\n `);\n\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_cleanup_orphan_positions\n AFTER DELETE ON \"${VERSION}\".\"offers_callbacks\"\n REFERENCING OLD TABLE AS deleted_rows\n FOR EACH STATEMENT\n EXECUTE FUNCTION cleanup_orphan_positions();\n `);\n\n await driver.execute(`\n CREATE OR REPLACE FUNCTION cleanup_orphan_groups()\n RETURNS TRIGGER AS $$\n BEGIN\n DELETE FROM \"${VERSION}\".\"groups\" g\n USING (\n SELECT DISTINCT group_chain_id, group_maker, group_group\n FROM deleted_rows\n ) AS affected\n WHERE g.chain_id = affected.group_chain_id\n AND g.maker = affected.group_maker\n AND g.\"group\" = affected.group_group\n AND NOT EXISTS (\n SELECT 1 FROM \"${VERSION}\".\"offers\" o\n WHERE o.group_chain_id = g.chain_id\n AND o.group_maker = g.maker\n AND o.group_group = g.\"group\"\n );\n RETURN NULL;\n END;\n $$ LANGUAGE plpgsql;\n `);\n\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_cleanup_orphan_groups\n AFTER DELETE ON \"${VERSION}\".\"offers\"\n REFERENCING OLD TABLE AS deleted_rows\n FOR EACH STATEMENT\n EXECUTE FUNCTION cleanup_orphan_groups();\n `);\n\n await driver.execute(`\n CREATE OR REPLACE FUNCTION cleanup_orphan_obligations_and_oracles()\n RETURNS TRIGGER AS $$\n DECLARE\n orphan_obligation_ids TEXT[];\n candidate_oracles RECORD;\n BEGIN\n -- 1. Find orphan obligation IDs\n SELECT ARRAY_AGG(DISTINCT obligation_id) INTO orphan_obligation_ids\n FROM deleted_rows d\n WHERE NOT EXISTS (\n SELECT 1 FROM \"${VERSION}\".\"offers\" ov\n WHERE ov.obligation_id = d.obligation_id\n );\n\n -- 2. If no orphan obligations, exit early\n IF orphan_obligation_ids IS NULL OR array_length(orphan_obligation_ids, 1) IS NULL THEN\n RETURN NULL;\n END IF;\n\n -- 3. Capture candidate oracles (from collaterals of orphan obligations)\n CREATE TEMP TABLE _candidate_oracles ON COMMIT DROP AS\n SELECT DISTINCT oc.oracle_chain_id, oc.oracle_address\n FROM \"${VERSION}\".\"obligation_collaterals_v2\" oc\n WHERE oc.obligation_id = ANY(orphan_obligation_ids);\n\n -- 4. Delete orphan obligations (cascades to collaterals)\n DELETE FROM \"${VERSION}\".\"obligations\" ob\n WHERE ob.obligation_id = ANY(orphan_obligation_ids);\n\n -- 5. Delete oracles that are now orphaned (no remaining collateral references)\n DELETE FROM \"${VERSION}\".\"oracles\" o\n USING _candidate_oracles co\n WHERE o.chain_id = co.oracle_chain_id\n AND o.address = co.oracle_address\n AND NOT EXISTS (\n SELECT 1 FROM \"${VERSION}\".\"obligation_collaterals_v2\" oc\n WHERE oc.oracle_chain_id = o.chain_id\n AND oc.oracle_address = o.address\n );\n\n RETURN NULL;\n END;\n $$ LANGUAGE plpgsql;\n `);\n\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_cleanup_orphan_obligations_and_oracles\n AFTER DELETE ON \"${VERSION}\".\"offers\"\n REFERENCING OLD TABLE AS deleted_rows\n FOR EACH STATEMENT\n EXECUTE FUNCTION cleanup_orphan_obligations_and_oracles();\n `);\n\n // Create offset when lot is deleted (before delete to capture lot data)\n await driver.execute(`\n CREATE OR REPLACE FUNCTION create_offset_on_lot_delete()\n RETURNS trigger\n LANGUAGE plpgsql AS $$\n BEGIN\n INSERT INTO \"${VERSION}\".\"offsets\" (chain_id, \"user\", contract, \"group\", obligation_id, value)\n VALUES (\n OLD.chain_id,\n OLD.\"user\",\n OLD.contract,\n OLD.\"group\",\n OLD.obligation_id,\n OLD.upper::numeric - OLD.lower::numeric\n )\n ON CONFLICT (chain_id, \"user\", contract, \"group\", obligation_id) DO NOTHING;\n RETURN OLD;\n END;\n $$;\n `);\n\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_lots_create_offset_before_delete\n BEFORE DELETE ON \"${VERSION}\".\"lots\"\n FOR EACH ROW\n EXECUTE FUNCTION create_offset_on_lot_delete();\n `);\n\n // Delete position if no lots remain after lot deletion\n await driver.execute(`\n CREATE OR REPLACE FUNCTION delete_position_if_no_lots()\n RETURNS trigger\n LANGUAGE plpgsql AS $$\n BEGIN\n -- Check if any lots remain on this position\n IF NOT EXISTS (\n SELECT 1 FROM \"${VERSION}\".\"lots\" l\n WHERE l.chain_id = OLD.chain_id\n AND l.contract = OLD.contract\n AND l.\"user\" = OLD.\"user\"\n ) THEN\n -- No lots remain, delete the position (cascades to offsets)\n DELETE FROM \"${VERSION}\".\"positions\" p\n WHERE p.chain_id = OLD.chain_id\n AND p.contract = OLD.contract\n AND p.\"user\" = OLD.\"user\";\n END IF;\n RETURN NULL;\n END;\n $$;\n `);\n\n await driver.execute(`\n CREATE OR REPLACE TRIGGER trg_lots_delete_position_if_empty\n AFTER DELETE ON \"${VERSION}\".\"lots\"\n FOR EACH ROW\n EXECUTE FUNCTION delete_position_if_no_lots();\n `);\n });\n}\n","import type { Offer } from \"#core\";\nimport * as OfferCore from \"#core/Offer.ts\";\nimport type * as Gate from \"./Gate.ts\";\nimport type {\n ConfigRule,\n ConfigRulesPayload,\n ErrorPayload,\n SuccessPayload,\n ValidateOffersData,\n} from \"./types.ts\";\n\nexport type GatekeeperClient = {\n /** Validate offers and return the raw response payload. */\n validate: (body: unknown) => Promise<{ statusCode: number; body: unknown }>;\n /** Get configured rules for supported chains. */\n getConfigRules: (query?: {\n cursor?: string;\n limit?: number | string;\n types?: Array<ConfigRule[\"type\"]> | ConfigRule[\"type\"];\n }) => Promise<{ statusCode: number; body: ConfigRulesPayload }>;\n /** Validate offers and return decision results. */\n isAllowed: (offers: Offer.Offer[]) => Promise<Gate.Result<Offer.Offer, string>>;\n /** Base URL for the gatekeeper service. */\n baseUrl: string;\n};\n\nexport type ClientConfig = {\n baseUrl: string;\n timeoutMs?: number;\n fetchFn?: typeof fetch;\n originSecret?: string;\n};\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\n/**\n * Create an HTTP client for a gatekeeper service.\n * @param config - Gatekeeper client configuration. {@link ClientConfig}\n * @returns An HTTP-backed gatekeeper client. {@link GatekeeperClient}\n */\nexport function createHttpClient(config: ClientConfig): GatekeeperClient {\n const fetchFn = config.fetchFn ?? fetch;\n const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const baseUrl = normalizeBaseUrl(config.baseUrl);\n const baseHeaders = config.originSecret ? { \"x-origin-verify\": config.originSecret } : undefined;\n\n const request = async (path: string, init: RequestInit): Promise<Response> => {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n try {\n return await fetchFn(`${baseUrl}${path}`, {\n ...init,\n headers: mergeHeaders(baseHeaders, init.headers),\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timeout);\n }\n };\n\n const validate = async (body: unknown): Promise<{ statusCode: number; body: unknown }> => {\n const response = await request(\"/v1/validate\", {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n const json = (await response.json()) as unknown;\n return { statusCode: response.status, body: json };\n };\n\n const getConfigRules = async (query?: {\n cursor?: string;\n limit?: number | string;\n types?: Array<ConfigRule[\"type\"]> | ConfigRule[\"type\"];\n }): Promise<{ statusCode: number; body: ConfigRulesPayload }> => {\n const params = new URLSearchParams();\n if (query?.cursor) params.set(\"cursor\", query.cursor);\n if (query?.limit !== undefined) params.set(\"limit\", query.limit.toString());\n if (query?.types !== undefined) {\n const typesValue = Array.isArray(query.types) ? query.types.join(\",\") : query.types;\n if (typesValue.length > 0) params.set(\"types\", typesValue);\n }\n const path = params.size > 0 ? `/v1/config/rules?${params.toString()}` : \"/v1/config/rules\";\n const response = await request(path, { method: \"GET\" });\n const json = (await response.json()) as ConfigRulesPayload;\n return { statusCode: response.status, body: json };\n };\n\n const isAllowed = async (offers: Offer.Offer[]): Promise<Gate.Result<Offer.Offer, string>> => {\n const payload = {\n offers: offers.map((offer) => OfferCore.toSnakeCase(offer)),\n };\n\n const { statusCode, body } = await validate(payload);\n if (statusCode !== 200) {\n const errorMessage = extractErrorMessage(body);\n throw new Error(`Gatekeeper validation failed: ${errorMessage ?? `status ${statusCode}`}`);\n }\n\n const data = (body as SuccessPayload<ValidateOffersData>).data;\n if (!data || typeof data !== \"object\") {\n throw new Error(\"Gatekeeper validation response is invalid.\");\n }\n\n if (\"issues\" in data) {\n const issues = data.issues.map((issue) => ({\n ruleName: issue.rule,\n message: issue.message,\n item: offers[issue.index]!,\n }));\n const invalidIndices = new Set(data.issues.map((issue) => issue.index));\n const valid = offers.filter((_, index) => !invalidIndices.has(index));\n\n return { valid, issues };\n }\n\n if (!(\"payload\" in data) || !(\"root\" in data)) {\n throw new Error(\"Gatekeeper validation response is missing payload data.\");\n }\n\n return { valid: offers.slice(), issues: [] };\n };\n\n return {\n baseUrl,\n validate,\n getConfigRules,\n isAllowed,\n };\n}\n\nfunction mergeHeaders(\n base: RequestInit[\"headers\"] | undefined,\n extra: RequestInit[\"headers\"] | undefined,\n): RequestInit[\"headers\"] | undefined {\n if (!base && !extra) return undefined;\n const merged = new Headers(base ?? undefined);\n if (extra) {\n for (const [key, value] of new Headers(extra).entries()) {\n merged.set(key, value);\n }\n }\n return merged;\n}\n\nfunction normalizeBaseUrl(url: string): string {\n const trimmed = url.trim().replace(/\\/+$/, \"\");\n return trimmed;\n}\n\nfunction extractErrorMessage(payload: unknown): string | undefined {\n if (!payload || typeof payload !== \"object\") return undefined;\n const error = (payload as ErrorPayload).error;\n if (!error || typeof error !== \"object\") return undefined;\n return typeof error.message === \"string\" ? error.message : undefined;\n}\n","/**\n * A validation rule.\n */\nexport type Rule<T, Name extends string = string> =\n | { kind: \"single\"; name: Name; description: string; run: Single<T, Name> }\n | { kind: \"batch\"; name: Name; description: string; run: Batch<T, Name> };\n\nexport type RuleNames<Rules extends readonly { name: string }[]> = Rules[number][\"name\"];\n\n/**\n * A single item validation rule.\n * @param item - The item to validate.\n * @returns The issue that was found. If the item is valid, this will be undefined.\n */\nexport type Single<T, RuleName extends string> = (\n item: T,\n) =>\n | Omit<Issue<T, RuleName>, \"ruleName\" | \"item\">\n | undefined\n | Promise<Omit<Issue<T, RuleName>, \"ruleName\" | \"item\"> | undefined>;\n\n/**\n * A batch item validation rule.\n * @param items - The items to validate.\n * @returns A map of the items to the issue that was found.\n */\nexport type Batch<T, RuleName extends string> = (\n items: T[],\n) =>\n | Map<number, Omit<Issue<T, RuleName>, \"ruleName\" | \"item\"> | undefined>\n | Promise<Map<number, Omit<Issue<T, RuleName>, \"ruleName\" | \"item\"> | undefined>>;\n\n/**\n * Create a validation rule iterating over a single item at a time.\n * @param name - The name of the rule.\n * @param description - A human-readable description of the rule.\n * @param run - The function that validates the rule.\n * @returns The created rule.\n */\nexport function single<Name extends string, T>(\n name: Name,\n description: string,\n run: Single<T, Name>,\n): Rule<T, Name> {\n return { kind: \"single\", name, description, run } as const satisfies Rule<T, Name>;\n}\n\n/**\n * Create a validation rule iterating over a batch of items at a time.\n * @param name - The name of the rule.\n * @param description - A human-readable description of the rule.\n * @param run - The function that validates the rule.\n * @returns The created rule.\n */\nexport function batch<Name extends string, T>(\n name: Name,\n description: string,\n run: Batch<T, Name>,\n): Rule<T, Name> {\n return { kind: \"batch\", name, description, run } as const satisfies Rule<T, Name>;\n}\n\n/**\n * A validation issue.\n */\nexport type Issue<T, RuleName extends string = string> = {\n /** The name of the rule that caused the issue. */\n ruleName: RuleName;\n /** The message of the issue. */\n message: string;\n /** The item that was not valid. */\n item: T;\n};\n\n/**\n * The result of a validation.\n */\nexport type Result<T, RuleName extends string = string> = {\n /** The items that were valid. */\n valid: T[];\n /** The reports of the failed validations. */\n issues: Issue<T, RuleName>[];\n};\n\nexport async function run<\n T,\n Name extends string,\n Rules extends readonly Rule<T, Name>[],\n>(parameters: {\n items: T[];\n rules: Rules;\n chunkSize?: number;\n}): Promise<Result<T, RuleNames<Rules>>> {\n const { items, rules, chunkSize } = parameters;\n\n const issues: Issue<T, RuleNames<Rules>>[] = [];\n let validItems: T[] = items.slice();\n\n for (const rule of rules) {\n if (validItems.length === 0) return { valid: [], issues };\n\n const indicesToRemove: Set<number> = new Set();\n if (rule.kind === \"single\") {\n for (let i = 0; i < validItems.length; i++) {\n const item = validItems[i]!;\n const issue = await rule.run(item);\n if (issue) {\n issues.push({ ...issue, ruleName: rule.name, item });\n indicesToRemove.add(i);\n }\n }\n } else if (rule.kind === \"batch\") {\n const exec = async (slice: T[], offset: number) => {\n const map = await rule.run(slice);\n for (let i = 0; i < slice.length; i++) {\n const issue = map.get(i);\n if (issue !== undefined) {\n issues.push({ ...issue, ruleName: rule.name, item: slice[i]! });\n indicesToRemove.add(offset + i);\n }\n }\n };\n\n if (!chunkSize) await exec(validItems, 0);\n else {\n for (let i = 0; i < validItems.length; i += chunkSize) {\n await exec(validItems.slice(i, i + chunkSize), i);\n }\n }\n }\n\n validItems = validItems.filter((_, i) => !indicesToRemove.has(i));\n }\n\n return {\n valid: validItems,\n issues,\n };\n}\n","import type { Offer } from \"#core\";\nimport * as Gate from \"./Gate.ts\";\n\nexport type Rules = readonly Gate.Rule<Offer.Offer, string>[];\n\nexport type Gatekeeper = {\n isAllowed: (offers: Offer.Offer[]) => Promise<Gate.Result<Offer.Offer, string>>;\n};\n\ntype GatekeeperParameters = {\n rules: Rules;\n};\n\n/**\n * Create a gatekeeper instance with the provided rules.\n * @param parameters - Gatekeeper parameters. {@link GatekeeperParameters}\n * @returns Gatekeeper instance. {@link Gatekeeper}\n */\nexport function create(parameters: GatekeeperParameters): Gatekeeper {\n const { rules } = parameters;\n return {\n isAllowed: async (offers: Offer.Offer[]) => {\n return await Gate.run({\n items: offers,\n rules,\n });\n },\n };\n}\n","import type { Address, PublicClient, Transport } from \"viem\";\nimport { Callback, type Chain, Maturity, type Offer } from \"#core\";\nimport * as BigMath from \"#utils/BigMath.ts\";\nimport type * as Validation from \"./Gate.ts\";\nimport { batch, single } from \"./Gate.ts\";\n\nexport type ValidityParameters = {\n client: PublicClient<Transport, Chain.Chain>;\n};\n\n/**\n * set of rules to validate offers.\n *\n * @param _parameters - Validity parameters with chain and client\n * @returns Array of validation rules to evaluate against offers\n */\nexport function validity(_parameters: ValidityParameters) {\n const expiry = single(\"expiry\", \"Validates that offer has not expired\", (offer: Offer.Offer) => {\n if (offer.expiry < Math.floor(Date.now() / 1000)) {\n return { message: \"Expiry mismatch\" };\n }\n });\n\n return [expiry];\n}\n\nexport const chains = ({ chains }: { chains: Chain.Chain[] }) =>\n single(\n \"chain_ids\",\n `Validates that offer chain is one of: [${chains.map((c) => c.id).join(\", \")}]`,\n (offer: Offer.Offer) => {\n const allowedChainIds = chains.map((c) => c.id);\n if (!allowedChainIds.some((id) => id === offer.chainId)) {\n return {\n message: `Chain ID ${offer.chainId} is not in the allowed chains (${allowedChainIds.join(\", \")})`,\n };\n }\n },\n );\n\nexport const maturity = ({ maturities }: { maturities: Maturity.MaturityType[] }) =>\n single(\n \"maturity\",\n `Validates that offer maturity is one of: [${maturities!.join(\", \")}]`,\n (offer: Offer.Offer) => {\n const allowedMaturities = maturities!.map((m) => Maturity.from(m));\n if (!allowedMaturities.includes(offer.maturity)) {\n return {\n message: `Maturity must be one of (${allowedMaturities.join(\", \")}). Got: ${offer.maturity}`,\n };\n }\n },\n );\n\nexport const callback = ({\n callbacks,\n}: {\n callbacks: Callback.Type[];\n allowedAddresses: Address[];\n}) =>\n single(\n \"callback\",\n `Validates callbacks: buy empty callback is ${callbacks.includes(Callback.Type.BuyWithEmptyCallback) ? \"allowed\" : \"not allowed\"}; sell empty callback is ${callbacks.includes(Callback.Type.SellWithEmptyCallback) ? \"allowed\" : \"not allowed\"}; non-empty callbacks are rejected`,\n (offer: Offer.Offer) => {\n if (!Callback.isEmptyCallback(offer)) {\n return {\n message: \"Non-empty callbacks are not supported.\",\n };\n }\n if (\n Callback.isEmptyCallback(offer) &&\n offer.buy &&\n !callbacks.includes(Callback.Type.BuyWithEmptyCallback)\n ) {\n return {\n message: \"Buy offers with empty callback not allowed.\",\n };\n }\n if (\n Callback.isEmptyCallback(offer) &&\n !offer.buy &&\n !callbacks.includes(Callback.Type.SellWithEmptyCallback)\n ) {\n return {\n message: \"Sell offers with empty callback not allowed.\",\n };\n }\n },\n );\n\n/**\n * A validation rule that checks if the offer's loan token is allowed for its chain.\n * @param assetsByChainId - Allowed loan tokens indexed by chain id.\n * @returns The issue that was found. If the offer is valid, this will be undefined.\n */\nexport const loanToken = ({\n assetsByChainId,\n}: {\n assetsByChainId: Partial<Record<Chain.Id, Address[]>>;\n}) =>\n single(\n \"loan_token\",\n \"Validates that offer loan token is in the allowed token list for the offer chain\",\n (offer: Offer.Offer) => {\n const allowedLoanTokens = assetsByChainId[offer.chainId]?.map((asset) => asset.toLowerCase());\n if (!allowedLoanTokens || allowedLoanTokens.length === 0) {\n return { message: `No allowed loan tokens for chain ${offer.chainId}` };\n }\n if (!allowedLoanTokens.includes(offer.loanToken.toLowerCase())) {\n return { message: \"Loan token is not allowed\" };\n }\n return undefined;\n },\n );\n\n/**\n * A validation rule that checks if the offer's collateral tokens are allowed for its chain.\n * @param collateralAssetsByChainId - Allowed collateral tokens indexed by chain id.\n * @returns The issue that was found. If the offer is valid, this will be undefined.\n */\nexport const collateralToken = ({\n collateralAssetsByChainId,\n}: {\n collateralAssetsByChainId: Partial<Record<Chain.Id, Address[]>>;\n}) =>\n single(\n \"collateral_token\",\n \"Validates that offer collateral tokens are in the allowed token list for the offer chain\",\n (offer: Offer.Offer) => {\n const allowedCollateralTokens =\n collateralAssetsByChainId[offer.chainId]?.map((asset) => asset.toLowerCase()) ?? [];\n if (allowedCollateralTokens.length === 0) {\n return { message: `No allowed collateral tokens for chain ${offer.chainId}` };\n }\n if (offer.collaterals.length === 0) {\n return { message: \"At least one collateral token is required\" };\n }\n if (\n offer.collaterals.some(\n (collateral) => !allowedCollateralTokens.includes(collateral.asset.toLowerCase()),\n )\n ) {\n return { message: \"Collateral token is not allowed\" };\n }\n return undefined;\n },\n );\n\n/**\n * A validation rule that checks if the offer's oracle addresses are allowed for its chain.\n * @param oraclesByChainId - Allowed oracles indexed by chain id.\n * @returns The issue that was found. If the offer is valid, this will be undefined.\n */\nexport const oracle = ({\n oraclesByChainId,\n}: {\n oraclesByChainId: Partial<Record<Chain.Id, Address[]>>;\n}) =>\n single(\n \"oracle\",\n \"Validates that offer collateral oracles are in the allowed oracle list for the offer chain\",\n (offer: Offer.Offer) => {\n const allowedOracles = oraclesByChainId[offer.chainId]?.map((oracle) => oracle.toLowerCase());\n if (!allowedOracles || allowedOracles.length === 0) {\n return { message: `No allowed oracles for chain ${offer.chainId}` };\n }\n if (\n offer.collaterals.some(\n (collateral) => !allowedOracles.includes(collateral.oracle.toLowerCase()),\n )\n ) {\n return { message: \"Oracle is not allowed\" };\n }\n return undefined;\n },\n );\n\n/**\n * A batch validation rule that ensures all offers in a tree have the same maker address.\n * Returns an issue only for the first non-conforming offer.\n * This rule is signing-agnostic; signer verification is handled at the collector level.\n */\nexport const sameMaker = () =>\n batch(\n \"mixed_maker\",\n \"Validates that all offers in a batch have the same maker address\",\n (offers: Offer.Offer[]) => {\n const issues = new Map<\n number,\n Omit<Validation.Issue<Offer.Offer, \"mixed_maker\">, \"ruleName\" | \"item\"> | undefined\n >();\n\n if (offers.length === 0) return issues;\n\n const firstMaker = offers[0]!.maker.toLowerCase();\n\n for (let i = 1; i < offers.length; i++) {\n const offer = offers[i]!;\n if (offer.maker.toLowerCase() !== firstMaker) {\n issues.set(i, {\n message: `Offer has different maker ${offer.maker} than first offer ${offers[0]!.maker}`,\n });\n // Return only the first non-conforming offer\n // tree should be dropped entirely when only one offer is invalid\n return issues;\n }\n }\n\n return issues;\n },\n );\n\n/**\n * A validation rule that ensures mutual exclusivity of offer amount fields.\n * At most one of (assets, obligationUnits, obligationShares) can be non-zero.\n * Matches contract requirement: `atMostOneNonZero(offer.assets, offer.obligationUnits, offer.obligationShares)`.\n */\nexport const amountMutualExclusivity = () =>\n single(\n \"amount_mutual_exclusivity\",\n \"Validates that at most one of (assets, obligationUnits, obligationShares) is non-zero\",\n (offer: Offer.Offer) => {\n if (!BigMath.atMostOneNonZero(offer.assets, offer.obligationUnits, offer.obligationShares)) {\n return {\n message:\n \"Inconsistent offer input: at most one of (assets, obligationUnits, obligationShares) must be non-zero\",\n };\n }\n },\n );\n","import type { Address } from \"viem\";\nimport * as Callback from \"../core/Callback.ts\";\nimport type * as Chain from \"../core/Chain.ts\";\nimport * as Maturity from \"../core/Maturity.ts\";\nimport * as GateConfig from \"./GateConfig.ts\";\nimport * as Rules from \"./Rules.ts\";\n\nexport const morphoRules = (chains: Chain.Chain[]) => {\n const assetsByChainId: Partial<Record<Chain.Id, Address[]>> = {};\n const collateralAssetsByChainId: Partial<Record<Chain.Id, Address[]>> = {};\n const oraclesByChainId: Partial<Record<Chain.Id, Address[]>> = {};\n for (const chain of chains) {\n assetsByChainId[chain.id] = GateConfig.assets[chain.id.toString()] ?? [];\n collateralAssetsByChainId[chain.id] = GateConfig.collateralAssets[chain.id.toString()] ?? [];\n oraclesByChainId[chain.id] = GateConfig.oracles[chain.id.toString()] ?? [];\n }\n\n return [\n Rules.sameMaker(),\n Rules.amountMutualExclusivity(),\n Rules.chains({ chains }),\n Rules.maturity({\n maturities: [Maturity.MaturityType.EndOfWeek, Maturity.MaturityType.EndOfNextWeek],\n }),\n Rules.callback({\n callbacks: [Callback.Type.BuyWithEmptyCallback, Callback.Type.SellWithEmptyCallback],\n allowedAddresses: [],\n }),\n Rules.loanToken({ assetsByChainId }),\n Rules.collateralToken({ collateralAssetsByChainId }),\n Rules.oracle({ oraclesByChainId }),\n ];\n};\n","import {\n type Address,\n decodeAbiParameters,\n type Hex,\n type PublicClient,\n publicActions,\n type WalletClient as ViemClient,\n zeroAddress,\n} from \"viem\";\nimport type { Compute } from \"#core\";\nimport { Chain, Offer, Tree } from \"#core\";\nimport * as Errors from \"#utils/Errors.ts\";\nimport type * as Client from \"./MempoolClient.ts\";\n\nconst DEFAULT_BATCH_SIZE = 100;\n\ntype MempoolEVMClientConfig = {\n readonly client: ViemClient;\n readonly mempoolAddress: Address;\n readonly morphoAddress?: Address;\n readonly blockWindow?: number;\n};\n\nexport function from(parameters: from.Parameters): from.ReturnType {\n const config: MempoolEVMClientConfig = {\n client: parameters.client,\n mempoolAddress: parameters.mempoolAddress,\n morphoAddress: parameters.morphoAddress,\n blockWindow: parameters.blockWindow,\n };\n\n return {\n add: (parameters) => add(config, parameters),\n get: (parameters) => get(config, parameters),\n stream: (parameters) => streamOffers(config, parameters),\n };\n}\n\nexport declare namespace from {\n type Parameters = {\n /** The viem client to use. */\n client: ViemClient;\n /** The mempool address. */\n mempoolAddress: Address;\n /** The MorphoV2 contract address used for signature verification. */\n morphoAddress?: Address;\n /** The block window to use for the mempool. Defaults to 100. */\n blockWindow?: number;\n };\n\n type ReturnType = Client.Client;\n\n type ErrorType = null;\n}\n\n/**\n * Add an offer to the mempool.\n * @returns The created offer with its hash.\n * @throws WalletAccountNotSetError if the wallet account is not set.\n * @throws ViemClientError if the viem client throws an error.\n * @throws Offer.InvalidOfferError if the offer is invalid.\n */\nexport async function add(\n config: MempoolEVMClientConfig,\n offers: Client.AddParameters,\n): Promise<Hex> {\n if (!config.client.account) throw new WalletAccountNotSetError();\n\n const tree = Tree.from(offers.map((o) => Offer.from(o)));\n const chainId = await getChainId(config.client);\n for (const offer of tree.offers) {\n if (chainId !== offer.chainId) throw new ChainIdMismatchError(offer.chainId, chainId);\n }\n\n const signatureDomain = resolveSignatureDomain(config, chainId);\n const signature = await config.client.signTypedData({\n account: config.client.account,\n domain: Tree.signatureDomain(signatureDomain),\n types: Tree.signatureTypes,\n primaryType: \"Root\",\n message: { root: tree.root },\n });\n const encoded = await Tree.encode(tree, signature, signatureDomain);\n try {\n return await config.client.sendTransaction({\n chain: config.client.chain,\n account: config.client.account!,\n to: config.mempoolAddress,\n data: encoded,\n });\n } catch (error) {\n throw new ViemClientError(error instanceof Error ? error.message : \"Unknown error\");\n }\n}\n\nexport declare namespace add {\n export type ErrorType =\n | WalletAccountNotSetError\n | ViemClientError\n | Offer.InvalidOfferError\n | ChainIdMismatchError\n | MissingMorphoAddressError;\n}\n\nexport async function* get(\n config: MempoolEVMClientConfig,\n parameters?: Client.GetParameters,\n): AsyncGenerator<{ offers: Offer.Offer[]; blockNumber: number }, void, void> {\n const {\n loanToken,\n blockNumberGte,\n blockNumberLte,\n order = \"desc\",\n options: { maxBatchSize = DEFAULT_BATCH_SIZE } = {},\n } = parameters || {};\n\n yield* streamOffers(config, {\n loanToken,\n order,\n blockNumberGte,\n blockNumberLte,\n options: { maxBatchSize, blockWindow: config.blockWindow },\n });\n}\n\nexport declare namespace get {\n export type ErrorType = streamOffersReturnType;\n}\n\nconst chainIdCache = new Map<string, Chain.Id>();\n/**\n * Caches the chain id of a viem client.\n * @param client - The viem client.\n * @returns The chain id.\n */\nconst getChainId = async (client: ViemClient): Promise<Chain.Id> => {\n if (chainIdCache.has(client.uid)) return chainIdCache.get(client.uid)!;\n const chainId = await client.getChainId();\n chainIdCache.set(client.uid, chainId as Chain.Id);\n return chainId as Chain.Id;\n};\n\ntype streamOffersReturnType =\n | WalletAccountNotSetError\n | ChainIdMismatchError\n | MissingMorphoAddressError;\n\nasync function* streamOffers(\n config: MempoolEVMClientConfig,\n parameters: Compute<\n Omit<Client.GetParameters, \"options\"> & {\n options: Client.GetParameters[\"options\"] & { blockWindow?: number };\n }\n >,\n): AsyncGenerator<{ offers: Offer.Offer[]; blockNumber: number }, void, void> {\n const {\n loanToken,\n blockNumberGte,\n blockNumberLte,\n order = \"desc\",\n options: { maxBatchSize = DEFAULT_BATCH_SIZE, blockWindow = config.blockWindow } = {},\n } = parameters;\n\n const signatureDomain = resolveSignatureDomain(config, await getChainId(config.client));\n\n const stream = Chain.streamLogs({\n client: config.client.extend(publicActions) as PublicClient,\n contractAddress: config.mempoolAddress,\n event: {\n type: \"event\",\n name: \"Event\",\n inputs: [{ name: \"data\", type: \"bytes\", indexed: false, internalType: \"bytes\" }],\n anonymous: false,\n } as const,\n blockNumberGte,\n blockNumberLte,\n order,\n options: { maxBatchSize, blockWindow },\n });\n\n let blockNumber = order === \"asc\" ? blockNumberGte : blockNumberLte;\n for await (const { logs, blockNumber: newBlockNumber } of stream) {\n blockNumber = newBlockNumber;\n if (logs.length === 0) continue;\n\n const offers: Offer.Offer[] = [];\n for (const log of logs) {\n if (!log) continue;\n const [payload] = decodeAbiParameters([{ type: \"bytes\" }], log.data);\n try {\n const { tree } = await Tree.decode(payload, signatureDomain);\n for (const offer of tree.offers) {\n if (loanToken && offer.loanToken.toLowerCase() !== loanToken.toLowerCase()) continue;\n offers.push(offer);\n }\n } catch (_) {}\n }\n\n yield {\n offers,\n blockNumber,\n };\n }\n\n yield { offers: [], blockNumber: blockNumber! };\n return;\n}\n\nexport class WalletAccountNotSetError extends Errors.BaseError {\n override name = \"Mempool.WalletAccountNotSetError\";\n constructor() {\n super(\"Wallet account is not set.\");\n }\n}\n\nexport class ViemClientError extends Errors.BaseError {\n override name = \"Mempool.ViemClientError\";\n}\n\nexport class ChainIdMismatchError extends Errors.BaseError {\n override name = \"Mempool.ChainIdMismatchError\";\n constructor(expected: Chain.Id, actual: Chain.Id) {\n super(`Chain ID mismatch. Offer chain ID is ${expected}, network chain ID is ${actual}.`);\n }\n}\n\nconst resolveSignatureDomain = (\n config: MempoolEVMClientConfig,\n chainId: Chain.Id,\n): Tree.SignatureDomain => {\n const chain = config.client.chain as Chain.Chain | undefined;\n const verifyingContract =\n config.morphoAddress ??\n chain?.custom?.morpho?.address ??\n Chain.getChain(chainId)?.custom.morpho.address;\n if (!verifyingContract || verifyingContract.toLowerCase() === zeroAddress) {\n throw new MissingMorphoAddressError();\n }\n return { chainId, verifyingContract };\n};\n\nexport class MissingMorphoAddressError extends Errors.BaseError {\n override name = \"Mempool.MissingMorphoAddressError\";\n constructor() {\n super(\"Morpho address is required to verify root signatures (zero address is invalid).\");\n }\n}\n","import type { Hex } from \"viem\";\nimport type { Compute, Offer } from \"#core\";\nimport * as EVMClient from \"./MempoolEVMClient.ts\";\n\nexport type AddParameters = Compute<Omit<Offer.Offer, \"createdAt\">[]>;\n\nexport type GetParameters = {\n /** The block number to get offers from. */\n blockNumberGte?: number;\n /** The block number to get offers to. */\n blockNumberLte?: number;\n /** The loan asset to get offers from. */\n loanToken?: string;\n /** The order to get offers. Defaults to \"desc\". */\n order?: \"asc\" | \"desc\";\n /** The options to get offers from. */\n options?: {\n /** The maximum number of offers to return. Defaults to 100. Maximum is 1000. */\n maxBatchSize?: number;\n };\n};\n\n/**\n * Mempool client interface.\n */\nexport type Client = {\n /**\n * Add an offer to the mempool.\n * @returns The created offer with its hash.\n */\n add: (parameters: AddParameters) => Promise<Hex>;\n /** Get offers from the mempool. */\n get: (parameters?: GetParameters) => AsyncGenerator<{\n offers: Offer.Offer[];\n /** The block number of the last processed offer. Depends on the `order` parameter, block numbers will ascend or descend. */\n blockNumber: number;\n }>;\n\n /**\n * Stream offers from the mempool.\n * @returns A generator of offers alongside the last block number processed.\n */\n stream: (\n parameters: Compute<\n Omit<GetParameters, \"options\"> & {\n options: GetParameters[\"options\"] & { blockWindow?: number };\n }\n >,\n ) => AsyncGenerator<{\n offers: Offer.Offer[];\n blockNumber: number;\n }>;\n};\n\n/**\n * Client to interact with the Mempool contract on a specific chain.\n */\nexport function connect(parameters: EVMClient.from.Parameters): Client {\n return EVMClient.from(parameters);\n}\n\nexport declare namespace connect {\n export type ErrorType = EVMClient.from.ErrorType;\n}\n","export * from \"./MempoolClient.ts\";\nexport * from \"./MempoolEVMClient.ts\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,MAAa,iBAAiB;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAgBD,SAAgB,cAAc,UAAqB,QAA0B;CAC3E,MAAM,YAAsB,YAAa,QAAQ,IAAI,oBAAiC;CACtF,MAAM,gBACJ,OAAO,WAAW,YACd,SACA,OAAO,QAAQ,IAAI,qBAAqB,QAAQ,CAAC,aAAa,KAAK;CAEzE,MAAM,mBAA6C,eAAe,QAC/D,KAAK,KAAK,QAAQ;AACjB,MAAI,OAAO;AACX,SAAO;IAET,EAAE,CACH;CAED,MAAM,aAAa,gBACjB,iBAAiB,gBAAgB,iBAAiB;CAEpD,MAAM,QACJ,eACA,gBAEA,UAAU,YAAY,IACjB,UAAoB;AACnB,MAAI,CAAC,eAAe;AAElB,WAAQ,eAAe,UAAU;IAAE,OAAO;IAAa,GAAG;IAAO,CAAC,CAAC;AACnE;;EAGF,MAAM,EAAE,KAAK,GAAG,SAAS;EACzB,MAAM,QACJ,OAAQ,KAAiC,UAAU,WAC9C,KAAiC,QAClC;AACN,MAAI,MAAO,QAAQ,KAAiC;EACpD,MAAM,6BAAY,IAAI,MAAM,EAAC,aAAa;EAC1C,MAAM,QAAQ,YAAY,aAAa;EAEvC,MAAM,SAAiB,OAAO,QAAQ,KAAK,CACxC,KAAK,CAAC,GAAG,OAAO,GAAG,EAAE,GAAG,YAAY,EAAE,GAAG,CACzC,KAAK,IAAI;EAEZ,MAAM,OACJ,OAAO,SAAS,IACZ,GAAG,UAAU,IAAI,MAAM,IAAI,IAAI,IAAI,WACnC,GAAG,UAAU,IAAI,MAAM,IAAI;AAEjC,UAAQ,eAAe,KAAK;AAC5B,MAAI,MAEF,SAAQ,eAAe,MAAM;WAG3B;AAEZ,QAAO;EACL,OAAO,KAAK,SAAS,QAAQ;EAC7B,OAAO,KAAK,SAAS,QAAQ;EAC7B,MAAM,KAAK,QAAQ,OAAO;EAC1B,MAAM,KAAK,QAAQ,OAAO;EAC1B,OAAO,KAAK,SAAS,QAAQ;EAC7B,OAAO,KAAK,SAAS,QAAQ;EAC9B;;AAGH,SAAgB,eAAuB;CACrC,MAAM,cAAc;AACpB,QAAO;EAAE,OAAO;EAAM,OAAO;EAAM,MAAM;EAAM,MAAM;EAAM,OAAO;EAAM,OAAO;EAAM;;AAGvF,MAAM,gBAAgB,IAAI,mBAA2B;AAErD,SAAgB,cAAiB,QAAgB,IAAkC;AACjF,QAAO,cAAc,IAAI,QAAQ,GAAG;;AAGtC,SAAgB,YAAoB;AAClC,QAAO,cAAc,UAAU,IAAI,eAAe;;AAGpD,SAAS,YAAY,OAAwB;AAC3C,KACE,UAAU,QACV,UAAU,UACV,OAAO,UAAU,YACjB,OAAO,UAAU,YACjB,OAAO,UAAU,UAEjB,QAAO,OAAO,MAAM;AAEtB,KAAI,OAAO,UAAU,UAAU;AAC7B,MAAI,MAAM,SAAS,IAAI,CAAE,QAAO,KAAK,UAAU,MAAM;AACrD,SAAO;;AAET,KAAI;AACF,SAAO,UAAU,MAA4C;SACvD;AACN,MAAI;AACF,UAAO,KAAK,UAAU,MAAM;UACtB;AACN,UAAO,OAAO,MAAM;;;;;;;;;;;;;;;;;;;;;AC/D1B,SAAgB,UAAU,MAAsB;AAC9C,QAAO,MAAM,UAAU,KAAK;;;;;;;;;;;;;;;;;;AAiC9B,SAAgB,gBACd,QACA,MACA,IACY;AACZ,QAAO,OAAO,gBAAgB,MAAM,OAAO,SAAS;AAClD,MAAI;AACF,UAAO,MAAM,GAAG,KAAK;WACd,KAAK;AACZ,QAAK,gBAAgB,IAAa;AAClC,QAAK,UAAU,EAAE,MAAM,eAAe,OAAO,CAAC;AAC9C,SAAM;YACE;AACR,QAAK,KAAK;;GAEZ;;;;;ACnHJ,SAAgBA,MAAI,GAAW,GAAmB;AAChD,QAAO,IAAI,IAAI,IAAI;;AAGrB,SAAgB,IAAI,GAAW,GAAmB;AAChD,QAAO,IAAI,IAAI,IAAI;;;;;;;AAQrB,SAAgB,iBAAiB,GAAG,QAA2B;CAC7D,IAAI,eAAe;AACnB,MAAK,MAAM,SAAS,OAClB,KAAI,UAAU,IAAI;AAChB;AACA,MAAI,eAAe,EAAG,QAAO;;AAGjC,QAAO;;;;;;;;;;;;;;;;;;;;;;ACJT,UAAiBC,QACf,OACA,WAC+B;AAC/B,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,UACrC,OAAM,MAAM,MAAM,GAAG,IAAI,UAAU;;;;;ACtBvC,MAAa,QAAQ,OAAU,IAAsB,WAAW,GAAG,UAAU,OAAmB;CAC9F,IAAI;AACJ,MAAK,IAAI,IAAI,GAAG,IAAI,UAAU,IAC5B,KAAI;AACF,SAAO,MAAM,IAAI;UACV,KAAK;AACZ,YAAU;AACV,MAAI,IAAI,WAAW,EAAG,OAAM,IAAI,SAAS,MAAM,WAAW,GAAG,QAAQ,CAAC;;AAG1E,OAAM;;;;;;;;;;;;ACGR,eAAsB,eAAwB,YAOvB;CACrB,MAAM,EAAE,QAAQ,OAAO,WAAW,eAAe,cAAc,gBAAgB;CAC/E,MAAM,UAAqB,EAAE;AAE7B,MAAK,MAAM,cAAcC,QAAM,OAAO,UAAU,EAAE;EAChD,MAAM,eAAe,MAAM,YAEvB,UAAU,QAAQ;GAChB,cAAc;GACd,WAAW;GACX,GAAI,cAAc,EAAE,aAAa,GAAG,EAAE;GACvC,CAAC,EACJ,eACA,aACD;AACD,UAAQ,KAAK,GAAI,aAA2B;;AAG9C,QAAO;;;;;;;;;;;;;;;;;;ACzBT,IAAa,YAAb,MAAa,kBAA+D,MAAM;CAChF;CACA;CAEA,AAAS;CACT,AAAS,OAAO;CAEhB,YACE,cACA,UAII,EAAE,EACN;EACA,MAAM,iBAAiB;AACrB,OAAI,QAAQ,iBAAiB,WAAW;AACtC,QAAI,QAAQ,MAAM,QAAS,QAAO,QAAQ,MAAM;AAChD,QAAI,QAAQ,MAAM,aAAc,QAAO,QAAQ,MAAM;;AAEvD,OAAI,QAAQ,SAAS,aAAa,QAAQ,SAAS,OAAO,QAAQ,MAAM,YAAY,SAClF,QAAO,QAAQ,MAAM;AACvB,OAAI,QAAQ,OAAO,QAAS,QAAO,QAAQ,MAAM;AACjD,UAAO,QAAQ;MACb;EAEJ,MAAM,UAAU;GACd,gBAAgB;GAChB,GAAI,QAAQ,eAAe,CAAC,IAAI,GAAG,QAAQ,aAAa,GAAG,EAAE;GAC7D,GAAI,UAAU,CAAC,IAAI,UAAU,YAAY,YAAY,OAAU,GAAG,EAAE;GACrE,CACE,QAAQ,MAAM,OAAO,MAAM,SAAS,CACpC,KAAK,KAAK;AAEb,QAAM,SAAS,QAAQ,QAAQ,EAAE,OAAO,QAAQ,OAAO,GAAG,OAAU;AAEpE,OAAK,QAAQ,QAAQ;AACrB,OAAK,UAAU;AACf,OAAK,eAAe;;CAKtB,KAAK,IAAuD;AAC1D,SAAO,KAAK,MAAM,GAAG;;;;AAKzB,SAAS,KAAK,KAAc,IAAuD;AACjF,KAAI,KAAK,IAAI,CAAE,QAAO;AACtB,KAAI,OAAO,OAAO,QAAQ,YAAY,WAAW,OAAO,IAAI,MAAO,QAAO,KAAK,IAAI,OAAO,GAAG;AAC7F,QAAO,KAAK,OAAO;;AAGrB,IAAa,aAAb,cAAgC,UAAU;CACxC,AAAS,OAAO;CAChB,YAAY,aAAqB;AAC/B,QAAM,kCAAkC,cAAc;;;;;;;;;;;;;;;;;ACH1D,SAAgBC,cAAe,KAAkB;AAC/C,QAAO,gBACL,cACE,MACC,MAAc,EAAE,QAAQ,WAAW,MAAM,IAAI,EAAE,aAAa,GAAG,GAC/D,UACC,OAAO,UAAU,YAAY,UAAU,MAAM,aAAa,CAAC,GACvD,WAAW,MAAM,aAAa,CAAC,GAC/B,MACP,CACF;;;;;;;;AASH,SAAgBC,gBAAiB,KAAkB;AACjD,QAAO,cACL,MACC,MACC,UAAU,EAAE,aAAa,CAAC,GAAG,IAAI,EAAE,QAAQ,cAAc,GAAG,MAAM,EAAE,aAAa,CAAC,GACnF,UACC,OAAO,UAAU,YAAY,UAAU,MAAM,aAAa,CAAC,GAAG,MAAM,aAAa,GAAG,MACvF;;AAGH,SAAS,cACP,KACA,OACA,SACS;AACT,KAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM,QAAO;AAEpD,KAAI,MAAM,QAAQ,IAAI,CAAE,QAAO,IAAI,KAAK,SAAS,cAAc,MAAM,OAAO,QAAQ,CAAC;AAErF,QAAO,OAAO,QAAQ,IAA+B,CAAC,QACnD,KAAK,CAAC,KAAK,WAAW;EACrB,MAAM,SAAS,MAAM,IAAI;AACzB,MAAI,UACF,OAAO,UAAU,YAAY,UAAU,OACnC,cAAc,OAAO,OAAO,QAAQ,GACpC,QAAQ,MAAM;AAEpB,SAAO;IAET,EAAE,CACH;;AAGH,SAAgB,gBAAmB,OAAgC;AACjE,KAAI,OAAO,UAAU,SAAU,QAAO,MAAM,UAAU;AACtD,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,MAAM,IAAI,gBAAgB;AAC3D,KAAI,SAAS,OAAO,UAAU,UAAU;EACtC,MAAM,MAA+B,EAAE;AACvC,OAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,MAAM,CACxC,KAAI,KAAK,gBAAgB,EAAE;AAE7B,SAAO;;AAGT,QAAO;;;;;;;;;;;AC5HT,MAAa,cAAc,MAAmB;AAC5C,KAAI,CAAC,OAAO,UAAU,EAAE,CACtB,OAAM,IAAI,MAAM,2CAA2C,IAAI;AAEjE,KAAI,IAAI,EACN,OAAM,IAAI,MAAM,gDAAgD,IAAI;AAEtE,QAAO,IAAI,KAAK,EAAE,SAAS,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC;;;;;;;;;;ACTjD,SAAgB,KACd,QACA;AACA,eACG,mBAAmB;EAClB,IAAI,SAAS;EACb,IAAI,cAAmC;EACvC,MAAM,QAAa,EAAE;EAErB,MAAM,aACJ,IAAI,SAAe,YAAY;AAC7B,iBAAc;IACd;EAEJ,MAAM,QAAQ,SAAY;AACxB,SAAM,KAAK,KAAK;AAChB,kBAAe;AACf,iBAAc;;EAGhB,IAAI,SAAiC;EACrC,MAAM,aAAa;AACjB,YAAS;AAET,aAAU;AACV,kBAAe;AACf,iBAAc;;AAGhB,WAAS,OAAO,MAAM,EAAE,MAAM,CAAC;AAE/B,MAAI;AACF,UAAO,QAAQ;AACb,QAAI,MAAM,WAAW,EAAG,OAAM,MAAM;AACpC,WAAO,MAAM,SAAS,KAAK,OAAQ,OAAM,MAAM,OAAO;;YAEhD;AACR,SAAM;;KAEN;;;;;AC5CR,eAAsB,KAAK,MAAc;AACvC,QAAO,IAAI,SAAS,QAAQ,WAAW,KAAK,KAAK,CAAC;;;;;;;;;ACIpD,SAAgB,KACd,IACA,EAAE,YACF;CACA,IAAI,SAAS;CACb,MAAM,gBAAiB,SAAS;CAEhC,MAAM,QAAQ,YAAY;AACxB,SAAO,QAAQ;GACb,MAAM,QAAQ,MAAM,UAAU;AAC9B,OAAI,CAAC,OAAQ;AACb,SAAM,KAAK,MAAM;AACjB,OAAI,CAAC,OAAQ;AACb,SAAM,GAAG,EAAE,QAAQ,SAAS,CAAC;;;AAIjC,QAAO;AAEP,QAAO;;;;;;;;;;;;;;;ACpBT,IAAI,aAAkB,KAAK;AAE3B,MAAM,mBAAmB;AACzB,MAAM,YAAY;AAElB,MAAM,YAAY,SAAyB;CACzC,IAAI,OAAO;AACX,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG;AACvC,UAAQ,KAAK,WAAW,EAAE;AAC1B,SAAO,KAAK,KAAK,MAAM,UAAU;;AAEnC,QAAO,SAAS;;AAGlB,MAAM,mBAAmB,SAAsB;CAC7C,IAAI,QAAQ,SAAS,KAAK;AAC1B,cAAa;AACX,WAAS;EACT,IAAI,IAAI,KAAK,KAAK,QAAS,UAAU,IAAK,QAAQ,EAAE;AACpD,OAAK,IAAI,KAAK,KAAK,IAAK,MAAM,GAAI,IAAI,GAAG;AACzC,WAAS,IAAK,MAAM,QAAS,KAAK;;;;;;AAOtC,SAAgB,SAAY,MAAc,IAAgB;CACxD,MAAM,WAAW;AACjB,cAAa,gBAAgB,KAAK;AAClC,KAAI;AACF,SAAO,IAAI;WACH;AACR,eAAa;;;;;;AAOjB,SAAgB,KAAK,MAAoB;AACvC,cAAa,gBAAgB,KAAK;;;;;AAMpC,SAAgB,QAAgB;AAC9B,QAAO,YAAY;;;;;AAMrB,SAAgB,IAAI,cAAsB,MAAM,GAAW;AACzD,QAAO,KAAK,MAAM,OAAO,IAAI,eAAe,KAAK,GAAG;;;;;AAMtD,SAAgB,KAAK,cAAc,IAAc;AAC/C,QAAO,OAAO,GAAG;;;;;AAMnB,SAAgB,MAAM,QAA4B;CAChD,MAAM,SAAS,IAAI,WAAW,OAAO;AACrC,MAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK,EAC/B,QAAO,KAAK,IAAI,IAAI;AAEtB,QAAO;;;;;AAMT,SAAgB,IAAI,YAAyB;CAC3C,MAAM,SAAS,MAAM,WAAW;AAEhC,QAAO,KADU,MAAM,KAAK,SAAS,SAAS,KAAK,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAC5D,KAAK,GAAG;;;;;AAM/B,SAAgB,UAAmB;AACjC,QAAO,IAAI,GAAG;;;;;;;;;AC7FhB,SAAgB,MAAc;AAC5B,QAAO,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;;AAGtC,SAAgB,MAAc;AAC5B,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;AEaT,SAAgBC,UAA4D,YAOlE;CACR,MAAM,YAAY;CAClB,MAAM,EAAE,QAAQ,IAAI,SAAS,EAAE,eAAe,IAAI,mBAAmB,EAAE,KAAK;CAE5E,MAAM,mBAAmB,mBAAmB,SAAY,OAAO,eAAe,GAAG;CAEjF,IAAI,iBAAoC;CACxC,IAAI,oBAAkC,EAAE;CACxC,IAAI,cAAc;CAElB,MAAM,SAASC,WAAkB;CACjC,IAAI,0BAA0B;CAC9B,IAAI,OAAO;AACX,QAAO,EACL,WAAW,YAAY;AACrB,MAAI,CAAC,aAAa;AAChB,SAAM,QAAQ,UACI,KAAK,kBACnB,GAAG,OAAO,KAAK;IAAE,SAAS,OAAO,MAAM;IAAI;IAAe,CAAC,CAC5D,CACF;AACD,iBAAc;;AAEhB,MAAI,wBAAyB,QAAO;EAEpC,MAAM,OAAO,MAAM,OAAO,SAAS;GACjC,UAAU;GACV,qBAAqB;GACtB,CAAC;AAEF,QAAM,GAAG,YAAY,OAAO,SAAS;GACnC,MAAM,EAAE,OAAO,aAAa,2BAA2B,MAAM,KAAK,OAAO,SACvE,OAAO,MAAM,GACd;AAED,OAAI,qBAAqB,UAAa,KAAK,UAAW,kBAAkB;AACtE,WAAO,KAAK;KACV,KAAK;KACL;KACA,SAAS,OAAO,MAAM;KACtB,cAAc,KAAK;KACnB,kBAAkB;KACnB,CAAC;AAEF,UAAM,KAAK,OAAO,YAAY;KAC5B,SAAS,OAAO,MAAM;KACtB,aAAa;KACb,OAAO,QAAQ;KAChB,CAAC;AAEF,8BAA0B;AAC1B,WAAO;;AAGT,oBAAiB,MAAM,oBAAoB;IACzC;IACA;IACA;IACA;IACA;IACA,wBAAwB;IACzB,CAAC;AACF;GAEA,IAAI,EACF,OAAO,eACP,kBACA,mBAAmB,yBACjB,MAAM,UAAU;IAClB;IACA,OAAO;IACP;IACA;IACA;IACA;IACA;IACD,CAAC;AAEF,uBAAoB;GACpB,MAAM,cAAc,OAAO,cAAc,OAAO;AAEhD,sBAAmB,oBAAoB,cAAc;AAErD,OAAI,iBACF,OAAM,KAAK,OAAO,YAAY;IAC5B,SAAS,OAAO,MAAM;IACtB;IACA,OAAO,QAAQ;IAChB,CAAC;OAEF,OAAM,KAAK,OAAO,aAAa;IAC7B,SAAS,OAAO,MAAM;IACtB;IACA;IACD,CAAC;IAEJ;AAEF,SAAO;IAEV;;AAGH,MAAM,kBAAkB,OAAc,sBAAuD;CAC3F,MAAM,SAAS,kBAAkB,MAAM,MAAM,EAAE,SAAS,MAAM,WAAW;AACzE,KAAI,OAAQ,QAAO;AACnB,QAAO;;AAGT,MAAM,sBAAsB,OAAO,eAOR;CACzB,IAAI,EAAE,MAAM,QAAQ,QAAQ,WAAW,mBAAmB,2BAA2B;CACrF,IAAI,iBAAoC;AACxC,KAAI,OAAO,OAAO,KAAK,2BAA2B,MAAM;AACtD,mBAAiB,MAAM,OAAO,SAAS;GACrC,UAAU;GACV,qBAAqB;GACtB,CAAC;AAEF,MAAI,mBAAmB,QAAQ,eAAe,WAAW,MAAM;GAC7D,MAAM,MAAM;AACZ,UAAO,MAAM;IAAE;IAAW,SAAS,OAAO,MAAM;IAAI;IAAK,CAAC;AAC1D,SAAM,IAAI,MAAM,IAAI;;AAGtB,sBAAoB,kBAAkB,QAAQ,MAAM,EAAE,UAAU,eAAgB,OAAQ;;AAG1F,KACE,eAAgB,WAAW,QAC3B,eAAgB,SAAS,QACzB,eAAgB,eAAe,MAC/B;EACA,MAAM,MAAM;AACZ,SAAO,MAAM;GAAE;GAAW,SAAS,OAAO,MAAM;GAAI;GAAK,CAAC;AAC1D,QAAM,IAAI,MAAM,IAAI;;AAGtB,QAAO;EACL,MAAM,eAAgB;EACtB,QAAQ,eAAgB;EACxB,YAAY,eAAgB;EAC7B;;AAKH,MAAM,YAAY,OAAO,eAQyE;CAChG,IAAI,EAAE,QAAQ,OAAO,mBAAmB,gBAAgB,QAAQ,WAAW,iBACzE;CAEF,MAAM,QAAQ,OAAO;AAErB,KAAI,MAAM,SAAS,QAAQ,MAAM,WAAW,QAAQ,MAAM,eAAe,KACvE,OAAM,IAAI,MAAM,sBAAsB;CAExC,MAAM,cAAc,kBAAkB,kBAAkB,SAAS;AAEjE,KAAI,gBAAgB,QAAW;EAC7B,MAAM,WAAW;GACf,MAAM,MAAM;GACZ,QAAQ,MAAM;GACd,YAAY,MAAM;GACnB;AACD,oBAAkB,KAAK,SAAS;AAChC,SAAO;GAAE,OAAO;GAAU,kBAAkB;GAAO;GAAmB;;AAGxE,KAAI,YAAY,SAAS,MAAM,KAC7B,QAAO;EAAE,OAAO;EAAa,kBAAkB;EAAO;EAAmB;AAE3E,KAAI,YAAY,UAAU,MAAM,QAAQ;EACtC,MAAM,WAAW,eAAe,OAAO,kBAAkB,IAAI;AAC7D,SAAO,KAAK;GACV,KAAK;GACL;GACA,UAAU,MAAM;GAChB,UAAU,SAAS;GACnB,qBAAqB,YAAY;GACjC,cAAc,MAAM;GACrB,CAAC;AACF,sBAAoB,kBAAkB,QAAQ,MAAM,EAAE,UAAU,SAAS,OAAO;AAChF,SAAO;GAAE,OAAO;GAAU,kBAAkB;GAAM;GAAmB;;AAGvE,KAAI,YAAY,SAAS,KAAK,MAAM,QAAQ;AAC1C,SAAO,MAAM;GACX;GACA,UAAU,MAAM;GAChB,aAAa,CAAC,YAAY,QAAQ,MAAM,OAAO;GAC/C,KAAK;GACN,CAAC;EAEF,MAAM,6BAA6B;GACjC,MAAM,sBAAsB,EAAE;GAC9B,IAAI,QAAQ,YAAY,SAAS;GACjC,MAAM,YACJ,YAAY,SAAS,OAAO,aAAa,GAAG,MAAM,SAC9C,MAAM,SACN,YAAY,SAAS,OAAO,aAAa;AAC/C,UAAO,QAAQ,WAAW;AACxB,wBAAoB,KAAK,MAAM;AAC/B,YAAQ,QAAQ;;AAElB,UAAO;MACL;EAEJ,MAAM,gBAAgB,MAAM,QAAQ,IAClC,oBAAoB,KAAK,gBACvBC,MAAY,YAAY,MAAM,OAAO,SAAS;GAAE;GAAa,qBAAqB;GAAO,CAAC,CAAC,CAC5F,CACF;AAED,OAAK,MAAM,gBAAgB,eAAe;GACxC,MAAM,EACJ,OAAO,eACP,kBACA,mBAAmB,yBACjB,MAAM,UAAU;IAClB;IACA,OAAO;IACP;IACA;IACA;IACA;IACA;IACD,CAAC;AAGF,OAAI,cAAc,WAAW,aAAa,OACxC,QAAO;IAAE,OAAO;IAAe;IAAkB,mBAAmB;IAAsB;;AAE9F,SAAO,UAAU;GACf;GACA;GACA;GACA;GACA;GACA;GACA;GACD,CAAC;;AAGJ,KAAI,MAAM,eAAe,YAAY,MAAM;EACzC,MAAM,WAAW,eAAe,OAAO,kBAAkB,IAAI;AAC7D,SAAO,KAAK;GACV,KAAK;GACL;GACA,UAAU,MAAM;GAChB,UAAU,SAAS;GACnB,qBAAqB,YAAY;GACjC,cAAc,MAAM;GACrB,CAAC;AACF,sBAAoB,kBAAkB,QAAQ,MAAM,EAAE,UAAU,SAAS,OAAO;AAChF,SAAO;GAAE,OAAO;GAAU,kBAAkB;GAAM;GAAmB;;CAGvE,MAAM,WAAW;EACf,MAAM,MAAM;EACZ,QAAQ,MAAM;EACd,YAAY,MAAM;EACnB;AAED,mBAAkB,KAAK,SAAS;AAChC,QAAO;EAAE,OAAO;EAAU,kBAAkB;EAAO;EAAmB;;;;;ACvSxE,MAAa,QAAQ;CAAC;CAAU;CAAmB;CAAa;CAAS;AAqDzE,SAAgBC,UAGd,EACA,MACA,SACA,QACA,IACA,WAO0B;CAC1B,MAAM,QAAQC,UAAa;EACzB;EACA;EACA;EACD,CAAC;AAKF,QAAO;EACL;EACA,OALY,OAAO;EAMnB;EACA;EACA,UAPe,QAAQ,YAAY;EAQnC,SAAS,mBAAmB;GAC1B,MAAM,YAAY;GAClB,MAAM,QAAQ,OAAO;GACrB,MAAM,SAASC,WAAkB;GACjC,MAAM,cAAc,GAAG,OAAO,MAAM,GAAG,UAAU,CAAC,aAAa;GAC/D,MAAM,SAASC,UAAiB,UAAU,cAAc;AAExD,UAAO,KAAK;IACV,KAAK;IACL;IACA,UAAU,MAAM;IACjB,CAAC;GAEF,IAAI,WAAsD;GAC1D,IAAI;AACJ,UAAO,KACL,KAAI;AACF,QAAI,aAAa,KACf,YAAW,MAAMC,gBAAuB,QAAQ,GAAG,YAAY,QAAQ,YAAY;KACjF,MAAM,EAAE,WAAW,mBAAmB,MAAM,GAAG,OAAO,KAAK;MACzD,eAAe;MACf,SAAS,MAAM;MAChB,CAAC;AAEF,uBAAkB,eAAe;AAEjC,YAAO,QAAQ;MACb;MACA,WAAW;MACX,OAAO,eAAe;MACtB;MACA;MACD,CAAC;MACF;AAeJ,QAVgC,MAAMA,gBACpC,QACA,GAAG,YAAY,aACf,OAAO,SAAS;KACd,MAAM,0BAA0B,MAAM,MAAM,WAAW;AACvD,UAAK,aAAa,kCAAkC,wBAAwB;AAC5E,YAAO;MAEV,IAIC,QAAQ,mBAAmB,UAC3B,oBAAoB,UACpB,QAAQ,mBAAmB,gBAE3B;IAEF,MAAM,EAAE,aAAa,SAAS,MAAMA,gBAClC,QACA,GAAG,YAAY,QACf,YAAY;AACV,SAAI,aAAa,KAAM,OAAM,IAAI,MAAM,8BAA8B;KACrE,MAAM,EAAE,OAAO,aAAa,SAAS,MAAM,SAAS,MAAM;AAC1D,YAAO;MAAE;MAAa;MAAM;MAE/B;AAED,QAAI,KACF,YAAW;SACN;AACL,uBAAkB;AAClB,WAAM;;YAED,KAAK;IACZ,MAAM,UAAU,eAAe;AAC/B,WAAO,MAAM;KACX,KAAK;KACL;KACA,UAAU,MAAM;KAChB,OAAO,UAAU,IAAI,UAAU,OAAO,IAAI;KAC1C,OAAO,UAAU,IAAI,QAAQ;KAC9B,CAAC;;;EAIT;;;;;;AAOH,SAAgB,MAAM,WAAkC;CACtD,IAAI,UAAU;CACd,MAAM,KAAK,UAAU,SAAS;CAC9B,MAAM,SAASF,WAAkB;CACjC,MAAM,cAAc,GAAG,UAAU,MAAM,GAAG,UAAU,CAAC,aAAa,UAAU;CAC5E,MAAM,SAASC,UAAiB,UAAU,cAAc;CACxD,MAAM,SAAS,UAAU,GAAG;CAC5B,IAAI,cAAc;AAElB,EAAC,YAAY;AACX,SAAO,CAAC,QACN,KAAI;AACF,SAAMC,gBAAuB,QAAQ,GAAG,YAAY,QAAQ,YAAY;AACtE,QAAI,CAAC,aAAa;AAChB,WAAM,OAAO,KAAK;MAChB,SAAS,UAAU,MAAM;MACzB,eAAe,UAAU;MAC1B,CAAC;AACF,mBAAc;;IAEhB,MAAM,CAAC,OAAO,EAAE,aAAa,0BAA0B,MAAM,QAAQ,IAAI,CACvE,UAAU,OAAO,SAAS;KACxB,UAAU;KACV,qBAAqB;KACtB,CAAC,EACF,OAAO,aAAa;KAClB,eAAe,UAAU;KACzB,SAAS,UAAU,MAAM;KAC1B,CAAC,CACH,CAAC;IAGF,MAAM,QADmB,OAAO,MAAM,OAAO,GACZ,uBAAuB,KAAK,MAAM,UAAU;IAE7E,MAAM,WAAW,OAAO,UAAU,GAAG,YAAY,OAAO;AACxD,QAAI;AACF,WAAMC,KAAW,MAAM;cACf;AACR,cAAS,KAAK;;AAGhB,UAAM,GAAG,MAAM;KACf;WACK,KAAK;GACZ,MAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC;AACjE,UAAO,MAAM;IACX,KAAK;IACL,WAAW,UAAU;IACrB,UAAU,UAAU,MAAM;IAC1B,KAAK;IACN,CAAC;;AAGN,QAAM,GAAG,QAAQ;KACf;AAEJ,cAAa;AACX,YAAU;;;;;;AC9Od,MAAa,aAAa,SAAS;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;;;ACVF,MAAa,oBAAoB,SAAS,CACxC,uLACA,qDACD,CAAC;;;;ACHF,MAAa,WAAW,SAAS;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;;;;;;;;;;;ACjDF,MAAa,SAAS,CACpB;CACE,MAAM;CACN,MAAM;CACN,QAAQ,EAAE;CACV,SAAS,CAAC;EAAE,MAAM;EAAI,MAAM;EAAW,CAAC;CACxC,iBAAiB;CAClB,CACF;AAED,MAAa,UAAU,CACrB;CACE,MAAM;CACN,MAAM;CACN,QAAQ,EAAE;CACV,SAAS,CAAC;EAAE,MAAM;EAAI,MAAM;EAAW,CAAC;CACxC,iBAAiB;CAClB,CACF;AAED,MAAa,SAAS;CACpB;EACE,MAAM;EACN,MAAM;EACN,QAAQ;GACN;IACE,MAAM;IACN,MAAM;IACN,cAAc;IACf;GACD;IACE,MAAM;IACN,MAAM;IACN,cAAc;IACf;GACD;IACE,MAAM;IACN,MAAM;IACN,cAAc;IACf;GACF;EACD,SAAS,CACP;GACE,MAAM;GACN,MAAM;GACN,cAAc;GACf,CACF;EACD,iBAAiB;EAClB;CACD;EACE,MAAM;EACN,MAAM;EACN,QAAQ,CACN;GACE,MAAM;GACN,MAAM;GACN,cAAc;GACf,EACD;GACE,MAAM;GACN,MAAM;GACN,cAAc;GACf,CACF;EACD,SAAS,CACP;GACE,MAAM;GACN,MAAM;GACN,cAAc;GACf,CACF;EACD,iBAAiB;EAClB;CACD;EACE,MAAM;EACN,MAAM;EACN,QAAQ,CACN;GACE,MAAM;GACN,MAAM;GACN,cAAc;GACf,CACF;EACD,SAAS;GACP;IACE,MAAM;IACN,MAAM;IACN,c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"}
|