@augustdigital/sdk 9.11.0 → 9.12.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 (38) hide show
  1. package/lib/adapters/solana/constants.d.ts +12 -4
  2. package/lib/adapters/solana/constants.js +8 -3
  3. package/lib/adapters/solana/getters.d.ts +5 -0
  4. package/lib/adapters/solana/getters.js +35 -1
  5. package/lib/adapters/solana/idl/vault-idl.d.ts +334 -7
  6. package/lib/adapters/solana/idl/vault-idl.js +600 -59
  7. package/lib/adapters/solana/idl/withdrawal-queue-idl.d.ts +790 -0
  8. package/lib/adapters/solana/idl/withdrawal-queue-idl.js +1868 -0
  9. package/lib/adapters/solana/index.d.ts +108 -10
  10. package/lib/adapters/solana/index.js +137 -12
  11. package/lib/adapters/solana/pricing.d.ts +11 -0
  12. package/lib/adapters/solana/pricing.js +24 -8
  13. package/lib/adapters/solana/queue.actions.d.ts +98 -0
  14. package/lib/adapters/solana/queue.actions.js +488 -0
  15. package/lib/adapters/solana/token-reads.d.ts +108 -0
  16. package/lib/adapters/solana/token-reads.js +145 -0
  17. package/lib/adapters/solana/types.d.ts +200 -1
  18. package/lib/adapters/solana/utils.d.ts +16 -0
  19. package/lib/adapters/solana/utils.js +41 -4
  20. package/lib/adapters/solana/vault.actions.d.ts +17 -0
  21. package/lib/adapters/solana/vault.actions.js +14 -125
  22. package/lib/adapters/solana/withdrawal-queue.d.ts +125 -0
  23. package/lib/adapters/solana/withdrawal-queue.js +301 -0
  24. package/lib/core/analytics/method-taxonomy.js +2 -0
  25. package/lib/core/analytics/version.d.ts +1 -1
  26. package/lib/core/analytics/version.js +1 -1
  27. package/lib/main.d.ts +16 -0
  28. package/lib/main.js +16 -0
  29. package/lib/modules/vaults/getters.d.ts +2 -2
  30. package/lib/modules/vaults/getters.js +103 -3
  31. package/lib/modules/vaults/main.d.ts +12 -0
  32. package/lib/modules/vaults/main.js +17 -1
  33. package/lib/modules/vaults/types.d.ts +14 -1
  34. package/lib/sdk.d.ts +2389 -1723
  35. package/lib/types/vaults.d.ts +47 -1
  36. package/lib/types/vaults.js +5 -0
  37. package/lib/types/webserver.d.ts +8 -0
  38. package/package.json +1 -1
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readPricingSnapshot = readPricingSnapshot;
4
+ exports.resolveUserTokenAccount = resolveUserTokenAccount;
5
+ /**
6
+ * Account reads shared by the Solana write handlers (`vault.actions.ts`,
7
+ * `queue.actions.ts`) and the withdrawal-queue readers.
8
+ *
9
+ * Internal: kept out of `vault.actions.ts` because `Solana.actions` is that
10
+ * whole module, so anything exported from it becomes public API.
11
+ */
12
+ const spl_token_1 = require("@solana/spl-token");
13
+ const core_1 = require("../../core");
14
+ const utils_1 = require("./utils");
15
+ /**
16
+ * The vault state and share-mint supply as of a **single slot**.
17
+ *
18
+ * Both figures price the quote, so they have to come from one snapshot. Read
19
+ * independently — even concurrently, as two RPC requests — a deposit or
20
+ * redemption landing in between combines a supply and an asset total that
21
+ * never coexisted, and the quote is wrong in whichever direction the
22
+ * interleaving fell. Seeing a 10% deposit's new assets against the old supply
23
+ * quotes ~10% high, and the floor then rejects a redemption whose share price
24
+ * never moved; the opposite ordering quotes low and silently weakens the
25
+ * protection. `getMultipleAccountsInfo` is served from one slot, so the pair
26
+ * is always coherent — and it costs one round trip instead of two.
27
+ *
28
+ * @param program - Anchor program, used only for its account coder; the
29
+ * provider it was built with is irrelevant, so no read-only program is needed.
30
+ * @param vaultStatePda - Vault state account to decode.
31
+ * @param shareMintAddr - Share mint whose supply and decimals are read.
32
+ * @param extraAccounts - Further accounts to read in the same call and slot,
33
+ * returned raw and in order (`null` for an absent one). Lets a caller that
34
+ * also needs, say, token accounts avoid a second round trip.
35
+ * @returns The decoded `VaultState`, the share mint's raw `supply`, its
36
+ * `decimals`, and `extraAccountInfos` — all from the same slot.
37
+ * @throws {@link AugustSDKError} when either account is absent, or is not the
38
+ * account type it should be.
39
+ */
40
+ async function readPricingSnapshot({ connection, program, vaultStatePda, shareMintAddr, extraAccounts = [], }) {
41
+ const [vaultStateInfo, shareMintInfo, ...extraAccountInfos] = await connection.getMultipleAccountsInfo([
42
+ vaultStatePda,
43
+ shareMintAddr,
44
+ ...extraAccounts,
45
+ ]);
46
+ if (!vaultStateInfo) {
47
+ throw new core_1.AugustSDKError('UNKNOWN', `Vault state account ${vaultStatePda.toBase58()} does not exist; it cannot be priced.`);
48
+ }
49
+ if (!shareMintInfo) {
50
+ throw new core_1.AugustSDKError('UNKNOWN', `Share mint ${shareMintAddr.toBase58()} does not exist; it cannot be priced.`);
51
+ }
52
+ // `vaultState`, not the IDL's own `VaultState`: `Program` runs the IDL
53
+ // through `convertIdlToCamelCase`, so its coder only answers to the
54
+ // camelCase name and the IDL spelling throws `Account not found`. (A coder
55
+ // built directly from the raw IDL behaves the opposite way — which is why
56
+ // this has to be checked against a real `Program`, as its test does.)
57
+ //
58
+ // Decoded by name rather than `decodeAny`, so a `vaultAddress` pointing at
59
+ // some other account of this program fails here instead of being decoded as
60
+ // whatever it happens to be.
61
+ let vaultStateData;
62
+ try {
63
+ vaultStateData = program.coder.accounts.decode('vaultState', vaultStateInfo.data);
64
+ }
65
+ catch (e) {
66
+ throw new core_1.AugustSDKError('UNKNOWN', `Account ${vaultStatePda.toBase58()} is not a vault state account for this program.`, { cause: e });
67
+ }
68
+ let mint;
69
+ try {
70
+ mint = (0, spl_token_1.unpackMint)(shareMintAddr, shareMintInfo, spl_token_1.TOKEN_PROGRAM_ID);
71
+ }
72
+ catch (e) {
73
+ throw new core_1.AugustSDKError('UNKNOWN', `Account ${shareMintAddr.toBase58()} is not an SPL Token mint.`, { cause: e });
74
+ }
75
+ return {
76
+ vaultStateData,
77
+ supply: mint.supply,
78
+ shareDecimals: mint.decimals,
79
+ extraAccountInfos,
80
+ };
81
+ }
82
+ /**
83
+ * Pick which token account to hand the vault program for a given mint, and
84
+ * describe how to create it when the user has none.
85
+ *
86
+ * The vault program constrains these accounts by `token::mint` +
87
+ * `token::authority` (not `associated_token::…`), so any account the signer
88
+ * owns qualifies. We therefore keep an existing account when there is one —
89
+ * that is where the user's balance already lives — and fall back to the
90
+ * associated token account otherwise.
91
+ *
92
+ * Two deliberate choices:
93
+ *
94
+ * - **The create is returned, not sent.** Prepended to the deposit/redeem via
95
+ * `.preInstructions()` it is atomic with the transfer, so there is no window
96
+ * in which the vault instruction can reference an account that has not
97
+ * landed. Sent as its own transaction — as this module used to — it raced
98
+ * its own confirmation. Observed in production (2026-08-11):
99
+ * a deposit failed with `Simulation failed … Logs: []` while the share-ATA
100
+ * create was still in flight, then succeeded 17s later on retry. The empty
101
+ * log array means the transaction never reached program execution, so there
102
+ * was nothing on-chain to debug from.
103
+ * - **Idempotent.** `createAssociatedTokenAccountIdempotentInstruction` is a
104
+ * no-op when the account already exists, so a concurrent create — another
105
+ * tab, a wallet's auto-provisioning — cannot turn into an
106
+ * `SystemError::AccountAlreadyInUse` ("already in use") failure between our
107
+ * read and our submit.
108
+ *
109
+ * Which account wins when several exist is decided by
110
+ * {@link selectRichestTokenAccount} — the same rule every balance *read* in
111
+ * this adapter uses, so the account a UI reports and the account a transfer
112
+ * names are never different accounts.
113
+ *
114
+ * Classic SPL Token only: the ATA is derived under `TOKEN_PROGRAM_ID`, matching
115
+ * the `tokenProgram` both handlers pass, even though the program's
116
+ * `TokenInterface` would also accept Token-2022.
117
+ *
118
+ * @param owner - Wallet that owns the account and pays rent for any creation.
119
+ * @throws AugustSDKError when a candidate account's balance cannot be read
120
+ * (propagated from the shared selector).
121
+ */
122
+ async function resolveUserTokenAccount({ connection, owner, mint, }) {
123
+ const existing = await connection.getParsedTokenAccountsByOwner(owner, {
124
+ mint,
125
+ });
126
+ const richest = (0, utils_1.selectRichestTokenAccount)(existing.value);
127
+ if (richest)
128
+ return {
129
+ address: richest.pubkey,
130
+ balance: richest.amount,
131
+ frozen: richest.frozen,
132
+ };
133
+ // Off-curve allowed: a multisig vault holds and signs as a PDA.
134
+ const ata = await (0, spl_token_1.getAssociatedTokenAddress)(mint, owner, true);
135
+ return {
136
+ address: ata,
137
+ balance: BigInt(0),
138
+ frozen: false,
139
+ createIx: (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(owner, // payer
140
+ ata, // associated token account
141
+ owner, // owner
142
+ mint),
143
+ };
144
+ }
145
+ //# sourceMappingURL=token-reads.js.map
@@ -1,4 +1,4 @@
1
- import type { AnchorProvider } from '@coral-xyz/anchor';
1
+ import type { AnchorProvider, BN } from '@coral-xyz/anchor';
2
2
  import type { Connection, PublicKey } from '@solana/web3.js';
3
3
  export type ISolanaRpcEndpoint = `https://${string}`;
4
4
  export type ISolanaNetwork = 'devnet' | 'mainnet-beta' | 'testnet' | 'localnet';
@@ -17,11 +17,129 @@ export interface ISolanaVaultState {
17
17
  withdrawalFee: number | null;
18
18
  localAum: number | null;
19
19
  deployedAum: number | null;
20
+ /**
21
+ * Virtual-share offset the program prices with (a power of ten). Absent on
22
+ * builds that predate it, and `0` on vaults created before it; read it
23
+ * through `resolveShareOffset`, which maps both to the default.
24
+ */
25
+ shareOffset?: BN | null;
20
26
  aumIncreaseLimit: number | null;
21
27
  aumDecreaseLimit: number | null;
22
28
  pdaBump: number[] | null;
23
29
  vaultVersion: number[] | null;
24
30
  paused: boolean | null;
31
+ /**
32
+ * The only key the vault accepts a redeem from, or the default (all-zero)
33
+ * public key when no withdrawal queue is attached. When set it is this
34
+ * vault's withdrawal-queue PDA: a direct holder redeem is refused with
35
+ * `WithdrawalQueueRequired` (6021), and holders exit through the queue
36
+ * instead. Vaults created before the queue existed read the default key.
37
+ */
38
+ withdrawalQueueAuthority: PublicKey | null;
39
+ /**
40
+ * Number of registered operator subaccounts. Non-zero means operator
41
+ * transfers must go to a registered subaccount; `0` on vaults created before
42
+ * subaccounts existed, and on every mainnet vault today.
43
+ */
44
+ subaccountCount: BN | null;
45
+ /**
46
+ * Raw deposit-mint units taken out to subaccounts and not yet returned,
47
+ * across all of them. Distinct from `deployedAum`, which the operator marks
48
+ * without moving tokens. Informational: nothing on-chain trusts it.
49
+ */
50
+ deployedPrincipal: BN | null;
51
+ }
52
+ /**
53
+ * A vault's withdrawal queue account (`WithdrawalQueue` in the
54
+ * august_withdrawal_queue program), as Anchor decodes it.
55
+ *
56
+ * One per vault, at the PDA `["withdrawal_queue", vault_state]`. Integer fields
57
+ * are `BN`s in raw on-chain units; times are in seconds.
58
+ */
59
+ export interface ISolanaWithdrawalQueueState {
60
+ /** The vault this queue serves. */
61
+ vaultState: PublicKey;
62
+ /** The vault's deposit mint, copied at initialization. */
63
+ depositMint: PublicKey;
64
+ /** The vault's share mint, copied at initialization. */
65
+ shareMint: PublicKey;
66
+ /** The queue's share escrow: holds every pending request's shares. */
67
+ escrowShares: PublicKey;
68
+ /**
69
+ * The queue's deposit-mint escrow. Transit only: a payout passes through it
70
+ * within the finalizing transaction, so it normally holds nothing.
71
+ */
72
+ escrowAssets: PublicKey;
73
+ /**
74
+ * Seconds between a request and its eligibility. Stamped on each request when
75
+ * it is created, so a change applies to later requests only.
76
+ */
77
+ cooldownSeconds: BN;
78
+ /**
79
+ * Seconds after scheduled eligibility that a request may still be finalized,
80
+ * or `0` for no expiry. Stamped on each request when it is created.
81
+ */
82
+ fulfillmentWindowSeconds: BN;
83
+ /** Queue-wide counter; the last value stamped on a request (the first is 1). */
84
+ sequence: BN;
85
+ /** Number of live (unfinalized, uncancelled) requests. */
86
+ pendingRequests: BN;
87
+ /** Raw shares escrowed across all live requests. */
88
+ pendingShares: BN;
89
+ /** Canonical bump of the queue PDA. */
90
+ bump: number;
91
+ }
92
+ /**
93
+ * One withdrawal request (`WithdrawalRequest` in the august_withdrawal_queue
94
+ * program), as Anchor decodes it.
95
+ *
96
+ * At the PDA `["withdrawal_request", queue, owner, request_id as u64 LE]`. The
97
+ * account exists while the request is pending and is closed when it is
98
+ * finalized or cancelled. Integer fields are `BN`s; times are Unix seconds.
99
+ */
100
+ export interface ISolanaWithdrawalRequestState {
101
+ /** The queue holding this request's shares. */
102
+ queue: PublicKey;
103
+ /** Who requested; may cancel, and may always finalize. */
104
+ owner: PublicKey;
105
+ /** Deposit-mint token account the payout goes to. */
106
+ recipientTokenAccount: PublicKey;
107
+ /**
108
+ * Who may finalize besides the owner, or the default (all-zero) public key
109
+ * for anyone.
110
+ */
111
+ finalizer: PublicKey;
112
+ /** Raw shares escrowed for this request. */
113
+ shares: BN;
114
+ /** Owner-chosen id, unique per owner while the request exists. */
115
+ requestId: BN;
116
+ /**
117
+ * Queue-wide stamp given at creation. Instructions that target the request
118
+ * pass it as `expected_sequence`, so a delayed call cannot land on a
119
+ * recreated request with the same id.
120
+ */
121
+ sequence: BN;
122
+ /** When the request was created. */
123
+ requestedAt: BN;
124
+ /** `requestedAt + cooldown` at creation. Never changes. */
125
+ scheduledEligibleAt: BN;
126
+ /**
127
+ * When finalization may begin. Equals `scheduledEligibleAt` unless an admin
128
+ * or operator expedited the request, which only ever moves it earlier.
129
+ */
130
+ eligibleAt: BN;
131
+ /**
132
+ * When the request stops being finalizable (the instant itself counts as
133
+ * expired), or `0` for never. An expired request can only be cancelled.
134
+ */
135
+ expiresAt: BN;
136
+ /** Bump of the request PDA. */
137
+ bump: number;
138
+ /**
139
+ * The owner's floor on the net payout, in raw deposit-mint units; `0` for
140
+ * none. A claim that would pay less is refused with `PayoutBelowFloor`.
141
+ */
142
+ minAssetsOut: BN;
25
143
  }
26
144
  export interface ISolanaToken {
27
145
  address: string;
@@ -117,4 +235,85 @@ export interface ISolanaRedeemOptions {
117
235
  * silently dropped; with neither, the plain `redeem` is sent.
118
236
  */
119
237
  minAssetsOut?: bigint;
238
+ /**
239
+ * Claim this withdrawal request instead of redeeming instantly: the request
240
+ * account's address, as `id` on the entries `getVaultAvailableRedemptions`
241
+ * returns. Its shares, recipient and vault come from the request, so the
242
+ * `redeemShares` and `vaultAddress` arguments are ignored. The queue pays
243
+ * at the share price of the moment it settles, held to the floor the request
244
+ * was made with, so `slippageBps` and `minAssetsOut` must not be set
245
+ * alongside it.
246
+ *
247
+ * Required on a vault with a withdrawal queue attached, which refuses a
248
+ * direct redeem. See {@link SolanaAdapter.vaultRequestRedeem}.
249
+ */
250
+ request?: PublicKey | string;
251
+ }
252
+ /**
253
+ * Input to {@link SolanaAdapter.vaultRequestRedeem}.
254
+ */
255
+ export interface ISolanaRequestRedeemParams {
256
+ /** The vault's `VaultState` account address. */
257
+ vault: PublicKey | string;
258
+ /** The holder, who signs, escrows the shares and pays rent for the request. */
259
+ wallet: PublicKey | string;
260
+ /** Shares to escrow: `bigint` in raw share units, or `number` as a UI amount. */
261
+ amount: number | bigint;
262
+ /**
263
+ * Wallet to pay when the request is claimed; its deposit-token account is
264
+ * created in the same transaction if it has none, at the holder's expense.
265
+ * Defaults to the holder.
266
+ */
267
+ recipient?: PublicKey | string;
268
+ /**
269
+ * The one key besides the holder that may claim the request, e.g. a keeper.
270
+ * Defaults to anyone, which is what lets a keeper settle requests for
271
+ * holders who do not come back.
272
+ */
273
+ finalizer?: PublicKey | string;
274
+ /**
275
+ * The request's id, unique per holder while it is pending. Defaults to a
276
+ * random `u64`; pass one only to choose it yourself.
277
+ */
278
+ requestId?: bigint;
279
+ /**
280
+ * Tolerance below the quoted net payout, in basis points (`0` to `10000`).
281
+ * The floor is fixed now and checked when the request is claimed, so it
282
+ * guards against a fee rise or an AUM mark-down in between; yield earned in
283
+ * the meantime only raises the payout. Ignored when `minAssetsOut` is given.
284
+ * @defaultValue 50 (0.5%)
285
+ */
286
+ slippageBps?: number;
287
+ /**
288
+ * Explicit floor on the net payout, in raw deposit-mint units, stored on the
289
+ * request as is. Skips the quote. `0n` means no floor: the claim pays
290
+ * whatever the shares are worth when it lands.
291
+ *
292
+ * Must be a `bigint` in `0 .. 2^64-1`; anything else throws
293
+ * {@link AugustValidationError} before the transaction is built.
294
+ */
295
+ minAssetsOut?: bigint;
296
+ }
297
+ /**
298
+ * What {@link SolanaAdapter.vaultRequestRedeem} returns.
299
+ */
300
+ export interface ISolanaRequestRedeemResult {
301
+ /** The confirmed transaction's signature. */
302
+ signature: string;
303
+ /**
304
+ * The new request account's address: pass it as `request` to claim or
305
+ * cancel. `getVaultAvailableRedemptions` lists it as `id`.
306
+ */
307
+ request: string;
308
+ /** The request id, as a decimal string (a `u64`). */
309
+ requestId: string;
310
+ }
311
+ /**
312
+ * Input to {@link SolanaAdapter.vaultCancelRedeemRequest}.
313
+ */
314
+ export interface ISolanaCancelRedeemRequestParams {
315
+ /** The holder who made the request; only they may cancel it. */
316
+ wallet: PublicKey | string;
317
+ /** The request account's address, as returned by `vaultRequestRedeem`. */
318
+ request: PublicKey | string;
120
319
  }
@@ -2,6 +2,7 @@ import { AnchorProvider, BN, Program, type web3 } from '@coral-xyz/anchor';
2
2
  import { PublicKey, type ParsedAccountData, type Transaction } from '@solana/web3.js';
3
3
  import type { ISolanaConnectionOptions, ISolanaVaultState } from './types';
4
4
  import { BlockhashConfirmingProvider } from './confirm';
5
+ import type { ISolanaProgramIds } from './constants';
5
6
  declare function getExplorerLink({ signature, type, network, }: {
6
7
  signature: string;
7
8
  type: 'tx' | 'address' | 'token';
@@ -9,6 +10,19 @@ declare function getExplorerLink({ signature, type, network, }: {
9
10
  import { isSolanaAddress } from '../../core/helpers/chain-address';
10
11
  export { isSolanaAddress };
11
12
  declare function isSolana(signature: string): boolean;
13
+ /**
14
+ * Throws unless `type` is a program type `programNames` maps. Checked at
15
+ * runtime for untyped callers: a typo would otherwise read as an undeployed
16
+ * program, and a prototype key like `toString` as a program id.
17
+ * @internal
18
+ */
19
+ export declare function assertSolanaProgramType(type: unknown): asserts type is keyof ISolanaProgramIds;
20
+ /**
21
+ * Error text for `program` having no canonical deployment on `network`, naming
22
+ * the networks it is deployed on.
23
+ * @internal
24
+ */
25
+ export declare function undeployedProgramMessage(program: keyof ISolanaProgramIds, network: string): string;
12
26
  declare function getProgram({ provider, idl, programId, network, }: {
13
27
  idl?: any;
14
28
  programId?: string;
@@ -180,12 +194,14 @@ export declare const SolanaUtils: {
180
194
  programIds: {
181
195
  devnet: {
182
196
  vault: string;
197
+ withdrawalQueue: string;
183
198
  };
184
199
  "mainnet-beta": {
185
200
  vault: string;
186
201
  };
187
202
  localnet: {
188
203
  vault: string;
204
+ withdrawalQueue: string;
189
205
  };
190
206
  };
191
207
  getVaultMints: typeof getVaultMints;
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SolanaUtils = exports.isSolanaAddress = void 0;
4
+ exports.assertSolanaProgramType = assertSolanaProgramType;
5
+ exports.undeployedProgramMessage = undeployedProgramMessage;
4
6
  exports.selectRichestTokenAccount = selectRichestTokenAccount;
5
7
  exports.uiAmountToRawBn = uiAmountToRawBn;
6
8
  const anchor_1 = require("@coral-xyz/anchor");
@@ -40,8 +42,42 @@ function isSolana(signature) {
40
42
  // Check length - Solana signatures are typically 88 characters
41
43
  return (signature.length >= 80 && signature.length <= 100);
42
44
  }
45
+ /** On-chain name (IDL `metadata.name`) of each program type. */
46
+ const programNames = {
47
+ vault: 'august_vault',
48
+ withdrawalQueue: 'august_withdrawal_queue',
49
+ };
50
+ /**
51
+ * Throws unless `type` is a program type `programNames` maps. Checked at
52
+ * runtime for untyped callers: a typo would otherwise read as an undeployed
53
+ * program, and a prototype key like `toString` as a program id.
54
+ * @internal
55
+ */
56
+ function assertSolanaProgramType(type) {
57
+ if (typeof type !== 'string' || !Object.hasOwn(programNames, type)) {
58
+ throw new core_1.AugustValidationError('INVALID_INPUT', `Unknown Solana program type '${String(type)}'. Expected one of: ${Object.keys(programNames).join(', ')}.`);
59
+ }
60
+ }
61
+ /**
62
+ * Error text for `program` having no canonical deployment on `network`, naming
63
+ * the networks it is deployed on.
64
+ * @internal
65
+ */
66
+ function undeployedProgramMessage(program, network) {
67
+ const deployed = Object.entries(constants_1.programIds)
68
+ .filter(([, ids]) => ids[program])
69
+ .map(([name]) => name);
70
+ return (`No canonical ${programNames[program]} deployment for Solana network '${network}'. ` +
71
+ `Deployed networks: ${deployed.join(', ')}.`);
72
+ }
43
73
  function getProgram({ provider, idl, programId, network, }) {
44
74
  const baseIdl = idl ?? constants_1.vaultIdl;
75
+ // The withdrawal queue IDL resolves through `programIds.withdrawalQueue`;
76
+ // anything else is treated as the vault. Recognised by name, so the queue IDL
77
+ // never has to be imported here (and pulled into every bundle).
78
+ const program = baseIdl?.metadata?.name === programNames.withdrawalQueue
79
+ ? 'withdrawalQueue'
80
+ : 'vault';
45
81
  // Precedence: explicit `programId` → a custom IDL's `address` → the network
46
82
  // default → the bundled IDL's embedded `address`.
47
83
  //
@@ -50,7 +86,9 @@ function getProgram({ provider, idl, programId, network, }) {
50
86
  // copy (second bundle instance, or JSON round-tripped), silently retargeting
51
87
  // devnet callers at mainnet. Every copy carries the same build stamp, so it
52
88
  // still defers to the network default — but a genuinely custom IDL is honoured.
53
- const suppliedAddress = typeof baseIdl?.address === 'string' && baseIdl.address !== constants_1.vaultIdl.address
89
+ // A build stamp is the program's canonical id, which some network maps.
90
+ const isBuildStamp = Object.values(constants_1.programIds).some((ids) => ids[program] === baseIdl?.address);
91
+ const suppliedAddress = typeof baseIdl?.address === 'string' && !isBuildStamp
54
92
  ? baseIdl.address
55
93
  : undefined;
56
94
  const explicitId = programId ?? suppliedAddress;
@@ -58,10 +96,9 @@ function getProgram({ provider, idl, programId, network, }) {
58
96
  return new anchor_1.Program({ ...baseIdl, address: explicitId }, provider);
59
97
  }
60
98
  if (network) {
61
- const networkDefault = (0, constants_1.getDeployedProgramIds)(network)?.vault;
99
+ const networkDefault = (0, constants_1.getDeployedProgramIds)(network)?.[program];
62
100
  if (!networkDefault) {
63
- throw new core_1.AugustValidationError('INVALID_INPUT', `No canonical august_vault deployment for Solana network '${network}'. ` +
64
- `Deployed networks: ${Object.keys(constants_1.programIds).join(', ')}. ` +
101
+ throw new core_1.AugustValidationError('INVALID_INPUT', `${undeployedProgramMessage(program, network)} ` +
65
102
  `Pass an explicit \`programId\` (or an IDL carrying the target \`address\`) to target a program on this network.`);
66
103
  }
67
104
  return new anchor_1.Program({ ...baseIdl, address: networkDefault }, provider);
@@ -35,6 +35,23 @@ export declare function describeSolanaError(e: unknown): string;
35
35
  * program's message.
36
36
  */
37
37
  export declare function slippageHint(e: unknown): string;
38
+ /**
39
+ * Validate a caller-supplied slippage floor before it reaches Anchor's `u64`
40
+ * encoder.
41
+ *
42
+ * Anchor serializes a `BN` to `u64` via `toArrayLike`, which writes the
43
+ * magnitude and drops the sign — a `-1n` floor would reach the program as a
44
+ * floor of `1`, inverting the caller's intent instead of failing. Values above
45
+ * `u64` fare no better: they surface as an untyped "byte array longer than
46
+ * desired length" from inside the encoder, naming nothing the caller passed.
47
+ * Both are caught here, at the public-API boundary.
48
+ *
49
+ * @param value - The caller's `minSharesOut` / `minAssetsOut`, in raw base units.
50
+ * @param label - Option name, quoted in the error.
51
+ * @returns `value`, once known to fit an unsigned 64-bit integer.
52
+ * @throws {@link AugustValidationError} when it is not a `bigint` in `0 .. 2^64-1`.
53
+ */
54
+ export declare function validateExplicitFloor(value: bigint, label: string): bigint;
38
55
  /**
39
56
  * Deposit funds into a Solana August vault and mint share tokens.
40
57
  *