envio 3.8.0 → 3.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.
Files changed (64) hide show
  1. package/README.md +2 -2
  2. package/index.d.ts +158 -104
  3. package/package.json +6 -6
  4. package/src/AddressRows.res +121 -0
  5. package/src/AddressRows.res.mjs +143 -0
  6. package/src/Batch.res +2 -0
  7. package/src/Batch.res.mjs +2 -1
  8. package/src/ChainState.res +76 -70
  9. package/src/ChainState.res.mjs +76 -65
  10. package/src/ChainState.resi +14 -9
  11. package/src/Config.res +23 -82
  12. package/src/Config.res.mjs +19 -63
  13. package/src/ContractMapping.res +66 -0
  14. package/src/ContractMapping.res.mjs +73 -0
  15. package/src/Core.res +20 -0
  16. package/src/Core.res.mjs +4 -0
  17. package/src/EventConfigBuilder.res +0 -2
  18. package/src/EventConfigBuilder.res.mjs +0 -2
  19. package/src/FetchState.res +59 -67
  20. package/src/FetchState.res.mjs +34 -44
  21. package/src/InMemoryStore.res +17 -30
  22. package/src/InMemoryStore.res.mjs +11 -23
  23. package/src/IndexerState.res +21 -1
  24. package/src/IndexerState.res.mjs +9 -3
  25. package/src/IndexerState.resi +1 -0
  26. package/src/Main.res +25 -15
  27. package/src/Main.res.mjs +19 -14
  28. package/src/MemoryStorage.res +39 -66
  29. package/src/MemoryStorage.res.mjs +28 -65
  30. package/src/Metrics.res +15 -1
  31. package/src/Metrics.res.mjs +5 -1
  32. package/src/Persistence.res +30 -16
  33. package/src/Persistence.res.mjs +8 -5
  34. package/src/PgStorage.res +183 -65
  35. package/src/PgStorage.res.mjs +92 -58
  36. package/src/Rollback.res +14 -10
  37. package/src/Rollback.res.mjs +4 -2
  38. package/src/SimulateItems.res +5 -12
  39. package/src/SimulateItems.res.mjs +6 -10
  40. package/src/TestIndexer.res +93 -111
  41. package/src/TestIndexer.res.mjs +61 -88
  42. package/src/Utils.res +7 -0
  43. package/src/Utils.res.mjs +9 -2
  44. package/src/Writing.res +2 -0
  45. package/src/Writing.res.mjs +2 -1
  46. package/src/bindings/ClickHouse.res +6 -0
  47. package/src/bindings/ClickHouse.res.mjs +4 -0
  48. package/src/bindings/NodeJs.res +9 -0
  49. package/src/bindings/NodeJs.res.mjs +8 -1
  50. package/src/bindings/Postgres.res +9 -0
  51. package/src/bindings/Postgres.res.mjs +3 -0
  52. package/src/db/EntityHistory.res +12 -18
  53. package/src/db/EntityHistory.res.mjs +3 -14
  54. package/src/db/InternalTable.res +171 -65
  55. package/src/db/InternalTable.res.mjs +176 -73
  56. package/src/db/Table.res +24 -0
  57. package/src/db/Table.res.mjs +20 -1
  58. package/src/sources/AddressSet.res +0 -22
  59. package/src/sources/AddressStore.res +48 -88
  60. package/src/sources/AddressStore.res.mjs +11 -22
  61. package/src/sources/SvmHyperSyncClient.res +17 -21
  62. package/src/sources/SvmHyperSyncSource.res +4 -9
  63. package/src/sources/SvmHyperSyncSource.res.mjs +5 -13
  64. package/svm.schema.json +10 -4
package/README.md CHANGED
@@ -69,7 +69,7 @@ A few things already running in production:
69
69
 
70
70
  **Multichain indexing**
71
71
  - Index EVM, SVM, and Fuel blockchains from a single indexer
72
- - 70+ EVM chains with native HyperSync support, plus any EVM chain via RPC
72
+ - 79+ EVM chains with first-class HyperSync support, plus any EVM chain via RPC
73
73
  - Real-time indexing with reorg handling built in
74
74
 
75
75
  **Developer experience**
@@ -129,7 +129,7 @@ HyperSync can also be used directly for custom data pipelines in Python, Rust, N
129
129
 
130
130
  ## Supported networks
131
131
 
132
- HyperIndex supports any EVM-compatible L1, L2, or L3, plus Fuel and Solana (experimental). 70+ chains have native HyperSync support for maximum speed. For any EVM chain not on the HyperSync list, RPC-based indexing works out of the box.
132
+ HyperIndex supports any EVM-compatible L1, L2, or L3, plus Fuel and Solana (beta). 79+ chains have first-class HyperSync support for maximum speed. For any EVM chain not on the HyperSync list, RPC-based indexing works out of the box. Solana indexing runs on HyperSync for Solana, with instruction-level handlers and IDL-aware decoding.
133
133
 
134
134
  [Full network list →](https://docs.envio.dev/docs/HyperIndex/supported-networks)
135
135
 
package/index.d.ts CHANGED
@@ -1169,37 +1169,34 @@ export type SvmLogKind =
1169
1169
  | "data"
1170
1170
  | (string & {});
1171
1171
 
1172
- export type SvmLog = {
1172
+ export type SvmAllLogFields = {
1173
1173
  readonly kind: SvmLogKind;
1174
1174
  readonly message: string;
1175
1175
  };
1176
1176
 
1177
- export type SvmAccountActivity = {
1177
+ export type SvmAllAccountLamportsFields = {
1178
+ readonly pre: bigint;
1179
+ readonly post: bigint;
1180
+ };
1181
+
1182
+ export type SvmAllAccountTokenActivityFields = {
1183
+ readonly mint: string;
1184
+ readonly owner: string;
1185
+ readonly decimals: number;
1186
+ readonly preAmount: bigint | undefined;
1187
+ readonly postAmount: bigint | undefined;
1188
+ };
1189
+
1190
+ export type SvmAllAccountActivityFields = {
1178
1191
  readonly address: string;
1179
1192
  readonly transactionAccountIndex: number;
1180
1193
  readonly isSigner: boolean;
1181
1194
  readonly isWritable: boolean;
1182
- readonly lamports: { readonly pre: bigint; readonly post: bigint } | undefined;
1183
- readonly token: {
1184
- readonly mint: string;
1185
- readonly owner: string;
1186
- readonly decimals: number;
1187
- readonly preAmount: bigint | undefined;
1188
- readonly postAmount: bigint | undefined;
1189
- } | undefined;
1195
+ readonly lamports: SvmAllAccountLamportsFields | undefined;
1196
+ readonly token: SvmAllAccountTokenActivityFields | undefined;
1190
1197
  };
1191
1198
 
1192
- export type SvmInstructionAccount<
1193
- Activity = SvmAccountActivity,
1194
- Name extends string = string,
1195
- > = {
1196
- readonly address: string;
1197
- readonly accountName: Name;
1198
- readonly instructionAccountIndex: number;
1199
- readonly activity: Activity | undefined;
1200
- };
1201
-
1202
- export type SvmBlock = {
1199
+ export type SvmAllBlockFields = {
1203
1200
  readonly slot: number;
1204
1201
  readonly time: number;
1205
1202
  readonly hash: string;
@@ -1208,10 +1205,10 @@ export type SvmBlock = {
1208
1205
  readonly parentHash: string;
1209
1206
  };
1210
1207
 
1211
- /** All SVM parent-transaction fields when selected. Handler
1212
- * `fields.transaction` narrows this; `accountActivities` is implied by
1208
+ /** All SVM parent-transaction fields. Handler `fields.transaction` narrows
1209
+ * this via {@link SvmTransaction}; `accountActivities` is implied by
1213
1210
  * `fields.accountActivity`. */
1214
- export type SvmTransaction = {
1211
+ export type SvmAllTransactionFields = {
1215
1212
  readonly transactionIndex: number;
1216
1213
  readonly signature: string;
1217
1214
  readonly feePayer: string;
@@ -1250,10 +1247,8 @@ export type SvmAccountActivityFieldName =
1250
1247
  | "transactionAccountIndex"
1251
1248
  | "isSigner"
1252
1249
  | "isWritable"
1253
- | "lamports"
1254
1250
  | "lamports.pre"
1255
1251
  | "lamports.post"
1256
- | "token"
1257
1252
  | "token.mint"
1258
1253
  | "token.owner"
1259
1254
  | "token.decimals"
@@ -1276,6 +1271,19 @@ export type SvmFieldsSelection = {
1276
1271
  readonly log?: readonly SvmLogFieldName[];
1277
1272
  };
1278
1273
 
1274
+ /** A {@link SvmFieldsSelection} with every field selected.
1275
+ *
1276
+ * Type-level only — its knobs are field-name arrays rather than literals, so it
1277
+ * describes a payload (`SvmInstruction<SvmAllFieldsSelection>`) but can't be
1278
+ * passed as a registration's `fields` value. */
1279
+ export type SvmAllFieldsSelection = {
1280
+ readonly instruction: readonly SvmInstructionFieldName[];
1281
+ readonly transaction: readonly SvmTransactionFieldName[];
1282
+ readonly accountActivity: readonly SvmAccountActivityFieldName[];
1283
+ readonly block: readonly SvmBlockFieldName[];
1284
+ readonly log: readonly SvmLogFieldName[];
1285
+ };
1286
+
1279
1287
  type SvmListedArray<Fields, Knob extends keyof SvmFieldsSelection> = Fields[Knob &
1280
1288
  keyof Fields];
1281
1289
  type SvmListedFields<Fields, Knob extends keyof SvmFieldsSelection> = NonNullable<
@@ -1302,15 +1310,7 @@ type SvmActivityHas<Fields, Name extends string> = [SvmActivityListed<Fields>] e
1302
1310
  ? false
1303
1311
  : Name extends SvmActivityListed<Fields>
1304
1312
  ? true
1305
- : Name extends `lamports.${string}`
1306
- ? "lamports" extends SvmActivityListed<Fields>
1307
- ? true
1308
- : false
1309
- : Name extends `token.${string}`
1310
- ? "token" extends SvmActivityListed<Fields>
1311
- ? true
1312
- : false
1313
- : false;
1313
+ : false;
1314
1314
 
1315
1315
  type SvmActivityField<Fields, Name extends string, T> = SvmActivityHas<
1316
1316
  Fields,
@@ -1319,38 +1319,37 @@ type SvmActivityField<Fields, Name extends string, T> = SvmActivityHas<
1319
1319
  ? T
1320
1320
  : FieldNotSelected<`Field '${Name}' is not selected for this handler. Add it to fields.accountActivity in the registration options.`>;
1321
1321
 
1322
- type SvmSelectedLamports<Fields> =
1323
- SvmActivityHas<Fields, "lamports.pre"> extends true
1324
- ? SvmActivityHas<Fields, "lamports.post"> extends true
1325
- ? { readonly pre: bigint; readonly post: bigint } | undefined
1326
- : { readonly pre: bigint } | undefined
1327
- : SvmActivityHas<Fields, "lamports.post"> extends true
1328
- ? { readonly post: bigint } | undefined
1329
- : FieldNotSelected<`Field 'lamports' is not selected for this handler. Add it to fields.accountActivity in the registration options.`>;
1330
-
1331
- export type SvmAccountTokenActivity = {
1332
- readonly mint: string;
1333
- readonly owner: string;
1334
- readonly decimals: number;
1335
- readonly preAmount: bigint | undefined;
1336
- readonly postAmount: bigint | undefined;
1337
- };
1322
+ /** The pre/post lamport balances of a {@link SvmAccountActivity}, narrowed to
1323
+ * the registration's fields selection. */
1324
+ export type SvmAccountLamports<Fields extends SvmFieldsSelection> = [
1325
+ SvmActivityListed<Fields> & `lamports.${string}`,
1326
+ ] extends [never]
1327
+ ? FieldNotSelected<`Field 'lamports' is not selected for this handler. Add it to fields.accountActivity in the registration options.`>
1328
+ : {
1329
+ readonly [K in keyof SvmAllAccountLamportsFields]: SvmActivityHas<Fields, `lamports.${K & string}`> extends true
1330
+ ? SvmAllAccountLamportsFields[K]
1331
+ : FieldNotSelected<`Field 'lamports.${K & string}' is not selected for this handler. Add it to fields.accountActivity in the registration options.`>;
1332
+ } | undefined;
1338
1333
 
1339
- type SvmSelectedToken<Fields> = [SvmActivityListed<Fields> & (`token` | `token.${string}`)] extends [never]
1334
+ /** The token activity of a {@link SvmAccountActivity}, narrowed to the
1335
+ * registration's fields selection. */
1336
+ export type SvmAccountTokenActivity<Fields extends SvmFieldsSelection> = [SvmActivityListed<Fields> & `token.${string}`] extends [never]
1340
1337
  ? FieldNotSelected<`Field 'token' is not selected for this handler. Add it to fields.accountActivity in the registration options.`>
1341
1338
  : {
1342
- readonly [K in keyof SvmAccountTokenActivity as SvmActivityHas<Fields, `token.${K & string}`> extends true
1343
- ? K
1344
- : never]: SvmAccountTokenActivity[K];
1339
+ readonly [K in keyof SvmAllAccountTokenActivityFields]: SvmActivityHas<Fields, `token.${K & string}`> extends true
1340
+ ? SvmAllAccountTokenActivityFields[K]
1341
+ : FieldNotSelected<`Field 'token.${K & string}' is not selected for this handler. Add it to fields.accountActivity in the registration options.`>;
1345
1342
  } | undefined;
1346
1343
 
1347
- type SvmSelectedAccountActivity<Fields> = {
1344
+ /** An account activity of a {@link SvmTransaction}, narrowed to the
1345
+ * registration's fields selection. */
1346
+ export type SvmAccountActivity<Fields extends SvmFieldsSelection> = {
1348
1347
  readonly address: string;
1349
1348
  readonly transactionAccountIndex: SvmActivityField<Fields, "transactionAccountIndex", number>;
1350
1349
  readonly isSigner: SvmActivityField<Fields, "isSigner", boolean>;
1351
1350
  readonly isWritable: SvmActivityField<Fields, "isWritable", boolean>;
1352
- readonly lamports: SvmSelectedLamports<Fields>;
1353
- readonly token: SvmSelectedToken<Fields>;
1351
+ readonly lamports: SvmAccountLamports<Fields>;
1352
+ readonly token: SvmAccountTokenActivity<Fields>;
1354
1353
  };
1355
1354
 
1356
1355
  type SvmInstrListed<Fields> = SvmListedFields<Fields, "instruction">;
@@ -1358,37 +1357,54 @@ type SvmInstrField<Fields, Name extends SvmInstructionFieldName, T> = Name exten
1358
1357
  ? T
1359
1358
  : FieldNotSelected<`Field '${Name}' is not selected for this handler. Add it to fields.instruction in the registration options.`>;
1360
1359
 
1360
+ /** A named account of a {@link SvmInstruction}. Its `activity` narrows to the
1361
+ * registration's fields selection. */
1362
+ export type SvmInstructionAccount<
1363
+ Fields extends SvmFieldsSelection,
1364
+ Name extends string = string,
1365
+ > = {
1366
+ readonly address: string;
1367
+ readonly accountName: Name;
1368
+ readonly instructionAccountIndex: number;
1369
+ readonly activity:
1370
+ | ([SvmActivityListed<Fields>] extends [never]
1371
+ ? FieldNotSelected<`Field 'activity' is not selected for this handler. Add fields.accountActivity in the registration options.`>
1372
+ : SvmAccountActivity<Fields>)
1373
+ | undefined;
1374
+ };
1375
+
1361
1376
  type SvmNamedAccounts<
1362
1377
  Acc extends Readonly<Record<string, unknown>>,
1363
- Fields,
1378
+ Fields extends SvmFieldsSelection,
1364
1379
  > = {
1365
- readonly [K in keyof Acc & string]: SvmInstructionAccount<
1366
- [SvmActivityListed<Fields>] extends [never]
1367
- ? FieldNotSelected<`Field 'activity' is not selected for this handler. Add fields.accountActivity in the registration options.`>
1368
- : SvmSelectedAccountActivity<Fields> | undefined,
1369
- K
1370
- >;
1380
+ readonly [K in keyof Acc & string]: SvmInstructionAccount<Fields, K>;
1371
1381
  };
1372
1382
 
1373
- type SvmSelectedTransaction<Fields> = {
1374
- readonly [K in keyof SvmTransaction]: K extends SvmListedFields<Fields, "transaction">
1375
- ? SvmTransaction[K]
1383
+ /** The parent transaction of a {@link SvmInstruction}, narrowed to the
1384
+ * registration's fields selection. */
1385
+ export type SvmTransaction<Fields extends SvmFieldsSelection> = {
1386
+ readonly [K in keyof SvmAllTransactionFields]: K extends SvmListedFields<Fields, "transaction">
1387
+ ? SvmAllTransactionFields[K]
1376
1388
  : FieldNotSelected<`Field '${K & string}' is not selected for this handler. Add it to fields.transaction in the registration options.`>;
1377
1389
  } & {
1378
1390
  readonly accountActivities: [SvmActivityListed<Fields>] extends [never]
1379
1391
  ? FieldNotSelected<`Field 'accountActivities' is not selected for this handler. Add fields.accountActivity in the registration options.`>
1380
- : readonly SvmSelectedAccountActivity<Fields>[];
1392
+ : readonly SvmAccountActivity<Fields>[];
1381
1393
  };
1382
1394
 
1383
- type SvmSelectedBlock<Fields> = {
1384
- readonly [K in keyof SvmBlock]: K extends "slot"
1385
- ? SvmBlock[K]
1395
+ /** The block of a {@link SvmInstruction}, narrowed to the registration's
1396
+ * fields selection. `slot` is always selected. */
1397
+ export type SvmBlock<Fields extends SvmFieldsSelection> = {
1398
+ readonly [K in keyof SvmAllBlockFields]: K extends "slot"
1399
+ ? SvmAllBlockFields[K]
1386
1400
  : K extends SvmListedFields<Fields, "block">
1387
- ? SvmBlock[K]
1401
+ ? SvmAllBlockFields[K]
1388
1402
  : FieldNotSelected<`Field '${K & string}' is not selected for this handler. Add it to fields.block in the registration options.`>;
1389
1403
  };
1390
1404
 
1391
- type SvmSelectedLog<Fields> = {
1405
+ /** A log of a {@link SvmInstruction}, narrowed to the registration's fields
1406
+ * selection. */
1407
+ export type SvmLog<Fields extends SvmFieldsSelection> = {
1392
1408
  readonly kind: "kind" extends SvmListedFields<Fields, "log">
1393
1409
  ? SvmLogKind
1394
1410
  : FieldNotSelected<`Field 'kind' is not selected for this handler. Add it to fields.log in the registration options.`>;
@@ -1397,10 +1413,12 @@ type SvmSelectedLog<Fields> = {
1397
1413
  : FieldNotSelected<`Field 'message' is not selected for this handler. Add it to fields.log in the registration options.`>;
1398
1414
  };
1399
1415
 
1400
- export type SvmInstruction<
1401
- ProgInstr = { readonly args: unknown; readonly accounts: Readonly<Record<string, string>> },
1402
- Fields = {},
1403
- > = {
1416
+ type SvmAnyProgramInstruction = {
1417
+ readonly args: unknown;
1418
+ readonly accounts: Readonly<Record<string, string>>;
1419
+ };
1420
+
1421
+ type SvmSelectedInstruction<Fields extends SvmFieldsSelection, ProgInstr> = {
1404
1422
  readonly programName: string;
1405
1423
  readonly instructionName: string;
1406
1424
  readonly discriminator: string;
@@ -1411,7 +1429,7 @@ export type SvmInstruction<
1411
1429
  readonly args: SvmInstrField<
1412
1430
  Fields,
1413
1431
  "args",
1414
- ProgInstr extends { readonly args: infer A } ? A | undefined : unknown | undefined
1432
+ ProgInstr extends { readonly args: infer A } ? A : unknown
1415
1433
  >;
1416
1434
  readonly accounts: SvmInstrField<
1417
1435
  Fields,
@@ -1423,25 +1441,54 @@ export type SvmInstruction<
1423
1441
  readonly accountArguments: SvmInstrField<Fields, "accountArguments", readonly string[]>;
1424
1442
  readonly logs: [SvmListedFields<Fields, "log">] extends [never]
1425
1443
  ? FieldNotSelected<`Field 'logs' is not selected for this handler. Add fields.log in the registration options.`>
1426
- : readonly SvmSelectedLog<Fields>[];
1427
- readonly transaction: SvmSelectedTransaction<Fields>;
1428
- readonly block: SvmSelectedBlock<Fields>;
1429
- };
1444
+ : readonly SvmLog<Fields>[];
1445
+ readonly transaction: SvmTransaction<Fields>;
1446
+ readonly block: SvmBlock<Fields>;
1447
+ };
1448
+
1449
+ type SvmConfiguredInstruction<Program extends string, Instruction extends string> = [
1450
+ Program,
1451
+ ] extends [never]
1452
+ ? SvmAnyProgramInstruction
1453
+ : Program extends keyof SvmProgramsT
1454
+ ? Instruction extends keyof SvmProgramsT[Program]
1455
+ ? SvmProgramsT[Program][Instruction]
1456
+ : SvmAnyProgramInstruction
1457
+ : SvmAnyProgramInstruction;
1458
+
1459
+ /** The `instruction` payload of an `indexer.onInstruction` handler. `Fields`
1460
+ * must be the registration's fields selection (use `typeof fields` on a
1461
+ * `const fields = {...} as const satisfies SvmFieldsSelection`, or
1462
+ * {@link SvmAllFieldsSelection}). Pass the config-declared program and
1463
+ * instruction names to type `args` and `accounts`. */
1464
+ export type SvmInstruction<
1465
+ Fields extends SvmFieldsSelection,
1466
+ Program extends keyof SvmProgramsT & string = never,
1467
+ Instruction extends keyof SvmProgramsT[Program] & string = never,
1468
+ > = SvmSelectedInstruction<Fields, SvmConfiguredInstruction<Program, Instruction>>;
1430
1469
 
1431
- /** Arguments passed to handlers registered via `indexer.onInstruction`. */
1432
- export type SvmOnInstructionHandlerArgs<
1433
- Config extends IndexerConfigTypes = GlobalConfig,
1434
- Instr = SvmInstruction,
1435
- > = {
1470
+ type SvmOnInstructionArgsFor<Instr, Config extends IndexerConfigTypes> = {
1436
1471
  readonly instruction: Instr;
1437
1472
  readonly context: SvmOnSlotContext<Config>;
1438
1473
  };
1439
1474
 
1475
+ type SvmOnInstructionHandlerFor<Instr, Config extends IndexerConfigTypes> = (
1476
+ args: SvmOnInstructionArgsFor<Instr, Config>,
1477
+ ) => Promise<void>;
1478
+
1479
+ /** Arguments passed to handlers registered via `indexer.onInstruction`.
1480
+ * Takes the same type arguments as {@link SvmInstruction}. */
1481
+ export type SvmOnInstructionHandlerArgs<
1482
+ Fields extends SvmFieldsSelection,
1483
+ Program extends keyof SvmProgramsT & string = never,
1484
+ Instruction extends keyof SvmProgramsT[Program] & string = never,
1485
+ > = SvmOnInstructionArgsFor<SvmInstruction<Fields, Program, Instruction>, GlobalConfig>;
1486
+
1440
1487
  /** Options for an SVM `indexer.onInstruction` registration. */
1441
1488
  export type SvmOnInstructionOptions<
1442
1489
  P extends string = string,
1443
1490
  I extends string = string,
1444
- Fields extends SvmFieldsSelection | undefined = undefined,
1491
+ Fields extends SvmFieldsSelection = {},
1445
1492
  > = {
1446
1493
  /** Program name as declared under `chains[].programs[].name` in
1447
1494
  * `config.yaml`. */
@@ -1452,10 +1499,21 @@ export type SvmOnInstructionOptions<
1452
1499
  readonly fields?: Fields & SvmFieldsLiteralCheck<Fields>;
1453
1500
  };
1454
1501
 
1455
- /** Handler function for an SVM `indexer.onInstruction` registration. */
1502
+ /** Handler function for an SVM `indexer.onInstruction` registration. Takes
1503
+ * the same type arguments as {@link SvmInstruction}, so a standalone handler
1504
+ * needs a single annotation:
1505
+ *
1506
+ * const handleSwap: SvmOnInstructionHandler<typeof fields, "Swapper", "swap"> =
1507
+ * async ({ instruction, context }) => { ... };
1508
+ */
1456
1509
  export type SvmOnInstructionHandler<
1457
- Config extends IndexerConfigTypes = GlobalConfig,
1458
- > = (args: SvmOnInstructionHandlerArgs<Config>) => Promise<void>;
1510
+ Fields extends SvmFieldsSelection,
1511
+ Program extends keyof SvmProgramsT & string = never,
1512
+ Instruction extends keyof SvmProgramsT[Program] & string = never,
1513
+ > = SvmOnInstructionHandlerFor<
1514
+ SvmInstruction<Fields, Program, Instruction>,
1515
+ GlobalConfig
1516
+ >;
1459
1517
 
1460
1518
  // ============== Indexer Types ==============
1461
1519
 
@@ -1685,18 +1743,13 @@ type SvmEcosystem<Config extends IndexerConfigTypes = GlobalConfig> =
1685
1743
  readonly onInstruction: <
1686
1744
  P extends keyof Programs & string,
1687
1745
  I extends keyof Programs[P] & string,
1688
- const F extends SvmFieldsSelection | undefined,
1746
+ const F extends SvmFieldsSelection = {},
1689
1747
  >(
1690
1748
  options: SvmOnInstructionOptions<P, I, F>,
1691
- handler: (
1692
- args: SvmOnInstructionHandlerArgs<
1693
- Config,
1694
- SvmInstruction<
1695
- Programs[P][I],
1696
- [F] extends [undefined] ? {} : F
1697
- >
1698
- >,
1699
- ) => Promise<void>,
1749
+ handler: SvmOnInstructionHandlerFor<
1750
+ SvmSelectedInstruction<F, Programs[P][I]>,
1751
+ Config
1752
+ >,
1700
1753
  ) => void;
1701
1754
  }
1702
1755
  : {
@@ -1867,9 +1920,9 @@ type SvmSimulateItem<Config extends IndexerConfigTypes = GlobalConfig> =
1867
1920
  /** Logs scoped to this instruction. */
1868
1921
  logs?: readonly { readonly kind?: string; readonly message?: string }[];
1869
1922
  /** Override block fields. */
1870
- block?: Partial<SvmBlock>;
1923
+ block?: Partial<SvmAllBlockFields>;
1871
1924
  /** Override transaction fields. `accountActivities` are joined onto named accounts at process time. */
1872
- transaction?: Partial<SvmTransaction> & {
1925
+ transaction?: Partial<SvmAllTransactionFields> & {
1873
1926
  readonly accountActivities?: readonly {
1874
1927
  readonly address: string;
1875
1928
  readonly transactionAccountIndex?: number;
@@ -2138,6 +2191,7 @@ type EvmContractsT = GlobalConfig extends { evm: { contracts: infer X extends
2138
2191
  type FuelChainsT = GlobalConfig extends { fuel: { chains: infer X extends Record<string, { id: number }> } } ? X : {};
2139
2192
  type FuelContractsT = GlobalConfig extends { fuel: { contracts: infer X extends Record<string, Record<string, any>> } } ? X : {};
2140
2193
  type SvmChainsT = GlobalConfig extends { svm: { chains: infer X extends Record<string, { id: number }> } } ? X : {};
2194
+ type SvmProgramsT = GlobalConfig extends { svm: { programs: infer X extends Record<string, Record<string, any>> } } ? X : {};
2141
2195
  type EntitiesT = GlobalConfig extends { entities: infer X extends Record<string, object> } ? X : {};
2142
2196
  type EnumsT = GlobalConfig extends { enums: infer X extends Record<string, any> } ? X : {};
2143
2197
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "envio",
3
- "version": "3.8.0",
3
+ "version": "3.9.0",
4
4
  "type": "module",
5
5
  "description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
6
6
  "bin": "./bin.mjs",
@@ -69,10 +69,10 @@
69
69
  "tsx": "4.21.0"
70
70
  },
71
71
  "optionalDependencies": {
72
- "envio-linux-x64": "3.8.0",
73
- "envio-linux-x64-musl": "3.8.0",
74
- "envio-linux-arm64": "3.8.0",
75
- "envio-darwin-x64": "3.8.0",
76
- "envio-darwin-arm64": "3.8.0"
72
+ "envio-linux-x64": "3.9.0",
73
+ "envio-linux-x64-musl": "3.9.0",
74
+ "envio-linux-arm64": "3.9.0",
75
+ "envio-darwin-x64": "3.9.0",
76
+ "envio-darwin-arm64": "3.9.0"
77
77
  }
78
78
  }
@@ -0,0 +1,121 @@
1
+ type key = {
2
+ chainId: ChainId.t,
3
+ address: NodeJs.Buffer.t,
4
+ contractId: int,
5
+ }
6
+
7
+ type row = {
8
+ chainId: ChainId.t,
9
+ address: NodeJs.Buffer.t,
10
+ contractId: int,
11
+ registrationBlock: int,
12
+ }
13
+
14
+ type staged = {
15
+ row: row,
16
+ checkpointId: Internal.checkpointId,
17
+ }
18
+
19
+ type seedRows = {
20
+ addresses: array<NodeJs.Buffer.t>,
21
+ contractIds: array<int>,
22
+ registrationBlocks: array<int>,
23
+ }
24
+
25
+ let emptySeedRows = (): seedRows => {
26
+ addresses: [],
27
+ contractIds: [],
28
+ registrationBlocks: [],
29
+ }
30
+
31
+ // Config addresses are registered by no event. Rollback never reaches them.
32
+ let configRegistrationBlock = -1
33
+
34
+ let keyOf = (row: row): key => {
35
+ chainId: row.chainId,
36
+ address: row.address,
37
+ contractId: row.contractId,
38
+ }
39
+
40
+ let packBuffers = (addresses: array<NodeJs.Buffer.t>) => (
41
+ NodeJs.Buffer.concat(addresses),
42
+ addresses->Array.map(address => address->NodeJs.Buffer.length),
43
+ )
44
+
45
+ let packKeys = (rows: array<row>) => packBuffers(rows->Array.map(row => row.address))
46
+
47
+ let seedRowsOf = (rows: array<row>): seedRows => {
48
+ let addresses = []
49
+ let contractIds = []
50
+ let registrationBlocks = []
51
+ rows->Array.forEach(row => {
52
+ addresses->Array.push(row.address)->ignore
53
+ contractIds->Array.push(row.contractId)->ignore
54
+ registrationBlocks->Array.push(row.registrationBlock)->ignore
55
+ })
56
+ {addresses, contractIds, registrationBlocks}
57
+ }
58
+
59
+ // Rows arrive clustered per chain. Normalizing a chain id is a schema parse.
60
+ let group = (rows: array<row>): dict<seedRows> => {
61
+ let rowsByChain: dict<array<row>> = Dict.make()
62
+ let runChainId = ref(None)
63
+ let runKey = ref("")
64
+ rows->Array.forEach(row => {
65
+ if runChainId.contents !== Some(row.chainId) {
66
+ runChainId := Some(row.chainId)
67
+ runKey := row.chainId->ChainId.normalizeOrThrow->ChainId.toString
68
+ }
69
+ rowsByChain->Utils.Dict.push(runKey.contents, row)
70
+ })
71
+ rowsByChain->Utils.Dict.mapValues(seedRowsOf)
72
+ }
73
+
74
+ module Table = {
75
+ type t = dict<row>
76
+
77
+ let dictKey = (key: key) =>
78
+ `${key.chainId->ChainId.toString}|${key.contractId->Int.toString}|${key.address->NodeJs.Buffer.toBase64}`
79
+
80
+ let make = (): t => Dict.make()
81
+
82
+ let clear = (table: t) => table->Utils.Dict.clearInPlace
83
+
84
+ let insert = (table: t, row: row) => {
85
+ let key = row->keyOf->dictKey
86
+ switch table->Utils.Dict.dangerouslyGetNonOption(key) {
87
+ | Some(_) => ()
88
+ | None => table->Dict.set(key, row)
89
+ }
90
+ }
91
+
92
+ let insertMany = (table: t, rows: array<row>) => rows->Array.forEach(row => table->insert(row))
93
+
94
+ let delete = (table: t, key: key) => table->Utils.Dict.deleteInPlace(key->dictKey)
95
+
96
+ let rows = (table: t): array<row> => table->Dict.valuesToArray
97
+
98
+ let groupByChain = (table: t) => table->rows->group
99
+ }
100
+
101
+ let render = (rows: array<row>, ~ecosystem: string, ~shouldChecksum: bool) => {
102
+ let (bytes, lengths) = rows->packKeys
103
+ Core.getAddon().renderAddresses(~ecosystem, ~shouldChecksum, ~bytes, ~lengths)
104
+ }
105
+
106
+ let renderOfContract = (
107
+ rows: seedRows,
108
+ ~ecosystem: string,
109
+ ~shouldChecksum: bool,
110
+ ~contractId: int,
111
+ ) => {
112
+ let (bytes, lengths) = packBuffers(rows.addresses)
113
+ Core.getAddon().renderContractAddresses(
114
+ ~ecosystem,
115
+ ~shouldChecksum,
116
+ ~bytes,
117
+ ~lengths,
118
+ ~contractIds=rows.contractIds,
119
+ ~contractId,
120
+ )
121
+ }