envio 3.7.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 (79) hide show
  1. package/README.md +2 -2
  2. package/index.d.ts +399 -156
  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 +82 -68
  9. package/src/ChainState.res.mjs +81 -65
  10. package/src/ChainState.resi +14 -9
  11. package/src/Config.res +41 -91
  12. package/src/Config.res.mjs +34 -68
  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/Envio.res +54 -76
  18. package/src/EventConfigBuilder.res +157 -30
  19. package/src/EventConfigBuilder.res.mjs +118 -24
  20. package/src/FetchState.res +59 -67
  21. package/src/FetchState.res.mjs +34 -44
  22. package/src/HandlerRegister.res +20 -11
  23. package/src/HandlerRegister.res.mjs +22 -5
  24. package/src/Hasura.res +30 -22
  25. package/src/Hasura.res.mjs +11 -5
  26. package/src/InMemoryStore.res +18 -36
  27. package/src/InMemoryStore.res.mjs +12 -26
  28. package/src/IndexerState.res +21 -1
  29. package/src/IndexerState.res.mjs +9 -3
  30. package/src/IndexerState.resi +1 -0
  31. package/src/Internal.res +33 -13
  32. package/src/Internal.res.mjs +12 -16
  33. package/src/Main.res +27 -20
  34. package/src/Main.res.mjs +19 -14
  35. package/src/MemoryStorage.res +78 -73
  36. package/src/MemoryStorage.res.mjs +66 -81
  37. package/src/Metrics.res +15 -1
  38. package/src/Metrics.res.mjs +5 -1
  39. package/src/Persistence.res +34 -18
  40. package/src/Persistence.res.mjs +8 -5
  41. package/src/PgStorage.res +189 -66
  42. package/src/PgStorage.res.mjs +93 -59
  43. package/src/Rollback.res +14 -10
  44. package/src/Rollback.res.mjs +4 -2
  45. package/src/SimulateItems.res +254 -9
  46. package/src/SimulateItems.res.mjs +214 -47
  47. package/src/TestIndexer.res +119 -121
  48. package/src/TestIndexer.res.mjs +95 -100
  49. package/src/Utils.res +7 -0
  50. package/src/Utils.res.mjs +9 -2
  51. package/src/Writing.res +2 -0
  52. package/src/Writing.res.mjs +2 -1
  53. package/src/bindings/ClickHouse.res +39 -6
  54. package/src/bindings/ClickHouse.res.mjs +29 -4
  55. package/src/bindings/NodeJs.res +9 -0
  56. package/src/bindings/NodeJs.res.mjs +8 -1
  57. package/src/bindings/Postgres.res +9 -0
  58. package/src/bindings/Postgres.res.mjs +3 -0
  59. package/src/db/EntityHistory.res +12 -18
  60. package/src/db/EntityHistory.res.mjs +3 -14
  61. package/src/db/InternalTable.res +182 -65
  62. package/src/db/InternalTable.res.mjs +183 -73
  63. package/src/db/Table.res +24 -0
  64. package/src/db/Table.res.mjs +20 -1
  65. package/src/sources/AddressSet.res +0 -22
  66. package/src/sources/AddressStore.res +48 -88
  67. package/src/sources/AddressStore.res.mjs +11 -22
  68. package/src/sources/EvmHyperSyncSource.res +3 -2
  69. package/src/sources/SimulateSource.res +8 -4
  70. package/src/sources/SimulateSource.res.mjs +7 -3
  71. package/src/sources/Svm.res +34 -7
  72. package/src/sources/Svm.res.mjs +32 -4
  73. package/src/sources/SvmHyperSyncClient.res +24 -30
  74. package/src/sources/SvmHyperSyncClient.res.mjs +3 -2
  75. package/src/sources/SvmHyperSyncSource.res +88 -36
  76. package/src/sources/SvmHyperSyncSource.res.mjs +71 -39
  77. package/src/sources/TransactionStore.res +38 -0
  78. package/src/sources/TransactionStore.res.mjs +5 -0
  79. package/svm.schema.json +37 -82
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
@@ -1160,152 +1160,360 @@ export type SvmOnSlotOptions<Config extends IndexerConfigTypes = GlobalConfig> =
1160
1160
 
1161
1161
  // ============== SVM onInstruction types ==============
1162
1162
 
1163
- /** Borsh-decoded params view of an instruction. Present whenever a
1164
- * `ProgramSchema` was attached to the program (bundled, Anchor IDL, or
1165
- * hand-written `accounts`/`args` in YAML). Absent when no schema applies or
1166
- * the discriminator didn't match any registered instruction. */
1167
- export type SvmInstructionParams = {
1168
- /** Schema-declared instruction name. */
1169
- readonly name: string;
1170
- /** Borsh-decoded args object. POC types this as `unknown`; narrow with a
1171
- * locally-declared type until the typed-args codegen lands. */
1172
- readonly args: unknown;
1173
- /** Named accounts in schema order. Keys are exactly the schema-declared
1174
- * names; values are base58 pubkeys. */
1175
- readonly accounts: Readonly<Record<string, string>>;
1176
- /** Accounts beyond the schema's named list (Anchor `remaining_accounts`,
1177
- * IDL drift). Empty when counts match the schema. */
1178
- readonly extraAccounts: readonly string[];
1163
+ export type SvmLogKind =
1164
+ | "invoke"
1165
+ | "success"
1166
+ | "failed"
1167
+ | "consumed"
1168
+ | "log"
1169
+ | "data"
1170
+ | (string & {});
1171
+
1172
+ export type SvmAllLogFields = {
1173
+ readonly kind: SvmLogKind;
1174
+ readonly message: string;
1175
+ };
1176
+
1177
+ export type SvmAllAccountLamportsFields = {
1178
+ readonly pre: bigint;
1179
+ readonly post: bigint;
1179
1180
  };
1180
1181
 
1181
- /** Permissive fallback shape for an instruction's `block`. The generated
1182
- * per-instruction type narrows this to `slot`/`hash` (always present) and
1183
- * `time` (always present but possibly `undefined`), plus the selected
1184
- * `field_selection.block_fields`. */
1185
- export type SvmInstructionBlock = {
1186
- /** Slot this instruction's block was matched in. */
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 = {
1191
+ readonly address: string;
1192
+ readonly transactionAccountIndex: number;
1193
+ readonly isSigner: boolean;
1194
+ readonly isWritable: boolean;
1195
+ readonly lamports: SvmAllAccountLamportsFields | undefined;
1196
+ readonly token: SvmAllAccountTokenActivityFields | undefined;
1197
+ };
1198
+
1199
+ export type SvmAllBlockFields = {
1187
1200
  readonly slot: number;
1188
- /** Unix block time (seconds). Absent when HyperSync/Solana doesn't report a
1189
- * block time for this slot. */
1190
- readonly time?: number;
1191
- /** Block hash. */
1201
+ readonly time: number;
1192
1202
  readonly hash: string;
1193
- /** Block height. Select via `field_selection.block_fields`. */
1194
- readonly height?: number;
1195
- /** Parent slot. Select via `field_selection.block_fields`. */
1196
- readonly parentSlot?: number;
1197
- /** Parent block hash. Select via `field_selection.block_fields`. */
1198
- readonly parentHash?: string;
1199
- };
1200
-
1201
- export type SvmTokenBalance = {
1202
- readonly account?: string;
1203
- readonly mint?: string;
1204
- /** Owner at the end of the transaction, falling back to the owner on entry
1205
- * when the account was closed during it. Pre and post owners differ only
1206
- * when a `SetAuthority(AccountOwner)` runs mid-transaction. */
1207
- readonly owner?: string;
1208
- /** Mint decimals, for scaling the raw amounts below. */
1209
- readonly decimals?: number;
1210
- /** Raw amount in base units before the transaction. Absent when the token
1211
- * account was created during it. */
1212
- readonly preAmount?: bigint;
1213
- /** Raw amount in base units after the transaction. Absent when the token
1214
- * account was closed during it. */
1215
- readonly postAmount?: bigint;
1216
- };
1217
-
1218
- export type SvmLog = {
1219
- readonly kind: string;
1220
- readonly message: string;
1203
+ readonly height: number;
1204
+ readonly parentSlot: number;
1205
+ readonly parentHash: string;
1221
1206
  };
1222
1207
 
1223
- /** A single Solana instruction delivered to an `onInstruction` handler.
1224
- *
1225
- * Carries the matched instruction's own fields (`programId`, `data`,
1226
- * `accounts`, discriminator prefixes, `params`) plus the program/instruction
1227
- * names, parent transaction, scoped logs, and block context. Parameterised
1228
- * over `Params` so the per-(program, instruction) overload of
1229
- * `onInstruction` can narrow `instruction.params` to the codegen-generated
1230
- * `{ args, accounts }` shape.
1208
+ /** All SVM parent-transaction fields. Handler `fields.transaction` narrows
1209
+ * this via {@link SvmTransaction}; `accountActivities` is implied by
1210
+ * `fields.accountActivity`. */
1211
+ export type SvmAllTransactionFields = {
1212
+ readonly transactionIndex: number;
1213
+ readonly signature: string;
1214
+ readonly feePayer: string;
1215
+ readonly success: boolean;
1216
+ readonly err: string | undefined;
1217
+ readonly fee: bigint;
1218
+ readonly computeUnitsConsumed: bigint | undefined;
1219
+ readonly accountKeys: readonly string[];
1220
+ readonly recentBlockhash: string;
1221
+ readonly version: string | undefined;
1222
+ readonly allSignatures: readonly string[];
1223
+ };
1224
+
1225
+ export type SvmInstructionFieldName =
1226
+ | "args"
1227
+ | "accounts"
1228
+ | "accountArguments"
1229
+ | "programId"
1230
+ | "data"
1231
+ | "path"
1232
+ | "isInner";
1233
+ export type SvmTransactionFieldName =
1234
+ | "transactionIndex"
1235
+ | "signature"
1236
+ | "feePayer"
1237
+ | "success"
1238
+ | "err"
1239
+ | "fee"
1240
+ | "computeUnitsConsumed"
1241
+ | "accountKeys"
1242
+ | "recentBlockhash"
1243
+ | "version"
1244
+ | "allSignatures";
1245
+ export type SvmAccountActivityFieldName =
1246
+ | "address"
1247
+ | "transactionAccountIndex"
1248
+ | "isSigner"
1249
+ | "isWritable"
1250
+ | "lamports.pre"
1251
+ | "lamports.post"
1252
+ | "token.mint"
1253
+ | "token.owner"
1254
+ | "token.decimals"
1255
+ | "token.preAmount"
1256
+ | "token.postAmount";
1257
+ export type SvmBlockFieldName =
1258
+ | "slot"
1259
+ | "time"
1260
+ | "hash"
1261
+ | "height"
1262
+ | "parentSlot"
1263
+ | "parentHash";
1264
+ export type SvmLogFieldName = "kind" | "message";
1265
+
1266
+ export type SvmFieldsSelection = {
1267
+ readonly instruction?: readonly SvmInstructionFieldName[];
1268
+ readonly transaction?: readonly SvmTransactionFieldName[];
1269
+ readonly accountActivity?: readonly SvmAccountActivityFieldName[];
1270
+ readonly block?: readonly SvmBlockFieldName[];
1271
+ readonly log?: readonly SvmLogFieldName[];
1272
+ };
1273
+
1274
+ /** A {@link SvmFieldsSelection} with every field selected.
1231
1275
  *
1232
- * `data` and discriminator prefixes are `0x`-prefixed hex strings; accounts
1233
- * are base58 strings. */
1234
- export type SvmInstruction<
1235
- Params extends SvmInstructionParams = SvmInstructionParams,
1236
- Tx = SvmTransaction,
1237
- Block = SvmInstructionBlock,
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
+
1287
+ type SvmListedArray<Fields, Knob extends keyof SvmFieldsSelection> = Fields[Knob &
1288
+ keyof Fields];
1289
+ type SvmListedFields<Fields, Knob extends keyof SvmFieldsSelection> = NonNullable<
1290
+ SvmListedArray<Fields, Knob>
1291
+ >[number] &
1292
+ string;
1293
+
1294
+ type SvmFieldsLiteralCheck<Fields> = [Fields] extends [undefined]
1295
+ ? unknown
1296
+ : IsWidenedArray<SvmListedArray<Fields, "instruction">> extends true
1297
+ ? EvmFieldsMustBeLiteral<"instruction">
1298
+ : IsWidenedArray<SvmListedArray<Fields, "transaction">> extends true
1299
+ ? EvmFieldsMustBeLiteral<"transaction">
1300
+ : IsWidenedArray<SvmListedArray<Fields, "accountActivity">> extends true
1301
+ ? EvmFieldsMustBeLiteral<"accountActivity">
1302
+ : IsWidenedArray<SvmListedArray<Fields, "block">> extends true
1303
+ ? EvmFieldsMustBeLiteral<"block">
1304
+ : IsWidenedArray<SvmListedArray<Fields, "log">> extends true
1305
+ ? EvmFieldsMustBeLiteral<"log">
1306
+ : unknown;
1307
+
1308
+ type SvmActivityListed<Fields> = SvmListedFields<Fields, "accountActivity">;
1309
+ type SvmActivityHas<Fields, Name extends string> = [SvmActivityListed<Fields>] extends [never]
1310
+ ? false
1311
+ : Name extends SvmActivityListed<Fields>
1312
+ ? true
1313
+ : false;
1314
+
1315
+ type SvmActivityField<Fields, Name extends string, T> = SvmActivityHas<
1316
+ Fields,
1317
+ Name
1318
+ > extends true
1319
+ ? T
1320
+ : FieldNotSelected<`Field '${Name}' is not selected for this handler. Add it to fields.accountActivity in the registration options.`>;
1321
+
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;
1333
+
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]
1337
+ ? FieldNotSelected<`Field 'token' is not selected for this handler. Add it to fields.accountActivity in the registration options.`>
1338
+ : {
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.`>;
1342
+ } | undefined;
1343
+
1344
+ /** An account activity of a {@link SvmTransaction}, narrowed to the
1345
+ * registration's fields selection. */
1346
+ export type SvmAccountActivity<Fields extends SvmFieldsSelection> = {
1347
+ readonly address: string;
1348
+ readonly transactionAccountIndex: SvmActivityField<Fields, "transactionAccountIndex", number>;
1349
+ readonly isSigner: SvmActivityField<Fields, "isSigner", boolean>;
1350
+ readonly isWritable: SvmActivityField<Fields, "isWritable", boolean>;
1351
+ readonly lamports: SvmAccountLamports<Fields>;
1352
+ readonly token: SvmAccountTokenActivity<Fields>;
1353
+ };
1354
+
1355
+ type SvmInstrListed<Fields> = SvmListedFields<Fields, "instruction">;
1356
+ type SvmInstrField<Fields, Name extends SvmInstructionFieldName, T> = Name extends SvmInstrListed<Fields>
1357
+ ? T
1358
+ : FieldNotSelected<`Field '${Name}' is not selected for this handler. Add it to fields.instruction in the registration options.`>;
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,
1238
1365
  > = {
1239
- /** Program name as declared under `programs[].name` in `config.yaml`. */
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
+
1376
+ type SvmNamedAccounts<
1377
+ Acc extends Readonly<Record<string, unknown>>,
1378
+ Fields extends SvmFieldsSelection,
1379
+ > = {
1380
+ readonly [K in keyof Acc & string]: SvmInstructionAccount<Fields, K>;
1381
+ };
1382
+
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]
1388
+ : FieldNotSelected<`Field '${K & string}' is not selected for this handler. Add it to fields.transaction in the registration options.`>;
1389
+ } & {
1390
+ readonly accountActivities: [SvmActivityListed<Fields>] extends [never]
1391
+ ? FieldNotSelected<`Field 'accountActivities' is not selected for this handler. Add fields.accountActivity in the registration options.`>
1392
+ : readonly SvmAccountActivity<Fields>[];
1393
+ };
1394
+
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]
1400
+ : K extends SvmListedFields<Fields, "block">
1401
+ ? SvmAllBlockFields[K]
1402
+ : FieldNotSelected<`Field '${K & string}' is not selected for this handler. Add it to fields.block in the registration options.`>;
1403
+ };
1404
+
1405
+ /** A log of a {@link SvmInstruction}, narrowed to the registration's fields
1406
+ * selection. */
1407
+ export type SvmLog<Fields extends SvmFieldsSelection> = {
1408
+ readonly kind: "kind" extends SvmListedFields<Fields, "log">
1409
+ ? SvmLogKind
1410
+ : FieldNotSelected<`Field 'kind' is not selected for this handler. Add it to fields.log in the registration options.`>;
1411
+ readonly message: "message" extends SvmListedFields<Fields, "log">
1412
+ ? string
1413
+ : FieldNotSelected<`Field 'message' is not selected for this handler. Add it to fields.log in the registration options.`>;
1414
+ };
1415
+
1416
+ type SvmAnyProgramInstruction = {
1417
+ readonly args: unknown;
1418
+ readonly accounts: Readonly<Record<string, string>>;
1419
+ };
1420
+
1421
+ type SvmSelectedInstruction<Fields extends SvmFieldsSelection, ProgInstr> = {
1240
1422
  readonly programName: string;
1241
- /** Instruction name as declared under `instructions[].name` in
1242
- * `config.yaml`. */
1243
1423
  readonly instructionName: string;
1244
- readonly programId: string;
1245
- readonly data: string;
1246
- readonly accounts: readonly string[];
1247
- readonly instructionAddress: readonly number[];
1248
- readonly isInner: boolean;
1249
- readonly d1?: string;
1250
- readonly d2?: string;
1251
- readonly d4?: string;
1252
- readonly d8?: string;
1253
- /** Borsh-decoded params. Present when a schema is configured and matched. */
1254
- readonly params?: Params;
1255
- /** Parent transaction. Carries only the fields selected via this
1256
- * instruction's `field_selection`; unselected fields are typed as
1257
- * `FieldNotSelected<...>` so reading them is a compile error. Always present
1258
- * (`{}` when no fields are selected). */
1259
- readonly transaction: Tx;
1260
- /** Present when the instruction's `include_logs` is `true`; only logs
1261
- * scoped to this exact instruction (matching `instruction_address`). */
1262
- readonly logs?: readonly SvmLog[];
1263
- /** The block this instruction's slot belongs to. Carries `slot`/`hash`
1264
- * (always present) and `time` (always present but possibly `undefined`),
1265
- * plus the fields selected via this instruction's
1266
- * `field_selection.block_fields`; unselected fields are typed as
1267
- * `FieldNotSelected<...>`. */
1268
- readonly block: Block;
1269
- };
1270
-
1271
- /** Arguments passed to handlers registered via `indexer.onInstruction`. */
1272
- export type SvmOnInstructionHandlerArgs<
1273
- Config extends IndexerConfigTypes = GlobalConfig,
1274
- Instr extends SvmInstruction = SvmInstruction,
1275
- > = {
1424
+ readonly discriminator: string;
1425
+ readonly programId: SvmInstrField<Fields, "programId", string>;
1426
+ readonly data: SvmInstrField<Fields, "data", string>;
1427
+ readonly path: SvmInstrField<Fields, "path", readonly number[]>;
1428
+ readonly isInner: SvmInstrField<Fields, "isInner", boolean>;
1429
+ readonly args: SvmInstrField<
1430
+ Fields,
1431
+ "args",
1432
+ ProgInstr extends { readonly args: infer A } ? A : unknown
1433
+ >;
1434
+ readonly accounts: SvmInstrField<
1435
+ Fields,
1436
+ "accounts",
1437
+ ProgInstr extends { readonly accounts: infer Acc extends Readonly<Record<string, unknown>> }
1438
+ ? SvmNamedAccounts<Acc, Fields>
1439
+ : SvmNamedAccounts<Readonly<Record<string, string>>, Fields>
1440
+ >;
1441
+ readonly accountArguments: SvmInstrField<Fields, "accountArguments", readonly string[]>;
1442
+ readonly logs: [SvmListedFields<Fields, "log">] extends [never]
1443
+ ? FieldNotSelected<`Field 'logs' is not selected for this handler. Add fields.log in the registration options.`>
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>>;
1469
+
1470
+ type SvmOnInstructionArgsFor<Instr, Config extends IndexerConfigTypes> = {
1276
1471
  readonly instruction: Instr;
1277
1472
  readonly context: SvmOnSlotContext<Config>;
1278
1473
  };
1279
1474
 
1280
- /** Shape extracted from `Global.config.svm.programs[P][I]`. The codegen
1281
- * emits `{ args: ...; accounts: ... }` per (program, instruction); this
1282
- * helper turns that into a `SvmInstructionParams`-compatible record. */
1283
- type SvmParamsFromProgramTable<TInstr> = TInstr extends {
1284
- args: infer A;
1285
- accounts: infer Acc extends Readonly<Record<string, string>>;
1286
- }
1287
- ? {
1288
- readonly name: string;
1289
- readonly args: A;
1290
- readonly accounts: Acc;
1291
- readonly extraAccounts: readonly string[];
1292
- }
1293
- : SvmInstructionParams;
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>;
1294
1486
 
1295
1487
  /** Options for an SVM `indexer.onInstruction` registration. */
1296
- export type SvmOnInstructionOptions<P extends string = string, I extends string = string> = {
1488
+ export type SvmOnInstructionOptions<
1489
+ P extends string = string,
1490
+ I extends string = string,
1491
+ Fields extends SvmFieldsSelection = {},
1492
+ > = {
1297
1493
  /** Program name as declared under `chains[].programs[].name` in
1298
1494
  * `config.yaml`. */
1299
1495
  readonly program: P;
1300
1496
  /** Instruction name as declared under
1301
1497
  * `chains[].programs[].instructions[].name` in `config.yaml`. */
1302
1498
  readonly instruction: I;
1499
+ readonly fields?: Fields & SvmFieldsLiteralCheck<Fields>;
1303
1500
  };
1304
1501
 
1305
- /** 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
+ */
1306
1509
  export type SvmOnInstructionHandler<
1307
- Config extends IndexerConfigTypes = GlobalConfig,
1308
- > = (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
+ >;
1309
1517
 
1310
1518
  // ============== Indexer Types ==============
1311
1519
 
@@ -1530,28 +1738,18 @@ type SvmEcosystem<Config extends IndexerConfigTypes = GlobalConfig> =
1530
1738
  /**
1531
1739
  * Register an instruction handler. Dispatch matches on
1532
1740
  * `(programId, discriminator)` from the YAML config.
1533
- * `instruction.params.args` and
1534
- * `instruction.params.accounts` are typed from the
1535
- * program's Borsh schema (Anchor IDL, bundled, or
1536
- * hand-written `accounts`/`args` in YAML). `params` stays
1537
- * optional at runtime because schema-matching can fail on
1538
- * IDL drift or unknown discriminators.
1741
+ * Handler `fields` is the only source of payload selection.
1539
1742
  */
1540
1743
  readonly onInstruction: <
1541
1744
  P extends keyof Programs & string,
1542
1745
  I extends keyof Programs[P] & string,
1746
+ const F extends SvmFieldsSelection = {},
1543
1747
  >(
1544
- options: SvmOnInstructionOptions<P, I>,
1545
- handler: (
1546
- args: SvmOnInstructionHandlerArgs<
1547
- Config,
1548
- SvmInstruction<
1549
- SvmParamsFromProgramTable<Programs[P][I]>,
1550
- Programs[P][I]["transaction"],
1551
- Programs[P][I]["block"]
1552
- >
1553
- >,
1554
- ) => Promise<void>,
1748
+ options: SvmOnInstructionOptions<P, I, F>,
1749
+ handler: SvmOnInstructionHandlerFor<
1750
+ SvmSelectedInstruction<F, Programs[P][I]>,
1751
+ Config
1752
+ >,
1555
1753
  ) => void;
1556
1754
  }
1557
1755
  : {
@@ -1691,14 +1889,71 @@ type FuelTestIndexerChainConfig<Config extends IndexerConfigTypes = GlobalConfig
1691
1889
  simulate?: FuelSimulateItem<Config>[];
1692
1890
  };
1693
1891
 
1694
- /** Configuration for a single SVM chain in the test indexer. SVM has no
1695
- * `onEvent` handlers yet, so simulate items aren't supported — only slot
1696
- * range overrides for driving `indexer.onSlot` block handlers under test. */
1697
- type SvmTestIndexerChainConfig = {
1892
+ /** Simulate item type for SVM ecosystem. */
1893
+ type SvmSimulateItem<Config extends IndexerConfigTypes = GlobalConfig> =
1894
+ Config["svm"] extends { programs: infer Programs extends Record<string, Record<string, any>> }
1895
+ ? {
1896
+ [P in keyof Programs]: {
1897
+ [I in keyof Programs[P]]: {
1898
+ /** Program name as declared under `chains[].programs[].name`. */
1899
+ program: P;
1900
+ /** Instruction name as declared under the program. */
1901
+ instruction: I;
1902
+ /** Override the slot. Auto-increments by default. */
1903
+ slot?: number;
1904
+ /** Instruction path in the CPI tree. Defaults to `[0]`. */
1905
+ path?: readonly number[];
1906
+ /** Override the program id. Defaults to the configured `program_id`. */
1907
+ programId?: string;
1908
+ /** Raw instruction data, `0x`-prefixed hex. */
1909
+ data?: string;
1910
+ /** Whether this is a CPI-invoked inner instruction. */
1911
+ isInner?: boolean;
1912
+ /** Decoded args. Keys match the instruction's arg names. */
1913
+ args?: Programs[P][I] extends { args: infer A } ? A : unknown;
1914
+ /** Named accounts. Keys match the instruction's account names. */
1915
+ accounts?: Programs[P][I] extends { accounts: infer Acc extends Record<string, unknown> }
1916
+ ? { readonly [K in keyof Acc]?: { readonly address: string } }
1917
+ : Record<string, { readonly address: string }>;
1918
+ /** Positional account addresses, zipped onto IDL names when `accounts` is omitted. */
1919
+ accountArguments?: readonly string[];
1920
+ /** Logs scoped to this instruction. */
1921
+ logs?: readonly { readonly kind?: string; readonly message?: string }[];
1922
+ /** Override block fields. */
1923
+ block?: Partial<SvmAllBlockFields>;
1924
+ /** Override transaction fields. `accountActivities` are joined onto named accounts at process time. */
1925
+ transaction?: Partial<SvmAllTransactionFields> & {
1926
+ readonly accountActivities?: readonly {
1927
+ readonly address: string;
1928
+ readonly transactionAccountIndex?: number;
1929
+ readonly isSigner?: boolean;
1930
+ readonly isWritable?: boolean;
1931
+ readonly lamports?: {
1932
+ readonly pre?: bigint;
1933
+ readonly post?: bigint;
1934
+ };
1935
+ readonly token?: {
1936
+ readonly mint?: string;
1937
+ readonly owner?: string;
1938
+ readonly decimals?: number;
1939
+ readonly preAmount?: bigint;
1940
+ readonly postAmount?: bigint;
1941
+ };
1942
+ }[];
1943
+ };
1944
+ };
1945
+ }[keyof Programs[P]];
1946
+ }[keyof Programs]
1947
+ : never;
1948
+
1949
+ /** Configuration for a single SVM chain in the test indexer. */
1950
+ type SvmTestIndexerChainConfig<Config extends IndexerConfigTypes = GlobalConfig> = {
1698
1951
  /** The slot number to start processing from. Defaults to config startBlock or progressBlock+1. */
1699
1952
  startBlock?: number;
1700
- /** The slot number to stop processing at. */
1953
+ /** The slot number to stop processing at. Defaults to max simulate slot when simulate is provided. */
1701
1954
  endBlock?: number;
1955
+ /** Simulate items to process instead of fetching from real sources. */
1956
+ simulate?: SvmSimulateItem<Config>[];
1702
1957
  };
1703
1958
 
1704
1959
  /** Entity change value containing sets and/or deleted IDs. */
@@ -1806,7 +2061,7 @@ type FuelTestChains<Config extends IndexerConfigTypes = GlobalConfig> =
1806
2061
 
1807
2062
  type SvmTestChains<Config extends IndexerConfigTypes = GlobalConfig> =
1808
2063
  HasSvm<Config> extends true
1809
- ? { [K in SvmChainIds<Config>]?: SvmTestIndexerChainConfig }
2064
+ ? { [K in SvmChainIds<Config>]?: SvmTestIndexerChainConfig<Config> }
1810
2065
  : {};
1811
2066
 
1812
2067
  /** Process configuration for the test indexer, with chains keyed by chain ID. */
@@ -1958,18 +2213,6 @@ export type FuelChainId = IsEmptyObject<FuelChainsT> extends true ? NotConfigure
1958
2213
  /** Union of all configured SVM chain IDs. */
1959
2214
  export type SvmChainId = IsEmptyObject<SvmChainsT> extends true ? NotConfigured<"SvmChainId", "Configure SVM chains"> : SvmChainsT [keyof SvmChainsT ]["id"];
1960
2215
 
1961
- /** The SVM parent-transaction type generated from this project's
1962
- * `field_selection`: the union of every instruction's `transaction` shape,
1963
- * with unselected fields typed as `FieldNotSelected<...>`. Resolves to a
1964
- * `NotConfigured` hint until `envio codegen` augments {@link Global}. */
1965
- export type SvmTransaction = IsEmptyObject<SvmProgramsT> extends true
1966
- ? NotConfigured<"SvmTransaction", "Configure SVM programs">
1967
- : {
1968
- [P in keyof SvmProgramsT]: {
1969
- [I in keyof SvmProgramsT[P]]: SvmProgramsT[P][I]["transaction"];
1970
- }[keyof SvmProgramsT[P]];
1971
- }[keyof SvmProgramsT];
1972
-
1973
2216
  /** Lookup an EVM event type by contract and event name. Without generics,
1974
2217
  * resolves to the discriminated union of every EVM event in the project. */
1975
2218
  export type EvmEvent<