@across-protocol/sdk 4.3.113 → 4.3.114-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/arch/svm/SpokeUtils.d.ts +17 -24
- package/dist/cjs/arch/svm/SpokeUtils.js.map +1 -1
- package/dist/cjs/arch/svm/types.d.ts +2 -1
- package/dist/cjs/arch/svm/types.js.map +1 -1
- package/dist/cjs/arch/svm/utils.d.ts +4 -9
- package/dist/cjs/arch/svm/utils.js.map +1 -1
- package/dist/cjs/gasPriceOracle/adapters/solana.js.map +1 -1
- package/dist/cjs/index.d.ts +0 -1
- package/dist/cjs/index.js +1 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/relayFeeCalculator/chain-queries/svmQuery.d.ts +4 -4
- package/dist/cjs/relayFeeCalculator/chain-queries/svmQuery.js +1 -1
- package/dist/cjs/relayFeeCalculator/chain-queries/svmQuery.js.map +1 -1
- package/dist/esm/arch/svm/SpokeUtils.d.ts +17 -24
- package/dist/esm/arch/svm/SpokeUtils.js.map +1 -1
- package/dist/esm/arch/svm/types.d.ts +6 -1
- package/dist/esm/arch/svm/types.js.map +1 -1
- package/dist/esm/arch/svm/utils.d.ts +4 -9
- package/dist/esm/arch/svm/utils.js.map +1 -1
- package/dist/esm/gasPriceOracle/adapters/solana.js +1 -1
- package/dist/esm/gasPriceOracle/adapters/solana.js.map +1 -1
- package/dist/esm/index.d.ts +0 -1
- package/dist/esm/index.js +0 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/relayFeeCalculator/chain-queries/svmQuery.d.ts +4 -4
- package/dist/esm/relayFeeCalculator/chain-queries/svmQuery.js +3 -3
- package/dist/esm/relayFeeCalculator/chain-queries/svmQuery.js.map +1 -1
- package/dist/types/arch/svm/SpokeUtils.d.ts +17 -24
- package/dist/types/arch/svm/SpokeUtils.d.ts.map +1 -1
- package/dist/types/arch/svm/types.d.ts +6 -1
- package/dist/types/arch/svm/types.d.ts.map +1 -1
- package/dist/types/arch/svm/utils.d.ts +4 -9
- package/dist/types/arch/svm/utils.d.ts.map +1 -1
- package/dist/types/gasPriceOracle/adapters/solana.d.ts.map +1 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/relayFeeCalculator/chain-queries/svmQuery.d.ts +4 -4
- package/dist/types/relayFeeCalculator/chain-queries/svmQuery.d.ts.map +1 -1
- package/package.json +17 -8
- package/src/arch/svm/SpokeUtils.ts +24 -26
- package/src/arch/svm/types.ts +9 -0
- package/src/arch/svm/utils.ts +4 -4
- package/src/gasPriceOracle/adapters/solana.ts +8 -3
- package/src/index.ts +0 -1
- package/src/relayFeeCalculator/chain-queries/svmQuery.ts +6 -7
- package/dist/cjs/pool/TransactionManager.d.ts +0 -12
- package/dist/cjs/pool/TransactionManager.js +0 -121
- package/dist/cjs/pool/TransactionManager.js.map +0 -1
- package/dist/cjs/pool/index.d.ts +0 -1
- package/dist/cjs/pool/index.js +0 -5
- package/dist/cjs/pool/index.js.map +0 -1
- package/dist/cjs/pool/poolClient.d.ts +0 -228
- package/dist/cjs/pool/poolClient.js +0 -869
- package/dist/cjs/pool/poolClient.js.map +0 -1
- package/dist/cjs/pool/uma/across/constants.d.ts +0 -2
- package/dist/cjs/pool/uma/across/constants.js +0 -6
- package/dist/cjs/pool/uma/across/constants.js.map +0 -1
- package/dist/cjs/pool/uma/across/index.d.ts +0 -2
- package/dist/cjs/pool/uma/across/index.js +0 -8
- package/dist/cjs/pool/uma/across/index.js.map +0 -1
- package/dist/cjs/pool/uma/across/transactionManager.d.ts +0 -12
- package/dist/cjs/pool/uma/across/transactionManager.js +0 -121
- package/dist/cjs/pool/uma/across/transactionManager.js.map +0 -1
- package/dist/cjs/pool/uma/clients/erc20/client.d.ts +0 -26
- package/dist/cjs/pool/uma/clients/erc20/client.js +0 -38
- package/dist/cjs/pool/uma/clients/erc20/client.js.map +0 -1
- package/dist/cjs/pool/uma/clients/erc20/index.d.ts +0 -1
- package/dist/cjs/pool/uma/clients/erc20/index.js +0 -5
- package/dist/cjs/pool/uma/clients/erc20/index.js.map +0 -1
- package/dist/cjs/pool/uma/clients/index.d.ts +0 -1
- package/dist/cjs/pool/uma/clients/index.js +0 -6
- package/dist/cjs/pool/uma/clients/index.js.map +0 -1
- package/dist/cjs/pool/uma/index.d.ts +0 -13
- package/dist/cjs/pool/uma/index.js +0 -9
- package/dist/cjs/pool/uma/index.js.map +0 -1
- package/dist/cjs/pool/uma/oracle/index.d.ts +0 -1
- package/dist/cjs/pool/uma/oracle/index.js +0 -6
- package/dist/cjs/pool/uma/oracle/index.js.map +0 -1
- package/dist/cjs/pool/uma/oracle/utils.d.ts +0 -7
- package/dist/cjs/pool/uma/oracle/utils.js +0 -20
- package/dist/cjs/pool/uma/oracle/utils.js.map +0 -1
- package/dist/cjs/pool/uma/utils.d.ts +0 -17
- package/dist/cjs/pool/uma/utils.js +0 -69
- package/dist/cjs/pool/uma/utils.js.map +0 -1
- package/dist/esm/pool/TransactionManager.d.ts +0 -12
- package/dist/esm/pool/TransactionManager.js +0 -122
- package/dist/esm/pool/TransactionManager.js.map +0 -1
- package/dist/esm/pool/index.d.ts +0 -1
- package/dist/esm/pool/index.js +0 -2
- package/dist/esm/pool/index.js.map +0 -1
- package/dist/esm/pool/poolClient.d.ts +0 -238
- package/dist/esm/pool/poolClient.js +0 -899
- package/dist/esm/pool/poolClient.js.map +0 -1
- package/dist/esm/pool/uma/across/constants.d.ts +0 -2
- package/dist/esm/pool/uma/across/constants.js +0 -3
- package/dist/esm/pool/uma/across/constants.js.map +0 -1
- package/dist/esm/pool/uma/across/index.d.ts +0 -2
- package/dist/esm/pool/uma/across/index.js +0 -4
- package/dist/esm/pool/uma/across/index.js.map +0 -1
- package/dist/esm/pool/uma/across/transactionManager.d.ts +0 -12
- package/dist/esm/pool/uma/across/transactionManager.js +0 -122
- package/dist/esm/pool/uma/across/transactionManager.js.map +0 -1
- package/dist/esm/pool/uma/clients/erc20/client.d.ts +0 -26
- package/dist/esm/pool/uma/clients/erc20/client.js +0 -35
- package/dist/esm/pool/uma/clients/erc20/client.js.map +0 -1
- package/dist/esm/pool/uma/clients/erc20/index.d.ts +0 -1
- package/dist/esm/pool/uma/clients/erc20/index.js +0 -2
- package/dist/esm/pool/uma/clients/erc20/index.js.map +0 -1
- package/dist/esm/pool/uma/clients/index.d.ts +0 -1
- package/dist/esm/pool/uma/clients/index.js +0 -3
- package/dist/esm/pool/uma/clients/index.js.map +0 -1
- package/dist/esm/pool/uma/index.d.ts +0 -13
- package/dist/esm/pool/uma/index.js +0 -9
- package/dist/esm/pool/uma/index.js.map +0 -1
- package/dist/esm/pool/uma/oracle/index.d.ts +0 -1
- package/dist/esm/pool/uma/oracle/index.js +0 -3
- package/dist/esm/pool/uma/oracle/index.js.map +0 -1
- package/dist/esm/pool/uma/oracle/utils.d.ts +0 -23
- package/dist/esm/pool/uma/oracle/utils.js +0 -33
- package/dist/esm/pool/uma/oracle/utils.js.map +0 -1
- package/dist/esm/pool/uma/utils.d.ts +0 -17
- package/dist/esm/pool/uma/utils.js +0 -68
- package/dist/esm/pool/uma/utils.js.map +0 -1
- package/dist/types/pool/TransactionManager.d.ts +0 -13
- package/dist/types/pool/TransactionManager.d.ts.map +0 -1
- package/dist/types/pool/index.d.ts +0 -2
- package/dist/types/pool/index.d.ts.map +0 -1
- package/dist/types/pool/poolClient.d.ts +0 -239
- package/dist/types/pool/poolClient.d.ts.map +0 -1
- package/dist/types/pool/uma/across/constants.d.ts +0 -3
- package/dist/types/pool/uma/across/constants.d.ts.map +0 -1
- package/dist/types/pool/uma/across/index.d.ts +0 -3
- package/dist/types/pool/uma/across/index.d.ts.map +0 -1
- package/dist/types/pool/uma/across/transactionManager.d.ts +0 -13
- package/dist/types/pool/uma/across/transactionManager.d.ts.map +0 -1
- package/dist/types/pool/uma/clients/erc20/client.d.ts +0 -27
- package/dist/types/pool/uma/clients/erc20/client.d.ts.map +0 -1
- package/dist/types/pool/uma/clients/erc20/index.d.ts +0 -2
- package/dist/types/pool/uma/clients/erc20/index.d.ts.map +0 -1
- package/dist/types/pool/uma/clients/index.d.ts +0 -2
- package/dist/types/pool/uma/clients/index.d.ts.map +0 -1
- package/dist/types/pool/uma/index.d.ts +0 -14
- package/dist/types/pool/uma/index.d.ts.map +0 -1
- package/dist/types/pool/uma/oracle/index.d.ts +0 -2
- package/dist/types/pool/uma/oracle/index.d.ts.map +0 -1
- package/dist/types/pool/uma/oracle/utils.d.ts +0 -24
- package/dist/types/pool/uma/oracle/utils.d.ts.map +0 -1
- package/dist/types/pool/uma/utils.d.ts +0 -18
- package/dist/types/pool/uma/utils.d.ts.map +0 -1
- package/src/pool/TransactionManager.ts +0 -73
- package/src/pool/index.ts +0 -1
- package/src/pool/poolClient.ts +0 -849
- package/src/pool/uma/across/constants.ts +0 -2
- package/src/pool/uma/across/index.ts +0 -2
- package/src/pool/uma/across/transactionManager.ts +0 -73
- package/src/pool/uma/clients/erc20/README.md +0 -29
- package/src/pool/uma/clients/erc20/client.e2e.ts +0 -26
- package/src/pool/uma/clients/erc20/client.ts +0 -67
- package/src/pool/uma/clients/erc20/index.ts +0 -1
- package/src/pool/uma/clients/index.ts +0 -1
- package/src/pool/uma/index.ts +0 -33
- package/src/pool/uma/oracle/index.ts +0 -2
- package/src/pool/uma/oracle/utils.ts +0 -38
- package/src/pool/uma/utils.test.ts +0 -24
- package/src/pool/uma/utils.ts +0 -53
package/src/pool/poolClient.ts
DELETED
|
@@ -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
|
-
}
|