sally-defi-ts-sdk 0.3.2
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/LICENSE +21 -0
- package/README.md +263 -0
- package/dist/aio/client.d.ts +93 -0
- package/dist/aio/client.d.ts.map +1 -0
- package/dist/aio/client.js +283 -0
- package/dist/aio/client.js.map +1 -0
- package/dist/aio/index.d.ts +20 -0
- package/dist/aio/index.d.ts.map +1 -0
- package/dist/aio/index.js +19 -0
- package/dist/aio/index.js.map +1 -0
- package/dist/aio/modules/fees.d.ts +19 -0
- package/dist/aio/modules/fees.d.ts.map +1 -0
- package/dist/aio/modules/fees.js +47 -0
- package/dist/aio/modules/fees.js.map +1 -0
- package/dist/aio/modules/liquidity.d.ts +47 -0
- package/dist/aio/modules/liquidity.d.ts.map +1 -0
- package/dist/aio/modules/liquidity.js +115 -0
- package/dist/aio/modules/liquidity.js.map +1 -0
- package/dist/aio/modules/prices.d.ts +18 -0
- package/dist/aio/modules/prices.d.ts.map +1 -0
- package/dist/aio/modules/prices.js +48 -0
- package/dist/aio/modules/prices.js.map +1 -0
- package/dist/aio/modules/swap.d.ts +50 -0
- package/dist/aio/modules/swap.d.ts.map +1 -0
- package/dist/aio/modules/swap.js +267 -0
- package/dist/aio/modules/swap.js.map +1 -0
- package/dist/aio/modules/wallet.d.ts +13 -0
- package/dist/aio/modules/wallet.d.ts.map +1 -0
- package/dist/aio/modules/wallet.js +27 -0
- package/dist/aio/modules/wallet.js.map +1 -0
- package/dist/aio/token.d.ts +19 -0
- package/dist/aio/token.d.ts.map +1 -0
- package/dist/aio/token.js +50 -0
- package/dist/aio/token.js.map +1 -0
- package/dist/client.d.ts +142 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +452 -0
- package/dist/client.js.map +1 -0
- package/dist/constants.d.ts +36 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +39 -0
- package/dist/constants.js.map +1 -0
- package/dist/data/deployment.json +1 -0
- package/dist/deployment.d.ts +44 -0
- package/dist/deployment.d.ts.map +1 -0
- package/dist/deployment.js +118 -0
- package/dist/deployment.js.map +1 -0
- package/dist/errors.d.ts +57 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +197 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/fees.d.ts +32 -0
- package/dist/modules/fees.d.ts.map +1 -0
- package/dist/modules/fees.js +64 -0
- package/dist/modules/fees.js.map +1 -0
- package/dist/modules/liquidity.d.ts +134 -0
- package/dist/modules/liquidity.d.ts.map +1 -0
- package/dist/modules/liquidity.js +277 -0
- package/dist/modules/liquidity.js.map +1 -0
- package/dist/modules/prices.d.ts +47 -0
- package/dist/modules/prices.d.ts.map +1 -0
- package/dist/modules/prices.js +85 -0
- package/dist/modules/prices.js.map +1 -0
- package/dist/modules/swap.d.ts +102 -0
- package/dist/modules/swap.d.ts.map +1 -0
- package/dist/modules/swap.js +400 -0
- package/dist/modules/swap.js.map +1 -0
- package/dist/modules/wallet.d.ts +16 -0
- package/dist/modules/wallet.d.ts.map +1 -0
- package/dist/modules/wallet.js +30 -0
- package/dist/modules/wallet.js.map +1 -0
- package/dist/permit2.d.ts +97 -0
- package/dist/permit2.d.ts.map +1 -0
- package/dist/permit2.js +130 -0
- package/dist/permit2.js.map +1 -0
- package/dist/previews.d.ts +57 -0
- package/dist/previews.d.ts.map +1 -0
- package/dist/previews.js +69 -0
- package/dist/previews.js.map +1 -0
- package/dist/safety.d.ts +80 -0
- package/dist/safety.d.ts.map +1 -0
- package/dist/safety.js +133 -0
- package/dist/safety.js.map +1 -0
- package/dist/token.d.ts +215 -0
- package/dist/token.d.ts.map +1 -0
- package/dist/token.js +239 -0
- package/dist/token.js.map +1 -0
- package/dist/types.d.ts +229 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +462 -0
- package/dist/types.js.map +1 -0
- package/dist/util.d.ts +13 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +22 -0
- package/dist/util.js.map +1 -0
- package/package.json +48 -0
- package/src/aio/client.ts +329 -0
- package/src/aio/index.ts +20 -0
- package/src/aio/modules/fees.ts +60 -0
- package/src/aio/modules/liquidity.ts +181 -0
- package/src/aio/modules/prices.ts +57 -0
- package/src/aio/modules/swap.ts +347 -0
- package/src/aio/modules/wallet.ts +34 -0
- package/src/aio/token.ts +59 -0
- package/src/client.ts +526 -0
- package/src/constants.ts +43 -0
- package/src/data/deployment.json +1 -0
- package/src/deployment.ts +132 -0
- package/src/errors.ts +215 -0
- package/src/index.ts +90 -0
- package/src/modules/fees.ts +78 -0
- package/src/modules/liquidity.ts +446 -0
- package/src/modules/prices.ts +97 -0
- package/src/modules/swap.ts +502 -0
- package/src/modules/wallet.ts +37 -0
- package/src/permit2.ts +169 -0
- package/src/previews.ts +95 -0
- package/src/safety.ts +152 -0
- package/src/token.ts +254 -0
- package/src/types.ts +438 -0
- package/src/util.ts +20 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed result objects for every Sally tuple/struct return.
|
|
3
|
+
*
|
|
4
|
+
* ethers decodes Solidity structs into positional `Result` arrays. These classes
|
|
5
|
+
* give each field a name, so callers get `pos.liquidity` instead of `pos[7]` —
|
|
6
|
+
* and AI/agent callers get a stable, documented schema. Every class has a
|
|
7
|
+
* `fromRaw` constructor that maps the ABI component order to named fields.
|
|
8
|
+
*
|
|
9
|
+
* Amounts are kept as raw `bigint` (wei / token base units). Use
|
|
10
|
+
* {@link TokenAmount} or the `prices` helpers to humanize.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { pyRound } from "./util.js";
|
|
14
|
+
|
|
15
|
+
// --------------------------------------------------------------------------- //
|
|
16
|
+
// Enums
|
|
17
|
+
// --------------------------------------------------------------------------- //
|
|
18
|
+
/** DEX generation used for a swap hop (matches contract `version` uint8). */
|
|
19
|
+
export enum PoolVersion {
|
|
20
|
+
V2 = 2,
|
|
21
|
+
V3 = 3,
|
|
22
|
+
V4 = 4,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Lock asset kind as stored by the LiquidityController.
|
|
27
|
+
*
|
|
28
|
+
* Values match the on-chain constants
|
|
29
|
+
* (`LOCK_KIND_V3_NFT=1`, `LOCK_KIND_V2_LP=2`, `LOCK_KIND_V4_NFT=3`).
|
|
30
|
+
*/
|
|
31
|
+
export enum LockKind {
|
|
32
|
+
V3_POSITION = 1,
|
|
33
|
+
V2_LP = 2,
|
|
34
|
+
V4_POSITION = 3,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type Raw = readonly any[];
|
|
38
|
+
|
|
39
|
+
const NATIVE_SENTINELS = new Set([
|
|
40
|
+
"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
|
|
41
|
+
"0x0000000000000000000000000000000000000000",
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
// --------------------------------------------------------------------------- //
|
|
45
|
+
// Swap routing
|
|
46
|
+
// --------------------------------------------------------------------------- //
|
|
47
|
+
/** One hop of a hybrid route (can itself be multi-token within a version). */
|
|
48
|
+
export class SwapStep {
|
|
49
|
+
constructor(
|
|
50
|
+
public readonly version: number,
|
|
51
|
+
public readonly path: string[],
|
|
52
|
+
public readonly dexPath: number[],
|
|
53
|
+
public readonly pools: string[],
|
|
54
|
+
public readonly baseToken: string,
|
|
55
|
+
public readonly estimatedAmountOut: bigint,
|
|
56
|
+
) {}
|
|
57
|
+
|
|
58
|
+
static fromRaw(r: Raw): SwapStep {
|
|
59
|
+
return new SwapStep(
|
|
60
|
+
Number(r[0]),
|
|
61
|
+
[...r[1]].map((a) => String(a)),
|
|
62
|
+
[...r[2]].map((x) => Number(x)),
|
|
63
|
+
[...r[3]].map((a) => String(a)),
|
|
64
|
+
String(r[4]),
|
|
65
|
+
BigInt(r[5]),
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
get isEmpty(): boolean {
|
|
70
|
+
return this.version === 0 && this.path.length === 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** ABI-encodable tuple for this step. */
|
|
74
|
+
toTuple(): [number, string[], number[], string[], string, bigint] {
|
|
75
|
+
return [this.version, this.path, this.dexPath, this.pools, this.baseToken, this.estimatedAmountOut];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Result of `getBestSwapPath` — up to three cross-version steps.
|
|
81
|
+
*
|
|
82
|
+
* This is exactly the struct `executeHybridSwap` consumes, so it round-trips:
|
|
83
|
+
* quote -> {@link toTuple} -> execute.
|
|
84
|
+
*/
|
|
85
|
+
export class SwapPath {
|
|
86
|
+
constructor(
|
|
87
|
+
public readonly firstStep: SwapStep,
|
|
88
|
+
public readonly secondStep: SwapStep,
|
|
89
|
+
public readonly thirdStep: SwapStep,
|
|
90
|
+
public readonly stepCount: number,
|
|
91
|
+
) {}
|
|
92
|
+
|
|
93
|
+
static fromRaw(r: Raw): SwapPath {
|
|
94
|
+
return new SwapPath(
|
|
95
|
+
SwapStep.fromRaw(r[0]),
|
|
96
|
+
SwapStep.fromRaw(r[1]),
|
|
97
|
+
SwapStep.fromRaw(r[2]),
|
|
98
|
+
Number(r[3]),
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** ABI-encodable tuple for `executeHybridSwap(swapData, …)`. */
|
|
103
|
+
toTuple(): [ReturnType<SwapStep["toTuple"]>, ReturnType<SwapStep["toTuple"]>, ReturnType<SwapStep["toTuple"]>, number] {
|
|
104
|
+
return [this.firstStep.toTuple(), this.secondStep.toTuple(), this.thirdStep.toTuple(), this.stepCount];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
get activeSteps(): SwapStep[] {
|
|
108
|
+
return [this.firstStep, this.secondStep, this.thirdStep].slice(0, this.stepCount);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Quoted output = the last active step's estimate. */
|
|
112
|
+
get estimatedAmountOut(): bigint {
|
|
113
|
+
const steps = this.activeSteps;
|
|
114
|
+
return steps.length ? steps[steps.length - 1].estimatedAmountOut : 0n;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Every pool this route would route through (across all active steps). */
|
|
118
|
+
get poolAddresses(): string[] {
|
|
119
|
+
const out: string[] = [];
|
|
120
|
+
for (const st of this.activeSteps) out.push(...st.pools);
|
|
121
|
+
return out;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Return a list of route-integrity violations (empty == sound route).
|
|
126
|
+
*
|
|
127
|
+
* Guards against funds entering the wrong pool: verifies the path starts at
|
|
128
|
+
* `tokenIn`, ends at `tokenOut` and that every hop chains into the next
|
|
129
|
+
* (`step[i]` last token == `step[i+1]` first token). Native sentinels are
|
|
130
|
+
* resolved to `wnative` before comparing.
|
|
131
|
+
*/
|
|
132
|
+
checkIntegrity(tokenIn: string, tokenOut: string, wnative?: string | null): string[] {
|
|
133
|
+
const norm = (a: string): string => {
|
|
134
|
+
a = a.toLowerCase();
|
|
135
|
+
if (wnative && NATIVE_SENTINELS.has(a)) return wnative.toLowerCase();
|
|
136
|
+
return a;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const problems: string[] = [];
|
|
140
|
+
const steps = this.activeSteps;
|
|
141
|
+
if (steps.length === 0) return ["empty route (step_count == 0)"];
|
|
142
|
+
|
|
143
|
+
// Chain over the steps that actually carry a token path. Anchoring the
|
|
144
|
+
// start/end and hop-continuity checks to this list (instead of raw steps)
|
|
145
|
+
// means an empty intermediate/edge step can't silently drop a link.
|
|
146
|
+
const chain = steps.filter((s) => s.path.length > 0);
|
|
147
|
+
if (chain.length === 0) return ["route has no token path"];
|
|
148
|
+
|
|
149
|
+
if (norm(chain[0].path[0]) !== norm(tokenIn)) {
|
|
150
|
+
problems.push(`path start ${chain[0].path[0]} != token_in ${tokenIn}`);
|
|
151
|
+
}
|
|
152
|
+
const last = chain[chain.length - 1];
|
|
153
|
+
if (norm(last.path[last.path.length - 1]) !== norm(tokenOut)) {
|
|
154
|
+
problems.push(`path end ${last.path[last.path.length - 1]} != token_out ${tokenOut}`);
|
|
155
|
+
}
|
|
156
|
+
for (let i = 0; i < chain.length - 1; i++) {
|
|
157
|
+
const a = chain[i].path[chain[i].path.length - 1];
|
|
158
|
+
const b = chain[i + 1].path[0];
|
|
159
|
+
if (norm(a) !== norm(b)) {
|
|
160
|
+
problems.push(`hop ${i}->${i + 1} broken: ${a} != ${b}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return problems;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// --------------------------------------------------------------------------- //
|
|
168
|
+
// Token safety / pricing
|
|
169
|
+
// --------------------------------------------------------------------------- //
|
|
170
|
+
/** Honeypot / transfer-tax probe from `getTokenInfos`. */
|
|
171
|
+
export class TokenInfo {
|
|
172
|
+
constructor(
|
|
173
|
+
public readonly buyEstimate: bigint,
|
|
174
|
+
public readonly buyResult: bigint,
|
|
175
|
+
public readonly sellEstimate: bigint,
|
|
176
|
+
public readonly sellResult: bigint,
|
|
177
|
+
public readonly buySuccess: boolean,
|
|
178
|
+
public readonly approveSuccess: boolean,
|
|
179
|
+
public readonly sellSuccess: boolean,
|
|
180
|
+
) {}
|
|
181
|
+
|
|
182
|
+
static fromRaw(r: Raw): TokenInfo {
|
|
183
|
+
return new TokenInfo(
|
|
184
|
+
BigInt(r[0]), BigInt(r[1]), BigInt(r[2]), BigInt(r[3]),
|
|
185
|
+
Boolean(r[4]), Boolean(r[5]), Boolean(r[6]),
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** True if the sell leg failed while the buy succeeded. */
|
|
190
|
+
get isHoneypot(): boolean {
|
|
191
|
+
return this.buySuccess && !this.sellSuccess;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
get buyTaxBps(): number {
|
|
195
|
+
if (this.buyEstimate === 0n) return 0;
|
|
196
|
+
return Math.max(0, pyRound((1 - Number(this.buyResult) / Number(this.buyEstimate)) * 10_000));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
get sellTaxBps(): number {
|
|
200
|
+
if (this.sellEstimate === 0n) return 0;
|
|
201
|
+
return Math.max(0, pyRound((1 - Number(this.sellResult) / Number(this.sellEstimate)) * 10_000));
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** A USD/WETH price (1e18-scaled) plus the base token it was priced via. */
|
|
206
|
+
export class PriceResult {
|
|
207
|
+
constructor(public readonly price: bigint, public readonly viaToken: string) {}
|
|
208
|
+
|
|
209
|
+
static fromRaw(r: Raw): PriceResult {
|
|
210
|
+
return new PriceResult(BigInt(r[0]), String(r[1]));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
get asFloat(): number {
|
|
214
|
+
return Number(this.price) / 1e18;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** One entry of `getWalletBalance` — balance + live USD valuation. */
|
|
219
|
+
export class WalletBalance {
|
|
220
|
+
constructor(
|
|
221
|
+
public readonly token: string,
|
|
222
|
+
public readonly balance: bigint,
|
|
223
|
+
public readonly usdPrice18: bigint,
|
|
224
|
+
public readonly usdValue: bigint,
|
|
225
|
+
public readonly decimals: number,
|
|
226
|
+
public readonly ok: boolean,
|
|
227
|
+
) {}
|
|
228
|
+
|
|
229
|
+
static fromRaw(r: Raw): WalletBalance {
|
|
230
|
+
return new WalletBalance(String(r[0]), BigInt(r[1]), BigInt(r[2]), BigInt(r[3]), Number(r[4]), Boolean(r[5]));
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
get balanceFloat(): number {
|
|
234
|
+
return Number(this.balance) / 10 ** this.decimals;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
get usdValueFloat(): number {
|
|
238
|
+
return Number(this.usdValue) / 1e18;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// --------------------------------------------------------------------------- //
|
|
243
|
+
// Liquidity positions
|
|
244
|
+
// --------------------------------------------------------------------------- //
|
|
245
|
+
export class V2Position {
|
|
246
|
+
constructor(
|
|
247
|
+
public readonly pair: string,
|
|
248
|
+
public readonly token0: string,
|
|
249
|
+
public readonly token1: string,
|
|
250
|
+
public readonly lpBalance: bigint,
|
|
251
|
+
public readonly reserve0: bigint,
|
|
252
|
+
public readonly reserve1: bigint,
|
|
253
|
+
public readonly totalSupply: bigint,
|
|
254
|
+
public readonly share0: bigint,
|
|
255
|
+
public readonly share1: bigint,
|
|
256
|
+
public readonly locked: boolean,
|
|
257
|
+
public readonly unlockTime: bigint,
|
|
258
|
+
) {}
|
|
259
|
+
|
|
260
|
+
static fromRaw(r: Raw): V2Position {
|
|
261
|
+
return new V2Position(
|
|
262
|
+
String(r[0]), String(r[1]), String(r[2]), BigInt(r[3]), BigInt(r[4]), BigInt(r[5]),
|
|
263
|
+
BigInt(r[6]), BigInt(r[7]), BigInt(r[8]), Boolean(r[9]), BigInt(r[10]),
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export class V3Position {
|
|
269
|
+
constructor(
|
|
270
|
+
public readonly positionManager: string,
|
|
271
|
+
public readonly tokenId: bigint,
|
|
272
|
+
public readonly token0: string,
|
|
273
|
+
public readonly token1: string,
|
|
274
|
+
public readonly fee: number,
|
|
275
|
+
public readonly tickLower: number,
|
|
276
|
+
public readonly tickUpper: number,
|
|
277
|
+
public readonly liquidity: bigint,
|
|
278
|
+
public readonly tokensOwed0: bigint,
|
|
279
|
+
public readonly tokensOwed1: bigint,
|
|
280
|
+
public readonly locked: boolean,
|
|
281
|
+
public readonly unlockTime: bigint,
|
|
282
|
+
) {}
|
|
283
|
+
|
|
284
|
+
static fromRaw(r: Raw): V3Position {
|
|
285
|
+
return new V3Position(
|
|
286
|
+
String(r[0]), BigInt(r[1]), String(r[2]), String(r[3]), Number(r[4]), Number(r[5]),
|
|
287
|
+
Number(r[6]), BigInt(r[7]), BigInt(r[8]), BigInt(r[9]), Boolean(r[10]), BigInt(r[11]),
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export class V4Position {
|
|
293
|
+
constructor(
|
|
294
|
+
public readonly positionManager: string,
|
|
295
|
+
public readonly tokenId: bigint,
|
|
296
|
+
public readonly poolId: string,
|
|
297
|
+
public readonly currency0: string,
|
|
298
|
+
public readonly currency1: string,
|
|
299
|
+
public readonly fee: number,
|
|
300
|
+
public readonly tickSpacing: number,
|
|
301
|
+
public readonly hooks: string,
|
|
302
|
+
public readonly tickLower: number,
|
|
303
|
+
public readonly tickUpper: number,
|
|
304
|
+
public readonly liquidity: bigint,
|
|
305
|
+
public readonly locked: boolean,
|
|
306
|
+
public readonly unlockTime: bigint,
|
|
307
|
+
) {}
|
|
308
|
+
|
|
309
|
+
static fromRaw(r: Raw): V4Position {
|
|
310
|
+
return new V4Position(
|
|
311
|
+
String(r[0]), BigInt(r[1]), String(r[2]), String(r[3]), String(r[4]), Number(r[5]),
|
|
312
|
+
Number(r[6]), String(r[7]), Number(r[8]), Number(r[9]), BigInt(r[10]), Boolean(r[11]), BigInt(r[12]),
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export class V2PoolState {
|
|
318
|
+
constructor(
|
|
319
|
+
public readonly pair: string,
|
|
320
|
+
public readonly token0: string,
|
|
321
|
+
public readonly token1: string,
|
|
322
|
+
public readonly reserve0: bigint,
|
|
323
|
+
public readonly reserve1: bigint,
|
|
324
|
+
) {}
|
|
325
|
+
|
|
326
|
+
static fromRaw(r: Raw): V2PoolState {
|
|
327
|
+
return new V2PoolState(String(r[0]), String(r[1]), String(r[2]), BigInt(r[3]), BigInt(r[4]));
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export class V3PoolState {
|
|
332
|
+
constructor(
|
|
333
|
+
public readonly pool: string,
|
|
334
|
+
public readonly token0: string,
|
|
335
|
+
public readonly token1: string,
|
|
336
|
+
public readonly fee: number,
|
|
337
|
+
public readonly tick: number,
|
|
338
|
+
public readonly sqrtPriceX96: bigint,
|
|
339
|
+
public readonly liquidity: bigint,
|
|
340
|
+
public readonly tickSpacing: number,
|
|
341
|
+
) {}
|
|
342
|
+
|
|
343
|
+
static fromRaw(r: Raw): V3PoolState {
|
|
344
|
+
return new V3PoolState(
|
|
345
|
+
String(r[0]), String(r[1]), String(r[2]), Number(r[3]), Number(r[4]), BigInt(r[5]),
|
|
346
|
+
BigInt(r[6]), Number(r[7]),
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export class V4PoolState {
|
|
352
|
+
constructor(
|
|
353
|
+
public readonly poolId: string,
|
|
354
|
+
public readonly currency0: string,
|
|
355
|
+
public readonly currency1: string,
|
|
356
|
+
public readonly fee: number,
|
|
357
|
+
public readonly tickSpacing: number,
|
|
358
|
+
public readonly hooks: string,
|
|
359
|
+
public readonly sqrtPriceX96: bigint,
|
|
360
|
+
public readonly tick: number,
|
|
361
|
+
public readonly protocolFee: number,
|
|
362
|
+
public readonly lpFee: number,
|
|
363
|
+
public readonly liquidity: bigint,
|
|
364
|
+
) {}
|
|
365
|
+
|
|
366
|
+
static fromRaw(r: Raw): V4PoolState {
|
|
367
|
+
return new V4PoolState(
|
|
368
|
+
String(r[0]), String(r[1]), String(r[2]), Number(r[3]), Number(r[4]), String(r[5]),
|
|
369
|
+
BigInt(r[6]), Number(r[7]), Number(r[8]), Number(r[9]), BigInt(r[10]),
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/** A time-lock entry from `getLocks`. */
|
|
375
|
+
export class Lock {
|
|
376
|
+
constructor(
|
|
377
|
+
public readonly kind: number,
|
|
378
|
+
public readonly asset: string,
|
|
379
|
+
public readonly tokenIdOrAmount: bigint,
|
|
380
|
+
public readonly lockTime: bigint,
|
|
381
|
+
public readonly unlockTime: bigint,
|
|
382
|
+
public readonly owner: string,
|
|
383
|
+
public readonly tokenA: string,
|
|
384
|
+
public readonly tokenB: string,
|
|
385
|
+
public readonly nonce: bigint,
|
|
386
|
+
) {}
|
|
387
|
+
|
|
388
|
+
static fromRaw(r: Raw): Lock {
|
|
389
|
+
return new Lock(
|
|
390
|
+
Number(r[0]), String(r[1]), BigInt(r[2]), BigInt(r[3]), BigInt(r[4]), String(r[5]),
|
|
391
|
+
String(r[6]), String(r[7]), BigInt(r[8]),
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
get kindName(): string {
|
|
396
|
+
const name = LockKind[this.kind];
|
|
397
|
+
return name !== undefined ? name : `UNKNOWN(${this.kind})`;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/** Uncollected fees of a V3/V4 position from `getClaimableFees`. */
|
|
402
|
+
export class ClaimableFees {
|
|
403
|
+
constructor(
|
|
404
|
+
public readonly token0: string,
|
|
405
|
+
public readonly amount0: bigint,
|
|
406
|
+
public readonly token1: string,
|
|
407
|
+
public readonly amount1: bigint,
|
|
408
|
+
) {}
|
|
409
|
+
|
|
410
|
+
static fromRaw(r: Raw): ClaimableFees {
|
|
411
|
+
return new ClaimableFees(String(r[0]), BigInt(r[1]), String(r[2]), BigInt(r[3]));
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** Paged referral-fee balances from `getReferralFeeTokens`. */
|
|
416
|
+
export class ReferralFeeTokens {
|
|
417
|
+
constructor(
|
|
418
|
+
public readonly tokens: string[],
|
|
419
|
+
public readonly amounts: bigint[],
|
|
420
|
+
public readonly maxIndex: number,
|
|
421
|
+
) {}
|
|
422
|
+
|
|
423
|
+
static fromRaw(r: Raw): ReferralFeeTokens {
|
|
424
|
+
return new ReferralFeeTokens(
|
|
425
|
+
[...r[0]].map((a) => String(a)),
|
|
426
|
+
[...r[1]].map((x) => BigInt(x)),
|
|
427
|
+
Number(r[2]),
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
asDict(): Record<string, bigint> {
|
|
432
|
+
const out: Record<string, bigint> = {};
|
|
433
|
+
for (let i = 0; i < this.tokens.length && i < this.amounts.length; i++) {
|
|
434
|
+
out[this.tokens[i]] = this.amounts[i];
|
|
435
|
+
}
|
|
436
|
+
return out;
|
|
437
|
+
}
|
|
438
|
+
}
|
package/src/util.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Small numeric helpers that match Python semantics exactly, so this SDK is a
|
|
3
|
+
* faithful 1:1 port (and not subtly off by a unit at .5 boundaries).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Round half-to-even ("banker's rounding"), matching Python's built-in `round()`.
|
|
8
|
+
*
|
|
9
|
+
* JS `Math.round` rounds half **up** (0.5 -> 1, 2.5 -> 3), while Python rounds
|
|
10
|
+
* half to the nearest **even** integer (0.5 -> 0, 2.5 -> 2). The SDK's tax-bps
|
|
11
|
+
* and price-impact-bps math goes through Python `round()`, so we reproduce it.
|
|
12
|
+
*/
|
|
13
|
+
export function pyRound(x: number): number {
|
|
14
|
+
const floor = Math.floor(x);
|
|
15
|
+
const diff = x - floor;
|
|
16
|
+
if (diff < 0.5) return floor;
|
|
17
|
+
if (diff > 0.5) return floor + 1;
|
|
18
|
+
// Exactly .5 -> pick the even neighbour.
|
|
19
|
+
return floor % 2 === 0 ? floor : floor + 1;
|
|
20
|
+
}
|