@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,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
|
+
}
|