@nradko/metric-omm-sdk-v1 0.0.16
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/README.md +111 -0
- package/dist/abis/MetricOmmPool.d.ts +784 -0
- package/dist/abis/MetricOmmPool.d.ts.map +1 -0
- package/dist/abis/MetricOmmPool.js +1008 -0
- package/dist/abis/MetricOmmPool.js.map +1 -0
- package/dist/abis/MetricOmmPoolFactory.d.ts +1365 -0
- package/dist/abis/MetricOmmPoolFactory.d.ts.map +1 -0
- package/dist/abis/MetricOmmPoolFactory.js +1754 -0
- package/dist/abis/MetricOmmPoolFactory.js.map +1 -0
- package/dist/abis/MetricOmmPoolLiquidityAdder.d.ts +308 -0
- package/dist/abis/MetricOmmPoolLiquidityAdder.d.ts.map +1 -0
- package/dist/abis/MetricOmmPoolLiquidityAdder.js +401 -0
- package/dist/abis/MetricOmmPoolLiquidityAdder.js.map +1 -0
- package/dist/abis/MetricOmmPoolStateView.d.ts +538 -0
- package/dist/abis/MetricOmmPoolStateView.d.ts.map +1 -0
- package/dist/abis/MetricOmmPoolStateView.js +717 -0
- package/dist/abis/MetricOmmPoolStateView.js.map +1 -0
- package/dist/abis/MetricOmmPoolSwapper.d.ts +557 -0
- package/dist/abis/MetricOmmPoolSwapper.d.ts.map +1 -0
- package/dist/abis/MetricOmmPoolSwapper.js +723 -0
- package/dist/abis/MetricOmmPoolSwapper.js.map +1 -0
- package/dist/abis/Multicall3.d.ts +333 -0
- package/dist/abis/Multicall3.d.ts.map +1 -0
- package/dist/abis/Multicall3.js +441 -0
- package/dist/abis/Multicall3.js.map +1 -0
- package/dist/abis/PriceProvider.d.ts +142 -0
- package/dist/abis/PriceProvider.d.ts.map +1 -0
- package/dist/abis/PriceProvider.js +184 -0
- package/dist/abis/PriceProvider.js.map +1 -0
- package/dist/abis/PriceProviderUi.d.ts +433 -0
- package/dist/abis/PriceProviderUi.d.ts.map +1 -0
- package/dist/abis/PriceProviderUi.js +318 -0
- package/dist/abis/PriceProviderUi.js.map +1 -0
- package/dist/abis/index.d.ts +11 -0
- package/dist/abis/index.d.ts.map +1 -0
- package/dist/abis/index.js +11 -0
- package/dist/abis/index.js.map +1 -0
- package/dist/addresses.d.ts +52 -0
- package/dist/addresses.d.ts.map +1 -0
- package/dist/addresses.js +58 -0
- package/dist/addresses.js.map +1 -0
- package/dist/constants.d.ts +20 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +26 -0
- package/dist/constants.js.map +1 -0
- package/dist/factory/collectFees.d.ts +41 -0
- package/dist/factory/collectFees.d.ts.map +1 -0
- package/dist/factory/collectFees.js +120 -0
- package/dist/factory/collectFees.js.map +1 -0
- package/dist/factory/index.d.ts +5 -0
- package/dist/factory/index.d.ts.map +1 -0
- package/dist/factory/index.js +5 -0
- package/dist/factory/index.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/pool/create.d.ts +80 -0
- package/dist/pool/create.d.ts.map +1 -0
- package/dist/pool/create.js +80 -0
- package/dist/pool/create.js.map +1 -0
- package/dist/pool/index.d.ts +7 -0
- package/dist/pool/index.d.ts.map +1 -0
- package/dist/pool/index.js +10 -0
- package/dist/pool/index.js.map +1 -0
- package/dist/pool/liquidity.d.ts +165 -0
- package/dist/pool/liquidity.d.ts.map +1 -0
- package/dist/pool/liquidity.js +508 -0
- package/dist/pool/liquidity.js.map +1 -0
- package/dist/pool/read.d.ts +22 -0
- package/dist/pool/read.d.ts.map +1 -0
- package/dist/pool/read.js +88 -0
- package/dist/pool/read.js.map +1 -0
- package/dist/router/index.d.ts +5 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/index.js +5 -0
- package/dist/router/index.js.map +1 -0
- package/dist/router/swap.d.ts +117 -0
- package/dist/router/swap.d.ts.map +1 -0
- package/dist/router/swap.js +298 -0
- package/dist/router/swap.js.map +1 -0
- package/dist/stateView/index.d.ts +5 -0
- package/dist/stateView/index.d.ts.map +1 -0
- package/dist/stateView/index.js +5 -0
- package/dist/stateView/index.js.map +1 -0
- package/dist/stateView/read.d.ts +80 -0
- package/dist/stateView/read.d.ts.map +1 -0
- package/dist/stateView/read.js +249 -0
- package/dist/stateView/read.js.map +1 -0
- package/dist/types.d.ts +134 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/binData.d.ts +65 -0
- package/dist/utils/binData.d.ts.map +1 -0
- package/dist/utils/binData.js +109 -0
- package/dist/utils/binData.js.map +1 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +10 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/liquidityMath.d.ts +10 -0
- package/dist/utils/liquidityMath.d.ts.map +1 -0
- package/dist/utils/liquidityMath.js +31 -0
- package/dist/utils/liquidityMath.js.map +1 -0
- package/dist/utils/price.d.ts +13 -0
- package/dist/utils/price.d.ts.map +1 -0
- package/dist/utils/price.js +21 -0
- package/dist/utils/price.js.map +1 -0
- package/package.json +74 -0
- package/src/abis/MetricOmmPool.ts +1007 -0
- package/src/abis/MetricOmmPoolFactory.ts +1753 -0
- package/src/abis/MetricOmmPoolLiquidityAdder.ts +400 -0
- package/src/abis/MetricOmmPoolStateView.ts +716 -0
- package/src/abis/MetricOmmPoolSwapper.ts +722 -0
- package/src/abis/Multicall3.ts +440 -0
- package/src/abis/PriceProvider.ts +183 -0
- package/src/abis/PriceProviderUi.ts +317 -0
- package/src/abis/index.ts +11 -0
- package/src/addresses.ts +100 -0
- package/src/constants.ts +35 -0
- package/src/factory/collectFees.ts +197 -0
- package/src/factory/index.ts +12 -0
- package/src/index.ts +157 -0
- package/src/pool/create.ts +158 -0
- package/src/pool/index.ts +47 -0
- package/src/pool/liquidity.ts +839 -0
- package/src/pool/read.ts +131 -0
- package/src/router/index.ts +27 -0
- package/src/router/swap.ts +507 -0
- package/src/stateView/index.ts +18 -0
- package/src/stateView/read.ts +355 -0
- package/src/types.ts +162 -0
- package/src/utils/binData.ts +127 -0
- package/src/utils/index.ts +26 -0
- package/src/utils/liquidityMath.ts +47 -0
- package/src/utils/price.ts +23 -0
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MetricAMM SDK - StateView Read Functions
|
|
3
|
+
* Efficient batch read functions using the StateView contract
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Address, PublicClient } from "viem";
|
|
7
|
+
import { STATE_VIEW_ABI } from "../constants.js";
|
|
8
|
+
import type {
|
|
9
|
+
Slot0,
|
|
10
|
+
Slot1,
|
|
11
|
+
BinStateExternal,
|
|
12
|
+
BinStatesExternal,
|
|
13
|
+
BinStatesScaled,
|
|
14
|
+
FeeConfig,
|
|
15
|
+
PositionBinSharesResult,
|
|
16
|
+
} from "../types.js";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get slot0 data efficiently (all in one call)
|
|
20
|
+
*/
|
|
21
|
+
export async function getSlot0(
|
|
22
|
+
publicClient: PublicClient,
|
|
23
|
+
stateViewAddress: Address,
|
|
24
|
+
poolAddress: Address,
|
|
25
|
+
): Promise<Slot0> {
|
|
26
|
+
const result = (await publicClient.readContract({
|
|
27
|
+
address: stateViewAddress,
|
|
28
|
+
abi: STATE_VIEW_ABI,
|
|
29
|
+
functionName: "slot0",
|
|
30
|
+
args: [poolAddress],
|
|
31
|
+
})) as any[];
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
pauseLevel: Number(result[0]),
|
|
35
|
+
curBinIdx: Number(result[1]),
|
|
36
|
+
curPosInBin: result[2],
|
|
37
|
+
curBinDistFromProvidedPrice: Number(result[3]),
|
|
38
|
+
spreadFeeE6: Number(result[4]),
|
|
39
|
+
notionalFeeE8: Number(result[5]),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get slot1 data (total scaled token amounts in bins)
|
|
45
|
+
*/
|
|
46
|
+
export async function getSlot1(
|
|
47
|
+
publicClient: PublicClient,
|
|
48
|
+
stateViewAddress: Address,
|
|
49
|
+
poolAddress: Address,
|
|
50
|
+
): Promise<Slot1> {
|
|
51
|
+
const result = (await publicClient.readContract({
|
|
52
|
+
address: stateViewAddress,
|
|
53
|
+
abi: STATE_VIEW_ABI,
|
|
54
|
+
functionName: "slot1",
|
|
55
|
+
args: [poolAddress],
|
|
56
|
+
})) as any[];
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
totalScaledToken0InBins: result[0],
|
|
60
|
+
totalScaledToken1InBins: result[1],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get bin state with balances in external (native token decimal) units
|
|
66
|
+
*/
|
|
67
|
+
export async function getBinStateExternal(
|
|
68
|
+
publicClient: PublicClient,
|
|
69
|
+
stateViewAddress: Address,
|
|
70
|
+
poolAddress: Address,
|
|
71
|
+
binIdx: number,
|
|
72
|
+
): Promise<BinStateExternal> {
|
|
73
|
+
const result = (await publicClient.readContract({
|
|
74
|
+
address: stateViewAddress,
|
|
75
|
+
abi: STATE_VIEW_ABI,
|
|
76
|
+
functionName: "binState",
|
|
77
|
+
args: [poolAddress, binIdx],
|
|
78
|
+
})) as any[];
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
token0Balance: result[0],
|
|
82
|
+
token1Balance: result[1],
|
|
83
|
+
lengthE6: result[2],
|
|
84
|
+
addFeeBuyE6: result[3],
|
|
85
|
+
addFeeSellE6: result[4],
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Get multiple bin states efficiently (batch read)
|
|
91
|
+
*/
|
|
92
|
+
export async function getBinStatesExternal(
|
|
93
|
+
publicClient: PublicClient,
|
|
94
|
+
stateViewAddress: Address,
|
|
95
|
+
poolAddress: Address,
|
|
96
|
+
binIndices: number[],
|
|
97
|
+
): Promise<BinStatesExternal> {
|
|
98
|
+
const result = (await publicClient.readContract({
|
|
99
|
+
address: stateViewAddress,
|
|
100
|
+
abi: STATE_VIEW_ABI,
|
|
101
|
+
functionName: "binStates",
|
|
102
|
+
args: [poolAddress, binIndices],
|
|
103
|
+
})) as any[];
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
token0Balances: result[0],
|
|
107
|
+
token1Balances: result[1],
|
|
108
|
+
lengthsInUnits: result[2],
|
|
109
|
+
addFeeBuysE6: result[3],
|
|
110
|
+
addFeeSellsE6: result[4],
|
|
111
|
+
totalShares: result[5],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Get multiple bin states in scaled (internal) units (parallel reads).
|
|
117
|
+
*/
|
|
118
|
+
export async function getBinStatesScaled(
|
|
119
|
+
publicClient: PublicClient,
|
|
120
|
+
stateViewAddress: Address,
|
|
121
|
+
poolAddress: Address,
|
|
122
|
+
binIndices: number[],
|
|
123
|
+
): Promise<BinStatesScaled> {
|
|
124
|
+
const scaledReads = binIndices.map(
|
|
125
|
+
(binIdx) =>
|
|
126
|
+
publicClient.readContract({
|
|
127
|
+
address: stateViewAddress,
|
|
128
|
+
abi: STATE_VIEW_ABI,
|
|
129
|
+
functionName: "binStateScaled",
|
|
130
|
+
args: [poolAddress, binIdx],
|
|
131
|
+
}) as Promise<readonly [bigint, bigint, number, number, number]>,
|
|
132
|
+
);
|
|
133
|
+
const shareReads = binIndices.map(
|
|
134
|
+
(binIdx) =>
|
|
135
|
+
publicClient.readContract({
|
|
136
|
+
address: stateViewAddress,
|
|
137
|
+
abi: STATE_VIEW_ABI,
|
|
138
|
+
functionName: "binTotalShares",
|
|
139
|
+
args: [poolAddress, binIdx],
|
|
140
|
+
}) as Promise<bigint>,
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
const [scaled, shares] = await Promise.all([Promise.all(scaledReads), Promise.all(shareReads)]);
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
token0BalancesScaled: scaled.map((r) => r[0]),
|
|
147
|
+
token1BalancesScaled: scaled.map((r) => r[1]),
|
|
148
|
+
lengthsInUnits: scaled.map((r) => r[2]),
|
|
149
|
+
addFeeBuysE6: scaled.map((r) => r[3]),
|
|
150
|
+
addFeeSellsE6: scaled.map((r) => r[4]),
|
|
151
|
+
totalShares: shares,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Get bin total shares
|
|
157
|
+
*/
|
|
158
|
+
export async function getBinTotalShares(
|
|
159
|
+
publicClient: PublicClient,
|
|
160
|
+
stateViewAddress: Address,
|
|
161
|
+
poolAddress: Address,
|
|
162
|
+
binIdx: number,
|
|
163
|
+
): Promise<bigint> {
|
|
164
|
+
return (await publicClient.readContract({
|
|
165
|
+
address: stateViewAddress,
|
|
166
|
+
abi: STATE_VIEW_ABI,
|
|
167
|
+
functionName: "binTotalShares",
|
|
168
|
+
args: [poolAddress, binIdx],
|
|
169
|
+
})) as bigint;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Get user position shares via StateView
|
|
174
|
+
*/
|
|
175
|
+
export async function getPositionBinSharesFromStateView(
|
|
176
|
+
publicClient: PublicClient,
|
|
177
|
+
stateViewAddress: Address,
|
|
178
|
+
poolAddress: Address,
|
|
179
|
+
owner: Address,
|
|
180
|
+
salt: bigint,
|
|
181
|
+
binIdx: number,
|
|
182
|
+
): Promise<bigint> {
|
|
183
|
+
return (await publicClient.readContract({
|
|
184
|
+
address: stateViewAddress,
|
|
185
|
+
abi: STATE_VIEW_ABI,
|
|
186
|
+
functionName: "positionBinShares",
|
|
187
|
+
args: [poolAddress, owner, salt, binIdx],
|
|
188
|
+
})) as bigint;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Create a position bin key (matches Solidity's toPositionBinKey)
|
|
193
|
+
* Layout: [address(160)] | [salt(80)] | [bin(16)] = 256 bits
|
|
194
|
+
*/
|
|
195
|
+
export function toPositionBinKey(owner: Address, salt: bigint, bin: number): `0x${string}` {
|
|
196
|
+
// Convert owner address to bigint (160 bits)
|
|
197
|
+
const ownerBigInt = BigInt(owner);
|
|
198
|
+
// Salt is 80 bits, bin is 16 bits (signed, convert to uint16)
|
|
199
|
+
const binUint16 = bin < 0 ? BigInt(bin + 0x10000) : BigInt(bin);
|
|
200
|
+
// Pack: owner << 96 | salt << 16 | bin
|
|
201
|
+
const packed =
|
|
202
|
+
(ownerBigInt << 96n) | ((salt & 0xffffffffffffffffffffn) << 16n) | (binUint16 & 0xffffn);
|
|
203
|
+
return `0x${packed.toString(16).padStart(64, "0")}` as `0x${string}`;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Get user position shares for a range of bins via StateView batch call
|
|
208
|
+
*
|
|
209
|
+
* @param publicClient - Viem public client
|
|
210
|
+
* @param stateViewAddress - StateView contract address
|
|
211
|
+
* @param poolAddress - Pool address
|
|
212
|
+
* @param owner - Position owner (e.g., NFTPositionManager address)
|
|
213
|
+
* @param salt - Position salt (e.g., NFT token ID)
|
|
214
|
+
* @param lowerBin - Lower bin index (inclusive)
|
|
215
|
+
* @param upperBin - Upper bin index (inclusive)
|
|
216
|
+
* @returns Array of { binIdx, shares } for bins with non-zero shares
|
|
217
|
+
*/
|
|
218
|
+
export async function getPositionBinSharesRange(
|
|
219
|
+
publicClient: PublicClient,
|
|
220
|
+
stateViewAddress: Address,
|
|
221
|
+
poolAddress: Address,
|
|
222
|
+
owner: Address,
|
|
223
|
+
salt: bigint,
|
|
224
|
+
lowerBin: number,
|
|
225
|
+
upperBin: number,
|
|
226
|
+
): Promise<PositionBinSharesResult[]> {
|
|
227
|
+
const binIndices: number[] = [];
|
|
228
|
+
const positionBinKeys: `0x${string}`[] = [];
|
|
229
|
+
|
|
230
|
+
for (let bin = lowerBin; bin <= upperBin; bin++) {
|
|
231
|
+
binIndices.push(bin);
|
|
232
|
+
positionBinKeys.push(toPositionBinKey(owner, salt, bin));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Batch read all bin shares using the new positionBinSharesBatch function
|
|
236
|
+
const results = (await publicClient.readContract({
|
|
237
|
+
address: stateViewAddress,
|
|
238
|
+
abi: STATE_VIEW_ABI,
|
|
239
|
+
functionName: "positionBinSharesBatch",
|
|
240
|
+
args: [poolAddress, positionBinKeys],
|
|
241
|
+
})) as bigint[];
|
|
242
|
+
|
|
243
|
+
const positionShares: PositionBinSharesResult[] = [];
|
|
244
|
+
for (let i = 0; i < binIndices.length; i++) {
|
|
245
|
+
const shares = results[i];
|
|
246
|
+
if (shares > 0n) {
|
|
247
|
+
positionShares.push({
|
|
248
|
+
binIdx: binIndices[i],
|
|
249
|
+
shares,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return positionShares;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Get user position shares for specific (possibly non-contiguous) bins via StateView batch call.
|
|
259
|
+
*
|
|
260
|
+
* Unlike getPositionBinSharesRange which scans a contiguous range,
|
|
261
|
+
* this function queries exact bin indices you specify.
|
|
262
|
+
*
|
|
263
|
+
* @param publicClient - Viem public client
|
|
264
|
+
* @param stateViewAddress - StateView contract address
|
|
265
|
+
* @param poolAddress - Pool address
|
|
266
|
+
* @param owner - Position owner address
|
|
267
|
+
* @param salt - Position salt
|
|
268
|
+
* @param bins - Array of specific bin indices to query (e.g., [-3, 1, 2])
|
|
269
|
+
* @returns Array of { binIdx, shares } for bins with non-zero shares
|
|
270
|
+
*/
|
|
271
|
+
export async function getPositionBinSharesForBins(
|
|
272
|
+
publicClient: PublicClient,
|
|
273
|
+
stateViewAddress: Address,
|
|
274
|
+
poolAddress: Address,
|
|
275
|
+
owner: Address,
|
|
276
|
+
salt: bigint,
|
|
277
|
+
bins: number[],
|
|
278
|
+
): Promise<PositionBinSharesResult[]> {
|
|
279
|
+
const positionBinKeys = bins.map((bin) => toPositionBinKey(owner, salt, bin));
|
|
280
|
+
|
|
281
|
+
const results = (await publicClient.readContract({
|
|
282
|
+
address: stateViewAddress,
|
|
283
|
+
abi: STATE_VIEW_ABI,
|
|
284
|
+
functionName: "positionBinSharesBatch",
|
|
285
|
+
args: [poolAddress, positionBinKeys],
|
|
286
|
+
})) as bigint[];
|
|
287
|
+
|
|
288
|
+
const positionShares: PositionBinSharesResult[] = [];
|
|
289
|
+
for (let i = 0; i < bins.length; i++) {
|
|
290
|
+
const shares = results[i];
|
|
291
|
+
if (shares > 0n) {
|
|
292
|
+
positionShares.push({
|
|
293
|
+
binIdx: bins[i],
|
|
294
|
+
shares,
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return positionShares;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Get fee configuration
|
|
304
|
+
*/
|
|
305
|
+
export async function getFeeConfig(
|
|
306
|
+
publicClient: PublicClient,
|
|
307
|
+
stateViewAddress: Address,
|
|
308
|
+
poolAddress: Address,
|
|
309
|
+
): Promise<FeeConfig> {
|
|
310
|
+
const result = (await publicClient.readContract({
|
|
311
|
+
address: stateViewAddress,
|
|
312
|
+
abi: STATE_VIEW_ABI,
|
|
313
|
+
functionName: "feeConfig",
|
|
314
|
+
args: [poolAddress],
|
|
315
|
+
})) as any[];
|
|
316
|
+
|
|
317
|
+
return {
|
|
318
|
+
adminAddr: result[0],
|
|
319
|
+
protocolFee: result[1],
|
|
320
|
+
adminFee: result[2],
|
|
321
|
+
adminFeeDest: result[3],
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Get price provider address
|
|
327
|
+
*/
|
|
328
|
+
export async function getPriceProvider(
|
|
329
|
+
publicClient: PublicClient,
|
|
330
|
+
stateViewAddress: Address,
|
|
331
|
+
poolAddress: Address,
|
|
332
|
+
): Promise<Address> {
|
|
333
|
+
return (await publicClient.readContract({
|
|
334
|
+
address: stateViewAddress,
|
|
335
|
+
abi: STATE_VIEW_ABI,
|
|
336
|
+
functionName: "priceProvider",
|
|
337
|
+
args: [poolAddress],
|
|
338
|
+
})) as Address;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Get last trade timestamp
|
|
343
|
+
*/
|
|
344
|
+
export async function getLastTradeTimestamp(
|
|
345
|
+
publicClient: PublicClient,
|
|
346
|
+
stateViewAddress: Address,
|
|
347
|
+
poolAddress: Address,
|
|
348
|
+
): Promise<number> {
|
|
349
|
+
return (await publicClient.readContract({
|
|
350
|
+
address: stateViewAddress,
|
|
351
|
+
abi: STATE_VIEW_ABI,
|
|
352
|
+
functionName: "lastTradeTimestamp",
|
|
353
|
+
args: [poolAddress],
|
|
354
|
+
})) as number;
|
|
355
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MetricAMM SDK Types
|
|
3
|
+
* All interfaces and type definitions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Address } from "viem";
|
|
7
|
+
|
|
8
|
+
// ============ Core Types ============
|
|
9
|
+
|
|
10
|
+
export interface LiquidityDelta {
|
|
11
|
+
bin: number; // int24
|
|
12
|
+
deltaShares: bigint; // int104
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* v1 pool and LiquidityAdder payload: parallel arrays of bin indices and share magnitudes (add or remove).
|
|
17
|
+
*/
|
|
18
|
+
export interface PoolLiquidityDelta {
|
|
19
|
+
binIdxs: readonly bigint[];
|
|
20
|
+
shares: readonly bigint[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Bin configuration for pool creation.
|
|
25
|
+
* All values are in E6 format (1e6 = 100%).
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* // Bin with 1% length, 0.3% buy fee, 0.1% sell fee
|
|
29
|
+
* { lengthE6: 10000, addFeeBuyE6: 3000, addFeeSellE6: 1000 }
|
|
30
|
+
*/
|
|
31
|
+
export interface BinData {
|
|
32
|
+
/** Bin length in E6 format (10000 = 1%, 1000000 = 100%) */
|
|
33
|
+
lengthE6: number;
|
|
34
|
+
/** Additional buy fee in E6 format */
|
|
35
|
+
addFeeBuyE6: number;
|
|
36
|
+
/** Additional sell fee in E6 format */
|
|
37
|
+
addFeeSellE6: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ============ Pool Types ============
|
|
41
|
+
|
|
42
|
+
export interface PoolImmutables {
|
|
43
|
+
factory: Address;
|
|
44
|
+
token0: Address;
|
|
45
|
+
token1: Address;
|
|
46
|
+
token0ScaleMultiplier: bigint;
|
|
47
|
+
token1ScaleMultiplier: bigint;
|
|
48
|
+
initialScaledToken0PerShareE18: bigint;
|
|
49
|
+
initialScaledToken1PerShareE18: bigint;
|
|
50
|
+
minimalMintableLiquidity: bigint;
|
|
51
|
+
maxDriftE8: bigint;
|
|
52
|
+
maxDriftDecayPerSecondE8: bigint;
|
|
53
|
+
lowestBin: number;
|
|
54
|
+
highestBin: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface PoolState {
|
|
58
|
+
pauseLevel: number;
|
|
59
|
+
curBinIdx: number;
|
|
60
|
+
curPosInBin: bigint;
|
|
61
|
+
curBinDistFromProvidedPrice: number;
|
|
62
|
+
spreadFeeE6: number;
|
|
63
|
+
notionalFeeE8: number;
|
|
64
|
+
totalScaledToken0InBins: bigint;
|
|
65
|
+
totalScaledToken1InBins: bigint;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface BinState {
|
|
69
|
+
token0BalanceScaled: bigint;
|
|
70
|
+
token1BalanceScaled: bigint;
|
|
71
|
+
lengthE6: number;
|
|
72
|
+
addFeeBuyE6: number;
|
|
73
|
+
addFeeSellE6: number;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface BinStateExternal {
|
|
77
|
+
token0Balance: bigint; // Unscaled, in native token decimals
|
|
78
|
+
token1Balance: bigint; // Unscaled, in native token decimals
|
|
79
|
+
lengthE6: number;
|
|
80
|
+
addFeeBuyE6: number;
|
|
81
|
+
addFeeSellE6: number;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface BinStatesExternal {
|
|
85
|
+
token0Balances: bigint[];
|
|
86
|
+
token1Balances: bigint[];
|
|
87
|
+
lengthsInUnits: number[];
|
|
88
|
+
addFeeBuysE6: number[];
|
|
89
|
+
addFeeSellsE6: number[];
|
|
90
|
+
totalShares: bigint[];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface BinStatesScaled {
|
|
94
|
+
token0BalancesScaled: bigint[];
|
|
95
|
+
token1BalancesScaled: bigint[];
|
|
96
|
+
lengthsInUnits: number[];
|
|
97
|
+
addFeeBuysE6: number[];
|
|
98
|
+
addFeeSellsE6: number[];
|
|
99
|
+
totalShares: bigint[];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ============ StateView Types ============
|
|
103
|
+
|
|
104
|
+
export interface Slot0 {
|
|
105
|
+
pauseLevel: number;
|
|
106
|
+
curBinIdx: number;
|
|
107
|
+
curPosInBin: bigint;
|
|
108
|
+
curBinDistFromProvidedPrice: number;
|
|
109
|
+
spreadFeeE6: number;
|
|
110
|
+
notionalFeeE8: number;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface Slot1 {
|
|
114
|
+
totalScaledToken0InBins: bigint;
|
|
115
|
+
totalScaledToken1InBins: bigint;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface FeeConfig {
|
|
119
|
+
adminAddr: Address;
|
|
120
|
+
protocolFee: number;
|
|
121
|
+
adminFee: number;
|
|
122
|
+
adminFeeDest: Address;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ============ Position Types ============
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Result type for getPositionBinSharesRange
|
|
129
|
+
*/
|
|
130
|
+
export interface PositionBinSharesResult {
|
|
131
|
+
binIdx: number;
|
|
132
|
+
shares: bigint;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ============ Liquidity Types ============
|
|
136
|
+
|
|
137
|
+
export interface CalculateUniformLiquidityParams {
|
|
138
|
+
valuePerBinInToken: bigint;
|
|
139
|
+
valueIsInToken0: boolean;
|
|
140
|
+
currentPrice: number;
|
|
141
|
+
lowerBin: number;
|
|
142
|
+
upperBin: number;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface LiquidityBinValueInput {
|
|
146
|
+
bin: number;
|
|
147
|
+
targetValueInToken: bigint;
|
|
148
|
+
targetValueInToken0: boolean;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface CalculateAnyLiquidityParams {
|
|
152
|
+
bins: LiquidityBinValueInput[];
|
|
153
|
+
currentPrice: number;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface PreparedLiquidityDistribution {
|
|
157
|
+
deltas: LiquidityDelta[];
|
|
158
|
+
specAmount0: bigint;
|
|
159
|
+
specAmount1: bigint;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export type CalculatedLiquidityDistribution = PreparedLiquidityDistribution;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MetricAMM SDK - Bin Data Utilities
|
|
3
|
+
* Functions for packing/unpacking bin data
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { BinData } from "../types.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Pack bin data into 48-bit representation
|
|
10
|
+
* Layout: [lengthE6: 16 bits][addFeeBuyE6: 16 bits][addFeeSellE6: 16 bits]
|
|
11
|
+
*/
|
|
12
|
+
export function packBinData(binData: BinData): bigint {
|
|
13
|
+
const length = BigInt(binData.lengthE6) & 0xffffn;
|
|
14
|
+
const buyFee = BigInt(binData.addFeeBuyE6) & 0xffffn;
|
|
15
|
+
const sellFee = BigInt(binData.addFeeSellE6) & 0xffffn;
|
|
16
|
+
|
|
17
|
+
return length | (buyFee << 16n) | (sellFee << 32n);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Pack 5 bins into a single uint256
|
|
22
|
+
* Each bin takes 48 bits, total 240 bits used, 16 bits unused
|
|
23
|
+
*/
|
|
24
|
+
export function packBins5(bins: BinData[]): bigint {
|
|
25
|
+
if (bins.length !== 5) {
|
|
26
|
+
throw new Error("Must provide exactly 5 bins");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let packed = 0n;
|
|
30
|
+
for (let i = 0; i < 5; i++) {
|
|
31
|
+
const binPacked = packBinData(bins[i]);
|
|
32
|
+
packed |= binPacked << (BigInt(i) * 48n);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return packed;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Pack an array of bin data into uint256 array (5 bins per uint256)
|
|
40
|
+
* Pads with zero bins if length is not divisible by 5
|
|
41
|
+
*/
|
|
42
|
+
export function packBinDataArray(bins: BinData[]): bigint[] {
|
|
43
|
+
const zeroBin: BinData = { lengthE6: 0, addFeeBuyE6: 0, addFeeSellE6: 0 };
|
|
44
|
+
const result: bigint[] = [];
|
|
45
|
+
|
|
46
|
+
// Process in chunks of 5
|
|
47
|
+
for (let i = 0; i < bins.length; i += 5) {
|
|
48
|
+
const chunk: BinData[] = [];
|
|
49
|
+
for (let j = 0; j < 5; j++) {
|
|
50
|
+
chunk.push(bins[i + j] || zeroBin);
|
|
51
|
+
}
|
|
52
|
+
result.push(packBins5(chunk));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Unpack 48-bit bin data
|
|
60
|
+
*/
|
|
61
|
+
export function unpackBinData(packed: bigint): BinData {
|
|
62
|
+
const lengthE6 = Number(packed & 0xffffn);
|
|
63
|
+
const addFeeBuyE6 = Number((packed >> 16n) & 0xffffn);
|
|
64
|
+
const addFeeSellE6 = Number((packed >> 32n) & 0xffffn);
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
lengthE6,
|
|
68
|
+
addFeeBuyE6,
|
|
69
|
+
addFeeSellE6,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Pack bin data array into uint256 array ready for contract calls.
|
|
75
|
+
*
|
|
76
|
+
* @param bins Array of bin configurations
|
|
77
|
+
* @returns Packed uint256 array ready for contract calls
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* // Create 3 bins: 1% length with default fees
|
|
81
|
+
* const bins = createBins([
|
|
82
|
+
* { lengthE6: 10000, addFeeBuyE6: 0, addFeeSellE6: 0 },
|
|
83
|
+
* { lengthE6: 10000, addFeeBuyE6: 0, addFeeSellE6: 0 },
|
|
84
|
+
* { lengthE6: 10000, addFeeBuyE6: 0, addFeeSellE6: 0 },
|
|
85
|
+
* ]);
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* // Create bins with custom fees
|
|
89
|
+
* const bins = createBins([
|
|
90
|
+
* { lengthE6: 10000, addFeeBuyE6: 500, addFeeSellE6: 200 }, // 1% length, +0.05% buy, +0.02% sell
|
|
91
|
+
* { lengthE6: 20000, addFeeBuyE6: 0, addFeeSellE6: 0 }, // 2% length, no extra fees
|
|
92
|
+
* ]);
|
|
93
|
+
*/
|
|
94
|
+
export function createBins(bins: BinData[]): bigint[] {
|
|
95
|
+
return packBinDataArray(bins);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Create uniform bins with the same configuration.
|
|
100
|
+
*
|
|
101
|
+
* @param count Number of bins to create
|
|
102
|
+
* @param lengthE6 Bin length in E6 format (10000 = 1%)
|
|
103
|
+
* @param addFeeBuyE6 Additional buy fee in E6 format (default: 0)
|
|
104
|
+
* @param addFeeSellE6 Additional sell fee in E6 format (default: 0)
|
|
105
|
+
* @returns Packed uint256 array ready for contract calls
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* // Create 20 uniform bins, each 1% length
|
|
109
|
+
* const bins = createUniformBins(20, 10000);
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* // Create 10 bins with 0.5% length and +0.1% buy fee
|
|
113
|
+
* const bins = createUniformBins(10, 5000, 1000);
|
|
114
|
+
*/
|
|
115
|
+
export function createUniformBins(
|
|
116
|
+
count: number,
|
|
117
|
+
lengthE6: number,
|
|
118
|
+
addFeeBuyE6: number = 0,
|
|
119
|
+
addFeeSellE6: number = 0,
|
|
120
|
+
): bigint[] {
|
|
121
|
+
const bins: BinData[] = Array(count).fill({
|
|
122
|
+
lengthE6,
|
|
123
|
+
addFeeBuyE6,
|
|
124
|
+
addFeeSellE6,
|
|
125
|
+
});
|
|
126
|
+
return packBinDataArray(bins);
|
|
127
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MetricAMM SDK - Utility Functions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Bin data utilities
|
|
6
|
+
export {
|
|
7
|
+
packBinData,
|
|
8
|
+
packBins5,
|
|
9
|
+
packBinDataArray,
|
|
10
|
+
unpackBinData,
|
|
11
|
+
createBins,
|
|
12
|
+
createUniformBins,
|
|
13
|
+
} from "./binData.js";
|
|
14
|
+
|
|
15
|
+
// Price utilities
|
|
16
|
+
export { priceToQ64, q64ToPrice } from "./price.js";
|
|
17
|
+
|
|
18
|
+
// Liquidity math utilities
|
|
19
|
+
export {
|
|
20
|
+
ONE_E18,
|
|
21
|
+
ceilDiv,
|
|
22
|
+
toPriceE18 as toPriceX18,
|
|
23
|
+
convertToken0ToToken1,
|
|
24
|
+
convertToken1ToToken0,
|
|
25
|
+
scaledPositiveDeltaToExternal,
|
|
26
|
+
} from "./liquidityMath.js";
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MetricAMM SDK - Liquidity Math Utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export const ONE_E18 = 1_000_000_000_000_000_000n;
|
|
6
|
+
|
|
7
|
+
export function ceilDiv(numerator: bigint, denominator: bigint): bigint {
|
|
8
|
+
if (denominator <= 0n) throw new Error("denominator must be > 0");
|
|
9
|
+
if (numerator < 0n) throw new Error("numerator must be >= 0");
|
|
10
|
+
return numerator === 0n ? 0n : (numerator + denominator - 1n) / denominator;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function toPriceE18(currentPrice: number): bigint {
|
|
14
|
+
if (!Number.isFinite(currentPrice) || currentPrice <= 0) {
|
|
15
|
+
throw new Error("currentPrice must be a positive finite number");
|
|
16
|
+
}
|
|
17
|
+
const priceE18 = BigInt(Math.round(currentPrice * 1e18));
|
|
18
|
+
if (priceE18 <= 0n) {
|
|
19
|
+
throw new Error("currentPrice is too small");
|
|
20
|
+
}
|
|
21
|
+
return priceE18;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function convertToken0ToToken1(
|
|
25
|
+
amount0: bigint,
|
|
26
|
+
token0ScaleMultiplier: bigint,
|
|
27
|
+
token1ScaleMultiplier: bigint,
|
|
28
|
+
priceE18: bigint,
|
|
29
|
+
): bigint {
|
|
30
|
+
return (amount0 * token0ScaleMultiplier * priceE18) / (token1ScaleMultiplier * ONE_E18);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function convertToken1ToToken0(
|
|
34
|
+
amount1: bigint,
|
|
35
|
+
token0ScaleMultiplier: bigint,
|
|
36
|
+
token1ScaleMultiplier: bigint,
|
|
37
|
+
priceX18: bigint,
|
|
38
|
+
): bigint {
|
|
39
|
+
return (amount1 * token1ScaleMultiplier * ONE_E18) / (token0ScaleMultiplier * priceX18);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function scaledPositiveDeltaToExternal(
|
|
43
|
+
scaledAmount: bigint,
|
|
44
|
+
scaleMultiplier: bigint,
|
|
45
|
+
): bigint {
|
|
46
|
+
return ceilDiv(scaledAmount, scaleMultiplier);
|
|
47
|
+
}
|