@gzeoneth/gov-tracker 0.2.1 → 0.3.0-beta.3e02aff

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 (377) hide show
  1. package/README.md +129 -72
  2. package/dist/abis.d.ts +3 -0
  3. package/dist/abis.d.ts.map +1 -1
  4. package/dist/abis.js +30 -2
  5. package/dist/abis.js.map +1 -1
  6. package/dist/calldata/index.d.ts +1 -1
  7. package/dist/calldata/index.d.ts.map +1 -1
  8. package/dist/calldata/index.js.map +1 -1
  9. package/dist/calldata/parameter-decoder.d.ts.map +1 -1
  10. package/dist/calldata/parameter-decoder.js +8 -1
  11. package/dist/calldata/parameter-decoder.js.map +1 -1
  12. package/dist/calldata/signature-lookup.d.ts +17 -2
  13. package/dist/calldata/signature-lookup.d.ts.map +1 -1
  14. package/dist/calldata/signature-lookup.js +20 -2
  15. package/dist/calldata/signature-lookup.js.map +1 -1
  16. package/dist/cli/cli.d.ts +21 -0
  17. package/dist/cli/cli.d.ts.map +1 -0
  18. package/dist/cli/{monitor.js → cli.js} +372 -73
  19. package/dist/cli/cli.js.map +1 -0
  20. package/dist/cli/lib/cli.d.ts +54 -3
  21. package/dist/cli/lib/cli.d.ts.map +1 -1
  22. package/dist/cli/lib/cli.js +387 -78
  23. package/dist/cli/lib/cli.js.map +1 -1
  24. package/dist/cli/lib/concurrency.d.ts +20 -0
  25. package/dist/cli/lib/concurrency.d.ts.map +1 -0
  26. package/dist/cli/lib/concurrency.js +32 -0
  27. package/dist/cli/lib/concurrency.js.map +1 -0
  28. package/dist/cli/lib/json-state.d.ts +23 -0
  29. package/dist/cli/lib/json-state.d.ts.map +1 -1
  30. package/dist/cli/lib/json-state.js +51 -4
  31. package/dist/cli/lib/json-state.js.map +1 -1
  32. package/dist/cli/tui/App.d.ts +11 -0
  33. package/dist/cli/tui/App.d.ts.map +1 -0
  34. package/dist/cli/tui/App.js +123 -0
  35. package/dist/cli/tui/App.js.map +1 -0
  36. package/dist/cli/tui/components/CopyableText.d.ts +23 -0
  37. package/dist/cli/tui/components/CopyableText.d.ts.map +1 -0
  38. package/dist/cli/tui/components/CopyableText.js +49 -0
  39. package/dist/cli/tui/components/CopyableText.js.map +1 -0
  40. package/dist/cli/tui/components/Header.d.ts +20 -0
  41. package/dist/cli/tui/components/Header.d.ts.map +1 -0
  42. package/dist/cli/tui/components/Header.js +47 -0
  43. package/dist/cli/tui/components/Header.js.map +1 -0
  44. package/dist/cli/tui/components/KeyHelp.d.ts +19 -0
  45. package/dist/cli/tui/components/KeyHelp.d.ts.map +1 -0
  46. package/dist/cli/tui/components/KeyHelp.js +60 -0
  47. package/dist/cli/tui/components/KeyHelp.js.map +1 -0
  48. package/dist/cli/tui/components/ProposalRow.d.ts +11 -0
  49. package/dist/cli/tui/components/ProposalRow.d.ts.map +1 -0
  50. package/dist/cli/tui/components/ProposalRow.js +92 -0
  51. package/dist/cli/tui/components/ProposalRow.js.map +1 -0
  52. package/dist/cli/tui/components/ScrollIndicator.d.ts +19 -0
  53. package/dist/cli/tui/components/ScrollIndicator.d.ts.map +1 -0
  54. package/dist/cli/tui/components/ScrollIndicator.js +50 -0
  55. package/dist/cli/tui/components/ScrollIndicator.js.map +1 -0
  56. package/dist/cli/tui/components/SearchBar.d.ts +12 -0
  57. package/dist/cli/tui/components/SearchBar.d.ts.map +1 -0
  58. package/dist/cli/tui/components/SearchBar.js +36 -0
  59. package/dist/cli/tui/components/SearchBar.js.map +1 -0
  60. package/dist/cli/tui/components/Spinner.d.ts +10 -0
  61. package/dist/cli/tui/components/Spinner.d.ts.map +1 -0
  62. package/dist/cli/tui/components/Spinner.js +24 -0
  63. package/dist/cli/tui/components/Spinner.js.map +1 -0
  64. package/dist/cli/tui/components/StageProgress.d.ts +12 -0
  65. package/dist/cli/tui/components/StageProgress.d.ts.map +1 -0
  66. package/dist/cli/tui/components/StageProgress.js +41 -0
  67. package/dist/cli/tui/components/StageProgress.js.map +1 -0
  68. package/dist/cli/tui/components/StageRow.d.ts +12 -0
  69. package/dist/cli/tui/components/StageRow.d.ts.map +1 -0
  70. package/dist/cli/tui/components/StageRow.js +80 -0
  71. package/dist/cli/tui/components/StageRow.js.map +1 -0
  72. package/dist/cli/tui/components/StatusBadge.d.ts +12 -0
  73. package/dist/cli/tui/components/StatusBadge.d.ts.map +1 -0
  74. package/dist/cli/tui/components/StatusBadge.js +27 -0
  75. package/dist/cli/tui/components/StatusBadge.js.map +1 -0
  76. package/dist/cli/tui/components/ViewLayout.d.ts +22 -0
  77. package/dist/cli/tui/components/ViewLayout.d.ts.map +1 -0
  78. package/dist/cli/tui/components/ViewLayout.js +24 -0
  79. package/dist/cli/tui/components/ViewLayout.js.map +1 -0
  80. package/dist/cli/tui/components/VotingStats.d.ts +11 -0
  81. package/dist/cli/tui/components/VotingStats.d.ts.map +1 -0
  82. package/dist/cli/tui/components/VotingStats.js +87 -0
  83. package/dist/cli/tui/components/VotingStats.js.map +1 -0
  84. package/dist/cli/tui/hooks/index.d.ts +11 -0
  85. package/dist/cli/tui/hooks/index.d.ts.map +1 -0
  86. package/dist/cli/tui/hooks/index.js +18 -0
  87. package/dist/cli/tui/hooks/index.js.map +1 -0
  88. package/dist/cli/tui/hooks/useCache.d.ts +12 -0
  89. package/dist/cli/tui/hooks/useCache.d.ts.map +1 -0
  90. package/dist/cli/tui/hooks/useCache.js +52 -0
  91. package/dist/cli/tui/hooks/useCache.js.map +1 -0
  92. package/dist/cli/tui/hooks/useElectionData.d.ts +22 -0
  93. package/dist/cli/tui/hooks/useElectionData.d.ts.map +1 -0
  94. package/dist/cli/tui/hooks/useElectionData.js +133 -0
  95. package/dist/cli/tui/hooks/useElectionData.js.map +1 -0
  96. package/dist/cli/tui/hooks/useNavigation.d.ts +39 -0
  97. package/dist/cli/tui/hooks/useNavigation.d.ts.map +1 -0
  98. package/dist/cli/tui/hooks/useNavigation.js +173 -0
  99. package/dist/cli/tui/hooks/useNavigation.js.map +1 -0
  100. package/dist/cli/tui/hooks/useProposals.d.ts +10 -0
  101. package/dist/cli/tui/hooks/useProposals.d.ts.map +1 -0
  102. package/dist/cli/tui/hooks/useProposals.js +201 -0
  103. package/dist/cli/tui/hooks/useProposals.js.map +1 -0
  104. package/dist/cli/tui/hooks/useScrollableInput.d.ts +14 -0
  105. package/dist/cli/tui/hooks/useScrollableInput.d.ts.map +1 -0
  106. package/dist/cli/tui/hooks/useScrollableInput.js +44 -0
  107. package/dist/cli/tui/hooks/useScrollableInput.js.map +1 -0
  108. package/dist/cli/tui/hooks/useStageCalldata.d.ts +17 -0
  109. package/dist/cli/tui/hooks/useStageCalldata.d.ts.map +1 -0
  110. package/dist/cli/tui/hooks/useStageCalldata.js +77 -0
  111. package/dist/cli/tui/hooks/useStageCalldata.js.map +1 -0
  112. package/dist/cli/tui/index.d.ts +13 -0
  113. package/dist/cli/tui/index.d.ts.map +1 -0
  114. package/dist/cli/tui/index.js +96 -0
  115. package/dist/cli/tui/index.js.map +1 -0
  116. package/dist/cli/tui/ink-wrapper.d.ts +43 -0
  117. package/dist/cli/tui/ink-wrapper.d.ts.map +1 -0
  118. package/dist/cli/tui/ink-wrapper.js +41 -0
  119. package/dist/cli/tui/ink-wrapper.js.map +1 -0
  120. package/dist/cli/tui/types.d.ts +38 -0
  121. package/dist/cli/tui/types.d.ts.map +1 -0
  122. package/dist/cli/tui/types.js +6 -0
  123. package/dist/cli/tui/types.js.map +1 -0
  124. package/dist/cli/tui/utils/calldata-formatter.d.ts +7 -0
  125. package/dist/cli/tui/utils/calldata-formatter.d.ts.map +1 -0
  126. package/dist/cli/tui/utils/calldata-formatter.js +14 -0
  127. package/dist/cli/tui/utils/calldata-formatter.js.map +1 -0
  128. package/dist/cli/tui/utils/clipboard.d.ts +7 -0
  129. package/dist/cli/tui/utils/clipboard.d.ts.map +1 -0
  130. package/dist/cli/tui/utils/clipboard.js +46 -0
  131. package/dist/cli/tui/utils/clipboard.js.map +1 -0
  132. package/dist/cli/tui/utils/index.d.ts +16 -0
  133. package/dist/cli/tui/utils/index.d.ts.map +1 -0
  134. package/dist/cli/tui/utils/index.js +52 -0
  135. package/dist/cli/tui/utils/index.js.map +1 -0
  136. package/dist/cli/tui/utils/markdown-parser.d.ts +11 -0
  137. package/dist/cli/tui/utils/markdown-parser.d.ts.map +1 -0
  138. package/dist/cli/tui/utils/markdown-parser.js +77 -0
  139. package/dist/cli/tui/utils/markdown-parser.js.map +1 -0
  140. package/dist/cli/tui/utils/navigation.d.ts +17 -0
  141. package/dist/cli/tui/utils/navigation.d.ts.map +1 -0
  142. package/dist/cli/tui/utils/navigation.js +75 -0
  143. package/dist/cli/tui/utils/navigation.js.map +1 -0
  144. package/dist/cli/tui/utils/proposal-detail-helpers.d.ts +9 -0
  145. package/dist/cli/tui/utils/proposal-detail-helpers.d.ts.map +1 -0
  146. package/dist/cli/tui/utils/proposal-detail-helpers.js +21 -0
  147. package/dist/cli/tui/utils/proposal-detail-helpers.js.map +1 -0
  148. package/dist/cli/tui/utils/shortcuts.d.ts +17 -0
  149. package/dist/cli/tui/utils/shortcuts.d.ts.map +1 -0
  150. package/dist/cli/tui/utils/shortcuts.js +100 -0
  151. package/dist/cli/tui/utils/shortcuts.js.map +1 -0
  152. package/dist/cli/tui/utils/stage-formatter.d.ts +7 -0
  153. package/dist/cli/tui/utils/stage-formatter.d.ts.map +1 -0
  154. package/dist/cli/tui/utils/stage-formatter.js +14 -0
  155. package/dist/cli/tui/utils/stage-formatter.js.map +1 -0
  156. package/dist/cli/tui/utils/stage-status.d.ts +10 -0
  157. package/dist/cli/tui/utils/stage-status.d.ts.map +1 -0
  158. package/dist/cli/tui/utils/stage-status.js +64 -0
  159. package/dist/cli/tui/utils/stage-status.js.map +1 -0
  160. package/dist/cli/tui/utils/terminal.d.ts +18 -0
  161. package/dist/cli/tui/utils/terminal.d.ts.map +1 -0
  162. package/dist/cli/tui/utils/terminal.js +26 -0
  163. package/dist/cli/tui/utils/terminal.js.map +1 -0
  164. package/dist/cli/tui/utils/text.d.ts +7 -0
  165. package/dist/cli/tui/utils/text.d.ts.map +1 -0
  166. package/dist/cli/tui/utils/text.js +12 -0
  167. package/dist/cli/tui/utils/text.js.map +1 -0
  168. package/dist/cli/tui/utils/time.d.ts +19 -0
  169. package/dist/cli/tui/utils/time.d.ts.map +1 -0
  170. package/dist/cli/tui/utils/time.js +43 -0
  171. package/dist/cli/tui/utils/time.js.map +1 -0
  172. package/dist/cli/tui/views/CalldataView.d.ts +12 -0
  173. package/dist/cli/tui/views/CalldataView.d.ts.map +1 -0
  174. package/dist/cli/tui/views/CalldataView.js +110 -0
  175. package/dist/cli/tui/views/CalldataView.js.map +1 -0
  176. package/dist/cli/tui/views/DescriptionView.d.ts +12 -0
  177. package/dist/cli/tui/views/DescriptionView.d.ts.map +1 -0
  178. package/dist/cli/tui/views/DescriptionView.js +75 -0
  179. package/dist/cli/tui/views/DescriptionView.js.map +1 -0
  180. package/dist/cli/tui/views/ElectionView.d.ts +11 -0
  181. package/dist/cli/tui/views/ElectionView.d.ts.map +1 -0
  182. package/dist/cli/tui/views/ElectionView.js +193 -0
  183. package/dist/cli/tui/views/ElectionView.js.map +1 -0
  184. package/dist/cli/tui/views/HelpView.d.ts +10 -0
  185. package/dist/cli/tui/views/HelpView.d.ts.map +1 -0
  186. package/dist/cli/tui/views/HelpView.js +75 -0
  187. package/dist/cli/tui/views/HelpView.js.map +1 -0
  188. package/dist/cli/tui/views/ProposalDetail.d.ts +12 -0
  189. package/dist/cli/tui/views/ProposalDetail.d.ts.map +1 -0
  190. package/dist/cli/tui/views/ProposalDetail.js +103 -0
  191. package/dist/cli/tui/views/ProposalDetail.js.map +1 -0
  192. package/dist/cli/tui/views/ProposalList.d.ts +15 -0
  193. package/dist/cli/tui/views/ProposalList.d.ts.map +1 -0
  194. package/dist/cli/tui/views/ProposalList.js +154 -0
  195. package/dist/cli/tui/views/ProposalList.js.map +1 -0
  196. package/dist/cli/tui/views/SimulationView.d.ts +12 -0
  197. package/dist/cli/tui/views/SimulationView.d.ts.map +1 -0
  198. package/dist/cli/tui/views/SimulationView.js +110 -0
  199. package/dist/cli/tui/views/SimulationView.js.map +1 -0
  200. package/dist/cli/tui/views/StageView.d.ts +12 -0
  201. package/dist/cli/tui/views/StageView.d.ts.map +1 -0
  202. package/dist/cli/tui/views/StageView.js +109 -0
  203. package/dist/cli/tui/views/StageView.js.map +1 -0
  204. package/dist/cli/tui/views/registry.d.ts +18 -0
  205. package/dist/cli/tui/views/registry.d.ts.map +1 -0
  206. package/dist/cli/tui/views/registry.js +34 -0
  207. package/dist/cli/tui/views/registry.js.map +1 -0
  208. package/dist/constants.d.ts +44 -0
  209. package/dist/constants.d.ts.map +1 -1
  210. package/dist/constants.js +52 -1
  211. package/dist/constants.js.map +1 -1
  212. package/dist/data/bundled-cache.json +16408 -2561
  213. package/dist/deduplication.d.ts +132 -0
  214. package/dist/deduplication.d.ts.map +1 -0
  215. package/dist/deduplication.js +270 -0
  216. package/dist/deduplication.js.map +1 -0
  217. package/dist/discovery/governor-discovery.d.ts.map +1 -1
  218. package/dist/discovery/governor-discovery.js +52 -36
  219. package/dist/discovery/governor-discovery.js.map +1 -1
  220. package/dist/discovery/timelock-discovery.d.ts +15 -6
  221. package/dist/discovery/timelock-discovery.d.ts.map +1 -1
  222. package/dist/discovery/timelock-discovery.js +27 -11
  223. package/dist/discovery/timelock-discovery.js.map +1 -1
  224. package/dist/election/contracts.d.ts +8 -0
  225. package/dist/election/contracts.d.ts.map +1 -0
  226. package/dist/election/contracts.js +28 -0
  227. package/dist/election/contracts.js.map +1 -0
  228. package/dist/election/details.d.ts +15 -0
  229. package/dist/election/details.d.ts.map +1 -0
  230. package/dist/election/details.js +157 -0
  231. package/dist/election/details.js.map +1 -0
  232. package/dist/election/index.d.ts +11 -0
  233. package/dist/election/index.d.ts.map +1 -0
  234. package/dist/election/index.js +48 -0
  235. package/dist/election/index.js.map +1 -0
  236. package/dist/election/params.d.ts +13 -0
  237. package/dist/election/params.d.ts.map +1 -0
  238. package/dist/election/params.js +93 -0
  239. package/dist/election/params.js.map +1 -0
  240. package/dist/election/participants.d.ts +6 -0
  241. package/dist/election/participants.d.ts.map +1 -0
  242. package/dist/election/participants.js +104 -0
  243. package/dist/election/participants.js.map +1 -0
  244. package/dist/election/prepare.d.ts +10 -0
  245. package/dist/election/prepare.d.ts.map +1 -0
  246. package/dist/election/prepare.js +52 -0
  247. package/dist/election/prepare.js.map +1 -0
  248. package/dist/election/proposal-ids.d.ts +18 -0
  249. package/dist/election/proposal-ids.d.ts.map +1 -0
  250. package/dist/election/proposal-ids.js +77 -0
  251. package/dist/election/proposal-ids.js.map +1 -0
  252. package/dist/election/status.d.ts +15 -0
  253. package/dist/election/status.d.ts.map +1 -0
  254. package/dist/election/status.js +105 -0
  255. package/dist/election/status.js.map +1 -0
  256. package/dist/election/tracking.d.ts +28 -0
  257. package/dist/election/tracking.d.ts.map +1 -0
  258. package/dist/election/tracking.js +412 -0
  259. package/dist/election/tracking.js.map +1 -0
  260. package/dist/index.d.ts +32 -8
  261. package/dist/index.d.ts.map +1 -1
  262. package/dist/index.js +101 -9
  263. package/dist/index.js.map +1 -1
  264. package/dist/stages/builder.d.ts +4 -0
  265. package/dist/stages/builder.d.ts.map +1 -1
  266. package/dist/stages/builder.js +7 -0
  267. package/dist/stages/builder.js.map +1 -1
  268. package/dist/stages/l2-to-l1-message.d.ts +8 -1
  269. package/dist/stages/l2-to-l1-message.d.ts.map +1 -1
  270. package/dist/stages/l2-to-l1-message.js +79 -13
  271. package/dist/stages/l2-to-l1-message.js.map +1 -1
  272. package/dist/stages/proposal-created.d.ts +1 -0
  273. package/dist/stages/proposal-created.d.ts.map +1 -1
  274. package/dist/stages/proposal-created.js +1 -0
  275. package/dist/stages/proposal-created.js.map +1 -1
  276. package/dist/stages/proposal-queued.d.ts +1 -0
  277. package/dist/stages/proposal-queued.d.ts.map +1 -1
  278. package/dist/stages/proposal-queued.js +3 -1
  279. package/dist/stages/proposal-queued.js.map +1 -1
  280. package/dist/stages/retryables.js +2 -2
  281. package/dist/stages/retryables.js.map +1 -1
  282. package/dist/stages/timelock.d.ts +3 -1
  283. package/dist/stages/timelock.d.ts.map +1 -1
  284. package/dist/stages/timelock.js +10 -4
  285. package/dist/stages/timelock.js.map +1 -1
  286. package/dist/stages/utils.d.ts +7 -8
  287. package/dist/stages/utils.d.ts.map +1 -1
  288. package/dist/stages/utils.js +40 -27
  289. package/dist/stages/utils.js.map +1 -1
  290. package/dist/stages/voting.d.ts.map +1 -1
  291. package/dist/stages/voting.js +5 -4
  292. package/dist/stages/voting.js.map +1 -1
  293. package/dist/tracker/cache.d.ts +10 -6
  294. package/dist/tracker/cache.d.ts.map +1 -1
  295. package/dist/tracker/cache.js +39 -15
  296. package/dist/tracker/cache.js.map +1 -1
  297. package/dist/tracker/checkpoint-helpers.d.ts +80 -0
  298. package/dist/tracker/checkpoint-helpers.d.ts.map +1 -0
  299. package/dist/tracker/checkpoint-helpers.js +200 -0
  300. package/dist/tracker/checkpoint-helpers.js.map +1 -0
  301. package/dist/tracker/discovery.d.ts +40 -9
  302. package/dist/tracker/discovery.d.ts.map +1 -1
  303. package/dist/tracker/discovery.js +152 -15
  304. package/dist/tracker/discovery.js.map +1 -1
  305. package/dist/tracker/pipeline.d.ts.map +1 -1
  306. package/dist/tracker/pipeline.js +26 -11
  307. package/dist/tracker/pipeline.js.map +1 -1
  308. package/dist/tracker/query.d.ts +1 -0
  309. package/dist/tracker/query.d.ts.map +1 -1
  310. package/dist/tracker/query.js +14 -61
  311. package/dist/tracker/query.js.map +1 -1
  312. package/dist/tracker/state.d.ts +0 -10
  313. package/dist/tracker/state.d.ts.map +1 -1
  314. package/dist/tracker/state.js +1 -28
  315. package/dist/tracker/state.js.map +1 -1
  316. package/dist/tracker.d.ts +100 -8
  317. package/dist/tracker.d.ts.map +1 -1
  318. package/dist/tracker.js +405 -42
  319. package/dist/tracker.js.map +1 -1
  320. package/dist/types/config.d.ts +49 -0
  321. package/dist/types/config.d.ts.map +1 -1
  322. package/dist/types/core.d.ts +4 -2
  323. package/dist/types/core.d.ts.map +1 -1
  324. package/dist/types/election.d.ts +144 -1
  325. package/dist/types/election.d.ts.map +1 -1
  326. package/dist/types/index.d.ts +5 -7
  327. package/dist/types/index.d.ts.map +1 -1
  328. package/dist/types/index.js +2 -3
  329. package/dist/types/index.js.map +1 -1
  330. package/dist/types/stages.d.ts +79 -1
  331. package/dist/types/stages.d.ts.map +1 -1
  332. package/dist/types/stages.js.map +1 -1
  333. package/dist/types/tracking.d.ts +34 -4
  334. package/dist/types/tracking.d.ts.map +1 -1
  335. package/dist/utils/block-cache.d.ts +50 -0
  336. package/dist/utils/block-cache.d.ts.map +1 -0
  337. package/dist/utils/block-cache.js +80 -0
  338. package/dist/utils/block-cache.js.map +1 -0
  339. package/dist/utils/formatters.d.ts +91 -0
  340. package/dist/utils/formatters.d.ts.map +1 -0
  341. package/dist/utils/formatters.js +327 -0
  342. package/dist/utils/formatters.js.map +1 -0
  343. package/dist/utils/multicall.d.ts +52 -0
  344. package/dist/utils/multicall.d.ts.map +1 -0
  345. package/dist/utils/multicall.js +75 -0
  346. package/dist/utils/multicall.js.map +1 -0
  347. package/dist/utils/rpc-utils.d.ts +7 -1
  348. package/dist/utils/rpc-utils.d.ts.map +1 -1
  349. package/dist/utils/rpc-utils.js +43 -29
  350. package/dist/utils/rpc-utils.js.map +1 -1
  351. package/dist/utils/salt-computation.d.ts.map +1 -1
  352. package/dist/utils/salt-computation.js +33 -7
  353. package/dist/utils/salt-computation.js.map +1 -1
  354. package/dist/utils/sanitize.d.ts +28 -0
  355. package/dist/utils/sanitize.d.ts.map +1 -0
  356. package/dist/utils/sanitize.js +55 -0
  357. package/dist/utils/sanitize.js.map +1 -0
  358. package/dist/utils/stage-metadata.d.ts +0 -20
  359. package/dist/utils/stage-metadata.d.ts.map +1 -1
  360. package/dist/utils/stage-metadata.js +29 -44
  361. package/dist/utils/stage-metadata.js.map +1 -1
  362. package/dist/utils/timing.d.ts +23 -3
  363. package/dist/utils/timing.d.ts.map +1 -1
  364. package/dist/utils/timing.js +71 -7
  365. package/dist/utils/timing.js.map +1 -1
  366. package/package.json +29 -16
  367. package/dist/cli/monitor.d.ts +0 -3
  368. package/dist/cli/monitor.d.ts.map +0 -1
  369. package/dist/cli/monitor.js.map +0 -1
  370. package/dist/election.d.ts +0 -172
  371. package/dist/election.d.ts.map +0 -1
  372. package/dist/election.js +0 -467
  373. package/dist/election.js.map +0 -1
  374. package/dist/types/cross-chain.d.ts +0 -24
  375. package/dist/types/cross-chain.d.ts.map +0 -1
  376. package/dist/types/cross-chain.js +0 -6
  377. package/dist/types/cross-chain.js.map +0 -1
package/dist/tracker.js CHANGED
@@ -19,12 +19,50 @@ exports.createTracker = createTracker;
19
19
  const ethers_1 = require("ethers");
20
20
  const logger_1 = require("./utils/logger");
21
21
  const rpc_utils_1 = require("./utils/rpc-utils");
22
+ const timing_1 = require("./utils/timing");
23
+ const checkpoint_helpers_1 = require("./tracker/checkpoint-helpers");
22
24
  const constants_1 = require("./constants");
23
25
  const election_1 = require("./election");
24
26
  const governor_discovery_1 = require("./discovery/governor-discovery");
25
27
  const timelock_discovery_1 = require("./discovery/timelock-discovery");
26
28
  const utils_1 = require("./stages/utils");
27
29
  const { tracker: logTracker, discovery: logDiscovery } = logger_1.loggers;
30
+ /**
31
+ * Build a TrackingContext with current block numbers and timestamp.
32
+ * Called once at the start of a tracking session for consistent state.
33
+ */
34
+ async function buildTrackingContext(options) {
35
+ const { l2Provider, l1Provider, novaProvider, chunkSize, skipCache } = options;
36
+ const l2BlockInfo = await (0, timing_1.getCurrentBlockInfo)(l2Provider);
37
+ const context = {
38
+ l2BlockNumber: l2BlockInfo.blockNumber,
39
+ timestamp: l2BlockInfo.timestamp,
40
+ chunkSize,
41
+ skipCache,
42
+ };
43
+ logTracker("buildTrackingContext: l2Block=%d timestamp=%d", context.l2BlockNumber, context.timestamp);
44
+ if (l1Provider) {
45
+ try {
46
+ const l1Block = await (0, timing_1.getL1BlockNumberFromL2)(l2Provider);
47
+ context.l1BlockNumber = l1Block.toNumber();
48
+ logTracker("buildTrackingContext: l1Block=%d", context.l1BlockNumber);
49
+ }
50
+ catch (err) {
51
+ logTracker("buildTrackingContext: failed to get L1 block: %s", err.message);
52
+ }
53
+ }
54
+ if (novaProvider) {
55
+ try {
56
+ const novaBlockInfo = await (0, timing_1.getCurrentBlockInfo)(novaProvider);
57
+ context.novaBlockNumber = novaBlockInfo.blockNumber;
58
+ logTracker("buildTrackingContext: novaBlock=%d", context.novaBlockNumber);
59
+ }
60
+ catch (err) {
61
+ logTracker("buildTrackingContext: failed to get Nova block: %s", err.message);
62
+ }
63
+ }
64
+ return context;
65
+ }
28
66
  // Import context and pipeline from tracker modules
29
67
  const state_1 = require("./tracker/state");
30
68
  const pipeline_1 = require("./tracker/pipeline");
@@ -118,6 +156,44 @@ class ProposalStageTracker {
118
156
  static async readCacheStatus(cachePath) {
119
157
  return (0, cache_1.readCacheStatus)(cachePath);
120
158
  }
159
+ /**
160
+ * Clear a specific cache entry. Used by --force to ensure fresh tracking.
161
+ */
162
+ async clearCacheEntry(key) {
163
+ if (this.cache) {
164
+ await this.cache.delete(key);
165
+ logTracker("cleared cache entry: %s", key);
166
+ }
167
+ }
168
+ /**
169
+ * Clear all cache entries for a transaction.
170
+ * This clears both the base tx key and any operation-specific keys (tx:{hash}:op:{opId}).
171
+ * Used by CLI --force to ensure fresh tracking of all operations in a tx.
172
+ */
173
+ async clearTxCacheEntries(txHash) {
174
+ if (!this.cache)
175
+ return 0;
176
+ const baseCacheKey = (0, checkpoint_helpers_1.txHashCacheKey)(txHash);
177
+ const prefix = `${baseCacheKey}:op:`;
178
+ let cleared = 0;
179
+ // Clear the base tx key
180
+ if (await this.cache.has(baseCacheKey)) {
181
+ await this.cache.delete(baseCacheKey);
182
+ logTracker("cleared cache entry: %s", baseCacheKey);
183
+ cleared++;
184
+ }
185
+ // Clear all operation-specific keys for this tx
186
+ const allKeys = await this.cache.keys(prefix);
187
+ const keys = Array.isArray(allKeys) ? allKeys : Array.from(allKeys);
188
+ for (const key of keys) {
189
+ if (key.startsWith(prefix)) {
190
+ await this.cache.delete(key);
191
+ logTracker("cleared cache entry: %s", key);
192
+ cleared++;
193
+ }
194
+ }
195
+ return cleared;
196
+ }
121
197
  // Watermark Management
122
198
  /**
123
199
  * Load discovery watermarks from cache.
@@ -131,9 +207,84 @@ class ProposalStageTracker {
131
207
  * Save discovery watermarks to cache.
132
208
  * Watermarks are stored as TrackingCheckpoint with proper metadata,
133
209
  * following the same pattern as proposal/timelock checkpoints.
210
+ *
211
+ * @param watermarks - Block numbers per discovery key
212
+ * @param hashes - Block hashes per discovery key (for reorg detection)
134
213
  */
135
- async saveWatermarks(watermarks) {
136
- return (0, discovery_1.saveWatermarks)(watermarks, this.cache);
214
+ async saveWatermarks(watermarks, hashes = {}) {
215
+ return (0, discovery_1.saveWatermarks)(watermarks, hashes, this.cache);
216
+ }
217
+ /**
218
+ * Save an election checkpoint to cache.
219
+ * Elections are stored with key format: `election:{electionIndex}`
220
+ *
221
+ * For COMPLETED elections, automatically fetches and caches nominee/member
222
+ * election details to enable zero-RPC reads for historical elections.
223
+ *
224
+ * @param electionStatus - Election status from trackElectionProposal
225
+ * @param options.nomineeDetails - Pre-fetched nominee details (skips RPC fetch)
226
+ * @param options.memberDetails - Pre-fetched member details (skips RPC fetch)
227
+ */
228
+ async saveElectionCheckpoint(electionStatus, options = {}) {
229
+ if (!this.cache)
230
+ return;
231
+ const key = `election:${electionStatus.electionIndex}`;
232
+ const now = Date.now();
233
+ let nomineeDetails = options.nomineeDetails;
234
+ let memberDetails = options.memberDetails;
235
+ // For COMPLETED elections, fetch details if not provided
236
+ if (electionStatus.phase === "COMPLETED" && !nomineeDetails && !memberDetails) {
237
+ try {
238
+ const [rawNomineeDetails, rawMemberDetails] = await Promise.all([
239
+ (0, election_1.getNomineeElectionDetails)(electionStatus.electionIndex, this.l2Provider),
240
+ (0, election_1.getMemberElectionDetails)(electionStatus.electionIndex, this.l2Provider),
241
+ ]);
242
+ if (rawNomineeDetails) {
243
+ nomineeDetails = (0, election_1.serializeNomineeDetails)(rawNomineeDetails);
244
+ }
245
+ if (rawMemberDetails) {
246
+ memberDetails = (0, election_1.serializeMemberDetails)(rawMemberDetails);
247
+ }
248
+ logTracker("fetched election %d details: nominees=%d, members=%d", electionStatus.electionIndex, nomineeDetails?.nominees?.length ?? 0, memberDetails?.nominees?.length ?? 0);
249
+ }
250
+ catch (err) {
251
+ logTracker("failed to fetch election %d details (non-fatal): %s", electionStatus.electionIndex, err.message);
252
+ }
253
+ }
254
+ await this.cache.set(key, {
255
+ version: 1,
256
+ createdAt: now,
257
+ input: { type: "election", electionIndex: electionStatus.electionIndex },
258
+ lastProcessedStage: null,
259
+ lastProcessedBlock: { l1: 0, l2: 0 },
260
+ cachedData: { electionStatus, nomineeDetails, memberDetails },
261
+ metadata: { errorCount: 0, lastTrackedAt: now },
262
+ });
263
+ logTracker("saved election checkpoint: %s (phase: %s)", key, electionStatus.phase);
264
+ }
265
+ /**
266
+ * Get an election checkpoint from cache.
267
+ *
268
+ * For COMPLETED elections, includes cached nominee/member details:
269
+ * - nomineeDetails: Contenders, nominees, excluded nominees, quorum threshold
270
+ * - memberDetails: Final nominee rankings, winners, voting deadlines
271
+ *
272
+ * @param electionIndex - Election index
273
+ * @returns Election data or null if not cached
274
+ */
275
+ async getElectionCheckpoint(electionIndex) {
276
+ if (!this.cache)
277
+ return null;
278
+ const key = `election:${electionIndex}`;
279
+ const checkpoint = await this.cache.get(key);
280
+ if (!checkpoint?.cachedData?.electionStatus) {
281
+ return null;
282
+ }
283
+ return {
284
+ status: checkpoint.cachedData.electionStatus,
285
+ nomineeDetails: checkpoint.cachedData.nomineeDetails ?? null,
286
+ memberDetails: checkpoint.cachedData.memberDetails ?? null,
287
+ };
137
288
  }
138
289
  // Discovery API
139
290
  /**
@@ -162,9 +313,10 @@ class ProposalStageTracker {
162
313
  * Discover all proposals and timelock operations with auto-watermark management.
163
314
  *
164
315
  * This is the unified discovery API that handles everything internally:
316
+ * - Verifies watermark hashes to detect chain reorgs (rolls back if mismatch)
165
317
  * - Loads watermarks from cache (or uses provided fromWatermarks)
166
318
  * - Discovers from all enabled targets in parallel
167
- * - Auto-saves updated watermarks to cache
319
+ * - Auto-saves updated watermarks and hashes to cache
168
320
  *
169
321
  * @param targets - Which governors/timelocks to scan
170
322
  * @param toBlock - End block for discovery
@@ -172,11 +324,13 @@ class ProposalStageTracker {
172
324
  * @returns Discovered proposals, timelock ops, and updated watermarks
173
325
  */
174
326
  async discoverAll(targets, toBlock, fromWatermarks) {
175
- // Load watermarks from cache (or use provided override)
176
- const watermarks = fromWatermarks ?? (await this.loadWatermarks());
177
- const result = await (0, discovery_2.discoverAll)(targets, toBlock, this.l2Provider, this.cache, watermarks, { chunkSize: this.chunkingConfig.l2ChunkSize });
178
- // Auto-save updated watermarks
179
- await this.saveWatermarks(result.watermarks);
327
+ // Load watermarks and hashes from cache (or use provided override)
328
+ const loaded = await this.loadWatermarks();
329
+ const watermarks = fromWatermarks ?? loaded.watermarks;
330
+ const hashes = fromWatermarks ? {} : loaded.hashes; // Only use cached hashes if using cached watermarks
331
+ const result = await (0, discovery_2.discoverAll)(targets, toBlock, this.l2Provider, this.cache, watermarks, hashes, { chunkSize: this.chunkingConfig.l2ChunkSize });
332
+ // Auto-save updated watermarks and hashes
333
+ await this.saveWatermarks(result.watermarks, result.hashes);
180
334
  return result;
181
335
  }
182
336
  // Checkpoint Query API
@@ -229,42 +383,58 @@ class ProposalStageTracker {
229
383
  * - Automatically loads existing checkpoint from cache (zero-RPC resume)
230
384
  * - Automatically saves checkpoint to cache after tracking
231
385
  *
386
+ * @param txHash - Transaction hash to track
387
+ * @param operationId - Optional: track only this specific timelock operation
388
+ *
232
389
  * @example
233
390
  * ```typescript
391
+ * // Track all operations in a transaction
234
392
  * const results = await tracker.trackByTxHash("0x...");
235
- * for (const result of results) {
236
- * console.log(`Found ${result.stages.length} stages`);
237
- * }
393
+ *
394
+ * // Track a specific operation
395
+ * const results = await tracker.trackByTxHash("0x...", "0xoperationId...");
238
396
  * ```
239
397
  */
240
- async trackByTxHash(txHash) {
241
- logTracker("trackByTxHash %s", txHash);
242
- // Cache key for this transaction
243
- const cacheKey = (0, cache_1.txHashCacheKey)(txHash);
398
+ async trackByTxHash(txHash, operationId) {
399
+ logTracker("trackByTxHash %s%s", txHash, operationId ? ` operationId=${operationId}` : "");
400
+ // Determine cache key based on whether operationId is provided
401
+ // - Governor proposals and timelock discovery: tx:{txHash}
402
+ // - Specific timelock operation: tx:{txHash}:op:{operationId}
403
+ const baseCacheKey = (0, checkpoint_helpers_1.txHashCacheKey)(txHash);
244
404
  // Load checkpoint from cache for resume
245
405
  let checkpoint;
246
406
  if (this.cache) {
247
- checkpoint = (await this.cache.get(cacheKey)) ?? undefined;
248
- if (checkpoint) {
249
- logTracker("loaded checkpoint from cache: %s", cacheKey);
407
+ // If operationId provided, try operation-specific key first
408
+ if (operationId) {
409
+ const opCacheKey = (0, checkpoint_helpers_1.timelockOpCacheKey)(txHash, operationId);
410
+ checkpoint = (await this.cache.get(opCacheKey)) ?? undefined;
411
+ if (checkpoint) {
412
+ logTracker("loaded checkpoint from cache: %s", opCacheKey);
413
+ }
414
+ }
415
+ // Fall back to base cache key (for governor proposals or legacy checkpoints)
416
+ if (!checkpoint) {
417
+ checkpoint = (await this.cache.get(baseCacheKey)) ?? undefined;
418
+ if (checkpoint) {
419
+ logTracker("loaded checkpoint from cache: %s", baseCacheKey);
420
+ }
250
421
  }
251
422
  }
252
423
  try {
253
- return await this.trackByTxHashInternal(txHash, cacheKey, checkpoint);
424
+ return await this.trackByTxHashInternal(txHash, baseCacheKey, checkpoint, operationId);
254
425
  }
255
426
  catch (error) {
256
427
  // Save checkpoint on error with incremented error count
257
428
  // Gas estimation errors don't count against consecutive errors
258
429
  if (this.cache) {
259
- const input = {
260
- type: "governor",
261
- governorAddress: "",
262
- proposalId: "",
263
- creationTxHash: txHash,
264
- };
265
430
  const prevErrorCount = checkpoint?.metadata?.errorCount ?? 0;
431
+ const newErrorCount = (0, checkpoint_helpers_1.incrementErrorCount)(prevErrorCount, error);
266
432
  const isGasError = (0, rpc_utils_1.isGasEstimationError)(error);
267
- const newErrorCount = isGasError ? prevErrorCount : prevErrorCount + 1;
433
+ // Use operation-specific key for timelock errors if operationId is known
434
+ const errorCacheKey = operationId ? (0, checkpoint_helpers_1.timelockOpCacheKey)(txHash, operationId) : baseCacheKey;
435
+ const input = operationId
436
+ ? { type: "timelock", timelockAddress: "", operationId, scheduledTxHash: txHash }
437
+ : { type: "governor", governorAddress: "", proposalId: "", creationTxHash: txHash };
268
438
  const errorCheckpoint = checkpoint ?? {
269
439
  version: 1,
270
440
  createdAt: Date.now(),
@@ -273,9 +443,9 @@ class ProposalStageTracker {
273
443
  lastProcessedBlock: { l1: 0, l2: 0 },
274
444
  cachedData: {},
275
445
  };
276
- errorCheckpoint.metadata = { errorCount: newErrorCount, lastTrackedAt: Date.now() };
277
- await this.cache.set(cacheKey, errorCheckpoint);
278
- logTracker("saved checkpoint on error: %s (errorCount=%d%s)", cacheKey, newErrorCount, isGasError ? " - gas error, not incrementing" : "");
446
+ errorCheckpoint.metadata = (0, checkpoint_helpers_1.createCheckpointMetadata)(newErrorCount);
447
+ await this.cache.set(errorCacheKey, errorCheckpoint);
448
+ logTracker("saved checkpoint on error: %s (errorCount=%d%s)", errorCacheKey, newErrorCount, isGasError ? " - gas error, not incrementing" : "");
279
449
  }
280
450
  throw error;
281
451
  }
@@ -285,29 +455,32 @@ class ProposalStageTracker {
285
455
  *
286
456
  * Uses PipelineContext for stateful tracking - no parameter passing between stages.
287
457
  */
288
- async trackByTxHashInternal(txHash, cacheKey, checkpoint) {
458
+ async trackByTxHashInternal(txHash, baseCacheKey, checkpoint, operationId) {
289
459
  // RESUME PATH: If we have a checkpoint, check what type it is
290
460
  if (checkpoint && checkpoint.input.type !== "discovery") {
291
461
  logTracker("RESUME: found checkpoint for tx, type=%s", checkpoint.input.type);
292
462
  if (checkpoint.input.type === "governor") {
293
463
  const input = checkpoint.input;
294
- const result = await this.trackGovernorWithPipeline(input.governorAddress, input.proposalId, input.creationTxHash, checkpoint, cacheKey);
464
+ const result = await this.trackGovernorWithPipeline(input.governorAddress, input.proposalId, input.creationTxHash, checkpoint, baseCacheKey);
295
465
  return [result];
296
466
  }
297
467
  else if (checkpoint.input.type === "timelock") {
298
468
  const input = checkpoint.input;
299
- const result = await this.trackTimelockWithPipeline(input.timelockAddress, input.operationId, input.scheduledTxHash, checkpoint, cacheKey);
469
+ const opCacheKey = (0, checkpoint_helpers_1.timelockOpCacheKey)(txHash, input.operationId);
470
+ const result = await this.trackTimelockWithPipeline(input.timelockAddress, input.operationId, input.scheduledTxHash, checkpoint, opCacheKey);
300
471
  return [result];
301
472
  }
302
473
  }
303
- // Try as proposal first
304
- const proposal = await (0, governor_discovery_1.discoverProposalByTxHash)(txHash, this.l2Provider);
305
- if (proposal) {
306
- logDiscovery("found proposal in tx, proposalId=%s", proposal.proposalId);
307
- const result = await this.trackGovernorWithPipeline(proposal.governorAddress, proposal.proposalId, proposal.creationTxHash, checkpoint, cacheKey);
308
- return [result];
474
+ // Try as proposal first (only if no operationId specified)
475
+ if (!operationId) {
476
+ const proposal = await (0, governor_discovery_1.discoverProposalByTxHash)(txHash, this.l2Provider);
477
+ if (proposal) {
478
+ logDiscovery("found proposal in tx, proposalId=%s", proposal.proposalId);
479
+ const result = await this.trackGovernorWithPipeline(proposal.governorAddress, proposal.proposalId, proposal.creationTxHash, checkpoint, baseCacheKey);
480
+ return [result];
481
+ }
309
482
  }
310
- // Try as timelock operations (may be batch with multiple ops)
483
+ // Try as timelock operations
311
484
  const callScheduledEvents = await (0, timelock_discovery_1.findCallScheduledByTxHash)(txHash, this.l2Provider);
312
485
  if (callScheduledEvents && callScheduledEvents.length > 0) {
313
486
  logDiscovery("found %d timelock operation(s) in tx", callScheduledEvents.length);
@@ -315,11 +488,28 @@ class ProposalStageTracker {
315
488
  const seenOperationIds = new Set();
316
489
  const results = [];
317
490
  for (const event of callScheduledEvents) {
491
+ // Skip if we've already seen this operationId (batch deduplication)
318
492
  if (seenOperationIds.has(event.operationId))
319
493
  continue;
320
494
  seenOperationIds.add(event.operationId);
321
- const result = await this.trackTimelockWithPipeline(event.timelockAddress, event.operationId, txHash, checkpoint, cacheKey, event);
495
+ // If specific operationId requested, skip non-matching operations
496
+ if (operationId && event.operationId.toLowerCase() !== operationId.toLowerCase())
497
+ continue;
498
+ // Use operation-specific cache key for each timelock operation
499
+ const opCacheKey = (0, checkpoint_helpers_1.timelockOpCacheKey)(txHash, event.operationId);
500
+ // Load operation-specific checkpoint if not already loaded
501
+ let opCheckpoint = checkpoint;
502
+ if (this.cache && !opCheckpoint) {
503
+ opCheckpoint = (await this.cache.get(opCacheKey)) ?? undefined;
504
+ if (opCheckpoint) {
505
+ logTracker("loaded operation checkpoint from cache: %s", opCacheKey);
506
+ }
507
+ }
508
+ const result = await this.trackTimelockWithPipeline(event.timelockAddress, event.operationId, txHash, opCheckpoint, opCacheKey, event);
322
509
  results.push(result);
510
+ // If specific operationId requested and found, we're done
511
+ if (operationId)
512
+ break;
323
513
  }
324
514
  return results;
325
515
  }
@@ -353,7 +543,23 @@ class ProposalStageTracker {
353
543
  const finalState = await (0, pipeline_1.trackGovernorPipeline)(initialState);
354
544
  // Build result from state
355
545
  const result = this.buildResultFromState(finalState);
356
- // Save checkpoint to cache
546
+ // Track election status if this is an election governor proposal
547
+ if (result.isElection) {
548
+ const electionStatus = await this.trackElectionStatus(proposalId);
549
+ if (electionStatus) {
550
+ result.electionStatus = electionStatus;
551
+ await this.saveElectionCheckpoint(electionStatus);
552
+ // Elections are fully tracked via election checkpoints, remove tx:* checkpoint
553
+ if (this.cache && cacheKey) {
554
+ await this.cache.delete(cacheKey);
555
+ logTracker("election tracked via election checkpoint, removed tx:* checkpoint: %s", cacheKey);
556
+ }
557
+ return result;
558
+ }
559
+ // If election tracking failed, fall through to save tx:* checkpoint for retry
560
+ logTracker("election tracking failed, saving tx:* checkpoint for retry");
561
+ }
562
+ // Save checkpoint to cache (non-elections and failed election tracking)
357
563
  if (this.cache && cacheKey) {
358
564
  result.checkpoint.metadata = { errorCount: 0, lastTrackedAt: Date.now() };
359
565
  await this.cache.set(cacheKey, result.checkpoint);
@@ -517,6 +723,154 @@ class ProposalStageTracker {
517
723
  nova: this.novaProvider,
518
724
  };
519
725
  }
726
+ // Election Tracking
727
+ /**
728
+ * Track election status for a given proposal ID.
729
+ *
730
+ * Searches through elections to find the one containing this proposal,
731
+ * then tracks the full election lifecycle.
732
+ */
733
+ async trackElectionStatus(proposalId) {
734
+ logTracker("trackElectionStatus for proposal %s", proposalId);
735
+ try {
736
+ // Get current L2 block for block-scoped caching
737
+ const { blockNumber: l2BlockNumber } = await (0, timing_1.getCurrentBlockInfo)(this.l2Provider);
738
+ const electionIndex = await (0, election_1.getElectionIndexForProposalId)(proposalId, this.l2Provider, this.l1Provider, { novaProvider: this.novaProvider, blockNumber: l2BlockNumber });
739
+ if (electionIndex === null) {
740
+ logTracker("no election found for proposal %s", proposalId);
741
+ return null;
742
+ }
743
+ logTracker("found election index %d for proposal %s", electionIndex, proposalId);
744
+ return (0, election_1.trackElectionProposal)(electionIndex, this.l2Provider, this.l1Provider, {
745
+ novaProvider: this.novaProvider,
746
+ });
747
+ }
748
+ catch (error) {
749
+ // Election tracking is non-critical - log and return null
750
+ // The proposal stages are already tracked successfully
751
+ logTracker("election tracking failed for proposal %s: %O", proposalId, error);
752
+ return null;
753
+ }
754
+ }
755
+ /**
756
+ * Track an election by its index.
757
+ *
758
+ * This method provides direct election tracking when you have the election index.
759
+ * For tracking via tx hash, use trackByTxHash() which auto-detects elections.
760
+ *
761
+ * Caching behavior:
762
+ * - COMPLETED elections: Returns cached data immediately (0 RPC calls)
763
+ * - Incomplete elections: Makes fresh RPC calls and updates cache
764
+ * - No cache: Always makes fresh RPC calls
765
+ *
766
+ * @param electionIndex - Election index (0-based)
767
+ * @param options.force - Force fresh tracking even for completed elections
768
+ * @returns Election status
769
+ */
770
+ async trackElection(electionIndex, options = {}) {
771
+ logTracker("trackElection for index %d (force=%s)", electionIndex, options.force ?? false);
772
+ // Check cache first for completed elections (skip RPC calls)
773
+ if (this.cache && !options.force) {
774
+ const cached = await this.getElectionCheckpoint(electionIndex);
775
+ if (cached && cached.status.phase === "COMPLETED") {
776
+ logTracker("returning cached COMPLETED election %d (0 RPC calls)", electionIndex);
777
+ return cached.status;
778
+ }
779
+ }
780
+ // Build full tracking context for consistent state across all calls
781
+ const context = await buildTrackingContext({
782
+ l2Provider: this.l2Provider,
783
+ l1Provider: this.l1Provider,
784
+ novaProvider: this.novaProvider,
785
+ skipCache: options.force,
786
+ });
787
+ // Track fresh for incomplete elections or cache miss
788
+ const status = await (0, election_1.trackElectionProposal)(electionIndex, this.l2Provider, this.l1Provider, {
789
+ novaProvider: this.novaProvider,
790
+ l2BlockNumber: context.l2BlockNumber,
791
+ timestamp: context.timestamp,
792
+ skipCache: context.skipCache,
793
+ });
794
+ if (this.cache) {
795
+ await this.saveElectionCheckpoint(status);
796
+ }
797
+ return status;
798
+ }
799
+ /**
800
+ * Track all elections with caching.
801
+ *
802
+ * Caching behavior:
803
+ * - COMPLETED elections: Returns cached data immediately (0 RPC calls)
804
+ * - Incomplete elections: Makes fresh RPC calls and updates cache
805
+ *
806
+ * @param options.includeNext - Include the "next" election slot (default: true)
807
+ * @param options.force - Force fresh tracking for all elections
808
+ * @returns Array of election statuses
809
+ */
810
+ async trackAllElections(options = {}) {
811
+ logTracker("trackAllElections (includeNext=%s, force=%s)", options.includeNext ?? true, options.force ?? false);
812
+ // Build context once at the start for consistent state across all elections
813
+ const context = await buildTrackingContext({
814
+ l2Provider: this.l2Provider,
815
+ l1Provider: this.l1Provider,
816
+ novaProvider: this.novaProvider,
817
+ skipCache: options.force,
818
+ });
819
+ const status = await (0, election_1.checkElectionStatus)(this.l2Provider, this.l1Provider);
820
+ const electionCount = status.electionCount;
821
+ const results = [];
822
+ // Track existing elections (indices 0 to electionCount-1)
823
+ for (let i = 0; i < electionCount; i++) {
824
+ try {
825
+ // Check cache first for completed elections (skip RPC calls)
826
+ if (this.cache && !options.force) {
827
+ const cached = await this.getElectionCheckpoint(i);
828
+ if (cached && cached.status.phase === "COMPLETED") {
829
+ logTracker("returning cached COMPLETED election %d (0 RPC calls)", i);
830
+ results.push(cached.status);
831
+ continue;
832
+ }
833
+ }
834
+ // Track with shared context
835
+ const electionStatus = await (0, election_1.trackElectionProposal)(i, this.l2Provider, this.l1Provider, {
836
+ novaProvider: this.novaProvider,
837
+ l2BlockNumber: context.l2BlockNumber,
838
+ timestamp: context.timestamp,
839
+ skipCache: context.skipCache,
840
+ });
841
+ results.push(electionStatus);
842
+ if (this.cache) {
843
+ await this.saveElectionCheckpoint(electionStatus);
844
+ }
845
+ }
846
+ catch (err) {
847
+ logTracker("Failed to track election %d: %s", i, err);
848
+ }
849
+ }
850
+ // Optionally track the next election (not yet created) for createElection preparation
851
+ if (options.includeNext ?? true) {
852
+ try {
853
+ // Next election always needs fresh RPC calls since it doesn't exist yet
854
+ const nextElectionStatus = await (0, election_1.trackElectionProposal)(electionCount, this.l2Provider, this.l1Provider, {
855
+ novaProvider: this.novaProvider,
856
+ l2BlockNumber: context.l2BlockNumber,
857
+ timestamp: context.timestamp,
858
+ });
859
+ results.push({
860
+ ...nextElectionStatus,
861
+ canCreateElection: status.canCreateElection,
862
+ secondsUntilElection: status.secondsUntilElection,
863
+ timeUntilElection: status.timeUntilElection,
864
+ });
865
+ // Don't cache the "next" election since it doesn't exist yet
866
+ }
867
+ catch (err) {
868
+ logTracker("Failed to track next election %d: %s", electionCount, err);
869
+ }
870
+ }
871
+ logTracker("Tracked %d elections", results.length);
872
+ return results;
873
+ }
520
874
  // Election Support
521
875
  /**
522
876
  * Check Security Council election status and prepare available actions
@@ -532,6 +886,7 @@ class ProposalStageTracker {
532
886
  status,
533
887
  canCreate: status.canCreateElection,
534
888
  canTriggerMember: false,
889
+ canExecuteMember: false,
535
890
  prepared: {},
536
891
  };
537
892
  if (status.canCreateElection) {
@@ -540,15 +895,23 @@ class ProposalStageTracker {
540
895
  }
541
896
  if (status.electionCount > 0) {
542
897
  const currentElectionIndex = status.electionCount - 1;
543
- const electionStatus = await (0, election_1.trackElectionProposal)(currentElectionIndex, this.l2Provider, this.l1Provider);
898
+ // Use cached tracking for the current election
899
+ const electionStatus = await this.trackElection(currentElectionIndex);
544
900
  result.currentElection = electionStatus;
545
901
  result.canTriggerMember = electionStatus.canProceedToMemberPhase;
902
+ result.canExecuteMember = electionStatus.canExecuteMember;
546
903
  if (electionStatus.canProceedToMemberPhase) {
547
904
  const memberTx = await (0, election_1.prepareMemberElectionTrigger)(electionStatus, this.l2Provider);
548
905
  if (memberTx) {
549
906
  result.prepared.triggerMember = memberTx;
550
907
  }
551
908
  }
909
+ if (electionStatus.canExecuteMember) {
910
+ const executeTx = await (0, election_1.prepareMemberElectionExecution)(electionStatus, this.l2Provider);
911
+ if (executeTx) {
912
+ result.prepared.executeMember = executeTx;
913
+ }
914
+ }
552
915
  }
553
916
  return result;
554
917
  }