@augustdigital/sdk 9.3.0 → 9.4.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 (56) hide show
  1. package/lib/adapters/evm/getters.js +40 -0
  2. package/lib/adapters/evm/index.d.ts +106 -2
  3. package/lib/adapters/evm/index.js +125 -0
  4. package/lib/adapters/solana/index.d.ts +12 -5
  5. package/lib/adapters/solana/index.js +12 -4
  6. package/lib/adapters/solana/pricing.d.ts +173 -0
  7. package/lib/adapters/solana/pricing.js +223 -0
  8. package/lib/adapters/solana/types.d.ts +45 -0
  9. package/lib/adapters/solana/vault.actions.d.ts +33 -8
  10. package/lib/adapters/solana/vault.actions.js +185 -28
  11. package/lib/adapters/stellar/actions.d.ts +2 -2
  12. package/lib/adapters/stellar/actions.js +2 -2
  13. package/lib/adapters/stellar/getters.d.ts +1 -1
  14. package/lib/adapters/stellar/getters.js +2 -2
  15. package/lib/adapters/stellar/index.d.ts +1 -1
  16. package/lib/adapters/stellar/index.js +1 -1
  17. package/lib/adapters/stellar/types.d.ts +1 -2
  18. package/lib/core/analytics/method-taxonomy.js +7 -0
  19. package/lib/core/analytics/version.d.ts +1 -1
  20. package/lib/core/analytics/version.js +1 -1
  21. package/lib/core/base.class.d.ts +2 -2
  22. package/lib/core/base.class.js +2 -2
  23. package/lib/core/constants/core.d.ts +17 -3
  24. package/lib/core/constants/core.js +17 -3
  25. package/lib/core/constants/vaults.js +4 -0
  26. package/lib/core/fetcher.js +112 -45
  27. package/lib/core/helpers/concurrency.d.ts +37 -0
  28. package/lib/core/helpers/concurrency.js +58 -0
  29. package/lib/core/helpers/core.d.ts +9 -0
  30. package/lib/core/helpers/core.js +47 -0
  31. package/lib/core/helpers/vaults.d.ts +1 -1
  32. package/lib/core/helpers/vaults.js +1 -1
  33. package/lib/core/helpers/web3.js +14 -1
  34. package/lib/core/logger/curator-alert.d.ts +2 -2
  35. package/lib/core/logger/curator-alert.js +2 -2
  36. package/lib/evm/methods/crossChainVaultRegistry.d.ts +2 -3
  37. package/lib/evm/methods/crossChainVaultRegistry.js +2 -3
  38. package/lib/evm/types/crossChain.d.ts +1 -1
  39. package/lib/main.d.ts +7 -5
  40. package/lib/main.js +7 -5
  41. package/lib/modules/vaults/getters.d.ts +10 -3
  42. package/lib/modules/vaults/getters.js +205 -71
  43. package/lib/modules/vaults/main.d.ts +4 -4
  44. package/lib/modules/vaults/main.js +7 -4
  45. package/lib/modules/vaults/read.actions.d.ts +181 -0
  46. package/lib/modules/vaults/read.actions.js +331 -36
  47. package/lib/modules/vaults/types.d.ts +13 -0
  48. package/lib/modules/vaults/utils.js +5 -1
  49. package/lib/modules/vaults/write.actions.d.ts +74 -6
  50. package/lib/modules/vaults/write.actions.js +133 -23
  51. package/lib/sdk.d.ts +9827 -9342
  52. package/lib/services/subgraph/schema.d.ts +1 -1
  53. package/lib/services/subgraph/schema.js +1 -1
  54. package/lib/types/pools.d.ts +1 -1
  55. package/lib/types/vaults.d.ts +4 -4
  56. package/package.json +1 -1
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ /**
3
+ * Off-chain mirror of the `august_vault` pricing math.
4
+ *
5
+ * Used to quote what a deposit or redeem is expected to return so a slippage
6
+ * floor can be handed to `deposit_checked` / `redeem_checked`. Mirrors
7
+ * `VaultState::shares_for_deposit_with_offset` and
8
+ * `assets_for_redeem_with_offset` (`programs/august-vault/src/state/vault.rs`):
9
+ * `u128` intermediates, a per-vault virtual-share offset defaulting to
10
+ * `EXTRA_SHARES = 1_000_000`, a pro-rata floor (deposit) or cap (redeem),
11
+ * every division rounded down; plus the withdrawal fee `redeem_checked` takes,
12
+ * `ceil(assets * fee / 1e6)` at `FEE_RATE_DENOMINATOR_VALUE = 1_000_000`.
13
+ *
14
+ * A quote is only a quote. The program prices at execution, against state
15
+ * that may have moved since the read; the floor derived here is what protects
16
+ * the caller when the two differ.
17
+ *
18
+ * This mirror cannot validate itself — agreeing with its own tests proves
19
+ * nothing about the program — so every claim below about program behaviour is
20
+ * cited to its handler in `fractal-protocol/solana-upshift-vault-programs`, by
21
+ * file and function rather than line. Verified against that repo at 3b91c86.
22
+ * Do not "fix" the math here against intuition; re-read the handler.
23
+ *
24
+ * Adapter-internal. These functions are exported for `vault.actions.ts` and
25
+ * the unit tests only — deliberately absent from the `adapters/solana` barrel,
26
+ * so they are not public SDK surface and carry no benchmark or telemetry
27
+ * taxonomy obligation. Promoting one to the barrel means taking both on.
28
+ *
29
+ * @packageDocumentation
30
+ */
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.DEFAULT_SLIPPAGE_BPS = exports.DEFAULT_SHARE_OFFSET = void 0;
33
+ exports.toBigInt = toBigInt;
34
+ exports.resolveShareOffset = resolveShareOffset;
35
+ exports.totalAssetsOf = totalAssetsOf;
36
+ exports.sharesForDeposit = sharesForDeposit;
37
+ exports.assetsForRedeem = assetsForRedeem;
38
+ exports.withdrawalFee = withdrawalFee;
39
+ exports.applySlippage = applySlippage;
40
+ exports.quoteDepositFloor = quoteDepositFloor;
41
+ exports.quoteRedeemFloor = quoteRedeemFloor;
42
+ const core_1 = require("../../core");
43
+ /** What the program uses when a vault stores `share_offset == 0` (vaults created before the field existed). */
44
+ exports.DEFAULT_SHARE_OFFSET = 1000000n;
45
+ /** Denominator of `VaultState.withdrawal_fee`: the fee is in parts per million. */
46
+ const FEE_RATE_DENOMINATOR = 1000000n;
47
+ /** Slippage tolerance applied when a caller gives neither `slippageBps` nor an explicit floor. */
48
+ exports.DEFAULT_SLIPPAGE_BPS = 50;
49
+ const BPS_DENOMINATOR = 10000n;
50
+ /**
51
+ * Coerce an on-chain integer as Anchor decodes it (`BN`, `number`, decimal
52
+ * string, or `bigint`) to `bigint`.
53
+ *
54
+ * @param value - The decoded field.
55
+ * @param label - Named in the error when the value is not a non-negative integer.
56
+ * @throws AugustSDKError when the value cannot be read as a non-negative integer.
57
+ */
58
+ function toBigInt(value, label) {
59
+ if (typeof value === 'bigint' && value >= 0n)
60
+ return value;
61
+ if (typeof value === 'number' && Number.isSafeInteger(value) && value >= 0)
62
+ return BigInt(value);
63
+ const text = typeof value === 'string'
64
+ ? value
65
+ : value !== null && typeof value === 'object'
66
+ ? String(value)
67
+ : '';
68
+ if (/^\d+$/.test(text))
69
+ return BigInt(text);
70
+ throw new core_1.AugustSDKError('UNKNOWN', `Solana vault pricing: ${label} is not a non-negative integer (got ${String(value)}).`);
71
+ }
72
+ /**
73
+ * The vault's effective share offset. A stored zero (or a state decoded from
74
+ * an IDL that predates the field) resolves to the program default, exactly as
75
+ * `VaultState::share_offset()` does on-chain.
76
+ *
77
+ * @param raw - `VaultState.shareOffset` as decoded, or `undefined`.
78
+ */
79
+ function resolveShareOffset(raw) {
80
+ if (raw === undefined || raw === null)
81
+ return exports.DEFAULT_SHARE_OFFSET;
82
+ const offset = toBigInt(raw, 'shareOffset');
83
+ return offset === 0n ? exports.DEFAULT_SHARE_OFFSET : offset;
84
+ }
85
+ /**
86
+ * `localAum + deployedAum`, the `total_assets()` the program prices against.
87
+ *
88
+ * @param state - Decoded `VaultState`.
89
+ * @throws AugustSDKError when either field is missing, which means the state
90
+ * was decoded with an IDL this SDK cannot price against.
91
+ */
92
+ function totalAssetsOf(state) {
93
+ return (toBigInt(state.localAum, 'localAum') +
94
+ toBigInt(state.deployedAum, 'deployedAum'));
95
+ }
96
+ function requireSharePrice(supply, totalAssets) {
97
+ // Mirrors `SharePriceUndefined`: outstanding shares against no assets has no
98
+ // price in either direction, and the program would refuse the instruction.
99
+ if (totalAssets === 0n && supply > 0n) {
100
+ throw new core_1.AugustValidationError('INVALID_INPUT', 'This vault holds no assets while shares are outstanding, so it has no share price; deposits and redemptions are refused until the operator recapitalises it.');
101
+ }
102
+ }
103
+ /**
104
+ * Shares minted for depositing `amount` base units.
105
+ *
106
+ * `floor(max(amount * (supply + offset) / (totalAssets + offset), amount * supply / totalAssets))`.
107
+ * Above par the offset term is the larger and binds; below par the pro-rata
108
+ * floor binds so a depositor never hands value to incumbents on arrival.
109
+ *
110
+ * @param input - Share supply, total assets and the vault's resolved offset,
111
+ * all in raw base units.
112
+ * @throws AugustValidationError when the vault has no share price.
113
+ */
114
+ function sharesForDeposit(input) {
115
+ const { supply, totalAssets, amount, offset } = input;
116
+ requireSharePrice(supply, totalAssets);
117
+ const withOffsets = (amount * (supply + offset)) / (totalAssets + offset);
118
+ if (totalAssets === 0n)
119
+ return withOffsets;
120
+ const proRata = (amount * supply) / totalAssets;
121
+ return withOffsets > proRata ? withOffsets : proRata;
122
+ }
123
+ /**
124
+ * Assets paid, before the withdrawal fee, for burning `shares`.
125
+ *
126
+ * `floor(min(shares * (totalAssets + offset) / (supply + offset), shares * totalAssets / supply))`.
127
+ * The mirror of {@link sharesForDeposit}: above par the offset term binds,
128
+ * below par the pro-rata cap does, so no redeemer takes more than its share.
129
+ *
130
+ * @param input - Share supply, total assets and the vault's resolved offset,
131
+ * all in raw base units.
132
+ * @throws AugustValidationError when the vault has no share price.
133
+ */
134
+ function assetsForRedeem(input) {
135
+ const { supply, totalAssets, shares, offset } = input;
136
+ requireSharePrice(supply, totalAssets);
137
+ const withOffsets = (shares * (totalAssets + offset)) / (supply + offset);
138
+ if (supply === 0n)
139
+ return withOffsets;
140
+ const proRata = (shares * totalAssets) / supply;
141
+ return withOffsets < proRata ? withOffsets : proRata;
142
+ }
143
+ /**
144
+ * The withdrawal fee the program takes from a gross redemption:
145
+ * `ceil(assets * feePpm / 1e6)`, rounded **up** as on-chain.
146
+ *
147
+ * @param assets - Gross assets from {@link assetsForRedeem}.
148
+ * @param feePpm - `VaultState.withdrawalFee`, parts per million.
149
+ */
150
+ function withdrawalFee(assets, feePpm) {
151
+ return (assets * feePpm + FEE_RATE_DENOMINATOR - 1n) / FEE_RATE_DENOMINATOR;
152
+ }
153
+ /**
154
+ * Lower `expected` by `slippageBps` basis points, rounding down.
155
+ *
156
+ * @param expected - The quoted output in raw base units.
157
+ * @param slippageBps - Integer basis points, `0` to `10_000`.
158
+ * @throws AugustValidationError when `slippageBps` is out of range or not an integer.
159
+ */
160
+ function applySlippage(expected, slippageBps) {
161
+ if (!Number.isInteger(slippageBps) ||
162
+ slippageBps < 0 ||
163
+ slippageBps > Number(BPS_DENOMINATOR)) {
164
+ throw new core_1.AugustValidationError('INVALID_INPUT', `slippageBps must be an integer between 0 and 10000, got ${slippageBps}.`);
165
+ }
166
+ return (expected * (BPS_DENOMINATOR - BigInt(slippageBps))) / BPS_DENOMINATOR;
167
+ }
168
+ /**
169
+ * The `min_shares_out` to pass to `deposit_checked`: the quoted shares for
170
+ * `amount`, lowered by `slippageBps`.
171
+ *
172
+ * Nothing is netted out, because there is no deposit-side fee. In
173
+ * `instructions/deposit.rs::handler_checked` the comparison is
174
+ * `require!(shares >= min_shares_out, SlippageExceeded)` directly on the
175
+ * `shares_for_deposit` result, with no fee term anywhere in the handler.
176
+ * Structurally too: `VaultState` carries exactly one fee field,
177
+ * `withdrawal_fee`, and `deposit_checked` takes no `fee_recipient_account`
178
+ * among its accounts (`redeem_checked` does), so it has no account to pay one
179
+ * to. Gross and net are the same quantity here.
180
+ *
181
+ * Quoting from state read *before* the transaction is correct despite the
182
+ * handler transferring the deposit in first: `transfer_in_ctx` moves SPL
183
+ * tokens into the vault ATA, but `total_assets()` sums the stored `local_aum`
184
+ * and `deployed_aum` fields, and `local_aum` is incremented only *after*
185
+ * `shares_for_deposit` has been computed. Supply is likewise read before the
186
+ * mint. The handler prices against the same pre-deposit figures this quote
187
+ * does.
188
+ *
189
+ * @param input - Vault state, deposit amount and tolerance.
190
+ */
191
+ function quoteDepositFloor(input) {
192
+ return applySlippage(sharesForDeposit(input), input.slippageBps);
193
+ }
194
+ /**
195
+ * The `min_assets_out` to pass to `redeem_checked`: the quoted payout for
196
+ * `shares` **net of the withdrawal fee** — which is what `redeem_checked`
197
+ * compares against — lowered by `slippageBps`.
198
+ *
199
+ * Net rather than gross is the hinge of the whole guarantee, so it is pinned
200
+ * here rather than left to be re-derived. In
201
+ * `instructions/redeem.rs::handler_checked` the program computes the gross
202
+ * `assets`, subtracts `fees` — the `ceil_div` of `assets * withdrawal_fee`
203
+ * over `FEE_RATE_DENOMINATOR_VALUE` — and compares `min_assets_out` against
204
+ * that difference, which is the figure the caller actually receives.
205
+ * `Redeem::ceil_div` is `(n + d - 1) / d`, which is what
206
+ * {@link withdrawalFee} reproduces.
207
+ *
208
+ * Getting this wrong fails quietly in the dangerous direction. Quote against
209
+ * the gross payout and the floor sits a whole fee above what the program
210
+ * measures, so it binds early and reverts healthy redemptions. Net it twice —
211
+ * or drop the fee from a vault that charges one — and the floor sits below the
212
+ * real payout by the fee, leaving protection weaker than the advertised
213
+ * `slippageBps` instead of visibly broken. `withdrawal_fee` is capped just
214
+ * under 10% (`set_withdrawal_fee`), which bounds that silent gap.
215
+ *
216
+ * @param input - Vault state, shares to burn, fee and tolerance.
217
+ */
218
+ function quoteRedeemFloor(input) {
219
+ const gross = assetsForRedeem(input);
220
+ const net = gross - withdrawalFee(gross, input.feePpm);
221
+ return applySlippage(net, input.slippageBps);
222
+ }
223
+ //# sourceMappingURL=pricing.js.map
@@ -65,3 +65,48 @@ export interface ISolanaVaultStats {
65
65
  feeRecipient: string;
66
66
  lastUpdated: Date;
67
67
  }
68
+ /**
69
+ * Slippage protection for {@link SolanaAdapter.vaultDeposit}.
70
+ *
71
+ * The SDK quotes the shares a deposit should mint from the vault's current
72
+ * state and passes a floor to the program's `deposit_checked` instruction,
73
+ * which reverts with `SlippageExceeded` if the share price moves past it
74
+ * before execution.
75
+ */
76
+ export interface ISolanaDepositOptions {
77
+ /**
78
+ * Tolerance below the quoted shares, in basis points (`0` to `10000`).
79
+ * `0` demands the quote exactly. Ignored when `minSharesOut` is given.
80
+ * @defaultValue 50 (0.5%)
81
+ */
82
+ slippageBps?: number;
83
+ /**
84
+ * Explicit floor in raw share units, passed to `deposit_checked` as is.
85
+ * Skips the quote and the single snapshot read it needs. `0n` restores the
86
+ * unguarded behaviour of the plain `deposit` instruction.
87
+ *
88
+ * Must be a `bigint` in `0 .. 2^64-1`; anything else throws
89
+ * {@link AugustValidationError} before the transaction is built.
90
+ */
91
+ minSharesOut?: bigint;
92
+ }
93
+ /**
94
+ * Slippage protection for {@link SolanaAdapter.vaultRedeem}.
95
+ *
96
+ * The floor is measured **net of the withdrawal fee**, i.e. on what the wallet
97
+ * actually receives, matching the program's `redeem_checked`.
98
+ */
99
+ export interface ISolanaRedeemOptions {
100
+ /**
101
+ * Tolerance below the quoted net payout, in basis points (`0` to `10000`).
102
+ * `0` demands the quote exactly. Ignored when `minAssetsOut` is given.
103
+ * @defaultValue 50 (0.5%)
104
+ */
105
+ slippageBps?: number;
106
+ /**
107
+ * Explicit floor in raw deposit-mint units, net of the withdrawal fee,
108
+ * passed to `redeem_checked` as is. Skips the quote. `0n` restores the
109
+ * unguarded behaviour of the plain `redeem` instruction.
110
+ */
111
+ minAssetsOut?: bigint;
112
+ }
@@ -1,6 +1,6 @@
1
1
  import { type web3 } from '@coral-xyz/anchor';
2
2
  import { type Connection, PublicKey, type Transaction } from '@solana/web3.js';
3
- import type { ISolanaConnectionOptions } from './types';
3
+ import type { ISolanaConnectionOptions, ISolanaDepositOptions, ISolanaRedeemOptions } from './types';
4
4
  import type { SendTransactionOptions } from '@solana/wallet-adapter-base';
5
5
  /**
6
6
  * Extract a human- and machine-readable reason from a thrown Solana/Anchor
@@ -20,6 +20,21 @@ import type { SendTransactionOptions } from '@solana/wallet-adapter-base';
20
20
  * preserved on the wrapped error's `cause` and in telemetry for diagnosis.
21
21
  */
22
22
  export declare function describeSolanaError(e: unknown): string;
23
+ /**
24
+ * A sentence to append when the program rejected the instruction for
25
+ * slippage, so the caller learns what to do rather than just what happened.
26
+ * Empty for every other error.
27
+ *
28
+ * Not merely a restatement of the program's reason string. Both checked
29
+ * instructions share error 6018, whose on-chain message is share-worded —
30
+ * "Received fewer shares than the caller's minimum" — so on a *redeem*, where
31
+ * the floor is denominated in assets, the program describes the wrong
32
+ * quantity. This sentence is what makes that case readable. The numeric code
33
+ * `describeSolanaError` renders alongside it is kept deliberately: it is the
34
+ * handle support and telemetry group on, and it survives a reword of the
35
+ * program's message.
36
+ */
37
+ export declare function slippageHint(e: unknown): string;
23
38
  /**
24
39
  * Deposit funds into a Solana August vault and mint share tokens.
25
40
  *
@@ -36,16 +51,20 @@ export declare function describeSolanaError(e: unknown): string;
36
51
  * non-refundable while the account stays open — on top of the network fee.
37
52
  * Callers should ensure the wallet holds enough SOL for both before
38
53
  * prompting the user to sign.
39
- * @remarks The on-chain `deposit` instruction has no `min_shares_out`
40
- * parameter; slippage cannot be enforced on-chain until the program ships
41
- * that argument.
54
+ * @remarks Sends `deposit_checked`, not `deposit`. Unless `options.minSharesOut`
55
+ * is given, the vault state and share mint are read to quote the shares this
56
+ * deposit should mint, and that quote lowered by `options.slippageBps`
57
+ * (default {@link DEFAULT_SLIPPAGE_BPS}) is passed as the floor; the program
58
+ * reverts with `SlippageExceeded` if execution would mint fewer.
42
59
  */
43
- export declare function handleSolanaDeposit({ provider, connection, network, vaultProgramId, vaultAddress, depositAmount, publicKey, idl, }: {
60
+ export declare function handleSolanaDeposit({ provider, connection, network, vaultProgramId, vaultAddress, depositAmount, publicKey, idl, options, }: {
44
61
  vaultProgramId: PublicKey | string;
45
62
  vaultAddress?: PublicKey | string;
46
63
  idl: any;
47
64
  publicKey: PublicKey | string;
48
65
  depositAmount: number | bigint;
66
+ /** Slippage protection; see {@link ISolanaDepositOptions}. */
67
+ options?: ISolanaDepositOptions;
49
68
  /**
50
69
  * @deprecated Accepted and ignored. Share-account creation is now prepended
51
70
  * to the deposit instruction, so there is no longer a second transaction to
@@ -58,8 +77,12 @@ export declare function handleSolanaDeposit({ provider, connection, network, vau
58
77
  * Redeem vault shares back into the underlying mint on a Solana August vault.
59
78
  *
60
79
  * @param redeemShares `bigint` is treated as raw share-token units;
61
- * `number` is treated as a UI amount. See {@link handleSolanaDeposit} for
62
- * the same caveat about the missing on-chain slippage guard.
80
+ * `number` is treated as a UI amount.
81
+ * @remarks Sends `redeem_checked`, not `redeem`. Unless `options.minAssetsOut`
82
+ * is given, the payout is quoted from the vault state and share supply the
83
+ * handler already reads, **net of the withdrawal fee**, and that quote
84
+ * lowered by `options.slippageBps` (default {@link DEFAULT_SLIPPAGE_BPS}) is
85
+ * passed as the floor; the program reverts with `SlippageExceeded` below it.
63
86
  * @throws AugustValidationError on missing wallet/programId or invalid amount,
64
87
  * or when the wallet holds fewer shares than `redeemShares`.
65
88
  * @throws AugustSDKError when a candidate token account's balance cannot be
@@ -71,12 +94,14 @@ export declare function handleSolanaDeposit({ provider, connection, network, vau
71
94
  * non-refundable, on top of the network fee. Callers should ensure the
72
95
  * wallet holds enough SOL for all of it before prompting the user to sign.
73
96
  */
74
- export declare function handleSolanaRedeem({ provider, connection, vaultProgramId, vaultAddress, publicKey, redeemShares, idl, }: {
97
+ export declare function handleSolanaRedeem({ provider, connection, vaultProgramId, vaultAddress, publicKey, redeemShares, idl, options, }: {
75
98
  idl: any;
76
99
  vaultProgramId: PublicKey | string;
77
100
  vaultAddress?: PublicKey | string;
78
101
  publicKey: PublicKey | string;
79
102
  redeemShares: number | bigint;
103
+ /** Slippage protection; see {@link ISolanaRedeemOptions}. */
104
+ options?: ISolanaRedeemOptions;
80
105
  /**
81
106
  * @deprecated Accepted and ignored. Payout- and fee-recipient-account
82
107
  * creation is now prepended to the redeem instruction, so there is no longer