@gauntlet-xyz/sdk 0.0.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 (90) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +120 -0
  3. package/dist/manifest/vaults.json +139 -0
  4. package/dist/src/attribution/erc8021.d.ts +2 -0
  5. package/dist/src/attribution/erc8021.js +7 -0
  6. package/dist/src/attribution/erc8021.js.map +1 -0
  7. package/dist/src/attribution/index.d.ts +16 -0
  8. package/dist/src/attribution/index.js +37 -0
  9. package/dist/src/attribution/index.js.map +1 -0
  10. package/dist/src/client.d.ts +28 -0
  11. package/dist/src/client.js +35 -0
  12. package/dist/src/client.js.map +1 -0
  13. package/dist/src/errors.d.ts +55 -0
  14. package/dist/src/errors.js +97 -0
  15. package/dist/src/errors.js.map +1 -0
  16. package/dist/src/evm/abis/erc20.d.ts +40 -0
  17. package/dist/src/evm/abis/erc20.js +30 -0
  18. package/dist/src/evm/abis/erc20.js.map +1 -0
  19. package/dist/src/evm/abis/erc4626.d.ts +104 -0
  20. package/dist/src/evm/abis/erc4626.js +70 -0
  21. package/dist/src/evm/abis/erc4626.js.map +1 -0
  22. package/dist/src/evm/abis/multiDepositorVault.d.ts +1047 -0
  23. package/dist/src/evm/abis/multiDepositorVault.js +587 -0
  24. package/dist/src/evm/abis/multiDepositorVault.js.map +1 -0
  25. package/dist/src/evm/abis/priceAndFeeCalculator.d.ts +909 -0
  26. package/dist/src/evm/abis/priceAndFeeCalculator.js +490 -0
  27. package/dist/src/evm/abis/priceAndFeeCalculator.js.map +1 -0
  28. package/dist/src/evm/abis/provisioner.d.ts +4983 -0
  29. package/dist/src/evm/abis/provisioner.js +2738 -0
  30. package/dist/src/evm/abis/provisioner.js.map +1 -0
  31. package/dist/src/evm/adapters/aera.d.ts +5 -0
  32. package/dist/src/evm/adapters/aera.js +144 -0
  33. package/dist/src/evm/adapters/aera.js.map +1 -0
  34. package/dist/src/evm/adapters/index.d.ts +2 -0
  35. package/dist/src/evm/adapters/index.js +14 -0
  36. package/dist/src/evm/adapters/index.js.map +1 -0
  37. package/dist/src/evm/adapters/morpho.d.ts +2 -0
  38. package/dist/src/evm/adapters/morpho.js +79 -0
  39. package/dist/src/evm/adapters/morpho.js.map +1 -0
  40. package/dist/src/evm/adapters/types.d.ts +65 -0
  41. package/dist/src/evm/adapters/types.js +2 -0
  42. package/dist/src/evm/adapters/types.js.map +1 -0
  43. package/dist/src/evm/aeraContracts.d.ts +2315 -0
  44. package/dist/src/evm/aeraContracts.js +37 -0
  45. package/dist/src/evm/aeraContracts.js.map +1 -0
  46. package/dist/src/evm/deposit.d.ts +13 -0
  47. package/dist/src/evm/deposit.js +66 -0
  48. package/dist/src/evm/deposit.js.map +1 -0
  49. package/dist/src/evm/index.d.ts +10 -0
  50. package/dist/src/evm/index.js +5 -0
  51. package/dist/src/evm/index.js.map +1 -0
  52. package/dist/src/evm/types.d.ts +27 -0
  53. package/dist/src/evm/types.js +2 -0
  54. package/dist/src/evm/types.js.map +1 -0
  55. package/dist/src/evm/userCurrentBalance.d.ts +16 -0
  56. package/dist/src/evm/userCurrentBalance.js +164 -0
  57. package/dist/src/evm/userCurrentBalance.js.map +1 -0
  58. package/dist/src/evm/vaults.d.ts +17 -0
  59. package/dist/src/evm/vaults.js +39 -0
  60. package/dist/src/evm/vaults.js.map +1 -0
  61. package/dist/src/evm/withdraw.d.ts +24 -0
  62. package/dist/src/evm/withdraw.js +51 -0
  63. package/dist/src/evm/withdraw.js.map +1 -0
  64. package/dist/src/index.d.ts +7 -0
  65. package/dist/src/index.js +4 -0
  66. package/dist/src/index.js.map +1 -0
  67. package/dist/tsconfig.tsbuildinfo +1 -0
  68. package/manifest/vaults.json +139 -0
  69. package/package.json +64 -0
  70. package/src/attribution/erc8021.ts +14 -0
  71. package/src/attribution/index.ts +62 -0
  72. package/src/client.ts +95 -0
  73. package/src/errors.ts +135 -0
  74. package/src/evm/abis/erc20.ts +29 -0
  75. package/src/evm/abis/erc4626.ts +69 -0
  76. package/src/evm/abis/multiDepositorVault.ts +586 -0
  77. package/src/evm/abis/priceAndFeeCalculator.ts +489 -0
  78. package/src/evm/abis/provisioner.ts +2787 -0
  79. package/src/evm/adapters/aera.ts +254 -0
  80. package/src/evm/adapters/index.ts +15 -0
  81. package/src/evm/adapters/morpho.ts +92 -0
  82. package/src/evm/adapters/types.ts +64 -0
  83. package/src/evm/aeraContracts.ts +82 -0
  84. package/src/evm/deposit.ts +137 -0
  85. package/src/evm/index.ts +11 -0
  86. package/src/evm/types.ts +34 -0
  87. package/src/evm/userCurrentBalance.ts +265 -0
  88. package/src/evm/vaults.ts +88 -0
  89. package/src/evm/withdraw.ts +127 -0
  90. package/src/index.ts +28 -0
@@ -0,0 +1,254 @@
1
+ import { erc20Abi } from '../abis/erc20';
2
+ import {
3
+ requestDepositTxRequest,
4
+ requestRedeemTxRequest,
5
+ getMultiDepositorVault,
6
+ getPriceAndFeeCalculator,
7
+ } from '../aeraContracts';
8
+ import {
9
+ InvalidWithdrawParamsError,
10
+ UnimplementedFeatureError,
11
+ UnitConversionError,
12
+ UnsupportedFeatureError,
13
+ } from '../../errors';
14
+ import type {
15
+ EvmProtocolAdapter,
16
+ EvmTxStep,
17
+ AdapterDepositParams,
18
+ AdapterWithdrawParams,
19
+ AllowanceParams,
20
+ ApprovalParams,
21
+ } from './types';
22
+ import { PublicClient, type Address } from 'viem';
23
+ 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 (
31
+ publicClient: PublicClient,
32
+ tokenUnits: bigint,
33
+ vaultAddress: Address,
34
+ tokenAddress: Address
35
+ ) => {
36
+ const vaultContract = getMultiDepositorVault(publicClient, vaultAddress);
37
+
38
+ if (vaultContract === undefined) return;
39
+
40
+ const calculatorAddress = await vaultContract.read.feeCalculator();
41
+
42
+ if (!calculatorAddress) return;
43
+
44
+ const calculatorContract = getPriceAndFeeCalculator(publicClient, calculatorAddress);
45
+
46
+ const vaultUnits = await calculatorContract.read.convertTokenToUnits([
47
+ vaultAddress,
48
+ tokenAddress,
49
+ tokenUnits,
50
+ ]);
51
+
52
+ return vaultUnits;
53
+ };
54
+
55
+ export const getAeraV3TokenUnits = async (
56
+ publicClient: PublicClient,
57
+ vaultUnits: bigint,
58
+ vaultAddress: Address,
59
+ tokenAddress: Address
60
+ ) => {
61
+ const vaultContract = getMultiDepositorVault(publicClient, vaultAddress);
62
+ if (vaultContract === undefined) return;
63
+
64
+ const calculatorAddress = await vaultContract.read.feeCalculator();
65
+ if (!calculatorAddress) return;
66
+
67
+ const calculatorContract = getPriceAndFeeCalculator(publicClient, calculatorAddress);
68
+
69
+ return calculatorContract.read.convertUnitsToToken([vaultAddress, tokenAddress, vaultUnits]);
70
+ };
71
+
72
+ export const aeraAdapter: EvmProtocolAdapter = {
73
+ 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');
78
+ }
79
+
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
+ ];*/
91
+ }
92
+
93
+ if (isAsync) {
94
+ const vaultUnits = await getAeraV3VaultUnits(
95
+ publicClient,
96
+ amount,
97
+ vault.vaultAddress,
98
+ asset.address
99
+ );
100
+
101
+ if (vaultUnits === undefined) {
102
+ throw new UnitConversionError(vault.vaultAddress);
103
+ }
104
+
105
+ const deadline = BigInt(Math.ceil(new Date().getTime() / 1000) + DAY * 3);
106
+ // Request deposit
107
+ return [
108
+ {
109
+ type: 'requestDeposit',
110
+ ...requestDepositTxRequest(
111
+ vault.provisionerAddress,
112
+ asset.address,
113
+ amount,
114
+ (vaultUnits * BigInt(10000 - slippageBps)) / 10000n, // minUnitsOut
115
+ 0n, // solvertip
116
+ deadline,
117
+ BigInt(DAY * 10),
118
+ false,
119
+ account
120
+ ),
121
+ },
122
+ ];
123
+ }
124
+
125
+ throw new UnimplementedFeatureError('Aera Sync Operations');
126
+ },
127
+
128
+ 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');
133
+ }
134
+
135
+ let shares: bigint;
136
+ let amount: bigint | undefined;
137
+
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);
156
+ }
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
+
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(
175
+ vault.vaultAddress,
176
+ [{ asset: asset.address, amount: shares }],
177
+ account
178
+ ),
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[] = [];
192
+
193
+ if (!sufficient) {
194
+ steps.push(
195
+ this.buildApproval({
196
+ token: vault.vaultAddress,
197
+ spender: vault.provisionerAddress,
198
+ amount: shares,
199
+ account,
200
+ })
201
+ );
202
+ }
203
+
204
+ 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);
209
+ }
210
+ return [
211
+ ...steps,
212
+ {
213
+ type: 'requestRedeem',
214
+ ...requestRedeemTxRequest(
215
+ vault.provisionerAddress,
216
+ asset.address,
217
+ shares,
218
+ (amount * BigInt(10000 - slippageBps)) / 10000n, // minUnitsOut
219
+ 0n, // solvertip
220
+ deadline,
221
+ BigInt(DAY * 10),
222
+ false,
223
+ account
224
+ ),
225
+ },
226
+ ];
227
+ }
228
+
229
+ throw new UnimplementedFeatureError('Aera Sync Operations');
230
+ },
231
+
232
+ async checkAllowance(params: AllowanceParams) {
233
+ const { publicClient, token, owner, spender, amount } = params;
234
+ const current = await publicClient.readContract({
235
+ address: token,
236
+ abi: erc20Abi,
237
+ functionName: 'allowance',
238
+ args: [owner, spender],
239
+ });
240
+
241
+ return { sufficient: current >= amount, current };
242
+ },
243
+
244
+ buildApproval(params: ApprovalParams): EvmTxStep {
245
+ return {
246
+ type: 'approve',
247
+ address: params.token,
248
+ abi: erc20Abi,
249
+ functionName: 'approve',
250
+ args: [params.spender, params.amount],
251
+ account: params.account,
252
+ };
253
+ },
254
+ };
@@ -0,0 +1,15 @@
1
+ import { aeraAdapter } from './aera';
2
+ import { morphoAdapter } from './morpho';
3
+ import { UnsupportedProtocolError } from '../../errors';
4
+ import type { EvmProtocolAdapter } from './types';
5
+
6
+ export function getAdapter(protocol: string): EvmProtocolAdapter {
7
+ switch (protocol) {
8
+ case 'aera':
9
+ return aeraAdapter;
10
+ case 'morpho':
11
+ return morphoAdapter;
12
+ default:
13
+ throw new UnsupportedProtocolError(protocol);
14
+ }
15
+ }
@@ -0,0 +1,92 @@
1
+ import type {
2
+ EvmProtocolAdapter,
3
+ EvmTxStep,
4
+ AdapterDepositParams,
5
+ AdapterWithdrawParams,
6
+ AllowanceParams,
7
+ ApprovalParams,
8
+ } from './types';
9
+ import { erc20Abi } from '../abis/erc20';
10
+ import { erc4626Abi } from '../abis/erc4626';
11
+ import { InvalidWithdrawParamsError } from '../../errors';
12
+
13
+ export const morphoAdapter: EvmProtocolAdapter = {
14
+ async buildDeposit(params: AdapterDepositParams): Promise<EvmTxStep[]> {
15
+ const { vault, amount, receiver, account } = params;
16
+
17
+ return [
18
+ {
19
+ type: 'deposit',
20
+ address: vault.vaultAddress,
21
+ abi: erc4626Abi,
22
+ functionName: 'deposit',
23
+ args: [amount, receiver],
24
+ account,
25
+ },
26
+ ];
27
+ },
28
+
29
+ async buildWithdraw(params: AdapterWithdrawParams): Promise<EvmTxStep[]> {
30
+ const { vault, receiver, account, publicClient } = params;
31
+
32
+ let shares: bigint;
33
+
34
+ if ('entireAmount' in params && params.entireAmount) {
35
+ shares = await publicClient.readContract({
36
+ address: vault.vaultAddress,
37
+ abi: erc4626Abi,
38
+ functionName: 'balanceOf',
39
+ args: [account],
40
+ });
41
+ } else if ('amount' in params && params.amount != null) {
42
+ return [
43
+ {
44
+ type: 'withdraw',
45
+ address: vault.vaultAddress,
46
+ abi: erc4626Abi,
47
+ functionName: 'withdraw',
48
+ args: [params.amount, receiver, account],
49
+ account,
50
+ },
51
+ ];
52
+ } else if ('shares' in params && params.shares != null) {
53
+ shares = params.shares;
54
+ } else {
55
+ throw new InvalidWithdrawParamsError();
56
+ }
57
+
58
+ return [
59
+ {
60
+ type: 'redeem',
61
+ address: vault.vaultAddress,
62
+ abi: erc4626Abi,
63
+ functionName: 'redeem',
64
+ args: [shares, receiver, account],
65
+ account,
66
+ },
67
+ ];
68
+ },
69
+
70
+ async checkAllowance(params: AllowanceParams) {
71
+ const { publicClient, token, owner, spender, amount } = params;
72
+ const current = await publicClient.readContract({
73
+ address: token,
74
+ abi: erc20Abi,
75
+ functionName: 'allowance',
76
+ args: [owner, spender],
77
+ });
78
+
79
+ return { sufficient: current >= amount, current };
80
+ },
81
+
82
+ buildApproval(params: ApprovalParams): EvmTxStep {
83
+ return {
84
+ type: 'approve',
85
+ address: params.token,
86
+ abi: erc20Abi,
87
+ functionName: 'approve',
88
+ args: [params.spender, params.amount],
89
+ account: params.account,
90
+ };
91
+ },
92
+ };
@@ -0,0 +1,64 @@
1
+ import type { Abi, Address, Hex, PublicClient } from 'viem';
2
+ import type { TokenInfo, VaultDeployment } from '../types';
3
+
4
+ export interface EvmTxStep<TAbi extends Abi = Abi, TFunctionName extends string = string> {
5
+ type: 'approve' | 'deposit' | 'requestDeposit' | 'redeem' | 'requestRedeem' | 'withdraw';
6
+ address: Address;
7
+ abi: TAbi;
8
+ functionName: TFunctionName;
9
+ args: readonly unknown[];
10
+ account: Address;
11
+ attribution?: Hex;
12
+ }
13
+
14
+ export type TxStep = EvmTxStep; // | SolanaTxStep
15
+
16
+ export interface AdapterDepositParams {
17
+ vault: VaultDeployment;
18
+ amount: bigint;
19
+ receiver: Address;
20
+ account: Address;
21
+ async: boolean;
22
+ /** Attribution bytes (GTLT + optional ERC-8021). Passed to adapter for future calldata embedding. */
23
+ asset: TokenInfo;
24
+ publicClient: PublicClient;
25
+ /** Slippage tolerance in basis points (e.g. 100 = 1%). Defaults to 100. */
26
+ slippageBps?: number;
27
+ }
28
+
29
+ export type AdapterWithdrawParams = {
30
+ vault: VaultDeployment;
31
+ receiver: Address;
32
+ account: Address;
33
+ async: boolean | undefined;
34
+ asset: TokenInfo;
35
+ publicClient: PublicClient;
36
+ /** Slippage tolerance in basis points (e.g. 100 = 1%). Defaults to 100. */
37
+ slippageBps?: number;
38
+ } & (
39
+ | { shares: bigint; amount?: never; entireAmount?: never }
40
+ | { amount: bigint; shares?: never; entireAmount?: never }
41
+ | { entireAmount: true; shares?: never; amount?: never }
42
+ );
43
+
44
+ export interface AllowanceParams {
45
+ publicClient: PublicClient;
46
+ token: Address;
47
+ owner: Address;
48
+ spender: Address;
49
+ amount: bigint;
50
+ }
51
+
52
+ export interface ApprovalParams {
53
+ token: Address;
54
+ spender: Address;
55
+ amount: bigint;
56
+ account: Address;
57
+ }
58
+
59
+ export interface EvmProtocolAdapter {
60
+ buildDeposit(params: AdapterDepositParams): Promise<EvmTxStep[]>;
61
+ buildWithdraw(params: AdapterWithdrawParams): Promise<EvmTxStep[]>;
62
+ checkAllowance(params: AllowanceParams): Promise<{ sufficient: boolean; current: bigint }>;
63
+ buildApproval(params: ApprovalParams): EvmTxStep;
64
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * CODE PULLED FROM AERA-V3-TS-SDK in gauntlet/apps/packages/aera-v3-ts-sdk
3
+ * pulled in here with the goal to have this SDK replace the previous
4
+ */
5
+ import { type Address, type Client, type GetContractReturnType, getContract } from 'viem';
6
+ import { multiDepositorVaultAbi } from './abis/multiDepositorVault';
7
+ import { priceAndFeeCalculatorAbi } from './abis/priceAndFeeCalculator';
8
+ import { provisionerAbi } from './abis/provisioner';
9
+
10
+ export type MultiDepositorVaultContract<T extends Client> = GetContractReturnType<
11
+ typeof multiDepositorVaultAbi,
12
+ T,
13
+ Address
14
+ >;
15
+
16
+ export function getMultiDepositorVault<T extends Client>(
17
+ client: T,
18
+ vaultAddress: Address
19
+ ): MultiDepositorVaultContract<T> {
20
+ return getContract({
21
+ address: vaultAddress,
22
+ abi: multiDepositorVaultAbi,
23
+ client,
24
+ });
25
+ }
26
+
27
+ export type PriceAndFeeCalculatorContract<T extends Client> = GetContractReturnType<
28
+ typeof priceAndFeeCalculatorAbi,
29
+ T,
30
+ Address
31
+ >;
32
+
33
+ export function getPriceAndFeeCalculator<T extends Client>(
34
+ client: T,
35
+ address: Address
36
+ ): PriceAndFeeCalculatorContract<T> {
37
+ return getContract({
38
+ address,
39
+ abi: priceAndFeeCalculatorAbi,
40
+ client,
41
+ });
42
+ }
43
+
44
+ export function requestDepositTxRequest(
45
+ provisioner: Address,
46
+ token: Address,
47
+ tokensIn: bigint,
48
+ minUnitsOut: bigint,
49
+ solverTip: bigint,
50
+ deadline: bigint,
51
+ maxPriceAge: bigint,
52
+ isFixedPrice: boolean,
53
+ account: Address
54
+ ) {
55
+ return {
56
+ address: provisioner,
57
+ abi: provisionerAbi,
58
+ functionName: 'requestDeposit' as const,
59
+ args: [token, tokensIn, minUnitsOut, solverTip, deadline, maxPriceAge, isFixedPrice] as const,
60
+ account,
61
+ };
62
+ }
63
+
64
+ export function requestRedeemTxRequest(
65
+ provisioner: Address,
66
+ token: Address,
67
+ unitsIn: bigint,
68
+ minTokenOut: bigint,
69
+ solverTip: bigint,
70
+ deadline: bigint,
71
+ maxPriceAge: bigint,
72
+ isFixedPrice: boolean,
73
+ account: Address
74
+ ) {
75
+ return {
76
+ address: provisioner,
77
+ abi: provisionerAbi,
78
+ functionName: 'requestRedeem' as const,
79
+ args: [token, unitsIn, minTokenOut, solverTip, deadline, maxPriceAge, isFixedPrice] as const,
80
+ account,
81
+ };
82
+ }
@@ -0,0 +1,137 @@
1
+ import type { Address } from 'viem';
2
+ import type { GauntletClient } from '../client';
3
+ import type { EvmTxStep } from './adapters/types';
4
+ import { getAdapter } from './adapters';
5
+ import { encodeTransactionWithAttribution, PreparedTx } from '../attribution';
6
+ import {
7
+ AccountRequiredError,
8
+ VaultNotFoundError,
9
+ UnsupportedDepositModeError,
10
+ UnsupportedAssetError,
11
+ InvalidSlippageBPSError,
12
+ } from '../errors';
13
+ import { resolveVault } from './vaults';
14
+
15
+ export interface EvmDepositParams {
16
+ vaultId: string;
17
+ amount: bigint;
18
+ // Required for multichain vaults, will default to base
19
+ chainId?: number;
20
+ // Required for multiasset vaults, not utilized yet
21
+ assetSymbol?: string;
22
+ /** Request async (queued) deposit. Only valid for vaults with depositMode 'async' or 'both'. */
23
+ depositMode?: string;
24
+ // So a developer is able to specify a separate receiver than the tx sender
25
+ receiver?: Address;
26
+ /** Slippage tolerance in basis points (e.g. 100 = 1%). Defaults to 100. */
27
+ slippageBps?: number;
28
+ }
29
+
30
+ /**
31
+ * Builds the ordered list of EVM transactions required to deposit into a Gauntlet vault.
32
+ *
33
+ * Returns one or two transactions: an ERC-20 approval (only if the current allowance is
34
+ * insufficient) followed by the deposit or async deposit request. Each transaction is
35
+ * returned as a `PreparedTx` object ready to be signed and sent.
36
+ *
37
+ * @param client - A configured `GauntletClient` instance with an EVM public client and wallet.
38
+ * @param params - Deposit parameters including the vault identifier, token amount, and optional
39
+ * chain, asset symbol, deposit mode (`'sync'` | `'async'`), and receiver address.
40
+ * @returns Ordered array of prepared transactions to execute in sequence.
41
+ *
42
+ * @throws {VaultNotFoundError} If the vault ID is not found in the manifest.
43
+ * @throws {AccountRequiredError} If no wallet account is set on the client.
44
+ * @throws {UnsupportedDepositModeError} If the requested deposit mode is not supported by the vault.
45
+ * @throws {UnsupportedAssetError} If the specified asset symbol is not accepted by the vault.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * const txs = await getDepositTx(client, {
50
+ * vaultId: 'baseUsdcPrime',
51
+ * amount: 100_000_000n, // 100 USDC (6 decimals)
52
+ * });
53
+ * for (const tx of txs) {
54
+ * await walletClient.sendTransaction(tx.tx);
55
+ * }
56
+ * ```
57
+ */
58
+ export async function getDepositTx(
59
+ client: GauntletClient,
60
+ params: EvmDepositParams
61
+ ): Promise<PreparedTx[]> {
62
+ if (
63
+ params.slippageBps !== undefined &&
64
+ (!Number.isInteger(params.slippageBps) || params.slippageBps < 0 || params.slippageBps > 10000)
65
+ ) {
66
+ throw new InvalidSlippageBPSError(params.slippageBps);
67
+ }
68
+
69
+ const resolved = await resolveVault(client, params.vaultId, params.chainId);
70
+ if (!resolved) throw new VaultNotFoundError(params.vaultId);
71
+
72
+ const chainId = params.chainId ?? resolved.vault.chainId;
73
+
74
+ const account = client.wallet?.account?.address;
75
+ if (!account) throw new AccountRequiredError();
76
+
77
+ const { vault, protocol } = resolved;
78
+
79
+ if (params.depositMode === 'sync' && vault.depositMode === 'async') {
80
+ throw new UnsupportedDepositModeError(params.vaultId, 'sync', vault.depositMode);
81
+ }
82
+ if (params.depositMode === 'async' && vault.depositMode === 'sync') {
83
+ throw new UnsupportedDepositModeError(params.vaultId, 'async', vault.depositMode);
84
+ }
85
+ let modifiedDepositMode = params.depositMode;
86
+ if (params.depositMode === undefined) {
87
+ modifiedDepositMode = vault.depositMode === 'both' ? 'async' : vault.depositMode;
88
+ }
89
+
90
+ const spender = vault.provisionerAddress ?? vault.vaultAddress;
91
+ const adapter = getAdapter(protocol);
92
+ const publicClient = client.getPublicClient(chainId);
93
+ const token =
94
+ vault.supplyToken.length > 1
95
+ ? vault.supplyToken.find((tInfo) => tInfo.symbol === params.assetSymbol)
96
+ : vault.supplyToken[0];
97
+
98
+ if (token === undefined) {
99
+ throw new UnsupportedAssetError(params.assetSymbol ?? 'unknown', params.vaultId);
100
+ }
101
+
102
+ // NOTE: this could be moved to the buildDeposit level
103
+ const { sufficient } = await adapter.checkAllowance({
104
+ publicClient,
105
+ token: token.address,
106
+ owner: account,
107
+ spender,
108
+ amount: params.amount,
109
+ });
110
+
111
+ const steps: EvmTxStep[] = [];
112
+
113
+ if (!sufficient) {
114
+ steps.push(
115
+ adapter.buildApproval({
116
+ token: token.address,
117
+ spender,
118
+ amount: params.amount,
119
+ account,
120
+ })
121
+ );
122
+ }
123
+
124
+ const depositSteps = await adapter.buildDeposit({
125
+ vault,
126
+ amount: params.amount,
127
+ receiver: params.receiver ?? account,
128
+ account,
129
+ async: modifiedDepositMode === 'async',
130
+ asset: token,
131
+ publicClient,
132
+ slippageBps: params.slippageBps,
133
+ });
134
+ steps.push(...depositSteps);
135
+
136
+ return await Promise.all(steps.map((step) => encodeTransactionWithAttribution(client, step)));
137
+ }
@@ -0,0 +1,11 @@
1
+ export { getDepositTx } from './deposit';
2
+ export { getWithdrawTx } from './withdraw';
3
+ export { getUserCurrentBalance } from './userCurrentBalance';
4
+ export { getVaults, VaultId } from './vaults';
5
+
6
+ export type { EvmDepositParams } from './deposit';
7
+ export type { EvmWithdrawParams } from './withdraw';
8
+ export type { EvmTxStep } from './adapters/types';
9
+ export type { VaultInfo, VaultDeployment, TokenInfo, VaultManifest } from './types';
10
+ export type { VaultFilter } from './vaults';
11
+ export type { UserCurrentBalanceParams, UserCurrentBalance } from './userCurrentBalance';
@@ -0,0 +1,34 @@
1
+ import type { Address } from 'viem';
2
+
3
+ export interface TokenInfo {
4
+ symbol: string;
5
+ address: Address;
6
+ decimals: number;
7
+ }
8
+
9
+ export interface EvmVaultDeployment {
10
+ chain: 'evm';
11
+ chainId: number;
12
+ vaultAddress: Address;
13
+ /** Present for Aera multi-depositor vaults; absent for single-depositor and Morpho */
14
+ provisionerAddress?: Address;
15
+ vaultType: 'single-depositor' | 'multi-depositor';
16
+ depositMode: 'sync' | 'async' | 'both';
17
+ supplyToken: TokenInfo[];
18
+ }
19
+
20
+ /** Union of all supported chain deployment types. Narrow on `chain` to access chain-specific fields. */
21
+ export type VaultDeployment = EvmVaultDeployment;
22
+
23
+ export interface VaultInfo {
24
+ vaultId: string;
25
+ name: string;
26
+ protocol: 'aera' | 'morpho';
27
+ strategy: string;
28
+ deployments: VaultDeployment[];
29
+ }
30
+
31
+ export interface VaultManifest {
32
+ version: string;
33
+ vaults: VaultInfo[];
34
+ }