envio 3.7.0 → 3.8.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/index.d.ts +331 -142
- package/package.json +6 -6
- package/src/ChainState.res +9 -1
- package/src/ChainState.res.mjs +6 -1
- package/src/Config.res +19 -10
- package/src/Config.res.mjs +17 -7
- package/src/Envio.res +54 -76
- package/src/EventConfigBuilder.res +159 -30
- package/src/EventConfigBuilder.res.mjs +120 -24
- package/src/HandlerRegister.res +20 -11
- package/src/HandlerRegister.res.mjs +22 -5
- package/src/Hasura.res +30 -22
- package/src/Hasura.res.mjs +11 -5
- package/src/InMemoryStore.res +1 -6
- package/src/InMemoryStore.res.mjs +1 -3
- package/src/Internal.res +33 -13
- package/src/Internal.res.mjs +12 -16
- package/src/Main.res +2 -5
- package/src/MemoryStorage.res +40 -8
- package/src/MemoryStorage.res.mjs +38 -16
- package/src/Persistence.res +4 -2
- package/src/PgStorage.res +6 -1
- package/src/PgStorage.res.mjs +1 -1
- package/src/SimulateItems.res +261 -9
- package/src/SimulateItems.res.mjs +218 -47
- package/src/TestIndexer.res +26 -10
- package/src/TestIndexer.res.mjs +34 -12
- package/src/bindings/ClickHouse.res +33 -6
- package/src/bindings/ClickHouse.res.mjs +25 -4
- package/src/db/InternalTable.res +11 -0
- package/src/db/InternalTable.res.mjs +7 -0
- package/src/sources/EvmHyperSyncSource.res +3 -2
- package/src/sources/SimulateSource.res +8 -4
- package/src/sources/SimulateSource.res.mjs +7 -3
- package/src/sources/Svm.res +34 -7
- package/src/sources/Svm.res.mjs +32 -4
- package/src/sources/SvmHyperSyncClient.res +10 -12
- package/src/sources/SvmHyperSyncClient.res.mjs +3 -2
- package/src/sources/SvmHyperSyncSource.res +91 -34
- package/src/sources/SvmHyperSyncSource.res.mjs +77 -37
- package/src/sources/TransactionStore.res +38 -0
- package/src/sources/TransactionStore.res.mjs +5 -0
- package/svm.schema.json +27 -78
package/src/db/InternalTable.res
CHANGED
|
@@ -17,6 +17,7 @@ module Chains = {
|
|
|
17
17
|
type field = [
|
|
18
18
|
| progressFields
|
|
19
19
|
| #id
|
|
20
|
+
| #ecosystem
|
|
20
21
|
| #start_block
|
|
21
22
|
| #end_block
|
|
22
23
|
| #max_reorg_depth
|
|
@@ -29,6 +30,7 @@ module Chains = {
|
|
|
29
30
|
|
|
30
31
|
let fields: array<field> = [
|
|
31
32
|
#id,
|
|
33
|
+
#ecosystem,
|
|
32
34
|
#start_block,
|
|
33
35
|
#end_block,
|
|
34
36
|
#max_reorg_depth,
|
|
@@ -57,6 +59,7 @@ module Chains = {
|
|
|
57
59
|
|
|
58
60
|
type t = {
|
|
59
61
|
@as("id") id: ChainId.t,
|
|
62
|
+
@as("ecosystem") ecosystem: string,
|
|
60
63
|
@as("start_block") startBlock: int,
|
|
61
64
|
@as("end_block") endBlock: Null.t<int>,
|
|
62
65
|
@as("max_reorg_depth") maxReorgDepth: int,
|
|
@@ -70,6 +73,10 @@ module Chains = {
|
|
|
70
73
|
"envio_chains",
|
|
71
74
|
~fields=[
|
|
72
75
|
mkField((#id: field :> string), ChainId, ~fieldSchema=ChainId.schema, ~isPrimaryKey),
|
|
76
|
+
// Which ecosystem the chain belongs to (evm / fuel / svm). Chain ids are
|
|
77
|
+
// only unique within an ecosystem (HOS-1880: Svm ids are Envio-assigned),
|
|
78
|
+
// so consumers should treat (ecosystem, id) as the chain's identity.
|
|
79
|
+
mkField((#ecosystem: field :> string), String, ~fieldSchema=S.string),
|
|
73
80
|
// Values populated from config
|
|
74
81
|
mkField((#start_block: field :> string), Int32, ~fieldSchema=S.int),
|
|
75
82
|
mkField((#end_block: field :> string), Int32, ~fieldSchema=S.null(S.int), ~isNullable),
|
|
@@ -104,6 +111,7 @@ module Chains = {
|
|
|
104
111
|
let initialFromConfig = (chainConfig: Config.chain) => {
|
|
105
112
|
{
|
|
106
113
|
id: chainConfig.id,
|
|
114
|
+
ecosystem: (chainConfig.ecosystem: Ecosystem.name :> string),
|
|
107
115
|
startBlock: chainConfig.startBlock,
|
|
108
116
|
endBlock: chainConfig.endBlock->Null.fromOption,
|
|
109
117
|
maxReorgDepth: chainConfig.maxReorgDepth,
|
|
@@ -131,6 +139,7 @@ module Chains = {
|
|
|
131
139
|
let value = initialValues->(Utils.magic: t => dict<unknown>)->Dict.get((field :> string))
|
|
132
140
|
switch typeof(value) {
|
|
133
141
|
| #object => "NULL"
|
|
142
|
+
| #string => `'${value->(Utils.magic: option<unknown> => string)}'`
|
|
134
143
|
| #number => value->(Utils.magic: option<unknown> => int)->Int.toString
|
|
135
144
|
| #bigint => value->(Utils.magic: option<unknown> => bigint)->BigInt.toString
|
|
136
145
|
| #boolean => value->(Utils.magic: option<unknown> => bool) ? "true" : "false"
|
|
@@ -648,6 +657,7 @@ module Views = {
|
|
|
648
657
|
`CREATE VIEW "${pgSchema}"."${metaViewName}" AS
|
|
649
658
|
SELECT
|
|
650
659
|
"${(#id: Chains.field :> string)}" AS "chainId",
|
|
660
|
+
"${(#ecosystem: Chains.field :> string)}" AS "ecosystem",
|
|
651
661
|
"${(#start_block: Chains.field :> string)}" AS "startBlock",
|
|
652
662
|
"${(#end_block: Chains.field :> string)}" AS "endBlock",
|
|
653
663
|
"${(#progress_block: Chains.field :> string)}" AS "progressBlock",
|
|
@@ -666,6 +676,7 @@ ORDER BY "${(#id: Chains.field :> string)}";`
|
|
|
666
676
|
SELECT
|
|
667
677
|
"${(#source_block: Chains.field :> string)}" AS "block_height",
|
|
668
678
|
"${(#id: Chains.field :> string)}" AS "chain_id",
|
|
679
|
+
"${(#ecosystem: Chains.field :> string)}" AS "ecosystem",
|
|
669
680
|
"${(#end_block: Chains.field :> string)}" AS "end_block",
|
|
670
681
|
"${(#first_event_block: Chains.field :> string)}" AS "first_event_block_number",
|
|
671
682
|
"${(#_is_hyper_sync: Chains.field :> string)}" AS "is_hyper_sync",
|
|
@@ -13,6 +13,7 @@ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_excep
|
|
|
13
13
|
|
|
14
14
|
let fields = [
|
|
15
15
|
"id",
|
|
16
|
+
"ecosystem",
|
|
16
17
|
"start_block",
|
|
17
18
|
"end_block",
|
|
18
19
|
"max_reorg_depth",
|
|
@@ -27,6 +28,7 @@ let fields = [
|
|
|
27
28
|
|
|
28
29
|
let table = Table.mkTable("envio_chains", undefined, [
|
|
29
30
|
Table.mkField("id", "ChainId", ChainId.schema, undefined, undefined, undefined, true, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
31
|
+
Table.mkField("ecosystem", "String", S$RescriptSchema.string, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
30
32
|
Table.mkField("start_block", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
31
33
|
Table.mkField("end_block", "Int32", S$RescriptSchema.$$null(S$RescriptSchema.int), undefined, undefined, true, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
32
34
|
Table.mkField("max_reorg_depth", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
@@ -42,6 +44,7 @@ let table = Table.mkTable("envio_chains", undefined, [
|
|
|
42
44
|
function initialFromConfig(chainConfig) {
|
|
43
45
|
return {
|
|
44
46
|
id: chainConfig.id,
|
|
47
|
+
ecosystem: chainConfig.ecosystem,
|
|
45
48
|
start_block: chainConfig.startBlock,
|
|
46
49
|
end_block: Stdlib_Null.fromOption(chainConfig.endBlock),
|
|
47
50
|
max_reorg_depth: chainConfig.maxReorgDepth,
|
|
@@ -73,6 +76,8 @@ function makeInitialValuesQuery(pgSchema, chainConfigs) {
|
|
|
73
76
|
} else {
|
|
74
77
|
return "false";
|
|
75
78
|
}
|
|
79
|
+
} else if (match === "string") {
|
|
80
|
+
return `'` + value + `'`;
|
|
76
81
|
} else if (match === "object") {
|
|
77
82
|
return "NULL";
|
|
78
83
|
} else {
|
|
@@ -440,6 +445,7 @@ function makeMetaViewQuery(pgSchema) {
|
|
|
440
445
|
return `CREATE VIEW "` + pgSchema + `"."` + metaViewName + `" AS
|
|
441
446
|
SELECT
|
|
442
447
|
"` + "id" + `" AS "chainId",
|
|
448
|
+
"` + "ecosystem" + `" AS "ecosystem",
|
|
443
449
|
"` + "start_block" + `" AS "startBlock",
|
|
444
450
|
"` + "end_block" + `" AS "endBlock",
|
|
445
451
|
"` + "progress_block" + `" AS "progressBlock",
|
|
@@ -458,6 +464,7 @@ function makeChainMetadataViewQuery(pgSchema) {
|
|
|
458
464
|
SELECT
|
|
459
465
|
"` + "source_block" + `" AS "block_height",
|
|
460
466
|
"` + "id" + `" AS "chain_id",
|
|
467
|
+
"` + "ecosystem" + `" AS "ecosystem",
|
|
461
468
|
"` + "end_block" + `" AS "end_block",
|
|
462
469
|
"` + "first_event_block" + `" AS "first_event_block_number",
|
|
463
470
|
"` + "_is_hyper_sync" + `" AS "is_hyper_sync",
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
open Source
|
|
2
2
|
|
|
3
|
-
// Surfaced by
|
|
4
|
-
// token. The corrupted-token test feeds the real server error
|
|
3
|
+
// Surfaced by the HyperSync client (Rust) when HyperSync rejects the API
|
|
4
|
+
// token. The corrupted-token test feeds the real server error (from the query
|
|
5
|
+
// endpoint; the edge no longer 401s malformed tokens on /height) through this
|
|
5
6
|
// check so it can't silently drift away from what getHeightOrThrow guards on.
|
|
6
7
|
let isUnauthorizedError = (message: string) => message->String.includes("401 Unauthorized")
|
|
7
8
|
|
|
@@ -4,6 +4,8 @@ let make = (
|
|
|
4
4
|
~chainId: ChainId.t,
|
|
5
5
|
~addressStore: AddressStore.t,
|
|
6
6
|
~ecosystem: Ecosystem.name=Evm,
|
|
7
|
+
~transactionStore: option<TransactionStore.t>=None,
|
|
8
|
+
~blockStore: option<BlockStore.t>=None,
|
|
7
9
|
): Source.t => {
|
|
8
10
|
let reportedHeight = max(endBlock, 1)
|
|
9
11
|
|
|
@@ -106,10 +108,12 @@ let make = (
|
|
|
106
108
|
Promise.resolve({
|
|
107
109
|
Source.knownHeight: reportedHeight,
|
|
108
110
|
parsedQueueItems,
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
transactionStore
|
|
112
|
-
blockStore:
|
|
111
|
+
// EVM/Fuel keep transaction and block inline. SVM simulate returns a
|
|
112
|
+
// store page so materialize + activity attach run the same path as HyperSync.
|
|
113
|
+
transactionStore,
|
|
114
|
+
blockStore: blockStore->Option.getOr(
|
|
115
|
+
BlockStore.fromJs([], ~ecosystem, ~shouldChecksum=false),
|
|
116
|
+
),
|
|
113
117
|
fromBlockQueried: fromBlock,
|
|
114
118
|
latestFetchedBlockNumber: toBlockQueried,
|
|
115
119
|
stats: {
|
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
import * as BlockStore from "./BlockStore.res.mjs";
|
|
4
4
|
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
5
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
6
|
+
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
5
7
|
|
|
6
|
-
function make(items, endBlock, chainId, addressStore, ecosystemOpt) {
|
|
8
|
+
function make(items, endBlock, chainId, addressStore, ecosystemOpt, transactionStoreOpt, blockStoreOpt) {
|
|
7
9
|
let ecosystem = ecosystemOpt !== undefined ? ecosystemOpt : "evm";
|
|
10
|
+
let transactionStore = transactionStoreOpt !== undefined ? Primitive_option.valFromOption(transactionStoreOpt) : undefined;
|
|
11
|
+
let blockStore = blockStoreOpt !== undefined ? Primitive_option.valFromOption(blockStoreOpt) : undefined;
|
|
8
12
|
let reportedHeight = Primitive_int.max(endBlock, 1);
|
|
9
13
|
return {
|
|
10
14
|
name: "SimulateSource",
|
|
@@ -75,8 +79,8 @@ function make(items, endBlock, chainId, addressStore, ecosystemOpt) {
|
|
|
75
79
|
return Promise.resolve({
|
|
76
80
|
knownHeight: reportedHeight,
|
|
77
81
|
parsedQueueItems: parsedQueueItems,
|
|
78
|
-
transactionStore:
|
|
79
|
-
blockStore: BlockStore.fromJs([], ecosystem, false),
|
|
82
|
+
transactionStore: transactionStore,
|
|
83
|
+
blockStore: Stdlib_Option.getOr(blockStore, BlockStore.fromJs([], ecosystem, false)),
|
|
80
84
|
fromBlockQueried: fromBlock,
|
|
81
85
|
latestFetchedBlockNumber: toBlockQueried,
|
|
82
86
|
stats: {
|
package/src/sources/Svm.res
CHANGED
|
@@ -14,13 +14,38 @@ let eventTransactionFieldMask = TransactionStore.makeMaskFn(transactionFields)
|
|
|
14
14
|
// Rust store (`SvmBlockField`) — keep this order in sync.
|
|
15
15
|
let blockFields = ["slot", "time", "hash", "height", "parentSlot", "parentHash"]
|
|
16
16
|
|
|
17
|
-
// `slot
|
|
18
|
-
// via `
|
|
17
|
+
// `slot` is always included (the item's key); every other block field is
|
|
18
|
+
// opt-in via handler `fields.block`. All are materialised from the store.
|
|
19
19
|
//
|
|
20
20
|
// One instruction's selected block fields → store selection bitmask. Computed per
|
|
21
21
|
// event at config build and cached on the event config.
|
|
22
22
|
let eventBlockFieldMask = BlockStore.makeMaskFn(blockFields)
|
|
23
23
|
|
|
24
|
+
let attachAccountActivities = (payload: Internal.eventPayload, tx: Internal.eventTransaction) => {
|
|
25
|
+
let instruction = payload->(Utils.magic: Internal.eventPayload => dict<unknown>)
|
|
26
|
+
let transaction = tx->(Utils.magic: Internal.eventTransaction => dict<unknown>)
|
|
27
|
+
switch (instruction->Dict.get("accounts"), transaction->Dict.get("accountActivities")) {
|
|
28
|
+
| (Some(accounts), Some(activities)) if !(accounts->Array.isArray) =>
|
|
29
|
+
let byAddress = Dict.make()
|
|
30
|
+
(activities->(Utils.magic: unknown => array<Envio.svmAccountActivity>))->Array.forEach(
|
|
31
|
+
activity => byAddress->Dict.set(activity.address->SvmTypes.Pubkey.toString, activity),
|
|
32
|
+
)
|
|
33
|
+
(accounts->(Utils.magic: unknown => dict<Envio.svmInstructionAccount>))
|
|
34
|
+
->Dict.valuesToArray
|
|
35
|
+
->Array.forEach(account =>
|
|
36
|
+
switch byAddress->Dict.get(account.address->SvmTypes.Pubkey.toString) {
|
|
37
|
+
| Some(activity) =>
|
|
38
|
+
(account->(Utils.magic: Envio.svmInstructionAccount => dict<unknown>))->Dict.set(
|
|
39
|
+
"activity",
|
|
40
|
+
activity->(Utils.magic: Envio.svmAccountActivity => unknown),
|
|
41
|
+
)
|
|
42
|
+
| None => ()
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
| _ => ()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
24
49
|
let make = (~logger: Pino.t): Ecosystem.t => {
|
|
25
50
|
name: Svm,
|
|
26
51
|
blockNumberName: "height",
|
|
@@ -36,16 +61,18 @@ let make = (~logger: Pino.t): Ecosystem.t => {
|
|
|
36
61
|
logger,
|
|
37
62
|
toEvent: eventItem => eventItem.payload->(Utils.magic: Internal.eventPayload => Internal.event),
|
|
38
63
|
toEventLogger: eventItem => {
|
|
39
|
-
let
|
|
40
|
-
eventItem.
|
|
64
|
+
let eventConfig =
|
|
65
|
+
eventItem.onEventRegistration.eventConfig->(
|
|
66
|
+
Utils.magic: Internal.eventConfig => Internal.svmInstructionEventConfig
|
|
67
|
+
)
|
|
41
68
|
Logging.createChildFrom(
|
|
42
69
|
~logger,
|
|
43
70
|
~params={
|
|
44
|
-
"program":
|
|
45
|
-
"instruction":
|
|
71
|
+
"program": eventConfig.contractName,
|
|
72
|
+
"instruction": eventConfig.name,
|
|
46
73
|
"chainId": eventItem.chainId,
|
|
47
74
|
"slot": eventItem.blockNumber,
|
|
48
|
-
"programId":
|
|
75
|
+
"programId": eventConfig.programId,
|
|
49
76
|
},
|
|
50
77
|
)
|
|
51
78
|
},
|
package/src/sources/Svm.res.mjs
CHANGED
|
@@ -9,6 +9,7 @@ import * as Internal from "../Internal.res.mjs";
|
|
|
9
9
|
import * as BlockStore from "./BlockStore.res.mjs";
|
|
10
10
|
import * as Performance from "../bindings/Performance.res.mjs";
|
|
11
11
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
12
|
+
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
12
13
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
13
14
|
import * as TransactionStore from "./TransactionStore.res.mjs";
|
|
14
15
|
|
|
@@ -25,6 +26,32 @@ let blockFields = [
|
|
|
25
26
|
|
|
26
27
|
let eventBlockFieldMask = BlockStore.makeMaskFn(blockFields);
|
|
27
28
|
|
|
29
|
+
function attachAccountActivities(payload, tx) {
|
|
30
|
+
let match = payload["accounts"];
|
|
31
|
+
let match$1 = tx["accountActivities"];
|
|
32
|
+
if (match === undefined) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (match$1 === undefined) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
let accounts = Primitive_option.valFromOption(match);
|
|
39
|
+
if (Array.isArray(accounts)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
let byAddress = {};
|
|
43
|
+
Primitive_option.valFromOption(match$1).forEach(activity => {
|
|
44
|
+
byAddress[activity.address] = activity;
|
|
45
|
+
});
|
|
46
|
+
Object.values(accounts).forEach(account => {
|
|
47
|
+
let activity = byAddress[account.address];
|
|
48
|
+
if (activity !== undefined) {
|
|
49
|
+
account["activity"] = activity;
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
28
55
|
function make(logger) {
|
|
29
56
|
return {
|
|
30
57
|
name: "svm",
|
|
@@ -37,13 +64,13 @@ function make(logger) {
|
|
|
37
64
|
logger: logger,
|
|
38
65
|
toEvent: eventItem => eventItem.payload,
|
|
39
66
|
toEventLogger: eventItem => {
|
|
40
|
-
let
|
|
67
|
+
let eventConfig = eventItem.onEventRegistration.eventConfig;
|
|
41
68
|
return Logging.createChildFrom(logger, {
|
|
42
|
-
program:
|
|
43
|
-
instruction:
|
|
69
|
+
program: eventConfig.contractName,
|
|
70
|
+
instruction: eventConfig.name,
|
|
44
71
|
chainId: eventItem.chainId,
|
|
45
72
|
slot: eventItem.blockNumber,
|
|
46
|
-
programId:
|
|
73
|
+
programId: eventConfig.programId
|
|
47
74
|
});
|
|
48
75
|
},
|
|
49
76
|
toRawEvent: param => Stdlib_JsError.throwWithMessage("Raw events are not supported for SVM")
|
|
@@ -96,6 +123,7 @@ export {
|
|
|
96
123
|
eventTransactionFieldMask,
|
|
97
124
|
blockFields,
|
|
98
125
|
eventBlockFieldMask,
|
|
126
|
+
attachAccountActivities,
|
|
99
127
|
make,
|
|
100
128
|
GetFinalizedSlot,
|
|
101
129
|
makeRPCSource,
|
|
@@ -27,14 +27,15 @@ module Registration = {
|
|
|
27
27
|
// Earliest slot this registration accepts; `None` is unrestricted.
|
|
28
28
|
startBlock: option<int>,
|
|
29
29
|
discriminator?: string,
|
|
30
|
-
discriminatorByteLen: int,
|
|
31
30
|
isInner?: bool,
|
|
32
|
-
includeLogs: bool,
|
|
33
31
|
// DNF: outer array is OR of AND-groups.
|
|
34
32
|
accountFilters: array<array<accountFilter>>,
|
|
35
33
|
// camelCase Internal.svmTransactionField / svmBlockField names.
|
|
36
34
|
transactionFields: array<string>,
|
|
37
35
|
blockFields: array<string>,
|
|
36
|
+
accountActivityFields: array<string>,
|
|
37
|
+
logFields: array<string>,
|
|
38
|
+
instructionFields: array<string>,
|
|
38
39
|
// Borsh schema pieces; empty accounts + absent argsJson = no schema.
|
|
39
40
|
accounts: array<string>,
|
|
40
41
|
argsJson?: string,
|
|
@@ -55,9 +56,7 @@ module Registration = {
|
|
|
55
56
|
isWildcard: reg.isWildcard,
|
|
56
57
|
startBlock: reg.startBlock,
|
|
57
58
|
discriminator: ?eventConfig.discriminator,
|
|
58
|
-
discriminatorByteLen: eventConfig.discriminatorByteLen,
|
|
59
59
|
isInner: ?eventConfig.isInner,
|
|
60
|
-
includeLogs: eventConfig.includeLogs,
|
|
61
60
|
accountFilters: eventConfig.accountFilters->Array.map(group =>
|
|
62
61
|
group->Array.map(
|
|
63
62
|
(filter): accountFilter => {
|
|
@@ -68,6 +67,9 @@ module Registration = {
|
|
|
68
67
|
),
|
|
69
68
|
transactionFields: reg.fieldSelection.transactionFields->Utils.Set.toArray,
|
|
70
69
|
blockFields: reg.fieldSelection.blockFields->Utils.Set.toArray,
|
|
70
|
+
accountActivityFields: reg.fieldSelection.accountActivityFields->Utils.Set.toArray,
|
|
71
|
+
logFields: reg.fieldSelection.logFields->Utils.Set.toArray,
|
|
72
|
+
instructionFields: reg.fieldSelection.instructionFields->Utils.Set.toArray,
|
|
71
73
|
accounts: eventConfig.accounts,
|
|
72
74
|
argsJson: ?switch eventConfig.args {
|
|
73
75
|
| JSON.Null => None
|
|
@@ -205,8 +207,8 @@ module EventItems = {
|
|
|
205
207
|
}
|
|
206
208
|
|
|
207
209
|
type log = {
|
|
208
|
-
kind
|
|
209
|
-
message
|
|
210
|
+
kind?: string,
|
|
211
|
+
message?: string,
|
|
210
212
|
}
|
|
211
213
|
|
|
212
214
|
// One routed instruction; `block` and `transaction` are materialised from
|
|
@@ -215,17 +217,13 @@ module EventItems = {
|
|
|
215
217
|
onEventRegistrationIndex: int,
|
|
216
218
|
slot: int,
|
|
217
219
|
transactionIndex: int,
|
|
218
|
-
|
|
220
|
+
path: array<int>,
|
|
219
221
|
programId: string,
|
|
220
222
|
accounts: array<string>,
|
|
221
223
|
data: string,
|
|
222
|
-
d1?: string,
|
|
223
|
-
d2?: string,
|
|
224
|
-
d4?: string,
|
|
225
|
-
d8?: string,
|
|
226
224
|
isInner: bool,
|
|
227
225
|
decoded?: ResponseTypes.decodedInstruction,
|
|
228
|
-
// Present only when the routed registration
|
|
226
|
+
// Present only when the routed registration selected `fields.log`.
|
|
229
227
|
logs?: array<log>,
|
|
230
228
|
}
|
|
231
229
|
|
|
@@ -20,15 +20,16 @@ function fromOnEventRegistrations(onEventRegistrations) {
|
|
|
20
20
|
isWildcard: reg.isWildcard,
|
|
21
21
|
startBlock: reg.startBlock,
|
|
22
22
|
discriminator: eventConfig.discriminator,
|
|
23
|
-
discriminatorByteLen: eventConfig.discriminatorByteLen,
|
|
24
23
|
isInner: eventConfig.isInner,
|
|
25
|
-
includeLogs: eventConfig.includeLogs,
|
|
26
24
|
accountFilters: eventConfig.accountFilters.map(group => group.map(filter => ({
|
|
27
25
|
position: filter.position,
|
|
28
26
|
values: filter.values
|
|
29
27
|
}))),
|
|
30
28
|
transactionFields: Array.from(reg.fieldSelection.transactionFields),
|
|
31
29
|
blockFields: Array.from(reg.fieldSelection.blockFields),
|
|
30
|
+
accountActivityFields: Array.from(reg.fieldSelection.accountActivityFields),
|
|
31
|
+
logFields: Array.from(reg.fieldSelection.logFields),
|
|
32
|
+
instructionFields: Array.from(reg.fieldSelection.instructionFields),
|
|
32
33
|
accounts: eventConfig.accounts,
|
|
33
34
|
argsJson: tmp,
|
|
34
35
|
definedTypesJson: tmp$1
|
|
@@ -10,50 +10,105 @@ type options = {
|
|
|
10
10
|
addressStore: AddressStore.t,
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
let parseDecoded = (
|
|
16
|
-
d: SvmHyperSyncClient.ResponseTypes.decodedInstruction,
|
|
17
|
-
): Envio.svmInstructionParams => {
|
|
18
|
-
let args = try JSON.parseOrThrow(d.argsJson) catch {
|
|
13
|
+
let parseArgs = (d: SvmHyperSyncClient.ResponseTypes.decodedInstruction): JSON.t =>
|
|
14
|
+
try JSON.parseOrThrow(d.argsJson) catch {
|
|
19
15
|
| _ => JSON.Object(Dict.make())
|
|
20
16
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
|
|
18
|
+
let namedAccounts = (
|
|
19
|
+
~idlNames: array<string>,
|
|
20
|
+
~accountArguments: array<string>,
|
|
21
|
+
): dict<Envio.svmInstructionAccount> => {
|
|
22
|
+
let out = Dict.make()
|
|
23
|
+
idlNames->Array.forEachWithIndex((name, i) =>
|
|
24
|
+
switch accountArguments->Array.get(i) {
|
|
25
|
+
| Some(address) =>
|
|
26
|
+
out->Dict.set(
|
|
27
|
+
name,
|
|
28
|
+
{
|
|
29
|
+
Envio.address: address->SvmTypes.Pubkey.fromStringUnsafe,
|
|
30
|
+
accountName: name,
|
|
31
|
+
instructionAccountIndex: i,
|
|
32
|
+
},
|
|
33
|
+
)
|
|
34
|
+
| None => ()
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
out
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let selectedLog = (log: SvmHyperSyncClient.EventItems.log, ~logFields: Utils.Set.t<string>): Envio.svmLog => {
|
|
41
|
+
let out = Dict.make()
|
|
42
|
+
if logFields->Utils.Set.has("kind") {
|
|
43
|
+
switch log.kind {
|
|
44
|
+
| Some(kind) => out->Dict.set("kind", kind)
|
|
45
|
+
| None => ()
|
|
46
|
+
}
|
|
25
47
|
}
|
|
26
|
-
{
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
48
|
+
if logFields->Utils.Set.has("message") {
|
|
49
|
+
switch log.message {
|
|
50
|
+
| Some(message) => out->Dict.set("message", message)
|
|
51
|
+
| None => ()
|
|
52
|
+
}
|
|
31
53
|
}
|
|
54
|
+
out->(Utils.magic: dict<string> => Envio.svmLog)
|
|
32
55
|
}
|
|
33
56
|
|
|
34
|
-
|
|
57
|
+
let setField = (out: dict<unknown>, name: string, value: 'a) =>
|
|
58
|
+
out->Dict.set(name, value->(Utils.magic: 'a => unknown))
|
|
59
|
+
|
|
60
|
+
// `block` and `transaction` are omitted; they're materialised from the stores
|
|
61
|
+
// at batch prep. Named-account `.activity` is attached then too.
|
|
62
|
+
// Unselected instruction keys must be omitted, not assigned `undefined`.
|
|
35
63
|
let toSvmInstruction = (
|
|
36
64
|
item: SvmHyperSyncClient.EventItems.item,
|
|
37
65
|
~programName,
|
|
38
66
|
~instructionName,
|
|
67
|
+
~eventConfig: Internal.svmInstructionEventConfig,
|
|
68
|
+
~fieldSelection: Internal.fieldSelection,
|
|
39
69
|
): Envio.svmInstruction => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
70
|
+
let hasSelection = name => fieldSelection.instructionFields->Utils.Set.has(name)
|
|
71
|
+
let discriminator = switch eventConfig.discriminator {
|
|
72
|
+
| Some(d) => d
|
|
73
|
+
| None => item.data
|
|
74
|
+
}
|
|
75
|
+
let out = Dict.make()
|
|
76
|
+
out->setField("programName", programName)
|
|
77
|
+
out->setField("instructionName", instructionName)
|
|
78
|
+
out->setField("discriminator", discriminator)
|
|
79
|
+
if hasSelection("programId") {
|
|
80
|
+
out->setField("programId", item.programId->SvmTypes.Pubkey.fromStringUnsafe)
|
|
81
|
+
}
|
|
82
|
+
if hasSelection("data") {
|
|
83
|
+
out->setField("data", item.data)
|
|
84
|
+
}
|
|
85
|
+
if hasSelection("path") {
|
|
86
|
+
out->setField("path", item.path)
|
|
87
|
+
}
|
|
88
|
+
if hasSelection("isInner") {
|
|
89
|
+
out->setField("isInner", item.isInner)
|
|
90
|
+
}
|
|
91
|
+
if hasSelection("args") {
|
|
92
|
+
out->setField("args", item.decoded->Option.map(parseArgs))
|
|
93
|
+
}
|
|
94
|
+
if hasSelection("accounts") {
|
|
95
|
+
out->setField(
|
|
96
|
+
"accounts",
|
|
97
|
+
namedAccounts(~idlNames=eventConfig.accounts, ~accountArguments=item.accounts),
|
|
55
98
|
)
|
|
56
|
-
|
|
99
|
+
}
|
|
100
|
+
if hasSelection("accountArguments") {
|
|
101
|
+
out->setField("accountArguments", item.accounts->SvmTypes.Pubkey.fromStringsUnsafe)
|
|
102
|
+
}
|
|
103
|
+
if fieldSelection.logFields->Utils.Set.size > 0 {
|
|
104
|
+
out->setField(
|
|
105
|
+
"logs",
|
|
106
|
+
item.logs
|
|
107
|
+
->Option.getOr([])
|
|
108
|
+
->Array.map(log => selectedLog(log, ~logFields=fieldSelection.logFields)),
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
out->(Utils.magic: dict<unknown> => Envio.svmInstruction)
|
|
57
112
|
}
|
|
58
113
|
|
|
59
114
|
let make = (
|
|
@@ -144,18 +199,20 @@ let make = (
|
|
|
144
199
|
item,
|
|
145
200
|
~programName=eventConfig.contractName,
|
|
146
201
|
~instructionName=eventConfig.name,
|
|
202
|
+
~eventConfig,
|
|
203
|
+
~fieldSelection=onEventRegistration.fieldSelection,
|
|
147
204
|
)
|
|
148
205
|
Internal.Event({
|
|
149
206
|
onEventRegistration,
|
|
150
207
|
chainId,
|
|
151
208
|
blockNumber: item.slot,
|
|
152
|
-
// A slot orders by `(transactionIndex,
|
|
209
|
+
// A slot orders by `(transactionIndex, path)` — the
|
|
153
210
|
// transaction, then the instruction's position in its CPI tree. Both
|
|
154
211
|
// ride the item so the buffer comparator can order on the pair
|
|
155
212
|
// directly; no single integer can hold it (Solana allows a CPI depth
|
|
156
213
|
// of 5, which needs more bits than a JS integer is exact to).
|
|
157
214
|
logIndex: item.transactionIndex,
|
|
158
|
-
orderPath: item.
|
|
215
|
+
orderPath: item.path,
|
|
159
216
|
// The parent transaction is materialised from the store at batch prep.
|
|
160
217
|
transactionIndex: item.transactionIndex,
|
|
161
218
|
payload: payload->(Utils.magic: Envio.svmInstruction => Internal.eventPayload),
|