@coffer_so/sdk 1.0.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/LICENSE +21 -0
- package/README.md +283 -0
- package/dist/clients/AdminClient.d.ts +194 -0
- package/dist/clients/AdminClient.d.ts.map +1 -0
- package/dist/clients/AdminClient.js +482 -0
- package/dist/clients/AdminClient.js.map +1 -0
- package/dist/clients/CofferBackendClient.d.ts +877 -0
- package/dist/clients/CofferBackendClient.d.ts.map +1 -0
- package/dist/clients/CofferBackendClient.js +536 -0
- package/dist/clients/CofferBackendClient.js.map +1 -0
- package/dist/clients/CubeBackendClient.d.ts +877 -0
- package/dist/clients/CubeBackendClient.d.ts.map +1 -0
- package/dist/clients/CubeBackendClient.js +536 -0
- package/dist/clients/CubeBackendClient.js.map +1 -0
- package/dist/clients/CubicPoolClient.d.ts +120 -0
- package/dist/clients/CubicPoolClient.d.ts.map +1 -0
- package/dist/clients/CubicPoolClient.js +687 -0
- package/dist/clients/CubicPoolClient.js.map +1 -0
- package/dist/clients/PoolFactoryClient.d.ts +53 -0
- package/dist/clients/PoolFactoryClient.d.ts.map +1 -0
- package/dist/clients/PoolFactoryClient.js +91 -0
- package/dist/clients/PoolFactoryClient.js.map +1 -0
- package/dist/clients/RpcClient.d.ts +49 -0
- package/dist/clients/RpcClient.d.ts.map +1 -0
- package/dist/clients/RpcClient.js +135 -0
- package/dist/clients/RpcClient.js.map +1 -0
- package/dist/clients/SingleTokenDepositClient.d.ts +67 -0
- package/dist/clients/SingleTokenDepositClient.d.ts.map +1 -0
- package/dist/clients/SingleTokenDepositClient.js +105 -0
- package/dist/clients/SingleTokenDepositClient.js.map +1 -0
- package/dist/clients/contract-instructions.d.ts +24 -0
- package/dist/clients/contract-instructions.d.ts.map +1 -0
- package/dist/clients/contract-instructions.js +130 -0
- package/dist/clients/contract-instructions.js.map +1 -0
- package/dist/clients/index.d.ts +10 -0
- package/dist/clients/index.d.ts.map +1 -0
- package/dist/clients/index.js +26 -0
- package/dist/clients/index.js.map +1 -0
- package/dist/clients/quote-math.d.ts +15 -0
- package/dist/clients/quote-math.d.ts.map +1 -0
- package/dist/clients/quote-math.js +98 -0
- package/dist/clients/quote-math.js.map +1 -0
- package/dist/clients/tx-builders.d.ts +231 -0
- package/dist/clients/tx-builders.d.ts.map +1 -0
- package/dist/clients/tx-builders.js +861 -0
- package/dist/clients/tx-builders.js.map +1 -0
- package/dist/clients/versioned.d.ts +34 -0
- package/dist/clients/versioned.d.ts.map +1 -0
- package/dist/clients/versioned.js +55 -0
- package/dist/clients/versioned.js.map +1 -0
- package/dist/config/index.d.ts +65 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +75 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/networks.d.ts +12 -0
- package/dist/config/networks.d.ts.map +1 -0
- package/dist/config/networks.js +51 -0
- package/dist/config/networks.js.map +1 -0
- package/dist/config/tokens.d.ts +19 -0
- package/dist/config/tokens.d.ts.map +1 -0
- package/dist/config/tokens.js +43 -0
- package/dist/config/tokens.js.map +1 -0
- package/dist/idl/cubic_pool.json +4203 -0
- package/dist/idl/index.d.ts +1769 -0
- package/dist/idl/index.d.ts.map +1 -0
- package/dist/idl/index.js +18 -0
- package/dist/idl/index.js.map +1 -0
- package/dist/idl/protocol_admin.json +2615 -0
- package/dist/idl/single_token_liquidity.json +1121 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +206 -0
- package/dist/index.js.map +1 -0
- package/dist/math/cubicMath.d.ts +40 -0
- package/dist/math/cubicMath.d.ts.map +1 -0
- package/dist/math/cubicMath.js +82 -0
- package/dist/math/cubicMath.js.map +1 -0
- package/dist/math/fixedPoint.d.ts +19 -0
- package/dist/math/fixedPoint.d.ts.map +1 -0
- package/dist/math/fixedPoint.js +86 -0
- package/dist/math/fixedPoint.js.map +1 -0
- package/dist/math/index.d.ts +9 -0
- package/dist/math/index.d.ts.map +1 -0
- package/dist/math/index.js +30 -0
- package/dist/math/index.js.map +1 -0
- package/dist/math/logExp.d.ts +6 -0
- package/dist/math/logExp.d.ts.map +1 -0
- package/dist/math/logExp.js +68 -0
- package/dist/math/logExp.js.map +1 -0
- package/dist/math/lpLoss.d.ts +44 -0
- package/dist/math/lpLoss.d.ts.map +1 -0
- package/dist/math/lpLoss.js +103 -0
- package/dist/math/lpLoss.js.map +1 -0
- package/dist/math/maxSelloff.d.ts +164 -0
- package/dist/math/maxSelloff.d.ts.map +1 -0
- package/dist/math/maxSelloff.js +397 -0
- package/dist/math/maxSelloff.js.map +1 -0
- package/dist/math/singleToken.d.ts +54 -0
- package/dist/math/singleToken.d.ts.map +1 -0
- package/dist/math/singleToken.js +188 -0
- package/dist/math/singleToken.js.map +1 -0
- package/dist/math/slippage.d.ts +13 -0
- package/dist/math/slippage.d.ts.map +1 -0
- package/dist/math/slippage.js +44 -0
- package/dist/math/slippage.js.map +1 -0
- package/dist/math/surgeFee.d.ts +24 -0
- package/dist/math/surgeFee.d.ts.map +1 -0
- package/dist/math/surgeFee.js +85 -0
- package/dist/math/surgeFee.js.map +1 -0
- package/dist/math/weightedMath.d.ts +20 -0
- package/dist/math/weightedMath.d.ts.map +1 -0
- package/dist/math/weightedMath.js +66 -0
- package/dist/math/weightedMath.js.map +1 -0
- package/dist/parsers/borsh.d.ts +28 -0
- package/dist/parsers/borsh.d.ts.map +1 -0
- package/dist/parsers/borsh.js +104 -0
- package/dist/parsers/borsh.js.map +1 -0
- package/dist/parsers/contracts.d.ts +26 -0
- package/dist/parsers/contracts.d.ts.map +1 -0
- package/dist/parsers/contracts.js +62 -0
- package/dist/parsers/contracts.js.map +1 -0
- package/dist/parsers/events.d.ts +3 -0
- package/dist/parsers/events.d.ts.map +1 -0
- package/dist/parsers/events.js +281 -0
- package/dist/parsers/events.js.map +1 -0
- package/dist/parsers/index.d.ts +6 -0
- package/dist/parsers/index.d.ts.map +1 -0
- package/dist/parsers/index.js +22 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/parsers/mintAccount.d.ts +24 -0
- package/dist/parsers/mintAccount.d.ts.map +1 -0
- package/dist/parsers/mintAccount.js +27 -0
- package/dist/parsers/mintAccount.js.map +1 -0
- package/dist/parsers/poolAccount.d.ts +141 -0
- package/dist/parsers/poolAccount.d.ts.map +1 -0
- package/dist/parsers/poolAccount.js +224 -0
- package/dist/parsers/poolAccount.js.map +1 -0
- package/dist/types/contracts.d.ts +1340 -0
- package/dist/types/contracts.d.ts.map +1 -0
- package/dist/types/contracts.js +3 -0
- package/dist/types/contracts.js.map +1 -0
- package/dist/types/events.d.ts +172 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +3 -0
- package/dist/types/events.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +22 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/pool.d.ts +149 -0
- package/dist/types/pool.d.ts.map +1 -0
- package/dist/types/pool.js +3 -0
- package/dist/types/pool.js.map +1 -0
- package/dist/types/result.d.ts +24 -0
- package/dist/types/result.d.ts.map +1 -0
- package/dist/types/result.js +11 -0
- package/dist/types/result.js.map +1 -0
- package/dist/types/tx.d.ts +261 -0
- package/dist/types/tx.d.ts.map +1 -0
- package/dist/types/tx.js +3 -0
- package/dist/types/tx.js.map +1 -0
- package/dist/utils/errors.d.ts +44 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +192 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/extensions.d.ts +98 -0
- package/dist/utils/extensions.d.ts.map +1 -0
- package/dist/utils/extensions.js +187 -0
- package/dist/utils/extensions.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +21 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/pda.d.ts +8 -0
- package/dist/utils/pda.d.ts.map +1 -0
- package/dist/utils/pda.js +27 -0
- package/dist/utils/pda.js.map +1 -0
- package/dist/utils/retry.d.ts +22 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +62 -0
- package/dist/utils/retry.js.map +1 -0
- package/package.json +54 -0
- package/src/clients/AdminClient.ts +608 -0
- package/src/clients/CofferBackendClient.ts +1413 -0
- package/src/clients/CubicPoolClient.ts +719 -0
- package/src/clients/PoolFactoryClient.ts +110 -0
- package/src/clients/RpcClient.ts +195 -0
- package/src/clients/SingleTokenDepositClient.ts +143 -0
- package/src/clients/contract-instructions.ts +115 -0
- package/src/clients/index.ts +9 -0
- package/src/clients/quote-math.ts +81 -0
- package/src/clients/tx-builders.ts +1096 -0
- package/src/clients/versioned.ts +80 -0
- package/src/config/index.ts +111 -0
- package/src/config/networks.ts +71 -0
- package/src/config/tokens.ts +52 -0
- package/src/idl/cubic_pool.json +4203 -0
- package/src/idl/index.ts +13 -0
- package/src/idl/protocol_admin.json +2615 -0
- package/src/idl/single_token_liquidity.json +1121 -0
- package/src/index.ts +262 -0
- package/src/math/cubicMath.ts +92 -0
- package/src/math/fixedPoint.ts +71 -0
- package/src/math/index.ts +13 -0
- package/src/math/logExp.ts +61 -0
- package/src/math/lpLoss.ts +160 -0
- package/src/math/maxSelloff.ts +564 -0
- package/src/math/singleToken.ts +251 -0
- package/src/math/slippage.ts +38 -0
- package/src/math/surgeFee.ts +101 -0
- package/src/math/weightedMath.ts +64 -0
- package/src/parsers/borsh.ts +106 -0
- package/src/parsers/contracts.ts +64 -0
- package/src/parsers/events.ts +275 -0
- package/src/parsers/index.ts +5 -0
- package/src/parsers/mintAccount.ts +44 -0
- package/src/parsers/poolAccount.ts +372 -0
- package/src/types/contracts.ts +238 -0
- package/src/types/events.ts +198 -0
- package/src/types/index.ts +5 -0
- package/src/types/pool.ts +147 -0
- package/src/types/result.ts +51 -0
- package/src/types/tx.ts +278 -0
- package/src/utils/errors.ts +210 -0
- package/src/utils/extensions.ts +196 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/pda.ts +58 -0
- package/src/utils/retry.ts +85 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result returned by high-level client reads, quotes and transaction builders.
|
|
3
|
+
* Raw builders, parsers, math functions and Anchor instruction methods may
|
|
4
|
+
* throw. Use `if (res.ok) { ... } else { ... }` for result-based methods.
|
|
5
|
+
*/
|
|
6
|
+
export type SdkResult<T> =
|
|
7
|
+
| { ok: true; data: T }
|
|
8
|
+
| { ok: false; error: SdkError };
|
|
9
|
+
|
|
10
|
+
export interface SdkError {
|
|
11
|
+
/** Stable machine-readable code. */
|
|
12
|
+
code: SdkErrorCode;
|
|
13
|
+
/** Human-readable message, safe to show to end users. */
|
|
14
|
+
humanMessage: string;
|
|
15
|
+
/** Original error for debugging; never render this to end users. */
|
|
16
|
+
cause?: unknown;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type SdkErrorCode =
|
|
20
|
+
| "rpc_unavailable"
|
|
21
|
+
| "rpc_timeout"
|
|
22
|
+
| "rpc_rate_limited"
|
|
23
|
+
| "account_not_found"
|
|
24
|
+
| "invalid_input"
|
|
25
|
+
| "math_overflow"
|
|
26
|
+
| "parse_failure"
|
|
27
|
+
| "backend_unavailable"
|
|
28
|
+
| "backend_invalid_response"
|
|
29
|
+
| "insufficient_funds"
|
|
30
|
+
| "pool_disabled"
|
|
31
|
+
| "swaps_disabled"
|
|
32
|
+
| "selloff_window_full"
|
|
33
|
+
| "token_swaps_disabled"
|
|
34
|
+
| "unsupported_pool_state"
|
|
35
|
+
| "unsupported_token_extension"
|
|
36
|
+
| "slippage_exceeded"
|
|
37
|
+
| "simulation_failed"
|
|
38
|
+
| "tx_build_failed"
|
|
39
|
+
| "alt_fetch_failed"
|
|
40
|
+
| "auth_failed"
|
|
41
|
+
| "unknown";
|
|
42
|
+
|
|
43
|
+
export const ok = <T>(data: T): SdkResult<T> => ({ ok: true, data });
|
|
44
|
+
export const err = (
|
|
45
|
+
code: SdkErrorCode,
|
|
46
|
+
humanMessage: string,
|
|
47
|
+
cause?: unknown
|
|
48
|
+
): SdkResult<never> => ({
|
|
49
|
+
ok: false,
|
|
50
|
+
error: { code, humanMessage, cause },
|
|
51
|
+
});
|
package/src/types/tx.ts
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { PublicKey, TransactionInstruction } from "@solana/web3.js";
|
|
2
|
+
import BN from "bn.js";
|
|
3
|
+
|
|
4
|
+
export interface SwapParams {
|
|
5
|
+
user: PublicKey;
|
|
6
|
+
tokenInIndex: number;
|
|
7
|
+
tokenOutIndex: number;
|
|
8
|
+
amountIn: BN;
|
|
9
|
+
/** Hundredths-bps; omit to use SDK config default. */
|
|
10
|
+
slippageHundredthsBps?: number;
|
|
11
|
+
/** Optional explicit minimum; overrides slippage-derived value. */
|
|
12
|
+
minAmountOut?: BN;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface SwapQuote {
|
|
16
|
+
tokenInIndex: number;
|
|
17
|
+
tokenOutIndex: number;
|
|
18
|
+
amountIn: BN;
|
|
19
|
+
amountOut: BN;
|
|
20
|
+
/** Output before the sell-off surge fee (equals amountOut + surgeFeeAmount). */
|
|
21
|
+
grossAmountOut?: BN;
|
|
22
|
+
/** Spot-based upper bound on amountOut; useful for price-impact UI. */
|
|
23
|
+
spotOut: BN;
|
|
24
|
+
/** Absolute price impact in hundredths of basis point. */
|
|
25
|
+
priceImpactHbps: number;
|
|
26
|
+
feeAmount: BN;
|
|
27
|
+
protocolFeeAmount: BN;
|
|
28
|
+
/** Minimum amount_out to pass to the swap ix given the quoted slippage. */
|
|
29
|
+
minAmountOut: BN;
|
|
30
|
+
/** Variable sell-off surge fee taken from the output. `0` when no surge. */
|
|
31
|
+
surgeFeeAmount: BN;
|
|
32
|
+
/** Static fee (in PERCENT_SCALE units) + surge pct, for UI display. */
|
|
33
|
+
effectiveFeePct: number;
|
|
34
|
+
/** Post-trade window fill in PERCENT_SCALE units. `0` when window disabled. */
|
|
35
|
+
windowFillPct: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface AddLiquidityParams {
|
|
39
|
+
user: PublicKey;
|
|
40
|
+
/**
|
|
41
|
+
* Per-token spend CEILING, one entry per pool token, in raw units.
|
|
42
|
+
*
|
|
43
|
+
* ⚠ As of v5.1 (audit M-4 / I-1) this is an upper bound, **not** an exact
|
|
44
|
+
* amount. The program computes the largest strictly-proportional basket
|
|
45
|
+
* that fits inside this vector, deposits that, and leaves the rest in the
|
|
46
|
+
* user's wallet. Passing `[100, 100]` to a 1:9 pool deposits `[11, 100]`,
|
|
47
|
+
* not `[100, 100]`.
|
|
48
|
+
*
|
|
49
|
+
* Consequences for callers:
|
|
50
|
+
* - Do not render these as "amount you will deposit". Show the quoted
|
|
51
|
+
* proportional basket and treat this vector as a spend limit.
|
|
52
|
+
* - Balance checks should validate against the ceiling (that is the most
|
|
53
|
+
* that can be pulled), but post-tx accounting must read the
|
|
54
|
+
* `LiquidityAdded` event's `tokenAmounts` for what actually moved.
|
|
55
|
+
* - Length must equal `pool.tokenCount` or the program reverts with
|
|
56
|
+
* `InvalidArrayLength` (6064).
|
|
57
|
+
*/
|
|
58
|
+
tokenAmounts: BN[];
|
|
59
|
+
/**
|
|
60
|
+
* Slippage floor on BPT minted. Required and must be > 0 — this is the
|
|
61
|
+
* only guard on the join, since `tokenAmounts` is now a ceiling rather
|
|
62
|
+
* than a commitment.
|
|
63
|
+
*/
|
|
64
|
+
minimumBptAmount?: BN;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Result of `CubicPoolClient.quoteAddLiquidity`. Mirrors
|
|
69
|
+
* `cubic-pool/add_liquidity.rs`: the program crops the caller's ceiling
|
|
70
|
+
* vector to the single limiting ratio `min_i(amount_i / actual_i)`, pulls
|
|
71
|
+
* `depositAmounts` and leaves `refundAmounts` in the wallet.
|
|
72
|
+
*/
|
|
73
|
+
export interface AddLiquidityQuote {
|
|
74
|
+
/** The ceiling vector that was quoted (echo of the input). */
|
|
75
|
+
tokenAmounts: BN[];
|
|
76
|
+
/** What the program will actually pull per token (proportional basket). */
|
|
77
|
+
depositAmounts: BN[];
|
|
78
|
+
/** `tokenAmounts - depositAmounts`; stays in the user's wallet. */
|
|
79
|
+
refundAmounts: BN[];
|
|
80
|
+
/** BPT the program will mint for this basket at the synced state. */
|
|
81
|
+
bptOut: BN;
|
|
82
|
+
/** `bptOut` after the quoted slippage; pass as `minimumBptAmount`. */
|
|
83
|
+
minimumBptAmount: BN;
|
|
84
|
+
/** Index of the token that limits the basket (smallest amount/balance). */
|
|
85
|
+
limitingTokenIndex: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface RemoveLiquidityParams {
|
|
89
|
+
user: PublicKey;
|
|
90
|
+
bptAmount: BN;
|
|
91
|
+
minimumTokenAmounts?: BN[];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Single-token deposit ("zap"): deposit one token, the helper swaps it into
|
|
96
|
+
* the pool's proportions and joins on your behalf.
|
|
97
|
+
*
|
|
98
|
+
* Supported on pools of up to 10 tokens as of v5.1 (was 5 — the old cap was
|
|
99
|
+
* a heap-exhaustion limit, audit SF-3). Beyond 10 the program rejects with
|
|
100
|
+
* `PoolTooLargeForZap`.
|
|
101
|
+
*
|
|
102
|
+
* This deployed build does not account for Token-2022 transfer fees. The SDK
|
|
103
|
+
* rejects transfer-fee mints and other runtime-incompatible extensions before
|
|
104
|
+
* building a deposit. Plain Token-2022 mints and compatible extensions work.
|
|
105
|
+
*/
|
|
106
|
+
export interface SingleTokenDepositParams {
|
|
107
|
+
user: PublicKey;
|
|
108
|
+
tokenInIndex: number;
|
|
109
|
+
amountIn: BN;
|
|
110
|
+
/**
|
|
111
|
+
* Used only by the off-chain quote to derive `minimumBptAmount`. There is
|
|
112
|
+
* no per-call slippage argument on the instruction any more — the single
|
|
113
|
+
* `minimumBptAmount` floor bounds the entire zap, and per-leg swaps run
|
|
114
|
+
* with `min_out = 0` (which is what keeps the route correct under the
|
|
115
|
+
* path-dependent surge fee).
|
|
116
|
+
*/
|
|
117
|
+
slippageHundredthsBps?: number;
|
|
118
|
+
/**
|
|
119
|
+
* Required, must be > 0. The only slippage guard on the whole route:
|
|
120
|
+
* internal swaps + surge fees + the join.
|
|
121
|
+
*/
|
|
122
|
+
minimumBptAmount?: BN;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Quote includes the helperBalances supplied to the quote call, or assumes
|
|
126
|
+
* zero balances when omitted. Re-read helper ATAs and pool state before signing. */
|
|
127
|
+
export interface SingleTokenDepositQuote {
|
|
128
|
+
tokenInIndex: number;
|
|
129
|
+
amountIn: BN;
|
|
130
|
+
/** Per-token allocations (sum = amountIn). */
|
|
131
|
+
allocations: BN[];
|
|
132
|
+
/** Per-leg expected swap out. `0` for sidelined tokens. */
|
|
133
|
+
expectedOuts: BN[];
|
|
134
|
+
/** Per-leg min_out derived from slippage. */
|
|
135
|
+
minOuts: BN[];
|
|
136
|
+
/** Estimated actual pool credits after both helper and pool proportional cropping. */
|
|
137
|
+
depositedAmounts: BN[];
|
|
138
|
+
/** Helper-held excess returned to the user after add_liquidity. */
|
|
139
|
+
refundAmounts: BN[];
|
|
140
|
+
/** Projected new BPT from the complete swap-and-join sequence at quoted state/time. */
|
|
141
|
+
estimatedBpt: BN;
|
|
142
|
+
/** Indices of tokens excluded from the deposit (actBal == 0). */
|
|
143
|
+
sidelinedTokenIndices: number[];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface BuiltTx {
|
|
147
|
+
instructions: TransactionInstruction[];
|
|
148
|
+
/** Accounts that should sign (user is implicit). */
|
|
149
|
+
extraSigners?: PublicKey[];
|
|
150
|
+
/** Suggested CU limit — caller decides whether to prepend ComputeBudget ix. */
|
|
151
|
+
suggestedCuLimit: number;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface DeployPoolParams {
|
|
155
|
+
payer: PublicKey;
|
|
156
|
+
configKey: PublicKey;
|
|
157
|
+
poolId: BN;
|
|
158
|
+
/**
|
|
159
|
+
* Pool's token mints, in the same order as `weightsBps`/`virtualBalances`.
|
|
160
|
+
* There is no `tokens` field in the on-chain `initialize_cubic_pool` ix
|
|
161
|
+
* data — the program derives the token set solely from remaining_accounts
|
|
162
|
+
* (one mint per token). The SDK still requires this array so it can build
|
|
163
|
+
* that remaining_accounts list in the right order.
|
|
164
|
+
*/
|
|
165
|
+
tokens: PublicKey[];
|
|
166
|
+
weightsBps: number[];
|
|
167
|
+
virtualBalances: BN[];
|
|
168
|
+
swapFeeRate: number;
|
|
169
|
+
/** SPL Token program to use for the BPT mint (classic SPL Token recommended). */
|
|
170
|
+
bptTokenProgram?: PublicKey;
|
|
171
|
+
/**
|
|
172
|
+
* Optional creator-chosen Token-2022 banned-extensions bitmap. Omit
|
|
173
|
+
* (`undefined`/`null`) to inherit the config default. Set a bitmap to vet
|
|
174
|
+
* THIS pool's tokens against it and store it on the pool. `0` clears the
|
|
175
|
+
* configurable default; the hard floor and runtime restrictions still apply.
|
|
176
|
+
*
|
|
177
|
+
* ⚠ A permissive policy (un-banning PermanentDelegate / TransferHook /
|
|
178
|
+
* TransferFee) makes the pool drainable/abusable by the token issuer —
|
|
179
|
+
* surface this to the user before deploying.
|
|
180
|
+
*/
|
|
181
|
+
bannedExtensions?: BN | number | null;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ============================================================
|
|
185
|
+
// Range manager
|
|
186
|
+
// ============================================================
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* One compare-and-swap entry in a `range_manager_update`.
|
|
190
|
+
*
|
|
191
|
+
* ⚠ `expectedCurrent` was inserted **between** `index` and `newValue` in
|
|
192
|
+
* v5.1 (audit M-6). It is not optional padding and it is not appended at
|
|
193
|
+
* the end: the on-chain struct is `{ index: u8, expected_current: u64,
|
|
194
|
+
* new_value: u64 }` in exactly that order.
|
|
195
|
+
*/
|
|
196
|
+
export interface TokenChange {
|
|
197
|
+
/** Token index within the pool, `0 .. tokenCount-1`. */
|
|
198
|
+
index: number;
|
|
199
|
+
/**
|
|
200
|
+
* The value the caller believes is currently stored for this token —
|
|
201
|
+
* `virtualBalance` for a `vbChanges` entry, `weightBps` (as a BN) for a
|
|
202
|
+
* `weightChanges` entry.
|
|
203
|
+
*
|
|
204
|
+
* The program compares this against the live value and reverts the whole
|
|
205
|
+
* instruction with `RangeManagerStaleValue` (6061) on any mismatch. This
|
|
206
|
+
* makes every update a compare-and-swap: two managers racing, or a bot
|
|
207
|
+
* replaying a stale quote, can no longer clobber each other's writes.
|
|
208
|
+
*
|
|
209
|
+
* It must come from the same pool read that produced `newValue`. Do not
|
|
210
|
+
* synthesise it, and do not carry it across a re-read — on a stale
|
|
211
|
+
* failure, re-read the pool and recompute both fields together.
|
|
212
|
+
*/
|
|
213
|
+
expectedCurrent: BN;
|
|
214
|
+
/** The value to write if `expectedCurrent` still matches. */
|
|
215
|
+
newValue: BN;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export interface RangeManagerUpdateParams {
|
|
219
|
+
/** Must be the pool's configured `range_manager` and it must be enabled. */
|
|
220
|
+
authority: PublicKey;
|
|
221
|
+
/** Sparse virtual-balance changes. May be empty. */
|
|
222
|
+
vbChanges?: TokenChange[];
|
|
223
|
+
/**
|
|
224
|
+
* Sparse normalized-weight changes (basis points). May be empty. The
|
|
225
|
+
* resulting weight vector must still sum to 10_000.
|
|
226
|
+
*/
|
|
227
|
+
weightChanges?: TokenChange[];
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface SetRangeManagerParams {
|
|
231
|
+
/**
|
|
232
|
+
* Pool's governance config account. New in v5.1 (audit L-1) — it is
|
|
233
|
+
* PREPENDED before `pool` in the account list.
|
|
234
|
+
*/
|
|
235
|
+
config: PublicKey;
|
|
236
|
+
/** Pool admin, or config protocol admin for disable-only with the same manager. */
|
|
237
|
+
authority: PublicKey;
|
|
238
|
+
/** Pubkey allowed to call `range_manager_update`. */
|
|
239
|
+
newManager: PublicKey;
|
|
240
|
+
/** Gate flag; `false` blocks the manager even when the pubkey is set. */
|
|
241
|
+
enabled: boolean;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export interface SetRangeManagerConfigParams {
|
|
245
|
+
/** Pool-admin only. */
|
|
246
|
+
authority: PublicKey;
|
|
247
|
+
/** Max per-update virtual-balance change, `PERCENT_SCALE` (10_000 = 100%). */
|
|
248
|
+
maxVbChangePct: number;
|
|
249
|
+
/** Max per-update weight change, same units. */
|
|
250
|
+
maxWeightChangePct: number;
|
|
251
|
+
minUpdateIntervalSecs: number;
|
|
252
|
+
/**
|
|
253
|
+
* Absolute UPPER bound on `virtual_balance / actual_balance`, in basis
|
|
254
|
+
* points (10_000 = 1.0×). `0` disables the band. New in v5.1 (M-2/SF-20).
|
|
255
|
+
*
|
|
256
|
+
* The per-update percentage caps velocity, not distance — 5% steps
|
|
257
|
+
* compound to ~131× in 100 updates. This is the distance limit.
|
|
258
|
+
*/
|
|
259
|
+
maxLeverageBps: number;
|
|
260
|
+
/**
|
|
261
|
+
* Absolute LOWER bound on the same ratio, same units. `0` disables the
|
|
262
|
+
* floor. New in v5.1.
|
|
263
|
+
*/
|
|
264
|
+
minLeverageBps: number;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** Per-token sell-off policy, in pool order. Percent fields use 10,000 = 100%,
|
|
268
|
+
* except feeKinkPct, which is a whole percent (0 disables the kink).
|
|
269
|
+
*/
|
|
270
|
+
export interface SelloffParams {
|
|
271
|
+
maxSelloffPct: number;
|
|
272
|
+
periodLength: number;
|
|
273
|
+
feeThresholdPct: number;
|
|
274
|
+
feeSlopeLowPct: number;
|
|
275
|
+
feeSlopeHighPct: number;
|
|
276
|
+
feeSlopeMidPct: number;
|
|
277
|
+
feeKinkPct: number;
|
|
278
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import cubicPoolIdl from "../idl/cubic_pool.json";
|
|
2
|
+
import protocolAdminIdl from "../idl/protocol_admin.json";
|
|
3
|
+
import singleTokenLiquidityIdl from "../idl/single_token_liquidity.json";
|
|
4
|
+
import { SdkError, SdkErrorCode } from "../types/result";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Which on-chain program produced an error code.
|
|
8
|
+
*
|
|
9
|
+
* Anchor numbers every program's errors from 6000, so a bare custom-error
|
|
10
|
+
* code is ambiguous across the three Coffer programs — `6030` is
|
|
11
|
+
* `InvalidTokenProgram` in cubic-pool but `TokenExtensionsUnsupported` in
|
|
12
|
+
* single-token-liquidity. Pass this to {@link toSdkError} when you know
|
|
13
|
+
* which program the failing instruction belonged to; without it the
|
|
14
|
+
* cubic-pool table is used, which is the right default for swap / add /
|
|
15
|
+
* remove but WRONG for a zap or an admin call.
|
|
16
|
+
*/
|
|
17
|
+
export type CofferProgram = "cubicPool" | "singleTokenLiquidity" | "protocolAdmin";
|
|
18
|
+
|
|
19
|
+
const ANCHOR_NAME_TO_SDK: Record<string, SdkErrorCode> = {
|
|
20
|
+
InvalidTokenCount: "invalid_input",
|
|
21
|
+
InvalidTokenIndex: "invalid_input",
|
|
22
|
+
InvalidWeights: "invalid_input",
|
|
23
|
+
InvalidVirtualBalances: "invalid_input",
|
|
24
|
+
InsufficientLiquidity: "insufficient_funds",
|
|
25
|
+
SlippageExceeded: "slippage_exceeded",
|
|
26
|
+
InvalidAmounts: "invalid_input",
|
|
27
|
+
InsufficientBptOut: "slippage_exceeded",
|
|
28
|
+
InsufficientTokensOut: "slippage_exceeded",
|
|
29
|
+
FeeRateMaxExceeded: "invalid_input",
|
|
30
|
+
ProtocolFeeRateMaxExceeded: "invalid_input",
|
|
31
|
+
MathOverflow: "math_overflow",
|
|
32
|
+
MathUnderflow: "math_overflow",
|
|
33
|
+
DivisionByZero: "math_overflow",
|
|
34
|
+
TokenMintMismatch: "invalid_input",
|
|
35
|
+
InvalidTokenDecimals: "invalid_input",
|
|
36
|
+
AmountOutExceedsBalance: "invalid_input",
|
|
37
|
+
InvalidBptAmount: "invalid_input",
|
|
38
|
+
Unauthorized: "invalid_input",
|
|
39
|
+
InvalidMint: "invalid_input",
|
|
40
|
+
PoolDisabled: "pool_disabled",
|
|
41
|
+
SwapsDisabled: "swaps_disabled",
|
|
42
|
+
MaxSelloffExceeded: "selloff_window_full",
|
|
43
|
+
TokenInactive: "token_swaps_disabled",
|
|
44
|
+
PoolMustBeDisabled: "invalid_input",
|
|
45
|
+
ZeroAmount: "invalid_input",
|
|
46
|
+
ZeroFeeAmount: "invalid_input",
|
|
47
|
+
BannedExtension: "invalid_input",
|
|
48
|
+
TokenProgramMismatch: "invalid_input",
|
|
49
|
+
UserTokenAccountOwnerMismatch: "invalid_input",
|
|
50
|
+
InitialLiquidityTooSmall: "invalid_input",
|
|
51
|
+
InvalidTokenProgram: "invalid_input",
|
|
52
|
+
InvalidVault: "invalid_input",
|
|
53
|
+
InvalidSourceOwner: "invalid_input",
|
|
54
|
+
WouldBreakRentExempt: "invalid_input",
|
|
55
|
+
PoolAdminDisabled: "invalid_input",
|
|
56
|
+
ProtocolAdminUnset: "invalid_input",
|
|
57
|
+
NoPendingAdmin: "invalid_input",
|
|
58
|
+
NotPendingAdmin: "invalid_input",
|
|
59
|
+
InvalidPendingAdmin: "invalid_input",
|
|
60
|
+
ProtocolAdminNotTreasury: "invalid_input",
|
|
61
|
+
|
|
62
|
+
// ── cubic-pool 6055–6068, new in v5.1 ────────────────────────────────
|
|
63
|
+
/** Mint carries a Token-2022 extension this pool's policy forbids. */
|
|
64
|
+
UnsupportedExtension: "invalid_input",
|
|
65
|
+
/** Destination requires a memo — include the SPL Memo program account. */
|
|
66
|
+
MemoProgramMissing: "invalid_input",
|
|
67
|
+
TransferFeeCalculationMismatch: "invalid_input",
|
|
68
|
+
/** The whole deposit was eaten by the mint's transfer fee. */
|
|
69
|
+
AmountFullyConsumedByTransferFee: "invalid_input",
|
|
70
|
+
/** Only `pool.pool_admin` may make a pool's first (seed) deposit. */
|
|
71
|
+
SeedDepositNotPoolAdmin: "auth_failed",
|
|
72
|
+
StldTokenExtensionsUnsupported: "unsupported_pool_state",
|
|
73
|
+
/**
|
|
74
|
+
* Compare-and-swap guard on `range_manager_update` failed: the pool moved
|
|
75
|
+
* between the read and the write. The bot must re-read the pool and retry
|
|
76
|
+
* with fresh `expectedCurrent` values — it is a retryable race, not a
|
|
77
|
+
* permanent rejection.
|
|
78
|
+
*/
|
|
79
|
+
RangeManagerStaleValue: "invalid_input",
|
|
80
|
+
RangeManagerLeverageBandExceeded: "invalid_input",
|
|
81
|
+
RangeManagerOverrideMustDisable: "auth_failed",
|
|
82
|
+
/** An array argument's length != the pool's `token_count`. */
|
|
83
|
+
InvalidArrayLength: "invalid_input",
|
|
84
|
+
FirstDepositRequiresNonzero: "invalid_input",
|
|
85
|
+
TokenLivenessMismatch: "invalid_input",
|
|
86
|
+
/** Deposit too small to mint a single unit of BPT — increase the amount. */
|
|
87
|
+
DepositTooSmall: "invalid_input",
|
|
88
|
+
/** Pool holds no liquidity yet; the pool admin must seed it first. */
|
|
89
|
+
PoolNotSeeded: "unsupported_pool_state",
|
|
90
|
+
|
|
91
|
+
// ── protocol-admin ───────────────────────────────────────────────────
|
|
92
|
+
/** New admin cannot be the all-zero pubkey. */
|
|
93
|
+
InvalidAdmin: "invalid_input",
|
|
94
|
+
|
|
95
|
+
// ── single-token-liquidity 6030–6032, new in v5.1 ────────────────────
|
|
96
|
+
/** Zap route can't carry an armed transfer hook's extra accounts. */
|
|
97
|
+
TokenExtensionsUnsupported: "unsupported_pool_state",
|
|
98
|
+
InsufficientHelperSol: "insufficient_funds",
|
|
99
|
+
/** Pool exceeds `STLD_MAX_TOKENS` (10) — use `add_liquidity` instead. */
|
|
100
|
+
PoolTooLargeForZap: "unsupported_pool_state",
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
type AnchorIdlError = { code: number; name: string; msg: string };
|
|
104
|
+
type ErrorTable = Record<number, { code: SdkErrorCode; message: string; name: string }>;
|
|
105
|
+
|
|
106
|
+
function buildErrorTable(errors: AnchorIdlError[]): ErrorTable {
|
|
107
|
+
return Object.fromEntries(
|
|
108
|
+
errors.map((anchorError) => [
|
|
109
|
+
anchorError.code,
|
|
110
|
+
{
|
|
111
|
+
code: ANCHOR_NAME_TO_SDK[anchorError.name] ?? "invalid_input",
|
|
112
|
+
message: anchorError.msg,
|
|
113
|
+
name: anchorError.name,
|
|
114
|
+
},
|
|
115
|
+
])
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const ERROR_TABLES: Record<CofferProgram, ErrorTable> = {
|
|
120
|
+
cubicPool: buildErrorTable(cubicPoolIdl.errors as AnchorIdlError[]),
|
|
121
|
+
protocolAdmin: buildErrorTable(protocolAdminIdl.errors as AnchorIdlError[]),
|
|
122
|
+
singleTokenLiquidity: buildErrorTable(singleTokenLiquidityIdl.errors as AnchorIdlError[]),
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const CONTRACT_ERROR_MAP = ERROR_TABLES.cubicPool;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Convert a raw error (possibly from Anchor, web3.js, or fetch) into a
|
|
129
|
+
* cleanly-typed SdkError. Used by safeCall wrappers so callers always
|
|
130
|
+
* get structured errors, never exceptions.
|
|
131
|
+
*
|
|
132
|
+
* @param program Which Coffer program the failing instruction belonged to.
|
|
133
|
+
* Anchor numbers each program's errors from 6000 independently, so the
|
|
134
|
+
* same code means different things in different programs. Defaults to
|
|
135
|
+
* `"cubicPool"` (correct for swap / add / remove liquidity). Pass
|
|
136
|
+
* `"singleTokenLiquidity"` for zap failures and `"protocolAdmin"` for
|
|
137
|
+
* treasury-routed admin calls, or the message will be plausible and wrong.
|
|
138
|
+
*/
|
|
139
|
+
export function toSdkError(cause: unknown, program: CofferProgram = "cubicPool"): SdkError {
|
|
140
|
+
// Anchor-encoded program errors
|
|
141
|
+
const msg = extractMessage(cause);
|
|
142
|
+
const code = extractErrorCode(msg);
|
|
143
|
+
const table = ERROR_TABLES[program] ?? CONTRACT_ERROR_MAP;
|
|
144
|
+
if (code !== null && table[code]) {
|
|
145
|
+
return {
|
|
146
|
+
code: table[code].code,
|
|
147
|
+
humanMessage: table[code].message,
|
|
148
|
+
cause,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
// Common network strings
|
|
152
|
+
if (/timed? ?out|ETIMEDOUT/i.test(msg)) {
|
|
153
|
+
return { code: "rpc_timeout", humanMessage: "RPC timed out", cause };
|
|
154
|
+
}
|
|
155
|
+
if (/429|rate limit/i.test(msg)) {
|
|
156
|
+
return { code: "rpc_rate_limited", humanMessage: "RPC rate-limited - slow down", cause };
|
|
157
|
+
}
|
|
158
|
+
if (/fetch failed|ECONNREFUSED|ENOTFOUND|Proxy error|-32056|-32052|403/i.test(msg)) {
|
|
159
|
+
return { code: "rpc_unavailable", humanMessage: "RPC endpoint unreachable", cause };
|
|
160
|
+
}
|
|
161
|
+
if (/Account does not exist|account not found/i.test(msg)) {
|
|
162
|
+
return { code: "account_not_found", humanMessage: "Account does not exist on-chain", cause };
|
|
163
|
+
}
|
|
164
|
+
if (/insufficient funds/i.test(msg)) {
|
|
165
|
+
return { code: "insufficient_funds", humanMessage: "Insufficient funds for this operation", cause };
|
|
166
|
+
}
|
|
167
|
+
return { code: "unknown", humanMessage: msg || "Unknown error", cause };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function extractMessage(e: unknown): string {
|
|
171
|
+
if (!e) return "";
|
|
172
|
+
if (typeof e === "string") return e;
|
|
173
|
+
if (e instanceof Error) return e.message;
|
|
174
|
+
if (typeof e === "object" && e !== null && "message" in e) {
|
|
175
|
+
return String((e as { message?: string }).message ?? "");
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
return JSON.stringify(e);
|
|
179
|
+
} catch {
|
|
180
|
+
return String(e);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function extractErrorCode(msg: string): number | null {
|
|
185
|
+
// Anchor error format: "custom program error: 0x1774"
|
|
186
|
+
const hex = msg.match(/custom program error: 0x([0-9a-fA-F]+)/);
|
|
187
|
+
if (hex) return parseInt(hex[1], 16);
|
|
188
|
+
// Anchor SDK format: "Error Number: 6007"
|
|
189
|
+
const dec = msg.match(/Error Number:\s*(\d+)/);
|
|
190
|
+
if (dec) return parseInt(dec[1], 10);
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** @internal Exported for tests */
|
|
195
|
+
export function contractErrorMapForTests(program: CofferProgram = "cubicPool"): ErrorTable {
|
|
196
|
+
return ERROR_TABLES[program];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Look up a program error by its numeric code without needing an exception
|
|
201
|
+
* to parse. Returns `undefined` for codes the program does not define.
|
|
202
|
+
*/
|
|
203
|
+
export function describeProgramError(
|
|
204
|
+
code: number,
|
|
205
|
+
program: CofferProgram = "cubicPool"
|
|
206
|
+
): { name: string; message: string; sdkCode: SdkErrorCode } | undefined {
|
|
207
|
+
const hit = ERROR_TABLES[program]?.[code];
|
|
208
|
+
if (!hit) return undefined;
|
|
209
|
+
return { name: hit.name, message: hit.message, sdkCode: hit.code };
|
|
210
|
+
}
|