@obolnetwork/obol-sdk 2.0.0 → 2.1.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 +6 -0
- package/dist/cjs/package.json +4 -7
- package/dist/cjs/src/abi/Multicall.js +148 -0
- package/dist/cjs/src/abi/OWR.js +133 -0
- package/dist/cjs/src/abi/SplitMain.js +929 -0
- package/dist/cjs/src/ajv.js +17 -2
- package/dist/cjs/src/bytecodes.js +9 -0
- package/dist/cjs/src/constants.js +48 -1
- package/dist/cjs/src/index.js +146 -0
- package/dist/cjs/src/schema.js +52 -5
- package/dist/cjs/src/splitHelpers.js +177 -0
- package/dist/cjs/src/utils.js +22 -1
- package/dist/cjs/src/verification/common.js +8 -0
- package/dist/cjs/src/verification/v1.8.0.js +5 -3
- package/dist/cjs/test/fixtures.js +119 -2
- package/dist/cjs/test/methods.test.js +227 -11
- package/dist/esm/package.json +4 -7
- package/dist/esm/src/abi/Multicall.js +145 -0
- package/dist/esm/src/abi/OWR.js +130 -0
- package/dist/esm/src/abi/SplitMain.js +926 -0
- package/dist/esm/src/ajv.js +17 -2
- package/dist/esm/src/bytecodes.js +6 -0
- package/dist/esm/src/constants.js +47 -0
- package/dist/esm/src/index.js +148 -2
- package/dist/esm/src/schema.js +51 -4
- package/dist/esm/src/splitHelpers.js +168 -0
- package/dist/esm/src/utils.js +19 -0
- package/dist/esm/src/verification/common.js +8 -0
- package/dist/esm/src/verification/v1.8.0.js +5 -3
- package/dist/esm/test/fixtures.js +118 -1
- package/dist/esm/test/methods.test.js +206 -13
- package/dist/types/src/abi/Multicall.d.ts +35 -0
- package/dist/types/src/abi/OWR.d.ts +52 -0
- package/dist/types/src/abi/SplitMain.d.ts +1159 -0
- package/dist/types/src/bytecodes.d.ts +6 -0
- package/dist/types/src/constants.d.ts +25 -0
- package/dist/types/src/index.d.ts +29 -1
- package/dist/types/src/schema.d.ts +85 -4
- package/dist/types/src/splitHelpers.d.ts +62 -0
- package/dist/types/src/types.d.ts +40 -5
- package/dist/types/src/utils.d.ts +3 -0
- package/dist/types/test/fixtures.d.ts +51 -0
- package/package.json +4 -7
- package/src/abi/Multicall.ts +145 -0
- package/src/abi/OWR.ts +130 -0
- package/src/abi/SplitMain.ts +927 -0
- package/src/ajv.ts +33 -2
- package/src/bytecodes.ts +12 -0
- package/src/constants.ts +59 -0
- package/src/index.ts +244 -2
- package/src/schema.ts +67 -4
- package/src/splitHelpers.ts +341 -0
- package/src/types.ts +50 -6
- package/src/utils.ts +21 -0
- package/src/verification/common.ts +12 -0
- package/src/verification/v1.8.0.ts +4 -4
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ClusterValidator,
|
|
3
|
+
type ETH_ADDRESS,
|
|
4
|
+
type SplitRecipient,
|
|
5
|
+
} from './types';
|
|
6
|
+
import {
|
|
7
|
+
Contract,
|
|
8
|
+
Interface,
|
|
9
|
+
parseEther,
|
|
10
|
+
ZeroAddress,
|
|
11
|
+
type Signer,
|
|
12
|
+
} from 'ethers';
|
|
13
|
+
import { OWRFactoryContract } from './abi/OWR';
|
|
14
|
+
import { splitMainEthereumAbi } from './abi/SplitMain';
|
|
15
|
+
import { MultiCallContract } from './abi/Multicall';
|
|
16
|
+
import { CHAIN_CONFIGURATION } from './constants';
|
|
17
|
+
|
|
18
|
+
const splitMainContractInterface = new Interface(splitMainEthereumAbi);
|
|
19
|
+
const owrFactoryContractInterface = new Interface(OWRFactoryContract.abi);
|
|
20
|
+
|
|
21
|
+
type Call = {
|
|
22
|
+
target: ETH_ADDRESS;
|
|
23
|
+
callData: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type OWRArgs = {
|
|
27
|
+
recoveryAddress: ETH_ADDRESS;
|
|
28
|
+
principalRecipient: ETH_ADDRESS;
|
|
29
|
+
amountOfPrincipalStake: number;
|
|
30
|
+
predictedSplitterAddress: ETH_ADDRESS;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
type SplitArgs = {
|
|
34
|
+
accounts: ETH_ADDRESS[];
|
|
35
|
+
percentAllocations: number[];
|
|
36
|
+
distributorFee: number;
|
|
37
|
+
controllerAddress: ETH_ADDRESS;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const formatSplitRecipients = (
|
|
41
|
+
recipients: SplitRecipient[],
|
|
42
|
+
): { accounts: ETH_ADDRESS[]; percentAllocations: number[] } => {
|
|
43
|
+
// Has to be sorted when passed
|
|
44
|
+
recipients.sort((a, b) => a.account.localeCompare(b.account));
|
|
45
|
+
const accounts = recipients.map(item => item.account);
|
|
46
|
+
const percentAllocations = recipients.map(recipient => {
|
|
47
|
+
const splitTostring = (recipient.percentAllocation * 1e4).toFixed(0);
|
|
48
|
+
return parseInt(splitTostring);
|
|
49
|
+
});
|
|
50
|
+
return { accounts, percentAllocations };
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const predictSplitterAddress = async ({
|
|
54
|
+
signer,
|
|
55
|
+
accounts,
|
|
56
|
+
percentAllocations,
|
|
57
|
+
chainId,
|
|
58
|
+
distributorFee,
|
|
59
|
+
controllerAddress,
|
|
60
|
+
}: {
|
|
61
|
+
signer: Signer;
|
|
62
|
+
accounts: ETH_ADDRESS[];
|
|
63
|
+
percentAllocations: number[];
|
|
64
|
+
chainId: number;
|
|
65
|
+
distributorFee: number;
|
|
66
|
+
controllerAddress: ETH_ADDRESS;
|
|
67
|
+
}): Promise<ETH_ADDRESS> => {
|
|
68
|
+
try {
|
|
69
|
+
let predictedSplitterAddress: string;
|
|
70
|
+
const splitMainContractInstance = new Contract(
|
|
71
|
+
CHAIN_CONFIGURATION[chainId].SPLITMAIN_ADDRESS.address,
|
|
72
|
+
splitMainEthereumAbi,
|
|
73
|
+
signer,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
if (controllerAddress === ZeroAddress) {
|
|
77
|
+
predictedSplitterAddress =
|
|
78
|
+
await splitMainContractInstance.predictImmutableSplitAddress(
|
|
79
|
+
accounts,
|
|
80
|
+
percentAllocations,
|
|
81
|
+
distributorFee,
|
|
82
|
+
);
|
|
83
|
+
} else {
|
|
84
|
+
// It throws on deployed Immutable splitter
|
|
85
|
+
predictedSplitterAddress =
|
|
86
|
+
await splitMainContractInstance.createSplit.staticCall(
|
|
87
|
+
accounts,
|
|
88
|
+
percentAllocations,
|
|
89
|
+
distributorFee,
|
|
90
|
+
controllerAddress,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return predictedSplitterAddress;
|
|
95
|
+
} catch (e) {
|
|
96
|
+
throw e;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const handleDeployOWRAndSplitter = async ({
|
|
101
|
+
signer,
|
|
102
|
+
isSplitterDeployed,
|
|
103
|
+
predictedSplitterAddress,
|
|
104
|
+
accounts,
|
|
105
|
+
percentAllocations,
|
|
106
|
+
etherAmount,
|
|
107
|
+
principalRecipient,
|
|
108
|
+
chainId,
|
|
109
|
+
distributorFee,
|
|
110
|
+
controllerAddress,
|
|
111
|
+
recoveryAddress,
|
|
112
|
+
}: {
|
|
113
|
+
signer: Signer;
|
|
114
|
+
isSplitterDeployed: boolean;
|
|
115
|
+
predictedSplitterAddress: ETH_ADDRESS;
|
|
116
|
+
accounts: ETH_ADDRESS[];
|
|
117
|
+
percentAllocations: number[];
|
|
118
|
+
etherAmount: number;
|
|
119
|
+
principalRecipient: ETH_ADDRESS;
|
|
120
|
+
chainId: number;
|
|
121
|
+
distributorFee: number;
|
|
122
|
+
controllerAddress: ETH_ADDRESS;
|
|
123
|
+
recoveryAddress: ETH_ADDRESS;
|
|
124
|
+
}): Promise<ClusterValidator> => {
|
|
125
|
+
try {
|
|
126
|
+
if (isSplitterDeployed) {
|
|
127
|
+
const owrAddress = await createOWRContract({
|
|
128
|
+
owrArgs: {
|
|
129
|
+
principalRecipient,
|
|
130
|
+
amountOfPrincipalStake: etherAmount,
|
|
131
|
+
predictedSplitterAddress,
|
|
132
|
+
recoveryAddress,
|
|
133
|
+
},
|
|
134
|
+
signer,
|
|
135
|
+
chainId,
|
|
136
|
+
});
|
|
137
|
+
return {
|
|
138
|
+
withdrawal_address: owrAddress,
|
|
139
|
+
fee_recipient_address: predictedSplitterAddress,
|
|
140
|
+
};
|
|
141
|
+
} else {
|
|
142
|
+
const { owrAddress, splitterAddress } =
|
|
143
|
+
await deploySplitterAndOWRContracts({
|
|
144
|
+
owrArgs: {
|
|
145
|
+
principalRecipient,
|
|
146
|
+
amountOfPrincipalStake: etherAmount,
|
|
147
|
+
predictedSplitterAddress,
|
|
148
|
+
recoveryAddress,
|
|
149
|
+
},
|
|
150
|
+
splitterArgs: {
|
|
151
|
+
accounts,
|
|
152
|
+
percentAllocations,
|
|
153
|
+
distributorFee,
|
|
154
|
+
controllerAddress,
|
|
155
|
+
},
|
|
156
|
+
signer,
|
|
157
|
+
chainId,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
withdrawal_address: owrAddress,
|
|
162
|
+
fee_recipient_address: splitterAddress,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
} catch (e) {
|
|
166
|
+
throw e;
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const createOWRContract = async ({
|
|
171
|
+
owrArgs,
|
|
172
|
+
signer,
|
|
173
|
+
chainId,
|
|
174
|
+
}: {
|
|
175
|
+
owrArgs: OWRArgs;
|
|
176
|
+
signer: Signer;
|
|
177
|
+
chainId: number;
|
|
178
|
+
}): Promise<ETH_ADDRESS> => {
|
|
179
|
+
try {
|
|
180
|
+
const OWRFactoryInstance = new Contract(
|
|
181
|
+
CHAIN_CONFIGURATION[chainId].OWR_FACTORY_ADDRESS.address,
|
|
182
|
+
OWRFactoryContract.abi,
|
|
183
|
+
signer,
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
const tx = await OWRFactoryInstance.createOWRecipient(
|
|
187
|
+
owrArgs.recoveryAddress,
|
|
188
|
+
owrArgs.principalRecipient,
|
|
189
|
+
owrArgs.predictedSplitterAddress,
|
|
190
|
+
parseEther(owrArgs.amountOfPrincipalStake.toString()),
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
const receipt = await tx.wait();
|
|
194
|
+
const OWRAddressData = receipt?.logs[0]?.topics[1];
|
|
195
|
+
const formattedOWRAddress = '0x' + OWRAddressData?.slice(26, 66);
|
|
196
|
+
|
|
197
|
+
return formattedOWRAddress;
|
|
198
|
+
} catch (e) {
|
|
199
|
+
throw e;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
export const deploySplitterContract = async ({
|
|
204
|
+
signer,
|
|
205
|
+
accounts,
|
|
206
|
+
percentAllocations,
|
|
207
|
+
chainId,
|
|
208
|
+
distributorFee,
|
|
209
|
+
controllerAddress,
|
|
210
|
+
}: {
|
|
211
|
+
signer: Signer;
|
|
212
|
+
accounts: ETH_ADDRESS[];
|
|
213
|
+
percentAllocations: number[];
|
|
214
|
+
chainId: number;
|
|
215
|
+
distributorFee: number;
|
|
216
|
+
controllerAddress: ETH_ADDRESS;
|
|
217
|
+
}): Promise<ETH_ADDRESS> => {
|
|
218
|
+
try {
|
|
219
|
+
const splitMainContractInstance = new Contract(
|
|
220
|
+
CHAIN_CONFIGURATION[chainId].SPLITMAIN_ADDRESS.address,
|
|
221
|
+
splitMainEthereumAbi,
|
|
222
|
+
signer,
|
|
223
|
+
);
|
|
224
|
+
const tx = await splitMainContractInstance.createSplit(
|
|
225
|
+
accounts,
|
|
226
|
+
percentAllocations,
|
|
227
|
+
distributorFee,
|
|
228
|
+
controllerAddress,
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
const receipt = await tx.wait();
|
|
232
|
+
const splitterAddressData = receipt?.logs[0]?.topics[1];
|
|
233
|
+
const formattedSplitterAddress = '0x' + splitterAddressData?.slice(26, 66);
|
|
234
|
+
|
|
235
|
+
return formattedSplitterAddress;
|
|
236
|
+
} catch (e) {
|
|
237
|
+
throw e;
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
export const deploySplitterAndOWRContracts = async ({
|
|
241
|
+
owrArgs,
|
|
242
|
+
splitterArgs,
|
|
243
|
+
signer,
|
|
244
|
+
chainId,
|
|
245
|
+
}: {
|
|
246
|
+
owrArgs: OWRArgs;
|
|
247
|
+
splitterArgs: SplitArgs;
|
|
248
|
+
signer: Signer;
|
|
249
|
+
chainId: number;
|
|
250
|
+
}): Promise<{ owrAddress: ETH_ADDRESS; splitterAddress: ETH_ADDRESS }> => {
|
|
251
|
+
const executeCalls: Call[] = [];
|
|
252
|
+
try {
|
|
253
|
+
const splitTxData = encodeCreateSplitTxData(
|
|
254
|
+
splitterArgs.accounts,
|
|
255
|
+
splitterArgs.percentAllocations,
|
|
256
|
+
splitterArgs.distributorFee,
|
|
257
|
+
splitterArgs.controllerAddress,
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
const owrTxData = encodeCreateOWRecipientTxData(
|
|
261
|
+
owrArgs.recoveryAddress,
|
|
262
|
+
owrArgs.principalRecipient,
|
|
263
|
+
owrArgs.predictedSplitterAddress,
|
|
264
|
+
owrArgs.amountOfPrincipalStake,
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
executeCalls.push(
|
|
268
|
+
{
|
|
269
|
+
target: CHAIN_CONFIGURATION[chainId].SPLITMAIN_ADDRESS.address,
|
|
270
|
+
callData: splitTxData,
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
target: CHAIN_CONFIGURATION[chainId].OWR_FACTORY_ADDRESS.address,
|
|
274
|
+
callData: owrTxData,
|
|
275
|
+
},
|
|
276
|
+
);
|
|
277
|
+
const multicallAddess =
|
|
278
|
+
CHAIN_CONFIGURATION[chainId].MULTICALL_ADDRESS.address;
|
|
279
|
+
|
|
280
|
+
const executeMultiCalls = await multicall(
|
|
281
|
+
executeCalls,
|
|
282
|
+
signer,
|
|
283
|
+
multicallAddess,
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
const splitAddressData = executeMultiCalls?.logs[0]?.topics[1];
|
|
287
|
+
const formattedSplitterAddress = '0x' + splitAddressData?.slice(26, 66);
|
|
288
|
+
const owrAddressData = executeMultiCalls?.logs[1]?.topics[1];
|
|
289
|
+
const formattedOwrAddress = '0x' + owrAddressData?.slice(26, 66);
|
|
290
|
+
|
|
291
|
+
return {
|
|
292
|
+
owrAddress: formattedOwrAddress,
|
|
293
|
+
splitterAddress: formattedSplitterAddress,
|
|
294
|
+
};
|
|
295
|
+
} catch (e) {
|
|
296
|
+
throw e;
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
export const multicall = async (
|
|
301
|
+
calls: Call[],
|
|
302
|
+
signer: Signer,
|
|
303
|
+
multicallAddress: string,
|
|
304
|
+
): Promise<any> => {
|
|
305
|
+
const multiCallContractInstance = new Contract(
|
|
306
|
+
multicallAddress,
|
|
307
|
+
MultiCallContract.abi,
|
|
308
|
+
signer,
|
|
309
|
+
);
|
|
310
|
+
const tx = await multiCallContractInstance.aggregate(calls);
|
|
311
|
+
const receipt = await tx.wait();
|
|
312
|
+
return receipt;
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const encodeCreateSplitTxData = (
|
|
316
|
+
accounts: ETH_ADDRESS[],
|
|
317
|
+
percentAllocations: number[],
|
|
318
|
+
distributorFee: number,
|
|
319
|
+
controller: ETH_ADDRESS,
|
|
320
|
+
): ETH_ADDRESS => {
|
|
321
|
+
return splitMainContractInterface.encodeFunctionData('createSplit', [
|
|
322
|
+
accounts,
|
|
323
|
+
percentAllocations,
|
|
324
|
+
distributorFee,
|
|
325
|
+
controller,
|
|
326
|
+
]);
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
const encodeCreateOWRecipientTxData = (
|
|
330
|
+
recoveryAddress: ETH_ADDRESS,
|
|
331
|
+
principalRecipient: ETH_ADDRESS,
|
|
332
|
+
rewardRecipient: ETH_ADDRESS,
|
|
333
|
+
amountOfPrincipalStake: number,
|
|
334
|
+
): ETH_ADDRESS => {
|
|
335
|
+
return owrFactoryContractInterface.encodeFunctionData('createOWRecipient', [
|
|
336
|
+
recoveryAddress,
|
|
337
|
+
principalRecipient,
|
|
338
|
+
rewardRecipient,
|
|
339
|
+
parseEther(amountOfPrincipalStake.toString()),
|
|
340
|
+
]);
|
|
341
|
+
};
|
package/src/types.ts
CHANGED
|
@@ -58,10 +58,10 @@ export type ClusterCreator = {
|
|
|
58
58
|
* Validator withdrawal configuration
|
|
59
59
|
*/
|
|
60
60
|
export type ClusterValidator = {
|
|
61
|
-
/**
|
|
61
|
+
/** Address to receive MEV rewards (if enabled), block proposal and priority fees. */
|
|
62
62
|
fee_recipient_address: string;
|
|
63
63
|
|
|
64
|
-
/**
|
|
64
|
+
/** Address to receive skimming rewards and validator principal at exit. */
|
|
65
65
|
withdrawal_address: string;
|
|
66
66
|
};
|
|
67
67
|
|
|
@@ -79,7 +79,7 @@ export type ClusterPayload = {
|
|
|
79
79
|
validators: ClusterValidator[];
|
|
80
80
|
|
|
81
81
|
/** The cluster partial deposits in gwei or 32000000000. */
|
|
82
|
-
deposit_amounts?: string[];
|
|
82
|
+
deposit_amounts?: string[] | null;
|
|
83
83
|
};
|
|
84
84
|
|
|
85
85
|
/**
|
|
@@ -113,13 +113,52 @@ export interface ClusterDefinition extends ClusterPayload {
|
|
|
113
113
|
/** The number of distributed validators in the cluster. */
|
|
114
114
|
num_validators: number;
|
|
115
115
|
|
|
116
|
-
/** The cluster partial deposits in gwei or 32000000000. */
|
|
117
|
-
deposit_amounts?: string[];
|
|
118
|
-
|
|
119
116
|
/** The hash of the cluster definition. */
|
|
120
117
|
definition_hash?: string;
|
|
121
118
|
}
|
|
122
119
|
|
|
120
|
+
/**
|
|
121
|
+
* Split Recipient Keys
|
|
122
|
+
*/
|
|
123
|
+
export type SplitRecipient = {
|
|
124
|
+
/** The split recipient address. */
|
|
125
|
+
account: string;
|
|
126
|
+
|
|
127
|
+
/** The recipient split. */
|
|
128
|
+
percentAllocation: number;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Split Proxy Params
|
|
133
|
+
*/
|
|
134
|
+
export type TotalSplitPayload = {
|
|
135
|
+
/** The split recipients addresses and splits. */
|
|
136
|
+
splitRecipients: SplitRecipient[];
|
|
137
|
+
|
|
138
|
+
/** Split percentageNumber allocated for obol retroactive funding, minimum is 1%. */
|
|
139
|
+
ObolRAFSplit?: number;
|
|
140
|
+
|
|
141
|
+
/** The percentageNumber of accrued rewards that is paid to the caller of the distribution function to compensate them for the gas costs of doing so. Cannot be greater than 10%. For example, 5 represents 5%. */
|
|
142
|
+
distributorFee?: number;
|
|
143
|
+
|
|
144
|
+
/** Address that can mutate the split, should be ZeroAddress for immutable split. */
|
|
145
|
+
controllerAddress?: string;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* OWR and Split Proxy Params
|
|
150
|
+
*/
|
|
151
|
+
export interface RewardsSplitPayload extends TotalSplitPayload {
|
|
152
|
+
/** Address that will reclaim validator principal after exit. */
|
|
153
|
+
principalRecipient: string;
|
|
154
|
+
|
|
155
|
+
/** Amount needed to deploy all validators expected for the OWR/Splitter configuration. */
|
|
156
|
+
etherAmount: number;
|
|
157
|
+
|
|
158
|
+
/** Address that can control where the owr erc-20 tokens can be pushed, if set to zero it goes to splitter or principal address. */
|
|
159
|
+
recoveryAddress?: string;
|
|
160
|
+
}
|
|
161
|
+
|
|
123
162
|
/**
|
|
124
163
|
* Unsigned DV Builder Registration Message
|
|
125
164
|
*/
|
|
@@ -207,3 +246,8 @@ export type ClusterLock = {
|
|
|
207
246
|
/** Node Signature for the lock hash by the node secp256k1 key. */
|
|
208
247
|
node_signatures?: string[];
|
|
209
248
|
};
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* String expected to be Ethereum Address
|
|
252
|
+
*/
|
|
253
|
+
export type ETH_ADDRESS = string;
|
package/src/utils.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Provider } from 'ethers';
|
|
1
2
|
import { DefinitionFlow } from './constants';
|
|
2
3
|
import { type ClusterDefinition } from './types';
|
|
3
4
|
|
|
@@ -54,3 +55,23 @@ export const definitionFlow = (
|
|
|
54
55
|
}
|
|
55
56
|
return null;
|
|
56
57
|
};
|
|
58
|
+
|
|
59
|
+
export const findDeployedBytecode = async (
|
|
60
|
+
contractAddress: string,
|
|
61
|
+
provider: Provider,
|
|
62
|
+
): Promise<string> => {
|
|
63
|
+
return await provider?.getCode(contractAddress);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const isContractAvailable = async (
|
|
67
|
+
contractAddress: string,
|
|
68
|
+
provider: Provider,
|
|
69
|
+
bytecode?: string,
|
|
70
|
+
): Promise<boolean> => {
|
|
71
|
+
const code = await findDeployedBytecode(contractAddress, provider);
|
|
72
|
+
|
|
73
|
+
if (bytecode) {
|
|
74
|
+
return !!code && code === bytecode;
|
|
75
|
+
}
|
|
76
|
+
return !!code && code !== '0x' && code !== '0x0';
|
|
77
|
+
};
|
|
@@ -109,6 +109,18 @@ export const clusterLockHash = (clusterLock: ClusterLock): string => {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
if (semver.eq(clusterLock.cluster_definition.version, 'v1.8.0')) {
|
|
112
|
+
if (
|
|
113
|
+
clusterLock.cluster_definition.deposit_amounts === null &&
|
|
114
|
+
clusterLock.distributed_validators.some(
|
|
115
|
+
distributedValidator =>
|
|
116
|
+
distributedValidator.partial_deposit_data?.length !== 1 ||
|
|
117
|
+
distributedValidator.partial_deposit_data[0].amount !== '32000000000',
|
|
118
|
+
)
|
|
119
|
+
) {
|
|
120
|
+
throw new Error(
|
|
121
|
+
'mismatch between deposit_amounts and partial_deposit_data fields',
|
|
122
|
+
);
|
|
123
|
+
}
|
|
112
124
|
return hashClusterLockV1X8(clusterLock);
|
|
113
125
|
}
|
|
114
126
|
|
|
@@ -137,11 +137,11 @@ export const hashClusterDefinitionV1X8 = (
|
|
|
137
137
|
withdrawal_address: fromHexString(validator.withdrawal_address),
|
|
138
138
|
};
|
|
139
139
|
});
|
|
140
|
-
|
|
141
|
-
(amount: string) => {
|
|
140
|
+
if (cluster.deposit_amounts) {
|
|
141
|
+
val.deposit_amounts = cluster.deposit_amounts.map((amount: string) => {
|
|
142
142
|
return parseInt(amount);
|
|
143
|
-
}
|
|
144
|
-
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
145
|
|
|
146
146
|
if (!configOnly) {
|
|
147
147
|
val.config_hash = fromHexString(cluster.config_hash);
|