@upshiftfinance/sdk 0.4.0 → 0.5.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.
@@ -41,15 +41,32 @@ exports.readSuiVaultState = readSuiVaultState;
41
41
  exports.previewSuiDeposit = previewSuiDeposit;
42
42
  exports.previewSuiRedemption = previewSuiRedemption;
43
43
  exports.getSuiShareBalance = getSuiShareBalance;
44
+ exports.getSuiWithdrawalRequests = getSuiWithdrawalRequests;
45
+ exports.suiPositionRedemptions = suiPositionRedemptions;
46
+ exports.getSuiPositionRedemptions = getSuiPositionRedemptions;
47
+ exports.nextSuiWithdrawalRequestId = nextSuiWithdrawalRequestId;
48
+ exports.deriveSuiWithdrawalRequestId = deriveSuiWithdrawalRequestId;
44
49
  exports.suiVaultRefFromRow = suiVaultRefFromRow;
45
50
  exports.buildSuiVault = buildSuiVault;
46
51
  exports.getSuiVault = getSuiVault;
52
+ const types_1 = require("../../types");
47
53
  const core_1 = require("../../core");
54
+ const errors_1 = require("../../core/errors");
48
55
  const chain_address_1 = require("../../core/helpers/chain-address");
49
56
  const utils_1 = require("../../modules/vaults/utils");
50
57
  const client_1 = require("./client");
51
58
  const constants_1 = require("./constants");
52
59
  const targets_1 = require("./targets");
60
+ /**
61
+ * Re-throw a failed read as a typed SDK error: SDK errors pass through, and
62
+ * anything else (an object that does not exist, a malformed coin type, a
63
+ * package that is not the vault package) becomes `INVALID_INPUT`.
64
+ */
65
+ function asReadError(err, network) {
66
+ if (err instanceof core_1.UpshiftSDKError)
67
+ throw err;
68
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', `Sui read failed — check the vault ID, its coin types and the contract IDs for this network: ${err instanceof Error ? err.message : String(err)}`, { cause: err, context: { network } });
69
+ }
53
70
  /** Simulations need a sender; no signature or gas is involved. */
54
71
  const SIMULATION_SENDER = `0x${'0'.repeat(64)}`;
55
72
  /** The contract's "no limit" value for `u64` caps. */
@@ -136,6 +153,17 @@ async function simulateVaultReads(ref, sui, calls) {
136
153
  // Built per attempt: building resolves object versions against this client.
137
154
  const tx = new SuiTransaction();
138
155
  tx.setSender(SIMULATION_SENDER);
156
+ // Charge the management fee accrued since the last charge first, so every
157
+ // read sees the current NAV. A simulation persists nothing.
158
+ tx.moveCall({
159
+ target: (0, targets_1.suiMoveCallTarget)(contracts, 'chargeManagementFee'),
160
+ typeArguments,
161
+ arguments: [
162
+ tx.object(ref.vaultId),
163
+ tx.object(contracts.registryId),
164
+ tx.object(constants_1.SUI_CLOCK_ID),
165
+ ],
166
+ });
139
167
  for (const call of calls) {
140
168
  tx.moveCall({
141
169
  target: (0, targets_1.suiMoveCallTarget)(contracts, call.target),
@@ -159,8 +187,11 @@ async function simulateVaultReads(ref, sui, calls) {
159
187
  },
160
188
  });
161
189
  }
162
- return result.commandResults.map((c) => c.returnValues.map((v) => v.bcs));
163
- });
190
+ // Drop the fee charge's (empty) result so indexes match `calls`.
191
+ return result.commandResults
192
+ .slice(1)
193
+ .map((c) => c.returnValues.map((v) => v.bcs));
194
+ }).catch((err) => asReadError(err, ref.network));
164
195
  }
165
196
  /**
166
197
  * Read a vault's on-chain state.
@@ -192,7 +223,7 @@ async function readSuiVaultState(ref, sui) {
192
223
  target,
193
224
  registry: NEEDS_REGISTRY.has(target),
194
225
  }))),
195
- (0, client_1.withSuiClient)((0, client_1.resolveSuiNetworkConfig)(config), (client) => client.core.getObject({ objectId: ref.vaultId, include: { json: true } })),
226
+ (0, client_1.withSuiClient)((0, client_1.resolveSuiNetworkConfig)(config), (client) => client.core.getObject({ objectId: ref.vaultId, include: { json: true } })).catch((err) => asReadError(err, ref.network)),
196
227
  ]);
197
228
  const at = (i) => {
198
229
  const bytes = values[i]?.[0];
@@ -294,9 +325,256 @@ async function getSuiShareBalance(owner, shareCoinType, network, sui) {
294
325
  throw new core_1.UpshiftValidationError('INVALID_ADDRESS', 'getSuiShareBalance: owner must be a Sui address (0x + 64 hex chars).');
295
326
  }
296
327
  const config = suiConfigForNetwork(network, sui);
297
- const { balance } = await (0, client_1.withSuiClient)((0, client_1.resolveSuiNetworkConfig)(config), (client) => client.core.getBalance({ owner, coinType: shareCoinType }));
328
+ const { balance } = await (0, client_1.withSuiClient)((0, client_1.resolveSuiNetworkConfig)(config), (client) => client.core.getBalance({ owner, coinType: shareCoinType })).catch((err) => asReadError(err, network));
298
329
  return BigInt(balance.balance);
299
330
  }
331
+ /**
332
+ * IDs checked per object read: each needs its claim marker and its request,
333
+ * and the gRPC client sends at most 50 objects per request. The first page
334
+ * also carries the vault object, so it checks one ID fewer.
335
+ */
336
+ const REQUEST_SCAN_PAGE = 25;
337
+ /**
338
+ * Walk a wallet's request IDs on a vault, `0, 1, 2, …`, and read each one.
339
+ *
340
+ * The contract derives a request's object ID from (vault, owner, request ID)
341
+ * and leaves a permanent claim marker on the vault for every ID ever used,
342
+ * also after the request is claimed or cancelled. The SDK numbers requests
343
+ * sequentially, so the first ID without a marker is the next one to use, and
344
+ * every request below it that still exists is pending. This needs neither an
345
+ * event index (public fullnodes keep about two weeks of events) nor an
346
+ * indexer.
347
+ *
348
+ * Requests made outside the SDK with other IDs are not found.
349
+ *
350
+ * The first read also checks that `ref.vaultId` is a vault of the configured
351
+ * original package, so a wrong vault ID or `sui.originalPackageId` (which
352
+ * names the request IDs) fails loudly instead of finding nothing.
353
+ *
354
+ * RPC cost: one object read for up to 23 used IDs, one more per further 25.
355
+ */
356
+ async function scanSuiWithdrawalRequests(ref, owner, sui) {
357
+ const config = suiConfigForNetwork(ref.network, sui);
358
+ const contracts = (0, targets_1.resolveSuiVaultContracts)(config);
359
+ const [{ bcs }, { deriveDynamicFieldID }] = await Promise.all([
360
+ Promise.resolve().then(() => __importStar(require('@mysten/sui/bcs'))),
361
+ Promise.resolve().then(() => __importStar(require('@mysten/sui/utils'))),
362
+ ]);
363
+ const WithdrawalRequest = bcs.struct('WithdrawalRequest', {
364
+ id: bcs.Address,
365
+ vaultId: bcs.Address,
366
+ owner: bcs.Address,
367
+ requestId: bcs.u64(),
368
+ shares: bcs.u64(),
369
+ payout: bcs.Address,
370
+ finalizer: bcs.option(bcs.Address),
371
+ requestedAtMs: bcs.u64(),
372
+ eligibleAtMs: bcs.u64(),
373
+ expiresAtMs: bcs.option(bcs.u64()),
374
+ });
375
+ const requests = [];
376
+ for (let start = 0n;;) {
377
+ const first = start === 0n;
378
+ const size = first ? REQUEST_SCAN_PAGE - 1 : REQUEST_SCAN_PAGE;
379
+ const ids = Array.from({ length: size }, (_, i) => start + BigInt(i));
380
+ start += BigInt(size);
381
+ const requestIds = await Promise.all(ids.map((requestId) => deriveSuiWithdrawalRequestId(ref.vaultId, owner, requestId, contracts.originalPackageId)));
382
+ // The marker is a dynamic field on the vault keyed by the request ID.
383
+ const markerIds = requestIds.map((id) => deriveDynamicFieldID(ref.vaultId, '0x2::derived_object::Claimed', bcs.Address.serialize(id).toBytes()));
384
+ const { objects } = await (0, client_1.withSuiClient)((0, client_1.resolveSuiNetworkConfig)(config), (client) => client.core.getObjects({
385
+ objectIds: [
386
+ ...markerIds,
387
+ ...requestIds,
388
+ ...(first ? [ref.vaultId] : []),
389
+ ],
390
+ include: { content: true },
391
+ })).catch((err) => asReadError(err, ref.network));
392
+ const missing = (o) => {
393
+ if (!(o instanceof Error))
394
+ return false;
395
+ const reason = o.reason;
396
+ if (reason === 'notFound' || reason === 'deleted')
397
+ return true;
398
+ // Any other per-object error means the node did not answer for it.
399
+ throw new errors_1.UpshiftNetworkError(`Sui read: withdrawal request lookup failed: ${o.message}`, { cause: o, context: { network: ref.network } });
400
+ };
401
+ if (first) {
402
+ const vault = objects[2 * size];
403
+ // A missing vault is a wrong ID; any other per-object error is the node.
404
+ assertVaultOfPackage(missing(vault) ? undefined : vault, ref, contracts);
405
+ }
406
+ for (let i = 0; i < size; i += 1) {
407
+ if (missing(objects[i])) {
408
+ return { nextRequestId: ids[i], requests };
409
+ }
410
+ const object = objects[size + i];
411
+ // Claimed but gone: the request was claimed or cancelled.
412
+ if (missing(object) || object instanceof Error)
413
+ continue;
414
+ const parsed = WithdrawalRequest.parse(object.content);
415
+ requests.push({
416
+ request: requestIds[i],
417
+ requestId: BigInt(parsed.requestId),
418
+ owner: parsed.owner,
419
+ shares: BigInt(parsed.shares),
420
+ payout: parsed.payout,
421
+ finalizer: parsed.finalizer ?? null,
422
+ requestedAtMs: Number(parsed.requestedAtMs),
423
+ eligibleAtMs: Number(parsed.eligibleAtMs),
424
+ expiresAtMs: parsed.expiresAtMs == null ? null : Number(parsed.expiresAtMs),
425
+ });
426
+ }
427
+ }
428
+ }
429
+ /**
430
+ * Throw unless `object` is the vault `ref` names, typed by the configured
431
+ * original package: request IDs are derived from that package, so a wrong one
432
+ * would make every request invisible.
433
+ */
434
+ function assertVaultOfPackage(object, ref, contracts) {
435
+ const type = object instanceof Error ? undefined : object?.type;
436
+ const expected = `${contracts.originalPackageId}::vault::Vault<`.toLowerCase();
437
+ if (!type) {
438
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'Sui read: the vault object was not found — check the vault ID for this network.', { context: { network: ref.network } });
439
+ }
440
+ if (!type.toLowerCase().startsWith(expected)) {
441
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', `Sui read: ${ref.vaultId} is not a vault of the configured original package (its type is ${type}) — check the vault ID and sui.originalPackageId.`, { context: { network: ref.network } });
442
+ }
443
+ }
444
+ function assertOwner(owner, method) {
445
+ if (!(0, chain_address_1.isSuiAddress)(owner)) {
446
+ throw new core_1.UpshiftValidationError('INVALID_ADDRESS', `${method}: owner must be a Sui address (0x + 64 hex chars).`);
447
+ }
448
+ }
449
+ /**
450
+ * A wallet's pending withdrawal requests on a vault, oldest first.
451
+ *
452
+ * Finds the requests the SDK made (see `buildSuiRequestRedeemTransaction`),
453
+ * however old: requests made outside the SDK with non-sequential IDs are not
454
+ * listed. Claimed and cancelled requests no longer exist and are left out.
455
+ *
456
+ * RPC cost: one object read for a wallet that has made up to 23 requests on
457
+ * the vault (most wallets), one more per further 25.
458
+ *
459
+ * @param ref - The vault and its coin types and network.
460
+ * @param owner - Wallet that made the requests (`0x` + 64 hex chars).
461
+ * @param sui - The SDK's `sui` config; applied only for `ref.network`.
462
+ * @returns The pending requests; empty when there are none.
463
+ * @throws {@link UpshiftValidationError} (`INVALID_ADDRESS`) for a malformed
464
+ * vault ID or owner, (`INVALID_INPUT`) for unknown contract IDs, or a vault
465
+ * ID that is not a vault of the configured `sui.originalPackageId`.
466
+ * @throws {@link UpshiftNetworkError} when every Sui endpoint fails, or the
467
+ * node cannot answer for one of the objects.
468
+ * @example
469
+ * ```ts
470
+ * const pending = await getSuiWithdrawalRequests(ref, account.address, sdkSuiConfig);
471
+ * const now = Date.now();
472
+ * const claimable = pending.filter(
473
+ * (r) => r.eligibleAtMs <= now && (r.expiresAtMs === null || now < r.expiresAtMs),
474
+ * );
475
+ * ```
476
+ */
477
+ async function getSuiWithdrawalRequests(ref, owner, sui) {
478
+ assertVaultRef(ref, 'getSuiWithdrawalRequests');
479
+ assertOwner(owner, 'getSuiWithdrawalRequests');
480
+ return (await scanSuiWithdrawalRequests(ref, owner, sui)).requests;
481
+ }
482
+ /**
483
+ * Split a wallet's withdrawal requests into position redemptions, the way
484
+ * the EVM and Solana paths do: `availableRedemptions` holds requests still in
485
+ * their cooldown or past their window (cancel-only), `pendingRedemptions` the
486
+ * ones claimable now. Each entry's `amount` is the escrowed shares; `date` is
487
+ * when it becomes claimable, `timestamp` when it was made (Unix seconds).
488
+ * @internal
489
+ */
490
+ function suiPositionRedemptions(requests, vault, decimals, nowMs) {
491
+ const availableRedemptions = [];
492
+ const pendingRedemptions = [];
493
+ for (const r of requests) {
494
+ const status = r.expiresAtMs !== null && nowMs >= r.expiresAtMs
495
+ ? types_1.VaultRedemptionStatus.EXPIRED
496
+ : nowMs >= r.eligibleAtMs
497
+ ? types_1.VaultRedemptionStatus.READY_TO_CLAIM
498
+ : types_1.VaultRedemptionStatus.AWAITING_COOLDOWN;
499
+ const date = new Date(r.eligibleAtMs);
500
+ const entry = {
501
+ id: r.request,
502
+ hash: r.request,
503
+ timestamp: Math.floor(r.requestedAtMs / 1000),
504
+ receiver: r.payout,
505
+ day: (0, core_1.toNormalizedBn)(date.getUTCDate(), 0),
506
+ month: (0, core_1.toNormalizedBn)(date.getUTCMonth() + 1, 0),
507
+ year: (0, core_1.toNormalizedBn)(date.getUTCFullYear(), 0),
508
+ amount: (0, core_1.toNormalizedBn)(r.shares, decimals),
509
+ date,
510
+ vault: vault,
511
+ status,
512
+ };
513
+ if (status === types_1.VaultRedemptionStatus.READY_TO_CLAIM) {
514
+ pendingRedemptions.push(entry);
515
+ }
516
+ else {
517
+ availableRedemptions.push(entry);
518
+ }
519
+ }
520
+ return { availableRedemptions, pendingRedemptions };
521
+ }
522
+ /**
523
+ * A wallet's withdrawal requests on a vault as position redemptions (see
524
+ * {@link suiPositionRedemptions}). Empty when the SDK has no contract IDs for
525
+ * the network: the share balance can still be read without them, so a
526
+ * position should not fail for that.
527
+ *
528
+ * RPC cost: as {@link getSuiWithdrawalRequests}; none without contract IDs.
529
+ * @internal
530
+ */
531
+ async function getSuiPositionRedemptions(ref, owner, decimals, sui) {
532
+ const config = suiConfigForNetwork(ref.network, sui);
533
+ const defaults = constants_1.SUI_VAULT_CONTRACTS[ref.network];
534
+ const configured = (config.packageId ?? defaults.packageId) &&
535
+ (config.originalPackageId ?? defaults.originalPackageId) &&
536
+ (config.registryId ?? defaults.registryId);
537
+ if (!configured) {
538
+ return suiPositionRedemptions([], ref.vaultId, decimals, Date.now());
539
+ }
540
+ const requests = await getSuiWithdrawalRequests(ref, owner, sui);
541
+ return suiPositionRedemptions(requests, ref.vaultId, decimals, Date.now());
542
+ }
543
+ /**
544
+ * The request ID a wallet's next withdrawal request on a vault takes: the
545
+ * lowest it has never used.
546
+ *
547
+ * RPC cost: as {@link getSuiWithdrawalRequests}.
548
+ * @internal
549
+ */
550
+ async function nextSuiWithdrawalRequestId(ref, owner, sui) {
551
+ assertVaultRef(ref, 'nextSuiWithdrawalRequestId');
552
+ assertOwner(owner, 'nextSuiWithdrawalRequestId');
553
+ return (await scanSuiWithdrawalRequests(ref, owner, sui)).nextRequestId;
554
+ }
555
+ /**
556
+ * The object ID of a wallet's withdrawal request: derived from the vault, the
557
+ * owner and the request ID, as the contract derives it.
558
+ *
559
+ * @param vaultId - Vault object ID.
560
+ * @param owner - Wallet that made the request.
561
+ * @param requestId - The wallet's numeric request ID on the vault.
562
+ * @param originalPackageId - The original `upshift_vault` package, which
563
+ * names the derivation key type.
564
+ * @returns The request object ID.
565
+ * @internal
566
+ */
567
+ async function deriveSuiWithdrawalRequestId(vaultId, owner, requestId, originalPackageId) {
568
+ const [{ bcs }, { deriveObjectID, normalizeSuiAddress }] = await Promise.all([
569
+ Promise.resolve().then(() => __importStar(require('@mysten/sui/bcs'))),
570
+ Promise.resolve().then(() => __importStar(require('@mysten/sui/utils'))),
571
+ ]);
572
+ const key = bcs
573
+ .struct('RequestKey', { owner: bcs.Address, requestId: bcs.u64() })
574
+ .serialize({ owner: normalizeSuiAddress(owner), requestId })
575
+ .toBytes();
576
+ return deriveObjectID(normalizeSuiAddress(vaultId), `${originalPackageId}::withdrawal::RequestKey`, key);
577
+ }
300
578
  /**
301
579
  * The vault reference for a backend row, or `null` when the row has no usable
302
580
  * `sui_vault_metadata`.
@@ -360,7 +638,7 @@ function buildSuiVault(row, state) {
360
638
  *
361
639
  * A failed read (unknown contract IDs, every endpoint down, an aborted
362
640
  * simulation) does not fail the call: the vault is built from the backend row
363
- * alone (see {@link buildSuiVault}) and a warning is logged.
641
+ * alone (see `buildSuiVault`) and a warning is logged.
364
642
  *
365
643
  * RPC cost: as {@link readSuiVaultState}.
366
644
  *
@@ -10,6 +10,11 @@ import * as SuiConstants from './constants';
10
10
  import * as SuiGetters from './getters';
11
11
  import * as SuiTargets from './targets';
12
12
  import * as SuiUtils from './utils';
13
+ /**
14
+ * Sui helpers by area: chain identity (`utils`), constants, the gRPC client
15
+ * with failover (`client`), move-call targets (`targets`), vault reads
16
+ * (`getters`) and deposit / instant-redeem builders (`actions`).
17
+ */
13
18
  export declare const Sui: {
14
19
  utils: typeof SuiUtils;
15
20
  constants: typeof SuiConstants;
@@ -45,7 +50,7 @@ export interface ISuiAdapterVault {
45
50
  * sdk.sui.isSuiAddress(vault.address);
46
51
  * ```
47
52
  */
48
- declare class SuiAdapter {
53
+ export declare class SuiAdapter {
49
54
  private readonly _config;
50
55
  /**
51
56
  * @param config - Optional Sui settings; omit to target Sui mainnet.
@@ -79,7 +84,8 @@ declare class SuiAdapter {
79
84
  * RPC cost: one dry run (plus the coin lookup it needs).
80
85
  *
81
86
  * @param params - The vault, `amount` in asset base units, the `sender`, and
82
- * an optional `minSharesOut` (defaults to the dry run's exact preview).
87
+ * optionally `minSharesOut` or `slippageBps` (the minimum defaults to the
88
+ * dry run's preview less 0.1%).
83
89
  * @returns The unsigned transaction for the sender's wallet, the shares the
84
90
  * dry run minted, and the minimum it enforces.
85
91
  * @throws {@link UpshiftValidationError} for malformed input, unknown
@@ -95,17 +101,21 @@ declare class SuiAdapter {
95
101
  * amount: 1_000_000n,
96
102
  * sender: account.address,
97
103
  * });
98
- * await dAppKit.signAndExecuteTransaction({ transaction });
104
+ * const digest = await sdk.sui.executeTransaction(
105
+ * await dAppKit.signTransaction({ transaction }),
106
+ * );
99
107
  * ```
100
108
  */
101
109
  vaultDeposit(params: ISuiAdapterVault & {
102
110
  amount: bigint;
103
111
  sender: string;
104
112
  minSharesOut?: bigint;
113
+ slippageBps?: number;
105
114
  }): Promise<SuiActions.ISuiDepositTransaction>;
106
115
  /**
107
- * Build an unsigned instant redemption on the configured network: redeem
108
- * shares with a minimum net asset amount, send the assets to the sender.
116
+ * Build an unsigned instant redemption on the configured network: charge
117
+ * the management fee, redeem shares with a minimum net asset amount, send
118
+ * the assets to the sender.
109
119
  * Dry-runs it first; a vault with a withdrawal queue attached fails with
110
120
  * `queue_attached`.
111
121
  *
@@ -115,8 +125,8 @@ declare class SuiAdapter {
115
125
  * RPC cost: one dry run (plus the coin lookup it needs).
116
126
  *
117
127
  * @param params - The vault, `shares` in share base units, the `sender`, and
118
- * an optional `minAssetsOut` net of the instant fee (defaults to the dry
119
- * run's exact preview).
128
+ * optionally `minAssetsOut` (net of the instant fee) or `slippageBps` (the
129
+ * minimum defaults to the dry run's preview less 0.1%).
120
130
  * @returns The unsigned transaction, the dry run's gross and net assets, and
121
131
  * the minimum it enforces.
122
132
  * @throws {@link UpshiftValidationError} for malformed input, unknown
@@ -128,7 +138,144 @@ declare class SuiAdapter {
128
138
  shares: bigint;
129
139
  sender: string;
130
140
  minAssetsOut?: bigint;
141
+ slippageBps?: number;
131
142
  }): Promise<SuiActions.ISuiRedeemTransaction>;
143
+ /**
144
+ * Build an unsigned withdrawal request on the configured network, for a
145
+ * vault with a withdrawal queue attached (where instant redemption is off).
146
+ * Escrows the shares in a new request; dry-runs it first, so a vault that
147
+ * would reject it fails here.
148
+ *
149
+ * The request is priced when it is claimed. Once the vault's cooldown has
150
+ * run, claim it with {@link SuiAdapter.claimWithdrawal}; cancel it at any
151
+ * time with {@link SuiAdapter.vaultCancelRedeemRequest}. List a wallet's
152
+ * requests with {@link SuiAdapter.getWithdrawalRequests}.
153
+ *
154
+ * RPC cost: one object read for a wallet with up to 23 earlier requests on
155
+ * the vault (one more per further 25), then one dry run.
156
+ *
157
+ * @param params - The vault, `shares` in share base units, the `sender`, and
158
+ * optionally `payout` (defaults to the sender) and `finalizer`: who besides
159
+ * the owner may claim during the first day the request is claimable
160
+ * (anyone may after). Defaults to the owner alone; pass a keeper address,
161
+ * or `null` to let anyone claim as soon as the cooldown ends.
162
+ * @returns The unsigned transaction, the request ID, the request's object ID
163
+ * (`request`) for claiming or cancelling, and `expectedAssets` at today's
164
+ * price.
165
+ * @throws {@link UpshiftValidationError} for malformed input, unknown
166
+ * contract IDs, or a transaction that cannot be built.
167
+ * @throws {@link UpshiftVaultAbortError} when the vault would reject it,
168
+ * e.g. `queue_not_attached` (redeem instantly instead) or `paused`.
169
+ * @throws {@link UpshiftNetworkError} when every Sui endpoint fails.
170
+ * @example
171
+ * ```ts
172
+ * const { transaction, request } = await sdk.sui.vaultRequestRedeem({
173
+ * vaultId: vault.address,
174
+ * assetCoinType: vault.depositAssets[0].address,
175
+ * shareCoinType: vault.receipt.address,
176
+ * shares: 1_000_000n,
177
+ * sender: account.address,
178
+ * });
179
+ * await sdk.sui.executeTransaction(await dAppKit.signTransaction({ transaction }));
180
+ * ```
181
+ */
182
+ vaultRequestRedeem(params: ISuiAdapterVault & {
183
+ shares: bigint;
184
+ sender: string;
185
+ payout?: string;
186
+ finalizer?: string | null;
187
+ }): Promise<SuiActions.ISuiRequestRedeemTransaction>;
188
+ /**
189
+ * Build an unsigned cancellation of a pending withdrawal request on the
190
+ * configured network; the escrowed shares go back to the sender. Allowed at
191
+ * any time while the request exists, also while the vault is paused. Only
192
+ * the wallet that made the request may cancel it.
193
+ *
194
+ * RPC cost: one dry run.
195
+ *
196
+ * @param params - The vault, the `request` object ID and the `sender`.
197
+ * @returns The unsigned transaction and the shares it returns.
198
+ * @throws {@link UpshiftValidationError} for malformed input, unknown
199
+ * contract IDs, or a request that no longer exists.
200
+ * @throws {@link UpshiftVaultAbortError} when the vault would reject it,
201
+ * e.g. `not_request_owner`.
202
+ * @throws {@link UpshiftNetworkError} when every Sui endpoint fails.
203
+ * @example
204
+ * ```ts
205
+ * const { transaction } = await sdk.sui.vaultCancelRedeemRequest({
206
+ * vaultId, assetCoinType, shareCoinType, request, sender: account.address,
207
+ * });
208
+ * ```
209
+ */
210
+ vaultCancelRedeemRequest(params: ISuiAdapterVault & {
211
+ request: string;
212
+ sender: string;
213
+ }): Promise<SuiActions.ISuiCancelRedeemRequestTransaction>;
214
+ /**
215
+ * Build an unsigned claim of a withdrawal request on the configured
216
+ * network: burns the escrowed shares and pays their current value, with no
217
+ * instant fee, to the request's payout.
218
+ *
219
+ * The payout lands in the payout address's address balance, not as a coin
220
+ * object. A request can be claimed from `eligibleAtMs` until `expiresAtMs`
221
+ * by its owner or finalizer (anyone when it names none), and by anyone from
222
+ * one day after it became eligible.
223
+ *
224
+ * RPC cost: one dry run.
225
+ *
226
+ * @param params - The vault, the `request` object ID, the `sender`, and
227
+ * optionally `minAssetsOut` or `slippageBps` (the minimum defaults to the
228
+ * dry run's payout less 0.1%).
229
+ * @returns The unsigned transaction, the shares it burns, the dry run's
230
+ * payout, and the minimum it enforces.
231
+ * @throws {@link UpshiftValidationError} for malformed input, unknown
232
+ * contract IDs, or a request that no longer exists.
233
+ * @throws {@link UpshiftVaultAbortError} when the vault would reject it,
234
+ * e.g. `not_eligible_yet`, `request_expired` or `insufficient_liquidity`.
235
+ * @throws {@link UpshiftNetworkError} when every Sui endpoint fails.
236
+ * @example
237
+ * ```ts
238
+ * const [pending] = await sdk.sui.getWithdrawalRequests({ ...vault, owner: account.address });
239
+ * const { transaction } = await sdk.sui.claimWithdrawal({
240
+ * ...vault, request: pending.request, sender: account.address,
241
+ * });
242
+ * ```
243
+ */
244
+ claimWithdrawal(params: ISuiAdapterVault & {
245
+ request: string;
246
+ sender: string;
247
+ minAssetsOut?: bigint;
248
+ slippageBps?: number;
249
+ }): Promise<SuiActions.ISuiClaimWithdrawalTransaction>;
250
+ /**
251
+ * A wallet's pending withdrawal requests on a vault, on the configured
252
+ * network, oldest first. Finds every request made through the SDK however
253
+ * old; claimed and cancelled requests are left out.
254
+ *
255
+ * RPC cost: one object read for a wallet that has made up to 23 requests on
256
+ * the vault (most wallets), one more per further 25.
257
+ *
258
+ * @param params - The vault and the `owner` wallet.
259
+ * @returns The pending requests, with shares, payout, and the times they
260
+ * become claimable and expire; empty when there are none.
261
+ * @throws {@link UpshiftValidationError} for malformed input, unknown
262
+ * contract IDs, or a vault ID that is not a vault of the configured
263
+ * `sui.originalPackageId`.
264
+ * @throws {@link UpshiftNetworkError} when every Sui endpoint fails.
265
+ * @example
266
+ * ```ts
267
+ * const pending = await sdk.sui.getWithdrawalRequests({
268
+ * vaultId, assetCoinType, shareCoinType, owner: account.address,
269
+ * });
270
+ * const now = Date.now();
271
+ * const claimable = pending.filter(
272
+ * (r) => r.eligibleAtMs <= now && (r.expiresAtMs === null || now < r.expiresAtMs),
273
+ * );
274
+ * ```
275
+ */
276
+ getWithdrawalRequests(params: ISuiAdapterVault & {
277
+ owner: string;
278
+ }): Promise<SuiGetters.ISuiWithdrawalRequest[]>;
132
279
  /**
133
280
  * Execute a wallet-signed transaction on the configured network and wait
134
281
  * until it is indexed. Not needed when the wallet executes the transaction