@across-protocol/sdk 4.3.114-beta.0 → 4.3.114

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 (130) hide show
  1. package/dist/cjs/index.d.ts +0 -1
  2. package/dist/cjs/index.js +1 -2
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/esm/index.d.ts +0 -1
  5. package/dist/esm/index.js +0 -2
  6. package/dist/esm/index.js.map +1 -1
  7. package/dist/types/index.d.ts +0 -1
  8. package/dist/types/index.d.ts.map +1 -1
  9. package/package.json +1 -2
  10. package/src/index.ts +0 -1
  11. package/dist/cjs/pool/TransactionManager.d.ts +0 -12
  12. package/dist/cjs/pool/TransactionManager.js +0 -121
  13. package/dist/cjs/pool/TransactionManager.js.map +0 -1
  14. package/dist/cjs/pool/index.d.ts +0 -1
  15. package/dist/cjs/pool/index.js +0 -5
  16. package/dist/cjs/pool/index.js.map +0 -1
  17. package/dist/cjs/pool/poolClient.d.ts +0 -228
  18. package/dist/cjs/pool/poolClient.js +0 -869
  19. package/dist/cjs/pool/poolClient.js.map +0 -1
  20. package/dist/cjs/pool/uma/across/constants.d.ts +0 -2
  21. package/dist/cjs/pool/uma/across/constants.js +0 -6
  22. package/dist/cjs/pool/uma/across/constants.js.map +0 -1
  23. package/dist/cjs/pool/uma/across/index.d.ts +0 -2
  24. package/dist/cjs/pool/uma/across/index.js +0 -8
  25. package/dist/cjs/pool/uma/across/index.js.map +0 -1
  26. package/dist/cjs/pool/uma/across/transactionManager.d.ts +0 -12
  27. package/dist/cjs/pool/uma/across/transactionManager.js +0 -121
  28. package/dist/cjs/pool/uma/across/transactionManager.js.map +0 -1
  29. package/dist/cjs/pool/uma/clients/erc20/client.d.ts +0 -26
  30. package/dist/cjs/pool/uma/clients/erc20/client.js +0 -38
  31. package/dist/cjs/pool/uma/clients/erc20/client.js.map +0 -1
  32. package/dist/cjs/pool/uma/clients/erc20/index.d.ts +0 -1
  33. package/dist/cjs/pool/uma/clients/erc20/index.js +0 -5
  34. package/dist/cjs/pool/uma/clients/erc20/index.js.map +0 -1
  35. package/dist/cjs/pool/uma/clients/index.d.ts +0 -1
  36. package/dist/cjs/pool/uma/clients/index.js +0 -6
  37. package/dist/cjs/pool/uma/clients/index.js.map +0 -1
  38. package/dist/cjs/pool/uma/index.d.ts +0 -13
  39. package/dist/cjs/pool/uma/index.js +0 -9
  40. package/dist/cjs/pool/uma/index.js.map +0 -1
  41. package/dist/cjs/pool/uma/oracle/index.d.ts +0 -1
  42. package/dist/cjs/pool/uma/oracle/index.js +0 -6
  43. package/dist/cjs/pool/uma/oracle/index.js.map +0 -1
  44. package/dist/cjs/pool/uma/oracle/utils.d.ts +0 -7
  45. package/dist/cjs/pool/uma/oracle/utils.js +0 -20
  46. package/dist/cjs/pool/uma/oracle/utils.js.map +0 -1
  47. package/dist/cjs/pool/uma/utils.d.ts +0 -17
  48. package/dist/cjs/pool/uma/utils.js +0 -69
  49. package/dist/cjs/pool/uma/utils.js.map +0 -1
  50. package/dist/esm/pool/TransactionManager.d.ts +0 -12
  51. package/dist/esm/pool/TransactionManager.js +0 -122
  52. package/dist/esm/pool/TransactionManager.js.map +0 -1
  53. package/dist/esm/pool/index.d.ts +0 -1
  54. package/dist/esm/pool/index.js +0 -2
  55. package/dist/esm/pool/index.js.map +0 -1
  56. package/dist/esm/pool/poolClient.d.ts +0 -238
  57. package/dist/esm/pool/poolClient.js +0 -899
  58. package/dist/esm/pool/poolClient.js.map +0 -1
  59. package/dist/esm/pool/uma/across/constants.d.ts +0 -2
  60. package/dist/esm/pool/uma/across/constants.js +0 -3
  61. package/dist/esm/pool/uma/across/constants.js.map +0 -1
  62. package/dist/esm/pool/uma/across/index.d.ts +0 -2
  63. package/dist/esm/pool/uma/across/index.js +0 -4
  64. package/dist/esm/pool/uma/across/index.js.map +0 -1
  65. package/dist/esm/pool/uma/across/transactionManager.d.ts +0 -12
  66. package/dist/esm/pool/uma/across/transactionManager.js +0 -122
  67. package/dist/esm/pool/uma/across/transactionManager.js.map +0 -1
  68. package/dist/esm/pool/uma/clients/erc20/client.d.ts +0 -26
  69. package/dist/esm/pool/uma/clients/erc20/client.js +0 -35
  70. package/dist/esm/pool/uma/clients/erc20/client.js.map +0 -1
  71. package/dist/esm/pool/uma/clients/erc20/index.d.ts +0 -1
  72. package/dist/esm/pool/uma/clients/erc20/index.js +0 -2
  73. package/dist/esm/pool/uma/clients/erc20/index.js.map +0 -1
  74. package/dist/esm/pool/uma/clients/index.d.ts +0 -1
  75. package/dist/esm/pool/uma/clients/index.js +0 -3
  76. package/dist/esm/pool/uma/clients/index.js.map +0 -1
  77. package/dist/esm/pool/uma/index.d.ts +0 -13
  78. package/dist/esm/pool/uma/index.js +0 -9
  79. package/dist/esm/pool/uma/index.js.map +0 -1
  80. package/dist/esm/pool/uma/oracle/index.d.ts +0 -1
  81. package/dist/esm/pool/uma/oracle/index.js +0 -3
  82. package/dist/esm/pool/uma/oracle/index.js.map +0 -1
  83. package/dist/esm/pool/uma/oracle/utils.d.ts +0 -23
  84. package/dist/esm/pool/uma/oracle/utils.js +0 -33
  85. package/dist/esm/pool/uma/oracle/utils.js.map +0 -1
  86. package/dist/esm/pool/uma/utils.d.ts +0 -17
  87. package/dist/esm/pool/uma/utils.js +0 -68
  88. package/dist/esm/pool/uma/utils.js.map +0 -1
  89. package/dist/types/pool/TransactionManager.d.ts +0 -13
  90. package/dist/types/pool/TransactionManager.d.ts.map +0 -1
  91. package/dist/types/pool/index.d.ts +0 -2
  92. package/dist/types/pool/index.d.ts.map +0 -1
  93. package/dist/types/pool/poolClient.d.ts +0 -239
  94. package/dist/types/pool/poolClient.d.ts.map +0 -1
  95. package/dist/types/pool/uma/across/constants.d.ts +0 -3
  96. package/dist/types/pool/uma/across/constants.d.ts.map +0 -1
  97. package/dist/types/pool/uma/across/index.d.ts +0 -3
  98. package/dist/types/pool/uma/across/index.d.ts.map +0 -1
  99. package/dist/types/pool/uma/across/transactionManager.d.ts +0 -13
  100. package/dist/types/pool/uma/across/transactionManager.d.ts.map +0 -1
  101. package/dist/types/pool/uma/clients/erc20/client.d.ts +0 -27
  102. package/dist/types/pool/uma/clients/erc20/client.d.ts.map +0 -1
  103. package/dist/types/pool/uma/clients/erc20/index.d.ts +0 -2
  104. package/dist/types/pool/uma/clients/erc20/index.d.ts.map +0 -1
  105. package/dist/types/pool/uma/clients/index.d.ts +0 -2
  106. package/dist/types/pool/uma/clients/index.d.ts.map +0 -1
  107. package/dist/types/pool/uma/index.d.ts +0 -14
  108. package/dist/types/pool/uma/index.d.ts.map +0 -1
  109. package/dist/types/pool/uma/oracle/index.d.ts +0 -2
  110. package/dist/types/pool/uma/oracle/index.d.ts.map +0 -1
  111. package/dist/types/pool/uma/oracle/utils.d.ts +0 -24
  112. package/dist/types/pool/uma/oracle/utils.d.ts.map +0 -1
  113. package/dist/types/pool/uma/utils.d.ts +0 -18
  114. package/dist/types/pool/uma/utils.d.ts.map +0 -1
  115. package/src/pool/TransactionManager.ts +0 -73
  116. package/src/pool/index.ts +0 -1
  117. package/src/pool/poolClient.ts +0 -849
  118. package/src/pool/uma/across/constants.ts +0 -2
  119. package/src/pool/uma/across/index.ts +0 -2
  120. package/src/pool/uma/across/transactionManager.ts +0 -73
  121. package/src/pool/uma/clients/erc20/README.md +0 -29
  122. package/src/pool/uma/clients/erc20/client.e2e.ts +0 -26
  123. package/src/pool/uma/clients/erc20/client.ts +0 -67
  124. package/src/pool/uma/clients/erc20/index.ts +0 -1
  125. package/src/pool/uma/clients/index.ts +0 -1
  126. package/src/pool/uma/index.ts +0 -33
  127. package/src/pool/uma/oracle/index.ts +0 -2
  128. package/src/pool/uma/oracle/utils.ts +0 -38
  129. package/src/pool/uma/utils.test.ts +0 -24
  130. package/src/pool/uma/utils.ts +0 -53
@@ -1,849 +0,0 @@
1
- import assert from "assert";
2
- import * as uma from "./uma";
3
- import {
4
- bnZero,
5
- toBNWei,
6
- fixedPointAdjustment,
7
- calcPeriodicCompoundInterest,
8
- calcApr,
9
- BigNumber,
10
- BigNumberish,
11
- fromWei,
12
- } from "../utils";
13
- import { ethers, Signer } from "ethers";
14
- import type { Overrides } from "@ethersproject/contracts";
15
- import { TransactionRequest, TransactionReceipt, Log } from "@ethersproject/abstract-provider";
16
- import { Provider, Block } from "@ethersproject/providers";
17
- import set from "lodash/set";
18
- import get from "lodash/get";
19
- import has from "lodash/has";
20
- import { calculateInstantaneousRate, RateModel } from "../lpFeeCalculator";
21
- import { hubPool, acrossConfigStore } from "../contracts";
22
- import {
23
- AcceleratingDistributor,
24
- AcceleratingDistributor__factory,
25
- MerkleDistributor,
26
- MerkleDistributor__factory,
27
- TypedEvent,
28
- } from "../typechain";
29
-
30
- const { erc20 } = uma.clients;
31
- const { loop } = uma.utils;
32
- const { TransactionManager } = uma.across;
33
- const { SECONDS_PER_YEAR, DEFAULT_BLOCK_DELTA } = uma.across.constants;
34
- const { AddressZero } = ethers.constants;
35
-
36
- export type { Provider };
37
-
38
- export type Awaited<T> = T extends PromiseLike<infer U> ? U : T;
39
-
40
- export type Config = {
41
- chainId?: number;
42
- hubPoolAddress: string;
43
- acceleratingDistributorAddress: string;
44
- merkleDistributorAddress: string;
45
- wethAddress: string;
46
- configStoreAddress: string;
47
- confirmations?: number;
48
- blockDelta?: number;
49
- hasArchive?: boolean;
50
- hubPoolStartBlock?: number;
51
- };
52
- export type Dependencies = {
53
- provider: Provider;
54
- };
55
- export type StakeData = {
56
- cumulativeBalance: BigNumber;
57
- amountAirdropped: BigNumber;
58
- };
59
- export type Pool = {
60
- address: string;
61
- totalPoolSize: string;
62
- l1Token: string;
63
- lpToken: string;
64
- liquidReserves: string;
65
- exchangeRateCurrent: string;
66
- exchangeRatePrevious: string;
67
- estimatedApy: string;
68
- estimatedApr: string;
69
- blocksElapsed: number;
70
- secondsElapsed: number;
71
- utilizedReserves: string;
72
- projectedApr: string;
73
- liquidityUtilizationCurrent: string;
74
- };
75
- export type User = {
76
- address: string;
77
- poolAddress: string;
78
- lpTokens: string;
79
- positionValue: string;
80
- totalDeposited: string;
81
- feesEarned: string;
82
- };
83
- export type Transaction = {
84
- id: string;
85
- state: "requested" | "submitted" | "mined" | "error";
86
- toAddress: string;
87
- fromAddress: string;
88
- type: "Add Liquidity" | "Remove Liquidity";
89
- description: string;
90
- request?: TransactionRequest;
91
- hash?: string;
92
- receipt?: TransactionReceipt;
93
- error?: Error;
94
- };
95
- export type Token = {
96
- decimals: string;
97
- symbol: string;
98
- name: string;
99
- };
100
- export type State = {
101
- pools: Record<string, Pool>;
102
- users: Record<string, Record<string, User>>;
103
- transactions: Record<string, Transaction>;
104
- error?: Error;
105
- };
106
- export type EmitState = (path: string[], data: Pool | User | Transaction | Error) => void;
107
- export type PooledToken = {
108
- // LP token given to LPs of a specific L1 token.
109
- lpToken: string;
110
- // True if accepting new LP's.
111
- isEnabled: boolean;
112
- // Timestamp of last LP fee update.
113
- lastLpFeeUpdate: number;
114
- // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent
115
- // back later.
116
- utilizedReserves: BigNumber;
117
- // Number of LP funds held in contract less utilized reserves.
118
- liquidReserves: BigNumber;
119
- // Number of LP funds reserved to pay out to LPs as fees.
120
- undistributedLpFees: BigNumber;
121
- };
122
-
123
- class PoolState {
124
- constructor(
125
- private contract: hubPool.Instance,
126
- private address: string
127
- ) {}
128
- public async read(l1Token: string, latestBlock: number, previousBlock?: number) {
129
- // typechain does not have complete types for call options, so we have to cast blockTag to any
130
- const exchangeRatePrevious = await this.exchangeRateAtBlock(l1Token, previousBlock || latestBlock - 1);
131
-
132
- const exchangeRateCurrent = await this.contract.callStatic.exchangeRateCurrent(l1Token);
133
-
134
- const pooledToken: PooledToken = await this.contract.pooledTokens(l1Token);
135
- const liquidityUtilizationCurrent: BigNumber = await this.contract.callStatic.liquidityUtilizationCurrent(l1Token);
136
-
137
- return {
138
- address: this.address,
139
- l1Token,
140
- latestBlock,
141
- previousBlock,
142
- exchangeRatePrevious,
143
- exchangeRateCurrent,
144
- liquidityUtilizationCurrent,
145
- ...pooledToken,
146
- };
147
- }
148
- public exchangeRateAtBlock(l1Token: string, blockTag: number) {
149
- return this.contract.callStatic.exchangeRateCurrent(l1Token, { blockTag });
150
- }
151
- }
152
-
153
- type EventIdParams = { blockNumber: number; transactionIndex: number; logIndex: number };
154
- export class PoolEventState {
155
- private seen = new Set<string>();
156
- private iface: ethers.utils.Interface;
157
- // maintain ordered unique list of events so we can calculate state
158
- private events: uma.SerializableEvent[] = [];
159
- constructor(
160
- private contract: hubPool.Instance,
161
- private startBlock = 0
162
- ) {
163
- this.iface = new ethers.utils.Interface(hubPool.Factory.abi);
164
- }
165
- private makeId = (params: EventIdParams): string => {
166
- return uma.oracle.utils.eventKey(params);
167
- };
168
- hasEvent(params: EventIdParams): boolean {
169
- return this.seen.has(this.makeId(params));
170
- }
171
- private addEvent(params: EventIdParams): void {
172
- this.seen.add(this.makeId(params));
173
- }
174
- private filterSeen = (params: EventIdParams): boolean => {
175
- const seen = this.hasEvent(params);
176
- if (!seen) this.addEvent(params);
177
- return !seen;
178
- };
179
- private processEvent = (event: uma.SerializableEvent): void => {
180
- if (!this.filterSeen(event)) return;
181
- this.events = uma.oracle.utils.insertOrderedAscending(this.events, event, this.makeId);
182
- };
183
- private processEvents = (events: Array<uma.SerializableEvent>): void => {
184
- events.forEach(this.processEvent);
185
- };
186
-
187
- public async read(endBlock: number, l1TokenAddress?: string, userAddress?: string): Promise<hubPool.EventState> {
188
- const events = await Promise.all([
189
- ...(await this.contract.queryFilter(
190
- this.contract.filters.LiquidityAdded(l1TokenAddress, undefined, undefined, userAddress),
191
- this.startBlock,
192
- endBlock
193
- )),
194
- ...(await this.contract.queryFilter(
195
- this.contract.filters.LiquidityRemoved(l1TokenAddress, undefined, undefined, userAddress),
196
- this.startBlock,
197
- endBlock
198
- )),
199
- ]);
200
- this.processEvents(events);
201
- return hubPool.getEventState(this.events);
202
- }
203
- makeEventFromLog = (log: Log): uma.SerializableEvent => {
204
- const description = this.iface.parseLog(log);
205
- return {
206
- ...log,
207
- ...description,
208
- event: description.name,
209
- eventSignature: description.signature,
210
- };
211
- };
212
- getL1TokenFromReceipt(receipt: TransactionReceipt): string {
213
- const events = receipt.logs
214
- .filter((log) => ethers.utils.getAddress(log.address) === ethers.utils.getAddress(this.contract.address))
215
- .map(this.makeEventFromLog);
216
-
217
- // save these events
218
- this.processEvents(events);
219
- // only process token receipt events, because we just want the l1 token involved with this transfer
220
- const eventState = hubPool.getEventState(events);
221
- // event state is keyed by l1token address
222
- const l1Tokens = Object.keys(eventState);
223
- assert(l1Tokens.length, "Token not found from events");
224
- assert(l1Tokens.length === 1, "Multiple tokens found from events");
225
- return l1Tokens[0];
226
- }
227
- readTxReceipt(receipt: TransactionReceipt): hubPool.EventState {
228
- const events = receipt.logs
229
- .filter((log) => ethers.utils.getAddress(log.address) === ethers.utils.getAddress(this.contract.address))
230
- .map(this.makeEventFromLog);
231
- this.processEvents(events);
232
- return hubPool.getEventState(this.events);
233
- }
234
- }
235
-
236
- class UserState {
237
- private seen = new Set<string>();
238
- private events: uma.clients.erc20.Transfer[] = [];
239
- constructor(
240
- private contract: uma.clients.erc20.Instance,
241
- private userAddress: string,
242
- private startBlock = 0,
243
- private acceleratingDistributorContractAddress = ""
244
- ) {}
245
- private makeId(params: EventIdParams): string {
246
- return uma.oracle.utils.eventKey(params);
247
- }
248
- hasEvent(params: EventIdParams): boolean {
249
- return this.seen.has(this.makeId(params));
250
- }
251
- private addEvent(params: EventIdParams): void {
252
- this.seen.add(this.makeId(params));
253
- }
254
- private filterSeen = (params: EventIdParams): boolean => {
255
- const seen = this.hasEvent(params);
256
- if (!seen) this.addEvent(params);
257
- return !seen;
258
- };
259
- /**
260
- * readEvents. Fetch and cache events for the user.
261
- *
262
- * @param {number} endBlock
263
- */
264
- public async readEvents(endBlock: number): Promise<uma.clients.erc20.Transfer[]> {
265
- if (endBlock <= this.startBlock) return [];
266
- const { userAddress } = this;
267
- const events: TypedEvent<
268
- [string, string, BigNumber] & {
269
- from: string;
270
- to: string;
271
- value: BigNumber;
272
- }
273
- >[] = (
274
- await Promise.all([
275
- ...(await this.contract.queryFilter(
276
- this.contract.filters.Transfer(userAddress, undefined),
277
- this.startBlock,
278
- endBlock
279
- )),
280
- ...(await this.contract.queryFilter(
281
- this.contract.filters.Transfer(undefined, userAddress),
282
- this.startBlock,
283
- endBlock
284
- )),
285
- ])
286
- )
287
- // filter out events we have seen
288
- .filter(this.filterSeen)
289
- // filter out mint/burn transfers
290
- .filter(
291
- (event: uma.clients.erc20.Transfer) =>
292
- // ignore mint events
293
- event.args.from !== AddressZero &&
294
- // ignore burn events
295
- event.args.to !== AddressZero &&
296
- // ignore AD transfer events in
297
- event.args.to !== this.acceleratingDistributorContractAddress &&
298
- // ignore AD transfer events out
299
- event.args.from !== this.acceleratingDistributorContractAddress &&
300
- // ignore self transfer events
301
- event.args.from !== event.args.to
302
- )
303
- .flat();
304
-
305
- this.events = this.events.concat(events).sort((a, b) => {
306
- if (a.blockNumber !== b.blockNumber) return a.blockNumber - b.blockNumber;
307
- if (a.transactionIndex !== b.transactionIndex) return a.transactionIndex - b.transactionIndex;
308
- if (a.logIndex !== b.logIndex) return a.logIndex - b.logIndex;
309
- throw new Error("Duplicate events at tx hash: " + a.transactionHash);
310
- });
311
- // ethers queries are inclusive [start,end] unless start === end, then exclusive (start,end). we increment to make sure we dont see same event twice
312
- this.startBlock = endBlock + 1;
313
- return this.events;
314
- }
315
- /**
316
- * read. Reads the state for the user, building state from events as well as contract calls.
317
- *
318
- * @param {number} endBlock
319
- */
320
- public async read(endBlock: number) {
321
- const { userAddress } = this;
322
- const transferEvents = await this.readEvents(endBlock);
323
- const state = uma.clients.erc20.getEventState(transferEvents);
324
- const balanceTransferred = state?.balances?.[userAddress] || "0";
325
- return {
326
- transferEvents,
327
- balanceTransferred,
328
- address: userAddress,
329
- balanceOf: await this.contract.balanceOf(userAddress),
330
- };
331
- }
332
- }
333
-
334
- export function calculateRemoval(amountWei: BigNumber, percentWei: BigNumber) {
335
- const receive = amountWei.mul(percentWei).div(fixedPointAdjustment);
336
- const remain = amountWei.sub(receive);
337
- return {
338
- receive: receive.toString(),
339
- remain: remain.toString(),
340
- };
341
- }
342
- // params here mimic the user object type
343
- export function previewRemoval(
344
- values: { positionValue: BigNumberish; feesEarned: BigNumberish; totalDeposited: BigNumberish },
345
- percentFloat: number
346
- ) {
347
- const percentWei = toBNWei(percentFloat);
348
- return {
349
- position: {
350
- ...calculateRemoval(BigNumber.from(values.totalDeposited), percentWei),
351
- },
352
- fees: {
353
- ...calculateRemoval(BigNumber.from(values.feesEarned), percentWei),
354
- },
355
- total: {
356
- ...calculateRemoval(BigNumber.from(values.positionValue), percentWei),
357
- },
358
- };
359
- }
360
- function joinUserState(
361
- poolState: Pool,
362
- tokenEventState: hubPool.TokenEventState,
363
- userState: Awaited<ReturnType<UserState["read"]>>,
364
- transferValue = bnZero,
365
- cumulativeStakeBalance = bnZero,
366
- cumulativeStakeClaimBalance = bnZero
367
- ): User {
368
- const positionValue = BigNumber.from(poolState.exchangeRateCurrent)
369
- .mul(userState.balanceOf.add(cumulativeStakeBalance))
370
- .div(fixedPointAdjustment);
371
- const totalDeposited = BigNumber.from(tokenEventState?.tokenBalances[userState.address] || "0").add(
372
- cumulativeStakeClaimBalance
373
- );
374
- const feesEarned = positionValue.sub(totalDeposited.add(transferValue));
375
- return {
376
- address: userState.address,
377
- poolAddress: poolState.address,
378
- lpTokens: userState.balanceOf.toString(),
379
- positionValue: positionValue.toString(),
380
- totalDeposited: totalDeposited.toString(),
381
- feesEarned: feesEarned.toString(),
382
- };
383
- }
384
- function joinPoolState(
385
- poolState: Awaited<ReturnType<PoolState["read"]>>,
386
- latestBlock: Block,
387
- previousBlock: Block,
388
- rateModel?: RateModel
389
- ): Pool {
390
- const totalPoolSize = poolState.liquidReserves.add(poolState.utilizedReserves);
391
- const secondsElapsed = latestBlock.timestamp - previousBlock.timestamp;
392
- const blocksElapsed = latestBlock.number - previousBlock.number;
393
- const exchangeRatePrevious = poolState.exchangeRatePrevious.toString();
394
- const exchangeRateCurrent = poolState.exchangeRateCurrent.toString();
395
- const liquidityUtilizationCurrent = poolState.liquidityUtilizationCurrent.toString();
396
-
397
- const estimatedApy = calcPeriodicCompoundInterest(
398
- exchangeRatePrevious,
399
- exchangeRateCurrent,
400
- secondsElapsed,
401
- SECONDS_PER_YEAR
402
- );
403
- const estimatedApr = calcApr(exchangeRatePrevious, exchangeRateCurrent, secondsElapsed, SECONDS_PER_YEAR);
404
- let projectedApr = "";
405
-
406
- if (rateModel) {
407
- projectedApr = fromWei(
408
- calculateInstantaneousRate(rateModel, liquidityUtilizationCurrent)
409
- .mul(liquidityUtilizationCurrent)
410
- .div(fixedPointAdjustment)
411
- );
412
- }
413
-
414
- return {
415
- address: poolState.address,
416
- totalPoolSize: totalPoolSize.toString(),
417
- l1Token: poolState.l1Token,
418
- lpToken: poolState.lpToken,
419
- liquidReserves: poolState.liquidReserves.toString(),
420
- exchangeRateCurrent: poolState.exchangeRateCurrent.toString(),
421
- exchangeRatePrevious: poolState.exchangeRatePrevious.toString(),
422
- estimatedApy,
423
- estimatedApr,
424
- blocksElapsed,
425
- secondsElapsed,
426
- projectedApr,
427
- utilizedReserves: poolState.utilizedReserves.toString(),
428
- liquidityUtilizationCurrent,
429
- };
430
- }
431
- export class ReadPoolClient {
432
- private poolState: PoolState;
433
- private contract: hubPool.Instance;
434
- constructor(
435
- private address: string,
436
- private provider: Provider
437
- ) {
438
- this.contract = hubPool.connect(address, this.provider);
439
- this.poolState = new PoolState(this.contract, this.address);
440
- }
441
- public read(tokenAddress: string, latestBlock: number) {
442
- return this.poolState.read(tokenAddress, latestBlock);
443
- }
444
- }
445
- export function validateWithdraw(pool: Pool, user: User, lpTokenAmount: BigNumberish) {
446
- const l1TokensToReturn = BigNumber.from(lpTokenAmount).mul(pool.exchangeRateCurrent).div(fixedPointAdjustment);
447
- assert(BigNumber.from(l1TokensToReturn).gt("0"), "Must withdraw amount greater than 0");
448
- assert(BigNumber.from(lpTokenAmount).lte(user.lpTokens), "You cannot withdraw more than you have");
449
- return { lpTokenAmount, l1TokensToReturn: l1TokensToReturn.toString() };
450
- }
451
-
452
- export class Client {
453
- private transactionManagers: Record<string, ReturnType<typeof TransactionManager>> = {};
454
- private hubPool: hubPool.Instance;
455
- private acceleratingDistributor: AcceleratingDistributor;
456
- private merkleDistributor: MerkleDistributor;
457
- public readonly state: State = { pools: {}, users: {}, transactions: {} };
458
- private poolEvents: PoolEventState;
459
- private erc20s: Record<string, uma.clients.erc20.Instance> = {};
460
- private intervalStarted = false;
461
- private configStoreClient: acrossConfigStore.Client;
462
- private exchangeRateTable: Record<string, Record<number, BigNumberish>> = {};
463
- private userServices: Record<string, Record<string, UserState>> = {};
464
- constructor(
465
- public readonly config: Config,
466
- public readonly deps: Dependencies,
467
- private emit: EmitState
468
- ) {
469
- config.chainId = config.chainId || 1;
470
- this.hubPool = this.createHubPoolContract(deps.provider);
471
- this.acceleratingDistributor = this.createAcceleratingDistributorContract(deps.provider);
472
- this.merkleDistributor = this.createMerkleDistributorContract(deps.provider);
473
- this.poolEvents = new PoolEventState(this.hubPool, this.config.hubPoolStartBlock);
474
- this.configStoreClient = new acrossConfigStore.Client(config.configStoreAddress, deps.provider);
475
- }
476
- public getOrCreateErc20Contract(address: string): uma.clients.erc20.Instance {
477
- if (this.erc20s[address]) return this.erc20s[address];
478
- this.erc20s[address] = erc20.connect(address, this.deps.provider);
479
- return this.erc20s[address];
480
- }
481
- public getOrCreatePoolContract(): hubPool.Instance {
482
- return this.hubPool;
483
- }
484
- public createHubPoolContract(signerOrProvider: Signer | Provider): hubPool.Instance {
485
- return hubPool.connect(this.config.hubPoolAddress, signerOrProvider);
486
- }
487
- private getOrCreatePoolEvents() {
488
- return this.poolEvents;
489
- }
490
- public createAcceleratingDistributorContract(signerOrProvider: Signer | Provider): AcceleratingDistributor {
491
- return AcceleratingDistributor__factory.connect(this.config.acceleratingDistributorAddress, signerOrProvider);
492
- }
493
- public createMerkleDistributorContract(signerOrProvider: Signer | Provider): MerkleDistributor {
494
- return MerkleDistributor__factory.connect(this.config.merkleDistributorAddress, signerOrProvider);
495
- }
496
- public getOrCreateAcceleratingDistributorContract(): AcceleratingDistributor {
497
- return this.acceleratingDistributor;
498
- }
499
- public getOrCreateMerkleDistributorContract(): MerkleDistributor {
500
- return this.merkleDistributor;
501
- }
502
- private getOrCreateUserService(userAddress: string, tokenAddress: string) {
503
- if (has(this.userServices, [tokenAddress, userAddress])) return get(this.userServices, [tokenAddress, userAddress]);
504
- const erc20Contract = this.getOrCreateErc20Contract(tokenAddress);
505
- const userService = new UserState(erc20Contract, userAddress);
506
- // this service is stateful now, so needs to be cached
507
- set(this.userServices, [tokenAddress, userAddress], userService);
508
- return userService;
509
- }
510
- private updateExchangeRateTable(
511
- l1TokenAddress: string,
512
- exchangeRateTable: Record<number, BigNumberish>
513
- ): Record<number, BigNumberish> {
514
- if (!this.exchangeRateTable[l1TokenAddress]) this.exchangeRateTable[l1TokenAddress] = {};
515
- this.exchangeRateTable[l1TokenAddress] = { ...this.exchangeRateTable[l1TokenAddress], ...exchangeRateTable };
516
- return this.exchangeRateTable[l1TokenAddress];
517
- }
518
- async resolveStakingData(
519
- lpToken: string,
520
- l1TokenAddress: string,
521
- userState: Awaited<ReturnType<UserState["read"]>>
522
- ): Promise<StakeData> {
523
- assert(this.config.acceleratingDistributorAddress, "Must have the accelerating distributor address");
524
- assert(this.config.merkleDistributorAddress, "Must have the merkle distributor address");
525
-
526
- // Define the contracts we need to interact with.
527
- const acceleratingDistributorContract = this.getOrCreateAcceleratingDistributorContract();
528
- const merkleDistributorContract = this.getOrCreateMerkleDistributorContract();
529
- const poolContract = this.getOrCreatePoolContract();
530
-
531
- // Get the list of all claims made by the user.
532
- const claimList = await merkleDistributorContract.queryFilter(
533
- merkleDistributorContract.filters.Claimed(undefined, undefined, userState.address, undefined, undefined, lpToken)
534
- );
535
-
536
- // Calculate the total amount of LP tokens claimed by the user from the merkle
537
- // distributor contract with the exchange rate at the time of the claim.
538
- const amountOfLPClaimed = (
539
- await Promise.all(
540
- claimList.map(async (claim) =>
541
- claim.args.amount.mul(
542
- await poolContract.callStatic.exchangeRateCurrent(l1TokenAddress, { blockTag: claim.blockNumber })
543
- )
544
- )
545
- )
546
- ).reduce((prev, acc) => acc.add(prev), bnZero);
547
-
548
- // Get the cumulative balance of the user from the accelerating distributor contract.
549
- const { cumulativeBalance } = await acceleratingDistributorContract.getUserStake(lpToken, userState.address);
550
-
551
- return {
552
- cumulativeBalance,
553
- amountAirdropped: amountOfLPClaimed,
554
- };
555
- }
556
-
557
- // calculates the value of each LP token transfer at the block it was sent. this only works if we have archive node
558
- async calculateLpTransferValue(l1TokenAddress: string, userState: Awaited<ReturnType<UserState["read"]>>) {
559
- assert(this.config.hasArchive, "Can only calculate historical lp values with archive node");
560
- const contract = this.getOrCreatePoolContract();
561
- const pool = new PoolState(contract, this.config.hubPoolAddress);
562
- const blockNumbers = userState.transferEvents
563
- .map((x) => x.blockNumber)
564
- // we are going to lookup exchange rates for block numbers only if we dont already have it
565
- // its possible these values do not exist, so to prevent crashing do optional chaining
566
- .filter((blockNumber) => !this.exchangeRateTable?.[l1TokenAddress]?.[blockNumber]);
567
-
568
- // new exchange rate lookups
569
- const exchangeRateTable = this.updateExchangeRateTable(
570
- l1TokenAddress,
571
- Object.fromEntries(
572
- await Promise.all(
573
- blockNumbers.map(async (blockNumber) => {
574
- return [blockNumber, await pool.exchangeRateAtBlock(l1TokenAddress, blockNumber)];
575
- })
576
- )
577
- )
578
- );
579
-
580
- return userState.transferEvents.reduce((result, transfer) => {
581
- const exchangeRate = exchangeRateTable[transfer.blockNumber];
582
- if (transfer.args.to === userState.address) {
583
- return result.add(transfer.args.value.mul(exchangeRate).div(fixedPointAdjustment));
584
- }
585
- if (transfer.args.from === userState.address) {
586
- return result.sub(transfer.args.value.mul(exchangeRate).div(fixedPointAdjustment));
587
- }
588
- // we make sure to filter out any transfers where to/from is the same user
589
- return result;
590
- }, bnZero);
591
- }
592
- private getOrCreateTransactionManager(signer: Signer, address: string) {
593
- if (this.transactionManagers[address]) return this.transactionManagers[address];
594
- const txman = TransactionManager({ confirmations: this.config.confirmations }, signer, (event, id, data) => {
595
- if (event === "submitted") {
596
- this.state.transactions[id].state = event;
597
- this.state.transactions[id].hash = data as string;
598
- this.emit(["transactions", id], { ...this.state.transactions[id] });
599
- }
600
- if (event === "mined") {
601
- const txReceipt = data as TransactionReceipt;
602
- this.state.transactions[id].state = event;
603
- this.state.transactions[id].receipt = txReceipt;
604
- this.emit(["transactions", id], { ...this.state.transactions[id] });
605
- // trigger pool and user update for a known mined transaction
606
- const tx = this.state.transactions[id];
607
- this.updateUserWithTransaction(tx.fromAddress, txReceipt).catch((err) => {
608
- this.emit(["error"], err);
609
- });
610
- }
611
- if (event === "error") {
612
- this.state.transactions[id].state = event;
613
- this.state.transactions[id].error = data as Error;
614
- this.emit(["transactions", id], { ...this.state.transactions[id] });
615
- }
616
- });
617
- this.transactionManagers[address] = txman;
618
- return txman;
619
- }
620
- async addEthLiquidity(signer: Signer, l1TokenAmount: BigNumberish, overrides: Overrides = {}) {
621
- const { hubPoolAddress, wethAddress: l1Token } = this.config;
622
- const userAddress = await signer.getAddress();
623
- const contract = this.getOrCreatePoolContract();
624
- const txman = this.getOrCreateTransactionManager(signer, userAddress);
625
-
626
- // dont allow override value here
627
- const request = await contract.populateTransaction.addLiquidity(l1Token, l1TokenAmount, {
628
- ...overrides,
629
- value: l1TokenAmount,
630
- });
631
- const id = txman.request(request);
632
-
633
- this.state.transactions[id] = {
634
- id,
635
- state: "requested",
636
- toAddress: hubPoolAddress,
637
- fromAddress: userAddress,
638
- type: "Add Liquidity",
639
- description: "Adding ETH to pool",
640
- request,
641
- };
642
- this.emit(["transactions", id], { ...this.state.transactions[id] });
643
- await txman.update();
644
- return id;
645
- }
646
- async addTokenLiquidity(signer: Signer, l1Token: string, l1TokenAmount: BigNumberish, overrides: Overrides = {}) {
647
- const { hubPoolAddress } = this.config;
648
- const userAddress = await signer.getAddress();
649
- const contract = this.getOrCreatePoolContract();
650
- const txman = this.getOrCreateTransactionManager(signer, userAddress);
651
-
652
- const request = await contract.populateTransaction.addLiquidity(l1Token, l1TokenAmount, overrides);
653
- const id = await txman.request(request);
654
-
655
- this.state.transactions[id] = {
656
- id,
657
- state: "requested",
658
- toAddress: hubPoolAddress,
659
- fromAddress: userAddress,
660
- type: "Add Liquidity",
661
- description: "Adding Tokens to pool",
662
- request,
663
- };
664
-
665
- this.emit(["transactions", id], { ...this.state.transactions[id] });
666
- await txman.update();
667
- return id;
668
- }
669
- async validateWithdraw(l1Token: string, userAddress: string, lpAmount: BigNumberish) {
670
- await this.updatePool(l1Token);
671
- const poolState = this.getPoolState(l1Token);
672
- if (!this.hasUserState(l1Token, userAddress)) {
673
- await this.updateUser(l1Token, userAddress);
674
- }
675
- const userState = this.getUserState(poolState.l1Token, userAddress);
676
- return validateWithdraw(poolState, userState, lpAmount);
677
- }
678
- async removeTokenLiquidity(signer: Signer, l1Token: string, lpTokenAmount: BigNumberish, overrides: Overrides = {}) {
679
- const { hubPoolAddress } = this.config;
680
- const userAddress = await signer.getAddress();
681
- await this.validateWithdraw(l1Token, userAddress, lpTokenAmount);
682
- const contract = this.getOrCreatePoolContract();
683
- const txman = this.getOrCreateTransactionManager(signer, userAddress);
684
-
685
- const request = await contract.populateTransaction.removeLiquidity(l1Token, lpTokenAmount, false, overrides);
686
- const id = await txman.request(request);
687
-
688
- this.state.transactions[id] = {
689
- id,
690
- state: "requested",
691
- toAddress: hubPoolAddress,
692
- fromAddress: userAddress,
693
- type: "Remove Liquidity",
694
- description: "Withdrawing Tokens from pool",
695
- request,
696
- };
697
-
698
- this.emit(["transactions", id], { ...this.state.transactions[id] });
699
- await txman.update();
700
- return id;
701
- }
702
- async removeEthliquidity(signer: Signer, lpTokenAmount: BigNumberish, overrides: Overrides = {}) {
703
- const { hubPoolAddress, wethAddress: l1Token } = this.config;
704
- const userAddress = await signer.getAddress();
705
- await this.validateWithdraw(l1Token, userAddress, lpTokenAmount);
706
- const contract = this.getOrCreatePoolContract();
707
- const txman = this.getOrCreateTransactionManager(signer, userAddress);
708
-
709
- const request = await contract.populateTransaction.removeLiquidity(l1Token, lpTokenAmount, true, overrides);
710
- const id = await txman.request(request);
711
-
712
- this.state.transactions[id] = {
713
- id,
714
- state: "requested",
715
- toAddress: hubPoolAddress,
716
- fromAddress: userAddress,
717
- type: "Remove Liquidity",
718
- description: "Withdrawing Eth from pool",
719
- request,
720
- };
721
- this.emit(["transactions", id], { ...this.state.transactions[id] });
722
- await txman.update();
723
- return id;
724
- }
725
- getPoolState(l1TokenAddress: string): Pool {
726
- return this.state.pools[l1TokenAddress];
727
- }
728
- hasPoolState(l1TokenAddress: string): boolean {
729
- return Boolean(this.state.pools[l1TokenAddress]);
730
- }
731
- setUserState(l1TokenAddress: string, userAddress: string, state: User): User {
732
- set(this.state, ["users", userAddress, l1TokenAddress], state);
733
- return state;
734
- }
735
- getUserState(l1TokenAddress: string, userAddress: string): User {
736
- return get(this.state, ["users", userAddress, l1TokenAddress]);
737
- }
738
- hasUserState(l1TokenAddress: string, userAddress: string): boolean {
739
- return has(this.state, ["users", userAddress, l1TokenAddress]);
740
- }
741
- hasTxState(id: string): boolean {
742
- return has(this.state, ["transactions", id]);
743
- }
744
- getTxState(id: string): Transaction {
745
- return get(this.state, ["transactions", id]);
746
- }
747
- private async updateAndEmitUser(
748
- userState: Awaited<ReturnType<UserState["read"]>>,
749
- poolState: Pool,
750
- poolEventState: hubPool.EventState
751
- ): Promise<void> {
752
- const { l1Token: l1TokenAddress, lpToken } = poolState;
753
- const { address: userAddress } = userState;
754
- const transferValue = this.config.hasArchive
755
- ? await this.calculateLpTransferValue(l1TokenAddress, userState)
756
- : bnZero;
757
- const stakeData = await this.resolveStakingData(lpToken, l1TokenAddress, userState);
758
- const tokenEventState = poolEventState[l1TokenAddress];
759
- const newUserState = this.setUserState(
760
- l1TokenAddress,
761
- userAddress,
762
- joinUserState(
763
- poolState,
764
- tokenEventState,
765
- userState,
766
- transferValue,
767
- stakeData.cumulativeBalance,
768
- stakeData.amountAirdropped
769
- )
770
- );
771
- this.emit(["users", userAddress, l1TokenAddress], newUserState);
772
- }
773
- private async updateUserWithTransaction(userAddress: string, txReceipt: TransactionReceipt): Promise<void> {
774
- const latestBlock = await this.deps.provider.getBlock("latest");
775
- const getPoolEventState = this.getOrCreatePoolEvents();
776
- const l1TokenAddress = getPoolEventState.getL1TokenFromReceipt(txReceipt);
777
- await this.updatePool(l1TokenAddress, latestBlock);
778
- const poolState = this.getPoolState(l1TokenAddress);
779
- const poolEventState = getPoolEventState.readTxReceipt(txReceipt);
780
-
781
- const lpToken = poolState.lpToken;
782
- const getUserState = this.getOrCreateUserService(userAddress, lpToken);
783
- const userState = await getUserState.read(latestBlock.number);
784
-
785
- await this.updateAndEmitUser(userState, poolState, poolEventState);
786
- }
787
- async updateUser(userAddress: string, l1TokenAddress: string): Promise<void> {
788
- const latestBlock = await this.deps.provider.getBlock("latest");
789
- await this.updatePool(l1TokenAddress, latestBlock);
790
-
791
- const poolState = this.getPoolState(l1TokenAddress);
792
- const lpToken = poolState.lpToken;
793
- const getPoolEventState = this.getOrCreatePoolEvents();
794
- const poolEventState = await getPoolEventState.read(latestBlock.number, l1TokenAddress, userAddress);
795
-
796
- const getUserState = this.getOrCreateUserService(userAddress, lpToken);
797
- const userState = await getUserState.read(latestBlock.number);
798
-
799
- await this.updateAndEmitUser(userState, poolState, poolEventState);
800
- }
801
- async updatePool(l1TokenAddress: string, overrideLatestBlock?: Block): Promise<void> {
802
- // default to 100 block delta unless specified otherwise in config
803
- const { blockDelta = DEFAULT_BLOCK_DELTA } = this.config;
804
- const contract = this.getOrCreatePoolContract();
805
- const pool = new PoolState(contract, this.config.hubPoolAddress);
806
- const latestBlock = overrideLatestBlock || (await this.deps.provider.getBlock("latest"));
807
- const previousBlock = await this.deps.provider.getBlock(latestBlock.number - blockDelta);
808
- const state = await pool.read(l1TokenAddress, latestBlock.number, previousBlock.number);
809
-
810
- let rateModel: RateModel | undefined = undefined;
811
- try {
812
- // Use the default rate model (i.e. not any of the routeRateModels to project the Pool's APR). This assumes
813
- // that the default rate model is the most often used, but this may change in future if many different
814
- // route rate models are set.
815
- rateModel = await this.configStoreClient.getRateModel(l1TokenAddress);
816
- } catch (err) {
817
- // we could swallow this error or just log it since getting the rate model is optional,
818
- // but we will just emit it to the caller and let them decide what to do with it.
819
- this.emit(["error"], err as unknown as Error);
820
- }
821
-
822
- this.state.pools[l1TokenAddress] = joinPoolState(state, latestBlock, previousBlock, rateModel);
823
- this.emit(["pools", l1TokenAddress], this.state.pools[l1TokenAddress]);
824
- }
825
- async updateTransactions(): Promise<void> {
826
- for (const txMan of Object.values(this.transactionManagers)) {
827
- try {
828
- await txMan.update();
829
- } catch (err) {
830
- this.emit(["error"], err as unknown as Error);
831
- }
832
- }
833
- }
834
- // starts transaction checking intervals, defaults to 30 seconds
835
- startInterval(delayMs = 30000) {
836
- assert(!this.intervalStarted, "Interval already started, try stopping first");
837
- this.intervalStarted = true;
838
- loop(async () => {
839
- assert(this.intervalStarted, "HubPool Interval Stopped");
840
- await this.updateTransactions();
841
- }, delayMs).catch((err) => {
842
- this.emit(["error"], err);
843
- });
844
- }
845
- // starts transaction checking intervals
846
- stopInterval() {
847
- this.intervalStarted = false;
848
- }
849
- }