@trantorapex/apex-sdk 0.1.0

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 ADDED
@@ -0,0 +1,375 @@
1
+ # Apex SDK
2
+
3
+ Frontend SDK for Apex CL and Classic pools. It vendors a pinned `@pancakeswap/v3-sdk@3.10.0` snapshot as an Apex-owned fork, then adds Apex fee tiers, Apex CREATE2 address helpers, Classic AMM quoting, mixed CL/Classic path encoding, and exact ABI exports for the Apex contracts.
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ cd apex-sdk
9
+ npm install
10
+ npm run sync:abis
11
+ npm run build
12
+ npm test
13
+ ```
14
+
15
+ Install the published package:
16
+
17
+ ```bash
18
+ npm install @trantorapex/apex-sdk
19
+ ```
20
+
21
+ ## Config
22
+
23
+ Do not hardcode deployment addresses in app code. Keep one config object per chain:
24
+
25
+ ```ts
26
+ import type { ApexDeploymentConfig } from "@trantorapex/apex-sdk";
27
+
28
+ export const apex: ApexDeploymentConfig = {
29
+ chainId: 31337,
30
+ clFactory: "0x...",
31
+ clPoolDeployer: "0x...",
32
+ clSwapRouter: "0x...",
33
+ clQuoter: "0x...",
34
+ clNonfungiblePositionManager: "0x...",
35
+ clMasterChef: "0x...",
36
+ smartRouter: "0x...",
37
+ mixedQuoter: "0x...",
38
+ classicFactory: "0x...",
39
+ classicPairInitCodeHash: "0x...",
40
+ classicRouter: "0x...",
41
+ classicChef: "0x...",
42
+ weth: "0x...",
43
+ };
44
+ ```
45
+
46
+ ## Functions frontend should care about
47
+
48
+ ```ts
49
+ import {
50
+ ApexFeeAmount,
51
+ APEX_CL_POOL_INIT_CODE_HASH,
52
+ APEX_CL_TICK_SPACINGS,
53
+ APEX_CLASSIC_PAIR_INIT_CODE_HASH,
54
+ ApexClassicFarm,
55
+ ApexCLFarm,
56
+ ApexSmartRouter,
57
+ ApexVaultPosition,
58
+ getApexTickSpacing,
59
+ createApexPool,
60
+ computeCLPoolAddress,
61
+ computeClassicPoolAddress,
62
+ quoteApexClassicExactInput,
63
+ encodeApexMixedRouteToPath,
64
+ encodeApexMixedRouteToPancakeQuoteParams,
65
+ decodeApexMixedRoutePath,
66
+ parseApexProtocolFeePacked,
67
+ apexCLPoolAbi,
68
+ apexCLFactoryAbi,
69
+ apexCLMasterChefAbi,
70
+ apexNonfungiblePositionManagerAbi,
71
+ apexSwapRouterAbi,
72
+ apexSmartRouterAbi,
73
+ apexMixedQuoterAbi,
74
+ apexQuoterV2Abi,
75
+ apexClassicFactoryAbi,
76
+ apexClassicPairAbi,
77
+ Pool,
78
+ Route,
79
+ Trade,
80
+ SwapRouter,
81
+ NonfungiblePositionManager,
82
+ SwapQuoter,
83
+ TickMath,
84
+ nearestUsableTick,
85
+ encodeSqrtRatioX96,
86
+ } from "@trantorapex/apex-sdk";
87
+ ```
88
+
89
+ ### CL pool address
90
+
91
+ ```ts
92
+ const pool = computeCLPoolAddress({
93
+ config: apex,
94
+ tokenA,
95
+ tokenB,
96
+ fee: ApexFeeAmount.FEE_0_30,
97
+ });
98
+ ```
99
+
100
+ ### CL pool object
101
+
102
+ ```ts
103
+ const pool = createApexPool({
104
+ tokenA,
105
+ tokenB,
106
+ fee: ApexFeeAmount.FEE_0_30,
107
+ sqrtRatioX96,
108
+ liquidity,
109
+ tickCurrent,
110
+ ticks,
111
+ });
112
+ ```
113
+
114
+ `createApexPool` returns the forked Pancake `Pool`, with Apex fee tiers installed. Position, trade, route, quoter, swap-router, and NFT-position-manager logic should use the classes re-exported by `@trantorapex/apex-sdk`.
115
+
116
+ ### Periphery ABIs
117
+
118
+ Use the exact ABIs exported from compiled Apex contracts:
119
+
120
+ ```ts
121
+ import {
122
+ apexNonfungiblePositionManagerAbi,
123
+ apexSwapRouterAbi,
124
+ apexQuoterAbi,
125
+ apexQuoterV2Abi,
126
+ apexSmartRouterAbi,
127
+ apexMixedQuoterAbi,
128
+ apexTickLensAbi,
129
+ apexInterfaceMulticallAbi,
130
+ apexCLFactoryAbi,
131
+ apexCLMasterChefAbi,
132
+ apexCLPoolAbi,
133
+ apexClassicFactoryAbi,
134
+ apexClassicPairAbi,
135
+ } from "@trantorapex/apex-sdk";
136
+ ```
137
+
138
+ ### Classic pair address
139
+
140
+ ```ts
141
+ const stablePair = computeClassicPoolAddress({
142
+ config: apex,
143
+ tokenA: tokenA.address,
144
+ tokenB: tokenB.address,
145
+ stable: true,
146
+ });
147
+ ```
148
+
149
+ ### Classic quote
150
+
151
+ ```ts
152
+ const amountOut = quoteApexClassicExactInput({
153
+ amountIn,
154
+ tokenIn: tokenA.address,
155
+ token0,
156
+ token1,
157
+ reserve0,
158
+ reserve1,
159
+ token0Decimals: 18,
160
+ token1Decimals: 18,
161
+ stable: false,
162
+ fee,
163
+ });
164
+ ```
165
+
166
+ ### Classic farm UX
167
+
168
+ Use `ApexClassicFarm` for Classic LP staking. Pools are pid-based; read `ClassicChef.pidOf(pair)` from the exported ABI or an indexed farm list, then encode normal stake/claim/exit calls:
169
+
170
+ ```ts
171
+ const stakeClassic = ApexClassicFarm.depositCallParameters({
172
+ pid,
173
+ amount,
174
+ });
175
+
176
+ const claimClassic = ApexClassicFarm.harvestCallParameters({
177
+ pid,
178
+ });
179
+
180
+ const exitClassic = ApexClassicFarm.withdrawCallParameters({
181
+ pid,
182
+ amount,
183
+ });
184
+ ```
185
+
186
+ ### Mixed CL/Classic path
187
+
188
+ ```ts
189
+ const path = encodeApexMixedRouteToPath([
190
+ {
191
+ kind: "CL",
192
+ tokenIn: tokenA.address,
193
+ tokenOut: tokenB.address,
194
+ fee: ApexFeeAmount.FEE_0_30,
195
+ },
196
+ { kind: "CLASSIC_STABLE", tokenIn: tokenB.address, tokenOut: tokenC.address },
197
+ ]);
198
+ ```
199
+
200
+ Quote that path through `MixedQuoter.quoteExactInput(path, amountIn)`, then execute it with
201
+ `ApexSmartRouter`. The high-level helpers follow Pancake SmartRouter’s safety pattern:
202
+ they encode the swap, then wrap it in `SmartRouter.multicall(deadlineOrPreviousBlockhash, data)`.
203
+
204
+ ```ts
205
+ const swap = ApexSmartRouter.mixedExactInputCallParameters(
206
+ { hops, recipient: account, amountIn, amountOutMinimum },
207
+ { deadlineOrPreviousBlockhash: deadline },
208
+ );
209
+ ```
210
+
211
+ If you fork Pancake SmartRouter’s mixed quote provider, use Pancake-style quote params:
212
+
213
+ ```ts
214
+ const { path, flags } = encodeApexMixedRouteToPancakeQuoteParams(hops);
215
+ const quote = await publicClient.readContract({
216
+ address: apex.mixedQuoter,
217
+ abi: apexMixedQuoterAbi,
218
+ functionName: "quoteExactInput",
219
+ args: [path, flags, amountIn],
220
+ });
221
+ ```
222
+
223
+ For routes that Pancake SmartRouter partitions by protocol:
224
+
225
+ ```ts
226
+ // Classic volatile section
227
+ ApexSmartRouter.classicExactInputCallParameters(
228
+ { amountIn, amountOutMin, path, recipient },
229
+ { deadlineOrPreviousBlockhash: deadline },
230
+ );
231
+
232
+ // Classic stable section
233
+ ApexSmartRouter.stableExactInputCallParameters(
234
+ { amountIn, amountOutMin, path, flags, recipient },
235
+ { deadlineOrPreviousBlockhash: deadline },
236
+ );
237
+
238
+ // CL section
239
+ ApexSmartRouter.exactInputCallParameters(
240
+ { path, recipient, amountIn, amountOutMinimum },
241
+ { deadlineOrPreviousBlockhash: deadline },
242
+ );
243
+ ```
244
+
245
+ Use the raw `encode*` helpers only when deliberately assembling a custom multicall. User-facing swaps should use `*CallParameters`, or `ApexSmartRouter.swapCallParameters(rawCalls, options)` for custom batches. These require a deadline or previous blockhash and support cleanup calls such as `refundETH`, `sweepToken`, and `unwrapWETH9`.
246
+
247
+ The mixed periphery is exact-input only. Use the CL-only `SwapRouter`/`QuoterV2` for CL exact-output routes.
248
+
249
+ ### CL farm UX
250
+
251
+ Use `ApexCLFarm` for staked CL positions. It encodes the Apex-safe paths instead of making the frontend assemble Chef calls by hand.
252
+
253
+ ```ts
254
+ const { calldata, value } = ApexCLFarm.mintAndStakeCallParameters(
255
+ {
256
+ token0: tokenA.address,
257
+ token1: tokenB.address,
258
+ fee: ApexFeeAmount.FEE_0_30,
259
+ tickLower,
260
+ tickUpper,
261
+ amount0Desired,
262
+ amount1Desired,
263
+ amount0Min,
264
+ amount1Min,
265
+ account,
266
+ deadline,
267
+ },
268
+ {
269
+ stakingReceiver: apex.clMasterChef,
270
+ nonfungiblePositionManager: apex.clNonfungiblePositionManager,
271
+ },
272
+ );
273
+ ```
274
+
275
+ `mintAndStakeCallParameters` takes `account` and encodes it as the staked NFT owner. It rejects the Chef and NFP manager as owners so frontend callers cannot strand positions in protocol contracts.
276
+
277
+ When minting with native ETH, pass `value` in the options object. The SDK appends `refundETH()` in the same NFP multicall only when value is nonzero.
278
+
279
+ For fee collection on staked NFTs, prefer `collectCallParameters` or `decreaseAndCollectCallParameters`:
280
+
281
+ ```ts
282
+ const collect = ApexCLFarm.collectCallParameters({
283
+ tokenId,
284
+ recipient: account,
285
+ });
286
+
287
+ const exitPart = ApexCLFarm.decreaseAndCollectCallParameters(
288
+ { tokenId, liquidity, amount0Min, amount1Min, deadline },
289
+ { tokenId, recipient: account },
290
+ );
291
+ ```
292
+
293
+ These helpers call `CLMasterChef.multicall(...)` and use `collectTo` with the inner collect recipient set to `address(0)`, so Chef receives the tokens first and immediately sweeps/unwraps them to the final recipient.
294
+
295
+ For a full exit, use `closeAndBurnCallParameters`:
296
+
297
+ ```ts
298
+ const close = ApexCLFarm.closeAndBurnCallParameters(
299
+ { tokenId, liquidity, amount0Min, amount1Min, deadline },
300
+ { tokenId, recipient: account },
301
+ );
302
+ ```
303
+
304
+ This encodes `harvest -> decreaseLiquidity -> collectTo -> burn`. The harvest happens before liquidity is removed, so it is safe even when rewards are zero and keeps `burn` compatible with Pancake-style strict empty-position semantics.
305
+
306
+ ### Apex Vault UX
307
+
308
+ Use `ApexVaultPosition` for user-facing VeApexToken vault actions. Users choose reward-token percentages and a compound percentage. Compound is not user-claimable APEX; the user config only selects the compound bucket, and the protocol operator later calls the controller/vault compound functions.
309
+
310
+ ```ts
311
+ const approveVault = ApexVaultPosition.encodeVeApexTokenApprove({
312
+ tokenId,
313
+ spender: apexVault,
314
+ });
315
+
316
+ const stake = ApexVaultPosition.stakeCallParameters(tokenId, {
317
+ rewardConfigs: [
318
+ { rewardToken: weth, bps: 5_000 },
319
+ { rewardToken: usdc, bps: 2_000 },
320
+ ],
321
+ compoundBps: 3_000,
322
+ });
323
+ ```
324
+
325
+ The helper rejects configs that do not sum to exactly `10_000` bps, repeat a reward token, use zero bps for a reward token, or use the zero address as a reward token.
326
+
327
+ For an existing staked veNFT:
328
+
329
+ ```ts
330
+ const updateConfig = ApexVaultPosition.setUserConfigCallParameters(tokenId, {
331
+ rewardConfigs: [{ rewardToken: weth, bps: 7_000 }],
332
+ compoundBps: 3_000,
333
+ });
334
+
335
+ const claim = ApexVaultPosition.claimCallParameters({
336
+ tokenId,
337
+ rewardTokens: [weth, usdc],
338
+ });
339
+
340
+ const extend = ApexVaultPosition.extendLockCallParameters({
341
+ tokenId,
342
+ lockDuration: 26n * 7n * 86_400n,
343
+ });
344
+
345
+ const increase = ApexVaultPosition.increaseAmountCallParameters({
346
+ tokenId,
347
+ amount,
348
+ });
349
+ ```
350
+
351
+ The vault is custodial while staked. For staked veNFTs, route amount increases through `ApexVaultPosition.increaseAmountCallParameters(...)`, not raw `VeApexToken.depositFor(...)`, so Vault reward weights are refreshed. A direct VeApexToken transfer outside the vault is just a normal NFT transfer; the SDK should treat vault stake/unstake as the canonical earning path.
352
+
353
+ ### ABI refresh
354
+
355
+ After Solidity changes, refresh SDK ABIs from Forge artifacts before testing or publishing:
356
+
357
+ ```bash
358
+ forge build
359
+ npm run sync:abis --prefix apex-sdk
360
+ npm test --prefix apex-sdk
361
+ npm run build --prefix apex-sdk
362
+ ```
363
+
364
+ ## Notes
365
+
366
+ - Apex CL callbacks remain Pancake-compatible, so Pancake v3 periphery assumptions are preserved.
367
+ - The Pancake v3 SDK base is vendored under `vendor/pancake-v3-sdk`; Apex does not depend on the live `@pancakeswap/v3-sdk` npm package at runtime.
368
+ - Apex periphery exports include `NonfungiblePositionManager`, `SwapRouter`, `SmartRouter`, `Quoter`, `QuoterV2`, `MixedQuoter`, `TickLens`, and `InterfaceMulticall`.
369
+ - `MixedQuoter` supports both Apex-native `quoteExactInput(bytes,uint256)` and Pancake SmartRouter-style `quoteExactInput(bytes,uint256[],uint256)` for Classic+CL route discovery.
370
+ - Apex CL pool addresses use the Apex `CLPoolDeployer`, not the factory, matching the contract salt `keccak256(abi.encode(token0, token1, fee))`.
371
+ - Apex Classic pair addresses use the Classic factory salt `keccak256(abi.encodePacked(token0, token1, stable))`.
372
+ - `APEX_CL_POOL_INIT_CODE_HASH` and `APEX_CLASSIC_PAIR_INIT_CODE_HASH` are exported and used by default; override them only if the compiled contract bytecode changes.
373
+ - Apex Classic fees are denominated by `1_000_000`.
374
+ - Apex CL protocol fees are denominated by `10_000`, so `10_000` means 100%.
375
+ - Classic protocol fees are first realized by `collectClassicProtocolFees(pair)`, which burns FeeCenter-held fee LP into raw pair tokens. `pushAndSplitFees(tokens)` only splits raw token balances that are already in FeeCenter.