@apex_labs/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 +375 -0
- package/dist/index.cjs +22937 -0
- package/dist/index.d.cts +11153 -0
- package/dist/index.d.ts +11153 -0
- package/dist/index.js +22760 -0
- package/package.json +46 -0
- package/vendor/pancake-v3-sdk/LICENSE +674 -0
- package/vendor/pancake-v3-sdk/README.md +5 -0
- package/vendor/pancake-v3-sdk/package.json +19 -0
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 @apex_labs/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 "@apex_labs/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 "@apex_labs/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 `@apex_labs/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 "@apex_labs/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.
|