@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.
- package/LICENSE +21 -0
- package/README.md +120 -0
- package/dist/manifest/vaults.json +139 -0
- package/dist/src/attribution/erc8021.d.ts +2 -0
- package/dist/src/attribution/erc8021.js +7 -0
- package/dist/src/attribution/erc8021.js.map +1 -0
- package/dist/src/attribution/index.d.ts +16 -0
- package/dist/src/attribution/index.js +37 -0
- package/dist/src/attribution/index.js.map +1 -0
- package/dist/src/client.d.ts +28 -0
- package/dist/src/client.js +35 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/errors.d.ts +55 -0
- package/dist/src/errors.js +97 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/evm/abis/erc20.d.ts +40 -0
- package/dist/src/evm/abis/erc20.js +30 -0
- package/dist/src/evm/abis/erc20.js.map +1 -0
- package/dist/src/evm/abis/erc4626.d.ts +104 -0
- package/dist/src/evm/abis/erc4626.js +70 -0
- package/dist/src/evm/abis/erc4626.js.map +1 -0
- package/dist/src/evm/abis/multiDepositorVault.d.ts +1047 -0
- package/dist/src/evm/abis/multiDepositorVault.js +587 -0
- package/dist/src/evm/abis/multiDepositorVault.js.map +1 -0
- package/dist/src/evm/abis/priceAndFeeCalculator.d.ts +909 -0
- package/dist/src/evm/abis/priceAndFeeCalculator.js +490 -0
- package/dist/src/evm/abis/priceAndFeeCalculator.js.map +1 -0
- package/dist/src/evm/abis/provisioner.d.ts +4983 -0
- package/dist/src/evm/abis/provisioner.js +2738 -0
- package/dist/src/evm/abis/provisioner.js.map +1 -0
- package/dist/src/evm/adapters/aera.d.ts +5 -0
- package/dist/src/evm/adapters/aera.js +144 -0
- package/dist/src/evm/adapters/aera.js.map +1 -0
- package/dist/src/evm/adapters/index.d.ts +2 -0
- package/dist/src/evm/adapters/index.js +14 -0
- package/dist/src/evm/adapters/index.js.map +1 -0
- package/dist/src/evm/adapters/morpho.d.ts +2 -0
- package/dist/src/evm/adapters/morpho.js +79 -0
- package/dist/src/evm/adapters/morpho.js.map +1 -0
- package/dist/src/evm/adapters/types.d.ts +65 -0
- package/dist/src/evm/adapters/types.js +2 -0
- package/dist/src/evm/adapters/types.js.map +1 -0
- package/dist/src/evm/aeraContracts.d.ts +2315 -0
- package/dist/src/evm/aeraContracts.js +37 -0
- package/dist/src/evm/aeraContracts.js.map +1 -0
- package/dist/src/evm/deposit.d.ts +13 -0
- package/dist/src/evm/deposit.js +66 -0
- package/dist/src/evm/deposit.js.map +1 -0
- package/dist/src/evm/index.d.ts +10 -0
- package/dist/src/evm/index.js +5 -0
- package/dist/src/evm/index.js.map +1 -0
- package/dist/src/evm/types.d.ts +27 -0
- package/dist/src/evm/types.js +2 -0
- package/dist/src/evm/types.js.map +1 -0
- package/dist/src/evm/userCurrentBalance.d.ts +16 -0
- package/dist/src/evm/userCurrentBalance.js +164 -0
- package/dist/src/evm/userCurrentBalance.js.map +1 -0
- package/dist/src/evm/vaults.d.ts +17 -0
- package/dist/src/evm/vaults.js +39 -0
- package/dist/src/evm/vaults.js.map +1 -0
- package/dist/src/evm/withdraw.d.ts +24 -0
- package/dist/src/evm/withdraw.js +51 -0
- package/dist/src/evm/withdraw.js.map +1 -0
- package/dist/src/index.d.ts +7 -0
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/manifest/vaults.json +139 -0
- package/package.json +64 -0
- package/src/attribution/erc8021.ts +14 -0
- package/src/attribution/index.ts +62 -0
- package/src/client.ts +95 -0
- package/src/errors.ts +135 -0
- package/src/evm/abis/erc20.ts +29 -0
- package/src/evm/abis/erc4626.ts +69 -0
- package/src/evm/abis/multiDepositorVault.ts +586 -0
- package/src/evm/abis/priceAndFeeCalculator.ts +489 -0
- package/src/evm/abis/provisioner.ts +2787 -0
- package/src/evm/adapters/aera.ts +254 -0
- package/src/evm/adapters/index.ts +15 -0
- package/src/evm/adapters/morpho.ts +92 -0
- package/src/evm/adapters/types.ts +64 -0
- package/src/evm/aeraContracts.ts +82 -0
- package/src/evm/deposit.ts +137 -0
- package/src/evm/index.ts +11 -0
- package/src/evm/types.ts +34 -0
- package/src/evm/userCurrentBalance.ts +265 -0
- package/src/evm/vaults.ts +88 -0
- package/src/evm/withdraw.ts +127 -0
- 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
|
+
}
|
package/src/evm/index.ts
ADDED
|
@@ -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';
|
package/src/evm/types.ts
ADDED
|
@@ -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
|
+
}
|