@across-protocol/sdk 4.3.111-alpha.3 → 4.3.111

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 (566) hide show
  1. package/dist/cjs/addressAggregator/adapters/abstract.js +64 -50
  2. package/dist/cjs/addressAggregator/adapters/abstract.js.map +1 -1
  3. package/dist/cjs/addressAggregator/adapters/bybit.js +29 -16
  4. package/dist/cjs/addressAggregator/adapters/bybit.js.map +1 -1
  5. package/dist/cjs/addressAggregator/adapters/env.js +15 -11
  6. package/dist/cjs/addressAggregator/adapters/env.js.map +1 -1
  7. package/dist/cjs/addressAggregator/adapters/file.js +45 -32
  8. package/dist/cjs/addressAggregator/adapters/file.js.map +1 -1
  9. package/dist/cjs/addressAggregator/adapters/index.js +1 -1
  10. package/dist/cjs/addressAggregator/adapters/risklabs.js +36 -22
  11. package/dist/cjs/addressAggregator/adapters/risklabs.js.map +1 -1
  12. package/dist/cjs/addressAggregator/index.js +87 -57
  13. package/dist/cjs/addressAggregator/index.js.map +1 -1
  14. package/dist/cjs/apiClient/abstractClient.js +8 -9
  15. package/dist/cjs/apiClient/abstractClient.js.map +1 -1
  16. package/dist/cjs/apiClient/index.js +1 -1
  17. package/dist/cjs/apiClient/mockedClient.js +29 -23
  18. package/dist/cjs/apiClient/mockedClient.js.map +1 -1
  19. package/dist/cjs/apiClient/productionClient.js +103 -65
  20. package/dist/cjs/apiClient/productionClient.js.map +1 -1
  21. package/dist/cjs/arch/evm/BlockUtils.js +208 -122
  22. package/dist/cjs/arch/evm/BlockUtils.js.map +1 -1
  23. package/dist/cjs/arch/evm/MessageUtils.js +1 -1
  24. package/dist/cjs/arch/evm/MessageUtils.js.map +1 -1
  25. package/dist/cjs/arch/evm/SpokeUtils.js +288 -134
  26. package/dist/cjs/arch/evm/SpokeUtils.js.map +1 -1
  27. package/dist/cjs/arch/evm/index.js +1 -1
  28. package/dist/cjs/arch/evm/utils/index.js +1 -1
  29. package/dist/cjs/arch/evm/utils/wait.js +49 -38
  30. package/dist/cjs/arch/evm/utils/wait.js.map +1 -1
  31. package/dist/cjs/arch/index.js +1 -1
  32. package/dist/cjs/arch/svm/BlockUtils.js +158 -102
  33. package/dist/cjs/arch/svm/BlockUtils.js.map +1 -1
  34. package/dist/cjs/arch/svm/MessageUtils.js +2 -2
  35. package/dist/cjs/arch/svm/MessageUtils.js.map +1 -1
  36. package/dist/cjs/arch/svm/SpokeUtils.js +1147 -708
  37. package/dist/cjs/arch/svm/SpokeUtils.js.map +1 -1
  38. package/dist/cjs/arch/svm/encoders.js +1 -1
  39. package/dist/cjs/arch/svm/encoders.js.map +1 -1
  40. package/dist/cjs/arch/svm/eventsClient.js +236 -174
  41. package/dist/cjs/arch/svm/eventsClient.js.map +1 -1
  42. package/dist/cjs/arch/svm/index.js +1 -1
  43. package/dist/cjs/arch/svm/provider.js +3 -3
  44. package/dist/cjs/arch/svm/provider.js.map +1 -1
  45. package/dist/cjs/arch/svm/utils.js +355 -166
  46. package/dist/cjs/arch/svm/utils.js.map +1 -1
  47. package/dist/cjs/caching/Arweave/ArweaveClient.js +246 -168
  48. package/dist/cjs/caching/Arweave/ArweaveClient.js.map +1 -1
  49. package/dist/cjs/caching/Arweave/index.js +1 -1
  50. package/dist/cjs/caching/IPFS/PinataIPFSClient.js +49 -40
  51. package/dist/cjs/caching/IPFS/PinataIPFSClient.js.map +1 -1
  52. package/dist/cjs/caching/IPFS/index.js +1 -1
  53. package/dist/cjs/caching/Memory/MemoryCacheClient.js +18 -13
  54. package/dist/cjs/caching/Memory/MemoryCacheClient.js.map +1 -1
  55. package/dist/cjs/caching/Memory/index.js +1 -1
  56. package/dist/cjs/caching/index.js +1 -1
  57. package/dist/cjs/clients/AcrossConfigStoreClient/AcrossConfigStoreClient.js +381 -302
  58. package/dist/cjs/clients/AcrossConfigStoreClient/AcrossConfigStoreClient.js.map +1 -1
  59. package/dist/cjs/clients/AcrossConfigStoreClient/index.js +1 -1
  60. package/dist/cjs/clients/BaseAbstractClient.js +83 -58
  61. package/dist/cjs/clients/BaseAbstractClient.js.map +1 -1
  62. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js +900 -709
  63. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  64. package/dist/cjs/clients/BundleDataClient/index.js +1 -1
  65. package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.js +128 -95
  66. package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.js.map +1 -1
  67. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js +53 -48
  68. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
  69. package/dist/cjs/clients/BundleDataClient/utils/MerkleTreeUtils.js +8 -10
  70. package/dist/cjs/clients/BundleDataClient/utils/MerkleTreeUtils.js.map +1 -1
  71. package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js +90 -67
  72. package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -1
  73. package/dist/cjs/clients/BundleDataClient/utils/SuperstructUtils.js +24 -46
  74. package/dist/cjs/clients/BundleDataClient/utils/SuperstructUtils.js.map +1 -1
  75. package/dist/cjs/clients/BundleDataClient/utils/index.js +1 -1
  76. package/dist/cjs/clients/HubPoolClient.js +708 -526
  77. package/dist/cjs/clients/HubPoolClient.js.map +1 -1
  78. package/dist/cjs/clients/SpokePoolClient/EVMSpokePoolClient.js +179 -133
  79. package/dist/cjs/clients/SpokePoolClient/EVMSpokePoolClient.js.map +1 -1
  80. package/dist/cjs/clients/SpokePoolClient/SVMSpokePoolClient.js +183 -124
  81. package/dist/cjs/clients/SpokePoolClient/SVMSpokePoolClient.js.map +1 -1
  82. package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.js +389 -357
  83. package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.js.map +1 -1
  84. package/dist/cjs/clients/SpokePoolClient/SpokePoolClientManager.js +8 -9
  85. package/dist/cjs/clients/SpokePoolClient/SpokePoolClientManager.js.map +1 -1
  86. package/dist/cjs/clients/SpokePoolClient/index.js +3 -3
  87. package/dist/cjs/clients/SpokePoolClient/index.js.map +1 -1
  88. package/dist/cjs/clients/index.js +1 -1
  89. package/dist/cjs/clients/mocks/MockConfigStoreClient.js +67 -58
  90. package/dist/cjs/clients/mocks/MockConfigStoreClient.js.map +1 -1
  91. package/dist/cjs/clients/mocks/MockEvents.js +52 -47
  92. package/dist/cjs/clients/mocks/MockEvents.js.map +1 -1
  93. package/dist/cjs/clients/mocks/MockHubPoolClient.js +185 -142
  94. package/dist/cjs/clients/mocks/MockHubPoolClient.js.map +1 -1
  95. package/dist/cjs/clients/mocks/MockSpokePoolClient.js +192 -208
  96. package/dist/cjs/clients/mocks/MockSpokePoolClient.js.map +1 -1
  97. package/dist/cjs/clients/mocks/MockSvmCpiEventsClient.js +143 -140
  98. package/dist/cjs/clients/mocks/MockSvmCpiEventsClient.js.map +1 -1
  99. package/dist/cjs/clients/mocks/MockSvmSpokePoolClient.js +73 -57
  100. package/dist/cjs/clients/mocks/MockSvmSpokePoolClient.js.map +1 -1
  101. package/dist/cjs/clients/mocks/index.js +1 -1
  102. package/dist/cjs/coingecko/Coingecko.js +437 -285
  103. package/dist/cjs/coingecko/Coingecko.js.map +1 -1
  104. package/dist/cjs/coingecko/index.js +1 -1
  105. package/dist/cjs/constants.js +30 -23
  106. package/dist/cjs/constants.js.map +1 -1
  107. package/dist/cjs/contracts/acrossConfigStore.js +48 -27
  108. package/dist/cjs/contracts/acrossConfigStore.js.map +1 -1
  109. package/dist/cjs/contracts/hubPool.js +20 -36
  110. package/dist/cjs/contracts/hubPool.js.map +1 -1
  111. package/dist/cjs/contracts/index.js +1 -1
  112. package/dist/cjs/contracts/utils.js +8 -6
  113. package/dist/cjs/contracts/utils.js.map +1 -1
  114. package/dist/cjs/gasPriceOracle/adapters/arbitrum.js +16 -7
  115. package/dist/cjs/gasPriceOracle/adapters/arbitrum.js.map +1 -1
  116. package/dist/cjs/gasPriceOracle/adapters/ethereum.js +45 -26
  117. package/dist/cjs/gasPriceOracle/adapters/ethereum.js.map +1 -1
  118. package/dist/cjs/gasPriceOracle/adapters/linea-viem.js +28 -16
  119. package/dist/cjs/gasPriceOracle/adapters/linea-viem.js.map +1 -1
  120. package/dist/cjs/gasPriceOracle/adapters/polygon.js +112 -73
  121. package/dist/cjs/gasPriceOracle/adapters/polygon.js.map +1 -1
  122. package/dist/cjs/gasPriceOracle/adapters/solana.js +33 -20
  123. package/dist/cjs/gasPriceOracle/adapters/solana.js.map +1 -1
  124. package/dist/cjs/gasPriceOracle/oracle.js +104 -77
  125. package/dist/cjs/gasPriceOracle/oracle.js.map +1 -1
  126. package/dist/cjs/gasPriceOracle/types.js +3 -3
  127. package/dist/cjs/gasPriceOracle/types.js.map +1 -1
  128. package/dist/cjs/gasPriceOracle/util.js +8 -8
  129. package/dist/cjs/gasPriceOracle/util.js.map +1 -1
  130. package/dist/cjs/index.js +1 -1
  131. package/dist/cjs/interfaces/index.js +1 -1
  132. package/dist/cjs/lpFeeCalculator/index.js +1 -1
  133. package/dist/cjs/lpFeeCalculator/lpFeeCalculator.js +35 -33
  134. package/dist/cjs/lpFeeCalculator/lpFeeCalculator.js.map +1 -1
  135. package/dist/cjs/lpFeeCalculator/rateModel.js +9 -7
  136. package/dist/cjs/lpFeeCalculator/rateModel.js.map +1 -1
  137. package/dist/cjs/merkleDistributor/MerkleDistributor.js +18 -20
  138. package/dist/cjs/merkleDistributor/MerkleDistributor.js.map +1 -1
  139. package/dist/cjs/merkleDistributor/index.js +1 -1
  140. package/dist/cjs/merkleDistributor/model/index.js +1 -1
  141. package/dist/cjs/pool/TransactionManager.js +100 -45
  142. package/dist/cjs/pool/TransactionManager.js.map +1 -1
  143. package/dist/cjs/pool/index.js +1 -1
  144. package/dist/cjs/pool/poolClient.js +731 -464
  145. package/dist/cjs/pool/poolClient.js.map +1 -1
  146. package/dist/cjs/pool/uma/across/index.js +1 -1
  147. package/dist/cjs/pool/uma/across/transactionManager.js +100 -45
  148. package/dist/cjs/pool/uma/across/transactionManager.js.map +1 -1
  149. package/dist/cjs/pool/uma/clients/erc20/client.js +16 -18
  150. package/dist/cjs/pool/uma/clients/erc20/client.js.map +1 -1
  151. package/dist/cjs/pool/uma/clients/erc20/index.js +1 -1
  152. package/dist/cjs/pool/uma/clients/index.js +1 -1
  153. package/dist/cjs/pool/uma/index.js +1 -1
  154. package/dist/cjs/pool/uma/oracle/index.js +1 -1
  155. package/dist/cjs/pool/uma/oracle/utils.js +5 -4
  156. package/dist/cjs/pool/uma/oracle/utils.js.map +1 -1
  157. package/dist/cjs/pool/uma/utils.js +30 -11
  158. package/dist/cjs/pool/uma/utils.js.map +1 -1
  159. package/dist/cjs/priceClient/adapters/acrossApi.js +39 -22
  160. package/dist/cjs/priceClient/adapters/acrossApi.js.map +1 -1
  161. package/dist/cjs/priceClient/adapters/baseAdapter.js +73 -49
  162. package/dist/cjs/priceClient/adapters/baseAdapter.js.map +1 -1
  163. package/dist/cjs/priceClient/adapters/coingecko.js +61 -34
  164. package/dist/cjs/priceClient/adapters/coingecko.js.map +1 -1
  165. package/dist/cjs/priceClient/adapters/default.js +31 -16
  166. package/dist/cjs/priceClient/adapters/default.js.map +1 -1
  167. package/dist/cjs/priceClient/adapters/defiLlama.js +74 -40
  168. package/dist/cjs/priceClient/adapters/defiLlama.js.map +1 -1
  169. package/dist/cjs/priceClient/adapters/index.js +1 -1
  170. package/dist/cjs/priceClient/index.js +1 -1
  171. package/dist/cjs/priceClient/priceClient.js +159 -110
  172. package/dist/cjs/priceClient/priceClient.js.map +1 -1
  173. package/dist/cjs/providers/alchemy.js +19 -17
  174. package/dist/cjs/providers/alchemy.js.map +1 -1
  175. package/dist/cjs/providers/cachedProvider.js +129 -88
  176. package/dist/cjs/providers/cachedProvider.js.map +1 -1
  177. package/dist/cjs/providers/drpc.js +11 -9
  178. package/dist/cjs/providers/drpc.js.map +1 -1
  179. package/dist/cjs/providers/index.js +1 -1
  180. package/dist/cjs/providers/infura.js +12 -10
  181. package/dist/cjs/providers/infura.js.map +1 -1
  182. package/dist/cjs/providers/mocks/MockCachedSolanaRpcFactory.js +15 -7
  183. package/dist/cjs/providers/mocks/MockCachedSolanaRpcFactory.js.map +1 -1
  184. package/dist/cjs/providers/mocks/MockRateLimitedSolanaRpcFactory.js +14 -6
  185. package/dist/cjs/providers/mocks/MockRateLimitedSolanaRpcFactory.js.map +1 -1
  186. package/dist/cjs/providers/mocks/MockRetrySolanaRpcFactory.js +15 -7
  187. package/dist/cjs/providers/mocks/MockRetrySolanaRpcFactory.js.map +1 -1
  188. package/dist/cjs/providers/mocks/MockSolanaRpcFactory.js +66 -42
  189. package/dist/cjs/providers/mocks/MockSolanaRpcFactory.js.map +1 -1
  190. package/dist/cjs/providers/mocks/index.js +1 -1
  191. package/dist/cjs/providers/mocks/mockEthersProvider.js +31 -29
  192. package/dist/cjs/providers/mocks/mockEthersProvider.js.map +1 -1
  193. package/dist/cjs/providers/quicknode.js +21 -19
  194. package/dist/cjs/providers/quicknode.js.map +1 -1
  195. package/dist/cjs/providers/rateLimitedProvider.js +79 -64
  196. package/dist/cjs/providers/rateLimitedProvider.js.map +1 -1
  197. package/dist/cjs/providers/retryProvider.js +246 -163
  198. package/dist/cjs/providers/retryProvider.js.map +1 -1
  199. package/dist/cjs/providers/solana/baseRpcFactories.js +18 -14
  200. package/dist/cjs/providers/solana/baseRpcFactories.js.map +1 -1
  201. package/dist/cjs/providers/solana/cachedRpcFactory.js +112 -70
  202. package/dist/cjs/providers/solana/cachedRpcFactory.js.map +1 -1
  203. package/dist/cjs/providers/solana/defaultRpcFactory.js +15 -8
  204. package/dist/cjs/providers/solana/defaultRpcFactory.js.map +1 -1
  205. package/dist/cjs/providers/solana/index.js +1 -1
  206. package/dist/cjs/providers/solana/quorumFallbackRpcFactory.js +191 -135
  207. package/dist/cjs/providers/solana/quorumFallbackRpcFactory.js.map +1 -1
  208. package/dist/cjs/providers/solana/rateLimitedRpcFactory.js +90 -67
  209. package/dist/cjs/providers/solana/rateLimitedRpcFactory.js.map +1 -1
  210. package/dist/cjs/providers/solana/retryRpcFactory.js +79 -52
  211. package/dist/cjs/providers/solana/retryRpcFactory.js.map +1 -1
  212. package/dist/cjs/providers/solana/utils.js +2 -2
  213. package/dist/cjs/providers/solana/utils.js.map +1 -1
  214. package/dist/cjs/providers/speedProvider.js +53 -31
  215. package/dist/cjs/providers/speedProvider.js.map +1 -1
  216. package/dist/cjs/providers/types.js +1 -1
  217. package/dist/cjs/providers/types.js.map +1 -1
  218. package/dist/cjs/providers/utils.js +28 -26
  219. package/dist/cjs/providers/utils.js.map +1 -1
  220. package/dist/cjs/relayFeeCalculator/chain-queries/baseQuery.js +162 -108
  221. package/dist/cjs/relayFeeCalculator/chain-queries/baseQuery.js.map +1 -1
  222. package/dist/cjs/relayFeeCalculator/chain-queries/customGasToken.js +26 -14
  223. package/dist/cjs/relayFeeCalculator/chain-queries/customGasToken.js.map +1 -1
  224. package/dist/cjs/relayFeeCalculator/chain-queries/factory.js +29 -20
  225. package/dist/cjs/relayFeeCalculator/chain-queries/factory.js.map +1 -1
  226. package/dist/cjs/relayFeeCalculator/chain-queries/index.js +1 -1
  227. package/dist/cjs/relayFeeCalculator/chain-queries/svmQuery.js +137 -88
  228. package/dist/cjs/relayFeeCalculator/chain-queries/svmQuery.js.map +1 -1
  229. package/dist/cjs/relayFeeCalculator/index.js +1 -1
  230. package/dist/cjs/relayFeeCalculator/relayFeeCalculator.js +297 -199
  231. package/dist/cjs/relayFeeCalculator/relayFeeCalculator.js.map +1 -1
  232. package/dist/cjs/typeguards/error.js +7 -5
  233. package/dist/cjs/typeguards/error.js.map +1 -1
  234. package/dist/cjs/typeguards/index.js +1 -1
  235. package/dist/cjs/utils/AddressUtils.js +144 -117
  236. package/dist/cjs/utils/AddressUtils.js.map +1 -1
  237. package/dist/cjs/utils/ArrayUtils.js +78 -21
  238. package/dist/cjs/utils/ArrayUtils.js.map +1 -1
  239. package/dist/cjs/utils/BigNumberUtils.js +10 -9
  240. package/dist/cjs/utils/BigNumberUtils.js.map +1 -1
  241. package/dist/cjs/utils/BlockExplorerUtils.js +30 -26
  242. package/dist/cjs/utils/BlockExplorerUtils.js.map +1 -1
  243. package/dist/cjs/utils/BlockFinder.js +5 -2
  244. package/dist/cjs/utils/BlockFinder.js.map +1 -1
  245. package/dist/cjs/utils/BlockUtils.js +41 -24
  246. package/dist/cjs/utils/BlockUtils.js.map +1 -1
  247. package/dist/cjs/utils/BundleUtils.js +24 -21
  248. package/dist/cjs/utils/BundleUtils.js.map +1 -1
  249. package/dist/cjs/utils/CCTPUtils.js +126 -62
  250. package/dist/cjs/utils/CCTPUtils.js.map +1 -1
  251. package/dist/cjs/utils/CachingUtils.js +42 -20
  252. package/dist/cjs/utils/CachingUtils.js.map +1 -1
  253. package/dist/cjs/utils/ContractUtils.js +5 -5
  254. package/dist/cjs/utils/ContractUtils.js.map +1 -1
  255. package/dist/cjs/utils/DepositUtils.js +99 -122
  256. package/dist/cjs/utils/DepositUtils.js.map +1 -1
  257. package/dist/cjs/utils/EventUtils.js +70 -49
  258. package/dist/cjs/utils/EventUtils.js.map +1 -1
  259. package/dist/cjs/utils/FormattingUtils.js +32 -26
  260. package/dist/cjs/utils/FormattingUtils.js.map +1 -1
  261. package/dist/cjs/utils/HyperLiquidUtils.js +23 -10
  262. package/dist/cjs/utils/HyperLiquidUtils.js.map +1 -1
  263. package/dist/cjs/utils/IPFSUtils.js +34 -16
  264. package/dist/cjs/utils/IPFSUtils.js.map +1 -1
  265. package/dist/cjs/utils/JSONUtils.js +6 -6
  266. package/dist/cjs/utils/JSONUtils.js.map +1 -1
  267. package/dist/cjs/utils/LogUtils.js +12 -10
  268. package/dist/cjs/utils/LogUtils.js.map +1 -1
  269. package/dist/cjs/utils/Multicall.js +115 -56
  270. package/dist/cjs/utils/Multicall.js.map +1 -1
  271. package/dist/cjs/utils/NetworkUtils.js +28 -12
  272. package/dist/cjs/utils/NetworkUtils.js.map +1 -1
  273. package/dist/cjs/utils/NumberUtils.js +3 -1
  274. package/dist/cjs/utils/NumberUtils.js.map +1 -1
  275. package/dist/cjs/utils/ObjectUtils.js +41 -27
  276. package/dist/cjs/utils/ObjectUtils.js.map +1 -1
  277. package/dist/cjs/utils/Profiler.js +83 -80
  278. package/dist/cjs/utils/Profiler.js.map +1 -1
  279. package/dist/cjs/utils/ReviverUtils.js +9 -5
  280. package/dist/cjs/utils/ReviverUtils.js.map +1 -1
  281. package/dist/cjs/utils/SpokeUtils.js +84 -84
  282. package/dist/cjs/utils/SpokeUtils.js.map +1 -1
  283. package/dist/cjs/utils/TokenUtils.js +64 -41
  284. package/dist/cjs/utils/TokenUtils.js.map +1 -1
  285. package/dist/cjs/utils/TypeGuards.js +1 -1
  286. package/dist/cjs/utils/TypeGuards.js.map +1 -1
  287. package/dist/cjs/utils/ValidatorUtils.js +7 -7
  288. package/dist/cjs/utils/ValidatorUtils.js.map +1 -1
  289. package/dist/cjs/utils/abi/contracts/index.js +1 -1
  290. package/dist/cjs/utils/abi/index.js +22 -12
  291. package/dist/cjs/utils/abi/index.js.map +1 -1
  292. package/dist/cjs/utils/abi/typechain/factories/Multicall3__factory.js +12 -9
  293. package/dist/cjs/utils/abi/typechain/factories/Multicall3__factory.js.map +1 -1
  294. package/dist/cjs/utils/abi/typechain/index.js +1 -1
  295. package/dist/cjs/utils/common.js +53 -40
  296. package/dist/cjs/utils/common.js.map +1 -1
  297. package/dist/cjs/utils/index.js +1 -1
  298. package/dist/esm/addressAggregator/adapters/abstract.js +64 -48
  299. package/dist/esm/addressAggregator/adapters/abstract.js.map +1 -1
  300. package/dist/esm/addressAggregator/adapters/bybit.js +29 -15
  301. package/dist/esm/addressAggregator/adapters/bybit.js.map +1 -1
  302. package/dist/esm/addressAggregator/adapters/env.js +14 -9
  303. package/dist/esm/addressAggregator/adapters/env.js.map +1 -1
  304. package/dist/esm/addressAggregator/adapters/file.js +43 -29
  305. package/dist/esm/addressAggregator/adapters/file.js.map +1 -1
  306. package/dist/esm/addressAggregator/adapters/risklabs.js +35 -20
  307. package/dist/esm/addressAggregator/adapters/risklabs.js.map +1 -1
  308. package/dist/esm/addressAggregator/index.js +83 -52
  309. package/dist/esm/addressAggregator/index.js.map +1 -1
  310. package/dist/esm/addressAggregator/types.js +1 -1
  311. package/dist/esm/addressAggregator/types.js.map +1 -1
  312. package/dist/esm/apiClient/abstractClient.js +9 -15
  313. package/dist/esm/apiClient/abstractClient.js.map +1 -1
  314. package/dist/esm/apiClient/mockedClient.js +26 -21
  315. package/dist/esm/apiClient/mockedClient.js.map +1 -1
  316. package/dist/esm/apiClient/productionClient.js +101 -61
  317. package/dist/esm/apiClient/productionClient.js.map +1 -1
  318. package/dist/esm/arch/evm/BlockUtils.js +217 -139
  319. package/dist/esm/arch/evm/BlockUtils.js.map +1 -1
  320. package/dist/esm/arch/evm/SpokeUtils.js +289 -146
  321. package/dist/esm/arch/evm/SpokeUtils.js.map +1 -1
  322. package/dist/esm/arch/evm/utils/wait.js +46 -34
  323. package/dist/esm/arch/evm/utils/wait.js.map +1 -1
  324. package/dist/esm/arch/svm/BlockUtils.js +166 -118
  325. package/dist/esm/arch/svm/BlockUtils.js.map +1 -1
  326. package/dist/esm/arch/svm/SpokeUtils.js +1150 -738
  327. package/dist/esm/arch/svm/SpokeUtils.js.map +1 -1
  328. package/dist/esm/arch/svm/constants.js +1 -1
  329. package/dist/esm/arch/svm/constants.js.map +1 -1
  330. package/dist/esm/arch/svm/eventsClient.js +232 -172
  331. package/dist/esm/arch/svm/eventsClient.js.map +1 -1
  332. package/dist/esm/arch/svm/provider.js +1 -1
  333. package/dist/esm/arch/svm/provider.js.map +1 -1
  334. package/dist/esm/arch/svm/utils.js +345 -155
  335. package/dist/esm/arch/svm/utils.js.map +1 -1
  336. package/dist/esm/caching/Arweave/ArweaveClient.js +256 -182
  337. package/dist/esm/caching/Arweave/ArweaveClient.js.map +1 -1
  338. package/dist/esm/caching/IPFS/PinataIPFSClient.js +48 -47
  339. package/dist/esm/caching/IPFS/PinataIPFSClient.js.map +1 -1
  340. package/dist/esm/caching/Memory/MemoryCacheClient.js +19 -13
  341. package/dist/esm/caching/Memory/MemoryCacheClient.js.map +1 -1
  342. package/dist/esm/clients/AcrossConfigStoreClient/AcrossConfigStoreClient.js +408 -333
  343. package/dist/esm/clients/AcrossConfigStoreClient/AcrossConfigStoreClient.js.map +1 -1
  344. package/dist/esm/clients/BaseAbstractClient.js +92 -66
  345. package/dist/esm/clients/BaseAbstractClient.js.map +1 -1
  346. package/dist/esm/clients/BundleDataClient/BundleDataClient.js +1054 -927
  347. package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  348. package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.js +131 -102
  349. package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.js.map +1 -1
  350. package/dist/esm/clients/BundleDataClient/utils/FillUtils.js +59 -57
  351. package/dist/esm/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
  352. package/dist/esm/clients/BundleDataClient/utils/MerkleTreeUtils.js +5 -7
  353. package/dist/esm/clients/BundleDataClient/utils/MerkleTreeUtils.js.map +1 -1
  354. package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js +94 -75
  355. package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -1
  356. package/dist/esm/clients/BundleDataClient/utils/SuperstructUtils.js +23 -45
  357. package/dist/esm/clients/BundleDataClient/utils/SuperstructUtils.js.map +1 -1
  358. package/dist/esm/clients/HubPoolClient.js +740 -581
  359. package/dist/esm/clients/HubPoolClient.js.map +1 -1
  360. package/dist/esm/clients/SpokePoolClient/EVMSpokePoolClient.js +178 -133
  361. package/dist/esm/clients/SpokePoolClient/EVMSpokePoolClient.js.map +1 -1
  362. package/dist/esm/clients/SpokePoolClient/SVMSpokePoolClient.js +183 -126
  363. package/dist/esm/clients/SpokePoolClient/SVMSpokePoolClient.js.map +1 -1
  364. package/dist/esm/clients/SpokePoolClient/SpokePoolClient.js +399 -372
  365. package/dist/esm/clients/SpokePoolClient/SpokePoolClient.js.map +1 -1
  366. package/dist/esm/clients/SpokePoolClient/SpokePoolClientManager.js +9 -9
  367. package/dist/esm/clients/SpokePoolClient/SpokePoolClientManager.js.map +1 -1
  368. package/dist/esm/clients/SpokePoolClient/index.js +2 -2
  369. package/dist/esm/clients/SpokePoolClient/index.js.map +1 -1
  370. package/dist/esm/clients/SpokePoolClient/types.js +2 -2
  371. package/dist/esm/clients/SpokePoolClient/types.js.map +1 -1
  372. package/dist/esm/clients/mocks/MockConfigStoreClient.js +64 -53
  373. package/dist/esm/clients/mocks/MockConfigStoreClient.js.map +1 -1
  374. package/dist/esm/clients/mocks/MockEvents.js +49 -42
  375. package/dist/esm/clients/mocks/MockEvents.js.map +1 -1
  376. package/dist/esm/clients/mocks/MockHubPoolClient.js +182 -138
  377. package/dist/esm/clients/mocks/MockHubPoolClient.js.map +1 -1
  378. package/dist/esm/clients/mocks/MockSpokePoolClient.js +188 -202
  379. package/dist/esm/clients/mocks/MockSpokePoolClient.js.map +1 -1
  380. package/dist/esm/clients/mocks/MockSvmCpiEventsClient.js +132 -127
  381. package/dist/esm/clients/mocks/MockSvmCpiEventsClient.js.map +1 -1
  382. package/dist/esm/clients/mocks/MockSvmSpokePoolClient.js +69 -53
  383. package/dist/esm/clients/mocks/MockSvmSpokePoolClient.js.map +1 -1
  384. package/dist/esm/coingecko/Coingecko.js +443 -298
  385. package/dist/esm/coingecko/Coingecko.js.map +1 -1
  386. package/dist/esm/constants.js +47 -40
  387. package/dist/esm/constants.js.map +1 -1
  388. package/dist/esm/contracts/acrossConfigStore.js +46 -24
  389. package/dist/esm/contracts/acrossConfigStore.js.map +1 -1
  390. package/dist/esm/contracts/hubPool.js +18 -34
  391. package/dist/esm/contracts/hubPool.js.map +1 -1
  392. package/dist/esm/contracts/utils.js +5 -3
  393. package/dist/esm/contracts/utils.js.map +1 -1
  394. package/dist/esm/gasPriceOracle/adapters/arbitrum.js +14 -6
  395. package/dist/esm/gasPriceOracle/adapters/arbitrum.js.map +1 -1
  396. package/dist/esm/gasPriceOracle/adapters/ethereum.js +42 -22
  397. package/dist/esm/gasPriceOracle/adapters/ethereum.js.map +1 -1
  398. package/dist/esm/gasPriceOracle/adapters/linea-viem.js +25 -13
  399. package/dist/esm/gasPriceOracle/adapters/linea-viem.js.map +1 -1
  400. package/dist/esm/gasPriceOracle/adapters/polygon.js +108 -72
  401. package/dist/esm/gasPriceOracle/adapters/polygon.js.map +1 -1
  402. package/dist/esm/gasPriceOracle/adapters/solana.js +31 -22
  403. package/dist/esm/gasPriceOracle/adapters/solana.js.map +1 -1
  404. package/dist/esm/gasPriceOracle/oracle.js +96 -70
  405. package/dist/esm/gasPriceOracle/oracle.js.map +1 -1
  406. package/dist/esm/gasPriceOracle/types.js +2 -2
  407. package/dist/esm/gasPriceOracle/types.js.map +1 -1
  408. package/dist/esm/gasPriceOracle/util.js +4 -4
  409. package/dist/esm/gasPriceOracle/util.js.map +1 -1
  410. package/dist/esm/lpFeeCalculator/lpFeeCalculator.js +33 -30
  411. package/dist/esm/lpFeeCalculator/lpFeeCalculator.js.map +1 -1
  412. package/dist/esm/lpFeeCalculator/rateModel.js +9 -7
  413. package/dist/esm/lpFeeCalculator/rateModel.js.map +1 -1
  414. package/dist/esm/merkleDistributor/MerkleDistributor.js +17 -18
  415. package/dist/esm/merkleDistributor/MerkleDistributor.js.map +1 -1
  416. package/dist/esm/pool/TransactionManager.js +100 -45
  417. package/dist/esm/pool/TransactionManager.js.map +1 -1
  418. package/dist/esm/pool/poolClient.js +740 -479
  419. package/dist/esm/pool/poolClient.js.map +1 -1
  420. package/dist/esm/pool/uma/across/constants.js +2 -2
  421. package/dist/esm/pool/uma/across/constants.js.map +1 -1
  422. package/dist/esm/pool/uma/across/transactionManager.js +100 -45
  423. package/dist/esm/pool/uma/across/transactionManager.js.map +1 -1
  424. package/dist/esm/pool/uma/clients/erc20/client.js +13 -15
  425. package/dist/esm/pool/uma/clients/erc20/client.js.map +1 -1
  426. package/dist/esm/pool/uma/oracle/utils.js +3 -2
  427. package/dist/esm/pool/uma/oracle/utils.js.map +1 -1
  428. package/dist/esm/pool/uma/utils.js +28 -9
  429. package/dist/esm/pool/uma/utils.js.map +1 -1
  430. package/dist/esm/priceClient/adapters/acrossApi.js +40 -21
  431. package/dist/esm/priceClient/adapters/acrossApi.js.map +1 -1
  432. package/dist/esm/priceClient/adapters/baseAdapter.js +72 -46
  433. package/dist/esm/priceClient/adapters/baseAdapter.js.map +1 -1
  434. package/dist/esm/priceClient/adapters/coingecko.js +61 -33
  435. package/dist/esm/priceClient/adapters/coingecko.js.map +1 -1
  436. package/dist/esm/priceClient/adapters/default.js +31 -15
  437. package/dist/esm/priceClient/adapters/default.js.map +1 -1
  438. package/dist/esm/priceClient/adapters/defiLlama.js +73 -38
  439. package/dist/esm/priceClient/adapters/defiLlama.js.map +1 -1
  440. package/dist/esm/priceClient/priceClient.js +158 -109
  441. package/dist/esm/priceClient/priceClient.js.map +1 -1
  442. package/dist/esm/providers/alchemy.js +18 -16
  443. package/dist/esm/providers/alchemy.js.map +1 -1
  444. package/dist/esm/providers/cachedProvider.js +134 -99
  445. package/dist/esm/providers/cachedProvider.js.map +1 -1
  446. package/dist/esm/providers/constants.js +3 -3
  447. package/dist/esm/providers/constants.js.map +1 -1
  448. package/dist/esm/providers/drpc.js +10 -8
  449. package/dist/esm/providers/drpc.js.map +1 -1
  450. package/dist/esm/providers/infura.js +11 -9
  451. package/dist/esm/providers/infura.js.map +1 -1
  452. package/dist/esm/providers/mocks/MockCachedSolanaRpcFactory.js +15 -6
  453. package/dist/esm/providers/mocks/MockCachedSolanaRpcFactory.js.map +1 -1
  454. package/dist/esm/providers/mocks/MockRateLimitedSolanaRpcFactory.js +14 -5
  455. package/dist/esm/providers/mocks/MockRateLimitedSolanaRpcFactory.js.map +1 -1
  456. package/dist/esm/providers/mocks/MockRetrySolanaRpcFactory.js +15 -6
  457. package/dist/esm/providers/mocks/MockRetrySolanaRpcFactory.js.map +1 -1
  458. package/dist/esm/providers/mocks/MockSolanaRpcFactory.js +66 -41
  459. package/dist/esm/providers/mocks/MockSolanaRpcFactory.js.map +1 -1
  460. package/dist/esm/providers/mocks/mockEthersProvider.js +30 -27
  461. package/dist/esm/providers/mocks/mockEthersProvider.js.map +1 -1
  462. package/dist/esm/providers/quicknode.js +20 -18
  463. package/dist/esm/providers/quicknode.js.map +1 -1
  464. package/dist/esm/providers/rateLimitedProvider.js +80 -68
  465. package/dist/esm/providers/rateLimitedProvider.js.map +1 -1
  466. package/dist/esm/providers/retryProvider.js +259 -186
  467. package/dist/esm/providers/retryProvider.js.map +1 -1
  468. package/dist/esm/providers/solana/baseRpcFactories.js +19 -13
  469. package/dist/esm/providers/solana/baseRpcFactories.js.map +1 -1
  470. package/dist/esm/providers/solana/cachedRpcFactory.js +112 -75
  471. package/dist/esm/providers/solana/cachedRpcFactory.js.map +1 -1
  472. package/dist/esm/providers/solana/defaultRpcFactory.js +14 -6
  473. package/dist/esm/providers/solana/defaultRpcFactory.js.map +1 -1
  474. package/dist/esm/providers/solana/quorumFallbackRpcFactory.js +202 -149
  475. package/dist/esm/providers/solana/quorumFallbackRpcFactory.js.map +1 -1
  476. package/dist/esm/providers/solana/rateLimitedRpcFactory.js +90 -70
  477. package/dist/esm/providers/solana/rateLimitedRpcFactory.js.map +1 -1
  478. package/dist/esm/providers/solana/retryRpcFactory.js +74 -50
  479. package/dist/esm/providers/solana/retryRpcFactory.js.map +1 -1
  480. package/dist/esm/providers/solana/utils.js +1 -1
  481. package/dist/esm/providers/solana/utils.js.map +1 -1
  482. package/dist/esm/providers/speedProvider.js +51 -28
  483. package/dist/esm/providers/speedProvider.js.map +1 -1
  484. package/dist/esm/providers/types.js +2 -2
  485. package/dist/esm/providers/types.js.map +1 -1
  486. package/dist/esm/providers/utils.js +20 -17
  487. package/dist/esm/providers/utils.js.map +1 -1
  488. package/dist/esm/relayFeeCalculator/chain-queries/baseQuery.js +152 -98
  489. package/dist/esm/relayFeeCalculator/chain-queries/baseQuery.js.map +1 -1
  490. package/dist/esm/relayFeeCalculator/chain-queries/customGasToken.js +26 -13
  491. package/dist/esm/relayFeeCalculator/chain-queries/customGasToken.js.map +1 -1
  492. package/dist/esm/relayFeeCalculator/chain-queries/factory.js +19 -9
  493. package/dist/esm/relayFeeCalculator/chain-queries/factory.js.map +1 -1
  494. package/dist/esm/relayFeeCalculator/chain-queries/svmQuery.js +128 -83
  495. package/dist/esm/relayFeeCalculator/chain-queries/svmQuery.js.map +1 -1
  496. package/dist/esm/relayFeeCalculator/relayFeeCalculator.js +299 -211
  497. package/dist/esm/relayFeeCalculator/relayFeeCalculator.js.map +1 -1
  498. package/dist/esm/typeguards/error.js +5 -3
  499. package/dist/esm/typeguards/error.js.map +1 -1
  500. package/dist/esm/utils/AddressUtils.js +147 -115
  501. package/dist/esm/utils/AddressUtils.js.map +1 -1
  502. package/dist/esm/utils/ArrayUtils.js +78 -21
  503. package/dist/esm/utils/ArrayUtils.js.map +1 -1
  504. package/dist/esm/utils/BigNumberUtils.js +12 -11
  505. package/dist/esm/utils/BigNumberUtils.js.map +1 -1
  506. package/dist/esm/utils/BlockExplorerUtils.js +23 -19
  507. package/dist/esm/utils/BlockExplorerUtils.js.map +1 -1
  508. package/dist/esm/utils/BlockFinder.js +6 -2
  509. package/dist/esm/utils/BlockFinder.js.map +1 -1
  510. package/dist/esm/utils/BlockUtils.js +40 -31
  511. package/dist/esm/utils/BlockUtils.js.map +1 -1
  512. package/dist/esm/utils/BundleUtils.js +24 -21
  513. package/dist/esm/utils/BundleUtils.js.map +1 -1
  514. package/dist/esm/utils/CCTPUtils.js +123 -62
  515. package/dist/esm/utils/CCTPUtils.js.map +1 -1
  516. package/dist/esm/utils/CachingUtils.js +38 -17
  517. package/dist/esm/utils/CachingUtils.js.map +1 -1
  518. package/dist/esm/utils/ContractUtils.js +3 -3
  519. package/dist/esm/utils/ContractUtils.js.map +1 -1
  520. package/dist/esm/utils/DepositUtils.js +98 -121
  521. package/dist/esm/utils/DepositUtils.js.map +1 -1
  522. package/dist/esm/utils/EventUtils.js +69 -52
  523. package/dist/esm/utils/EventUtils.js.map +1 -1
  524. package/dist/esm/utils/FormattingUtils.js +26 -20
  525. package/dist/esm/utils/FormattingUtils.js.map +1 -1
  526. package/dist/esm/utils/HyperLiquidUtils.js +22 -8
  527. package/dist/esm/utils/HyperLiquidUtils.js.map +1 -1
  528. package/dist/esm/utils/IPFSUtils.js +35 -16
  529. package/dist/esm/utils/IPFSUtils.js.map +1 -1
  530. package/dist/esm/utils/JSONUtils.js +4 -4
  531. package/dist/esm/utils/JSONUtils.js.map +1 -1
  532. package/dist/esm/utils/LogUtils.js +12 -8
  533. package/dist/esm/utils/LogUtils.js.map +1 -1
  534. package/dist/esm/utils/Multicall.js +110 -50
  535. package/dist/esm/utils/Multicall.js.map +1 -1
  536. package/dist/esm/utils/NetworkUtils.js +28 -12
  537. package/dist/esm/utils/NetworkUtils.js.map +1 -1
  538. package/dist/esm/utils/NumberUtils.js +3 -1
  539. package/dist/esm/utils/NumberUtils.js.map +1 -1
  540. package/dist/esm/utils/ObjectUtils.js +41 -27
  541. package/dist/esm/utils/ObjectUtils.js.map +1 -1
  542. package/dist/esm/utils/Profiler.js +82 -77
  543. package/dist/esm/utils/Profiler.js.map +1 -1
  544. package/dist/esm/utils/ReviverUtils.js +7 -3
  545. package/dist/esm/utils/ReviverUtils.js.map +1 -1
  546. package/dist/esm/utils/SpokeUtils.js +78 -83
  547. package/dist/esm/utils/SpokeUtils.js.map +1 -1
  548. package/dist/esm/utils/TokenUtils.js +57 -33
  549. package/dist/esm/utils/TokenUtils.js.map +1 -1
  550. package/dist/esm/utils/ValidatorUtils.js +4 -4
  551. package/dist/esm/utils/ValidatorUtils.js.map +1 -1
  552. package/dist/esm/utils/abi/index.js +20 -10
  553. package/dist/esm/utils/abi/index.js.map +1 -1
  554. package/dist/esm/utils/abi/typechain/factories/Multicall3__factory.js +12 -8
  555. package/dist/esm/utils/abi/typechain/factories/Multicall3__factory.js.map +1 -1
  556. package/dist/esm/utils/common.js +52 -38
  557. package/dist/esm/utils/common.js.map +1 -1
  558. package/dist/types/constants.d.ts.map +1 -1
  559. package/dist/types/gasPriceOracle/oracle.d.ts.map +1 -1
  560. package/dist/types/utils/Multicall.d.ts.map +1 -1
  561. package/dist/types/utils/NetworkUtils.d.ts.map +1 -1
  562. package/package.json +3 -3
  563. package/src/constants.ts +1 -0
  564. package/src/gasPriceOracle/oracle.ts +1 -0
  565. package/src/utils/Multicall.ts +1 -0
  566. package/src/utils/NetworkUtils.ts +8 -1
@@ -1,3 +1,4 @@
1
+ import { __assign, __awaiter, __generator, __rest } from "tslib";
1
2
  import assert from "assert";
2
3
  import _ from "lodash";
3
4
  import { FillType, FillStatus, } from "../../interfaces";
@@ -8,51 +9,57 @@ import { BundleDataSS, getRefundInformationFromFill, isChainDisabledAtBlock, pre
8
9
  import { isEVMSpokePoolClient, isSVMSpokePoolClient } from "../SpokePoolClient";
9
10
  import { SpokePoolManager } from "../SpokePoolClient/SpokePoolClientManager";
10
11
  // max(uint256) - 1
11
- export const INFINITE_FILL_DEADLINE = bnUint32Max;
12
+ export var INFINITE_FILL_DEADLINE = bnUint32Max;
12
13
  // V3 dictionary helper functions
13
14
  function updateExpiredDepositsV3(dict, deposit) {
15
+ var _a, _b;
16
+ var _c, _d;
14
17
  // A deposit refund for a deposit is invalid if the depositor has a bytes32 address input for an EVM chain. It is valid otherwise.
15
18
  if (!deposit.depositor.isValidOn(deposit.originChainId)) {
16
19
  return;
17
20
  }
18
- const { originChainId, inputToken } = deposit;
19
- dict[originChainId] ??= {};
20
- dict[originChainId][inputToken.toBytes32()] ??= [];
21
+ var originChainId = deposit.originChainId, inputToken = deposit.inputToken;
22
+ (_a = dict[originChainId]) !== null && _a !== void 0 ? _a : (dict[originChainId] = {});
23
+ (_b = (_c = dict[originChainId])[_d = inputToken.toBytes32()]) !== null && _b !== void 0 ? _b : (_c[_d] = []);
21
24
  dict[originChainId][inputToken.toBytes32()].push(deposit);
22
25
  }
23
26
  function updateBundleDepositsV3(dict, deposit) {
24
- const { originChainId, inputToken } = deposit;
25
- dict[originChainId] ??= {};
26
- dict[originChainId][inputToken.toBytes32()] ??= [];
27
+ var _a, _b;
28
+ var _c, _d;
29
+ var originChainId = deposit.originChainId, inputToken = deposit.inputToken;
30
+ (_a = dict[originChainId]) !== null && _a !== void 0 ? _a : (dict[originChainId] = {});
31
+ (_b = (_c = dict[originChainId])[_d = inputToken.toBytes32()]) !== null && _b !== void 0 ? _b : (_c[_d] = []);
27
32
  dict[originChainId][inputToken.toBytes32()].push(deposit);
28
33
  }
29
34
  function updateBundleFillsV3(dict, fill, lpFeePct, repaymentChainId, repaymentToken, repaymentAddress) {
35
+ var _a, _b, _c;
36
+ var _d, _e;
30
37
  // We shouldn't pass any unrepayable fills into this function, so we perform an extra safety check.
31
38
  if (!fill.relayer.isValidOn(repaymentChainId)) {
32
39
  return;
33
40
  }
34
- dict[repaymentChainId] ??= {};
35
- dict[repaymentChainId][repaymentToken.toBytes32()] ??= {
41
+ (_a = dict[repaymentChainId]) !== null && _a !== void 0 ? _a : (dict[repaymentChainId] = {});
42
+ (_b = (_d = dict[repaymentChainId])[_e = repaymentToken.toBytes32()]) !== null && _b !== void 0 ? _b : (_d[_e] = {
36
43
  fills: [],
37
44
  totalRefundAmount: bnZero,
38
45
  realizedLpFees: bnZero,
39
46
  refunds: {},
40
- };
41
- const bundleFill = { ...fill, lpFeePct, relayer: repaymentAddress };
47
+ });
48
+ var bundleFill = __assign(__assign({}, fill), { lpFeePct: lpFeePct, relayer: repaymentAddress });
42
49
  // Add all fills, slow and fast, to dictionary.
43
50
  assign(dict, [repaymentChainId, repaymentToken.toBytes32(), "fills"], [bundleFill]);
44
51
  // All fills update the bundle LP fees.
45
- const refundObj = dict[repaymentChainId][repaymentToken.toBytes32()];
46
- const realizedLpFee = bundleFill.inputAmount.mul(bundleFill.lpFeePct).div(fixedPointAdjustment);
52
+ var refundObj = dict[repaymentChainId][repaymentToken.toBytes32()];
53
+ var realizedLpFee = bundleFill.inputAmount.mul(bundleFill.lpFeePct).div(fixedPointAdjustment);
47
54
  refundObj.realizedLpFees = refundObj.realizedLpFees ? refundObj.realizedLpFees.add(realizedLpFee) : realizedLpFee;
48
55
  // Only fast fills get refunded.
49
56
  if (!isSlowFill(bundleFill)) {
50
- const refundAmount = bundleFill.inputAmount.mul(fixedPointAdjustment.sub(lpFeePct)).div(fixedPointAdjustment);
57
+ var refundAmount = bundleFill.inputAmount.mul(fixedPointAdjustment.sub(lpFeePct)).div(fixedPointAdjustment);
51
58
  refundObj.totalRefundAmount = refundObj.totalRefundAmount
52
59
  ? refundObj.totalRefundAmount.add(refundAmount)
53
60
  : refundAmount;
54
61
  // Instantiate dictionary if it doesn't exist.
55
- refundObj.refunds ??= {};
62
+ (_c = refundObj.refunds) !== null && _c !== void 0 ? _c : (refundObj.refunds = {});
56
63
  if (refundObj.refunds[bundleFill.relayer.toBytes32()]) {
57
64
  refundObj.refunds[bundleFill.relayer.toBytes32()] =
58
65
  refundObj.refunds[bundleFill.relayer.toBytes32()].add(refundAmount);
@@ -63,976 +70,1096 @@ function updateBundleFillsV3(dict, fill, lpFeePct, repaymentChainId, repaymentTo
63
70
  }
64
71
  }
65
72
  function updateBundleExcessSlowFills(dict, deposit) {
66
- const { destinationChainId, outputToken } = deposit;
67
- dict[destinationChainId] ??= {};
68
- dict[destinationChainId][outputToken.toBytes32()] ??= [];
73
+ var _a, _b;
74
+ var _c, _d;
75
+ var destinationChainId = deposit.destinationChainId, outputToken = deposit.outputToken;
76
+ (_a = dict[destinationChainId]) !== null && _a !== void 0 ? _a : (dict[destinationChainId] = {});
77
+ (_b = (_c = dict[destinationChainId])[_d = outputToken.toBytes32()]) !== null && _b !== void 0 ? _b : (_c[_d] = []);
69
78
  dict[destinationChainId][outputToken.toBytes32()].push(deposit);
70
79
  }
71
80
  function updateBundleSlowFills(dict, deposit) {
81
+ var _a, _b;
82
+ var _c, _d;
72
83
  if (!deposit.recipient.isValidOn(deposit.destinationChainId)) {
73
84
  return;
74
85
  }
75
- const { destinationChainId, outputToken } = deposit;
76
- dict[destinationChainId] ??= {};
77
- dict[destinationChainId][outputToken.toBytes32()] ??= [];
86
+ var destinationChainId = deposit.destinationChainId, outputToken = deposit.outputToken;
87
+ (_a = dict[destinationChainId]) !== null && _a !== void 0 ? _a : (dict[destinationChainId] = {});
88
+ (_b = (_c = dict[destinationChainId])[_d = outputToken.toBytes32()]) !== null && _b !== void 0 ? _b : (_c[_d] = []);
78
89
  dict[destinationChainId][outputToken.toBytes32()].push(deposit);
79
90
  }
80
91
  // @notice Shared client for computing data needed to construct or validate a bundle.
81
- export class BundleDataClient {
82
- logger;
83
- clients;
84
- chainIdListForBundleEvaluationBlockNumbers;
85
- blockRangeEndBlockBuffer;
86
- loadDataCache = {};
87
- arweaveDataCache = {};
88
- bundleTimestampCache = {};
89
- spokePoolClientManager;
92
+ var BundleDataClient = /** @class */ (function () {
90
93
  // eslint-disable-next-line no-useless-constructor
91
- constructor(logger, clients, spokePoolClients, chainIdListForBundleEvaluationBlockNumbers, blockRangeEndBlockBuffer = {}) {
94
+ function BundleDataClient(logger, clients, spokePoolClients, chainIdListForBundleEvaluationBlockNumbers, blockRangeEndBlockBuffer) {
95
+ if (blockRangeEndBlockBuffer === void 0) { blockRangeEndBlockBuffer = {}; }
92
96
  this.logger = logger;
93
97
  this.clients = clients;
94
98
  this.chainIdListForBundleEvaluationBlockNumbers = chainIdListForBundleEvaluationBlockNumbers;
95
99
  this.blockRangeEndBlockBuffer = blockRangeEndBlockBuffer;
100
+ this.loadDataCache = {};
101
+ this.arweaveDataCache = {};
102
+ this.bundleTimestampCache = {};
96
103
  this.spokePoolClientManager = new SpokePoolManager(logger, spokePoolClients);
97
104
  }
98
105
  // This should be called whenever it's possible that the loadData information for a block range could have changed.
99
106
  // For instance, if the spoke or hub clients have been updated, it probably makes sense to clear this to be safe.
100
- clearCache() {
107
+ BundleDataClient.prototype.clearCache = function () {
101
108
  this.loadDataCache = {};
102
- }
103
- async loadDataFromCache(key) {
104
- // Always return a deep cloned copy of object stored in cache. Since JS passes by reference instead of value, we
105
- // want to minimize the risk that the programmer accidentally mutates data in the cache.
106
- return _.cloneDeep(await this.loadDataCache[key]);
107
- }
108
- getBundleTimestampsFromCache(key) {
109
+ };
110
+ BundleDataClient.prototype.loadDataFromCache = function (key) {
111
+ return __awaiter(this, void 0, void 0, function () {
112
+ var _a, _b;
113
+ return __generator(this, function (_c) {
114
+ switch (_c.label) {
115
+ case 0:
116
+ _b = (_a = _).cloneDeep;
117
+ return [4 /*yield*/, this.loadDataCache[key]];
118
+ case 1:
119
+ // Always return a deep cloned copy of object stored in cache. Since JS passes by reference instead of value, we
120
+ // want to minimize the risk that the programmer accidentally mutates data in the cache.
121
+ return [2 /*return*/, _b.apply(_a, [_c.sent()])];
122
+ }
123
+ });
124
+ });
125
+ };
126
+ BundleDataClient.prototype.getBundleTimestampsFromCache = function (key) {
109
127
  if (this.bundleTimestampCache[key]) {
110
128
  return _.cloneDeep(this.bundleTimestampCache[key]);
111
129
  }
112
130
  return undefined;
113
- }
114
- setBundleTimestampsInCache(key, timestamps) {
131
+ };
132
+ BundleDataClient.prototype.setBundleTimestampsInCache = function (key, timestamps) {
115
133
  this.bundleTimestampCache[key] = timestamps;
116
- }
117
- static getArweaveClientKey(blockRangesForChains) {
134
+ };
135
+ BundleDataClient.getArweaveClientKey = function (blockRangesForChains) {
118
136
  // As a unique key for this bundle, use the bundle mainnet end block, which should
119
137
  // never be duplicated between bundles as long as thebundle block range
120
138
  // always progresses forwards, which I think is a safe assumption. Other chains might pause
121
139
  // but mainnet should never pause.
122
140
  return blockRangesForChains[0][1].toString();
123
- }
124
- getArweaveBundleDataClientKey(blockRangesForChains) {
125
- return `bundles-${BundleDataClient.getArweaveClientKey(blockRangesForChains)}`;
126
- }
127
- async loadPersistedDataFromArweave(blockRangesForChains) {
128
- if (!isDefined(this.clients?.arweaveClient)) {
129
- return undefined;
130
- }
131
- const start = performance.now();
132
- const persistedData = await this.clients.arweaveClient.getByTopic(this.getArweaveBundleDataClientKey(blockRangesForChains), BundleDataSS);
133
- // If there is no data or the data is empty, return undefined because we couldn't
134
- // pull info from the Arweave persistence layer.
135
- if (!isDefined(persistedData) || persistedData.length < 1) {
136
- return undefined;
137
- }
138
- // A converter function to account for the fact that our SuperStruct schema does not support numeric
139
- // keys in records. Fundamentally, this is a limitation of superstruct itself.
140
- const convertTypedStringRecordIntoNumericRecord = (data) => Object.keys(data).reduce((acc, chainId) => {
141
- acc[Number(chainId)] = data[chainId];
142
- return acc;
143
- }, {});
144
- const convertSortableEventFieldsIntoRequiredFields = (data) => {
145
- return data.map((item) => {
146
- // For txnIndex/transactionIndex: throw if both are defined or both are missing.
147
- if ((item.txnIndex !== undefined && item.transactionIndex !== undefined) ||
148
- (item.txnIndex === undefined && item.transactionIndex === undefined)) {
149
- throw new Error("Either txnIndex or transactionIndex must be defined, but not both.");
141
+ };
142
+ BundleDataClient.prototype.getArweaveBundleDataClientKey = function (blockRangesForChains) {
143
+ return "bundles-".concat(BundleDataClient.getArweaveClientKey(blockRangesForChains));
144
+ };
145
+ BundleDataClient.prototype.loadPersistedDataFromArweave = function (blockRangesForChains) {
146
+ return __awaiter(this, void 0, void 0, function () {
147
+ var start, persistedData, convertTypedStringRecordIntoNumericRecord, convertSortableEventFieldsIntoRequiredFields, convertEmbeddedSortableEventFieldsIntoRequiredFields, data, bundleData;
148
+ var _a;
149
+ return __generator(this, function (_b) {
150
+ switch (_b.label) {
151
+ case 0:
152
+ if (!isDefined((_a = this.clients) === null || _a === void 0 ? void 0 : _a.arweaveClient)) {
153
+ return [2 /*return*/, undefined];
154
+ }
155
+ start = performance.now();
156
+ return [4 /*yield*/, this.clients.arweaveClient.getByTopic(this.getArweaveBundleDataClientKey(blockRangesForChains), BundleDataSS)];
157
+ case 1:
158
+ persistedData = _b.sent();
159
+ // If there is no data or the data is empty, return undefined because we couldn't
160
+ // pull info from the Arweave persistence layer.
161
+ if (!isDefined(persistedData) || persistedData.length < 1) {
162
+ return [2 /*return*/, undefined];
163
+ }
164
+ convertTypedStringRecordIntoNumericRecord = function (data) {
165
+ return Object.keys(data).reduce(function (acc, chainId) {
166
+ acc[Number(chainId)] = data[chainId];
167
+ return acc;
168
+ }, {});
169
+ };
170
+ convertSortableEventFieldsIntoRequiredFields = function (data) {
171
+ return data.map(function (item) {
172
+ // For txnIndex/transactionIndex: throw if both are defined or both are missing.
173
+ if ((item.txnIndex !== undefined && item.transactionIndex !== undefined) ||
174
+ (item.txnIndex === undefined && item.transactionIndex === undefined)) {
175
+ throw new Error("Either txnIndex or transactionIndex must be defined, but not both.");
176
+ }
177
+ // For txnRef/transactionHash: throw if both are defined or both are missing.
178
+ if ((item.txnRef !== undefined && item.transactionHash !== undefined) ||
179
+ (item.txnRef === undefined && item.transactionHash === undefined)) {
180
+ throw new Error("Either txnRef or transactionHash must be defined, but not both.");
181
+ }
182
+ // Destructure the fields we don't need anymore
183
+ var txnIndex = item.txnIndex, transactionIndex = item.transactionIndex, txnRef = item.txnRef, transactionHash = item.transactionHash, rest = __rest(item, ["txnIndex", "transactionIndex", "txnRef", "transactionHash"]);
184
+ // Return a new object with normalized fields.
185
+ // The non-null assertion (!) is safe here because our conditions ensure that one of each pair is defined.
186
+ return __assign(__assign({}, rest), { txnIndex: txnIndex !== null && txnIndex !== void 0 ? txnIndex : transactionIndex, txnRef: txnRef !== null && txnRef !== void 0 ? txnRef : transactionHash });
187
+ });
188
+ };
189
+ convertEmbeddedSortableEventFieldsIntoRequiredFields = function (data) {
190
+ return Object.fromEntries(Object.entries(data).map(function (_a) {
191
+ var chainId = _a[0], tokenData = _a[1];
192
+ return [
193
+ chainId,
194
+ Object.fromEntries(Object.entries(tokenData).map(function (_a) {
195
+ var token = _a[0], data = _a[1];
196
+ return [
197
+ token,
198
+ convertSortableEventFieldsIntoRequiredFields(data),
199
+ ];
200
+ })),
201
+ ];
202
+ }));
203
+ };
204
+ data = persistedData[0].data;
205
+ bundleData = {
206
+ bundleFillsV3: convertTypedStringRecordIntoNumericRecord(Object.fromEntries(Object.entries(data.bundleFillsV3).map(function (_a) {
207
+ var chainId = _a[0], tokenData = _a[1];
208
+ return [
209
+ chainId,
210
+ Object.fromEntries(Object.entries(tokenData).map(function (_a) {
211
+ var token = _a[0], data = _a[1];
212
+ return [
213
+ token,
214
+ {
215
+ refunds: Object.fromEntries(Object.entries(data.refunds).map(function (_a) {
216
+ var refundAddress = _a[0], refund = _a[1];
217
+ return [toBytes32(refundAddress), refund];
218
+ })),
219
+ totalRefundAmount: data.totalRefundAmount,
220
+ realizedLpFees: data.realizedLpFees,
221
+ fills: convertSortableEventFieldsIntoRequiredFields(data.fills),
222
+ },
223
+ ];
224
+ })),
225
+ ];
226
+ }))),
227
+ expiredDepositsToRefundV3: convertTypedStringRecordIntoNumericRecord(convertEmbeddedSortableEventFieldsIntoRequiredFields(data.expiredDepositsToRefundV3)),
228
+ bundleDepositsV3: convertTypedStringRecordIntoNumericRecord(convertEmbeddedSortableEventFieldsIntoRequiredFields(data.bundleDepositsV3)),
229
+ unexecutableSlowFills: convertTypedStringRecordIntoNumericRecord(convertEmbeddedSortableEventFieldsIntoRequiredFields(data.unexecutableSlowFills)),
230
+ bundleSlowFillsV3: convertTypedStringRecordIntoNumericRecord(convertEmbeddedSortableEventFieldsIntoRequiredFields(data.bundleSlowFillsV3)),
231
+ };
232
+ this.logger.debug({
233
+ at: "BundleDataClient#loadPersistedDataFromArweave",
234
+ message: "Loaded persisted data from Arweave in ".concat(Math.round(performance.now() - start) / 1000, "s."),
235
+ blockRanges: JSON.stringify(blockRangesForChains),
236
+ bundleData: prettyPrintV3SpokePoolEvents(bundleData.bundleDepositsV3, bundleData.bundleFillsV3, bundleData.bundleSlowFillsV3, bundleData.expiredDepositsToRefundV3, bundleData.unexecutableSlowFills),
237
+ });
238
+ return [2 /*return*/, bundleData];
150
239
  }
151
- // For txnRef/transactionHash: throw if both are defined or both are missing.
152
- if ((item.txnRef !== undefined && item.transactionHash !== undefined) ||
153
- (item.txnRef === undefined && item.transactionHash === undefined)) {
154
- throw new Error("Either txnRef or transactionHash must be defined, but not both.");
240
+ });
241
+ });
242
+ };
243
+ BundleDataClient.prototype.loadArweaveData = function (blockRangesForChains) {
244
+ return __awaiter(this, void 0, void 0, function () {
245
+ var arweaveKey, arweaveData, _a, _b;
246
+ return __generator(this, function (_c) {
247
+ switch (_c.label) {
248
+ case 0:
249
+ arweaveKey = this.getArweaveBundleDataClientKey(blockRangesForChains);
250
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
251
+ if (!this.arweaveDataCache[arweaveKey]) {
252
+ this.arweaveDataCache[arweaveKey] = this.loadPersistedDataFromArweave(blockRangesForChains);
253
+ }
254
+ _b = (_a = _).cloneDeep;
255
+ return [4 /*yield*/, this.arweaveDataCache[arweaveKey]];
256
+ case 1:
257
+ arweaveData = _b.apply(_a, [_c.sent()]);
258
+ return [2 /*return*/, arweaveData];
155
259
  }
156
- // Destructure the fields we don't need anymore
157
- const { txnIndex, transactionIndex, txnRef, transactionHash, ...rest } = item;
158
- // Return a new object with normalized fields.
159
- // The non-null assertion (!) is safe here because our conditions ensure that one of each pair is defined.
160
- return {
161
- ...rest,
162
- txnIndex: txnIndex ?? transactionIndex,
163
- txnRef: txnRef ?? transactionHash,
164
- };
165
260
  });
166
- };
167
- const convertEmbeddedSortableEventFieldsIntoRequiredFields = (data) => {
168
- return Object.fromEntries(Object.entries(data).map(([chainId, tokenData]) => [
169
- chainId,
170
- Object.fromEntries(Object.entries(tokenData).map(([token, data]) => [
171
- token,
172
- convertSortableEventFieldsIntoRequiredFields(data),
173
- ])),
174
- ]));
175
- };
176
- const data = persistedData[0].data;
177
- // This section processes and transforms bundle data loaded from Arweave storage into the correct format:
178
- // 1. Each field (bundleFillsV3, expiredDepositsToRefundV3, etc.) contains nested records keyed by chainId and token
179
- // 2. The chainId keys are converted from strings to numbers using convertTypedStringRecordIntoNumericRecord
180
- // 3. For arrays of events (fills, deposits, etc.), the transaction fields are normalized:
181
- // - txnIndex/transactionIndex -> txnIndex
182
- // - txnRef/transactionHash -> txnRef
183
- // This ensures consistent field names across all event objects
184
- // 4. The data structure maintains all other fields like refunds, totalRefundAmount, and realizedLpFees
185
- const bundleData = {
186
- bundleFillsV3: convertTypedStringRecordIntoNumericRecord(Object.fromEntries(Object.entries(data.bundleFillsV3).map(([chainId, tokenData]) => [
187
- chainId,
188
- Object.fromEntries(Object.entries(tokenData).map(([token, data]) => [
189
- token,
190
- {
191
- refunds: Object.fromEntries(Object.entries(data.refunds).map(([refundAddress, refund]) => [toBytes32(refundAddress), refund])),
192
- totalRefundAmount: data.totalRefundAmount,
193
- realizedLpFees: data.realizedLpFees,
194
- fills: convertSortableEventFieldsIntoRequiredFields(data.fills),
195
- },
196
- ])),
197
- ]))),
198
- expiredDepositsToRefundV3: convertTypedStringRecordIntoNumericRecord(convertEmbeddedSortableEventFieldsIntoRequiredFields(data.expiredDepositsToRefundV3)),
199
- bundleDepositsV3: convertTypedStringRecordIntoNumericRecord(convertEmbeddedSortableEventFieldsIntoRequiredFields(data.bundleDepositsV3)),
200
- unexecutableSlowFills: convertTypedStringRecordIntoNumericRecord(convertEmbeddedSortableEventFieldsIntoRequiredFields(data.unexecutableSlowFills)),
201
- bundleSlowFillsV3: convertTypedStringRecordIntoNumericRecord(convertEmbeddedSortableEventFieldsIntoRequiredFields(data.bundleSlowFillsV3)),
202
- };
203
- this.logger.debug({
204
- at: "BundleDataClient#loadPersistedDataFromArweave",
205
- message: `Loaded persisted data from Arweave in ${Math.round(performance.now() - start) / 1000}s.`,
206
- blockRanges: JSON.stringify(blockRangesForChains),
207
- bundleData: prettyPrintV3SpokePoolEvents(bundleData.bundleDepositsV3, bundleData.bundleFillsV3, bundleData.bundleSlowFillsV3, bundleData.expiredDepositsToRefundV3, bundleData.unexecutableSlowFills),
208
261
  });
209
- return bundleData;
210
- }
211
- async loadArweaveData(blockRangesForChains) {
212
- const arweaveKey = this.getArweaveBundleDataClientKey(blockRangesForChains);
213
- // eslint-disable-next-line @typescript-eslint/no-misused-promises
214
- if (!this.arweaveDataCache[arweaveKey]) {
215
- this.arweaveDataCache[arweaveKey] = this.loadPersistedDataFromArweave(blockRangesForChains);
216
- }
217
- const arweaveData = _.cloneDeep(await this.arweaveDataCache[arweaveKey]);
218
- return arweaveData;
219
- }
262
+ };
220
263
  // Common data re-formatting logic shared across all data worker public functions.
221
264
  // User must pass in spoke pool to search event data against. This allows the user to refund relays and fill deposits
222
265
  // on deprecated spoke pools.
223
- async loadData(blockRangesForChains, spokePoolClients, attemptArweaveLoad = false) {
224
- const key = JSON.stringify(blockRangesForChains);
225
- // eslint-disable-next-line @typescript-eslint/no-misused-promises
226
- if (!this.loadDataCache[key]) {
227
- let arweaveData;
228
- if (attemptArweaveLoad) {
229
- arweaveData = await this.loadArweaveData(blockRangesForChains);
230
- }
231
- else {
232
- arweaveData = undefined;
233
- }
234
- const data = isDefined(arweaveData)
235
- ? // We can return the data to a Promise to keep the return type consistent.
236
- // Note: this is now a fast operation since we've already loaded the data from Arweave.
237
- Promise.resolve(arweaveData)
238
- : this.loadDataFromScratch(blockRangesForChains, spokePoolClients);
239
- this.loadDataCache[key] = data;
240
- }
241
- return this.loadDataFromCache(key);
242
- }
243
- async loadDataFromScratch(blockRangesForChains, spokePoolClients) {
244
- let start = performance.now();
245
- const key = JSON.stringify(blockRangesForChains);
246
- if (!this.clients.configStoreClient.isUpdated) {
247
- throw new Error("ConfigStoreClient not updated");
248
- }
249
- else if (!this.clients.hubPoolClient.isUpdated) {
250
- throw new Error("HubPoolClient not updated");
251
- }
252
- const [bundleStartBlockForMainnet, bundleEndBlockForMainnet] = blockRangesForChains[0];
253
- const chainIds = this.clients.configStoreClient.getChainIdIndicesForBlock(bundleStartBlockForMainnet);
254
- if (blockRangesForChains.length > chainIds.length) {
255
- throw new Error(`Unexpected block range list length of ${blockRangesForChains.length}, should be <= ${chainIds.length}`);
256
- }
257
- // V3 specific objects:
258
- const bundleDepositsV3 = {}; // Deposits in bundle block range.
259
- const bundleFillsV3 = {}; // Fills to refund in bundle block range.
260
- const bundleInvalidFillsV3 = []; // Fills that are not valid in this bundle.
261
- const bundleUnrepayableFillsV3 = []; // Fills that are not repayable in this bundle.
262
- const bundleInvalidSlowFillRequests = []; // Slow fill requests that are not valid in this bundle.
263
- const bundleSlowFillsV3 = {}; // Deposits that we need to send slow fills
264
- // for in this bundle.
265
- const expiredDepositsToRefundV3 = {};
266
- // Newly expired deposits in this bundle that need to be refunded.
267
- const unexecutableSlowFills = {};
268
- // Deposit data for all Slowfills that was included in a previous
269
- // bundle and can no longer be executed because (1) they were replaced with a FastFill in this bundle or
270
- // (2) the fill deadline has passed. We'll need to decrement running balances for these deposits on the
271
- // destination chain where the slow fill would have been executed.
272
- const _canCreateSlowFillLeaf = (deposit) => {
273
- return (
274
- // Cannot slow fill when input and output tokens are not equivalent.
275
- this.clients.hubPoolClient.areTokensEquivalent(deposit.inputToken, deposit.originChainId, deposit.outputToken, deposit.destinationChainId, bundleEndBlockForMainnet) &&
276
- // Cannot slow fill from or to a lite chain.
277
- !deposit.fromLiteChain &&
278
- !deposit.toLiteChain);
279
- };
280
- const _depositIsExpired = (deposit) => {
281
- return deposit.fillDeadline < bundleBlockTimestamps[deposit.destinationChainId][1];
282
- };
283
- const _getFillStatusForDeposit = (deposit, queryBlock) => {
284
- return spokePoolClients[deposit.destinationChainId].relayFillStatus(deposit,
285
- // We can assume that in production
286
- // the block to query is not one that the spoke pool client
287
- // hasn't queried. This is because this function will usually be called
288
- // in production with block ranges that were validated by
289
- // DataworkerUtils.blockRangesAreInvalidForSpokeClients.
290
- Math.min(queryBlock, spokePoolClients[deposit.destinationChainId].latestHeightSearched));
291
- };
292
- // Infer chain ID's to load from number of block ranges passed in.
293
- const allChainIds = blockRangesForChains
294
- .map((_blockRange, index) => chainIds[index])
295
- .filter((chainId) => !isChainDisabledAtBlock(chainId, bundleStartBlockForMainnet, this.clients.configStoreClient) &&
296
- spokePoolClients[chainId] !== undefined);
297
- allChainIds.forEach((chainId) => {
298
- const spokePoolClient = spokePoolClients[chainId];
299
- if (!spokePoolClient.isUpdated) {
300
- throw new Error(`SpokePoolClient for chain ${chainId} not updated.`);
301
- }
302
- });
303
- // If spoke pools are V3 contracts, then we need to compute start and end timestamps for block ranges to
304
- // determine whether fillDeadlines have expired.
305
- // @dev Going to leave this in so we can see impact on run-time in prod. This makes (allChainIds.length * 2) RPC
306
- // calls in parallel.
307
- const _cachedBundleTimestamps = this.getBundleTimestampsFromCache(key);
308
- let bundleBlockTimestamps = {};
309
- if (!_cachedBundleTimestamps) {
310
- bundleBlockTimestamps = await this.getBundleBlockTimestamps(chainIds, blockRangesForChains, spokePoolClients);
311
- this.setBundleTimestampsInCache(key, bundleBlockTimestamps);
312
- this.logger.debug({
313
- at: "BundleDataClient#loadData",
314
- message: "Bundle block timestamps",
315
- bundleBlockTimestamps,
316
- blockRangesForChains: JSON.stringify(blockRangesForChains),
266
+ BundleDataClient.prototype.loadData = function (blockRangesForChains_1, spokePoolClients_1) {
267
+ return __awaiter(this, arguments, void 0, function (blockRangesForChains, spokePoolClients, attemptArweaveLoad) {
268
+ var key, arweaveData, data;
269
+ if (attemptArweaveLoad === void 0) { attemptArweaveLoad = false; }
270
+ return __generator(this, function (_a) {
271
+ switch (_a.label) {
272
+ case 0:
273
+ key = JSON.stringify(blockRangesForChains);
274
+ if (!!this.loadDataCache[key]) return [3 /*break*/, 4];
275
+ arweaveData = void 0;
276
+ if (!attemptArweaveLoad) return [3 /*break*/, 2];
277
+ return [4 /*yield*/, this.loadArweaveData(blockRangesForChains)];
278
+ case 1:
279
+ arweaveData = _a.sent();
280
+ return [3 /*break*/, 3];
281
+ case 2:
282
+ arweaveData = undefined;
283
+ _a.label = 3;
284
+ case 3:
285
+ data = isDefined(arweaveData)
286
+ ? // We can return the data to a Promise to keep the return type consistent.
287
+ // Note: this is now a fast operation since we've already loaded the data from Arweave.
288
+ Promise.resolve(arweaveData)
289
+ : this.loadDataFromScratch(blockRangesForChains, spokePoolClients);
290
+ this.loadDataCache[key] = data;
291
+ _a.label = 4;
292
+ case 4: return [2 /*return*/, this.loadDataFromCache(key)];
293
+ }
317
294
  });
318
- }
319
- else {
320
- bundleBlockTimestamps = _cachedBundleTimestamps;
321
- }
322
- // Use this dictionary to conveniently unite all events with the same relay data hash which will make
323
- // secondary lookups faster. The goal is to lazily fill up this dictionary with all events in the SpokePool
324
- // client's in-memory event cache.
325
- const v3RelayHashes = {};
326
- // Process all deposits first and populate the v3RelayHashes dictionary. Sort deposits into whether they are
327
- // in this bundle block range or in a previous bundle block range.
328
- const bundleDepositHashes = [];
329
- const olderDepositHashes = [];
330
- const decodeBundleDepositHash = (depositHash) => {
331
- const [relayDataHash, i] = depositHash.split("@");
332
- return { relayDataHash, index: Number(i) };
333
- };
334
- // Prerequisite step: Load all deposit events from the current or older bundles into the v3RelayHashes dictionary
335
- // for convenient matching with fills.
336
- for (const originChainId of allChainIds) {
337
- const originClient = spokePoolClients[originChainId];
338
- const originChainBlockRange = getBlockRangeForChain(blockRangesForChains, originChainId, chainIds);
339
- for (const destinationChainId of allChainIds) {
340
- originClient.getDepositsForDestinationChainWithDuplicates(destinationChainId).forEach((deposit) => {
341
- if (deposit.blockNumber > originChainBlockRange[1] || isZeroValueDeposit(deposit)) {
342
- return;
343
- }
344
- const relayDataHash = getRelayEventKey(deposit);
345
- if (!v3RelayHashes[relayDataHash]) {
346
- v3RelayHashes[relayDataHash] = {
347
- deposits: [deposit],
348
- fill: undefined,
349
- slowFillRequest: undefined,
350
- };
351
- }
352
- else {
353
- const { deposits } = v3RelayHashes[relayDataHash];
354
- assert(isDefined(deposits) && deposits.length > 0, "Deposit should exist in relay hash dictionary.");
355
- deposits.push(deposit);
356
- }
357
- // Account for duplicate deposits by concatenating the relayDataHash with the count of the number of times
358
- // we have seen it so far.
359
- const { deposits } = v3RelayHashes[relayDataHash];
360
- assert(isDefined(deposits) && deposits.length > 0, "Deposit should exist in relay hash dictionary.");
361
- const newBundleDepositHash = `${relayDataHash}@${deposits.length - 1}`;
362
- const decodedBundleDepositHash = decodeBundleDepositHash(newBundleDepositHash);
363
- assert(decodedBundleDepositHash.relayDataHash === relayDataHash &&
364
- decodedBundleDepositHash.index === deposits.length - 1, "Not using correct bundle deposit hash key");
365
- if (deposit.blockNumber >= originChainBlockRange[0]) {
366
- if (bundleDepositsV3?.[originChainId]?.[deposit.inputToken.toBytes32()]?.find((d) => duplicateEvent(deposit, d))) {
367
- this.logger.debug({
368
- at: "BundleDataClient#loadData",
369
- message: "Duplicate deposit detected",
370
- deposit: convertRelayDataParamsToBytes32(deposit),
371
- });
372
- throw new Error("Duplicate deposit detected");
373
- }
374
- bundleDepositHashes.push(newBundleDepositHash);
375
- updateBundleDepositsV3(bundleDepositsV3, deposit);
376
- }
377
- else if (deposit.blockNumber < originChainBlockRange[0]) {
378
- olderDepositHashes.push(newBundleDepositHash);
379
- }
380
- });
381
- }
382
- }
383
- this.logger.debug({
384
- at: "BundleDataClient#loadData",
385
- message: `Processed ${bundleDepositHashes.length + olderDepositHashes.length} deposits in ${performance.now() - start}ms.`,
386
295
  });
387
- start = performance.now();
388
- // Process fills and maintain the following the invariants:
389
- // - Every single fill whose type is not SlowFill in the bundle block range whose relay data matches
390
- // with a deposit in the same or an older range produces a refund to the filler,
391
- // unless the specified filler address cannot be repaid on the repayment chain.
392
- // - Fills can match with duplicate deposits, so for every matched fill whose type is not SlowFill
393
- // in the bundle block range, produce a refund to the filler for each matched deposit.
394
- // - For every SlowFill in the block range that matches with multiple deposits, produce a refund to the depositor
395
- // for every deposit except except the first.
396
- // Assumptions about fills:
397
- // - Duplicate fills for the same relay data hash are impossible to send.
398
- // - Fills can only be sent before the deposit's fillDeadline.
399
- const validatedBundleV3Fills = [];
400
- const validatedBundleSlowFills = [];
401
- const validatedBundleUnexecutableSlowFills = [];
402
- let fillCounter = 0;
403
- for (const originChainId of allChainIds) {
404
- const originClient = spokePoolClients[originChainId];
405
- for (const destinationChainId of allChainIds) {
406
- const destinationClient = spokePoolClients[destinationChainId];
407
- const destinationChainBlockRange = getBlockRangeForChain(blockRangesForChains, destinationChainId, chainIds);
408
- const originChainBlockRange = getBlockRangeForChain(blockRangesForChains, originChainId, chainIds);
409
- const fastFillsReplacingSlowFills = [];
410
- await forEachAsync(destinationClient
411
- .getFillsForOriginChain(originChainId)
412
- // We can remove fills for deposits with input amount equal to zero because these will result in 0 refunded
413
- // tokens to the filler. We can't remove non-empty message deposit here in case there is a slow fill
414
- // request for the deposit, we'd want to see the fill took place.
415
- .filter((fill) => fill.blockNumber <= destinationChainBlockRange[1] &&
416
- !isZeroValueFillOrSlowFillRequest(fill) &&
417
- !invalidOutputToken(fill)), async (fill) => {
418
- fillCounter++;
419
- const relayDataHash = getRelayEventKey(fill);
420
- if (v3RelayHashes[relayDataHash]) {
421
- if (!v3RelayHashes[relayDataHash].fill) {
422
- const { deposits } = v3RelayHashes[relayDataHash];
423
- assert(isDefined(deposits) && deposits.length > 0, "Deposit should exist in relay hash dictionary.");
424
- v3RelayHashes[relayDataHash].fill = fill;
425
- if (fill.blockNumber >= destinationChainBlockRange[0]) {
426
- let provider;
427
- if (isEVMSpokePoolClient(destinationClient)) {
428
- provider = destinationClient.spokePool.provider;
429
- }
430
- else if (isSVMSpokePoolClient(destinationClient)) {
431
- provider = destinationClient.svmEventsClient.getRpc();
432
- }
433
- const fillToRefund = await verifyFillRepayment(fill, provider, deposits[0], this.clients.hubPoolClient, bundleEndBlockForMainnet);
434
- if (!isDefined(fillToRefund)) {
435
- bundleUnrepayableFillsV3.push(fill);
436
- // We don't return here yet because we still need to mark unexecutable slow fill leaves
437
- // or duplicate deposits. However, we won't issue a fast fill refund.
438
- }
439
- else {
440
- v3RelayHashes[relayDataHash].fill = fillToRefund;
441
- validatedBundleV3Fills.push({
442
- ...fillToRefund,
443
- quoteTimestamp: deposits[0].quoteTimestamp,
444
- });
445
- // Now that we know this deposit has been filled on-chain, identify any duplicate deposits
446
- // sent for this fill and refund them to the filler, because this value would not be paid out
447
- // otherwise. These deposits can no longer expire and get refunded as an expired deposit,
448
- // and they won't trigger a pre-fill refund because the fill is in this bundle.
449
- // Pre-fill refunds only happen when deposits are sent in this bundle and the
450
- // fill is from a prior bundle. Paying out the filler keeps the behavior consistent for how
451
- // we deal with duplicate deposits regardless if the deposit is matched with a pre-fill or
452
- // a current bundle fill.
453
- const duplicateDeposits = deposits.slice(1);
454
- duplicateDeposits.forEach((duplicateDeposit) => {
455
- if (isSlowFill(fill)) {
456
- updateExpiredDepositsV3(expiredDepositsToRefundV3, duplicateDeposit);
457
- }
458
- else {
459
- validatedBundleV3Fills.push({
460
- ...fillToRefund,
461
- quoteTimestamp: duplicateDeposit.quoteTimestamp,
462
- });
463
- }
464
- });
465
- }
466
- // If fill replaced a slow fill request, then mark it as one that might have created an
467
- // unexecutable slow fill. We can't know for sure until we check the slow fill request
468
- // events.
469
- if (fill.relayExecutionInfo.fillType === FillType.ReplacedSlowFill &&
470
- _canCreateSlowFillLeaf(deposits[0])) {
471
- fastFillsReplacingSlowFills.push(relayDataHash);
472
- }
473
- }
474
- }
475
- else {
476
- this.logger.debug({
477
- at: "BundleDataClient#loadData",
478
- message: "Duplicate fill detected",
479
- fill: convertFillParamsToBytes32(fill),
480
- });
481
- throw new Error("Duplicate fill detected");
296
+ };
297
+ BundleDataClient.prototype.loadDataFromScratch = function (blockRangesForChains, spokePoolClients) {
298
+ return __awaiter(this, void 0, void 0, function () {
299
+ var start, key, _a, bundleStartBlockForMainnet, bundleEndBlockForMainnet, chainIds, bundleDepositsV3, bundleFillsV3, bundleInvalidFillsV3, bundleUnrepayableFillsV3, bundleInvalidSlowFillRequests, bundleSlowFillsV3, expiredDepositsToRefundV3, unexecutableSlowFills, _canCreateSlowFillLeaf, _depositIsExpired, _getFillStatusForDeposit, allChainIds, _cachedBundleTimestamps, bundleBlockTimestamps, v3RelayHashes, bundleDepositHashes, olderDepositHashes, decodeBundleDepositHash, _loop_1, _i, allChainIds_1, originChainId, validatedBundleV3Fills, validatedBundleSlowFills, validatedBundleUnexecutableSlowFills, fillCounter, _loop_2, _b, allChainIds_2, originChainId, promises, _c, v3FillLpFees, v3SlowFillLpFees, v3UnexecutableSlowFillLpFees, v3SpokeEventsReadable, invalidFillsWithPartialMatchedDeposits_1, preFillsForNextBundle_1, unknownReasonInvalidFills_1;
300
+ var _this = this;
301
+ return __generator(this, function (_d) {
302
+ switch (_d.label) {
303
+ case 0:
304
+ start = performance.now();
305
+ key = JSON.stringify(blockRangesForChains);
306
+ if (!this.clients.configStoreClient.isUpdated) {
307
+ throw new Error("ConfigStoreClient not updated");
482
308
  }
483
- return;
484
- }
485
- // At this point, there is no relay hash dictionary entry for this fill, so we need to
486
- // instantiate the entry. We won't modify the fill.relayer until we match it with a deposit.
487
- v3RelayHashes[relayDataHash] = {
488
- deposits: undefined,
489
- fill,
490
- slowFillRequest: undefined,
491
- };
492
- // TODO: We can remove the following historical query once we deprecate the deposit()
493
- // function since there won't be any old, unexpired deposits anymore assuming the spoke pool client
494
- // lookbacks have been validated, which they should be before we run this function.
495
- // Since there was no deposit matching the relay hash, we need to do a historical query for an
496
- // older deposit in case the spoke pool client's lookback isn't old enough to find the matching deposit.
497
- // We can skip this step if the fill's fill deadline is not infinite, because we can assume that the
498
- // spoke pool clients have loaded deposits old enough to cover all fills with a non-infinite fill deadline.
499
- if (fill.blockNumber >= destinationChainBlockRange[0]) {
500
- // Fill has a non-infinite expiry, and we can assume our spoke pool clients have old enough deposits
501
- // to conclude that this fill is invalid if we haven't found a matching deposit in memory, so
502
- // skip the historical query.
503
- if (!INFINITE_FILL_DEADLINE.eq(fill.fillDeadline)) {
504
- bundleInvalidFillsV3.push(fill);
505
- return;
309
+ else if (!this.clients.hubPoolClient.isUpdated) {
310
+ throw new Error("HubPoolClient not updated");
506
311
  }
507
- // If deposit is using the deterministic relay hash feature, then the following binary search-based
508
- // algorithm will not work. However, it is impossible to emit an infinite fill deadline using
509
- // the unsafeDepositV3 function so there is no need to catch the special case.
510
- const historicalDeposit = await queryHistoricalDepositForFill(originClient, fill);
511
- if (!historicalDeposit.found) {
512
- bundleInvalidFillsV3.push(fill);
312
+ _a = blockRangesForChains[0], bundleStartBlockForMainnet = _a[0], bundleEndBlockForMainnet = _a[1];
313
+ chainIds = this.clients.configStoreClient.getChainIdIndicesForBlock(bundleStartBlockForMainnet);
314
+ if (blockRangesForChains.length > chainIds.length) {
315
+ throw new Error("Unexpected block range list length of ".concat(blockRangesForChains.length, ", should be <= ").concat(chainIds.length));
513
316
  }
514
- else {
515
- const matchedDeposit = historicalDeposit.deposit;
516
- // If deposit is in a following bundle, then this fill will have to be refunded once that deposit
517
- // is in the current bundle.
518
- if (matchedDeposit.blockNumber > originChainBlockRange[1]) {
519
- bundleInvalidFillsV3.push(fill);
520
- return;
521
- }
522
- v3RelayHashes[relayDataHash].deposits = [matchedDeposit];
523
- let provider;
524
- if (isEVMSpokePoolClient(destinationClient)) {
525
- provider = destinationClient.spokePool.provider;
526
- }
527
- else if (isSVMSpokePoolClient(destinationClient)) {
528
- provider = destinationClient.svmEventsClient.getRpc();
529
- }
530
- const fillToRefund = await verifyFillRepayment(fill, provider, matchedDeposit, this.clients.hubPoolClient, bundleEndBlockForMainnet);
531
- if (!isDefined(fillToRefund)) {
532
- bundleUnrepayableFillsV3.push(fill);
533
- // Don't return yet as we still need to mark down any unexecutable slow fill leaves
534
- // in case this fast fill replaced a slow fill request.
317
+ bundleDepositsV3 = {};
318
+ bundleFillsV3 = {};
319
+ bundleInvalidFillsV3 = [];
320
+ bundleUnrepayableFillsV3 = [];
321
+ bundleInvalidSlowFillRequests = [];
322
+ bundleSlowFillsV3 = {};
323
+ expiredDepositsToRefundV3 = {};
324
+ unexecutableSlowFills = {};
325
+ _canCreateSlowFillLeaf = function (deposit) {
326
+ return (
327
+ // Cannot slow fill when input and output tokens are not equivalent.
328
+ _this.clients.hubPoolClient.areTokensEquivalent(deposit.inputToken, deposit.originChainId, deposit.outputToken, deposit.destinationChainId, bundleEndBlockForMainnet) &&
329
+ // Cannot slow fill from or to a lite chain.
330
+ !deposit.fromLiteChain &&
331
+ !deposit.toLiteChain);
332
+ };
333
+ _depositIsExpired = function (deposit) {
334
+ return deposit.fillDeadline < bundleBlockTimestamps[deposit.destinationChainId][1];
335
+ };
336
+ _getFillStatusForDeposit = function (deposit, queryBlock) {
337
+ return spokePoolClients[deposit.destinationChainId].relayFillStatus(deposit,
338
+ // We can assume that in production
339
+ // the block to query is not one that the spoke pool client
340
+ // hasn't queried. This is because this function will usually be called
341
+ // in production with block ranges that were validated by
342
+ // DataworkerUtils.blockRangesAreInvalidForSpokeClients.
343
+ Math.min(queryBlock, spokePoolClients[deposit.destinationChainId].latestHeightSearched));
344
+ };
345
+ allChainIds = blockRangesForChains
346
+ .map(function (_blockRange, index) { return chainIds[index]; })
347
+ .filter(function (chainId) {
348
+ return !isChainDisabledAtBlock(chainId, bundleStartBlockForMainnet, _this.clients.configStoreClient) &&
349
+ spokePoolClients[chainId] !== undefined;
350
+ });
351
+ allChainIds.forEach(function (chainId) {
352
+ var spokePoolClient = spokePoolClients[chainId];
353
+ if (!spokePoolClient.isUpdated) {
354
+ throw new Error("SpokePoolClient for chain ".concat(chainId, " not updated."));
535
355
  }
536
- else {
537
- // @dev Since queryHistoricalDepositForFill validates the fill by checking individual
538
- // object property values against the deposit's, we
539
- // sanity check it here by comparing the full relay hashes. If there's an error here then the
540
- // historical deposit query is not working as expected.
541
- assert(getRelayEventKey(matchedDeposit) === relayDataHash, "Relay hashes should match.");
542
- validatedBundleV3Fills.push({
543
- ...fillToRefund,
544
- quoteTimestamp: matchedDeposit.quoteTimestamp,
356
+ });
357
+ _cachedBundleTimestamps = this.getBundleTimestampsFromCache(key);
358
+ bundleBlockTimestamps = {};
359
+ if (!!_cachedBundleTimestamps) return [3 /*break*/, 2];
360
+ return [4 /*yield*/, this.getBundleBlockTimestamps(chainIds, blockRangesForChains, spokePoolClients)];
361
+ case 1:
362
+ bundleBlockTimestamps = _d.sent();
363
+ this.setBundleTimestampsInCache(key, bundleBlockTimestamps);
364
+ this.logger.debug({
365
+ at: "BundleDataClient#loadData",
366
+ message: "Bundle block timestamps",
367
+ bundleBlockTimestamps: bundleBlockTimestamps,
368
+ blockRangesForChains: JSON.stringify(blockRangesForChains),
369
+ });
370
+ return [3 /*break*/, 3];
371
+ case 2:
372
+ bundleBlockTimestamps = _cachedBundleTimestamps;
373
+ _d.label = 3;
374
+ case 3:
375
+ v3RelayHashes = {};
376
+ bundleDepositHashes = [];
377
+ olderDepositHashes = [];
378
+ decodeBundleDepositHash = function (depositHash) {
379
+ var _a = depositHash.split("@"), relayDataHash = _a[0], i = _a[1];
380
+ return { relayDataHash: relayDataHash, index: Number(i) };
381
+ };
382
+ _loop_1 = function (originChainId) {
383
+ var originClient = spokePoolClients[originChainId];
384
+ var originChainBlockRange = getBlockRangeForChain(blockRangesForChains, originChainId, chainIds);
385
+ for (var _e = 0, allChainIds_3 = allChainIds; _e < allChainIds_3.length; _e++) {
386
+ var destinationChainId = allChainIds_3[_e];
387
+ originClient.getDepositsForDestinationChainWithDuplicates(destinationChainId).forEach(function (deposit) {
388
+ var _a, _b;
389
+ if (deposit.blockNumber > originChainBlockRange[1] || isZeroValueDeposit(deposit)) {
390
+ return;
391
+ }
392
+ var relayDataHash = getRelayEventKey(deposit);
393
+ if (!v3RelayHashes[relayDataHash]) {
394
+ v3RelayHashes[relayDataHash] = {
395
+ deposits: [deposit],
396
+ fill: undefined,
397
+ slowFillRequest: undefined,
398
+ };
399
+ }
400
+ else {
401
+ var deposits_1 = v3RelayHashes[relayDataHash].deposits;
402
+ assert(isDefined(deposits_1) && deposits_1.length > 0, "Deposit should exist in relay hash dictionary.");
403
+ deposits_1.push(deposit);
404
+ }
405
+ // Account for duplicate deposits by concatenating the relayDataHash with the count of the number of times
406
+ // we have seen it so far.
407
+ var deposits = v3RelayHashes[relayDataHash].deposits;
408
+ assert(isDefined(deposits) && deposits.length > 0, "Deposit should exist in relay hash dictionary.");
409
+ var newBundleDepositHash = "".concat(relayDataHash, "@").concat(deposits.length - 1);
410
+ var decodedBundleDepositHash = decodeBundleDepositHash(newBundleDepositHash);
411
+ assert(decodedBundleDepositHash.relayDataHash === relayDataHash &&
412
+ decodedBundleDepositHash.index === deposits.length - 1, "Not using correct bundle deposit hash key");
413
+ if (deposit.blockNumber >= originChainBlockRange[0]) {
414
+ if ((_b = (_a = bundleDepositsV3 === null || bundleDepositsV3 === void 0 ? void 0 : bundleDepositsV3[originChainId]) === null || _a === void 0 ? void 0 : _a[deposit.inputToken.toBytes32()]) === null || _b === void 0 ? void 0 : _b.find(function (d) {
415
+ return duplicateEvent(deposit, d);
416
+ })) {
417
+ _this.logger.debug({
418
+ at: "BundleDataClient#loadData",
419
+ message: "Duplicate deposit detected",
420
+ deposit: convertRelayDataParamsToBytes32(deposit),
421
+ });
422
+ throw new Error("Duplicate deposit detected");
423
+ }
424
+ bundleDepositHashes.push(newBundleDepositHash);
425
+ updateBundleDepositsV3(bundleDepositsV3, deposit);
426
+ }
427
+ else if (deposit.blockNumber < originChainBlockRange[0]) {
428
+ olderDepositHashes.push(newBundleDepositHash);
429
+ }
545
430
  });
546
- v3RelayHashes[relayDataHash].fill = fillToRefund;
547
- // No need to check for duplicate deposits here since duplicate deposits with
548
- // infinite deadlines are impossible to send via unsafeDeposit().
549
- }
550
- if (fill.relayExecutionInfo.fillType === FillType.ReplacedSlowFill &&
551
- _canCreateSlowFillLeaf(matchedDeposit)) {
552
- fastFillsReplacingSlowFills.push(relayDataHash);
553
431
  }
432
+ };
433
+ // Prerequisite step: Load all deposit events from the current or older bundles into the v3RelayHashes dictionary
434
+ // for convenient matching with fills.
435
+ for (_i = 0, allChainIds_1 = allChainIds; _i < allChainIds_1.length; _i++) {
436
+ originChainId = allChainIds_1[_i];
437
+ _loop_1(originChainId);
554
438
  }
555
- }
556
- });
557
- // Process slow fill requests and produce slow fill leaves while maintaining the following the invariants:
558
- // - Slow fill leaves cannot be produced for deposits that have expired in this bundle.
559
- // - Slow fill leaves cannot be produced for deposits that have been filled.
560
- // Assumptions about fills:
561
- // - Duplicate slow fill requests for the same relay data hash are impossible to send.
562
- // - Slow fill requests can only be sent before the deposit's fillDeadline.
563
- // - Slow fill requests for a deposit that has been filled.
564
- await forEachAsync(destinationClient
565
- .getSlowFillRequestsForOriginChain(originChainId)
566
- .filter((request) => request.blockNumber <= destinationChainBlockRange[1] &&
567
- !isZeroValueFillOrSlowFillRequest(request) &&
568
- !invalidOutputToken(request)), async (slowFillRequest) => {
569
- const relayDataHash = getRelayEventKey(slowFillRequest);
570
- if (v3RelayHashes[relayDataHash]) {
571
- if (!v3RelayHashes[relayDataHash].slowFillRequest) {
572
- v3RelayHashes[relayDataHash].slowFillRequest = slowFillRequest;
573
- const { deposits, fill } = v3RelayHashes[relayDataHash];
574
- if (fill) {
575
- // Exiting here assumes that slow fill requests must precede fills, so if there was a fill
576
- // following this slow fill request, then we would have already seen it. We don't need to check
577
- // for a fill older than this slow fill request.
578
- return;
579
- }
439
+ this.logger.debug({
440
+ at: "BundleDataClient#loadData",
441
+ message: "Processed ".concat(bundleDepositHashes.length + olderDepositHashes.length, " deposits in ").concat(performance.now() - start, "ms."),
442
+ });
443
+ start = performance.now();
444
+ validatedBundleV3Fills = [];
445
+ validatedBundleSlowFills = [];
446
+ validatedBundleUnexecutableSlowFills = [];
447
+ fillCounter = 0;
448
+ _loop_2 = function (originChainId) {
449
+ var originClient, _loop_3, _f, allChainIds_4, destinationChainId;
450
+ return __generator(this, function (_g) {
451
+ switch (_g.label) {
452
+ case 0:
453
+ originClient = spokePoolClients[originChainId];
454
+ _loop_3 = function (destinationChainId) {
455
+ var destinationClient, destinationChainBlockRange, originChainBlockRange, fastFillsReplacingSlowFills;
456
+ return __generator(this, function (_h) {
457
+ switch (_h.label) {
458
+ case 0:
459
+ destinationClient = spokePoolClients[destinationChainId];
460
+ destinationChainBlockRange = getBlockRangeForChain(blockRangesForChains, destinationChainId, chainIds);
461
+ originChainBlockRange = getBlockRangeForChain(blockRangesForChains, originChainId, chainIds);
462
+ fastFillsReplacingSlowFills = [];
463
+ return [4 /*yield*/, forEachAsync(destinationClient
464
+ .getFillsForOriginChain(originChainId)
465
+ // We can remove fills for deposits with input amount equal to zero because these will result in 0 refunded
466
+ // tokens to the filler. We can't remove non-empty message deposit here in case there is a slow fill
467
+ // request for the deposit, we'd want to see the fill took place.
468
+ .filter(function (fill) {
469
+ return fill.blockNumber <= destinationChainBlockRange[1] &&
470
+ !isZeroValueFillOrSlowFillRequest(fill) &&
471
+ !invalidOutputToken(fill);
472
+ }), function (fill) { return __awaiter(_this, void 0, void 0, function () {
473
+ var relayDataHash, deposits, provider, fillToRefund_1, duplicateDeposits, historicalDeposit, matchedDeposit, provider, fillToRefund;
474
+ return __generator(this, function (_a) {
475
+ switch (_a.label) {
476
+ case 0:
477
+ fillCounter++;
478
+ relayDataHash = getRelayEventKey(fill);
479
+ if (!v3RelayHashes[relayDataHash]) return [3 /*break*/, 5];
480
+ if (!!v3RelayHashes[relayDataHash].fill) return [3 /*break*/, 3];
481
+ deposits = v3RelayHashes[relayDataHash].deposits;
482
+ assert(isDefined(deposits) && deposits.length > 0, "Deposit should exist in relay hash dictionary.");
483
+ v3RelayHashes[relayDataHash].fill = fill;
484
+ if (!(fill.blockNumber >= destinationChainBlockRange[0])) return [3 /*break*/, 2];
485
+ provider = void 0;
486
+ if (isEVMSpokePoolClient(destinationClient)) {
487
+ provider = destinationClient.spokePool.provider;
488
+ }
489
+ else if (isSVMSpokePoolClient(destinationClient)) {
490
+ provider = destinationClient.svmEventsClient.getRpc();
491
+ }
492
+ return [4 /*yield*/, verifyFillRepayment(fill, provider, deposits[0], this.clients.hubPoolClient, bundleEndBlockForMainnet)];
493
+ case 1:
494
+ fillToRefund_1 = _a.sent();
495
+ if (!isDefined(fillToRefund_1)) {
496
+ bundleUnrepayableFillsV3.push(fill);
497
+ // We don't return here yet because we still need to mark unexecutable slow fill leaves
498
+ // or duplicate deposits. However, we won't issue a fast fill refund.
499
+ }
500
+ else {
501
+ v3RelayHashes[relayDataHash].fill = fillToRefund_1;
502
+ validatedBundleV3Fills.push(__assign(__assign({}, fillToRefund_1), { quoteTimestamp: deposits[0].quoteTimestamp }));
503
+ duplicateDeposits = deposits.slice(1);
504
+ duplicateDeposits.forEach(function (duplicateDeposit) {
505
+ if (isSlowFill(fill)) {
506
+ updateExpiredDepositsV3(expiredDepositsToRefundV3, duplicateDeposit);
507
+ }
508
+ else {
509
+ validatedBundleV3Fills.push(__assign(__assign({}, fillToRefund_1), { quoteTimestamp: duplicateDeposit.quoteTimestamp }));
510
+ }
511
+ });
512
+ }
513
+ // If fill replaced a slow fill request, then mark it as one that might have created an
514
+ // unexecutable slow fill. We can't know for sure until we check the slow fill request
515
+ // events.
516
+ if (fill.relayExecutionInfo.fillType === FillType.ReplacedSlowFill &&
517
+ _canCreateSlowFillLeaf(deposits[0])) {
518
+ fastFillsReplacingSlowFills.push(relayDataHash);
519
+ }
520
+ _a.label = 2;
521
+ case 2: return [3 /*break*/, 4];
522
+ case 3:
523
+ this.logger.debug({
524
+ at: "BundleDataClient#loadData",
525
+ message: "Duplicate fill detected",
526
+ fill: convertFillParamsToBytes32(fill),
527
+ });
528
+ throw new Error("Duplicate fill detected");
529
+ case 4: return [2 /*return*/];
530
+ case 5:
531
+ // At this point, there is no relay hash dictionary entry for this fill, so we need to
532
+ // instantiate the entry. We won't modify the fill.relayer until we match it with a deposit.
533
+ v3RelayHashes[relayDataHash] = {
534
+ deposits: undefined,
535
+ fill: fill,
536
+ slowFillRequest: undefined,
537
+ };
538
+ if (!(fill.blockNumber >= destinationChainBlockRange[0])) return [3 /*break*/, 9];
539
+ // Fill has a non-infinite expiry, and we can assume our spoke pool clients have old enough deposits
540
+ // to conclude that this fill is invalid if we haven't found a matching deposit in memory, so
541
+ // skip the historical query.
542
+ if (!INFINITE_FILL_DEADLINE.eq(fill.fillDeadline)) {
543
+ bundleInvalidFillsV3.push(fill);
544
+ return [2 /*return*/];
545
+ }
546
+ return [4 /*yield*/, queryHistoricalDepositForFill(originClient, fill)];
547
+ case 6:
548
+ historicalDeposit = _a.sent();
549
+ if (!!historicalDeposit.found) return [3 /*break*/, 7];
550
+ bundleInvalidFillsV3.push(fill);
551
+ return [3 /*break*/, 9];
552
+ case 7:
553
+ matchedDeposit = historicalDeposit.deposit;
554
+ // If deposit is in a following bundle, then this fill will have to be refunded once that deposit
555
+ // is in the current bundle.
556
+ if (matchedDeposit.blockNumber > originChainBlockRange[1]) {
557
+ bundleInvalidFillsV3.push(fill);
558
+ return [2 /*return*/];
559
+ }
560
+ v3RelayHashes[relayDataHash].deposits = [matchedDeposit];
561
+ provider = void 0;
562
+ if (isEVMSpokePoolClient(destinationClient)) {
563
+ provider = destinationClient.spokePool.provider;
564
+ }
565
+ else if (isSVMSpokePoolClient(destinationClient)) {
566
+ provider = destinationClient.svmEventsClient.getRpc();
567
+ }
568
+ return [4 /*yield*/, verifyFillRepayment(fill, provider, matchedDeposit, this.clients.hubPoolClient, bundleEndBlockForMainnet)];
569
+ case 8:
570
+ fillToRefund = _a.sent();
571
+ if (!isDefined(fillToRefund)) {
572
+ bundleUnrepayableFillsV3.push(fill);
573
+ // Don't return yet as we still need to mark down any unexecutable slow fill leaves
574
+ // in case this fast fill replaced a slow fill request.
575
+ }
576
+ else {
577
+ // @dev Since queryHistoricalDepositForFill validates the fill by checking individual
578
+ // object property values against the deposit's, we
579
+ // sanity check it here by comparing the full relay hashes. If there's an error here then the
580
+ // historical deposit query is not working as expected.
581
+ assert(getRelayEventKey(matchedDeposit) === relayDataHash, "Relay hashes should match.");
582
+ validatedBundleV3Fills.push(__assign(__assign({}, fillToRefund), { quoteTimestamp: matchedDeposit.quoteTimestamp }));
583
+ v3RelayHashes[relayDataHash].fill = fillToRefund;
584
+ // No need to check for duplicate deposits here since duplicate deposits with
585
+ // infinite deadlines are impossible to send via unsafeDeposit().
586
+ }
587
+ if (fill.relayExecutionInfo.fillType === FillType.ReplacedSlowFill &&
588
+ _canCreateSlowFillLeaf(matchedDeposit)) {
589
+ fastFillsReplacingSlowFills.push(relayDataHash);
590
+ }
591
+ _a.label = 9;
592
+ case 9: return [2 /*return*/];
593
+ }
594
+ });
595
+ }); })];
596
+ case 1:
597
+ _h.sent();
598
+ // Process slow fill requests and produce slow fill leaves while maintaining the following the invariants:
599
+ // - Slow fill leaves cannot be produced for deposits that have expired in this bundle.
600
+ // - Slow fill leaves cannot be produced for deposits that have been filled.
601
+ // Assumptions about fills:
602
+ // - Duplicate slow fill requests for the same relay data hash are impossible to send.
603
+ // - Slow fill requests can only be sent before the deposit's fillDeadline.
604
+ // - Slow fill requests for a deposit that has been filled.
605
+ return [4 /*yield*/, forEachAsync(destinationClient
606
+ .getSlowFillRequestsForOriginChain(originChainId)
607
+ .filter(function (request) {
608
+ return request.blockNumber <= destinationChainBlockRange[1] &&
609
+ !isZeroValueFillOrSlowFillRequest(request) &&
610
+ !invalidOutputToken(request);
611
+ }), function (slowFillRequest) { return __awaiter(_this, void 0, void 0, function () {
612
+ var relayDataHash, _a, deposits, fill, matchedDeposit, historicalDeposit, matchedDeposit;
613
+ return __generator(this, function (_b) {
614
+ switch (_b.label) {
615
+ case 0:
616
+ relayDataHash = getRelayEventKey(slowFillRequest);
617
+ if (v3RelayHashes[relayDataHash]) {
618
+ if (!v3RelayHashes[relayDataHash].slowFillRequest) {
619
+ v3RelayHashes[relayDataHash].slowFillRequest = slowFillRequest;
620
+ _a = v3RelayHashes[relayDataHash], deposits = _a.deposits, fill = _a.fill;
621
+ if (fill) {
622
+ // Exiting here assumes that slow fill requests must precede fills, so if there was a fill
623
+ // following this slow fill request, then we would have already seen it. We don't need to check
624
+ // for a fill older than this slow fill request.
625
+ return [2 /*return*/];
626
+ }
627
+ assert(isDefined(deposits) && deposits.length > 0, "Deposit should exist in relay hash dictionary.");
628
+ matchedDeposit = deposits[0];
629
+ if (slowFillRequest.blockNumber >= destinationChainBlockRange[0] &&
630
+ _canCreateSlowFillLeaf(matchedDeposit) &&
631
+ !_depositIsExpired(matchedDeposit)) {
632
+ validatedBundleSlowFills.push(matchedDeposit);
633
+ }
634
+ }
635
+ else {
636
+ this.logger.debug({
637
+ at: "BundleDataClient#loadData",
638
+ message: "Duplicate slow fill request detected",
639
+ slowFillRequest: slowFillRequest,
640
+ });
641
+ throw new Error("Duplicate slow fill request detected.");
642
+ }
643
+ return [2 /*return*/];
644
+ }
645
+ // Instantiate dictionary if there is neither a deposit nor fill matching it.
646
+ v3RelayHashes[relayDataHash] = {
647
+ deposits: undefined,
648
+ fill: undefined,
649
+ slowFillRequest: slowFillRequest,
650
+ };
651
+ if (!(slowFillRequest.blockNumber >= destinationChainBlockRange[0])) return [3 /*break*/, 2];
652
+ if (!INFINITE_FILL_DEADLINE.eq(slowFillRequest.fillDeadline)) {
653
+ bundleInvalidSlowFillRequests.push(slowFillRequest);
654
+ return [2 /*return*/];
655
+ }
656
+ return [4 /*yield*/, queryHistoricalDepositForFill(originClient, slowFillRequest)];
657
+ case 1:
658
+ historicalDeposit = _b.sent();
659
+ if (!historicalDeposit.found) {
660
+ bundleInvalidSlowFillRequests.push(slowFillRequest);
661
+ return [2 /*return*/];
662
+ }
663
+ matchedDeposit = historicalDeposit.deposit;
664
+ // If deposit is in a following bundle, then this slow fill request will have to be created
665
+ // once that deposit is in the current bundle.
666
+ if (matchedDeposit.blockNumber > originChainBlockRange[1]) {
667
+ bundleInvalidSlowFillRequests.push(slowFillRequest);
668
+ return [2 /*return*/];
669
+ }
670
+ // @dev Since queryHistoricalDepositForFill validates the slow fill request by checking individual
671
+ // object property values against the deposit's, we
672
+ // sanity check it here by comparing the full relay hashes. If there's an error here then the
673
+ // historical deposit query is not working as expected.
674
+ assert(getRelayEventKey(matchedDeposit) === relayDataHash, "Deposit relay hashes should match.");
675
+ v3RelayHashes[relayDataHash].deposits = [matchedDeposit];
676
+ if (!_canCreateSlowFillLeaf(matchedDeposit) || _depositIsExpired(matchedDeposit)) {
677
+ return [2 /*return*/];
678
+ }
679
+ validatedBundleSlowFills.push(matchedDeposit);
680
+ _b.label = 2;
681
+ case 2: return [2 /*return*/];
682
+ }
683
+ });
684
+ }); })];
685
+ case 2:
686
+ // Process slow fill requests and produce slow fill leaves while maintaining the following the invariants:
687
+ // - Slow fill leaves cannot be produced for deposits that have expired in this bundle.
688
+ // - Slow fill leaves cannot be produced for deposits that have been filled.
689
+ // Assumptions about fills:
690
+ // - Duplicate slow fill requests for the same relay data hash are impossible to send.
691
+ // - Slow fill requests can only be sent before the deposit's fillDeadline.
692
+ // - Slow fill requests for a deposit that has been filled.
693
+ _h.sent();
694
+ // Process deposits and maintain the following invariants:
695
+ // - Deposits matching fills that are not type SlowFill from previous bundle block ranges should produce
696
+ // refunds for those fills.
697
+ // - Deposits matching fills that are type SlowFill from previous bundle block ranges should be refunded to the
698
+ // depositor.
699
+ // - All deposits expiring in this bundle, even those sent in prior bundle block ranges, should be refunded
700
+ // to the depositor.
701
+ // - An expired deposit cannot be refunded if the deposit was filled.
702
+ // - If a deposit from a prior bundle expired in this bundle, had a slow fill request created for it
703
+ // in a prior bundle, and has not been filled yet, then an unexecutable slow fill leaf has been created
704
+ // and needs to be refunded to the HubPool.
705
+ // - Deposits matching slow fill requests from previous bundle block ranges should produce slow fills
706
+ // if the deposit has not been filled.
707
+ // Assumptions:
708
+ // - If the deposit has a matching fill or slow fill request in the bundle then we have already stored
709
+ // it in the relay hashes dictionary.
710
+ // - We've created refunds for all fills in this bundle matching a deposit.
711
+ // - We've created slow fill leaves for all slow fill requests in this bundle matching an unfilled deposit.
712
+ // - Deposits for the same relay data hash can be sent an arbitrary amount of times.
713
+ // - Deposits can be sent an arbitrary amount of time after a fill has been sent for the matching relay data.
714
+ return [4 /*yield*/, mapAsync(bundleDepositHashes, function (depositHash) { return __awaiter(_this, void 0, void 0, function () {
715
+ var _a, relayDataHash, index, _b, deposits, fill, slowFillRequest, deposit, provider, fillToRefund, fillStatus, prefill, provider, verifiedFill;
716
+ return __generator(this, function (_c) {
717
+ switch (_c.label) {
718
+ case 0:
719
+ _a = decodeBundleDepositHash(depositHash), relayDataHash = _a.relayDataHash, index = _a.index;
720
+ _b = v3RelayHashes[relayDataHash], deposits = _b.deposits, fill = _b.fill, slowFillRequest = _b.slowFillRequest;
721
+ if (!deposits || deposits.length === 0) {
722
+ throw new Error("Deposits should exist in relay hash dictionary.");
723
+ }
724
+ deposit = deposits[index];
725
+ if (!deposit)
726
+ throw new Error("Deposit should exist in relay hash dictionary.");
727
+ if (deposit.originChainId !== originChainId || deposit.destinationChainId !== destinationChainId) {
728
+ return [2 /*return*/];
729
+ }
730
+ if (!fill) return [3 /*break*/, 3];
731
+ if (!(fill.blockNumber < destinationChainBlockRange[0])) return [3 /*break*/, 2];
732
+ provider = void 0;
733
+ if (isEVMSpokePoolClient(destinationClient)) {
734
+ provider = destinationClient.spokePool.provider;
735
+ }
736
+ else if (isSVMSpokePoolClient(destinationClient)) {
737
+ provider = destinationClient.svmEventsClient.getRpc();
738
+ }
739
+ return [4 /*yield*/, verifyFillRepayment(fill, provider, deposits[0], this.clients.hubPoolClient, bundleEndBlockForMainnet)];
740
+ case 1:
741
+ fillToRefund = _c.sent();
742
+ if (!isDefined(fillToRefund)) {
743
+ bundleUnrepayableFillsV3.push(fill);
744
+ }
745
+ else if (!isSlowFill(fill)) {
746
+ v3RelayHashes[relayDataHash].fill = fillToRefund;
747
+ validatedBundleV3Fills.push(__assign(__assign({}, fillToRefund), { quoteTimestamp: deposit.quoteTimestamp }));
748
+ }
749
+ else {
750
+ updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
751
+ }
752
+ _c.label = 2;
753
+ case 2: return [2 /*return*/];
754
+ case 3:
755
+ // If a slow fill request exists in memory, then we know the deposit has not been filled because fills
756
+ // must follow slow fill requests and we would have seen the fill already if it existed.,
757
+ // We can conclude that either the deposit has expired or we need to create a slow fill leaf for the
758
+ // deposit because it has not been filled. Slow fill leaves were already created for requests sent
759
+ // in the current bundle so only create new slow fill leaves for prior bundle deposits.
760
+ if (slowFillRequest) {
761
+ if (_depositIsExpired(deposit)) {
762
+ updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
763
+ }
764
+ else if (slowFillRequest.blockNumber < destinationChainBlockRange[0] &&
765
+ _canCreateSlowFillLeaf(deposit) &&
766
+ validatedBundleSlowFills.every(function (d) { return getRelayEventKey(d) !== relayDataHash; })) {
767
+ validatedBundleSlowFills.push(deposit);
768
+ }
769
+ return [2 /*return*/];
770
+ }
771
+ return [4 /*yield*/, _getFillStatusForDeposit(deposit, destinationChainBlockRange[1])];
772
+ case 4:
773
+ fillStatus = _c.sent();
774
+ if (!(fillStatus === FillStatus.Filled)) return [3 /*break*/, 7];
775
+ return [4 /*yield*/, this.findMatchingFillEvent(deposit, destinationClient)];
776
+ case 5:
777
+ prefill = _c.sent();
778
+ assert(isDefined(prefill), "findFillEvent# Cannot find prefill: ".concat(relayDataHash));
779
+ assert(getRelayEventKey(prefill) === relayDataHash, "Relay hashes should match.");
780
+ provider = void 0;
781
+ if (isEVMSpokePoolClient(destinationClient)) {
782
+ provider = destinationClient.spokePool.provider;
783
+ }
784
+ else if (isSVMSpokePoolClient(destinationClient)) {
785
+ provider = destinationClient.svmEventsClient.getRpc();
786
+ }
787
+ return [4 /*yield*/, verifyFillRepayment(prefill, provider, deposit, this.clients.hubPoolClient, bundleEndBlockForMainnet)];
788
+ case 6:
789
+ verifiedFill = _c.sent();
790
+ if (!isDefined(verifiedFill)) {
791
+ bundleUnrepayableFillsV3.push(prefill);
792
+ }
793
+ else if (!isSlowFill(verifiedFill)) {
794
+ validatedBundleV3Fills.push(__assign(__assign({}, verifiedFill), { quoteTimestamp: deposit.quoteTimestamp }));
795
+ }
796
+ else {
797
+ updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
798
+ }
799
+ return [3 /*break*/, 8];
800
+ case 7:
801
+ if (_depositIsExpired(deposit)) {
802
+ updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
803
+ }
804
+ else if (fillStatus === FillStatus.RequestedSlowFill &&
805
+ // Don't create duplicate slow fill requests for the same deposit.
806
+ validatedBundleSlowFills.every(function (d) { return getRelayEventKey(d) !== relayDataHash; })) {
807
+ if (_canCreateSlowFillLeaf(deposit)) {
808
+ validatedBundleSlowFills.push(deposit);
809
+ }
810
+ }
811
+ _c.label = 8;
812
+ case 8: return [2 /*return*/];
813
+ }
814
+ });
815
+ }); })];
816
+ case 3:
817
+ // Process deposits and maintain the following invariants:
818
+ // - Deposits matching fills that are not type SlowFill from previous bundle block ranges should produce
819
+ // refunds for those fills.
820
+ // - Deposits matching fills that are type SlowFill from previous bundle block ranges should be refunded to the
821
+ // depositor.
822
+ // - All deposits expiring in this bundle, even those sent in prior bundle block ranges, should be refunded
823
+ // to the depositor.
824
+ // - An expired deposit cannot be refunded if the deposit was filled.
825
+ // - If a deposit from a prior bundle expired in this bundle, had a slow fill request created for it
826
+ // in a prior bundle, and has not been filled yet, then an unexecutable slow fill leaf has been created
827
+ // and needs to be refunded to the HubPool.
828
+ // - Deposits matching slow fill requests from previous bundle block ranges should produce slow fills
829
+ // if the deposit has not been filled.
830
+ // Assumptions:
831
+ // - If the deposit has a matching fill or slow fill request in the bundle then we have already stored
832
+ // it in the relay hashes dictionary.
833
+ // - We've created refunds for all fills in this bundle matching a deposit.
834
+ // - We've created slow fill leaves for all slow fill requests in this bundle matching an unfilled deposit.
835
+ // - Deposits for the same relay data hash can be sent an arbitrary amount of times.
836
+ // - Deposits can be sent an arbitrary amount of time after a fill has been sent for the matching relay data.
837
+ _h.sent();
838
+ // For all fills that came after a slow fill request, we can now check if the slow fill request
839
+ // was a valid one and whether it was created in a previous bundle. If so, then it created a slow fill
840
+ // leaf that is now unexecutable.
841
+ fastFillsReplacingSlowFills.forEach(function (relayDataHash) {
842
+ var _a = v3RelayHashes[relayDataHash], deposits = _a.deposits, slowFillRequest = _a.slowFillRequest, fill = _a.fill;
843
+ assert((fill === null || fill === void 0 ? void 0 : fill.relayExecutionInfo.fillType) === FillType.ReplacedSlowFill, "Fill type should be ReplacedSlowFill.");
844
+ // Needed for TSC - are implicitly checking that deposit exists by making it to this point.
845
+ if (!deposits || deposits.length < 1) {
846
+ throw new Error("Deposit should exist in relay hash dictionary.");
847
+ }
848
+ // We should never push fast fills involving lite chains here because slow fill requests for them are invalid:
849
+ assert(_canCreateSlowFillLeaf(deposits[0]), "fastFillsReplacingSlowFills should contain only deposits that can be slow filled");
850
+ var destinationBlockRange = getBlockRangeForChain(blockRangesForChains, destinationChainId, chainIds);
851
+ var originBlockRange = getBlockRangeForChain(blockRangesForChains, originChainId, chainIds);
852
+ var matchedDeposit = deposits[0];
853
+ // For a slow fill leaf to have been created (and subsequently create an excess), the deposit matching the
854
+ // slow fill request must have been included in a previous bundle AND the slow fill request should not
855
+ // be included in this bundle. This is because a slow fill request is only valid once its deposit
856
+ // has been mined, so if the deposit is not in a prior bundle to the fill, then no slow fill leaf could
857
+ // have been created. Secondly, the slow fill request itself must have occurred in an older bundle than the
858
+ // fill otherwise the slow fill leaf be unexecutable for an already-filled deposit..
859
+ if (matchedDeposit.blockNumber < originBlockRange[0] &&
860
+ // If there is a slow fill request in this bundle that matches the relay hash, then there was no slow fill
861
+ // created that would be considered excess.
862
+ (!slowFillRequest || slowFillRequest.blockNumber < destinationBlockRange[0])) {
863
+ validatedBundleUnexecutableSlowFills.push(deposits[0]);
864
+ }
865
+ });
866
+ return [2 /*return*/];
867
+ }
868
+ });
869
+ };
870
+ _f = 0, allChainIds_4 = allChainIds;
871
+ _g.label = 1;
872
+ case 1:
873
+ if (!(_f < allChainIds_4.length)) return [3 /*break*/, 4];
874
+ destinationChainId = allChainIds_4[_f];
875
+ return [5 /*yield**/, _loop_3(destinationChainId)];
876
+ case 2:
877
+ _g.sent();
878
+ _g.label = 3;
879
+ case 3:
880
+ _f++;
881
+ return [3 /*break*/, 1];
882
+ case 4: return [2 /*return*/];
883
+ }
884
+ });
885
+ };
886
+ _b = 0, allChainIds_2 = allChainIds;
887
+ _d.label = 4;
888
+ case 4:
889
+ if (!(_b < allChainIds_2.length)) return [3 /*break*/, 7];
890
+ originChainId = allChainIds_2[_b];
891
+ return [5 /*yield**/, _loop_2(originChainId)];
892
+ case 5:
893
+ _d.sent();
894
+ _d.label = 6;
895
+ case 6:
896
+ _b++;
897
+ return [3 /*break*/, 4];
898
+ case 7:
899
+ this.logger.debug({
900
+ at: "BundleDataClient#loadData",
901
+ message: "Processed ".concat(fillCounter, " fills in ").concat(performance.now() - start, "ms."),
902
+ });
903
+ start = performance.now();
904
+ // For all deposits older than this bundle, we need to check if they expired in this bundle and if they did,
905
+ // whether there was a slow fill created for it in a previous bundle that is now unexecutable and replaced
906
+ // by a new expired deposit refund.
907
+ return [4 /*yield*/, forEachAsync(olderDepositHashes, function (depositHash) { return __awaiter(_this, void 0, void 0, function () {
908
+ var _a, relayDataHash, index, _b, deposits, slowFillRequest, fill, deposit, destinationChainId, destinationBlockRange, fillStatus;
909
+ return __generator(this, function (_c) {
910
+ switch (_c.label) {
911
+ case 0:
912
+ _a = decodeBundleDepositHash(depositHash), relayDataHash = _a.relayDataHash, index = _a.index;
913
+ _b = v3RelayHashes[relayDataHash], deposits = _b.deposits, slowFillRequest = _b.slowFillRequest, fill = _b.fill;
914
+ if (!deposits || deposits.length < 1) {
915
+ throw new Error("Deposit should exist in relay hash dictionary.");
916
+ }
917
+ deposit = deposits[index];
918
+ destinationChainId = deposit.destinationChainId;
919
+ destinationBlockRange = getBlockRangeForChain(blockRangesForChains, destinationChainId, chainIds);
920
+ if (!
921
+ // If there is a valid fill that we saw matching this deposit, then it does not need a refund.
922
+ (!fill &&
923
+ isDefined(deposit) && // Needed for TSC - we check this above.
924
+ _depositIsExpired(deposit) &&
925
+ deposit.fillDeadline >= bundleBlockTimestamps[destinationChainId][0] &&
926
+ spokePoolClients[destinationChainId] !== undefined))
927
+ // If there is a valid fill that we saw matching this deposit, then it does not need a refund.
928
+ return [3 /*break*/, 2];
929
+ return [4 /*yield*/, _getFillStatusForDeposit(deposit, destinationBlockRange[1])];
930
+ case 1:
931
+ fillStatus = _c.sent();
932
+ // If there is no matching fill and the deposit expired in this bundle and the fill status on-chain is not
933
+ // Filled, then we can to refund it as an expired deposit.
934
+ if (fillStatus !== FillStatus.Filled) {
935
+ updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
936
+ }
937
+ // If fill status is RequestedSlowFill, then we might need to mark down an unexecutable
938
+ // slow fill that we're going to replace with an expired deposit refund.
939
+ // If deposit cannot be slow filled, then exit early.
940
+ if (fillStatus !== FillStatus.RequestedSlowFill || !_canCreateSlowFillLeaf(deposit)) {
941
+ return [2 /*return*/];
942
+ }
943
+ // Now, check if there was a slow fill created for this deposit in a previous bundle which would now be
944
+ // unexecutable. Mark this deposit as having created an unexecutable slow fill if there is no matching
945
+ // slow fill request or the matching slow fill request took place in a previous bundle.
946
+ // If there is a slow fill request in this bundle, then the expired deposit refund will supersede
947
+ // the slow fill request. If there is no slow fill request seen or its older than this bundle, then we can
948
+ // assume a slow fill leaf was created for it when the deposit was mined. Therefore, because the deposit
949
+ // was in an older bundle, we can assume that a slow fill leaf was created at that time and therefore
950
+ // is now unexecutable.
951
+ if (!slowFillRequest || slowFillRequest.blockNumber < destinationBlockRange[0]) {
952
+ validatedBundleUnexecutableSlowFills.push(deposit);
953
+ }
954
+ _c.label = 2;
955
+ case 2: return [2 /*return*/];
956
+ }
957
+ });
958
+ }); })];
959
+ case 8:
960
+ // For all deposits older than this bundle, we need to check if they expired in this bundle and if they did,
961
+ // whether there was a slow fill created for it in a previous bundle that is now unexecutable and replaced
962
+ // by a new expired deposit refund.
963
+ _d.sent();
964
+ // Batch compute V3 lp fees.
965
+ start = performance.now();
966
+ promises = [
967
+ validatedBundleV3Fills.length > 0
968
+ ? this.clients.hubPoolClient.batchComputeRealizedLpFeePct(validatedBundleV3Fills.map(function (fill) {
969
+ var deposits = v3RelayHashes[getRelayEventKey(fill)].deposits;
970
+ assert(isDefined(deposits) && deposits.length > 0, "Deposit should exist in relay hash dictionary.");
971
+ var matchedDeposit = deposits[0];
972
+ assert(isDefined(matchedDeposit), "Deposit should exist in relay hash dictionary.");
973
+ var paymentChainId = getRefundInformationFromFill(__assign(__assign({}, fill), { fromLiteChain: matchedDeposit.fromLiteChain }), _this.clients.hubPoolClient, bundleEndBlockForMainnet).chainToSendRefundTo;
974
+ return __assign(__assign({}, fill), { paymentChainId: paymentChainId });
975
+ }))
976
+ : [],
977
+ validatedBundleSlowFills.length > 0
978
+ ? this.clients.hubPoolClient.batchComputeRealizedLpFeePct(validatedBundleSlowFills.map(function (deposit) {
979
+ return __assign(__assign({}, deposit), { paymentChainId: deposit.destinationChainId });
980
+ }))
981
+ : [],
982
+ validatedBundleUnexecutableSlowFills.length > 0
983
+ ? this.clients.hubPoolClient.batchComputeRealizedLpFeePct(validatedBundleUnexecutableSlowFills.map(function (deposit) {
984
+ return __assign(__assign({}, deposit), { paymentChainId: deposit.destinationChainId });
985
+ }))
986
+ : [],
987
+ ];
988
+ return [4 /*yield*/, Promise.all(promises)];
989
+ case 9:
990
+ _c = _d.sent(), v3FillLpFees = _c[0], v3SlowFillLpFees = _c[1], v3UnexecutableSlowFillLpFees = _c[2];
991
+ this.logger.debug({
992
+ at: "BundleDataClient#loadData",
993
+ message: "Computed batch async LP fees in ".concat(performance.now() - start, "ms."),
994
+ });
995
+ v3FillLpFees.forEach(function (_a, idx) {
996
+ var realizedLpFeePct = _a.realizedLpFeePct;
997
+ var fill = validatedBundleV3Fills[idx];
998
+ var deposits = v3RelayHashes[getRelayEventKey(fill)].deposits;
580
999
  assert(isDefined(deposits) && deposits.length > 0, "Deposit should exist in relay hash dictionary.");
581
- const matchedDeposit = deposits[0];
582
- if (slowFillRequest.blockNumber >= destinationChainBlockRange[0] &&
583
- _canCreateSlowFillLeaf(matchedDeposit) &&
584
- !_depositIsExpired(matchedDeposit)) {
585
- validatedBundleSlowFills.push(matchedDeposit);
1000
+ var associatedDeposit = deposits[0];
1001
+ assert(isDefined(associatedDeposit), "Deposit should exist in relay hash dictionary.");
1002
+ var _b = getRefundInformationFromFill(__assign(__assign({}, fill), { fromLiteChain: associatedDeposit.fromLiteChain }), _this.clients.hubPoolClient, bundleEndBlockForMainnet), chainToSendRefundTo = _b.chainToSendRefundTo, repaymentToken = _b.repaymentToken;
1003
+ updateBundleFillsV3(bundleFillsV3, fill, realizedLpFeePct, chainToSendRefundTo, repaymentToken, fill.relayer);
1004
+ });
1005
+ v3SlowFillLpFees.forEach(function (_a, idx) {
1006
+ var lpFeePct = _a.realizedLpFeePct;
1007
+ var deposit = validatedBundleSlowFills[idx];
1008
+ // We should not create slow fill leaves for duplicate deposit hashes and we should only create a slow
1009
+ // fill leaf for the first deposit (the quote timestamp of the deposit determines the LP fee, so its
1010
+ // important we pick out the correct deposit). Deposits are pushed into validatedBundleSlowFills in ascending
1011
+ // order so the following slice will only match the first deposit.
1012
+ var relayDataHash = getRelayEventKey(deposit);
1013
+ if (validatedBundleSlowFills.slice(0, idx).some(function (d) { return getRelayEventKey(d) === relayDataHash; })) {
1014
+ return;
586
1015
  }
587
- }
588
- else {
1016
+ assert(!_depositIsExpired(deposit), "Cannot create slow fill leaf for expired deposit.");
1017
+ updateBundleSlowFills(bundleSlowFillsV3, __assign(__assign({}, deposit), { lpFeePct: lpFeePct }));
1018
+ });
1019
+ v3UnexecutableSlowFillLpFees.forEach(function (_a, idx) {
1020
+ var lpFeePct = _a.realizedLpFeePct;
1021
+ var deposit = validatedBundleUnexecutableSlowFills[idx];
1022
+ updateBundleExcessSlowFills(unexecutableSlowFills, __assign(__assign({}, deposit), { lpFeePct: lpFeePct }));
1023
+ });
1024
+ v3SpokeEventsReadable = prettyPrintV3SpokePoolEvents(bundleDepositsV3, bundleFillsV3, bundleSlowFillsV3, expiredDepositsToRefundV3, unexecutableSlowFills);
1025
+ if (bundleInvalidFillsV3.length > 0) {
1026
+ invalidFillsWithPartialMatchedDeposits_1 = [];
1027
+ preFillsForNextBundle_1 = [];
1028
+ unknownReasonInvalidFills_1 = [];
1029
+ bundleInvalidFillsV3.forEach(function (fill) {
1030
+ var originClient = spokePoolClients[fill.originChainId];
1031
+ var fullyMatchedDeposit = originClient.getDepositForFill(fill);
1032
+ if (!isDefined(fullyMatchedDeposit)) {
1033
+ var partiallyMatchedDeposit = originClient.getDeposit(fill.depositId);
1034
+ if (isDefined(partiallyMatchedDeposit)) {
1035
+ invalidFillsWithPartialMatchedDeposits_1.push(fill);
1036
+ }
1037
+ else {
1038
+ unknownReasonInvalidFills_1.push(fill);
1039
+ }
1040
+ }
1041
+ else {
1042
+ var originBundleBlockRange = getBlockRangeForChain(blockRangesForChains, fill.originChainId, chainIds);
1043
+ if (fullyMatchedDeposit.blockNumber <= originBundleBlockRange[1]) {
1044
+ throw new Error("Detected invalid fill that matches fully with a deposit in current or prior bundle");
1045
+ }
1046
+ preFillsForNextBundle_1.push(fill);
1047
+ }
1048
+ });
589
1049
  this.logger.debug({
590
1050
  at: "BundleDataClient#loadData",
591
- message: "Duplicate slow fill request detected",
592
- slowFillRequest,
1051
+ message: "Finished loading V3 spoke pool data and found some invalid fills in range",
1052
+ blockRangesForChains: blockRangesForChains,
1053
+ invalidFillsWithPartialMatchedDeposits: invalidFillsWithPartialMatchedDeposits_1.map(function (invalidFill) {
1054
+ return convertFillParamsToBytes32(invalidFill);
1055
+ }),
1056
+ preFillsForNextBundle: preFillsForNextBundle_1.map(function (preFill) { return convertFillParamsToBytes32(preFill); }),
1057
+ unknownReasonInvalidFills: unknownReasonInvalidFills_1.map(function (invalidFill) {
1058
+ return convertFillParamsToBytes32(invalidFill);
1059
+ }),
593
1060
  });
594
- throw new Error("Duplicate slow fill request detected.");
595
- }
596
- return;
597
- }
598
- // Instantiate dictionary if there is neither a deposit nor fill matching it.
599
- v3RelayHashes[relayDataHash] = {
600
- deposits: undefined,
601
- fill: undefined,
602
- slowFillRequest: slowFillRequest,
603
- };
604
- // TODO: We can remove the following historical query once we deprecate the deposit()
605
- // function since there won't be any old, unexpired deposits anymore assuming the spoke pool client
606
- // lookbacks have been validated, which they should be before we run this function.
607
- // Since there was no deposit matching the relay hash, we need to do a historical query for an
608
- // older deposit in case the spoke pool client's lookback isn't old enough to find the matching deposit.
609
- // We can skip this step if the deposit's fill deadline is not infinite, because we can assume that the
610
- // spoke pool clients have loaded deposits old enough to cover all fills with a non-infinite fill deadline.
611
- // We do not need to handle the case where the deposit ID is > uint32 (in which case we wouldn't
612
- // want to perform a binary search lookup for it because the deposit ID is "unsafe" and cannot be
613
- // found using such a method) because infinite fill deadlines cannot be produced from the unsafeDepositV3()
614
- // function.
615
- if (slowFillRequest.blockNumber >= destinationChainBlockRange[0]) {
616
- if (!INFINITE_FILL_DEADLINE.eq(slowFillRequest.fillDeadline)) {
617
- bundleInvalidSlowFillRequests.push(slowFillRequest);
618
- return;
619
- }
620
- const historicalDeposit = await queryHistoricalDepositForFill(originClient, slowFillRequest);
621
- if (!historicalDeposit.found) {
622
- bundleInvalidSlowFillRequests.push(slowFillRequest);
623
- return;
624
- }
625
- const matchedDeposit = historicalDeposit.deposit;
626
- // If deposit is in a following bundle, then this slow fill request will have to be created
627
- // once that deposit is in the current bundle.
628
- if (matchedDeposit.blockNumber > originChainBlockRange[1]) {
629
- bundleInvalidSlowFillRequests.push(slowFillRequest);
630
- return;
631
- }
632
- // @dev Since queryHistoricalDepositForFill validates the slow fill request by checking individual
633
- // object property values against the deposit's, we
634
- // sanity check it here by comparing the full relay hashes. If there's an error here then the
635
- // historical deposit query is not working as expected.
636
- assert(getRelayEventKey(matchedDeposit) === relayDataHash, "Deposit relay hashes should match.");
637
- v3RelayHashes[relayDataHash].deposits = [matchedDeposit];
638
- if (!_canCreateSlowFillLeaf(matchedDeposit) || _depositIsExpired(matchedDeposit)) {
639
- return;
640
- }
641
- validatedBundleSlowFills.push(matchedDeposit);
642
- }
643
- });
644
- // Process deposits and maintain the following invariants:
645
- // - Deposits matching fills that are not type SlowFill from previous bundle block ranges should produce
646
- // refunds for those fills.
647
- // - Deposits matching fills that are type SlowFill from previous bundle block ranges should be refunded to the
648
- // depositor.
649
- // - All deposits expiring in this bundle, even those sent in prior bundle block ranges, should be refunded
650
- // to the depositor.
651
- // - An expired deposit cannot be refunded if the deposit was filled.
652
- // - If a deposit from a prior bundle expired in this bundle, had a slow fill request created for it
653
- // in a prior bundle, and has not been filled yet, then an unexecutable slow fill leaf has been created
654
- // and needs to be refunded to the HubPool.
655
- // - Deposits matching slow fill requests from previous bundle block ranges should produce slow fills
656
- // if the deposit has not been filled.
657
- // Assumptions:
658
- // - If the deposit has a matching fill or slow fill request in the bundle then we have already stored
659
- // it in the relay hashes dictionary.
660
- // - We've created refunds for all fills in this bundle matching a deposit.
661
- // - We've created slow fill leaves for all slow fill requests in this bundle matching an unfilled deposit.
662
- // - Deposits for the same relay data hash can be sent an arbitrary amount of times.
663
- // - Deposits can be sent an arbitrary amount of time after a fill has been sent for the matching relay data.
664
- await mapAsync(bundleDepositHashes, async (depositHash) => {
665
- const { relayDataHash, index } = decodeBundleDepositHash(depositHash);
666
- const { deposits, fill, slowFillRequest } = v3RelayHashes[relayDataHash];
667
- if (!deposits || deposits.length === 0) {
668
- throw new Error("Deposits should exist in relay hash dictionary.");
669
- }
670
- const deposit = deposits[index];
671
- if (!deposit)
672
- throw new Error("Deposit should exist in relay hash dictionary.");
673
- if (deposit.originChainId !== originChainId || deposit.destinationChainId !== destinationChainId) {
674
- return;
675
- }
676
- // If fill is in the current bundle then we can assume there is already a refund for it, so only
677
- // include this pre fill if the fill is in an older bundle.
678
- if (fill) {
679
- if (fill.blockNumber < destinationChainBlockRange[0]) {
680
- let provider;
681
- if (isEVMSpokePoolClient(destinationClient)) {
682
- provider = destinationClient.spokePool.provider;
683
- }
684
- else if (isSVMSpokePoolClient(destinationClient)) {
685
- provider = destinationClient.svmEventsClient.getRpc();
686
- }
687
- const fillToRefund = await verifyFillRepayment(fill, provider, deposits[0], this.clients.hubPoolClient, bundleEndBlockForMainnet);
688
- if (!isDefined(fillToRefund)) {
689
- bundleUnrepayableFillsV3.push(fill);
690
- }
691
- else if (!isSlowFill(fill)) {
692
- v3RelayHashes[relayDataHash].fill = fillToRefund;
693
- validatedBundleV3Fills.push({
694
- ...fillToRefund,
695
- quoteTimestamp: deposit.quoteTimestamp,
696
- });
697
- }
698
- else {
699
- updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
700
- }
701
- }
702
- return;
703
- }
704
- // If a slow fill request exists in memory, then we know the deposit has not been filled because fills
705
- // must follow slow fill requests and we would have seen the fill already if it existed.,
706
- // We can conclude that either the deposit has expired or we need to create a slow fill leaf for the
707
- // deposit because it has not been filled. Slow fill leaves were already created for requests sent
708
- // in the current bundle so only create new slow fill leaves for prior bundle deposits.
709
- if (slowFillRequest) {
710
- if (_depositIsExpired(deposit)) {
711
- updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
712
- }
713
- else if (slowFillRequest.blockNumber < destinationChainBlockRange[0] &&
714
- _canCreateSlowFillLeaf(deposit) &&
715
- validatedBundleSlowFills.every((d) => getRelayEventKey(d) !== relayDataHash)) {
716
- validatedBundleSlowFills.push(deposit);
717
- }
718
- return;
719
- }
720
- // So at this point in the code, there is no fill or slow fill request in memory for this deposit.
721
- // We need to check its fill status on-chain to figure out whether to issue a refund or a slow fill leaf.
722
- // We can assume at this point that all fills or slow fill requests, if found, were in previous bundles
723
- // because the spoke pool client lookback would have returned this entire bundle of events and stored
724
- // them into the relay hash dictionary.
725
- const fillStatus = await _getFillStatusForDeposit(deposit, destinationChainBlockRange[1]);
726
- if (fillStatus === FillStatus.Filled) {
727
- // We don't need to verify the fill block is before the bundle end block on the destination chain because
728
- // we queried the fillStatus at the end block. Therefore, if the fill took place after the end block,
729
- // then we wouldn't be in this branch of the code.
730
- const prefill = await this.findMatchingFillEvent(deposit, destinationClient);
731
- assert(isDefined(prefill), `findFillEvent# Cannot find prefill: ${relayDataHash}`);
732
- assert(getRelayEventKey(prefill) === relayDataHash, "Relay hashes should match.");
733
- let provider;
734
- if (isEVMSpokePoolClient(destinationClient)) {
735
- provider = destinationClient.spokePool.provider;
736
- }
737
- else if (isSVMSpokePoolClient(destinationClient)) {
738
- provider = destinationClient.svmEventsClient.getRpc();
739
1061
  }
740
- const verifiedFill = await verifyFillRepayment(prefill, provider, deposit, this.clients.hubPoolClient, bundleEndBlockForMainnet);
741
- if (!isDefined(verifiedFill)) {
742
- bundleUnrepayableFillsV3.push(prefill);
743
- }
744
- else if (!isSlowFill(verifiedFill)) {
745
- validatedBundleV3Fills.push({
746
- ...verifiedFill,
747
- quoteTimestamp: deposit.quoteTimestamp,
1062
+ if (bundleUnrepayableFillsV3.length > 0) {
1063
+ this.logger.debug({
1064
+ at: "BundleDataClient#loadData",
1065
+ message: "Finished loading V3 spoke pool data and found some unrepayable fills in range",
1066
+ blockRangesForChains: blockRangesForChains,
1067
+ bundleUnrepayableFillsV3: bundleUnrepayableFillsV3,
748
1068
  });
749
1069
  }
750
- else {
751
- updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
752
- }
753
- }
754
- else if (_depositIsExpired(deposit)) {
755
- updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
756
- }
757
- else if (fillStatus === FillStatus.RequestedSlowFill &&
758
- // Don't create duplicate slow fill requests for the same deposit.
759
- validatedBundleSlowFills.every((d) => getRelayEventKey(d) !== relayDataHash)) {
760
- if (_canCreateSlowFillLeaf(deposit)) {
761
- validatedBundleSlowFills.push(deposit);
1070
+ if (bundleInvalidSlowFillRequests.length > 0) {
1071
+ this.logger.debug({
1072
+ at: "BundleDataClient#loadData",
1073
+ message: "Finished loading V3 spoke pool data and found some invalid slow fill requests in range",
1074
+ blockRangesForChains: blockRangesForChains,
1075
+ bundleInvalidSlowFillRequests: bundleInvalidSlowFillRequests,
1076
+ });
762
1077
  }
763
- }
764
- });
765
- // For all fills that came after a slow fill request, we can now check if the slow fill request
766
- // was a valid one and whether it was created in a previous bundle. If so, then it created a slow fill
767
- // leaf that is now unexecutable.
768
- fastFillsReplacingSlowFills.forEach((relayDataHash) => {
769
- const { deposits, slowFillRequest, fill } = v3RelayHashes[relayDataHash];
770
- assert(fill?.relayExecutionInfo.fillType === FillType.ReplacedSlowFill, "Fill type should be ReplacedSlowFill.");
771
- // Needed for TSC - are implicitly checking that deposit exists by making it to this point.
772
- if (!deposits || deposits.length < 1) {
773
- throw new Error("Deposit should exist in relay hash dictionary.");
774
- }
775
- // We should never push fast fills involving lite chains here because slow fill requests for them are invalid:
776
- assert(_canCreateSlowFillLeaf(deposits[0]), "fastFillsReplacingSlowFills should contain only deposits that can be slow filled");
777
- const destinationBlockRange = getBlockRangeForChain(blockRangesForChains, destinationChainId, chainIds);
778
- const originBlockRange = getBlockRangeForChain(blockRangesForChains, originChainId, chainIds);
779
- const matchedDeposit = deposits[0];
780
- // For a slow fill leaf to have been created (and subsequently create an excess), the deposit matching the
781
- // slow fill request must have been included in a previous bundle AND the slow fill request should not
782
- // be included in this bundle. This is because a slow fill request is only valid once its deposit
783
- // has been mined, so if the deposit is not in a prior bundle to the fill, then no slow fill leaf could
784
- // have been created. Secondly, the slow fill request itself must have occurred in an older bundle than the
785
- // fill otherwise the slow fill leaf be unexecutable for an already-filled deposit..
786
- if (matchedDeposit.blockNumber < originBlockRange[0] &&
787
- // If there is a slow fill request in this bundle that matches the relay hash, then there was no slow fill
788
- // created that would be considered excess.
789
- (!slowFillRequest || slowFillRequest.blockNumber < destinationBlockRange[0])) {
790
- validatedBundleUnexecutableSlowFills.push(deposits[0]);
791
- }
792
- });
793
- }
794
- }
795
- this.logger.debug({
796
- at: "BundleDataClient#loadData",
797
- message: `Processed ${fillCounter} fills in ${performance.now() - start}ms.`,
798
- });
799
- start = performance.now();
800
- // For all deposits older than this bundle, we need to check if they expired in this bundle and if they did,
801
- // whether there was a slow fill created for it in a previous bundle that is now unexecutable and replaced
802
- // by a new expired deposit refund.
803
- await forEachAsync(olderDepositHashes, async (depositHash) => {
804
- const { relayDataHash, index } = decodeBundleDepositHash(depositHash);
805
- const { deposits, slowFillRequest, fill } = v3RelayHashes[relayDataHash];
806
- if (!deposits || deposits.length < 1) {
807
- throw new Error("Deposit should exist in relay hash dictionary.");
808
- }
809
- const deposit = deposits[index];
810
- const { destinationChainId } = deposit;
811
- const destinationBlockRange = getBlockRangeForChain(blockRangesForChains, destinationChainId, chainIds);
812
- // Only look for deposits that were mined before this bundle and that are newly expired.
813
- // If the fill deadline is lower than the bundle start block on the destination chain, then
814
- // we should assume it was refunded in a previous bundle.
815
- if (
816
- // If there is a valid fill that we saw matching this deposit, then it does not need a refund.
817
- !fill &&
818
- isDefined(deposit) && // Needed for TSC - we check this above.
819
- _depositIsExpired(deposit) &&
820
- deposit.fillDeadline >= bundleBlockTimestamps[destinationChainId][0] &&
821
- spokePoolClients[destinationChainId] !== undefined) {
822
- // If we haven't seen a fill matching this deposit, then we need to rule out that it was filled a long time ago
823
- // by checkings its on-chain fill status.
824
- const fillStatus = await _getFillStatusForDeposit(deposit, destinationBlockRange[1]);
825
- // If there is no matching fill and the deposit expired in this bundle and the fill status on-chain is not
826
- // Filled, then we can to refund it as an expired deposit.
827
- if (fillStatus !== FillStatus.Filled) {
828
- updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
1078
+ this.logger.debug({
1079
+ at: "BundleDataClient#loadDataFromScratch",
1080
+ message: "Computed bundle data in ".concat(Math.round(performance.now() - start) / 1000, "s."),
1081
+ blockRangesForChains: JSON.stringify(blockRangesForChains),
1082
+ v3SpokeEventsReadable: v3SpokeEventsReadable,
1083
+ });
1084
+ return [2 /*return*/, {
1085
+ bundleDepositsV3: bundleDepositsV3,
1086
+ expiredDepositsToRefundV3: expiredDepositsToRefundV3,
1087
+ bundleFillsV3: bundleFillsV3,
1088
+ unexecutableSlowFills: unexecutableSlowFills,
1089
+ bundleSlowFillsV3: bundleSlowFillsV3,
1090
+ }];
829
1091
  }
830
- // If fill status is RequestedSlowFill, then we might need to mark down an unexecutable
831
- // slow fill that we're going to replace with an expired deposit refund.
832
- // If deposit cannot be slow filled, then exit early.
833
- if (fillStatus !== FillStatus.RequestedSlowFill || !_canCreateSlowFillLeaf(deposit)) {
834
- return;
835
- }
836
- // Now, check if there was a slow fill created for this deposit in a previous bundle which would now be
837
- // unexecutable. Mark this deposit as having created an unexecutable slow fill if there is no matching
838
- // slow fill request or the matching slow fill request took place in a previous bundle.
839
- // If there is a slow fill request in this bundle, then the expired deposit refund will supersede
840
- // the slow fill request. If there is no slow fill request seen or its older than this bundle, then we can
841
- // assume a slow fill leaf was created for it when the deposit was mined. Therefore, because the deposit
842
- // was in an older bundle, we can assume that a slow fill leaf was created at that time and therefore
843
- // is now unexecutable.
844
- if (!slowFillRequest || slowFillRequest.blockNumber < destinationBlockRange[0]) {
845
- validatedBundleUnexecutableSlowFills.push(deposit);
846
- }
847
- }
848
- });
849
- // Batch compute V3 lp fees.
850
- start = performance.now();
851
- const promises = [
852
- validatedBundleV3Fills.length > 0
853
- ? this.clients.hubPoolClient.batchComputeRealizedLpFeePct(validatedBundleV3Fills.map((fill) => {
854
- const { deposits } = v3RelayHashes[getRelayEventKey(fill)];
855
- assert(isDefined(deposits) && deposits.length > 0, "Deposit should exist in relay hash dictionary.");
856
- const matchedDeposit = deposits[0];
857
- assert(isDefined(matchedDeposit), "Deposit should exist in relay hash dictionary.");
858
- const { chainToSendRefundTo: paymentChainId } = getRefundInformationFromFill({
859
- ...fill,
860
- fromLiteChain: matchedDeposit.fromLiteChain,
861
- }, this.clients.hubPoolClient, bundleEndBlockForMainnet);
862
- return {
863
- ...fill,
864
- paymentChainId,
865
- };
866
- }))
867
- : [],
868
- validatedBundleSlowFills.length > 0
869
- ? this.clients.hubPoolClient.batchComputeRealizedLpFeePct(validatedBundleSlowFills.map((deposit) => {
870
- return {
871
- ...deposit,
872
- paymentChainId: deposit.destinationChainId,
873
- };
874
- }))
875
- : [],
876
- validatedBundleUnexecutableSlowFills.length > 0
877
- ? this.clients.hubPoolClient.batchComputeRealizedLpFeePct(validatedBundleUnexecutableSlowFills.map((deposit) => {
878
- return {
879
- ...deposit,
880
- paymentChainId: deposit.destinationChainId,
881
- };
882
- }))
883
- : [],
884
- ];
885
- const [v3FillLpFees, v3SlowFillLpFees, v3UnexecutableSlowFillLpFees] = await Promise.all(promises);
886
- this.logger.debug({
887
- at: "BundleDataClient#loadData",
888
- message: `Computed batch async LP fees in ${performance.now() - start}ms.`,
889
- });
890
- v3FillLpFees.forEach(({ realizedLpFeePct }, idx) => {
891
- const fill = validatedBundleV3Fills[idx];
892
- const { deposits } = v3RelayHashes[getRelayEventKey(fill)];
893
- assert(isDefined(deposits) && deposits.length > 0, "Deposit should exist in relay hash dictionary.");
894
- const associatedDeposit = deposits[0];
895
- assert(isDefined(associatedDeposit), "Deposit should exist in relay hash dictionary.");
896
- const { chainToSendRefundTo, repaymentToken } = getRefundInformationFromFill({
897
- ...fill,
898
- fromLiteChain: associatedDeposit.fromLiteChain,
899
- }, this.clients.hubPoolClient, bundleEndBlockForMainnet);
900
- updateBundleFillsV3(bundleFillsV3, fill, realizedLpFeePct, chainToSendRefundTo, repaymentToken, fill.relayer);
901
- });
902
- v3SlowFillLpFees.forEach(({ realizedLpFeePct: lpFeePct }, idx) => {
903
- const deposit = validatedBundleSlowFills[idx];
904
- // We should not create slow fill leaves for duplicate deposit hashes and we should only create a slow
905
- // fill leaf for the first deposit (the quote timestamp of the deposit determines the LP fee, so its
906
- // important we pick out the correct deposit). Deposits are pushed into validatedBundleSlowFills in ascending
907
- // order so the following slice will only match the first deposit.
908
- const relayDataHash = getRelayEventKey(deposit);
909
- if (validatedBundleSlowFills.slice(0, idx).some((d) => getRelayEventKey(d) === relayDataHash)) {
910
- return;
911
- }
912
- assert(!_depositIsExpired(deposit), "Cannot create slow fill leaf for expired deposit.");
913
- updateBundleSlowFills(bundleSlowFillsV3, { ...deposit, lpFeePct });
914
- });
915
- v3UnexecutableSlowFillLpFees.forEach(({ realizedLpFeePct: lpFeePct }, idx) => {
916
- const deposit = validatedBundleUnexecutableSlowFills[idx];
917
- updateBundleExcessSlowFills(unexecutableSlowFills, { ...deposit, lpFeePct });
1092
+ });
918
1093
  });
919
- const v3SpokeEventsReadable = prettyPrintV3SpokePoolEvents(bundleDepositsV3, bundleFillsV3, bundleSlowFillsV3, expiredDepositsToRefundV3, unexecutableSlowFills);
920
- if (bundleInvalidFillsV3.length > 0) {
921
- // For extra clarity, check if any invalid fills match with a deposit on deposit ID and origin chain. These
922
- // are most likely truly invalid fills due to re-org.
923
- const invalidFillsWithPartialMatchedDeposits = [];
924
- // If the fill matches with a deposit following the bundle then the fill will be refunded as a pre-fill
925
- // in the next bundle.
926
- const preFillsForNextBundle = [];
927
- // These fills don't partially match with any deposit in our memory.
928
- const unknownReasonInvalidFills = [];
929
- bundleInvalidFillsV3.forEach((fill) => {
930
- const originClient = spokePoolClients[fill.originChainId];
931
- const fullyMatchedDeposit = originClient.getDepositForFill(fill);
932
- if (!isDefined(fullyMatchedDeposit)) {
933
- const partiallyMatchedDeposit = originClient.getDeposit(fill.depositId);
934
- if (isDefined(partiallyMatchedDeposit)) {
935
- invalidFillsWithPartialMatchedDeposits.push(fill);
936
- }
937
- else {
938
- unknownReasonInvalidFills.push(fill);
939
- }
940
- }
941
- else {
942
- const originBundleBlockRange = getBlockRangeForChain(blockRangesForChains, fill.originChainId, chainIds);
943
- if (fullyMatchedDeposit.blockNumber <= originBundleBlockRange[1]) {
944
- throw new Error("Detected invalid fill that matches fully with a deposit in current or prior bundle");
945
- }
946
- preFillsForNextBundle.push(fill);
1094
+ };
1095
+ BundleDataClient.prototype.findMatchingFillEvent = function (deposit, spokePoolClient) {
1096
+ return __awaiter(this, void 0, void 0, function () {
1097
+ return __generator(this, function (_a) {
1098
+ switch (_a.label) {
1099
+ case 0:
1100
+ if (!isSVMSpokePoolClient(spokePoolClient)) return [3 /*break*/, 2];
1101
+ return [4 /*yield*/, findSvmFillEvent(deposit, spokePoolClient.chainId, spokePoolClient.svmEventsClient, spokePoolClient.deploymentBlock, spokePoolClient.latestHeightSearched, spokePoolClient.logger)];
1102
+ case 1: return [2 /*return*/, _a.sent()];
1103
+ case 2:
1104
+ if (!isEVMSpokePoolClient(spokePoolClient)) return [3 /*break*/, 4];
1105
+ return [4 /*yield*/, findEvmFillEvent(spokePoolClient.spokePool, deposit, spokePoolClient.deploymentBlock, spokePoolClient.latestHeightSearched)];
1106
+ case 3: return [2 /*return*/, _a.sent()];
1107
+ case 4: throw new Error("Unsupported spoke pool client type");
947
1108
  }
948
1109
  });
949
- this.logger.debug({
950
- at: "BundleDataClient#loadData",
951
- message: "Finished loading V3 spoke pool data and found some invalid fills in range",
952
- blockRangesForChains,
953
- invalidFillsWithPartialMatchedDeposits: invalidFillsWithPartialMatchedDeposits.map((invalidFill) => convertFillParamsToBytes32(invalidFill)),
954
- preFillsForNextBundle: preFillsForNextBundle.map((preFill) => convertFillParamsToBytes32(preFill)),
955
- unknownReasonInvalidFills: unknownReasonInvalidFills.map((invalidFill) => convertFillParamsToBytes32(invalidFill)),
956
- });
957
- }
958
- if (bundleUnrepayableFillsV3.length > 0) {
959
- this.logger.debug({
960
- at: "BundleDataClient#loadData",
961
- message: "Finished loading V3 spoke pool data and found some unrepayable fills in range",
962
- blockRangesForChains,
963
- bundleUnrepayableFillsV3,
964
- });
965
- }
966
- if (bundleInvalidSlowFillRequests.length > 0) {
967
- this.logger.debug({
968
- at: "BundleDataClient#loadData",
969
- message: "Finished loading V3 spoke pool data and found some invalid slow fill requests in range",
970
- blockRangesForChains,
971
- bundleInvalidSlowFillRequests,
1110
+ });
1111
+ };
1112
+ BundleDataClient.prototype.getBundleBlockTimestamps = function (chainIds, blockRangesForChains, spokePoolClients) {
1113
+ return __awaiter(this, void 0, void 0, function () {
1114
+ var _a, _b;
1115
+ var _this = this;
1116
+ return __generator(this, function (_c) {
1117
+ switch (_c.label) {
1118
+ case 0:
1119
+ _b = (_a = Object).fromEntries;
1120
+ return [4 /*yield*/, mapAsync(chainIds, function (chainId, index) { return __awaiter(_this, void 0, void 0, function () {
1121
+ var blockRangeForChain, _startBlockForChain, _endBlockForChain, spokePoolClient, startBlockForChain, endBlockForChain, _a, startTime, _endTime, _b, endBlockDelta, endTime;
1122
+ return __generator(this, function (_c) {
1123
+ switch (_c.label) {
1124
+ case 0:
1125
+ blockRangeForChain = blockRangesForChains[index];
1126
+ if (!isDefined(blockRangeForChain) ||
1127
+ isChainDisabledAtBlock(chainId, blockRangesForChains[0][0], this.clients.configStoreClient)) {
1128
+ return [2 /*return*/];
1129
+ }
1130
+ _startBlockForChain = blockRangeForChain[0], _endBlockForChain = blockRangeForChain[1];
1131
+ spokePoolClient = spokePoolClients[chainId];
1132
+ // Relayer instances using the BundleDataClient for repayment estimates may only relay on a subset of chains.
1133
+ if (!isDefined(spokePoolClient)) {
1134
+ return [2 /*return*/];
1135
+ }
1136
+ startBlockForChain = Math.min(_startBlockForChain, spokePoolClient.latestHeightSearched);
1137
+ endBlockForChain = Math.min(_endBlockForChain + 1, spokePoolClient.latestHeightSearched);
1138
+ return [4 /*yield*/, spokePoolClient.getTimestampForBlock(startBlockForChain)];
1139
+ case 1:
1140
+ _b = [
1141
+ _c.sent()
1142
+ ];
1143
+ return [4 /*yield*/, spokePoolClient.getTimestampForBlock(endBlockForChain)];
1144
+ case 2:
1145
+ _a = _b.concat([
1146
+ _c.sent()
1147
+ ]), startTime = _a[0], _endTime = _a[1];
1148
+ endBlockDelta = endBlockForChain > startBlockForChain ? 1 : 0;
1149
+ endTime = Math.max(0, _endTime - endBlockDelta);
1150
+ // Sanity checks:
1151
+ assert(endTime >= startTime, "End time for block ".concat(endBlockForChain, " should be greater than start time for block ").concat(startBlockForChain, ": ").concat(endTime, " >= ").concat(startTime, "."));
1152
+ assert(startBlockForChain === 0 || startTime > 0, "Start timestamp must be greater than 0 if the start block is greater than 0.");
1153
+ return [2 /*return*/, [chainId, [startTime, endTime]]];
1154
+ }
1155
+ });
1156
+ }); })];
1157
+ case 1: return [2 /*return*/, _b.apply(_a, [(_c.sent()).filter(isDefined)])];
1158
+ }
972
1159
  });
973
- }
974
- this.logger.debug({
975
- at: "BundleDataClient#loadDataFromScratch",
976
- message: `Computed bundle data in ${Math.round(performance.now() - start) / 1000}s.`,
977
- blockRangesForChains: JSON.stringify(blockRangesForChains),
978
- v3SpokeEventsReadable,
979
1160
  });
980
- return {
981
- bundleDepositsV3,
982
- expiredDepositsToRefundV3,
983
- bundleFillsV3,
984
- unexecutableSlowFills,
985
- bundleSlowFillsV3,
986
- };
987
- }
988
- async findMatchingFillEvent(deposit, spokePoolClient) {
989
- if (isSVMSpokePoolClient(spokePoolClient)) {
990
- return await findSvmFillEvent(deposit, spokePoolClient.chainId, spokePoolClient.svmEventsClient, spokePoolClient.deploymentBlock, spokePoolClient.latestHeightSearched, spokePoolClient.logger);
991
- }
992
- else if (isEVMSpokePoolClient(spokePoolClient)) {
993
- return await findEvmFillEvent(spokePoolClient.spokePool, deposit, spokePoolClient.deploymentBlock, spokePoolClient.latestHeightSearched);
994
- }
995
- else {
996
- throw new Error("Unsupported spoke pool client type");
997
- }
998
- }
999
- async getBundleBlockTimestamps(chainIds, blockRangesForChains, spokePoolClients) {
1000
- return Object.fromEntries((await mapAsync(chainIds, async (chainId, index) => {
1001
- const blockRangeForChain = blockRangesForChains[index];
1002
- if (!isDefined(blockRangeForChain) ||
1003
- isChainDisabledAtBlock(chainId, blockRangesForChains[0][0], this.clients.configStoreClient)) {
1004
- return;
1005
- }
1006
- const [_startBlockForChain, _endBlockForChain] = blockRangeForChain;
1007
- const spokePoolClient = spokePoolClients[chainId];
1008
- // Relayer instances using the BundleDataClient for repayment estimates may only relay on a subset of chains.
1009
- if (!isDefined(spokePoolClient)) {
1010
- return;
1011
- }
1012
- // We can assume that in production the block ranges passed into this function would never
1013
- // contain blocks where the spoke pool client hasn't queried. This is because this function
1014
- // will usually be called in production with block ranges that were validated by
1015
- // DataworkerUtils.blockRangesAreInvalidForSpokeClients.
1016
- const startBlockForChain = Math.min(_startBlockForChain, spokePoolClient.latestHeightSearched);
1017
- // @dev Add 1 to the bundle end block. The thinking here is that there can be a gap between
1018
- // block timestamps in subsequent blocks. The bundle data client assumes that fill deadlines expire
1019
- // in exactly one bundle, therefore we must make sure that the bundle block timestamp for one bundle's
1020
- // end block is exactly equal to the bundle block timestamp for the next bundle's start block. This way
1021
- // there are no gaps in block timestamps between bundles.
1022
- const endBlockForChain = Math.min(_endBlockForChain + 1, spokePoolClient.latestHeightSearched);
1023
- const [startTime, _endTime] = [
1024
- await spokePoolClient.getTimestampForBlock(startBlockForChain),
1025
- await spokePoolClient.getTimestampForBlock(endBlockForChain),
1026
- ];
1027
- // @dev similar to reasoning above to ensure no gaps between bundle block range timestamps and also
1028
- // no overlap, subtract 1 from the end time.
1029
- const endBlockDelta = endBlockForChain > startBlockForChain ? 1 : 0;
1030
- const endTime = Math.max(0, _endTime - endBlockDelta);
1031
- // Sanity checks:
1032
- assert(endTime >= startTime, `End time for block ${endBlockForChain} should be greater than start time for block ${startBlockForChain}: ${endTime} >= ${startTime}.`);
1033
- assert(startBlockForChain === 0 || startTime > 0, "Start timestamp must be greater than 0 if the start block is greater than 0.");
1034
- return [chainId, [startTime, endTime]];
1035
- })).filter(isDefined));
1036
- }
1037
- }
1161
+ };
1162
+ return BundleDataClient;
1163
+ }());
1164
+ export { BundleDataClient };
1038
1165
  //# sourceMappingURL=BundleDataClient.js.map