@across-protocol/sdk 3.1.27 → 3.1.28

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 (229) hide show
  1. package/dist/cjs/clients/BundleDataClient/BundleDataClient.d.ts +60 -0
  2. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js +929 -0
  3. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -0
  4. package/dist/cjs/clients/BundleDataClient/index.d.ts +2 -0
  5. package/dist/cjs/clients/BundleDataClient/index.js +6 -0
  6. package/dist/cjs/clients/BundleDataClient/index.js.map +1 -0
  7. package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.d.ts +15 -0
  8. package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.js +131 -0
  9. package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.js.map +1 -0
  10. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.d.ts +6 -0
  11. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js +19 -0
  12. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js.map +1 -0
  13. package/dist/cjs/clients/BundleDataClient/utils/MerkleTreeUtils.d.ts +3 -0
  14. package/dist/cjs/clients/BundleDataClient/utils/MerkleTreeUtils.js +23 -0
  15. package/dist/cjs/clients/BundleDataClient/utils/MerkleTreeUtils.js.map +1 -0
  16. package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts +24 -0
  17. package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js +129 -0
  18. package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -0
  19. package/dist/cjs/clients/BundleDataClient/utils/SuperstructUtils.d.ts +302 -0
  20. package/dist/cjs/clients/BundleDataClient/utils/SuperstructUtils.js +77 -0
  21. package/dist/cjs/clients/BundleDataClient/utils/SuperstructUtils.js.map +1 -0
  22. package/dist/cjs/clients/BundleDataClient/utils/index.d.ts +6 -0
  23. package/dist/cjs/clients/BundleDataClient/utils/index.js +10 -0
  24. package/dist/cjs/clients/BundleDataClient/utils/index.js.map +1 -0
  25. package/dist/cjs/clients/BundleDataClient/utils/shims.d.ts +8 -0
  26. package/dist/cjs/clients/BundleDataClient/utils/shims.js +3 -0
  27. package/dist/cjs/clients/BundleDataClient/utils/shims.js.map +1 -0
  28. package/dist/cjs/clients/index.d.ts +1 -0
  29. package/dist/cjs/clients/index.js +2 -1
  30. package/dist/cjs/clients/index.js.map +1 -1
  31. package/dist/cjs/interfaces/BundleData.d.ts +63 -0
  32. package/dist/cjs/interfaces/BundleData.js +3 -0
  33. package/dist/cjs/interfaces/BundleData.js.map +1 -0
  34. package/dist/cjs/interfaces/index.d.ts +1 -0
  35. package/dist/cjs/interfaces/index.js +1 -0
  36. package/dist/cjs/interfaces/index.js.map +1 -1
  37. package/dist/cjs/providers/alchemy.js +5 -5
  38. package/dist/cjs/providers/alchemy.js.map +1 -1
  39. package/dist/cjs/providers/drpc.d.ts +2 -0
  40. package/dist/cjs/providers/drpc.js +21 -0
  41. package/dist/cjs/providers/drpc.js.map +1 -0
  42. package/dist/cjs/providers/infura.js +5 -5
  43. package/dist/cjs/providers/infura.js.map +1 -1
  44. package/dist/cjs/providers/types.d.ts +1 -1
  45. package/dist/cjs/providers/utils.js +3 -1
  46. package/dist/cjs/providers/utils.js.map +1 -1
  47. package/dist/cjs/utils/AddressUtils.d.ts +1 -0
  48. package/dist/cjs/utils/AddressUtils.js +15 -1
  49. package/dist/cjs/utils/AddressUtils.js.map +1 -1
  50. package/dist/cjs/utils/ContractUtils.d.ts +1 -0
  51. package/dist/cjs/utils/ContractUtils.js +12 -0
  52. package/dist/cjs/utils/ContractUtils.js.map +1 -0
  53. package/dist/cjs/utils/Multicall.d.ts +3 -2
  54. package/dist/cjs/utils/Multicall.js +40 -41
  55. package/dist/cjs/utils/Multicall.js.map +1 -1
  56. package/dist/cjs/utils/ObjectUtils.d.ts +18 -0
  57. package/dist/cjs/utils/ObjectUtils.js +27 -1
  58. package/dist/cjs/utils/ObjectUtils.js.map +1 -1
  59. package/dist/cjs/utils/abi/contracts/index.d.ts +1 -0
  60. package/dist/cjs/utils/abi/contracts/index.js +9 -0
  61. package/dist/cjs/utils/abi/contracts/index.js.map +1 -0
  62. package/dist/cjs/utils/abi/typechain/Multicall3.d.ts +289 -0
  63. package/dist/cjs/utils/abi/typechain/Multicall3.js +3 -0
  64. package/dist/cjs/utils/abi/typechain/Multicall3.js.map +1 -0
  65. package/dist/cjs/utils/abi/typechain/common.d.ts +21 -0
  66. package/dist/cjs/utils/abi/typechain/common.js +3 -0
  67. package/dist/cjs/utils/abi/typechain/common.js.map +1 -0
  68. package/dist/cjs/utils/abi/typechain/factories/Multicall3__factory.d.ts +339 -0
  69. package/dist/cjs/utils/abi/typechain/factories/Multicall3__factory.js +458 -0
  70. package/dist/cjs/utils/abi/typechain/factories/Multicall3__factory.js.map +1 -0
  71. package/dist/cjs/utils/abi/typechain/factories/index.d.ts +1 -0
  72. package/dist/cjs/utils/abi/typechain/factories/index.js +6 -0
  73. package/dist/cjs/utils/abi/typechain/factories/index.js.map +1 -0
  74. package/dist/cjs/utils/abi/typechain/index.d.ts +3 -0
  75. package/dist/cjs/utils/abi/typechain/index.js +8 -0
  76. package/dist/cjs/utils/abi/typechain/index.js.map +1 -0
  77. package/dist/esm/clients/BundleDataClient/BundleDataClient.d.ts +60 -0
  78. package/dist/esm/clients/BundleDataClient/BundleDataClient.js +1097 -0
  79. package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -0
  80. package/dist/esm/clients/BundleDataClient/index.d.ts +2 -0
  81. package/dist/esm/clients/BundleDataClient/index.js +3 -0
  82. package/dist/esm/clients/BundleDataClient/index.js.map +1 -0
  83. package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.d.ts +15 -0
  84. package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.js +182 -0
  85. package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.js.map +1 -0
  86. package/dist/esm/clients/BundleDataClient/utils/FillUtils.d.ts +6 -0
  87. package/dist/esm/clients/BundleDataClient/utils/FillUtils.js +20 -0
  88. package/dist/esm/clients/BundleDataClient/utils/FillUtils.js.map +1 -0
  89. package/dist/esm/clients/BundleDataClient/utils/MerkleTreeUtils.d.ts +3 -0
  90. package/dist/esm/clients/BundleDataClient/utils/MerkleTreeUtils.js +20 -0
  91. package/dist/esm/clients/BundleDataClient/utils/MerkleTreeUtils.js.map +1 -0
  92. package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts +24 -0
  93. package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js +157 -0
  94. package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -0
  95. package/dist/esm/clients/BundleDataClient/utils/SuperstructUtils.d.ts +302 -0
  96. package/dist/esm/clients/BundleDataClient/utils/SuperstructUtils.js +79 -0
  97. package/dist/esm/clients/BundleDataClient/utils/SuperstructUtils.js.map +1 -0
  98. package/dist/esm/clients/BundleDataClient/utils/index.d.ts +6 -0
  99. package/dist/esm/clients/BundleDataClient/utils/index.js +7 -0
  100. package/dist/esm/clients/BundleDataClient/utils/index.js.map +1 -0
  101. package/dist/esm/clients/BundleDataClient/utils/shims.d.ts +8 -0
  102. package/dist/esm/clients/BundleDataClient/utils/shims.js +2 -0
  103. package/dist/esm/clients/BundleDataClient/utils/shims.js.map +1 -0
  104. package/dist/esm/clients/index.d.ts +1 -0
  105. package/dist/esm/clients/index.js +2 -0
  106. package/dist/esm/clients/index.js.map +1 -1
  107. package/dist/esm/interfaces/BundleData.d.ts +63 -0
  108. package/dist/esm/interfaces/BundleData.js +2 -0
  109. package/dist/esm/interfaces/BundleData.js.map +1 -0
  110. package/dist/esm/interfaces/index.d.ts +1 -0
  111. package/dist/esm/interfaces/index.js +1 -0
  112. package/dist/esm/interfaces/index.js.map +1 -1
  113. package/dist/esm/providers/alchemy.js +6 -6
  114. package/dist/esm/providers/alchemy.js.map +1 -1
  115. package/dist/esm/providers/drpc.d.ts +2 -0
  116. package/dist/esm/providers/drpc.js +18 -0
  117. package/dist/esm/providers/drpc.js.map +1 -0
  118. package/dist/esm/providers/infura.js +6 -6
  119. package/dist/esm/providers/infura.js.map +1 -1
  120. package/dist/esm/providers/types.d.ts +1 -1
  121. package/dist/esm/providers/utils.js +3 -1
  122. package/dist/esm/providers/utils.js.map +1 -1
  123. package/dist/esm/utils/AddressUtils.d.ts +1 -0
  124. package/dist/esm/utils/AddressUtils.js +16 -1
  125. package/dist/esm/utils/AddressUtils.js.map +1 -1
  126. package/dist/esm/utils/ContractUtils.d.ts +1 -0
  127. package/dist/esm/utils/ContractUtils.js +8 -0
  128. package/dist/esm/utils/ContractUtils.js.map +1 -0
  129. package/dist/esm/utils/Multicall.d.ts +3 -2
  130. package/dist/esm/utils/Multicall.js +39 -42
  131. package/dist/esm/utils/Multicall.js.map +1 -1
  132. package/dist/esm/utils/ObjectUtils.d.ts +18 -0
  133. package/dist/esm/utils/ObjectUtils.js +24 -0
  134. package/dist/esm/utils/ObjectUtils.js.map +1 -1
  135. package/dist/esm/utils/abi/contracts/index.d.ts +1 -0
  136. package/dist/esm/utils/abi/contracts/index.js +2 -0
  137. package/dist/esm/utils/abi/contracts/index.js.map +1 -0
  138. package/dist/esm/utils/abi/typechain/Multicall3.d.ts +292 -0
  139. package/dist/esm/utils/abi/typechain/Multicall3.js +2 -0
  140. package/dist/esm/utils/abi/typechain/Multicall3.js.map +1 -0
  141. package/dist/esm/utils/abi/typechain/common.d.ts +21 -0
  142. package/dist/esm/utils/abi/typechain/common.js +2 -0
  143. package/dist/esm/utils/abi/typechain/common.js.map +1 -0
  144. package/dist/esm/utils/abi/typechain/factories/Multicall3__factory.d.ts +339 -0
  145. package/dist/esm/utils/abi/typechain/factories/Multicall3__factory.js +458 -0
  146. package/dist/esm/utils/abi/typechain/factories/Multicall3__factory.js.map +1 -0
  147. package/dist/esm/utils/abi/typechain/factories/index.d.ts +1 -0
  148. package/dist/esm/utils/abi/typechain/factories/index.js +5 -0
  149. package/dist/esm/utils/abi/typechain/factories/index.js.map +1 -0
  150. package/dist/esm/utils/abi/typechain/index.d.ts +3 -0
  151. package/dist/esm/utils/abi/typechain/index.js +4 -0
  152. package/dist/esm/utils/abi/typechain/index.js.map +1 -0
  153. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts +61 -0
  154. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts.map +1 -0
  155. package/dist/types/clients/BundleDataClient/index.d.ts +3 -0
  156. package/dist/types/clients/BundleDataClient/index.d.ts.map +1 -0
  157. package/dist/types/clients/BundleDataClient/utils/DataworkerUtils.d.ts +16 -0
  158. package/dist/types/clients/BundleDataClient/utils/DataworkerUtils.d.ts.map +1 -0
  159. package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts +7 -0
  160. package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts.map +1 -0
  161. package/dist/types/clients/BundleDataClient/utils/MerkleTreeUtils.d.ts +4 -0
  162. package/dist/types/clients/BundleDataClient/utils/MerkleTreeUtils.d.ts.map +1 -0
  163. package/dist/types/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts +25 -0
  164. package/dist/types/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts.map +1 -0
  165. package/dist/types/clients/BundleDataClient/utils/SuperstructUtils.d.ts +303 -0
  166. package/dist/types/clients/BundleDataClient/utils/SuperstructUtils.d.ts.map +1 -0
  167. package/dist/types/clients/BundleDataClient/utils/index.d.ts +7 -0
  168. package/dist/types/clients/BundleDataClient/utils/index.d.ts.map +1 -0
  169. package/dist/types/clients/BundleDataClient/utils/shims.d.ts +9 -0
  170. package/dist/types/clients/BundleDataClient/utils/shims.d.ts.map +1 -0
  171. package/dist/types/clients/index.d.ts +1 -0
  172. package/dist/types/clients/index.d.ts.map +1 -1
  173. package/dist/types/interfaces/BundleData.d.ts +64 -0
  174. package/dist/types/interfaces/BundleData.d.ts.map +1 -0
  175. package/dist/types/interfaces/index.d.ts +1 -0
  176. package/dist/types/interfaces/index.d.ts.map +1 -1
  177. package/dist/types/providers/drpc.d.ts +3 -0
  178. package/dist/types/providers/drpc.d.ts.map +1 -0
  179. package/dist/types/providers/types.d.ts +1 -1
  180. package/dist/types/providers/types.d.ts.map +1 -1
  181. package/dist/types/providers/utils.d.ts.map +1 -1
  182. package/dist/types/utils/AddressUtils.d.ts +1 -0
  183. package/dist/types/utils/AddressUtils.d.ts.map +1 -1
  184. package/dist/types/utils/ContractUtils.d.ts +2 -0
  185. package/dist/types/utils/ContractUtils.d.ts.map +1 -0
  186. package/dist/types/utils/Multicall.d.ts +3 -2
  187. package/dist/types/utils/Multicall.d.ts.map +1 -1
  188. package/dist/types/utils/ObjectUtils.d.ts +18 -0
  189. package/dist/types/utils/ObjectUtils.d.ts.map +1 -1
  190. package/dist/types/utils/abi/contracts/index.d.ts +2 -0
  191. package/dist/types/utils/abi/contracts/index.d.ts.map +1 -0
  192. package/dist/types/utils/abi/typechain/Multicall3.d.ts +293 -0
  193. package/dist/types/utils/abi/typechain/Multicall3.d.ts.map +1 -0
  194. package/dist/types/utils/abi/typechain/common.d.ts +22 -0
  195. package/dist/types/utils/abi/typechain/common.d.ts.map +1 -0
  196. package/dist/types/utils/abi/typechain/factories/Multicall3__factory.d.ts +340 -0
  197. package/dist/types/utils/abi/typechain/factories/Multicall3__factory.d.ts.map +1 -0
  198. package/dist/types/utils/abi/typechain/factories/index.d.ts +2 -0
  199. package/dist/types/utils/abi/typechain/factories/index.d.ts.map +1 -0
  200. package/dist/types/utils/abi/typechain/index.d.ts +4 -0
  201. package/dist/types/utils/abi/typechain/index.d.ts.map +1 -0
  202. package/package.json +6 -8
  203. package/src/clients/BundleDataClient/BundleDataClient.ts +1311 -0
  204. package/src/clients/BundleDataClient/index.ts +2 -0
  205. package/src/clients/BundleDataClient/utils/DataworkerUtils.ts +268 -0
  206. package/src/clients/BundleDataClient/utils/FillUtils.ts +46 -0
  207. package/src/clients/BundleDataClient/utils/MerkleTreeUtils.ts +26 -0
  208. package/src/clients/BundleDataClient/utils/PoolRebalanceUtils.ts +238 -0
  209. package/src/clients/BundleDataClient/utils/SuperstructUtils.ts +132 -0
  210. package/src/clients/BundleDataClient/utils/index.ts +6 -0
  211. package/src/clients/BundleDataClient/utils/shims.ts +10 -0
  212. package/src/clients/index.ts +1 -0
  213. package/src/interfaces/BundleData.ts +68 -0
  214. package/src/interfaces/index.ts +1 -0
  215. package/src/providers/alchemy.ts +6 -6
  216. package/src/providers/drpc.ts +19 -0
  217. package/src/providers/infura.ts +6 -6
  218. package/src/providers/types.ts +1 -1
  219. package/src/providers/utils.ts +3 -1
  220. package/src/utils/AddressUtils.ts +15 -1
  221. package/src/utils/ContractUtils.ts +8 -0
  222. package/src/utils/Multicall.ts +38 -30
  223. package/src/utils/ObjectUtils.ts +23 -0
  224. package/src/utils/abi/contracts/index.ts +1 -0
  225. package/src/utils/abi/typechain/Multicall3.ts +433 -0
  226. package/src/utils/abi/typechain/common.ts +30 -0
  227. package/src/utils/abi/typechain/factories/Multicall3__factory.ts +458 -0
  228. package/src/utils/abi/typechain/factories/index.ts +4 -0
  229. package/src/utils/abi/typechain/index.ts +6 -0
@@ -0,0 +1,2 @@
1
+ export * from "./BundleDataClient";
2
+ export * from "./utils";
@@ -0,0 +1,268 @@
1
+ // Create a combined `refunds` object containing refunds for V2 + V3 fills
2
+
3
+ import {
4
+ BundleDepositsV3,
5
+ BundleExcessSlowFills,
6
+ BundleFillsV3,
7
+ BundleSlowFills,
8
+ CombinedRefunds,
9
+ ExpiredDepositsToRefundV3,
10
+ PoolRebalanceLeaf,
11
+ Refund,
12
+ RunningBalances,
13
+ } from "../../../interfaces";
14
+ import {
15
+ bnZero,
16
+ AnyObject,
17
+ groupObjectCountsByTwoProps,
18
+ fixedPointAdjustment,
19
+ count2DDictionaryValues,
20
+ count3DDictionaryValues,
21
+ } from "../../../utils";
22
+ import {
23
+ addLastRunningBalance,
24
+ constructPoolRebalanceLeaves,
25
+ PoolRebalanceRoot,
26
+ updateRunningBalance,
27
+ updateRunningBalanceForDeposit,
28
+ } from "./PoolRebalanceUtils";
29
+ import { V3FillWithBlock } from "./shims";
30
+ import { AcrossConfigStoreClient } from "../../AcrossConfigStoreClient";
31
+ import { HubPoolClient } from "../../HubPoolClient";
32
+ import { buildPoolRebalanceLeafTree } from "./MerkleTreeUtils";
33
+
34
+ // and expired deposits.
35
+ export function getRefundsFromBundle(
36
+ bundleFillsV3: BundleFillsV3,
37
+ expiredDepositsToRefundV3: ExpiredDepositsToRefundV3
38
+ ): CombinedRefunds {
39
+ const combinedRefunds: {
40
+ [repaymentChainId: string]: {
41
+ [repaymentToken: string]: Refund;
42
+ };
43
+ } = {};
44
+ Object.entries(bundleFillsV3).forEach(([repaymentChainId, fillsForChain]) => {
45
+ combinedRefunds[repaymentChainId] ??= {};
46
+ Object.entries(fillsForChain).forEach(([l2TokenAddress, { refunds }]) => {
47
+ // refunds can be undefined if these fills were all slow fill executions.
48
+ if (refunds === undefined) {
49
+ return;
50
+ }
51
+ // @dev use shallow copy so that modifying combinedRefunds doesn't modify the original refunds object.
52
+ const refundsShallowCopy = { ...refunds };
53
+ if (combinedRefunds[repaymentChainId][l2TokenAddress] === undefined) {
54
+ combinedRefunds[repaymentChainId][l2TokenAddress] = refundsShallowCopy;
55
+ } else {
56
+ // Each refunds object should have a unique refund address so we can add new ones to the
57
+ // existing dictionary.
58
+ combinedRefunds[repaymentChainId][l2TokenAddress] = {
59
+ ...combinedRefunds[repaymentChainId][l2TokenAddress],
60
+ ...refundsShallowCopy,
61
+ };
62
+ }
63
+ });
64
+ });
65
+ Object.entries(expiredDepositsToRefundV3).forEach(([originChainId, depositsForChain]) => {
66
+ combinedRefunds[originChainId] ??= {};
67
+ Object.entries(depositsForChain).forEach(([l2TokenAddress, deposits]) => {
68
+ deposits.forEach((deposit) => {
69
+ if (combinedRefunds[originChainId][l2TokenAddress] === undefined) {
70
+ combinedRefunds[originChainId][l2TokenAddress] = { [deposit.depositor]: deposit.inputAmount };
71
+ } else {
72
+ const existingRefundAmount = combinedRefunds[originChainId][l2TokenAddress][deposit.depositor];
73
+ combinedRefunds[originChainId][l2TokenAddress][deposit.depositor] = deposit.inputAmount.add(
74
+ existingRefundAmount ?? bnZero
75
+ );
76
+ }
77
+ });
78
+ });
79
+ });
80
+ return combinedRefunds;
81
+ }
82
+
83
+ export function prettyPrintV3SpokePoolEvents(
84
+ bundleDepositsV3: BundleDepositsV3,
85
+ bundleFillsV3: BundleFillsV3,
86
+ bundleInvalidFillsV3: V3FillWithBlock[],
87
+ bundleSlowFillsV3: BundleSlowFills,
88
+ expiredDepositsToRefundV3: ExpiredDepositsToRefundV3,
89
+ unexecutableSlowFills: BundleExcessSlowFills
90
+ ): AnyObject {
91
+ return {
92
+ bundleDepositsV3: count2DDictionaryValues(bundleDepositsV3),
93
+ bundleFillsV3: count3DDictionaryValues(bundleFillsV3, "fills"),
94
+ bundleSlowFillsV3: count2DDictionaryValues(bundleSlowFillsV3),
95
+ expiredDepositsToRefundV3: count2DDictionaryValues(expiredDepositsToRefundV3),
96
+ unexecutableSlowFills: count2DDictionaryValues(unexecutableSlowFills),
97
+ allInvalidFillsInRangeByDestinationChainAndRelayer: groupObjectCountsByTwoProps(
98
+ bundleInvalidFillsV3,
99
+ "destinationChainId",
100
+ (fill) => `${fill.relayer}`
101
+ ),
102
+ };
103
+ }
104
+
105
+ export function getEndBlockBuffers(
106
+ chainIdListForBundleEvaluationBlockNumbers: number[],
107
+ blockRangeEndBlockBuffer: { [chainId: number]: number }
108
+ ): number[] {
109
+ // These buffers can be configured by the bot runner. They have two use cases:
110
+ // 1) Validate the end blocks specified in the pending root bundle. If the end block is greater than the latest
111
+ // block for its chain, then we should dispute the bundle because we can't look up events in the future for that
112
+ // chain. However, there are some cases where the proposer's node for that chain is returning a higher HEAD block
113
+ // than the bot-runner is seeing, so we can use this buffer to allow the proposer some margin of error. If
114
+ // the bundle end block is less than HEAD but within this buffer, then we won't dispute and we'll just exit
115
+ // early from this function.
116
+ // 2) Subtract from the latest block in a new root bundle proposal. This can be used to reduce the chance that
117
+ // bot runs using different providers see different contract state close to the HEAD block for a chain.
118
+ // Reducing the latest block that we query also gives partially filled deposits slightly more buffer for relayers
119
+ // to fully fill the deposit and reduces the chance that the data worker includes a slow fill payment that gets
120
+ // filled during the challenge period.
121
+ return chainIdListForBundleEvaluationBlockNumbers.map((chainId: number) => blockRangeEndBlockBuffer[chainId] ?? 0);
122
+ }
123
+
124
+ export function _buildPoolRebalanceRoot(
125
+ latestMainnetBlock: number,
126
+ mainnetBundleEndBlock: number,
127
+ bundleV3Deposits: BundleDepositsV3,
128
+ bundleFillsV3: BundleFillsV3,
129
+ bundleSlowFillsV3: BundleSlowFills,
130
+ unexecutableSlowFills: BundleExcessSlowFills,
131
+ expiredDepositsToRefundV3: ExpiredDepositsToRefundV3,
132
+ clients: { hubPoolClient: HubPoolClient; configStoreClient: AcrossConfigStoreClient },
133
+ maxL1TokenCountOverride?: number
134
+ ): PoolRebalanceRoot {
135
+ // Running balances are the amount of tokens that we need to send to each SpokePool to pay for all instant and
136
+ // slow relay refunds. They are decreased by the amount of funds already held by the SpokePool. Balances are keyed
137
+ // by the SpokePool's network and L1 token equivalent of the L2 token to refund.
138
+ // Realized LP fees are keyed the same as running balances and represent the amount of LP fees that should be paid
139
+ // to LP's for each running balance.
140
+
141
+ // For each FilledRelay group, identified by { repaymentChainId, L1TokenAddress }, initialize a "running balance"
142
+ // to the total refund amount for that group.
143
+ const runningBalances: RunningBalances = {};
144
+ const realizedLpFees: RunningBalances = {};
145
+
146
+ /**
147
+ * REFUNDS FOR FAST FILLS
148
+ */
149
+
150
+ // Add running balances and lp fees for v3 relayer refunds using BundleDataClient.bundleFillsV3. Refunds
151
+ // should be equal to inputAmount - lpFees so that relayers get to keep the relayer fee. Add the refund amount
152
+ // to the running balance for the repayment chain.
153
+ Object.entries(bundleFillsV3).forEach(([_repaymentChainId, fillsForChain]) => {
154
+ const repaymentChainId = Number(_repaymentChainId);
155
+ Object.entries(fillsForChain).forEach(
156
+ ([l2TokenAddress, { realizedLpFees: totalRealizedLpFee, totalRefundAmount }]) => {
157
+ const l1TokenCounterpart = clients.hubPoolClient.getL1TokenForL2TokenAtBlock(
158
+ l2TokenAddress,
159
+ repaymentChainId,
160
+ mainnetBundleEndBlock
161
+ );
162
+
163
+ updateRunningBalance(runningBalances, repaymentChainId, l1TokenCounterpart, totalRefundAmount);
164
+ updateRunningBalance(realizedLpFees, repaymentChainId, l1TokenCounterpart, totalRealizedLpFee);
165
+ }
166
+ );
167
+ });
168
+
169
+ /**
170
+ * PAYMENTS SLOW FILLS
171
+ */
172
+
173
+ // Add running balances and lp fees for v3 slow fills using BundleDataClient.bundleSlowFillsV3.
174
+ // Slow fills should still increment bundleLpFees and updatedOutputAmount should be equal to inputAmount - lpFees.
175
+ // Increment the updatedOutputAmount to the destination chain.
176
+ Object.entries(bundleSlowFillsV3).forEach(([_destinationChainId, depositsForChain]) => {
177
+ const destinationChainId = Number(_destinationChainId);
178
+ Object.entries(depositsForChain).forEach(([outputToken, deposits]) => {
179
+ deposits.forEach((deposit) => {
180
+ const l1TokenCounterpart = clients.hubPoolClient.getL1TokenForL2TokenAtBlock(
181
+ outputToken,
182
+ destinationChainId,
183
+ mainnetBundleEndBlock
184
+ );
185
+ const lpFee = deposit.lpFeePct.mul(deposit.inputAmount).div(fixedPointAdjustment);
186
+ updateRunningBalance(runningBalances, destinationChainId, l1TokenCounterpart, deposit.inputAmount.sub(lpFee));
187
+ // Slow fill LP fees are accounted for when the slow fill executes and a V3FilledRelay is emitted. i.e. when
188
+ // the slow fill execution is included in bundleFillsV3.
189
+ });
190
+ });
191
+ });
192
+
193
+ /**
194
+ * EXCESSES FROM UNEXECUTABLE SLOW FILLS
195
+ */
196
+
197
+ // Subtract destination chain running balances for BundleDataClient.unexecutableSlowFills.
198
+ // These are all slow fills that are impossible to execute and therefore the amount to return would be
199
+ // the updatedOutputAmount = inputAmount - lpFees.
200
+ Object.entries(unexecutableSlowFills).forEach(([_destinationChainId, slowFilledDepositsForChain]) => {
201
+ const destinationChainId = Number(_destinationChainId);
202
+ Object.entries(slowFilledDepositsForChain).forEach(([outputToken, slowFilledDeposits]) => {
203
+ slowFilledDeposits.forEach((deposit) => {
204
+ const l1TokenCounterpart = clients.hubPoolClient.getL1TokenForL2TokenAtBlock(
205
+ outputToken,
206
+ destinationChainId,
207
+ mainnetBundleEndBlock
208
+ );
209
+ const lpFee = deposit.lpFeePct.mul(deposit.inputAmount).div(fixedPointAdjustment);
210
+ updateRunningBalance(runningBalances, destinationChainId, l1TokenCounterpart, lpFee.sub(deposit.inputAmount));
211
+ // Slow fills don't add to lpFees, only when the slow fill is executed and a V3FilledRelay is emitted, so
212
+ // we don't need to subtract it here. Moreover, the HubPoole expects bundleLpFees to be > 0.
213
+ });
214
+ });
215
+ });
216
+
217
+ /**
218
+ * DEPOSITS
219
+ */
220
+
221
+ // Handle v3Deposits. These decrement running balances from the origin chain equal to the inputAmount.
222
+ // There should not be early deposits in v3.
223
+ Object.entries(bundleV3Deposits).forEach(([, depositsForChain]) => {
224
+ Object.entries(depositsForChain).forEach(([, deposits]) => {
225
+ deposits.forEach((deposit) => {
226
+ updateRunningBalanceForDeposit(runningBalances, clients.hubPoolClient, deposit, deposit.inputAmount.mul(-1));
227
+ });
228
+ });
229
+ });
230
+
231
+ /**
232
+ * REFUNDS FOR EXPIRED DEPOSITS
233
+ */
234
+
235
+ // Add origin chain running balance for expired v3 deposits. These should refund the inputAmount.
236
+ Object.entries(expiredDepositsToRefundV3).forEach(([_originChainId, depositsForChain]) => {
237
+ const originChainId = Number(_originChainId);
238
+ Object.entries(depositsForChain).forEach(([inputToken, deposits]) => {
239
+ deposits.forEach((deposit) => {
240
+ const l1TokenCounterpart = clients.hubPoolClient.getL1TokenForL2TokenAtBlock(
241
+ inputToken,
242
+ originChainId,
243
+ mainnetBundleEndBlock
244
+ );
245
+ updateRunningBalance(runningBalances, originChainId, l1TokenCounterpart, deposit.inputAmount);
246
+ });
247
+ });
248
+ });
249
+
250
+ // Add to the running balance value from the last valid root bundle proposal for {chainId, l1Token}
251
+ // combination if found.
252
+ addLastRunningBalance(latestMainnetBlock, runningBalances, clients.hubPoolClient);
253
+
254
+ const leaves: PoolRebalanceLeaf[] = constructPoolRebalanceLeaves(
255
+ mainnetBundleEndBlock,
256
+ runningBalances,
257
+ realizedLpFees,
258
+ clients.configStoreClient,
259
+ maxL1TokenCountOverride
260
+ );
261
+
262
+ return {
263
+ runningBalances,
264
+ realizedLpFees,
265
+ leaves,
266
+ tree: buildPoolRebalanceLeafTree(leaves),
267
+ };
268
+ }
@@ -0,0 +1,46 @@
1
+ import { Fill } from "../../../interfaces";
2
+ import { getBlockRangeForChain, isSlowFill } from "../../../utils";
3
+ import { HubPoolClient } from "../../HubPoolClient";
4
+
5
+ export function getRefundInformationFromFill(
6
+ fill: Fill,
7
+ hubPoolClient: HubPoolClient,
8
+ blockRangesForChains: number[][],
9
+ chainIdListForBundleEvaluationBlockNumbers: number[],
10
+ fromLiteChain: boolean
11
+ ): {
12
+ chainToSendRefundTo: number;
13
+ repaymentToken: string;
14
+ } {
15
+ // Handle slow relay where repaymentChainId = 0. Slow relays always pay recipient on destination chain.
16
+ // So, save the slow fill under the destination chain, and save the fast fill under its repayment chain.
17
+ let chainToSendRefundTo = isSlowFill(fill) ? fill.destinationChainId : fill.repaymentChainId;
18
+ // If the fill is for a deposit originating from the lite chain, the repayment chain is the origin chain
19
+ // regardless of whether it is a slow or fast fill (we ignore slow fills but this is for posterity).
20
+ if (fromLiteChain) {
21
+ chainToSendRefundTo = fill.originChainId;
22
+ }
23
+
24
+ // Save fill data and associate with repayment chain and L2 token refund should be denominated in.
25
+ const endBlockForMainnet = getBlockRangeForChain(
26
+ blockRangesForChains,
27
+ hubPoolClient.chainId,
28
+ chainIdListForBundleEvaluationBlockNumbers
29
+ )[1];
30
+
31
+ const l1TokenCounterpart = hubPoolClient.getL1TokenForL2TokenAtBlock(
32
+ fill.inputToken,
33
+ fill.originChainId,
34
+ endBlockForMainnet
35
+ );
36
+
37
+ const repaymentToken = hubPoolClient.getL2TokenForL1TokenAtBlock(
38
+ l1TokenCounterpart,
39
+ chainToSendRefundTo,
40
+ endBlockForMainnet
41
+ );
42
+ return {
43
+ chainToSendRefundTo,
44
+ repaymentToken,
45
+ };
46
+ }
@@ -0,0 +1,26 @@
1
+ import { MerkleTree } from "@across-protocol/contracts";
2
+ import { PoolRebalanceLeaf } from "../../../interfaces";
3
+ import { getParamType } from "../../../utils/ContractUtils";
4
+ import { utils } from "ethers";
5
+
6
+ export function buildPoolRebalanceLeafTree(poolRebalanceLeaves: PoolRebalanceLeaf[]): MerkleTree<PoolRebalanceLeaf> {
7
+ for (let i = 0; i < poolRebalanceLeaves.length; i++) {
8
+ // The 4 provided parallel arrays must be of equal length. Running Balances can optionally be 2x the length
9
+ if (
10
+ poolRebalanceLeaves[i].l1Tokens.length !== poolRebalanceLeaves[i].bundleLpFees.length ||
11
+ poolRebalanceLeaves[i].netSendAmounts.length !== poolRebalanceLeaves[i].bundleLpFees.length
12
+ ) {
13
+ throw new Error("Provided lef arrays are not of equal length");
14
+ }
15
+ if (
16
+ poolRebalanceLeaves[i].runningBalances.length !== poolRebalanceLeaves[i].bundleLpFees.length * 2 &&
17
+ poolRebalanceLeaves[i].runningBalances.length !== poolRebalanceLeaves[i].bundleLpFees.length
18
+ ) {
19
+ throw new Error("Running balances length unexpected");
20
+ }
21
+ }
22
+
23
+ const paramType = getParamType("MerkleLibTest", "verifyPoolRebalance", "rebalance");
24
+ const hashFn = (input: PoolRebalanceLeaf) => utils.keccak256(utils.defaultAbiCoder.encode([paramType], [input]));
25
+ return new MerkleTree<PoolRebalanceLeaf>(poolRebalanceLeaves, hashFn);
26
+ }
@@ -0,0 +1,238 @@
1
+ import { MerkleTree } from "@across-protocol/contracts/dist/utils/MerkleTree";
2
+ import { RunningBalances, PoolRebalanceLeaf, Clients, SpokePoolTargetBalance } from "../../../interfaces";
3
+ import { SpokePoolClient } from "../../SpokePoolClient";
4
+ import { BigNumber } from "ethers";
5
+ import { bnZero, compareAddresses } from "../../../utils";
6
+ import { HubPoolClient } from "../../HubPoolClient";
7
+ import { V3DepositWithBlock } from "./shims";
8
+ import { AcrossConfigStoreClient } from "../../AcrossConfigStoreClient";
9
+
10
+ export type PoolRebalanceRoot = {
11
+ runningBalances: RunningBalances;
12
+ realizedLpFees: RunningBalances;
13
+ leaves: PoolRebalanceLeaf[];
14
+ tree: MerkleTree<PoolRebalanceLeaf>;
15
+ };
16
+
17
+ // This returns a possible next block range that could be submitted as a new root bundle, or used as a reference
18
+ // when evaluating pending root bundle. The block end numbers must be less than the latest blocks for each chain ID
19
+ // (because we can't evaluate events in the future), and greater than the expected start blocks, which are the
20
+ // greater of 0 and the latest bundle end block for an executed root bundle proposal + 1.
21
+ export function getWidestPossibleExpectedBlockRange(
22
+ chainIdListForBundleEvaluationBlockNumbers: number[],
23
+ spokeClients: { [chainId: number]: SpokePoolClient },
24
+ endBlockBuffers: number[],
25
+ clients: Clients,
26
+ latestMainnetBlock: number,
27
+ enabledChains: number[]
28
+ ): number[][] {
29
+ // We impose a buffer on the head of the chain to increase the probability that the received blocks are final.
30
+ // Reducing the latest block that we query also gives partially filled deposits slightly more buffer for relayers
31
+ // to fully fill the deposit and reduces the chance that the data worker includes a slow fill payment that gets
32
+ // filled during the challenge period.
33
+ const latestPossibleBundleEndBlockNumbers = chainIdListForBundleEvaluationBlockNumbers.map(
34
+ (chainId: number, index) =>
35
+ spokeClients[chainId] && Math.max(spokeClients[chainId].latestBlockSearched - endBlockBuffers[index], 0)
36
+ );
37
+ return chainIdListForBundleEvaluationBlockNumbers.map((chainId: number, index) => {
38
+ const lastEndBlockForChain = clients.hubPoolClient.getLatestBundleEndBlockForChain(
39
+ chainIdListForBundleEvaluationBlockNumbers,
40
+ latestMainnetBlock,
41
+ chainId
42
+ );
43
+
44
+ // If chain is disabled, re-use the latest bundle end block for the chain as both the start
45
+ // and end block.
46
+ if (!enabledChains.includes(chainId)) {
47
+ return [lastEndBlockForChain, lastEndBlockForChain];
48
+ } else {
49
+ // If the latest block hasn't advanced enough from the previous proposed end block, then re-use it. It will
50
+ // be regarded as disabled by the Dataworker clients. Otherwise, add 1 to the previous proposed end block.
51
+ if (lastEndBlockForChain >= latestPossibleBundleEndBlockNumbers[index]) {
52
+ // @dev: Without this check, then `getNextBundleStartBlockNumber` could return `latestBlock+1` even when the
53
+ // latest block for the chain hasn't advanced, resulting in an invalid range being produced.
54
+ return [lastEndBlockForChain, lastEndBlockForChain];
55
+ } else {
56
+ // Chain has advanced far enough including the buffer, return range from previous proposed end block + 1 to
57
+ // latest block for chain minus buffer.
58
+ return [
59
+ clients.hubPoolClient.getNextBundleStartBlockNumber(
60
+ chainIdListForBundleEvaluationBlockNumbers,
61
+ latestMainnetBlock,
62
+ chainId
63
+ ),
64
+ latestPossibleBundleEndBlockNumbers[index],
65
+ ];
66
+ }
67
+ }
68
+ });
69
+ }
70
+
71
+ export function isChainDisabled(blockRangeForChain: number[]): boolean {
72
+ return blockRangeForChain[0] === blockRangeForChain[1];
73
+ }
74
+
75
+ // Note: this function computes the intended transfer amount before considering the transfer threshold.
76
+ // A positive number indicates a transfer from hub to spoke.
77
+ export function computeDesiredTransferAmountToSpoke(
78
+ runningBalance: BigNumber,
79
+ spokePoolTargetBalance: SpokePoolTargetBalance
80
+ ): BigNumber {
81
+ // Transfer is always desired if hub owes spoke.
82
+ if (runningBalance.gte(0)) {
83
+ return runningBalance;
84
+ }
85
+
86
+ // Running balance is negative, but its absolute value is less than the spoke pool target balance threshold.
87
+ // In this case, we transfer nothing.
88
+ if (runningBalance.abs().lt(spokePoolTargetBalance.threshold)) {
89
+ return bnZero;
90
+ }
91
+
92
+ // We are left with the case where the spoke pool is beyond the threshold.
93
+ // A transfer needs to be initiated to bring it down to the target.
94
+ const transferSize = runningBalance.abs().sub(spokePoolTargetBalance.target);
95
+
96
+ // If the transferSize is < 0, this indicates that the target is still above the running balance.
97
+ // This can only happen if the threshold is less than the target. This is likely due to a misconfiguration.
98
+ // In this case, we transfer nothing until the target is exceeded.
99
+ if (transferSize.lt(0)) {
100
+ return bnZero;
101
+ }
102
+
103
+ // Negate the transfer size because a transfer from spoke to hub is indicated by a negative number.
104
+ return transferSize.mul(-1);
105
+ }
106
+
107
+ // If the running balance is greater than the token transfer threshold, then set the net send amount
108
+ // equal to the running balance and reset the running balance to 0. Otherwise, the net send amount should be
109
+ // 0, indicating that we do not want the data worker to trigger a token transfer between hub pool and spoke
110
+ // pool when executing this leaf.
111
+ export function getNetSendAmountForL1Token(
112
+ spokePoolTargetBalance: SpokePoolTargetBalance,
113
+ runningBalance: BigNumber
114
+ ): BigNumber {
115
+ return computeDesiredTransferAmountToSpoke(runningBalance, spokePoolTargetBalance);
116
+ }
117
+
118
+ export function getRunningBalanceForL1Token(
119
+ spokePoolTargetBalance: SpokePoolTargetBalance,
120
+ runningBalance: BigNumber
121
+ ): BigNumber {
122
+ const desiredTransferAmount = computeDesiredTransferAmountToSpoke(runningBalance, spokePoolTargetBalance);
123
+ return runningBalance.sub(desiredTransferAmount);
124
+ }
125
+
126
+ export function updateRunningBalance(
127
+ runningBalances: RunningBalances,
128
+ l2ChainId: number,
129
+ l1Token: string,
130
+ updateAmount: BigNumber
131
+ ): void {
132
+ // Initialize dictionary if empty.
133
+ if (!runningBalances[l2ChainId]) {
134
+ runningBalances[l2ChainId] = {};
135
+ }
136
+ const runningBalance = runningBalances[l2ChainId][l1Token];
137
+ if (runningBalance) {
138
+ runningBalances[l2ChainId][l1Token] = runningBalance.add(updateAmount);
139
+ } else {
140
+ runningBalances[l2ChainId][l1Token] = updateAmount;
141
+ }
142
+ }
143
+
144
+ export function addLastRunningBalance(
145
+ latestMainnetBlock: number,
146
+ runningBalances: RunningBalances,
147
+ hubPoolClient: HubPoolClient
148
+ ): void {
149
+ Object.keys(runningBalances).forEach((repaymentChainId) => {
150
+ Object.keys(runningBalances[Number(repaymentChainId)]).forEach((l1TokenAddress) => {
151
+ const { runningBalance } = hubPoolClient.getRunningBalanceBeforeBlockForChain(
152
+ latestMainnetBlock,
153
+ Number(repaymentChainId),
154
+ l1TokenAddress
155
+ );
156
+ if (!runningBalance.eq(bnZero)) {
157
+ updateRunningBalance(runningBalances, Number(repaymentChainId), l1TokenAddress, runningBalance);
158
+ }
159
+ });
160
+ });
161
+ }
162
+
163
+ export function updateRunningBalanceForDeposit(
164
+ runningBalances: RunningBalances,
165
+ hubPoolClient: HubPoolClient,
166
+ deposit: V3DepositWithBlock,
167
+ updateAmount: BigNumber
168
+ ): void {
169
+ const l1TokenCounterpart = hubPoolClient.getL1TokenForL2TokenAtBlock(
170
+ deposit.inputToken,
171
+ deposit.originChainId,
172
+ deposit.quoteBlockNumber
173
+ );
174
+ updateRunningBalance(runningBalances, deposit.originChainId, l1TokenCounterpart, updateAmount);
175
+ }
176
+
177
+ export function constructPoolRebalanceLeaves(
178
+ latestMainnetBlock: number,
179
+ runningBalances: RunningBalances,
180
+ realizedLpFees: RunningBalances,
181
+ configStoreClient: AcrossConfigStoreClient,
182
+ maxL1TokenCount?: number
183
+ ): PoolRebalanceLeaf[] {
184
+ // Create one leaf per L2 chain ID. First we'll create a leaf with all L1 tokens for each chain ID, and then
185
+ // we'll split up any leaves with too many L1 tokens.
186
+ const leaves: PoolRebalanceLeaf[] = [];
187
+ Object.keys(runningBalances)
188
+ .map((chainId) => Number(chainId))
189
+ // Leaves should be sorted by ascending chain ID
190
+ .sort((chainIdA, chainIdB) => chainIdA - chainIdB)
191
+ .map((chainId) => {
192
+ // Sort addresses.
193
+ const sortedL1Tokens = Object.keys(runningBalances[chainId]).sort((addressA, addressB) => {
194
+ return compareAddresses(addressA, addressB);
195
+ });
196
+
197
+ // This begins at 0 and increments for each leaf for this { chainId, L1Token } combination.
198
+ let groupIndexForChainId = 0;
199
+
200
+ // Split addresses into multiple leaves if there are more L1 tokens than allowed per leaf.
201
+ const maxL1TokensPerLeaf =
202
+ maxL1TokenCount || configStoreClient.getMaxRefundCountForRelayerRefundLeafForBlock(latestMainnetBlock);
203
+ for (let i = 0; i < sortedL1Tokens.length; i += maxL1TokensPerLeaf) {
204
+ const l1TokensToIncludeInThisLeaf = sortedL1Tokens.slice(i, i + maxL1TokensPerLeaf);
205
+
206
+ const spokeTargetBalances = l1TokensToIncludeInThisLeaf.map((l1Token) =>
207
+ configStoreClient.getSpokeTargetBalancesForBlock(l1Token, chainId, latestMainnetBlock)
208
+ );
209
+
210
+ // Build leaves using running balances and realized lp fees data for l1Token + chain, or default to
211
+ // zero if undefined.
212
+ const leafBundleLpFees = l1TokensToIncludeInThisLeaf.map(
213
+ (l1Token) => realizedLpFees[chainId]?.[l1Token] ?? bnZero
214
+ );
215
+ const leafNetSendAmounts = l1TokensToIncludeInThisLeaf.map((l1Token, index) =>
216
+ runningBalances[chainId] && runningBalances[chainId][l1Token]
217
+ ? getNetSendAmountForL1Token(spokeTargetBalances[index], runningBalances[chainId][l1Token])
218
+ : bnZero
219
+ );
220
+ const leafRunningBalances = l1TokensToIncludeInThisLeaf.map((l1Token, index) =>
221
+ runningBalances[chainId]?.[l1Token]
222
+ ? getRunningBalanceForL1Token(spokeTargetBalances[index], runningBalances[chainId][l1Token])
223
+ : bnZero
224
+ );
225
+
226
+ leaves.push({
227
+ chainId: chainId,
228
+ bundleLpFees: leafBundleLpFees,
229
+ netSendAmounts: leafNetSendAmounts,
230
+ runningBalances: leafRunningBalances,
231
+ groupIndex: groupIndexForChainId++,
232
+ leafId: leaves.length,
233
+ l1Tokens: l1TokensToIncludeInThisLeaf,
234
+ });
235
+ }
236
+ });
237
+ return leaves;
238
+ }