@gauntlet-xyz/sdk 2.3.0 → 2.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.
- package/README.md +52 -0
- package/dist/api/client.d.ts +22 -1
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +11 -1
- package/dist/api/client.js.map +1 -1
- package/dist/api/generated.d.ts +51 -7
- package/dist/api/generated.d.ts.map +1 -1
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js.map +1 -1
- package/dist/errors.d.ts +11 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +21 -2
- package/dist/errors.js.map +1 -1
- package/dist/evm/abis/priceAndFeeCalculatorV2.d.ts +44 -0
- package/dist/evm/abis/priceAndFeeCalculatorV2.d.ts.map +1 -1
- package/dist/evm/abis/priceAndFeeCalculatorV2.js +22 -0
- package/dist/evm/abis/priceAndFeeCalculatorV2.js.map +1 -1
- package/dist/evm/abis/provisionerV2.d.ts +56 -0
- package/dist/evm/abis/provisionerV2.d.ts.map +1 -1
- package/dist/evm/abis/provisionerV2.js +33 -0
- package/dist/evm/abis/provisionerV2.js.map +1 -1
- package/dist/evm/adapters/aera.d.ts.map +1 -1
- package/dist/evm/adapters/aera.js +41 -10
- package/dist/evm/adapters/aera.js.map +1 -1
- package/dist/evm/adapters/types.d.ts +2 -0
- package/dist/evm/adapters/types.d.ts.map +1 -1
- package/dist/evm/aeraContracts/priceAndFeeCalculator.d.ts +10 -5
- package/dist/evm/aeraContracts/priceAndFeeCalculator.d.ts.map +1 -1
- package/dist/evm/aeraContracts/priceAndFeeCalculator.js +39 -5
- package/dist/evm/aeraContracts/priceAndFeeCalculator.js.map +1 -1
- package/dist/evm/aeraContracts/readOptions.d.ts +8 -0
- package/dist/evm/aeraContracts/readOptions.d.ts.map +1 -0
- package/dist/evm/aeraContracts/readOptions.js +4 -0
- package/dist/evm/aeraContracts/readOptions.js.map +1 -0
- package/dist/evm/aeraContracts/v2.d.ts +373 -2
- package/dist/evm/aeraContracts/v2.d.ts.map +1 -1
- package/dist/evm/aeraContracts/v2.js +84 -28
- package/dist/evm/aeraContracts/v2.js.map +1 -1
- package/dist/evm/aeraContracts.d.ts +9 -3
- package/dist/evm/aeraContracts.d.ts.map +1 -1
- package/dist/evm/aeraContracts.js +69 -8
- package/dist/evm/aeraContracts.js.map +1 -1
- package/dist/evm/deposit.d.ts.map +1 -1
- package/dist/evm/deposit.js +1 -1
- package/dist/evm/deposit.js.map +1 -1
- package/dist/evm/index.d.ts +8 -0
- package/dist/evm/index.d.ts.map +1 -1
- package/dist/evm/index.js +3 -0
- package/dist/evm/index.js.map +1 -1
- package/dist/evm/tokenModes.d.ts +22 -0
- package/dist/evm/tokenModes.d.ts.map +1 -0
- package/dist/evm/tokenModes.js +34 -0
- package/dist/evm/tokenModes.js.map +1 -0
- package/dist/evm/withdraw.d.ts +8 -0
- package/dist/evm/withdraw.d.ts.map +1 -1
- package/dist/evm/withdraw.js +85 -5
- package/dist/evm/withdraw.js.map +1 -1
- package/dist/evm/withdrawQuote.d.ts +127 -0
- package/dist/evm/withdrawQuote.d.ts.map +1 -0
- package/dist/evm/withdrawQuote.js +164 -0
- package/dist/evm/withdrawQuote.js.map +1 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/manifest/vaults.json +112 -154
- package/package.json +1 -1
- package/src/api/client.ts +35 -2
- package/src/api/generated.ts +51 -7
- package/src/api/index.ts +5 -0
- package/src/errors.ts +32 -2
- package/src/evm/abis/priceAndFeeCalculatorV2.ts +22 -0
- package/src/evm/abis/provisionerV2.ts +33 -0
- package/src/evm/adapters/aera.ts +50 -23
- package/src/evm/adapters/types.ts +2 -0
- package/src/evm/aeraContracts/priceAndFeeCalculator.ts +72 -5
- package/src/evm/aeraContracts/readOptions.ts +3 -0
- package/src/evm/aeraContracts/v2.ts +158 -34
- package/src/evm/aeraContracts.ts +81 -8
- package/src/evm/deposit.ts +2 -1
- package/src/evm/index.ts +32 -0
- package/src/evm/tokenModes.ts +54 -0
- package/src/evm/withdraw.ts +131 -7
- package/src/evm/withdrawQuote.ts +360 -0
- package/src/index.ts +16 -0
|
@@ -13,8 +13,9 @@ import {
|
|
|
13
13
|
convertUnitsToTokenIfActive,
|
|
14
14
|
} from './priceAndFeeCalculator';
|
|
15
15
|
import { MAX_BPS } from '../../constants';
|
|
16
|
-
import { StalePriceError } from '../../errors';
|
|
16
|
+
import { StalePriceError, UnsupportedFeatureError } from '../../errors';
|
|
17
17
|
import type { ContractVersion } from '../types';
|
|
18
|
+
import { readAtBlock } from './readOptions';
|
|
18
19
|
|
|
19
20
|
export type PriceAndFeeCalculatorContract<T extends Client> = GetContractReturnType<
|
|
20
21
|
typeof priceAndFeeCalculatorV2Abi,
|
|
@@ -33,16 +34,44 @@ export function getPriceAndFeeCalculator<T extends Client>(
|
|
|
33
34
|
});
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
type SyncRedeemReadOptions = {
|
|
38
|
+
blockNumber?: bigint;
|
|
39
|
+
blockTimestamp?: bigint;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
async function resolveReadContext(
|
|
43
|
+
client: PublicClient,
|
|
44
|
+
options: SyncRedeemReadOptions = {}
|
|
45
|
+
): Promise<Required<SyncRedeemReadOptions>> {
|
|
46
|
+
if (options.blockNumber !== undefined && options.blockTimestamp !== undefined) {
|
|
47
|
+
return { blockNumber: options.blockNumber, blockTimestamp: options.blockTimestamp };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const block =
|
|
51
|
+
options.blockNumber === undefined ? await client.getBlock() : await client.getBlock(options);
|
|
52
|
+
if (block.number === null) {
|
|
53
|
+
throw new UnsupportedFeatureError('Aera: sync redeem reads require a numbered block');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
blockNumber: options.blockNumber ?? block.number,
|
|
58
|
+
blockTimestamp: options.blockTimestamp ?? BigInt(block.timestamp),
|
|
59
|
+
};
|
|
42
60
|
}
|
|
43
61
|
|
|
44
|
-
async function getTokenDetails(
|
|
45
|
-
|
|
62
|
+
async function getTokenDetails(
|
|
63
|
+
client: PublicClient,
|
|
64
|
+
provisioner: Address,
|
|
65
|
+
token: Address,
|
|
66
|
+
options: SyncRedeemReadOptions = {}
|
|
67
|
+
) {
|
|
68
|
+
return client.readContract({
|
|
69
|
+
address: provisioner,
|
|
70
|
+
abi: provisionerV2Abi,
|
|
71
|
+
functionName: 'tokensDetails',
|
|
72
|
+
args: [token],
|
|
73
|
+
...readAtBlock(options),
|
|
74
|
+
});
|
|
46
75
|
}
|
|
47
76
|
|
|
48
77
|
async function getDepositUnitsOut({
|
|
@@ -54,6 +83,7 @@ async function getDepositUnitsOut({
|
|
|
54
83
|
token,
|
|
55
84
|
tokensIn,
|
|
56
85
|
multiplierIndex,
|
|
86
|
+
options,
|
|
57
87
|
}: {
|
|
58
88
|
client: PublicClient;
|
|
59
89
|
provisioner: Address;
|
|
@@ -63,8 +93,9 @@ async function getDepositUnitsOut({
|
|
|
63
93
|
token: Address;
|
|
64
94
|
tokensIn: bigint;
|
|
65
95
|
multiplierIndex: 4 | 6;
|
|
96
|
+
options?: SyncRedeemReadOptions;
|
|
66
97
|
}): Promise<bigint> {
|
|
67
|
-
const tokenDetails = await getTokenDetails(client, provisioner, token);
|
|
98
|
+
const tokenDetails = await getTokenDetails(client, provisioner, token, options);
|
|
68
99
|
const multiplier = BigInt(tokenDetails[multiplierIndex]);
|
|
69
100
|
const adjustedTokensIn = (tokensIn * multiplier) / MAX_BPS;
|
|
70
101
|
|
|
@@ -75,7 +106,8 @@ async function getDepositUnitsOut({
|
|
|
75
106
|
vault,
|
|
76
107
|
token,
|
|
77
108
|
adjustedTokensIn,
|
|
78
|
-
Rounding.Floor
|
|
109
|
+
Rounding.Floor,
|
|
110
|
+
options
|
|
79
111
|
);
|
|
80
112
|
}
|
|
81
113
|
|
|
@@ -88,6 +120,7 @@ async function getRedeemTokenOut({
|
|
|
88
120
|
token,
|
|
89
121
|
unitsIn,
|
|
90
122
|
multiplierIndex,
|
|
123
|
+
options,
|
|
91
124
|
}: {
|
|
92
125
|
client: PublicClient;
|
|
93
126
|
provisioner: Address;
|
|
@@ -97,9 +130,10 @@ async function getRedeemTokenOut({
|
|
|
97
130
|
token: Address;
|
|
98
131
|
unitsIn: bigint;
|
|
99
132
|
multiplierIndex: 5 | 7;
|
|
133
|
+
options?: SyncRedeemReadOptions;
|
|
100
134
|
}): Promise<bigint> {
|
|
101
135
|
const [tokenDetails, tokensOut] = await Promise.all([
|
|
102
|
-
getTokenDetails(client, provisioner, token),
|
|
136
|
+
getTokenDetails(client, provisioner, token, options),
|
|
103
137
|
convertUnitsToTokenIfActive(
|
|
104
138
|
client,
|
|
105
139
|
feeCalculator,
|
|
@@ -107,7 +141,8 @@ async function getRedeemTokenOut({
|
|
|
107
141
|
vault,
|
|
108
142
|
token,
|
|
109
143
|
unitsIn,
|
|
110
|
-
Rounding.Floor
|
|
144
|
+
Rounding.Floor,
|
|
145
|
+
options
|
|
111
146
|
),
|
|
112
147
|
]);
|
|
113
148
|
const multiplier = BigInt(tokenDetails[multiplierIndex]);
|
|
@@ -124,6 +159,7 @@ async function getWithdrawUnitsIn({
|
|
|
124
159
|
token,
|
|
125
160
|
tokensOut,
|
|
126
161
|
multiplierIndex,
|
|
162
|
+
options,
|
|
127
163
|
}: {
|
|
128
164
|
client: PublicClient;
|
|
129
165
|
provisioner: Address;
|
|
@@ -133,8 +169,9 @@ async function getWithdrawUnitsIn({
|
|
|
133
169
|
token: Address;
|
|
134
170
|
tokensOut: bigint;
|
|
135
171
|
multiplierIndex: 5 | 7;
|
|
172
|
+
options?: SyncRedeemReadOptions;
|
|
136
173
|
}): Promise<bigint> {
|
|
137
|
-
const tokenDetails = await getTokenDetails(client, provisioner, token);
|
|
174
|
+
const tokenDetails = await getTokenDetails(client, provisioner, token, options);
|
|
138
175
|
const multiplier = BigInt(tokenDetails[multiplierIndex]);
|
|
139
176
|
const preMultiplierTokens = (tokensOut * MAX_BPS + multiplier - 1n) / multiplier;
|
|
140
177
|
|
|
@@ -145,17 +182,37 @@ async function getWithdrawUnitsIn({
|
|
|
145
182
|
vault,
|
|
146
183
|
token,
|
|
147
184
|
preMultiplierTokens,
|
|
148
|
-
Rounding.Ceil
|
|
185
|
+
Rounding.Ceil,
|
|
186
|
+
options
|
|
149
187
|
);
|
|
150
188
|
}
|
|
151
189
|
|
|
152
|
-
|
|
190
|
+
/** Breakdown of the effective sync redeem multiplier, in basis points. */
|
|
191
|
+
export interface SyncRedeemRate {
|
|
192
|
+
/** Base sync redeem multiplier (tokensDetails.syncRedeemMultiplier). */
|
|
193
|
+
baseMultiplierBps: bigint;
|
|
194
|
+
/** Dynamic premium charged for the current oracle price age. */
|
|
195
|
+
dynamicPremiumBps: bigint;
|
|
196
|
+
/** Multiplier actually applied to size the redemption (base - dynamic premium). */
|
|
197
|
+
effectiveMultiplierBps: bigint;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Reads the live sync redeem rate, replicating the provisioner's effective-multiplier
|
|
202
|
+
* derivation (base multiplier minus a price-age-proportional dynamic premium).
|
|
203
|
+
*
|
|
204
|
+
* @throws {StalePriceError} If the oracle price is older than the configured max age,
|
|
205
|
+
* in which case the on-chain sync redeem would revert.
|
|
206
|
+
*/
|
|
207
|
+
export async function getSyncRedeemRate(
|
|
153
208
|
client: PublicClient,
|
|
154
209
|
provisioner: Address,
|
|
155
210
|
vault: Address,
|
|
156
211
|
token: Address,
|
|
157
|
-
feeCalculator: Address
|
|
158
|
-
|
|
212
|
+
feeCalculator: Address,
|
|
213
|
+
options: SyncRedeemReadOptions = {}
|
|
214
|
+
): Promise<SyncRedeemRate> {
|
|
215
|
+
const readContext = await resolveReadContext(client, options);
|
|
159
216
|
const [tokenDetails, syncRedeemDetails, anchorTimestamp] = await client.multicall({
|
|
160
217
|
contracts: [
|
|
161
218
|
{
|
|
@@ -177,12 +234,12 @@ async function getSyncRedeemMultiplier(
|
|
|
177
234
|
},
|
|
178
235
|
],
|
|
179
236
|
allowFailure: false,
|
|
237
|
+
blockNumber: readContext.blockNumber,
|
|
180
238
|
});
|
|
181
|
-
const
|
|
182
|
-
const syncRedeemMultiplier = BigInt(tokenDetails[7]);
|
|
239
|
+
const baseMultiplierBps = BigInt(tokenDetails[7]);
|
|
183
240
|
const maxPriceAge = BigInt(syncRedeemDetails[0]);
|
|
184
241
|
const maxDynamicPremiumBps = BigInt(syncRedeemDetails[2]);
|
|
185
|
-
const blockTimestamp =
|
|
242
|
+
const blockTimestamp = readContext.blockTimestamp;
|
|
186
243
|
const priceTimestamp = BigInt(anchorTimestamp);
|
|
187
244
|
|
|
188
245
|
if (priceTimestamp + maxPriceAge < blockTimestamp) {
|
|
@@ -198,7 +255,23 @@ async function getSyncRedeemMultiplier(
|
|
|
198
255
|
? 0n
|
|
199
256
|
: ((blockTimestamp - priceTimestamp) * maxDynamicPremiumBps + maxPriceAge - 1n) / maxPriceAge;
|
|
200
257
|
|
|
201
|
-
return
|
|
258
|
+
return {
|
|
259
|
+
baseMultiplierBps,
|
|
260
|
+
dynamicPremiumBps,
|
|
261
|
+
effectiveMultiplierBps: baseMultiplierBps - dynamicPremiumBps,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async function getSyncRedeemMultiplier(
|
|
266
|
+
client: PublicClient,
|
|
267
|
+
provisioner: Address,
|
|
268
|
+
vault: Address,
|
|
269
|
+
token: Address,
|
|
270
|
+
feeCalculator: Address,
|
|
271
|
+
options: SyncRedeemReadOptions = {}
|
|
272
|
+
): Promise<bigint> {
|
|
273
|
+
return (await getSyncRedeemRate(client, provisioner, vault, token, feeCalculator, options))
|
|
274
|
+
.effectiveMultiplierBps;
|
|
202
275
|
}
|
|
203
276
|
|
|
204
277
|
export async function getSyncRedeemTokenOut(
|
|
@@ -208,8 +281,12 @@ export async function getSyncRedeemTokenOut(
|
|
|
208
281
|
feeCalculatorVersion: ContractVersion,
|
|
209
282
|
vault: Address,
|
|
210
283
|
token: Address,
|
|
211
|
-
unitsIn: bigint
|
|
284
|
+
unitsIn: bigint,
|
|
285
|
+
effectiveMultiplierBps?: bigint,
|
|
286
|
+
options: SyncRedeemReadOptions = {}
|
|
212
287
|
): Promise<bigint> {
|
|
288
|
+
const readContext =
|
|
289
|
+
effectiveMultiplierBps === undefined ? await resolveReadContext(client, options) : options;
|
|
213
290
|
const [tokenAmount, multiplier] = await Promise.all([
|
|
214
291
|
convertUnitsToTokenIfActive(
|
|
215
292
|
client,
|
|
@@ -218,9 +295,12 @@ export async function getSyncRedeemTokenOut(
|
|
|
218
295
|
vault,
|
|
219
296
|
token,
|
|
220
297
|
unitsIn,
|
|
221
|
-
Rounding.Floor
|
|
298
|
+
Rounding.Floor,
|
|
299
|
+
readContext
|
|
222
300
|
),
|
|
223
|
-
|
|
301
|
+
effectiveMultiplierBps !== undefined
|
|
302
|
+
? Promise.resolve(effectiveMultiplierBps)
|
|
303
|
+
: getSyncRedeemMultiplier(client, provisioner, vault, token, feeCalculator, readContext),
|
|
224
304
|
]);
|
|
225
305
|
|
|
226
306
|
return (tokenAmount * multiplier) / MAX_BPS;
|
|
@@ -317,15 +397,15 @@ export async function getSyncWithdrawUnitsIn(
|
|
|
317
397
|
feeCalculatorVersion: ContractVersion,
|
|
318
398
|
vault: Address,
|
|
319
399
|
token: Address,
|
|
320
|
-
tokensOut: bigint
|
|
400
|
+
tokensOut: bigint,
|
|
401
|
+
effectiveMultiplierBps?: bigint,
|
|
402
|
+
options: SyncRedeemReadOptions = {}
|
|
321
403
|
): Promise<bigint> {
|
|
322
|
-
const
|
|
323
|
-
client,
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
token,
|
|
327
|
-
feeCalculator
|
|
328
|
-
);
|
|
404
|
+
const readContext =
|
|
405
|
+
effectiveMultiplierBps === undefined ? await resolveReadContext(client, options) : options;
|
|
406
|
+
const multiplier =
|
|
407
|
+
effectiveMultiplierBps ??
|
|
408
|
+
(await getSyncRedeemMultiplier(client, provisioner, vault, token, feeCalculator, readContext));
|
|
329
409
|
const prePremiumTokens = (tokensOut * MAX_BPS + multiplier - 1n) / multiplier;
|
|
330
410
|
|
|
331
411
|
return convertTokenToUnitsIfActive(
|
|
@@ -335,10 +415,54 @@ export async function getSyncWithdrawUnitsIn(
|
|
|
335
415
|
vault,
|
|
336
416
|
token,
|
|
337
417
|
prePremiumTokens,
|
|
338
|
-
Rounding.Ceil
|
|
418
|
+
Rounding.Ceil,
|
|
419
|
+
readContext
|
|
339
420
|
);
|
|
340
421
|
}
|
|
341
422
|
|
|
423
|
+
/** Current sync redeem epoch accounting, in numeraire (all values uint256). */
|
|
424
|
+
export interface SyncRedeemEpochState {
|
|
425
|
+
epochTimestamp: bigint;
|
|
426
|
+
epochStartTvlNumeraire: bigint;
|
|
427
|
+
epochRedeemedNumeraire: bigint;
|
|
428
|
+
epochCapNumeraire: bigint;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
export async function getSyncRedeemEpochState(
|
|
432
|
+
client: PublicClient,
|
|
433
|
+
provisioner: Address,
|
|
434
|
+
options: SyncRedeemReadOptions = {}
|
|
435
|
+
): Promise<SyncRedeemEpochState> {
|
|
436
|
+
const [epochTimestamp, epochStartTvlNumeraire, epochRedeemedNumeraire, epochCapNumeraire] =
|
|
437
|
+
await client.readContract({
|
|
438
|
+
address: provisioner,
|
|
439
|
+
abi: provisionerV2Abi,
|
|
440
|
+
functionName: 'getSyncRedeemEpochState',
|
|
441
|
+
...readAtBlock(options),
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
return { epochTimestamp, epochStartTvlNumeraire, epochRedeemedNumeraire, epochCapNumeraire };
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Raw expiry timestamp for the user's latest sync-deposit lock (0 if none was recorded).
|
|
449
|
+
* The user is locked while this value is greater than or equal to the relevant block timestamp.
|
|
450
|
+
*/
|
|
451
|
+
export async function getUserUnitsRefundableUntil(
|
|
452
|
+
client: PublicClient,
|
|
453
|
+
provisioner: Address,
|
|
454
|
+
user: Address,
|
|
455
|
+
options: SyncRedeemReadOptions = {}
|
|
456
|
+
): Promise<bigint> {
|
|
457
|
+
return client.readContract({
|
|
458
|
+
address: provisioner,
|
|
459
|
+
abi: provisionerV2Abi,
|
|
460
|
+
functionName: 'userUnitsRefundableUntil',
|
|
461
|
+
args: [user],
|
|
462
|
+
...readAtBlock(options),
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
|
|
342
466
|
export function depositTxRequest(
|
|
343
467
|
provisioner: Address,
|
|
344
468
|
token: Address,
|
package/src/evm/aeraContracts.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { provisionerAbi } from './abis/provisioner';
|
|
|
15
15
|
import { provisionerV2Abi } from './abis/provisionerV2';
|
|
16
16
|
import { MAX_BPS } from '../constants';
|
|
17
17
|
import { ContractVersion, type EvmVaultDeployment } from './types';
|
|
18
|
+
import { readAtBlock } from './aeraContracts/readOptions';
|
|
18
19
|
|
|
19
20
|
const contractVersionCache = new Map<string, ContractVersion>();
|
|
20
21
|
|
|
@@ -28,6 +29,19 @@ const contractVersionAbi = [
|
|
|
28
29
|
},
|
|
29
30
|
] as const;
|
|
30
31
|
|
|
32
|
+
const solvingGateAbi = [
|
|
33
|
+
{
|
|
34
|
+
type: 'function',
|
|
35
|
+
inputs: [
|
|
36
|
+
{ name: 'provisioner', internalType: 'address', type: 'address' },
|
|
37
|
+
{ name: 'token', internalType: 'address', type: 'address' },
|
|
38
|
+
],
|
|
39
|
+
name: 'paused',
|
|
40
|
+
outputs: [{ name: '', internalType: 'bool', type: 'bool' }],
|
|
41
|
+
stateMutability: 'view',
|
|
42
|
+
},
|
|
43
|
+
] as const;
|
|
44
|
+
|
|
31
45
|
export interface AeraRuntimeContracts {
|
|
32
46
|
provisioner: {
|
|
33
47
|
address: Address;
|
|
@@ -46,6 +60,19 @@ export interface AeraTokenModeSupport {
|
|
|
46
60
|
syncRedeem: boolean;
|
|
47
61
|
}
|
|
48
62
|
|
|
63
|
+
export function requireAeraSyncRedeemRuntime(runtime: AeraRuntimeContracts): void {
|
|
64
|
+
if (runtime.provisioner.version !== ContractVersion.V2) {
|
|
65
|
+
throw new UnsupportedFeatureError('Aera: sync redeem requires a V2 provisioner');
|
|
66
|
+
}
|
|
67
|
+
if (runtime.feeCalculator.version !== ContractVersion.V2) {
|
|
68
|
+
throw new UnsupportedFeatureError('Aera: sync redeem requires a V2 price and fee calculator');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export type AeraReadOptions = {
|
|
73
|
+
blockNumber?: bigint;
|
|
74
|
+
};
|
|
75
|
+
|
|
49
76
|
export function applySlippageDown(amount: bigint, slippageBps: number): bigint {
|
|
50
77
|
return (amount * (MAX_BPS - BigInt(slippageBps))) / MAX_BPS;
|
|
51
78
|
}
|
|
@@ -97,7 +124,8 @@ export function getMultiDepositorVault<T extends Client>(
|
|
|
97
124
|
|
|
98
125
|
export async function resolveContractVersion(
|
|
99
126
|
client: PublicClient,
|
|
100
|
-
address: Address
|
|
127
|
+
address: Address,
|
|
128
|
+
options: AeraReadOptions = {}
|
|
101
129
|
): Promise<ContractVersion> {
|
|
102
130
|
const cacheKey = contractVersionCacheKey(client, address);
|
|
103
131
|
const cached = contractVersionCache.get(cacheKey);
|
|
@@ -108,6 +136,7 @@ export async function resolveContractVersion(
|
|
|
108
136
|
address,
|
|
109
137
|
abi: contractVersionAbi,
|
|
110
138
|
functionName: 'version',
|
|
139
|
+
...readAtBlock(options),
|
|
111
140
|
});
|
|
112
141
|
const version = versionString.startsWith('2.') ? ContractVersion.V2 : ContractVersion.V1;
|
|
113
142
|
contractVersionCache.set(cacheKey, version);
|
|
@@ -123,7 +152,8 @@ export async function resolveContractVersion(
|
|
|
123
152
|
|
|
124
153
|
export async function resolveAeraRuntimeContracts(
|
|
125
154
|
client: PublicClient,
|
|
126
|
-
vault: EvmVaultDeployment
|
|
155
|
+
vault: EvmVaultDeployment,
|
|
156
|
+
options: AeraReadOptions = {}
|
|
127
157
|
): Promise<AeraRuntimeContracts> {
|
|
128
158
|
if (vault.vaultType !== 'multi-depositor') {
|
|
129
159
|
throw new UnimplementedFeatureError('Aera: single depositor vaults');
|
|
@@ -134,11 +164,13 @@ export async function resolveAeraRuntimeContracts(
|
|
|
134
164
|
address: vault.vaultAddress,
|
|
135
165
|
abi: multiDepositorVaultAbi,
|
|
136
166
|
functionName: 'provisioner',
|
|
167
|
+
...readAtBlock(options),
|
|
137
168
|
}),
|
|
138
169
|
client.readContract({
|
|
139
170
|
address: vault.vaultAddress,
|
|
140
171
|
abi: multiDepositorVaultAbi,
|
|
141
172
|
functionName: 'feeCalculator',
|
|
173
|
+
...readAtBlock(options),
|
|
142
174
|
}),
|
|
143
175
|
]);
|
|
144
176
|
|
|
@@ -150,8 +182,8 @@ export async function resolveAeraRuntimeContracts(
|
|
|
150
182
|
}
|
|
151
183
|
|
|
152
184
|
const [provisionerVersion, feeCalculatorVersion] = await Promise.all([
|
|
153
|
-
resolveContractVersion(client, provisionerAddress),
|
|
154
|
-
resolveContractVersion(client, feeCalculatorAddress),
|
|
185
|
+
resolveContractVersion(client, provisionerAddress, options),
|
|
186
|
+
resolveContractVersion(client, feeCalculatorAddress, options),
|
|
155
187
|
]);
|
|
156
188
|
|
|
157
189
|
return {
|
|
@@ -169,21 +201,61 @@ export async function resolveAeraRuntimeContracts(
|
|
|
169
201
|
export async function resolveAeraTokenModeSupport(
|
|
170
202
|
client: PublicClient,
|
|
171
203
|
runtime: AeraRuntimeContracts,
|
|
172
|
-
token: Address
|
|
204
|
+
token: Address,
|
|
205
|
+
options: AeraReadOptions & { includeSyncModes?: boolean } = {}
|
|
173
206
|
): Promise<AeraTokenModeSupport> {
|
|
174
207
|
if (runtime.provisioner.version === ContractVersion.V2) {
|
|
175
|
-
const
|
|
208
|
+
const tokenDetailsPromise = client.readContract({
|
|
176
209
|
address: runtime.provisioner.address,
|
|
177
210
|
abi: provisionerV2Abi,
|
|
178
211
|
functionName: 'tokensDetails',
|
|
179
212
|
args: [token],
|
|
213
|
+
...readAtBlock(options),
|
|
180
214
|
});
|
|
215
|
+
if (options.includeSyncModes === false) {
|
|
216
|
+
const tokenDetails = await tokenDetailsPromise;
|
|
217
|
+
return {
|
|
218
|
+
asyncDeposit: Boolean(tokenDetails[0]),
|
|
219
|
+
asyncRedeem: Boolean(tokenDetails[1]),
|
|
220
|
+
syncDeposit: false,
|
|
221
|
+
syncRedeem: false,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const [tokenDetails, solvingGateEnabled, solvingGate] = await Promise.all([
|
|
226
|
+
tokenDetailsPromise,
|
|
227
|
+
client.readContract({
|
|
228
|
+
address: runtime.provisioner.address,
|
|
229
|
+
abi: provisionerV2Abi,
|
|
230
|
+
functionName: 'SOLVING_GATE_ENABLED',
|
|
231
|
+
...readAtBlock(options),
|
|
232
|
+
}),
|
|
233
|
+
client.readContract({
|
|
234
|
+
address: runtime.provisioner.address,
|
|
235
|
+
abi: provisionerV2Abi,
|
|
236
|
+
functionName: 'solvingGate',
|
|
237
|
+
...readAtBlock(options),
|
|
238
|
+
}),
|
|
239
|
+
]);
|
|
240
|
+
const solvingPaused =
|
|
241
|
+
solvingGateEnabled && solvingGate !== zeroAddress
|
|
242
|
+
? await client.readContract({
|
|
243
|
+
address: solvingGate,
|
|
244
|
+
abi: solvingGateAbi,
|
|
245
|
+
functionName: 'paused',
|
|
246
|
+
args: [runtime.provisioner.address, token],
|
|
247
|
+
...readAtBlock(options),
|
|
248
|
+
})
|
|
249
|
+
: false;
|
|
181
250
|
|
|
182
251
|
return {
|
|
183
252
|
asyncDeposit: Boolean(tokenDetails[0]),
|
|
184
253
|
asyncRedeem: Boolean(tokenDetails[1]),
|
|
185
|
-
syncDeposit: Boolean(tokenDetails[2]),
|
|
186
|
-
syncRedeem:
|
|
254
|
+
syncDeposit: Boolean(tokenDetails[2]) && !solvingPaused,
|
|
255
|
+
syncRedeem:
|
|
256
|
+
Boolean(tokenDetails[3]) &&
|
|
257
|
+
!solvingPaused &&
|
|
258
|
+
runtime.feeCalculator.version === ContractVersion.V2,
|
|
187
259
|
};
|
|
188
260
|
}
|
|
189
261
|
|
|
@@ -192,6 +264,7 @@ export async function resolveAeraTokenModeSupport(
|
|
|
192
264
|
abi: provisionerAbi,
|
|
193
265
|
functionName: 'tokensDetails',
|
|
194
266
|
args: [token],
|
|
267
|
+
...readAtBlock(options),
|
|
195
268
|
});
|
|
196
269
|
|
|
197
270
|
return {
|
package/src/evm/deposit.ts
CHANGED
|
@@ -113,7 +113,8 @@ export async function getDepositTx(
|
|
|
113
113
|
const tokenModeSupport = await resolveAeraTokenModeSupport(
|
|
114
114
|
publicClient,
|
|
115
115
|
aeraRuntime,
|
|
116
|
-
token.address
|
|
116
|
+
token.address,
|
|
117
|
+
{ includeSyncModes: requestedDepositMode !== 'async' }
|
|
117
118
|
);
|
|
118
119
|
modifiedDepositMode = resolveOperationMode(params.vaultId, requestedDepositMode, {
|
|
119
120
|
async: tokenModeSupport.asyncDeposit,
|
package/src/evm/index.ts
CHANGED
|
@@ -1,10 +1,30 @@
|
|
|
1
1
|
export { getDepositTx } from './deposit';
|
|
2
2
|
export { getDepositReceiverApprovalTx } from './depositReceiverApproval';
|
|
3
3
|
export { getWithdrawTx } from './withdraw';
|
|
4
|
+
export { getSyncWithdrawQuote } from './withdrawQuote';
|
|
5
|
+
export { getAeraTokenModeSupport } from './tokenModes';
|
|
4
6
|
export { getUserCurrentBalance } from './userCurrentBalance';
|
|
5
7
|
export { getVaults, VaultId } from './vaults';
|
|
6
8
|
export { ContractVersion } from './types';
|
|
7
9
|
export { resolveAeraRuntimeContracts, resolveContractVersion } from './aeraContracts';
|
|
10
|
+
export {
|
|
11
|
+
GauntletSDKError,
|
|
12
|
+
AccountRequiredError,
|
|
13
|
+
AccountMismatchError,
|
|
14
|
+
ChainMismatchError,
|
|
15
|
+
InvalidSlippageBPSError,
|
|
16
|
+
InvalidSolverTipError,
|
|
17
|
+
InvalidSyncWithdrawBoundError,
|
|
18
|
+
InvalidWithdrawParamsError,
|
|
19
|
+
RpcNotConfiguredError,
|
|
20
|
+
StalePriceError,
|
|
21
|
+
UnsupportedAssetError,
|
|
22
|
+
UnsupportedDepositModeError,
|
|
23
|
+
UnsupportedFeatureError,
|
|
24
|
+
UnsupportedProtocolError,
|
|
25
|
+
UnimplementedFeatureError,
|
|
26
|
+
VaultNotFoundError,
|
|
27
|
+
} from '../errors';
|
|
8
28
|
export {
|
|
9
29
|
Rounding,
|
|
10
30
|
convertTokenToUnits,
|
|
@@ -19,7 +39,18 @@ export {
|
|
|
19
39
|
export type { EvmDepositParams } from './deposit';
|
|
20
40
|
export type { EvmDepositReceiverApprovalParams } from './depositReceiverApproval';
|
|
21
41
|
export type { EvmWithdrawParams } from './withdraw';
|
|
42
|
+
export type {
|
|
43
|
+
SyncWithdrawQuote,
|
|
44
|
+
SyncWithdrawQuoteParams,
|
|
45
|
+
SyncWithdrawCapacity,
|
|
46
|
+
SyncWithdrawQuoteContext,
|
|
47
|
+
SyncWithdrawQuoteRequest,
|
|
48
|
+
SyncWithdrawQuoteBounds,
|
|
49
|
+
} from './withdrawQuote';
|
|
50
|
+
export type { AeraTokenModeSupportParams } from './tokenModes';
|
|
51
|
+
export type { SyncRedeemRate } from './aeraContracts/v2';
|
|
22
52
|
export type { EvmTxStep } from './adapters/types';
|
|
53
|
+
export type { PreparedTx } from '../attribution';
|
|
23
54
|
export type {
|
|
24
55
|
VaultInfo,
|
|
25
56
|
VaultDeployment,
|
|
@@ -31,3 +62,4 @@ export type { VaultFilter } from './vaults';
|
|
|
31
62
|
export type { UserCurrentBalanceParams, UserCurrentBalance } from './userCurrentBalance';
|
|
32
63
|
export type { AeraRuntimeContracts, AeraTokenModeSupport } from './aeraContracts';
|
|
33
64
|
export type { NormalizedVaultPriceState } from './aeraContracts/priceAndFeeCalculator';
|
|
65
|
+
export type { SyncWithdrawBound } from '../errors';
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { GauntletClient } from '../client';
|
|
2
|
+
import { UnsupportedAssetError, UnsupportedFeatureError, VaultNotFoundError } from '../errors';
|
|
3
|
+
import { resolveVault } from './vaults';
|
|
4
|
+
import {
|
|
5
|
+
resolveAeraRuntimeContracts,
|
|
6
|
+
resolveAeraTokenModeSupport,
|
|
7
|
+
type AeraTokenModeSupport,
|
|
8
|
+
} from './aeraContracts';
|
|
9
|
+
|
|
10
|
+
export interface AeraTokenModeSupportParams {
|
|
11
|
+
vaultId: string;
|
|
12
|
+
/** EVM chain ID. Defaults to the vault's primary chain (Base for current multichain vaults). */
|
|
13
|
+
chainId?: number;
|
|
14
|
+
/** Required for multiasset vaults. */
|
|
15
|
+
assetSymbol?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Reads which deposit/redeem modes (sync vs async) are currently enabled on-chain for a vault token.
|
|
20
|
+
*
|
|
21
|
+
* Use this to decide which entry points to offer a user (e.g. whether an instant withdraw is
|
|
22
|
+
* available) before any amount is entered. Mode availability includes the provisioner's token
|
|
23
|
+
* settings and live runtime gates. A paused V2 solving gate disables both sync modes.
|
|
24
|
+
*
|
|
25
|
+
* @throws {VaultNotFoundError} If the vault ID is not found.
|
|
26
|
+
* @throws {UnsupportedFeatureError} If the vault is not an Aera deployment.
|
|
27
|
+
* @throws {UnsupportedAssetError} If the asset symbol is not accepted by the vault.
|
|
28
|
+
*/
|
|
29
|
+
export async function getAeraTokenModeSupport(
|
|
30
|
+
client: GauntletClient,
|
|
31
|
+
params: AeraTokenModeSupportParams
|
|
32
|
+
): Promise<AeraTokenModeSupport> {
|
|
33
|
+
const resolved = await resolveVault(client, params.vaultId, params.chainId);
|
|
34
|
+
if (!resolved) throw new VaultNotFoundError(params.vaultId);
|
|
35
|
+
|
|
36
|
+
const { vault, protocol } = resolved;
|
|
37
|
+
if (protocol !== 'aera') {
|
|
38
|
+
throw new UnsupportedFeatureError('Token mode support is only available for Aera vaults');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const chainId = params.chainId ?? vault.chainId;
|
|
42
|
+
const publicClient = client.getPublicClient(chainId);
|
|
43
|
+
|
|
44
|
+
const token =
|
|
45
|
+
vault.supplyToken.length > 1
|
|
46
|
+
? vault.supplyToken.find((tInfo) => tInfo.symbol === params.assetSymbol)
|
|
47
|
+
: vault.supplyToken[0];
|
|
48
|
+
if (token === undefined) {
|
|
49
|
+
throw new UnsupportedAssetError(params.assetSymbol ?? 'unknown', params.vaultId);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const runtime = await resolveAeraRuntimeContracts(publicClient, vault);
|
|
53
|
+
return resolveAeraTokenModeSupport(publicClient, runtime, token.address);
|
|
54
|
+
}
|