@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.
Files changed (228) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +283 -0
  3. package/dist/clients/AdminClient.d.ts +194 -0
  4. package/dist/clients/AdminClient.d.ts.map +1 -0
  5. package/dist/clients/AdminClient.js +482 -0
  6. package/dist/clients/AdminClient.js.map +1 -0
  7. package/dist/clients/CofferBackendClient.d.ts +877 -0
  8. package/dist/clients/CofferBackendClient.d.ts.map +1 -0
  9. package/dist/clients/CofferBackendClient.js +536 -0
  10. package/dist/clients/CofferBackendClient.js.map +1 -0
  11. package/dist/clients/CubeBackendClient.d.ts +877 -0
  12. package/dist/clients/CubeBackendClient.d.ts.map +1 -0
  13. package/dist/clients/CubeBackendClient.js +536 -0
  14. package/dist/clients/CubeBackendClient.js.map +1 -0
  15. package/dist/clients/CubicPoolClient.d.ts +120 -0
  16. package/dist/clients/CubicPoolClient.d.ts.map +1 -0
  17. package/dist/clients/CubicPoolClient.js +687 -0
  18. package/dist/clients/CubicPoolClient.js.map +1 -0
  19. package/dist/clients/PoolFactoryClient.d.ts +53 -0
  20. package/dist/clients/PoolFactoryClient.d.ts.map +1 -0
  21. package/dist/clients/PoolFactoryClient.js +91 -0
  22. package/dist/clients/PoolFactoryClient.js.map +1 -0
  23. package/dist/clients/RpcClient.d.ts +49 -0
  24. package/dist/clients/RpcClient.d.ts.map +1 -0
  25. package/dist/clients/RpcClient.js +135 -0
  26. package/dist/clients/RpcClient.js.map +1 -0
  27. package/dist/clients/SingleTokenDepositClient.d.ts +67 -0
  28. package/dist/clients/SingleTokenDepositClient.d.ts.map +1 -0
  29. package/dist/clients/SingleTokenDepositClient.js +105 -0
  30. package/dist/clients/SingleTokenDepositClient.js.map +1 -0
  31. package/dist/clients/contract-instructions.d.ts +24 -0
  32. package/dist/clients/contract-instructions.d.ts.map +1 -0
  33. package/dist/clients/contract-instructions.js +130 -0
  34. package/dist/clients/contract-instructions.js.map +1 -0
  35. package/dist/clients/index.d.ts +10 -0
  36. package/dist/clients/index.d.ts.map +1 -0
  37. package/dist/clients/index.js +26 -0
  38. package/dist/clients/index.js.map +1 -0
  39. package/dist/clients/quote-math.d.ts +15 -0
  40. package/dist/clients/quote-math.d.ts.map +1 -0
  41. package/dist/clients/quote-math.js +98 -0
  42. package/dist/clients/quote-math.js.map +1 -0
  43. package/dist/clients/tx-builders.d.ts +231 -0
  44. package/dist/clients/tx-builders.d.ts.map +1 -0
  45. package/dist/clients/tx-builders.js +861 -0
  46. package/dist/clients/tx-builders.js.map +1 -0
  47. package/dist/clients/versioned.d.ts +34 -0
  48. package/dist/clients/versioned.d.ts.map +1 -0
  49. package/dist/clients/versioned.js +55 -0
  50. package/dist/clients/versioned.js.map +1 -0
  51. package/dist/config/index.d.ts +65 -0
  52. package/dist/config/index.d.ts.map +1 -0
  53. package/dist/config/index.js +75 -0
  54. package/dist/config/index.js.map +1 -0
  55. package/dist/config/networks.d.ts +12 -0
  56. package/dist/config/networks.d.ts.map +1 -0
  57. package/dist/config/networks.js +51 -0
  58. package/dist/config/networks.js.map +1 -0
  59. package/dist/config/tokens.d.ts +19 -0
  60. package/dist/config/tokens.d.ts.map +1 -0
  61. package/dist/config/tokens.js +43 -0
  62. package/dist/config/tokens.js.map +1 -0
  63. package/dist/idl/cubic_pool.json +4203 -0
  64. package/dist/idl/index.d.ts +1769 -0
  65. package/dist/idl/index.d.ts.map +1 -0
  66. package/dist/idl/index.js +18 -0
  67. package/dist/idl/index.js.map +1 -0
  68. package/dist/idl/protocol_admin.json +2615 -0
  69. package/dist/idl/single_token_liquidity.json +1121 -0
  70. package/dist/index.d.ts +75 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +206 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/math/cubicMath.d.ts +40 -0
  75. package/dist/math/cubicMath.d.ts.map +1 -0
  76. package/dist/math/cubicMath.js +82 -0
  77. package/dist/math/cubicMath.js.map +1 -0
  78. package/dist/math/fixedPoint.d.ts +19 -0
  79. package/dist/math/fixedPoint.d.ts.map +1 -0
  80. package/dist/math/fixedPoint.js +86 -0
  81. package/dist/math/fixedPoint.js.map +1 -0
  82. package/dist/math/index.d.ts +9 -0
  83. package/dist/math/index.d.ts.map +1 -0
  84. package/dist/math/index.js +30 -0
  85. package/dist/math/index.js.map +1 -0
  86. package/dist/math/logExp.d.ts +6 -0
  87. package/dist/math/logExp.d.ts.map +1 -0
  88. package/dist/math/logExp.js +68 -0
  89. package/dist/math/logExp.js.map +1 -0
  90. package/dist/math/lpLoss.d.ts +44 -0
  91. package/dist/math/lpLoss.d.ts.map +1 -0
  92. package/dist/math/lpLoss.js +103 -0
  93. package/dist/math/lpLoss.js.map +1 -0
  94. package/dist/math/maxSelloff.d.ts +164 -0
  95. package/dist/math/maxSelloff.d.ts.map +1 -0
  96. package/dist/math/maxSelloff.js +397 -0
  97. package/dist/math/maxSelloff.js.map +1 -0
  98. package/dist/math/singleToken.d.ts +54 -0
  99. package/dist/math/singleToken.d.ts.map +1 -0
  100. package/dist/math/singleToken.js +188 -0
  101. package/dist/math/singleToken.js.map +1 -0
  102. package/dist/math/slippage.d.ts +13 -0
  103. package/dist/math/slippage.d.ts.map +1 -0
  104. package/dist/math/slippage.js +44 -0
  105. package/dist/math/slippage.js.map +1 -0
  106. package/dist/math/surgeFee.d.ts +24 -0
  107. package/dist/math/surgeFee.d.ts.map +1 -0
  108. package/dist/math/surgeFee.js +85 -0
  109. package/dist/math/surgeFee.js.map +1 -0
  110. package/dist/math/weightedMath.d.ts +20 -0
  111. package/dist/math/weightedMath.d.ts.map +1 -0
  112. package/dist/math/weightedMath.js +66 -0
  113. package/dist/math/weightedMath.js.map +1 -0
  114. package/dist/parsers/borsh.d.ts +28 -0
  115. package/dist/parsers/borsh.d.ts.map +1 -0
  116. package/dist/parsers/borsh.js +104 -0
  117. package/dist/parsers/borsh.js.map +1 -0
  118. package/dist/parsers/contracts.d.ts +26 -0
  119. package/dist/parsers/contracts.d.ts.map +1 -0
  120. package/dist/parsers/contracts.js +62 -0
  121. package/dist/parsers/contracts.js.map +1 -0
  122. package/dist/parsers/events.d.ts +3 -0
  123. package/dist/parsers/events.d.ts.map +1 -0
  124. package/dist/parsers/events.js +281 -0
  125. package/dist/parsers/events.js.map +1 -0
  126. package/dist/parsers/index.d.ts +6 -0
  127. package/dist/parsers/index.d.ts.map +1 -0
  128. package/dist/parsers/index.js +22 -0
  129. package/dist/parsers/index.js.map +1 -0
  130. package/dist/parsers/mintAccount.d.ts +24 -0
  131. package/dist/parsers/mintAccount.d.ts.map +1 -0
  132. package/dist/parsers/mintAccount.js +27 -0
  133. package/dist/parsers/mintAccount.js.map +1 -0
  134. package/dist/parsers/poolAccount.d.ts +141 -0
  135. package/dist/parsers/poolAccount.d.ts.map +1 -0
  136. package/dist/parsers/poolAccount.js +224 -0
  137. package/dist/parsers/poolAccount.js.map +1 -0
  138. package/dist/types/contracts.d.ts +1340 -0
  139. package/dist/types/contracts.d.ts.map +1 -0
  140. package/dist/types/contracts.js +3 -0
  141. package/dist/types/contracts.js.map +1 -0
  142. package/dist/types/events.d.ts +172 -0
  143. package/dist/types/events.d.ts.map +1 -0
  144. package/dist/types/events.js +3 -0
  145. package/dist/types/events.js.map +1 -0
  146. package/dist/types/index.d.ts +6 -0
  147. package/dist/types/index.d.ts.map +1 -0
  148. package/dist/types/index.js +22 -0
  149. package/dist/types/index.js.map +1 -0
  150. package/dist/types/pool.d.ts +149 -0
  151. package/dist/types/pool.d.ts.map +1 -0
  152. package/dist/types/pool.js +3 -0
  153. package/dist/types/pool.js.map +1 -0
  154. package/dist/types/result.d.ts +24 -0
  155. package/dist/types/result.d.ts.map +1 -0
  156. package/dist/types/result.js +11 -0
  157. package/dist/types/result.js.map +1 -0
  158. package/dist/types/tx.d.ts +261 -0
  159. package/dist/types/tx.d.ts.map +1 -0
  160. package/dist/types/tx.js +3 -0
  161. package/dist/types/tx.js.map +1 -0
  162. package/dist/utils/errors.d.ts +44 -0
  163. package/dist/utils/errors.d.ts.map +1 -0
  164. package/dist/utils/errors.js +192 -0
  165. package/dist/utils/errors.js.map +1 -0
  166. package/dist/utils/extensions.d.ts +98 -0
  167. package/dist/utils/extensions.d.ts.map +1 -0
  168. package/dist/utils/extensions.js +187 -0
  169. package/dist/utils/extensions.js.map +1 -0
  170. package/dist/utils/index.d.ts +5 -0
  171. package/dist/utils/index.d.ts.map +1 -0
  172. package/dist/utils/index.js +21 -0
  173. package/dist/utils/index.js.map +1 -0
  174. package/dist/utils/pda.d.ts +8 -0
  175. package/dist/utils/pda.d.ts.map +1 -0
  176. package/dist/utils/pda.js +27 -0
  177. package/dist/utils/pda.js.map +1 -0
  178. package/dist/utils/retry.d.ts +22 -0
  179. package/dist/utils/retry.d.ts.map +1 -0
  180. package/dist/utils/retry.js +62 -0
  181. package/dist/utils/retry.js.map +1 -0
  182. package/package.json +54 -0
  183. package/src/clients/AdminClient.ts +608 -0
  184. package/src/clients/CofferBackendClient.ts +1413 -0
  185. package/src/clients/CubicPoolClient.ts +719 -0
  186. package/src/clients/PoolFactoryClient.ts +110 -0
  187. package/src/clients/RpcClient.ts +195 -0
  188. package/src/clients/SingleTokenDepositClient.ts +143 -0
  189. package/src/clients/contract-instructions.ts +115 -0
  190. package/src/clients/index.ts +9 -0
  191. package/src/clients/quote-math.ts +81 -0
  192. package/src/clients/tx-builders.ts +1096 -0
  193. package/src/clients/versioned.ts +80 -0
  194. package/src/config/index.ts +111 -0
  195. package/src/config/networks.ts +71 -0
  196. package/src/config/tokens.ts +52 -0
  197. package/src/idl/cubic_pool.json +4203 -0
  198. package/src/idl/index.ts +13 -0
  199. package/src/idl/protocol_admin.json +2615 -0
  200. package/src/idl/single_token_liquidity.json +1121 -0
  201. package/src/index.ts +262 -0
  202. package/src/math/cubicMath.ts +92 -0
  203. package/src/math/fixedPoint.ts +71 -0
  204. package/src/math/index.ts +13 -0
  205. package/src/math/logExp.ts +61 -0
  206. package/src/math/lpLoss.ts +160 -0
  207. package/src/math/maxSelloff.ts +564 -0
  208. package/src/math/singleToken.ts +251 -0
  209. package/src/math/slippage.ts +38 -0
  210. package/src/math/surgeFee.ts +101 -0
  211. package/src/math/weightedMath.ts +64 -0
  212. package/src/parsers/borsh.ts +106 -0
  213. package/src/parsers/contracts.ts +64 -0
  214. package/src/parsers/events.ts +275 -0
  215. package/src/parsers/index.ts +5 -0
  216. package/src/parsers/mintAccount.ts +44 -0
  217. package/src/parsers/poolAccount.ts +372 -0
  218. package/src/types/contracts.ts +238 -0
  219. package/src/types/events.ts +198 -0
  220. package/src/types/index.ts +5 -0
  221. package/src/types/pool.ts +147 -0
  222. package/src/types/result.ts +51 -0
  223. package/src/types/tx.ts +278 -0
  224. package/src/utils/errors.ts +210 -0
  225. package/src/utils/extensions.ts +196 -0
  226. package/src/utils/index.ts +4 -0
  227. package/src/utils/pda.ts +58 -0
  228. package/src/utils/retry.ts +85 -0
@@ -0,0 +1,608 @@
1
+ import * as anchor from "@coral-xyz/anchor";
2
+ import { Program } from "@coral-xyz/anchor";
3
+ import {
4
+ AccountMeta,
5
+ AddressLookupTableProgram,
6
+ SYSVAR_CLOCK_PUBKEY,
7
+ SYSVAR_RENT_PUBKEY,
8
+ Connection,
9
+ PublicKey,
10
+ SystemProgram,
11
+ } from "@solana/web3.js";
12
+ import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
13
+ import BN from "bn.js";
14
+ import { CofferConfig } from "../config";
15
+ import { PROTOCOL_ADMIN_IDL } from "../idl";
16
+ import { buildContractInstruction } from "./contract-instructions";
17
+ import { deriveAltAddress } from "./tx-builders";
18
+ import { deriveTreasuryPda } from "../utils/pda";
19
+
20
+ /** Upstream BPF upgradeable loader; ProgramData PDA = findPda([programId]). */
21
+ export const BPF_LOADER_UPGRADEABLE_PROGRAM_ID = new PublicKey(
22
+ "BPFLoaderUpgradeab1e11111111111111111111111",
23
+ );
24
+
25
+ /**
26
+ * AdminClient — wraps `protocol_admin` with treasury-routed admin
27
+ * operations.
28
+ *
29
+ * The cubic_pool program enforces that every admin instruction must be
30
+ * signed by the Treasury PDA (`seeds = [b"treasury"]`, owned by
31
+ * protocol_admin). This client builds the canonical flow:
32
+ *
33
+ * admin wallet
34
+ * → protocol_admin.<wrapper> (treasury.admin == signer)
35
+ * → CPI cubic_pool.<admin_ix> (signer == TREASURY_PDA)
36
+ *
37
+ * Direct calls into cubic_pool admin instructions will fail on-chain.
38
+ *
39
+ * Instruction methods return a `TransactionInstruction` (or a Promise of it). Compose into a tx
40
+ * with `@solana/web3.js` and sign with the admin wallet.
41
+ *
42
+ * The deployed audit-fixes-excluded-SF contract allows the supervisor to
43
+ * freeze AND unfreeze pools and to deactivate AND reactivate tokens. Other
44
+ * administrative operations require treasury.admin. This is not a freeze-only
45
+ * supervisor model.
46
+
47
+ */
48
+ export class AdminClient {
49
+ readonly program: Program;
50
+ readonly config: CofferConfig;
51
+ readonly cubicPoolProgramId: PublicKey;
52
+ readonly stldProgramId: PublicKey;
53
+ readonly treasuryPda: PublicKey;
54
+
55
+ constructor(opts: { config: CofferConfig; provider: anchor.AnchorProvider }) {
56
+ const { config, provider } = opts;
57
+ this.config = config;
58
+ const idl = JSON.parse(JSON.stringify(PROTOCOL_ADMIN_IDL)) as any;
59
+ idl.address = config.programs.protocolAdmin.toString();
60
+ this.program = new Program(idl, provider) as any;
61
+ this.cubicPoolProgramId = config.programs.cubicPool;
62
+ this.stldProgramId = config.programs.singleTokenLiquidity;
63
+ [this.treasuryPda] = deriveTreasuryPda(config.programs.protocolAdmin);
64
+ }
65
+
66
+ /**
67
+ * ProgramData PDA of the protocol-admin program itself, under the
68
+ * upgradeable BPF loader. `initialize` is gated on it (audit L-5): only
69
+ * the key that can upgrade the program may bootstrap its Treasury.
70
+ */
71
+ programDataPda(): PublicKey {
72
+ const [programData] = PublicKey.findProgramAddressSync(
73
+ [this.program.programId.toBuffer()],
74
+ BPF_LOADER_UPGRADEABLE_PROGRAM_ID,
75
+ );
76
+ return programData;
77
+ }
78
+
79
+ /**
80
+ * Idempotent treasury init. Returns true if a new treasury was created.
81
+ * `admin` becomes the initial `treasury.admin`.
82
+ *
83
+ * ⚠ v5.1 (audit L-5) added the `program_data` account: the signer must be
84
+ * the protocol-admin program's current upgrade authority, otherwise this
85
+ * reverts. `admin` may not be the all-zero pubkey (`InvalidAdmin`, 6009).
86
+ */
87
+ async initializeTreasuryIfMissing(connection: Connection, admin: PublicKey, payer: PublicKey = admin): Promise<boolean> {
88
+ const info = await connection.getAccountInfo(this.treasuryPda);
89
+ if (info) return false;
90
+ if (admin.equals(PublicKey.default)) {
91
+ throw new Error("AdminClient: admin cannot be the default (all-zero) pubkey");
92
+ }
93
+ await (this.program.methods as any)
94
+ .initialize(admin)
95
+ .accounts({
96
+ treasury: this.treasuryPda,
97
+ payer,
98
+ programData: this.programDataPda(),
99
+ systemProgram: SystemProgram.programId,
100
+ })
101
+ .rpc();
102
+ return true;
103
+ }
104
+
105
+ // ── Admin lifecycle ──────────────────────────────────────────────────────
106
+
107
+ initiateAdminTransferIx(admin: PublicKey, newAdmin: PublicKey) {
108
+ return (this.program.methods as any)
109
+ .initiateAdminTransfer(newAdmin)
110
+ .accounts({ treasury: this.treasuryPda, admin })
111
+ .instruction();
112
+ }
113
+
114
+ acceptAdminTransferIx(newAdmin: PublicKey) {
115
+ return (this.program.methods as any)
116
+ .acceptAdminTransfer()
117
+ .accounts({ treasury: this.treasuryPda, newAdmin })
118
+ .instruction();
119
+ }
120
+
121
+ cancelAdminTransferIx(admin: PublicKey) {
122
+ return (this.program.methods as any)
123
+ .cancelAdminTransfer()
124
+ .accounts({ treasury: this.treasuryPda, admin })
125
+ .instruction();
126
+ }
127
+
128
+ // ── Treasury vault management ────────────────────────────────────────────
129
+
130
+ registerTokenIx(admin: PublicKey, mint: PublicKey, tokenProgram = TOKEN_PROGRAM_ID) {
131
+ if (!tokenProgram.equals(TOKEN_PROGRAM_ID)) throw new Error("Treasury vaults only support classic SPL Token in this deployment");
132
+ const [vault] = PublicKey.findProgramAddressSync(
133
+ [Buffer.from("vault"), mint.toBuffer()],
134
+ this.program.programId,
135
+ );
136
+ return (this.program.methods as any)
137
+ .registerToken()
138
+ .accounts({
139
+ treasury: this.treasuryPda,
140
+ mint,
141
+ vault,
142
+ admin,
143
+ tokenProgram,
144
+ systemProgram: SystemProgram.programId,
145
+ })
146
+ .instruction();
147
+ }
148
+
149
+ /**
150
+ * Withdraw from a registered treasury vault.
151
+ *
152
+ * Treasury vaults use classic SPL Token in this deployed build. The mint
153
+ * argument derives the vault PDA; it is not an account in the instruction.
154
+ */
155
+ withdrawIx(
156
+ admin: PublicKey,
157
+ mint: PublicKey,
158
+ recipient: PublicKey,
159
+ amount: BN,
160
+ tokenProgram = TOKEN_PROGRAM_ID,
161
+ ) {
162
+ if (!tokenProgram.equals(TOKEN_PROGRAM_ID)) throw new Error("Treasury vaults only support classic SPL Token in this deployment");
163
+ const [vault] = PublicKey.findProgramAddressSync(
164
+ [Buffer.from("vault"), mint.toBuffer()],
165
+ this.program.programId,
166
+ );
167
+ return (this.program.methods as any)
168
+ .withdraw(amount)
169
+ .accounts({
170
+ treasury: this.treasuryPda,
171
+ vault,
172
+ recipient,
173
+ admin,
174
+ tokenProgram,
175
+ })
176
+ .instruction();
177
+ }
178
+
179
+ // ── Program upgrade authority ────────────────────────────────────────────
180
+
181
+ /**
182
+ * Hand the upgrade authority for `program` to `newAuthority`.
183
+ *
184
+ * ⚠ v5.1 (audit M-3) removed the `new_authority` ARGUMENT and made it an
185
+ * ACCOUNT that must **co-sign**: the loader's `SetAuthorityChecked` is
186
+ * used so a mistyped destination cannot take the authority
187
+ * irrecoverably. The returned instruction therefore has two required
188
+ * signers — the current `admin` and `newAuthority`. Both must sign the
189
+ * transaction or it fails signature verification before it ever reaches
190
+ * the program.
191
+ */
192
+ transferUpgradeAuthorityIx(
193
+ admin: PublicKey,
194
+ program: PublicKey,
195
+ newAuthority: PublicKey,
196
+ ) {
197
+ const [programdata] = PublicKey.findProgramAddressSync(
198
+ [program.toBuffer()],
199
+ BPF_LOADER_UPGRADEABLE_PROGRAM_ID,
200
+ );
201
+ return (this.program.methods as any)
202
+ .transferUpgradeAuthority()
203
+ .accounts({
204
+ treasury: this.treasuryPda,
205
+ admin,
206
+ program,
207
+ programdata,
208
+ newAuthority,
209
+ bpfLoaderUpgradeable: BPF_LOADER_UPGRADEABLE_PROGRAM_ID,
210
+ })
211
+ .instruction();
212
+ }
213
+
214
+ /**
215
+ * Make `program` permanently non-upgradeable.
216
+ *
217
+ * ⚠ v5.1 (audit M-3) dropped `new_authority_info` and added `program`:
218
+ * the account list is `[treasury, admin, program, programdata,
219
+ * bpf_loader_upgradeable]`. This is irreversible.
220
+ */
221
+ freezePoolProgramIx(admin: PublicKey, program: PublicKey) {
222
+ const [programdata] = PublicKey.findProgramAddressSync(
223
+ [program.toBuffer()],
224
+ BPF_LOADER_UPGRADEABLE_PROGRAM_ID,
225
+ );
226
+ return (this.program.methods as any)
227
+ .freezePoolProgram()
228
+ .accounts({
229
+ treasury: this.treasuryPda,
230
+ admin,
231
+ program,
232
+ programdata,
233
+ bpfLoaderUpgradeable: BPF_LOADER_UPGRADEABLE_PROGRAM_ID,
234
+ })
235
+ .instruction();
236
+ }
237
+
238
+ // ── Pool config / pool admin (treasury-routed) ───────────────────────────
239
+
240
+ poolInitializeConfigIx(admin: PublicKey, config: PublicKey, defaultProtocolFeeRate: number) {
241
+ return (this.program.methods as any)
242
+ .poolInitializeConfig(defaultProtocolFeeRate)
243
+ .accounts({
244
+ treasury: this.treasuryPda,
245
+ admin,
246
+ config,
247
+ cubicPoolProgram: this.cubicPoolProgramId,
248
+ systemProgram: SystemProgram.programId,
249
+ })
250
+ .instruction();
251
+ }
252
+
253
+ // setSwapFeeRate has been removed from the protocol-admin wrapper —
254
+ // it's a level-1 (pool-admin) instruction, signed directly by the
255
+ // wallet stored in `pool.pool_admin`. Use buildSetSwapFeeRateIx instead.
256
+
257
+ setProtocolFeeRateIx(admin: PublicKey, config: PublicKey, pool: PublicKey, protocolFeeRate: number) {
258
+ return (this.program.methods as any)
259
+ .poolSetProtocolFeeRate(protocolFeeRate)
260
+ .accounts({ ...this.poolAdminAccounts(admin, config, pool) })
261
+ .instruction();
262
+ }
263
+
264
+ setPoolEnabledIx(admin: PublicKey, config: PublicKey, pool: PublicKey, enabled: boolean) {
265
+ return (this.program.methods as any)
266
+ .poolSetPoolEnabled(enabled)
267
+ .accounts({ ...this.poolAdminAccounts(admin, config, pool) })
268
+ .instruction();
269
+ }
270
+
271
+ setSwapsEnabledIx(admin: PublicKey, config: PublicKey, pool: PublicKey, enabled: boolean) {
272
+ return (this.program.methods as any)
273
+ .poolSetSwapsEnabled(enabled)
274
+ .accounts({ ...this.poolAdminAccounts(admin, config, pool) })
275
+ .instruction();
276
+ }
277
+
278
+ /**
279
+ * Update a config's Token-2022 extension policy.
280
+ *
281
+ * ⚠ v5.1 (audit H-5) added a second REQUIRED argument,
282
+ * `hardBannedExtensions`. Two distinct bitmaps:
283
+ *
284
+ * - `banned` — the config's default policy, inherited by new pools that
285
+ * do not pass their own override. A pool creator may override it in
286
+ * either direction.
287
+ * - `hardBanned` — the protocol floor. It is OR-ed into every pool's
288
+ * effective bitmap at creation and a creator override can never clear
289
+ * it. This is what keeps `PermanentDelegate` / `TransferHook` mints out
290
+ * of vault custody regardless of what a pool creator chooses.
291
+ *
292
+ * Loosening `hardBanned` is a protocol-wide safety decision, not a
293
+ * routine config tweak.
294
+ */
295
+ setBannedExtensionsIx(
296
+ admin: PublicKey,
297
+ config: PublicKey,
298
+ banned: BN,
299
+ hardBanned: BN,
300
+ ) {
301
+ if (hardBanned === undefined) {
302
+ throw new Error(
303
+ "AdminClient.setBannedExtensionsIx: hardBanned is required as of v5.1. " +
304
+ "Pass the config's current hard_banned_extensions to leave the floor unchanged.",
305
+ );
306
+ }
307
+ return (this.program.methods as any)
308
+ .poolSetBannedExtensions(banned, hardBanned)
309
+ .accounts({
310
+ treasury: this.treasuryPda,
311
+ admin,
312
+ config,
313
+ cubicPoolProgram: this.cubicPoolProgramId,
314
+ })
315
+ .instruction();
316
+ }
317
+
318
+ /**
319
+ * Migrate a pool account from the v4 storage layout to v5.
320
+ *
321
+ * ⚠ v5.1 (audit H-7) added `reactivateTokens` and this instruction is no
322
+ * longer a no-op — it mutates pool state.
323
+ *
324
+ * @param reactivateTokens Pass `true` ONLY on the one-shot v4 → v5 pass.
325
+ * On any later call `true` silently re-opens every token that was
326
+ * deliberately disabled via `set_token_active`, undoing a circuit
327
+ * breaker. Default is `false` for that reason.
328
+ */
329
+ migratePoolToV5Ix(
330
+ admin: PublicKey,
331
+ config: PublicKey,
332
+ pool: PublicKey,
333
+ reactivateTokens = false,
334
+ ) {
335
+ return (this.program.methods as any)
336
+ .poolMigrateToV5(reactivateTokens)
337
+ .accounts({
338
+ treasury: this.treasuryPda,
339
+ admin,
340
+ pool,
341
+ config,
342
+ systemProgram: SystemProgram.programId,
343
+ cubicPoolProgram: this.cubicPoolProgramId,
344
+ })
345
+ .instruction();
346
+ }
347
+
348
+ /**
349
+ * Drain lamports from a single-token-liquidity helper PDA.
350
+ *
351
+ * ⚠ v5.1 (audit L-8 / SF-12) added the `pool` and `system_program`
352
+ * accounts. `pool` is not merely a seed source: the program checks it
353
+ * belongs to `config`, closing the hole where the admin of one config
354
+ * could drain a helper governed by another.
355
+ */
356
+ stldWithdrawSolIx(
357
+ admin: PublicKey,
358
+ config: PublicKey,
359
+ pool: PublicKey,
360
+ source: PublicKey,
361
+ recipient: PublicKey,
362
+ amount: BN,
363
+ ) {
364
+ return (this.program.methods as any)
365
+ .stldWithdrawSol(amount)
366
+ .accounts({
367
+ treasury: this.treasuryPda,
368
+ admin,
369
+ config,
370
+ pool,
371
+ source,
372
+ recipient,
373
+ systemProgram: SystemProgram.programId,
374
+ stldProgram: this.stldProgramId,
375
+ })
376
+ .instruction();
377
+ }
378
+
379
+ // ── Circuit breaker (admin OR supervisor) ────────────────────────────────
380
+
381
+ /**
382
+ * Batch-freeze pools. `pairs` are `[config, pool]` tuples passed via
383
+ * remaining_accounts.
384
+ *
385
+ * Authority: treasury.admin or treasury.supervisor. Both directions are
386
+ * permitted by the deployed audit-fixes-excluded-SF contract.
387
+ */
388
+ freezePoolsIx(authority: PublicKey, pairs: Array<{ config: PublicKey; pool: PublicKey }>) {
389
+ return (this.program.methods as any)
390
+ .freezePools()
391
+ .accounts({
392
+ treasury: this.treasuryPda,
393
+ authority,
394
+ cubicPoolProgram: this.cubicPoolProgramId,
395
+ })
396
+ .remainingAccounts(this.configPoolRemaining(pairs, /* poolWritable */ true))
397
+ .instruction();
398
+ }
399
+
400
+ /**
401
+ * Batch-unfreeze pools — mirror of {@link freezePoolsIx}.
402
+ *
403
+ * The deployed contract permits either treasury.admin or treasury.supervisor.
404
+ */
405
+ unfreezePoolsIx(admin: PublicKey, pairs: Array<{ config: PublicKey; pool: PublicKey }>) {
406
+ return (this.program.methods as any)
407
+ .unfreezePools()
408
+ .accounts({
409
+ treasury: this.treasuryPda,
410
+ authority: admin,
411
+ cubicPoolProgram: this.cubicPoolProgramId,
412
+ })
413
+ .remainingAccounts(this.configPoolRemaining(pairs, /* poolWritable */ true))
414
+ .instruction();
415
+ }
416
+
417
+ /**
418
+ * Flip a token's input kill switch on a pool.
419
+ *
420
+ * Both admin and supervisor may set either value in the deployed build.
421
+ */
422
+ setTokenActiveIx(
423
+ authority: PublicKey,
424
+ config: PublicKey,
425
+ pool: PublicKey,
426
+ tokenIndex: number,
427
+ isActive: boolean,
428
+ ) {
429
+ return (this.program.methods as any)
430
+ .poolSetTokenActive(tokenIndex, isActive)
431
+ .accounts({
432
+ treasury: this.treasuryPda,
433
+ authority,
434
+ config,
435
+ pool,
436
+ cubicPoolProgram: this.cubicPoolProgramId,
437
+ })
438
+ .instruction();
439
+ }
440
+
441
+ /**
442
+ * Set or revoke the supervisor pubkey. Admin only. Pass
443
+ * `PublicKey.default` to revoke.
444
+ *
445
+ * The supervisor may freeze/unfreeze pools and set token activity in either
446
+ * direction. Setting or revoking a supervisor remains admin-only.
447
+ */
448
+ setSupervisorIx(admin: PublicKey, newSupervisor: PublicKey) {
449
+ return (this.program.methods as any)
450
+ .setSupervisor(newSupervisor)
451
+ .accounts({
452
+ treasury: this.treasuryPda,
453
+ admin,
454
+ systemProgram: SystemProgram.programId,
455
+ })
456
+ .instruction();
457
+ }
458
+
459
+ /**
460
+ * Collects protocol fees from a pool to the supplied recipient ATAs.
461
+ *
462
+ * `vaults` / `recipients` / `tokenPrograms` must be aligned with
463
+ * `pool.token_mints` (one entry per token in pool order).
464
+ */
465
+ collectProtocolFeesIx(
466
+ admin: PublicKey,
467
+ config: PublicKey,
468
+ pool: PublicKey,
469
+ vaults: PublicKey[],
470
+ recipients: PublicKey[],
471
+ tokenPrograms: PublicKey[] = vaults.map(() => TOKEN_PROGRAM_ID),
472
+ ) {
473
+ const remaining: AccountMeta[] = this.tripleRemaining(vaults, recipients, tokenPrograms);
474
+ return (this.program.methods as any)
475
+ .poolCollectProtocolFees()
476
+ .accounts({ ...this.poolAdminAccounts(admin, config, pool) })
477
+ .remainingAccounts(remaining)
478
+ .instruction();
479
+ }
480
+
481
+ /**
482
+ * Emergency drain. Pool must be paused first. `amounts.length` must equal
483
+ * the pool's token_count; pass 0 to skip a token.
484
+ */
485
+ debugWithdrawLiquidityIx(
486
+ admin: PublicKey,
487
+ config: PublicKey,
488
+ pool: PublicKey,
489
+ amounts: BN[],
490
+ vaults: PublicKey[],
491
+ recipients: PublicKey[],
492
+ tokenPrograms: PublicKey[] = vaults.map(() => TOKEN_PROGRAM_ID),
493
+ ) {
494
+ const remaining: AccountMeta[] = this.tripleRemaining(vaults, recipients, tokenPrograms);
495
+ return (this.program.methods as any)
496
+ .poolDebugWithdrawLiquidity(amounts)
497
+ .accounts({ ...this.poolAdminAccounts(admin, config, pool) })
498
+ .remainingAccounts(remaining)
499
+ .instruction();
500
+ }
501
+
502
+ /** Build Treasury initialization without sending. Payer must be the current
503
+ * protocol-admin upgrade authority; the assigned admin may be a different key.
504
+ */
505
+ initializeTreasuryIx(payer: PublicKey, admin: PublicKey) {
506
+ if (admin.equals(PublicKey.default)) throw new Error("Admin cannot be the default pubkey");
507
+ return buildContractInstruction(this.config, "protocolAdmin", "initialize", { admin }, {
508
+ treasury: this.treasuryPda, payer, program_data: this.programDataPda(), system_program: SystemProgram.programId,
509
+ });
510
+ }
511
+
512
+ upgradePoolProgramIx(admin: PublicKey, program: PublicKey, buffer: PublicKey, spill: PublicKey) {
513
+ return buildContractInstruction(this.config, "protocolAdmin", "upgrade_pool_program", {}, {
514
+ treasury: this.treasuryPda, admin, programdata: this.deriveProgramData(program),
515
+ program_to_upgrade: program, buffer, spill, rent: SYSVAR_RENT_PUBKEY,
516
+ clock: SYSVAR_CLOCK_PUBKEY, bpf_loader_upgradeable: BPF_LOADER_UPGRADEABLE_PROGRAM_ID,
517
+ });
518
+ }
519
+
520
+ /** Closing a program disables it and returns its storage balance. */
521
+ closePoolProgramIx(admin: PublicKey, program: PublicKey, recipient: PublicKey) {
522
+ return buildContractInstruction(this.config, "protocolAdmin", "close_pool_program", {}, {
523
+ treasury: this.treasuryPda, admin, programdata: this.deriveProgramData(program),
524
+ program_to_close: program, recipient, bpf_loader_upgradeable: BPF_LOADER_UPGRADEABLE_PROGRAM_ID,
525
+ });
526
+ }
527
+
528
+ withdrawSolIx(admin: PublicKey, recipient: PublicKey, amount: BN) {
529
+ return buildContractInstruction(this.config, "protocolAdmin", "withdraw_sol", { amount }, { treasury: this.treasuryPda, admin, recipient });
530
+ }
531
+
532
+ poolWithdrawSolIx(admin: PublicKey, config: PublicKey, source: PublicKey, recipient: PublicKey, amount: BN) {
533
+ return buildContractInstruction(this.config, "protocolAdmin", "pool_withdraw_sol", { amount }, {
534
+ treasury: this.treasuryPda, admin, config, source, recipient, cubic_pool_program: this.cubicPoolProgramId,
535
+ });
536
+ }
537
+
538
+ poolInitializeAltIx(admin: PublicKey, config: PublicKey, pool: PublicKey, recentSlot: BN) {
539
+ return buildContractInstruction(this.config, "protocolAdmin", "pool_initialize_alt", { recent_slot: recentSlot }, {
540
+ treasury: this.treasuryPda, admin, pool, config,
541
+ lookup_table: deriveAltAddress(this.treasuryPda, recentSlot), system_program: SystemProgram.programId,
542
+ alt_program: AddressLookupTableProgram.programId, cubic_pool_program: this.cubicPoolProgramId,
543
+ });
544
+ }
545
+
546
+ poolInitiateProtocolAdminTransferIx(admin: PublicKey, config: PublicKey, newAdmin: PublicKey) {
547
+ return buildContractInstruction(this.config, "protocolAdmin", "pool_initiate_protocol_admin_transfer", { new_admin: newAdmin }, {
548
+ treasury: this.treasuryPda, admin, config, cubic_pool_program: this.cubicPoolProgramId,
549
+ });
550
+ }
551
+
552
+ poolAcceptProtocolAdminTransferIx(admin: PublicKey, config: PublicKey) {
553
+ return buildContractInstruction(this.config, "protocolAdmin", "pool_accept_protocol_admin_transfer", {}, {
554
+ treasury: this.treasuryPda, admin, config, cubic_pool_program: this.cubicPoolProgramId,
555
+ });
556
+ }
557
+
558
+ poolCancelProtocolAdminTransferIx(admin: PublicKey, config: PublicKey) {
559
+ return buildContractInstruction(this.config, "protocolAdmin", "pool_cancel_protocol_admin_transfer", {}, {
560
+ treasury: this.treasuryPda, admin, config, cubic_pool_program: this.cubicPoolProgramId,
561
+ });
562
+ }
563
+
564
+ private deriveProgramData(program: PublicKey): PublicKey {
565
+ return PublicKey.findProgramAddressSync([program.toBuffer()], BPF_LOADER_UPGRADEABLE_PROGRAM_ID)[0];
566
+ }
567
+
568
+ // ── Internals ────────────────────────────────────────────────────────────
569
+
570
+ private poolAdminAccounts(admin: PublicKey, config: PublicKey, pool: PublicKey) {
571
+ return {
572
+ treasury: this.treasuryPda,
573
+ admin,
574
+ config,
575
+ pool,
576
+ cubicPoolProgram: this.cubicPoolProgramId,
577
+ };
578
+ }
579
+
580
+ private configPoolRemaining(
581
+ pairs: Array<{ config: PublicKey; pool: PublicKey }>,
582
+ poolWritable: boolean,
583
+ ): AccountMeta[] {
584
+ const acc: AccountMeta[] = [];
585
+ for (const { config, pool } of pairs) {
586
+ acc.push({ pubkey: config, isSigner: false, isWritable: false });
587
+ acc.push({ pubkey: pool, isSigner: false, isWritable: poolWritable });
588
+ }
589
+ return acc;
590
+ }
591
+
592
+ private tripleRemaining(
593
+ vaults: PublicKey[],
594
+ recipients: PublicKey[],
595
+ tokenPrograms: PublicKey[],
596
+ ): AccountMeta[] {
597
+ if (vaults.length !== recipients.length || vaults.length !== tokenPrograms.length) {
598
+ throw new Error("AdminClient: vaults/recipients/tokenPrograms must be the same length");
599
+ }
600
+ const acc: AccountMeta[] = [];
601
+ for (let i = 0; i < vaults.length; i++) {
602
+ acc.push({ pubkey: vaults[i], isSigner: false, isWritable: true });
603
+ acc.push({ pubkey: recipients[i], isSigner: false, isWritable: true });
604
+ acc.push({ pubkey: tokenPrograms[i], isSigner: false, isWritable: false });
605
+ }
606
+ return acc;
607
+ }
608
+ }