@gauntlet-xyz/sdk 1.0.5 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/dist/constants.d.ts +16 -0
  2. package/dist/constants.d.ts.map +1 -0
  3. package/dist/constants.js +28 -0
  4. package/dist/constants.js.map +1 -0
  5. package/dist/errors.d.ts +18 -3
  6. package/dist/errors.d.ts.map +1 -1
  7. package/dist/errors.js +20 -2
  8. package/dist/errors.js.map +1 -1
  9. package/dist/evm/abis/priceAndFeeCalculatorV2.d.ts +233 -0
  10. package/dist/evm/abis/priceAndFeeCalculatorV2.d.ts.map +1 -0
  11. package/dist/evm/abis/priceAndFeeCalculatorV2.js +119 -0
  12. package/dist/evm/abis/priceAndFeeCalculatorV2.js.map +1 -0
  13. package/dist/evm/abis/provisionerV2.d.ts +460 -0
  14. package/dist/evm/abis/provisionerV2.d.ts.map +1 -0
  15. package/dist/evm/abis/provisionerV2.js +203 -0
  16. package/dist/evm/abis/provisionerV2.js.map +1 -0
  17. package/dist/evm/adapters/aera.d.ts +3 -3
  18. package/dist/evm/adapters/aera.d.ts.map +1 -1
  19. package/dist/evm/adapters/aera.js +179 -103
  20. package/dist/evm/adapters/aera.js.map +1 -1
  21. package/dist/evm/adapters/types.d.ts +12 -1
  22. package/dist/evm/adapters/types.d.ts.map +1 -1
  23. package/dist/evm/aeraContracts/priceAndFeeCalculator.d.ts +41 -0
  24. package/dist/evm/aeraContracts/priceAndFeeCalculator.d.ts.map +1 -0
  25. package/dist/evm/aeraContracts/priceAndFeeCalculator.js +140 -0
  26. package/dist/evm/aeraContracts/priceAndFeeCalculator.js.map +1 -0
  27. package/dist/evm/aeraContracts/v1.d.ts +2317 -0
  28. package/dist/evm/aeraContracts/v1.d.ts.map +1 -0
  29. package/dist/evm/aeraContracts/v1.js +59 -0
  30. package/dist/evm/aeraContracts/v1.js.map +1 -0
  31. package/dist/evm/aeraContracts/v2.d.ts +2802 -0
  32. package/dist/evm/aeraContracts/v2.d.ts.map +1 -0
  33. package/dist/evm/aeraContracts/v2.js +217 -0
  34. package/dist/evm/aeraContracts/v2.js.map +1 -0
  35. package/dist/evm/aeraContracts.d.ts +23 -2316
  36. package/dist/evm/aeraContracts.d.ts.map +1 -1
  37. package/dist/evm/aeraContracts.js +117 -24
  38. package/dist/evm/aeraContracts.js.map +1 -1
  39. package/dist/evm/deposit.d.ts +5 -1
  40. package/dist/evm/deposit.d.ts.map +1 -1
  41. package/dist/evm/deposit.js +28 -14
  42. package/dist/evm/deposit.js.map +1 -1
  43. package/dist/evm/depositReceiverApproval.d.ts +17 -0
  44. package/dist/evm/depositReceiverApproval.d.ts.map +1 -0
  45. package/dist/evm/depositReceiverApproval.js +32 -0
  46. package/dist/evm/depositReceiverApproval.js.map +1 -0
  47. package/dist/evm/index.d.ts +8 -1
  48. package/dist/evm/index.d.ts.map +1 -1
  49. package/dist/evm/index.js +4 -0
  50. package/dist/evm/index.js.map +1 -1
  51. package/dist/evm/operationMode.d.ts +9 -0
  52. package/dist/evm/operationMode.d.ts.map +1 -0
  53. package/dist/evm/operationMode.js +41 -0
  54. package/dist/evm/operationMode.js.map +1 -0
  55. package/dist/evm/types.d.ts +7 -3
  56. package/dist/evm/types.d.ts.map +1 -1
  57. package/dist/evm/types.js +4 -1
  58. package/dist/evm/types.js.map +1 -1
  59. package/dist/evm/userCurrentBalance.d.ts.map +1 -1
  60. package/dist/evm/userCurrentBalance.js +68 -58
  61. package/dist/evm/userCurrentBalance.js.map +1 -1
  62. package/dist/evm/withdraw.d.ts +5 -1
  63. package/dist/evm/withdraw.d.ts.map +1 -1
  64. package/dist/evm/withdraw.js +25 -13
  65. package/dist/evm/withdraw.js.map +1 -1
  66. package/dist/index.d.ts +8 -1
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.js +5 -1
  69. package/dist/index.js.map +1 -1
  70. package/manifest/vaults.json +31 -139
  71. package/package.json +1 -1
  72. package/src/constants.ts +32 -0
  73. package/src/errors.ts +44 -5
  74. package/src/evm/abis/priceAndFeeCalculatorV2.ts +118 -0
  75. package/src/evm/abis/provisionerV2.ts +202 -0
  76. package/src/evm/adapters/aera.ts +419 -137
  77. package/src/evm/adapters/types.ts +19 -1
  78. package/src/evm/aeraContracts/priceAndFeeCalculator.ts +223 -0
  79. package/src/evm/aeraContracts/v1.ts +157 -0
  80. package/src/evm/aeraContracts/v2.ts +466 -0
  81. package/src/evm/aeraContracts.ts +173 -52
  82. package/src/evm/deposit.ts +48 -16
  83. package/src/evm/depositReceiverApproval.ts +51 -0
  84. package/src/evm/index.ts +23 -1
  85. package/src/evm/operationMode.ts +60 -0
  86. package/src/evm/types.ts +9 -3
  87. package/src/evm/userCurrentBalance.ts +80 -55
  88. package/src/evm/withdraw.ts +42 -15
  89. package/src/index.ts +19 -0
@@ -1,14 +1,18 @@
1
1
  import { erc20Abi } from '../abis/erc20';
2
2
  import {
3
- requestDepositTxRequest,
4
- requestRedeemTxRequest,
5
3
  getMultiDepositorVault,
6
- getPriceAndFeeCalculator,
4
+ applySlippageDown,
5
+ applySlippageUp,
6
+ resolveContractVersion,
7
+ type AeraRuntimeContracts,
7
8
  } from '../aeraContracts';
9
+ import { convertTokenToUnits, convertUnitsToToken } from '../aeraContracts/priceAndFeeCalculator';
10
+ import * as provisionerV1 from '../aeraContracts/v1';
11
+ import * as provisionerV2 from '../aeraContracts/v2';
8
12
  import {
9
13
  InvalidWithdrawParamsError,
14
+ InvalidSolverTipError,
10
15
  UnimplementedFeatureError,
11
- UnitConversionError,
12
16
  UnsupportedFeatureError,
13
17
  } from '../../errors';
14
18
  import type {
@@ -19,42 +23,45 @@ import type {
19
23
  AllowanceParams,
20
24
  ApprovalParams,
21
25
  } from './types';
22
- import { PublicClient, type Address } from 'viem';
26
+ import type { Address, PublicClient } from 'viem';
23
27
  import { multiDepositorVaultAbi } from '../abis/multiDepositorVault';
24
-
25
- const SECOND = 1;
26
- const MINUTE = SECOND * 60;
27
- const HOUR = MINUTE * 60;
28
- const DAY = HOUR * 24;
29
-
30
- export const getAeraV3VaultUnits = async (
28
+ import {
29
+ DEFAULT_BPS,
30
+ DAY,
31
+ DEFAULT_MAX_PRICE_AGE,
32
+ DEFAULT_REQUEST_DEADLINE_BUFFER,
33
+ DEFAULT_SOLVER_TIP,
34
+ } from '../../constants';
35
+ import { ContractVersion } from '../types';
36
+
37
+ export const convertTokenAmountToUnits = async (
31
38
  publicClient: PublicClient,
32
- tokenUnits: bigint,
39
+ tokenAmount: bigint,
33
40
  vaultAddress: Address,
34
41
  tokenAddress: Address
35
42
  ) => {
36
43
  const vaultContract = getMultiDepositorVault(publicClient, vaultAddress);
37
-
38
44
  if (vaultContract === undefined) return;
39
45
 
40
46
  const calculatorAddress = await vaultContract.read.feeCalculator();
41
-
42
47
  if (!calculatorAddress) return;
48
+ const calculatorVersion = await resolveContractVersion(publicClient, calculatorAddress);
43
49
 
44
- const calculatorContract = getPriceAndFeeCalculator(publicClient, calculatorAddress);
45
-
46
- const vaultUnits = await calculatorContract.read.convertTokenToUnits([
50
+ const unitsAmount = await convertTokenToUnits(
51
+ publicClient,
52
+ calculatorAddress,
53
+ calculatorVersion,
47
54
  vaultAddress,
48
55
  tokenAddress,
49
- tokenUnits,
50
- ]);
56
+ tokenAmount
57
+ );
51
58
 
52
- return vaultUnits;
59
+ return unitsAmount;
53
60
  };
54
61
 
55
- export const getAeraV3TokenUnits = async (
62
+ export const convertUnitsToTokenAmount = async (
56
63
  publicClient: PublicClient,
57
- vaultUnits: bigint,
64
+ unitsAmount: bigint,
58
65
  vaultAddress: Address,
59
66
  tokenAddress: Address
60
67
  ) => {
@@ -63,59 +70,227 @@ export const getAeraV3TokenUnits = async (
63
70
 
64
71
  const calculatorAddress = await vaultContract.read.feeCalculator();
65
72
  if (!calculatorAddress) return;
73
+ const calculatorVersion = await resolveContractVersion(publicClient, calculatorAddress);
66
74
 
67
- const calculatorContract = getPriceAndFeeCalculator(publicClient, calculatorAddress);
68
-
69
- return calculatorContract.read.convertUnitsToToken([vaultAddress, tokenAddress, vaultUnits]);
75
+ return convertUnitsToToken(
76
+ publicClient,
77
+ calculatorAddress,
78
+ calculatorVersion,
79
+ vaultAddress,
80
+ tokenAddress,
81
+ unitsAmount
82
+ );
70
83
  };
71
84
 
85
+ function subtractSolverTip(tokenAmount: bigint, solverTip: bigint): bigint {
86
+ if (solverTip === 0n) return tokenAmount;
87
+ if (solverTip >= tokenAmount) {
88
+ throw new InvalidSolverTipError(solverTip, tokenAmount);
89
+ }
90
+
91
+ return tokenAmount - solverTip;
92
+ }
93
+
94
+ function getRequestDeadline(expirationDays?: number): bigint {
95
+ const deadlineBuffer =
96
+ expirationDays === undefined ? DEFAULT_REQUEST_DEADLINE_BUFFER : DAY * expirationDays;
97
+ return BigInt(Math.ceil(new Date().getTime() / 1000) + deadlineBuffer);
98
+ }
99
+
100
+ async function getDepositUnitsOut({
101
+ publicClient,
102
+ runtime,
103
+ vault,
104
+ token,
105
+ tokensIn,
106
+ isAsync,
107
+ }: {
108
+ publicClient: PublicClient;
109
+ runtime: AeraRuntimeContracts;
110
+ vault: Address;
111
+ token: Address;
112
+ tokensIn: bigint;
113
+ isAsync: boolean;
114
+ }): Promise<bigint> {
115
+ if (runtime.provisioner.version === ContractVersion.V2) {
116
+ return isAsync
117
+ ? provisionerV2.getAsyncDepositUnitsOut(
118
+ publicClient,
119
+ runtime.provisioner.address,
120
+ runtime.feeCalculator.address,
121
+ runtime.feeCalculator.version,
122
+ vault,
123
+ token,
124
+ tokensIn
125
+ )
126
+ : provisionerV2.getSyncDepositUnitsOut(
127
+ publicClient,
128
+ runtime.provisioner.address,
129
+ runtime.feeCalculator.address,
130
+ runtime.feeCalculator.version,
131
+ vault,
132
+ token,
133
+ tokensIn
134
+ );
135
+ }
136
+
137
+ return provisionerV1.getAsyncDepositUnitsOut(
138
+ publicClient,
139
+ runtime.provisioner.address,
140
+ runtime.feeCalculator.address,
141
+ runtime.feeCalculator.version,
142
+ vault,
143
+ token,
144
+ tokensIn
145
+ );
146
+ }
147
+
148
+ function getAsyncRedeemTokenOut(
149
+ publicClient: PublicClient,
150
+ runtime: AeraRuntimeContracts,
151
+ vault: Address,
152
+ token: Address,
153
+ unitsIn: bigint
154
+ ): Promise<bigint> {
155
+ return runtime.provisioner.version === ContractVersion.V2
156
+ ? provisionerV2.getAsyncRedeemTokenOut(
157
+ publicClient,
158
+ runtime.provisioner.address,
159
+ runtime.feeCalculator.address,
160
+ runtime.feeCalculator.version,
161
+ vault,
162
+ token,
163
+ unitsIn
164
+ )
165
+ : provisionerV1.getAsyncRedeemTokenOut(
166
+ publicClient,
167
+ runtime.provisioner.address,
168
+ runtime.feeCalculator.address,
169
+ runtime.feeCalculator.version,
170
+ vault,
171
+ token,
172
+ unitsIn
173
+ );
174
+ }
175
+
176
+ function getAsyncWithdrawUnitsIn(
177
+ publicClient: PublicClient,
178
+ runtime: AeraRuntimeContracts,
179
+ vault: Address,
180
+ token: Address,
181
+ tokensOut: bigint
182
+ ): Promise<bigint> {
183
+ return runtime.provisioner.version === ContractVersion.V2
184
+ ? provisionerV2.getAsyncWithdrawUnitsIn(
185
+ publicClient,
186
+ runtime.provisioner.address,
187
+ runtime.feeCalculator.address,
188
+ runtime.feeCalculator.version,
189
+ vault,
190
+ token,
191
+ tokensOut
192
+ )
193
+ : provisionerV1.getAsyncWithdrawUnitsIn(
194
+ publicClient,
195
+ runtime.provisioner.address,
196
+ runtime.feeCalculator.address,
197
+ runtime.feeCalculator.version,
198
+ vault,
199
+ token,
200
+ tokensOut
201
+ );
202
+ }
203
+
204
+ function requireAeraRuntime(runtime: AeraRuntimeContracts | undefined): AeraRuntimeContracts {
205
+ if (!runtime) {
206
+ throw new UnsupportedFeatureError('Aera: runtime contracts were not resolved');
207
+ }
208
+
209
+ return runtime;
210
+ }
211
+
72
212
  export const aeraAdapter: EvmProtocolAdapter = {
73
213
  async buildDeposit(params: AdapterDepositParams): Promise<EvmTxStep[]> {
74
- const { vault, receiver, amount, account, publicClient, asset, async: isAsync, slippageBps = 100 } = params;
75
-
76
- if (receiver !== account) {
77
- throw new UnsupportedFeatureError('Aera: separate receiver address');
214
+ const {
215
+ vault,
216
+ receiver,
217
+ amount,
218
+ account,
219
+ publicClient,
220
+ asset,
221
+ async: isAsync,
222
+ slippageBps = DEFAULT_BPS,
223
+ solverTip = DEFAULT_SOLVER_TIP,
224
+ maxPriceAge = DEFAULT_MAX_PRICE_AGE,
225
+ aeraRuntime,
226
+ } = params;
227
+
228
+ const runtime = requireAeraRuntime(aeraRuntime);
229
+ const provisionerAddress = runtime.provisioner.address;
230
+ const isContractV2 = runtime.provisioner.version === ContractVersion.V2;
231
+ if (receiver !== account && !isContractV2) {
232
+ throw new UnsupportedFeatureError('Aera: separate receiver address on V1');
78
233
  }
79
234
 
80
- if (!vault.provisionerAddress) {
81
- // Not implemented because untested and clients won't need in V1
82
- throw new UnimplementedFeatureError('Aera: single depositor vaults');
83
- // single-depositor vault
84
- /*return [
85
- {
86
- type: 'deposit',
87
- // SDK only supports single asset deposit
88
- ...depositTxRequest(vault.vaultAddress, [{ asset: asset.address, amount }], account),
89
- },
90
- ];*/
235
+ if (!isAsync && !isContractV2) {
236
+ throw new UnsupportedFeatureError('Aera: sync operations on V1');
91
237
  }
92
238
 
93
- if (isAsync) {
94
- const vaultUnits = await getAeraV3VaultUnits(
95
- publicClient,
96
- amount,
97
- vault.vaultAddress,
98
- asset.address
99
- );
239
+ const tokensInForUnits = isAsync ? subtractSolverTip(amount, solverTip) : amount;
240
+ const vaultUnits = await getDepositUnitsOut({
241
+ publicClient,
242
+ runtime,
243
+ vault: vault.vaultAddress,
244
+ token: asset.address,
245
+ tokensIn: tokensInForUnits,
246
+ isAsync,
247
+ });
100
248
 
101
- if (vaultUnits === undefined) {
102
- throw new UnitConversionError(vault.vaultAddress);
103
- }
249
+ const minUnitsOut = applySlippageDown(vaultUnits, slippageBps);
104
250
 
105
- const deadline = BigInt(Math.ceil(new Date().getTime() / 1000) + DAY * 3);
106
- // Request deposit
251
+ if (isAsync) {
252
+ const deadline = getRequestDeadline(vault.expirationDays);
107
253
  return [
108
254
  {
109
255
  type: 'requestDeposit',
110
- ...requestDepositTxRequest(
111
- vault.provisionerAddress,
256
+ ...(isContractV2
257
+ ? provisionerV2.requestDepositTxRequest(
258
+ provisionerAddress,
259
+ asset.address,
260
+ amount,
261
+ minUnitsOut,
262
+ solverTip,
263
+ deadline,
264
+ maxPriceAge,
265
+ false,
266
+ receiver,
267
+ account
268
+ )
269
+ : provisionerV1.requestDepositTxRequest(
270
+ provisionerAddress,
271
+ asset.address,
272
+ amount,
273
+ minUnitsOut,
274
+ solverTip,
275
+ deadline,
276
+ maxPriceAge,
277
+ false,
278
+ account
279
+ )),
280
+ },
281
+ ];
282
+ }
283
+
284
+ if (isContractV2) {
285
+ return [
286
+ {
287
+ type: 'deposit',
288
+ ...provisionerV2.depositTxRequest(
289
+ provisionerAddress,
112
290
  asset.address,
113
291
  amount,
114
- (vaultUnits * BigInt(10000 - slippageBps)) / 10000n, // minUnitsOut
115
- 0n, // solvertip
116
- deadline,
117
- BigInt(DAY * 10),
118
- false,
292
+ minUnitsOut,
293
+ receiver,
119
294
  account
120
295
  ),
121
296
  },
@@ -126,107 +301,214 @@ export const aeraAdapter: EvmProtocolAdapter = {
126
301
  },
127
302
 
128
303
  async buildWithdraw(params: AdapterWithdrawParams): Promise<EvmTxStep[]> {
129
- const { vault, receiver, account, asset, publicClient, async: isAsync, slippageBps = 100 } = params;
130
-
131
- if (receiver !== account) {
132
- throw new UnsupportedFeatureError('Aera: separate receiver address');
304
+ const {
305
+ vault,
306
+ receiver,
307
+ account,
308
+ asset,
309
+ publicClient,
310
+ async: isAsync,
311
+ slippageBps = DEFAULT_BPS,
312
+ solverTip = DEFAULT_SOLVER_TIP,
313
+ maxPriceAge = DEFAULT_MAX_PRICE_AGE,
314
+ aeraRuntime,
315
+ } = params;
316
+
317
+ const runtime = requireAeraRuntime(aeraRuntime);
318
+ const provisionerAddress = runtime.provisioner.address;
319
+ const isContractV2 = runtime.provisioner.version === ContractVersion.V2;
320
+ if (receiver !== account && !isContractV2) {
321
+ throw new UnsupportedFeatureError('Aera: separate receiver address on V1');
133
322
  }
134
323
 
135
- let shares: bigint;
136
- let amount: bigint | undefined;
324
+ if (!isAsync && !isContractV2) {
325
+ throw new UnsupportedFeatureError('Aera: sync operations on V1');
326
+ }
137
327
 
138
- if ('entireAmount' in params && params.entireAmount) {
139
- shares = await publicClient.readContract({
140
- address: vault.vaultAddress,
141
- abi: multiDepositorVaultAbi,
142
- functionName: 'balanceOf',
143
- args: [account],
144
- });
145
- amount = await getAeraV3TokenUnits(publicClient, shares, vault.vaultAddress, asset.address);
146
- } else if ('amount' in params && params.amount != null) {
147
- const tempShares = await getAeraV3VaultUnits(
148
- publicClient,
149
- params.amount,
150
- vault.vaultAddress,
151
- asset.address
152
- );
153
- amount = params.amount;
154
- if (tempShares === undefined) {
155
- throw new UnitConversionError(vault.vaultAddress);
328
+ const isV2ExactTokenWithdraw =
329
+ isContractV2 && !isAsync && 'amount' in params && params.amount != null;
330
+ let minTokenOut: bigint;
331
+ let maxUnitsIn: bigint;
332
+ let shares: bigint | undefined;
333
+
334
+ if (isContractV2 && !isAsync) {
335
+ if ('entireAmount' in params && params.entireAmount) {
336
+ shares = await publicClient.readContract({
337
+ address: vault.vaultAddress,
338
+ abi: multiDepositorVaultAbi,
339
+ functionName: 'balanceOf',
340
+ args: [account],
341
+ });
342
+ } else if ('shares' in params && params.shares != null) {
343
+ shares = params.shares;
344
+ } else if (!('amount' in params && params.amount != null)) {
345
+ throw new InvalidWithdrawParamsError();
156
346
  }
157
- shares = tempShares;
158
- } else if ('shares' in params && params.shares != null) {
159
- shares = params.shares;
160
- amount = await getAeraV3TokenUnits(publicClient, shares, vault.vaultAddress, asset.address);
161
- } else {
162
- throw new InvalidWithdrawParamsError();
163
- }
164
347
 
165
- if (!vault.provisionerAddress) {
166
- // Not implemented because untested and clients won't need in V1
167
- throw new UnimplementedFeatureError('Aera: single depositor vaults');
168
- //single-depositer vault
169
- // TODO shares or amount ??
170
- /*return [
171
- {
172
- type: 'withdraw',
173
- // SDK only supports single asset deposit
174
- ...withdrawTxRequest(
348
+ if (isV2ExactTokenWithdraw) {
349
+ minTokenOut = applySlippageDown(params.amount, slippageBps);
350
+ maxUnitsIn = applySlippageUp(
351
+ await provisionerV2.getSyncWithdrawUnitsIn(
352
+ publicClient,
353
+ provisionerAddress,
354
+ runtime.feeCalculator.address,
355
+ runtime.feeCalculator.version,
175
356
  vault.vaultAddress,
176
- [{ asset: asset.address, amount: shares }],
177
- account
357
+ asset.address,
358
+ params.amount
178
359
  ),
179
- },
180
- ];*/
181
- }
182
-
183
- const { sufficient } = await this.checkAllowance({
184
- publicClient,
185
- token: vault.vaultAddress,
186
- owner: account,
187
- spender: vault.provisionerAddress,
188
- amount: shares,
189
- });
190
-
191
- const steps: EvmTxStep[] = [];
360
+ slippageBps
361
+ );
362
+ } else {
363
+ if (shares === undefined) {
364
+ throw new InvalidWithdrawParamsError();
365
+ }
366
+
367
+ minTokenOut = applySlippageDown(
368
+ await provisionerV2.getSyncRedeemTokenOut(
369
+ publicClient,
370
+ provisionerAddress,
371
+ runtime.feeCalculator.address,
372
+ runtime.feeCalculator.version,
373
+ vault.vaultAddress,
374
+ asset.address,
375
+ shares
376
+ ),
377
+ slippageBps
378
+ );
379
+ maxUnitsIn = applySlippageUp(shares, slippageBps);
380
+ }
381
+ } else {
382
+ if ('entireAmount' in params && params.entireAmount) {
383
+ shares = await publicClient.readContract({
384
+ address: vault.vaultAddress,
385
+ abi: multiDepositorVaultAbi,
386
+ functionName: 'balanceOf',
387
+ args: [account],
388
+ });
389
+ } else if ('amount' in params && params.amount != null) {
390
+ shares = await getAsyncWithdrawUnitsIn(
391
+ publicClient,
392
+ runtime,
393
+ vault.vaultAddress,
394
+ asset.address,
395
+ params.amount + solverTip
396
+ );
397
+ } else if ('shares' in params && params.shares != null) {
398
+ shares = params.shares;
399
+ } else {
400
+ throw new InvalidWithdrawParamsError();
401
+ }
192
402
 
193
- if (!sufficient) {
194
- steps.push(
195
- this.buildApproval({
196
- token: vault.vaultAddress,
197
- spender: vault.provisionerAddress,
198
- amount: shares,
199
- account,
200
- })
403
+ const tokenOutBeforeTip = await getAsyncRedeemTokenOut(
404
+ publicClient,
405
+ runtime,
406
+ vault.vaultAddress,
407
+ asset.address,
408
+ shares
201
409
  );
410
+ minTokenOut = applySlippageDown(subtractSolverTip(tokenOutBeforeTip, solverTip), slippageBps);
411
+ maxUnitsIn = shares;
202
412
  }
203
413
 
414
+ const steps: EvmTxStep[] = [];
415
+
204
416
  if (isAsync) {
205
- // Request redeem
206
- const deadline = BigInt(Math.ceil(new Date().getTime() / 1000) + DAY * 3);
207
- if (amount === undefined) {
208
- throw new UnitConversionError(vault.vaultAddress);
417
+ if (shares === undefined) {
418
+ throw new InvalidWithdrawParamsError();
209
419
  }
420
+
421
+ // Only async requestRedeem needs a vault unit allowance: the provisioner
422
+ // pulls units from the user. V2 sync redeem/withdraw exits through the
423
+ // vault and burns the caller's units directly, so no approval is needed.
424
+ const { sufficient } = await this.checkAllowance({
425
+ publicClient,
426
+ token: vault.vaultAddress,
427
+ owner: account,
428
+ spender: provisionerAddress,
429
+ amount: shares,
430
+ });
431
+
432
+ if (!sufficient) {
433
+ steps.push(
434
+ this.buildApproval({
435
+ token: vault.vaultAddress,
436
+ spender: provisionerAddress,
437
+ amount: shares,
438
+ account,
439
+ })
440
+ );
441
+ }
442
+
443
+ const deadline = getRequestDeadline(vault.expirationDays);
444
+
210
445
  return [
211
446
  ...steps,
212
447
  {
213
448
  type: 'requestRedeem',
214
- ...requestRedeemTxRequest(
215
- vault.provisionerAddress,
449
+ ...(isContractV2
450
+ ? provisionerV2.requestRedeemTxRequest(
451
+ provisionerAddress,
452
+ asset.address,
453
+ shares,
454
+ minTokenOut,
455
+ solverTip,
456
+ deadline,
457
+ maxPriceAge,
458
+ false,
459
+ receiver,
460
+ account
461
+ )
462
+ : provisionerV1.requestRedeemTxRequest(
463
+ provisionerAddress,
464
+ asset.address,
465
+ shares,
466
+ minTokenOut,
467
+ solverTip,
468
+ deadline,
469
+ maxPriceAge,
470
+ false,
471
+ account
472
+ )),
473
+ },
474
+ ];
475
+ }
476
+
477
+ if ('amount' in params && params.amount != null) {
478
+ return [
479
+ ...steps,
480
+ {
481
+ type: 'withdraw',
482
+ ...provisionerV2.withdrawTxRequest(
483
+ provisionerAddress,
216
484
  asset.address,
217
- shares,
218
- (amount * BigInt(10000 - slippageBps)) / 10000n, // minUnitsOut
219
- 0n, // solvertip
220
- deadline,
221
- BigInt(DAY * 10),
222
- false,
485
+ params.amount,
486
+ maxUnitsIn,
487
+ receiver,
223
488
  account
224
489
  ),
225
490
  },
226
491
  ];
227
492
  }
228
493
 
229
- throw new UnimplementedFeatureError('Aera Sync Operations');
494
+ if (shares === undefined) {
495
+ throw new InvalidWithdrawParamsError();
496
+ }
497
+
498
+ return [
499
+ ...steps,
500
+ {
501
+ type: 'redeem',
502
+ ...provisionerV2.redeemTxRequest(
503
+ provisionerAddress,
504
+ asset.address,
505
+ shares,
506
+ minTokenOut,
507
+ receiver,
508
+ account
509
+ ),
510
+ },
511
+ ];
230
512
  },
231
513
 
232
514
  async checkAllowance(params: AllowanceParams) {
@@ -1,8 +1,16 @@
1
1
  import type { Abi, Address, Hex, PublicClient } from 'viem';
2
+ import type { AeraRuntimeContracts } from '../aeraContracts';
2
3
  import type { TokenInfo, VaultDeployment } from '../types';
3
4
 
4
5
  export interface EvmTxStep<TAbi extends Abi = Abi, TFunctionName extends string = string> {
5
- type: 'approve' | 'deposit' | 'requestDeposit' | 'redeem' | 'requestRedeem' | 'withdraw';
6
+ type:
7
+ | 'approve'
8
+ | 'deposit'
9
+ | 'requestDeposit'
10
+ | 'redeem'
11
+ | 'requestRedeem'
12
+ | 'setDepositReceiverApproval'
13
+ | 'withdraw';
6
14
  address: Address;
7
15
  abi: TAbi;
8
16
  functionName: TFunctionName;
@@ -24,6 +32,11 @@ export interface AdapterDepositParams {
24
32
  publicClient: PublicClient;
25
33
  /** Slippage tolerance in basis points (e.g. 100 = 1%). Defaults to 100. */
26
34
  slippageBps?: number;
35
+ /** Solver tip passed to async Aera provisioner requests. Defaults to 0. */
36
+ solverTip?: bigint;
37
+ /** Maximum price age passed to async Aera provisioner requests. Defaults to 10 days. */
38
+ maxPriceAge?: bigint;
39
+ aeraRuntime?: AeraRuntimeContracts;
27
40
  }
28
41
 
29
42
  export type AdapterWithdrawParams = {
@@ -35,6 +48,11 @@ export type AdapterWithdrawParams = {
35
48
  publicClient: PublicClient;
36
49
  /** Slippage tolerance in basis points (e.g. 100 = 1%). Defaults to 100. */
37
50
  slippageBps?: number;
51
+ /** Solver tip passed to async Aera provisioner requests. Defaults to 0. */
52
+ solverTip?: bigint;
53
+ /** Maximum price age passed to async Aera provisioner requests. Defaults to 10 days. */
54
+ maxPriceAge?: bigint;
55
+ aeraRuntime?: AeraRuntimeContracts;
38
56
  } & (
39
57
  | { shares: bigint; amount?: never; entireAmount?: never }
40
58
  | { amount: bigint; shares?: never; entireAmount?: never }