@gauntlet-xyz/sdk 3.0.1 → 3.1.1

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 (117) hide show
  1. package/README.md +34 -3
  2. package/dist/api/activity.d.ts +3 -1
  3. package/dist/api/activity.d.ts.map +1 -1
  4. package/dist/api/activityRows.d.ts +11 -0
  5. package/dist/api/activityRows.d.ts.map +1 -0
  6. package/dist/api/caip.d.ts.map +1 -1
  7. package/dist/api/client.d.ts.map +1 -1
  8. package/dist/api/decimal.d.ts.map +1 -1
  9. package/dist/api/http.d.ts.map +1 -1
  10. package/dist/api/index.js +7 -8
  11. package/dist/api/positionHistory.d.ts.map +1 -1
  12. package/dist/attribution/index.d.ts +5 -2
  13. package/dist/attribution/index.d.ts.map +1 -1
  14. package/dist/{chunk-HC2BS7MK.js → chunk-JJOLVL5V.js} +113 -6
  15. package/dist/chunk-JJOLVL5V.js.map +7 -0
  16. package/dist/{chunk-S2TTA45N.js → chunk-JRSNLXFY.js} +2 -2
  17. package/dist/{chunk-SU6JAKIA.js → chunk-MEKISE2T.js} +131 -47
  18. package/dist/chunk-MEKISE2T.js.map +7 -0
  19. package/dist/{chunk-7TA2OJUK.js → chunk-YQXTLIJA.js} +209 -96
  20. package/dist/chunk-YQXTLIJA.js.map +7 -0
  21. package/dist/cjs/api/activity.d.ts +3 -1
  22. package/dist/cjs/api/activity.d.ts.map +1 -1
  23. package/dist/cjs/api/activity.js +14 -12
  24. package/dist/cjs/api/activity.js.map +2 -2
  25. package/dist/cjs/api/activityRows.d.ts +11 -0
  26. package/dist/cjs/api/activityRows.d.ts.map +1 -0
  27. package/dist/cjs/api/activityRows.js +139 -0
  28. package/dist/cjs/api/activityRows.js.map +7 -0
  29. package/dist/cjs/api/caip.d.ts.map +1 -1
  30. package/dist/cjs/api/caip.js +3 -1
  31. package/dist/cjs/api/caip.js.map +2 -2
  32. package/dist/cjs/api/client.d.ts.map +1 -1
  33. package/dist/cjs/api/client.js +29 -1
  34. package/dist/cjs/api/client.js.map +2 -2
  35. package/dist/cjs/api/decimal.d.ts.map +1 -1
  36. package/dist/cjs/api/decimal.js +1 -0
  37. package/dist/cjs/api/decimal.js.map +2 -2
  38. package/dist/cjs/api/http.d.ts.map +1 -1
  39. package/dist/cjs/api/http.js +1 -0
  40. package/dist/cjs/api/http.js.map +2 -2
  41. package/dist/cjs/api/positionHistory.d.ts.map +1 -1
  42. package/dist/cjs/api/positionHistory.js +17 -4
  43. package/dist/cjs/api/positionHistory.js.map +2 -2
  44. package/dist/cjs/attribution/index.d.ts +5 -2
  45. package/dist/cjs/attribution/index.d.ts.map +1 -1
  46. package/dist/cjs/attribution/index.js +3 -1
  47. package/dist/cjs/attribution/index.js.map +2 -2
  48. package/dist/cjs/evm/adapters/aera.d.ts.map +1 -1
  49. package/dist/cjs/evm/adapters/aera.js +16 -7
  50. package/dist/cjs/evm/adapters/aera.js.map +2 -2
  51. package/dist/cjs/evm/adapters/types.d.ts +1 -0
  52. package/dist/cjs/evm/adapters/types.d.ts.map +1 -1
  53. package/dist/cjs/evm/adapters/types.js.map +1 -1
  54. package/dist/cjs/evm/aeraContracts.d.ts.map +1 -1
  55. package/dist/cjs/evm/aeraContracts.js +21 -11
  56. package/dist/cjs/evm/aeraContracts.js.map +2 -2
  57. package/dist/cjs/evm/deposit.d.ts +3 -2
  58. package/dist/cjs/evm/deposit.d.ts.map +1 -1
  59. package/dist/cjs/evm/deposit.js +40 -10
  60. package/dist/cjs/evm/deposit.js.map +2 -2
  61. package/dist/cjs/evm/depositQuote.d.ts.map +1 -1
  62. package/dist/cjs/evm/depositQuote.js +1 -0
  63. package/dist/cjs/evm/depositQuote.js.map +2 -2
  64. package/dist/cjs/evm/depositReceiverApproval.d.ts.map +1 -1
  65. package/dist/cjs/evm/depositReceiverApproval.js +14 -9
  66. package/dist/cjs/evm/depositReceiverApproval.js.map +2 -2
  67. package/dist/cjs/evm/userCurrentBalance.d.ts +15 -1
  68. package/dist/cjs/evm/userCurrentBalance.d.ts.map +1 -1
  69. package/dist/cjs/evm/userCurrentBalance.js +94 -51
  70. package/dist/cjs/evm/userCurrentBalance.js.map +2 -2
  71. package/dist/cjs/evm/withdraw.d.ts +2 -0
  72. package/dist/cjs/evm/withdraw.d.ts.map +1 -1
  73. package/dist/cjs/evm/withdraw.js +14 -1
  74. package/dist/cjs/evm/withdraw.js.map +2 -2
  75. package/dist/cjs/evm/withdrawQuote.d.ts.map +1 -1
  76. package/dist/cjs/evm/withdrawQuote.js +1 -0
  77. package/dist/cjs/evm/withdrawQuote.js.map +2 -2
  78. package/dist/evm/adapters/aera.d.ts.map +1 -1
  79. package/dist/evm/adapters/types.d.ts +1 -0
  80. package/dist/evm/adapters/types.d.ts.map +1 -1
  81. package/dist/evm/aeraContracts.d.ts.map +1 -1
  82. package/dist/evm/deposit.d.ts +3 -2
  83. package/dist/evm/deposit.d.ts.map +1 -1
  84. package/dist/evm/depositQuote.d.ts.map +1 -1
  85. package/dist/evm/depositReceiverApproval.d.ts.map +1 -1
  86. package/dist/evm/index.js +6 -8
  87. package/dist/evm/userCurrentBalance.d.ts +15 -1
  88. package/dist/evm/userCurrentBalance.d.ts.map +1 -1
  89. package/dist/evm/withdraw.d.ts +2 -0
  90. package/dist/evm/withdraw.d.ts.map +1 -1
  91. package/dist/evm/withdrawQuote.d.ts.map +1 -1
  92. package/dist/index.js +11 -13
  93. package/dist/privy/index.js +2 -2
  94. package/package.json +1 -1
  95. package/src/api/activity.ts +18 -15
  96. package/src/api/activityRows.ts +143 -0
  97. package/src/api/caip.ts +3 -1
  98. package/src/api/client.ts +36 -1
  99. package/src/api/decimal.ts +1 -0
  100. package/src/api/http.ts +1 -0
  101. package/src/api/positionHistory.ts +20 -5
  102. package/src/attribution/index.ts +6 -2
  103. package/src/evm/adapters/aera.ts +26 -8
  104. package/src/evm/adapters/types.ts +1 -0
  105. package/src/evm/aeraContracts.ts +29 -14
  106. package/src/evm/deposit.ts +43 -12
  107. package/src/evm/depositQuote.ts +1 -0
  108. package/src/evm/depositReceiverApproval.ts +14 -9
  109. package/src/evm/userCurrentBalance.ts +144 -60
  110. package/src/evm/withdraw.ts +20 -1
  111. package/src/evm/withdrawQuote.ts +1 -0
  112. package/dist/chunk-7TA2OJUK.js.map +0 -7
  113. package/dist/chunk-HC2BS7MK.js.map +0 -7
  114. package/dist/chunk-STIV2CC4.js +0 -57
  115. package/dist/chunk-STIV2CC4.js.map +0 -7
  116. package/dist/chunk-SU6JAKIA.js.map +0 -7
  117. /package/dist/{chunk-S2TTA45N.js.map → chunk-JRSNLXFY.js.map} +0 -0
@@ -1,13 +1,28 @@
1
1
  import { parseAbi, type Address } from 'viem';
2
2
  import type { GauntletClient } from '../client';
3
3
  import type { EvmVaultDeployment } from './types';
4
- import { ChainMismatchError, UnsupportedProtocolError, VaultNotFoundError } from '../errors';
4
+ import {
5
+ ChainMismatchError,
6
+ GauntletSDKError,
7
+ UnsupportedAssetError,
8
+ UnsupportedProtocolError,
9
+ VaultNotFoundError,
10
+ } from '../errors';
5
11
  import { getMultiDepositorVault, resolveAeraRuntimeContracts } from './aeraContracts';
6
12
  import { convertUnitsToToken } from './aeraContracts/priceAndFeeCalculator';
7
13
  import { getUserUnitsRefundableUntil } from './aeraContracts/v2';
8
14
  import { provisionerV2Abi } from './abis/provisionerV2';
9
15
  import { ContractVersion } from './types';
10
- import { BLOCKS_3_DAYS, CHAIN_NAMES, DEFAULT_BLOCKS_3_DAYS, LOG_PAGE_SIZE } from '../constants';
16
+ import {
17
+ BLOCKS_3_DAYS,
18
+ CHAIN_NAMES,
19
+ DAY,
20
+ DEFAULT_BLOCKS_3_DAYS,
21
+ LOG_PAGE_SIZE,
22
+ } from '../constants';
23
+
24
+ // Log chunks fetched at once per event type.
25
+ const LOG_CHUNK_CONCURRENCY = 16;
11
26
 
12
27
  // Inline as-const ABI items give viem full type inference for args and return types.
13
28
  const DEPOSIT_REQUESTED_V1_ABI = [
@@ -55,9 +70,20 @@ export interface UserCurrentBalanceParams {
55
70
  vaultId: string;
56
71
  address: Address;
57
72
  chainId?: number;
73
+ /** Required for deployments that support multiple assets, ignored otherwise. */
74
+ assetSymbol?: string;
75
+ /**
76
+ * Scan from this block, including expired requests that still hold escrow.
77
+ * Requires `chainId` for a vault with more than one deployment.
78
+ */
79
+ fromBlock?: bigint;
58
80
  }
59
81
 
60
82
  export interface UserCurrentBalance {
83
+ /** Block used for balances, conversions, and request state. */
84
+ blockNumber: bigint;
85
+ /** First block included in the request scan. Older escrow is outside this result. */
86
+ fromBlock: bigint;
61
87
  /** Chain identifier, e.g. "base" */
62
88
  chain: string;
63
89
  /** EVM chain id of the deployment, e.g. 8453 */
@@ -91,23 +117,77 @@ function dedupeByRequestHash<TLog extends { args: { [key: string]: unknown } }>(
91
117
  });
92
118
  }
93
119
 
120
+ /** Step back by the expected block count, and widen until the block predates the cutoff. */
121
+ async function requestScanStart(
122
+ publicClient: ReturnType<GauntletClient['getPublicClient']>,
123
+ chainId: number,
124
+ blockNumber: bigint,
125
+ days: number,
126
+ cutoff: bigint
127
+ ): Promise<bigint> {
128
+ let span = ((BLOCKS_3_DAYS[chainId] ?? DEFAULT_BLOCKS_3_DAYS) * BigInt(days)) / 3n;
129
+ for (;;) {
130
+ if (span >= blockNumber) return 0n;
131
+ const start = blockNumber - span;
132
+ const block = await publicClient.getBlock({ blockNumber: start });
133
+ if (block.timestamp <= cutoff) return start;
134
+ span *= 2n;
135
+ }
136
+ }
137
+
138
+ async function mapInBatches<T, P extends Promise<unknown>>(
139
+ items: T[],
140
+ size: number,
141
+ fn: (item: T) => P
142
+ ): Promise<Awaited<P>[]> {
143
+ const results: Awaited<P>[] = [];
144
+ for (let i = 0; i < items.length; i += size) {
145
+ results.push(...(await Promise.all(items.slice(i, i + size).map(fn))));
146
+ }
147
+ return results;
148
+ }
149
+
94
150
  async function queryDeploymentBalance(
95
151
  client: GauntletClient,
96
152
  deployment: EvmVaultDeployment,
97
- address: Address
153
+ params: UserCurrentBalanceParams
98
154
  ): Promise<UserCurrentBalance> {
99
155
  const publicClient = client.getPublicClient(deployment.chainId);
100
- const token = deployment.supplyToken[0];
156
+ const { address } = params;
157
+ const token =
158
+ deployment.supplyToken.length > 1
159
+ ? deployment.supplyToken.find((candidate) => candidate.symbol === params.assetSymbol)
160
+ : deployment.supplyToken[0];
161
+ if (token === undefined)
162
+ throw new UnsupportedAssetError(params.assetSymbol ?? 'unknown', params.vaultId);
163
+ const snapshot = await publicClient.getBlock({ blockTag: 'latest' });
164
+ if (snapshot.number === null) {
165
+ throw new GauntletSDKError('The balance snapshot has no block number');
166
+ }
167
+ const blockNumber = snapshot.number;
168
+ const readOptions = { blockNumber };
169
+ const expirationDays = deployment.expirationDays ?? 3;
170
+ if (!Number.isSafeInteger(expirationDays) || expirationDays <= 0) {
171
+ throw new GauntletSDKError('The request expiration must be a positive integer number of days');
172
+ }
173
+ const scanDays = Math.max(3, expirationDays);
174
+ const cutoff = snapshot.timestamp - BigInt(DAY) * BigInt(scanDays);
175
+ const fromBlock =
176
+ params.fromBlock ??
177
+ (await requestScanStart(publicClient, deployment.chainId, blockNumber, scanDays, cutoff));
178
+ if (fromBlock < 0n || fromBlock > blockNumber) {
179
+ throw new GauntletSDKError('The request scan range is invalid');
180
+ }
101
181
 
102
182
  const vaultContract = getMultiDepositorVault(publicClient, deployment.vaultAddress);
103
183
  const [runtime, units] = await Promise.all([
104
- resolveAeraRuntimeContracts(publicClient, deployment),
105
- vaultContract.read.balanceOf([address]),
184
+ resolveAeraRuntimeContracts(publicClient, deployment, readOptions),
185
+ vaultContract.read.balanceOf([address], readOptions),
106
186
  ]);
107
187
  const provisionerAddress = runtime.provisioner.address;
108
188
  const isV2 = runtime.provisioner.version === ContractVersion.V2;
109
189
  const unitsLockedUntilPromise = isV2
110
- ? getUserUnitsRefundableUntil(publicClient, provisionerAddress, address)
190
+ ? getUserUnitsRefundableUntil(publicClient, provisionerAddress, address, readOptions)
111
191
  : Promise.resolve(undefined);
112
192
 
113
193
  const balance = await convertUnitsToToken(
@@ -116,63 +196,56 @@ async function queryDeploymentBalance(
116
196
  runtime.feeCalculator.version,
117
197
  deployment.vaultAddress,
118
198
  token.address,
119
- units
199
+ units,
200
+ readOptions
120
201
  );
121
202
 
122
- // Look back ~3 days for pending async requests
123
- const currentBlock = await publicClient.getBlockNumber();
124
- const lookback = BLOCKS_3_DAYS[deployment.chainId] ?? DEFAULT_BLOCKS_3_DAYS;
125
- const fromBlock = currentBlock > lookback ? currentBlock - lookback : 0n;
126
-
127
- // Compute block-range chunks to stay within the 10,000-block RPC limit, then fetch in parallel
203
+ // Compute block-range chunks to stay within the 10,000-block RPC limit, then fetch in bounded batches
128
204
  const chunks: [bigint, bigint][] = [];
129
- for (let cursor = fromBlock; cursor <= currentBlock; cursor += LOG_PAGE_SIZE + 1n) {
130
- const end = cursor + LOG_PAGE_SIZE <= currentBlock ? cursor + LOG_PAGE_SIZE : currentBlock;
205
+ for (let cursor = fromBlock; cursor <= blockNumber; cursor += LOG_PAGE_SIZE + 1n) {
206
+ const end = cursor + LOG_PAGE_SIZE <= blockNumber ? cursor + LOG_PAGE_SIZE : blockNumber;
131
207
  chunks.push([cursor, end]);
132
208
  }
133
209
 
210
+ // Each map keeps LOG_CHUNK_CONCURRENCY queries in flight.
134
211
  const [depositPages, redeemPages] = await Promise.all([
135
- Promise.all(
136
- chunks.map(([from, to]) =>
137
- isV2
138
- ? publicClient.getContractEvents({
139
- address: provisionerAddress,
140
- abi: provisionerV2Abi,
141
- eventName: 'DepositRequested',
142
- args: { receiver: address },
143
- fromBlock: from,
144
- toBlock: to,
145
- })
146
- : publicClient.getContractEvents({
147
- address: provisionerAddress,
148
- abi: DEPOSIT_REQUESTED_V1_ABI,
149
- eventName: 'DepositRequested',
150
- args: { user: address },
151
- fromBlock: from,
152
- toBlock: to,
153
- })
154
- )
212
+ mapInBatches(chunks, LOG_CHUNK_CONCURRENCY, ([from, to]) =>
213
+ isV2
214
+ ? publicClient.getContractEvents({
215
+ address: provisionerAddress,
216
+ abi: provisionerV2Abi,
217
+ eventName: 'DepositRequested',
218
+ args: { receiver: address, token: token.address },
219
+ fromBlock: from,
220
+ toBlock: to,
221
+ })
222
+ : publicClient.getContractEvents({
223
+ address: provisionerAddress,
224
+ abi: DEPOSIT_REQUESTED_V1_ABI,
225
+ eventName: 'DepositRequested',
226
+ args: { user: address, token: token.address },
227
+ fromBlock: from,
228
+ toBlock: to,
229
+ })
155
230
  ),
156
- Promise.all(
157
- chunks.map(([from, to]) =>
158
- isV2
159
- ? publicClient.getContractEvents({
160
- address: provisionerAddress,
161
- abi: provisionerV2Abi,
162
- eventName: 'RedeemRequested',
163
- args: { user: address },
164
- fromBlock: from,
165
- toBlock: to,
166
- })
167
- : publicClient.getContractEvents({
168
- address: provisionerAddress,
169
- abi: REDEEM_REQUESTED_V1_ABI,
170
- eventName: 'RedeemRequested',
171
- args: { user: address },
172
- fromBlock: from,
173
- toBlock: to,
174
- })
175
- )
231
+ mapInBatches(chunks, LOG_CHUNK_CONCURRENCY, ([from, to]) =>
232
+ isV2
233
+ ? publicClient.getContractEvents({
234
+ address: provisionerAddress,
235
+ abi: provisionerV2Abi,
236
+ eventName: 'RedeemRequested',
237
+ args: { user: address, token: token.address },
238
+ fromBlock: from,
239
+ toBlock: to,
240
+ })
241
+ : publicClient.getContractEvents({
242
+ address: provisionerAddress,
243
+ abi: REDEEM_REQUESTED_V1_ABI,
244
+ eventName: 'RedeemRequested',
245
+ args: { user: address, token: token.address },
246
+ fromBlock: from,
247
+ toBlock: to,
248
+ })
176
249
  ),
177
250
  ]);
178
251
 
@@ -196,6 +269,7 @@ async function queryDeploymentBalance(
196
269
  })),
197
270
  ],
198
271
  allowFailure: false,
272
+ blockNumber,
199
273
  });
200
274
 
201
275
  const depositChecks = pendingChecks.slice(0, depositLogs.length);
@@ -223,12 +297,15 @@ async function queryDeploymentBalance(
223
297
  runtime.feeCalculator.version,
224
298
  deployment.vaultAddress,
225
299
  token.address,
226
- pendingWithdrawUnits
300
+ pendingWithdrawUnits,
301
+ readOptions
227
302
  )
228
303
  : 0n;
229
304
  const unitsLockedUntil = await unitsLockedUntilPromise;
230
305
 
231
306
  return {
307
+ blockNumber,
308
+ fromBlock,
232
309
  chain: CHAIN_NAMES[deployment.chainId] ?? `chain-${deployment.chainId}`,
233
310
  chainId: deployment.chainId,
234
311
  token: token.address,
@@ -249,7 +326,9 @@ async function queryDeploymentBalance(
249
326
  * - `pendingWithdraw` — vault units locked in a pending async redeem request (converted to tokens).
250
327
  *
251
328
  * Only supported for Aera multi-depositor vaults. Pending amounts are detected by scanning
252
- * the last ~3 days of provisioner events and cross-checking hash existence on-chain.
329
+ * the configured request lifetime, with a minimum of three days. Set `fromBlock` (with `chainId`
330
+ * on a multi-chain vault) for older escrow.
331
+ * All state reads use one block. The returned range identifies the scanned history.
253
332
  *
254
333
  * @param client - A configured `GauntletClient` instance with an EVM public client for each
255
334
  * chain the vault is deployed on.
@@ -260,6 +339,7 @@ async function queryDeploymentBalance(
260
339
  * @throws {VaultNotFoundError} If the vault ID is not found in the manifest.
261
340
  * @throws {UnsupportedProtocolError} If the vault is not an Aera multi-depositor vault.
262
341
  * @throws {ChainMismatchError} If `chainId` is specified but no deployment exists for that chain.
342
+ * @throws {UnsupportedAssetError} If a multi-asset deployment gets no matching `assetSymbol`.
263
343
  *
264
344
  * @example
265
345
  * ```ts
@@ -274,6 +354,7 @@ export async function getUserCurrentBalance(
274
354
  client: GauntletClient,
275
355
  params: UserCurrentBalanceParams
276
356
  ): Promise<UserCurrentBalance[]> {
357
+ params = { ...params };
277
358
  const manifest = await client.manifest;
278
359
  const vaultInfo = manifest.vaults.find((v) => v.vaultId === params.vaultId);
279
360
  if (!vaultInfo) throw new VaultNotFoundError(params.vaultId);
@@ -294,8 +375,11 @@ export async function getUserCurrentBalance(
294
375
  evmDeployments.map((d) => `${d.chainId}`).join(', ')
295
376
  );
296
377
  }
297
- return [await queryDeploymentBalance(client, deployment, params.address)];
378
+ return [await queryDeploymentBalance(client, deployment, params)];
379
+ }
380
+ if (params.fromBlock !== undefined && evmDeployments.length > 1) {
381
+ throw new GauntletSDKError('fromBlock requires chainId for a vault with several deployments');
298
382
  }
299
383
 
300
- return Promise.all(evmDeployments.map((d) => queryDeploymentBalance(client, d, params.address)));
384
+ return Promise.all(evmDeployments.map((d) => queryDeploymentBalance(client, d, params)));
301
385
  }
@@ -9,6 +9,7 @@ import {
9
9
  AccountRequiredError,
10
10
  VaultNotFoundError,
11
11
  UnsupportedAssetError,
12
+ UnsupportedFeatureError,
12
13
  InvalidSlippageBPSError,
13
14
  InvalidWithdrawParamsError,
14
15
  } from '../errors';
@@ -49,6 +50,8 @@ export type EvmWithdrawParams = {
49
50
  * Supplying bounds implies `depositMode: 'sync'`; explicit async requests are rejected.
50
51
  */
51
52
  syncWithdrawQuote?: SyncWithdrawQuoteBounds;
53
+ /** Limit a sync withdrawal to the shares reviewed before a rate change. */
54
+ maxShares?: bigint;
52
55
  } & (
53
56
  | { shares: bigint; amount?: never; entireAmount?: never }
54
57
  | { amount: bigint; shares?: never; entireAmount?: never }
@@ -56,6 +59,15 @@ export type EvmWithdrawParams = {
56
59
  );
57
60
 
58
61
  function validateWithdrawParams(params: EvmWithdrawParams) {
62
+ if (params.entireAmount !== undefined && typeof params.entireAmount !== 'boolean') {
63
+ throw new InvalidWithdrawParamsError();
64
+ }
65
+ if (
66
+ (params.amount !== undefined && params.amount < 0n) ||
67
+ (params.shares !== undefined && params.shares < 0n)
68
+ ) {
69
+ throw new InvalidWithdrawParamsError();
70
+ }
59
71
  const modes = [
60
72
  'amount' in params && params.amount != null,
61
73
  'shares' in params && params.shares != null,
@@ -171,6 +183,7 @@ export async function getWithdrawTx(
171
183
  client: GauntletClient,
172
184
  params: EvmWithdrawParams
173
185
  ): Promise<PreparedTx[]> {
186
+ params = structuredClone(params);
174
187
  validateWithdrawParams(params);
175
188
 
176
189
  if (
@@ -196,6 +209,9 @@ export async function getWithdrawTx(
196
209
  }
197
210
 
198
211
  const { vault, protocol } = resolved;
212
+ if (params.maxShares !== undefined && protocol !== 'aera') {
213
+ throw new UnsupportedFeatureError('maxShares requires an Aera sync withdrawal');
214
+ }
199
215
 
200
216
  const token =
201
217
  vault.supplyToken.length > 1
@@ -267,6 +283,7 @@ export async function getWithdrawTx(
267
283
  maxPriceAge: params.maxPriceAge,
268
284
  aeraRuntime,
269
285
  syncWithdrawQuote: params.syncWithdrawQuote,
286
+ maxShares: params.maxShares,
270
287
  ...('shares' in params && params.shares != null ? { shares: params.shares } : {}),
271
288
  ...('amount' in params && params.amount != null ? { amount: params.amount } : {}),
272
289
  ...('entireAmount' in params && params.entireAmount ? { entireAmount: true as const } : {}),
@@ -274,5 +291,7 @@ export async function getWithdrawTx(
274
291
 
275
292
  const steps = await adapter.buildWithdraw(withdrawParams as AdapterWithdrawParams);
276
293
 
277
- return await Promise.all(steps.map((step) => encodeTransactionWithAttribution(client, step)));
294
+ return await Promise.all(
295
+ steps.map((step) => encodeTransactionWithAttribution(client, step, chainId))
296
+ );
278
297
  }
@@ -255,6 +255,7 @@ export async function getSyncWithdrawQuote(
255
255
  client: GauntletClient,
256
256
  params: SyncWithdrawQuoteParams
257
257
  ): Promise<SyncWithdrawQuote> {
258
+ params = structuredClone(params);
258
259
  validateSyncWithdrawQuoteParams(params);
259
260
 
260
261
  if (