@obolnetwork/obol-sdk 2.10.2 → 2.11.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/dist/cjs/package.json +1 -1
- package/dist/cjs/src/abi/BatchDeposit.js +120 -0
- package/dist/cjs/src/abi/Multicall3.js +253 -0
- package/dist/cjs/src/bytecodes.js +4 -4
- package/dist/cjs/src/constants.js +13 -7
- package/dist/cjs/src/eoa/eoa.js +48 -0
- package/dist/cjs/src/eoa/eoaHelpers.js +45 -1
- package/dist/cjs/src/index.js +2 -2
- package/dist/cjs/src/schema.js +83 -1
- package/dist/cjs/src/splits/splitHelpers.js +64 -19
- package/dist/cjs/src/splits/splits.js +54 -11
- package/dist/cjs/test/eoa/eoa.spec.js +75 -0
- package/dist/cjs/test/splits/splits.spec.js +84 -0
- package/dist/esm/package.json +1 -1
- package/dist/esm/src/abi/BatchDeposit.js +117 -0
- package/dist/esm/src/abi/Multicall3.js +250 -0
- package/dist/esm/src/bytecodes.js +3 -3
- package/dist/esm/src/constants.js +14 -8
- package/dist/esm/src/eoa/eoa.js +50 -2
- package/dist/esm/src/eoa/eoaHelpers.js +43 -0
- package/dist/esm/src/index.js +2 -2
- package/dist/esm/src/schema.js +82 -0
- package/dist/esm/src/splits/splitHelpers.js +61 -17
- package/dist/esm/src/splits/splits.js +56 -13
- package/dist/esm/test/eoa/eoa.spec.js +76 -1
- package/dist/esm/test/splits/splits.spec.js +85 -1
- package/dist/types/src/abi/BatchDeposit.d.ts +49 -0
- package/dist/types/src/abi/Multicall3.d.ts +37 -0
- package/dist/types/src/bytecodes.d.ts +3 -3
- package/dist/types/src/eoa/eoa.d.ts +34 -1
- package/dist/types/src/eoa/eoaHelpers.d.ts +15 -0
- package/dist/types/src/schema.d.ts +76 -0
- package/dist/types/src/splits/splitHelpers.d.ts +22 -1
- package/dist/types/src/splits/splits.d.ts +33 -1
- package/dist/types/src/types.d.ts +40 -1
- package/package.json +1 -1
- package/src/abi/BatchDeposit.ts +117 -0
- package/src/abi/Multicall3.ts +250 -0
- package/src/bytecodes.ts +3 -3
- package/src/constants.ts +16 -10
- package/src/eoa/eoa.ts +60 -2
- package/src/eoa/eoaHelpers.ts +68 -0
- package/src/index.ts +4 -4
- package/src/schema.ts +84 -0
- package/src/splits/splitHelpers.ts +99 -19
- package/src/splits/splits.ts +65 -15
- package/src/types.ts +43 -1
- package/dist/cjs/src/abi/Multicall.js +0 -148
- package/dist/esm/src/abi/Multicall.js +0 -145
- package/dist/types/src/abi/Multicall.d.ts +0 -35
- package/src/abi/Multicall.ts +0 -145
package/src/schema.ts
CHANGED
|
@@ -280,3 +280,87 @@ export const eoaWithdrawalPayloadSchema = {
|
|
|
280
280
|
},
|
|
281
281
|
required: ['pubkey', 'allocation', 'requiredFee'],
|
|
282
282
|
};
|
|
283
|
+
|
|
284
|
+
export const ovmDepositPayloadSchema = {
|
|
285
|
+
type: 'object',
|
|
286
|
+
properties: {
|
|
287
|
+
ovmAddress: {
|
|
288
|
+
type: 'string',
|
|
289
|
+
pattern: '^0x[a-fA-F0-9]{40}$',
|
|
290
|
+
},
|
|
291
|
+
deposits: {
|
|
292
|
+
type: 'array',
|
|
293
|
+
minItems: 1,
|
|
294
|
+
items: {
|
|
295
|
+
type: 'object',
|
|
296
|
+
properties: {
|
|
297
|
+
pubkey: {
|
|
298
|
+
type: 'string',
|
|
299
|
+
pattern: '^0x[a-fA-F0-9]{96}$',
|
|
300
|
+
},
|
|
301
|
+
withdrawal_credentials: {
|
|
302
|
+
type: 'string',
|
|
303
|
+
pattern: '^0x[a-fA-F0-9]{64}$',
|
|
304
|
+
description: '32 bytes withdrawal credentials',
|
|
305
|
+
},
|
|
306
|
+
signature: {
|
|
307
|
+
type: 'string',
|
|
308
|
+
pattern: '^0x[a-fA-F0-9]{192}$',
|
|
309
|
+
description: '96 bytes signature (190 hex chars + 0x prefix)',
|
|
310
|
+
},
|
|
311
|
+
deposit_data_root: {
|
|
312
|
+
type: 'string',
|
|
313
|
+
pattern: '^0x[a-fA-F0-9]{64}$', // 32 bytes = 64 hex chars + 0x prefix
|
|
314
|
+
},
|
|
315
|
+
amount: {
|
|
316
|
+
type: 'string',
|
|
317
|
+
pattern: '^[0-9]+$',
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
required: [
|
|
321
|
+
'pubkey',
|
|
322
|
+
'withdrawal_credentials',
|
|
323
|
+
'signature',
|
|
324
|
+
'deposit_data_root',
|
|
325
|
+
'amount',
|
|
326
|
+
],
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
required: ['ovmAddress', 'deposits'],
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
export const eoaDepositPayloadSchema = {
|
|
334
|
+
type: 'object',
|
|
335
|
+
properties: {
|
|
336
|
+
deposits: {
|
|
337
|
+
type: 'array',
|
|
338
|
+
minItems: 1,
|
|
339
|
+
items: {
|
|
340
|
+
type: 'object',
|
|
341
|
+
properties: {
|
|
342
|
+
pubKey: {
|
|
343
|
+
type: 'string',
|
|
344
|
+
pattern: '^0x[a-fA-F0-9]{96}$',
|
|
345
|
+
},
|
|
346
|
+
withdrawalCredentials: {
|
|
347
|
+
type: 'string',
|
|
348
|
+
pattern: '^0x[a-fA-F0-9]{64}$',
|
|
349
|
+
description: '32 bytes withdrawal credentials',
|
|
350
|
+
},
|
|
351
|
+
signature: {
|
|
352
|
+
type: 'string',
|
|
353
|
+
pattern: '^0x[a-fA-F0-9]{192}$',
|
|
354
|
+
description: '96 bytes signature (190 hex chars + 0x prefix)',
|
|
355
|
+
},
|
|
356
|
+
amount: {
|
|
357
|
+
type: 'string',
|
|
358
|
+
pattern: '^[0-9]+$',
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
required: ['pubKey', 'withdrawalCredentials', 'signature', 'amount'],
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
required: ['deposits'],
|
|
366
|
+
};
|
|
@@ -12,9 +12,9 @@ import { Contract, Interface, parseEther, ZeroAddress } from 'ethers';
|
|
|
12
12
|
import { OWRContract, OWRFactoryContract } from '../abi/OWR';
|
|
13
13
|
import { OVMFactoryContract, OVMContract } from '../abi/OVMFactory';
|
|
14
14
|
import { splitMainEthereumAbi } from '../abi/SplitMain';
|
|
15
|
-
import { MultiCallContract } from '../abi/Multicall';
|
|
16
15
|
import { CHAIN_CONFIGURATION, ETHER_TO_GWEI } from '../constants';
|
|
17
16
|
import { splitV2FactoryAbi } from '../abi/splitV2FactoryAbi';
|
|
17
|
+
import { MultiCall3Contract } from '../abi/Multicall3';
|
|
18
18
|
|
|
19
19
|
const splitMainContractInterface = new Interface(splitMainEthereumAbi);
|
|
20
20
|
const owrFactoryContractInterface = new Interface(OWRFactoryContract.abi);
|
|
@@ -217,7 +217,7 @@ export const handleDeployOWRAndSplitter = async ({
|
|
|
217
217
|
splitterAddress = result.splitterAddress;
|
|
218
218
|
} catch (error: any) {
|
|
219
219
|
throw new Error(
|
|
220
|
-
`Failed to deploy both splitter and OWR contracts: ${error.message ?? '
|
|
220
|
+
`Failed to deploy both splitter and OWR contracts: ${error.message ?? 'Multicall3 contract deployment failed'}`,
|
|
221
221
|
);
|
|
222
222
|
}
|
|
223
223
|
|
|
@@ -444,7 +444,7 @@ export const deploySplitterAndOWRContracts = async ({
|
|
|
444
444
|
},
|
|
445
445
|
);
|
|
446
446
|
|
|
447
|
-
const executeMultiCalls = await
|
|
447
|
+
const executeMultiCalls = await multicall3(executeCalls, signer, chainId);
|
|
448
448
|
|
|
449
449
|
const splitAddressData = executeMultiCalls?.logs[0]?.topics[1];
|
|
450
450
|
const formattedSplitterAddress = '0x' + splitAddressData?.slice(26, 66);
|
|
@@ -502,26 +502,26 @@ export const getOWRTranches = async ({
|
|
|
502
502
|
}
|
|
503
503
|
};
|
|
504
504
|
|
|
505
|
-
export const
|
|
505
|
+
export const multicall3 = async (
|
|
506
506
|
calls: Call[],
|
|
507
507
|
signer: SignerType,
|
|
508
508
|
chainId: number,
|
|
509
509
|
): Promise<any> => {
|
|
510
510
|
try {
|
|
511
511
|
const chainConfig = getChainConfig(chainId);
|
|
512
|
-
const
|
|
513
|
-
const
|
|
514
|
-
|
|
515
|
-
|
|
512
|
+
const multicall3Address = chainConfig.MULTICALL3_CONTRACT.address;
|
|
513
|
+
const multiCall3ContractInstance = new Contract(
|
|
514
|
+
multicall3Address,
|
|
515
|
+
MultiCall3Contract.abi,
|
|
516
516
|
signer,
|
|
517
517
|
);
|
|
518
518
|
|
|
519
519
|
let tx;
|
|
520
520
|
try {
|
|
521
|
-
tx = await
|
|
521
|
+
tx = await multiCall3ContractInstance.aggregate(calls);
|
|
522
522
|
} catch (error: any) {
|
|
523
523
|
throw new Error(
|
|
524
|
-
`Failed to submit
|
|
524
|
+
`Failed to submit multicall3 transaction: ${error.message ?? 'Transaction submission failed'}`,
|
|
525
525
|
);
|
|
526
526
|
}
|
|
527
527
|
|
|
@@ -530,13 +530,13 @@ export const multicall = async (
|
|
|
530
530
|
receipt = await tx.wait();
|
|
531
531
|
} catch (error: any) {
|
|
532
532
|
throw new Error(
|
|
533
|
-
`
|
|
533
|
+
`Multicall3 transaction failed or was reverted: ${error.message ?? 'Transaction execution failed'}`,
|
|
534
534
|
);
|
|
535
535
|
}
|
|
536
536
|
|
|
537
537
|
if (!receipt) {
|
|
538
538
|
throw new Error(
|
|
539
|
-
'
|
|
539
|
+
'Multicall3 transaction succeeded but no receipt was returned',
|
|
540
540
|
);
|
|
541
541
|
}
|
|
542
542
|
|
|
@@ -545,13 +545,13 @@ export const multicall = async (
|
|
|
545
545
|
// Re-throw if it's already our custom error
|
|
546
546
|
if (
|
|
547
547
|
error.message.includes('Failed to') ||
|
|
548
|
-
error.message.includes('
|
|
548
|
+
error.message.includes('Multicall3 transaction')
|
|
549
549
|
) {
|
|
550
550
|
throw error;
|
|
551
551
|
}
|
|
552
552
|
// Handle unexpected errors
|
|
553
553
|
throw new Error(
|
|
554
|
-
`Unexpected error in
|
|
554
|
+
`Unexpected error in multicall3: ${error.message ?? 'Unknown error during multicall3 execution'}`,
|
|
555
555
|
);
|
|
556
556
|
}
|
|
557
557
|
};
|
|
@@ -845,8 +845,8 @@ export const deployOVMAndSplitV2 = async ({
|
|
|
845
845
|
callData: ovmTxData,
|
|
846
846
|
});
|
|
847
847
|
|
|
848
|
-
// Execute
|
|
849
|
-
const executeMultiCalls = await
|
|
848
|
+
// Execute multicall3
|
|
849
|
+
const executeMultiCalls = await multicall3(executeCalls, signer, chainId);
|
|
850
850
|
|
|
851
851
|
// Extract addresses from events
|
|
852
852
|
let ovmAddress: string | undefined;
|
|
@@ -861,7 +861,7 @@ export const deployOVMAndSplitV2 = async ({
|
|
|
861
861
|
}
|
|
862
862
|
if (!ovmAddress) {
|
|
863
863
|
throw new Error(
|
|
864
|
-
'Failed to extract contract addresses from
|
|
864
|
+
'Failed to extract contract addresses from multicall3 events',
|
|
865
865
|
);
|
|
866
866
|
}
|
|
867
867
|
|
|
@@ -944,9 +944,89 @@ export const requestWithdrawalFromOVM = async ({
|
|
|
944
944
|
const receipt = await tx.wait();
|
|
945
945
|
|
|
946
946
|
return { txHash: receipt.hash };
|
|
947
|
-
} catch (error:
|
|
947
|
+
} catch (error: unknown) {
|
|
948
|
+
const errorMessage =
|
|
949
|
+
error instanceof Error ? error.message : 'Request withdrawal failed';
|
|
950
|
+
throw new Error(`Failed to request withdrawal from OVM: ${errorMessage}`);
|
|
951
|
+
}
|
|
952
|
+
};
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* Deposits to OVM contract using multicall3 for batch operations
|
|
956
|
+
* @param ovmAddress - The address of the OVM contract
|
|
957
|
+
* @param deposits - Array of deposit objects with all required parameters
|
|
958
|
+
* @param signer - The signer to use for the transaction
|
|
959
|
+
* @returns Promise that resolves to an array of transaction hashes
|
|
960
|
+
*/
|
|
961
|
+
export const depositWithMulticall3 = async ({
|
|
962
|
+
ovmAddress,
|
|
963
|
+
deposits,
|
|
964
|
+
signer,
|
|
965
|
+
chainId,
|
|
966
|
+
}: {
|
|
967
|
+
ovmAddress: string;
|
|
968
|
+
deposits: Array<{
|
|
969
|
+
pubkey: string;
|
|
970
|
+
withdrawal_credentials: string;
|
|
971
|
+
signature: string;
|
|
972
|
+
deposit_data_root: string;
|
|
973
|
+
amount: string;
|
|
974
|
+
}>;
|
|
975
|
+
signer: SignerType;
|
|
976
|
+
chainId: number;
|
|
977
|
+
}): Promise<{ txHashes: string[] }> => {
|
|
978
|
+
try {
|
|
979
|
+
const ovmContract = new Contract(ovmAddress, OVMContract.abi, signer);
|
|
980
|
+
const chainConfig = getChainConfig(chainId);
|
|
981
|
+
const multicall3Address = chainConfig.MULTICALL3_CONTRACT.address;
|
|
982
|
+
const multiCall3ContractInstance = new Contract(
|
|
983
|
+
multicall3Address,
|
|
984
|
+
MultiCall3Contract.abi,
|
|
985
|
+
signer,
|
|
986
|
+
);
|
|
987
|
+
|
|
988
|
+
const BATCH_SIZE = 500;
|
|
989
|
+
const txHashes: string[] = [];
|
|
990
|
+
|
|
991
|
+
// Process deposits in batches of 500
|
|
992
|
+
for (let i = 0; i < deposits.length; i += BATCH_SIZE) {
|
|
993
|
+
const batchDeposits = deposits.slice(i, i + BATCH_SIZE);
|
|
994
|
+
|
|
995
|
+
// Use Multicall3 aggregate3Value (payable per-call)
|
|
996
|
+
const callsWithValue = batchDeposits.map(deposit => ({
|
|
997
|
+
target: ovmAddress,
|
|
998
|
+
allowFailure: false,
|
|
999
|
+
callData: ovmContract.interface.encodeFunctionData('deposit', [
|
|
1000
|
+
deposit.pubkey,
|
|
1001
|
+
deposit.withdrawal_credentials,
|
|
1002
|
+
deposit.signature,
|
|
1003
|
+
deposit.deposit_data_root,
|
|
1004
|
+
]),
|
|
1005
|
+
value: BigInt(deposit.amount),
|
|
1006
|
+
}));
|
|
1007
|
+
|
|
1008
|
+
const totalBatchValue = callsWithValue.reduce(
|
|
1009
|
+
(sum: bigint, c: { value: bigint }) => sum + c.value,
|
|
1010
|
+
BigInt(0),
|
|
1011
|
+
);
|
|
1012
|
+
|
|
1013
|
+
const tx = await multiCall3ContractInstance.aggregate3Value(
|
|
1014
|
+
callsWithValue,
|
|
1015
|
+
{ value: totalBatchValue },
|
|
1016
|
+
);
|
|
1017
|
+
|
|
1018
|
+
const receipt = await tx.wait();
|
|
1019
|
+
if (receipt?.hash) {
|
|
1020
|
+
txHashes.push(receipt.hash);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
return { txHashes };
|
|
1025
|
+
} catch (error: unknown) {
|
|
1026
|
+
const errorMessage =
|
|
1027
|
+
error instanceof Error ? error.message : 'Deposit failed';
|
|
948
1028
|
throw new Error(
|
|
949
|
-
`Failed to
|
|
1029
|
+
`Failed to deposit to OVM with multicall3: ${errorMessage}`,
|
|
950
1030
|
);
|
|
951
1031
|
}
|
|
952
1032
|
};
|
package/src/splits/splits.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
deployOVMContract,
|
|
6
6
|
deployOVMAndSplitV2,
|
|
7
7
|
requestWithdrawalFromOVM,
|
|
8
|
+
depositWithMulticall3,
|
|
8
9
|
} from './splitHelpers';
|
|
9
10
|
import {
|
|
10
11
|
CHAIN_CONFIGURATION,
|
|
@@ -16,6 +17,7 @@ import {
|
|
|
16
17
|
ovmRewardsSplitPayloadSchema,
|
|
17
18
|
ovmTotalSplitPayloadSchema,
|
|
18
19
|
ovmRequestWithdrawalPayloadSchema,
|
|
20
|
+
ovmDepositPayloadSchema,
|
|
19
21
|
} from '../schema';
|
|
20
22
|
import { validatePayload } from '../ajv';
|
|
21
23
|
import { isContractAvailable } from '../utils';
|
|
@@ -26,6 +28,7 @@ import {
|
|
|
26
28
|
type OVMRewardsSplitPayload,
|
|
27
29
|
type OVMTotalSplitPayload,
|
|
28
30
|
type OVMRequestWithdrawalPayload,
|
|
31
|
+
type OVMDepositPayload,
|
|
29
32
|
} from '../types';
|
|
30
33
|
|
|
31
34
|
/**
|
|
@@ -103,15 +106,15 @@ export class ObolSplits {
|
|
|
103
106
|
}
|
|
104
107
|
const ovmFactoryConfig = chainConfig.OVM_FACTORY_CONTRACT;
|
|
105
108
|
const splitV2FactoryConfig = chainConfig.SPLIT_V2_FACTORY_CONTRACT;
|
|
106
|
-
const
|
|
109
|
+
const multiCall3Config = chainConfig.MULTICALL3_CONTRACT;
|
|
107
110
|
|
|
108
111
|
if (
|
|
109
112
|
!ovmFactoryConfig?.address ||
|
|
110
113
|
!ovmFactoryConfig?.bytecode ||
|
|
111
114
|
!splitV2FactoryConfig?.address ||
|
|
112
115
|
!splitV2FactoryConfig?.bytecode ||
|
|
113
|
-
!
|
|
114
|
-
!
|
|
116
|
+
!multiCall3Config?.address ||
|
|
117
|
+
!multiCall3Config?.bytecode
|
|
115
118
|
) {
|
|
116
119
|
throw new Error(
|
|
117
120
|
`Contracts configuration is incomplete for chain ${this.chainId}`,
|
|
@@ -130,16 +133,16 @@ export class ObolSplits {
|
|
|
130
133
|
splitV2FactoryConfig.bytecode,
|
|
131
134
|
);
|
|
132
135
|
|
|
133
|
-
const
|
|
134
|
-
|
|
136
|
+
const checkMultiCall3Contract = await isContractAvailable(
|
|
137
|
+
multiCall3Config.address,
|
|
135
138
|
this.provider,
|
|
136
|
-
|
|
139
|
+
multiCall3Config.bytecode,
|
|
137
140
|
);
|
|
138
141
|
|
|
139
142
|
if (
|
|
140
143
|
!checkOVMFactoryContract ||
|
|
141
144
|
!checkSplitV2FactoryContract ||
|
|
142
|
-
!
|
|
145
|
+
!checkMultiCall3Contract
|
|
143
146
|
) {
|
|
144
147
|
throw new Error(
|
|
145
148
|
`Splitter contract is not deployed or available on chain ${this.chainId}`,
|
|
@@ -270,15 +273,15 @@ export class ObolSplits {
|
|
|
270
273
|
|
|
271
274
|
const ovmFactoryConfig = chainConfig.OVM_FACTORY_CONTRACT;
|
|
272
275
|
const splitV2FactoryConfig = chainConfig.SPLIT_V2_FACTORY_CONTRACT;
|
|
273
|
-
const
|
|
276
|
+
const multiCall3Config = chainConfig.MULTICALL3_CONTRACT;
|
|
274
277
|
|
|
275
278
|
if (
|
|
276
279
|
!ovmFactoryConfig?.address ||
|
|
277
280
|
!ovmFactoryConfig?.bytecode ||
|
|
278
281
|
!splitV2FactoryConfig?.address ||
|
|
279
282
|
!splitV2FactoryConfig?.bytecode ||
|
|
280
|
-
!
|
|
281
|
-
!
|
|
283
|
+
!multiCall3Config?.address ||
|
|
284
|
+
!multiCall3Config?.bytecode
|
|
282
285
|
) {
|
|
283
286
|
throw new Error(
|
|
284
287
|
`Contracts configuration is incomplete for chain ${this.chainId}`,
|
|
@@ -297,16 +300,16 @@ export class ObolSplits {
|
|
|
297
300
|
splitV2FactoryConfig.bytecode,
|
|
298
301
|
);
|
|
299
302
|
|
|
300
|
-
const
|
|
301
|
-
|
|
303
|
+
const checkMultiCall3Contract = await isContractAvailable(
|
|
304
|
+
multiCall3Config.address,
|
|
302
305
|
this.provider,
|
|
303
|
-
|
|
306
|
+
multiCall3Config.bytecode,
|
|
304
307
|
);
|
|
305
308
|
|
|
306
309
|
if (
|
|
307
310
|
!checkOVMFactoryContract ||
|
|
308
311
|
!checkSplitV2FactoryContract ||
|
|
309
|
-
!
|
|
312
|
+
!checkMultiCall3Contract
|
|
310
313
|
) {
|
|
311
314
|
throw new Error(
|
|
312
315
|
`Splitter contract is not deployed or available on chain ${this.chainId}`,
|
|
@@ -382,7 +385,7 @@ export class ObolSplits {
|
|
|
382
385
|
fee_recipient_address: predictedRewardsSplitAddress,
|
|
383
386
|
};
|
|
384
387
|
} else {
|
|
385
|
-
// Use
|
|
388
|
+
// Use multicall3 to deploy any contracts that aren't deployed
|
|
386
389
|
const ovmAddress = await deployOVMAndSplitV2({
|
|
387
390
|
ovmArgs: {
|
|
388
391
|
OVMOwnerAddress: validatedPayload.OVMOwnerAddress,
|
|
@@ -451,4 +454,51 @@ export class ObolSplits {
|
|
|
451
454
|
signer: this.signer,
|
|
452
455
|
});
|
|
453
456
|
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Deposits to OVM contract using multicall3 for batch operations.
|
|
460
|
+
*
|
|
461
|
+
* This method allows depositing to an OVM contract using multicall3 for efficient batch processing.
|
|
462
|
+
* Each deposit includes validator public key, withdrawal credentials, signature, deposit data root, and amount.
|
|
463
|
+
*
|
|
464
|
+
* @remarks
|
|
465
|
+
* **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
|
|
466
|
+
* and not pushed to version control.
|
|
467
|
+
*
|
|
468
|
+
* @param {OVMDepositPayload} payload - Data needed to deposit to OVM
|
|
469
|
+
* @returns {Promise<{txHashes: string[]}>} Array of transaction hashes for all batches
|
|
470
|
+
* @throws Will throw an error if the signer is not provided, OVM address is invalid, or the deposit fails
|
|
471
|
+
*
|
|
472
|
+
* An example of how to use deposit:
|
|
473
|
+
* ```typescript
|
|
474
|
+
* const result = await client.splits.deposit({
|
|
475
|
+
* ovmAddress: '0x1234567890123456789012345678901234567890',
|
|
476
|
+
* deposits: [{
|
|
477
|
+
* pubkey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
478
|
+
* withdrawal_credentials: '0x1234567890123456789012345678901234567890',
|
|
479
|
+
* signature: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
480
|
+
* deposit_data_root: '0x1234567890123456789012345678901234567890123456789012345678901234',
|
|
481
|
+
* amount: '32000000000000000000' // 32 ETH in wei
|
|
482
|
+
* }]
|
|
483
|
+
* });
|
|
484
|
+
* console.log('Deposits completed:', result.txHashes);
|
|
485
|
+
* ```
|
|
486
|
+
*/
|
|
487
|
+
async deposit(payload: OVMDepositPayload): Promise<{ txHashes: string[] }> {
|
|
488
|
+
if (!this.signer) {
|
|
489
|
+
throw new Error('Signer is required in deposit');
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const validatedPayload = validatePayload<OVMDepositPayload>(
|
|
493
|
+
payload,
|
|
494
|
+
ovmDepositPayloadSchema,
|
|
495
|
+
);
|
|
496
|
+
|
|
497
|
+
return await depositWithMulticall3({
|
|
498
|
+
ovmAddress: validatedPayload.ovmAddress,
|
|
499
|
+
deposits: validatedPayload.deposits,
|
|
500
|
+
signer: this.signer,
|
|
501
|
+
chainId: this.chainId,
|
|
502
|
+
});
|
|
503
|
+
}
|
|
454
504
|
}
|
package/src/types.ts
CHANGED
|
@@ -582,7 +582,7 @@ export type ChainConfig = {
|
|
|
582
582
|
address: string;
|
|
583
583
|
bytecode: string;
|
|
584
584
|
};
|
|
585
|
-
|
|
585
|
+
MULTICALL3_CONTRACT: {
|
|
586
586
|
address: string;
|
|
587
587
|
bytecode: string;
|
|
588
588
|
};
|
|
@@ -609,6 +609,9 @@ export type ChainConfig = {
|
|
|
609
609
|
EOA_WITHDRAWAL_CONTRACT?: {
|
|
610
610
|
address: string;
|
|
611
611
|
};
|
|
612
|
+
BATCH_DEPOSIT_CONTRACT?: {
|
|
613
|
+
address: string;
|
|
614
|
+
};
|
|
612
615
|
};
|
|
613
616
|
|
|
614
617
|
/**
|
|
@@ -641,3 +644,42 @@ export type EOAWithdrawalPayload = {
|
|
|
641
644
|
/** Required fee in wei */
|
|
642
645
|
requiredFee: string;
|
|
643
646
|
};
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* Payload for depositing to OVM contract with multicall3
|
|
650
|
+
*/
|
|
651
|
+
export type OVMDepositPayload = {
|
|
652
|
+
/** OVM contract address */
|
|
653
|
+
ovmAddress: string;
|
|
654
|
+
|
|
655
|
+
/** Array of deposit objects */
|
|
656
|
+
deposits: Array<{
|
|
657
|
+
/** Validator public key in hex format (48 bytes) */
|
|
658
|
+
pubkey: string;
|
|
659
|
+
/** Withdrawal credentials in hex format */
|
|
660
|
+
withdrawal_credentials: string;
|
|
661
|
+
/** Deposit signature in hex format */
|
|
662
|
+
signature: string;
|
|
663
|
+
/** Deposit data root in hex format (32 bytes) */
|
|
664
|
+
deposit_data_root: string;
|
|
665
|
+
/** Deposit amount in wei as string */
|
|
666
|
+
amount: string;
|
|
667
|
+
}>;
|
|
668
|
+
};
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Payload for depositing to batch deposit contract
|
|
672
|
+
*/
|
|
673
|
+
export type EOADepositPayload = {
|
|
674
|
+
/** Array of deposit objects */
|
|
675
|
+
deposits: Array<{
|
|
676
|
+
/** Validator public key in hex format (48 bytes) */
|
|
677
|
+
pubKey: string;
|
|
678
|
+
/** Withdrawal credentials in hex format */
|
|
679
|
+
withdrawalCredentials: string;
|
|
680
|
+
/** Deposit signature in hex format */
|
|
681
|
+
signature: string;
|
|
682
|
+
/** Deposit amount in wei as string */
|
|
683
|
+
amount: string;
|
|
684
|
+
}>;
|
|
685
|
+
};
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MultiCallContract = void 0;
|
|
4
|
-
exports.MultiCallContract = {
|
|
5
|
-
abi: [
|
|
6
|
-
{
|
|
7
|
-
constant: true,
|
|
8
|
-
inputs: [],
|
|
9
|
-
name: 'getCurrentBlockTimestamp',
|
|
10
|
-
outputs: [
|
|
11
|
-
{
|
|
12
|
-
name: 'timestamp',
|
|
13
|
-
type: 'uint256',
|
|
14
|
-
},
|
|
15
|
-
],
|
|
16
|
-
payable: false,
|
|
17
|
-
stateMutability: 'view',
|
|
18
|
-
type: 'function',
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
constant: false,
|
|
22
|
-
inputs: [
|
|
23
|
-
{
|
|
24
|
-
components: [
|
|
25
|
-
{
|
|
26
|
-
name: 'target',
|
|
27
|
-
type: 'address',
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
name: 'callData',
|
|
31
|
-
type: 'bytes',
|
|
32
|
-
},
|
|
33
|
-
],
|
|
34
|
-
name: 'calls',
|
|
35
|
-
type: 'tuple[]',
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
name: 'aggregate',
|
|
39
|
-
outputs: [
|
|
40
|
-
{
|
|
41
|
-
name: 'blockNumber',
|
|
42
|
-
type: 'uint256',
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
name: 'returnData',
|
|
46
|
-
type: 'bytes[]',
|
|
47
|
-
},
|
|
48
|
-
],
|
|
49
|
-
payable: false,
|
|
50
|
-
stateMutability: 'nonpayable',
|
|
51
|
-
type: 'function',
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
constant: true,
|
|
55
|
-
inputs: [],
|
|
56
|
-
name: 'getLastBlockHash',
|
|
57
|
-
outputs: [
|
|
58
|
-
{
|
|
59
|
-
name: 'blockHash',
|
|
60
|
-
type: 'bytes32',
|
|
61
|
-
},
|
|
62
|
-
],
|
|
63
|
-
payable: false,
|
|
64
|
-
stateMutability: 'view',
|
|
65
|
-
type: 'function',
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
constant: true,
|
|
69
|
-
inputs: [
|
|
70
|
-
{
|
|
71
|
-
name: 'addr',
|
|
72
|
-
type: 'address',
|
|
73
|
-
},
|
|
74
|
-
],
|
|
75
|
-
name: 'getEthBalance',
|
|
76
|
-
outputs: [
|
|
77
|
-
{
|
|
78
|
-
name: 'balance',
|
|
79
|
-
type: 'uint256',
|
|
80
|
-
},
|
|
81
|
-
],
|
|
82
|
-
payable: false,
|
|
83
|
-
stateMutability: 'view',
|
|
84
|
-
type: 'function',
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
constant: true,
|
|
88
|
-
inputs: [],
|
|
89
|
-
name: 'getCurrentBlockDifficulty',
|
|
90
|
-
outputs: [
|
|
91
|
-
{
|
|
92
|
-
name: 'difficulty',
|
|
93
|
-
type: 'uint256',
|
|
94
|
-
},
|
|
95
|
-
],
|
|
96
|
-
payable: false,
|
|
97
|
-
stateMutability: 'view',
|
|
98
|
-
type: 'function',
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
constant: true,
|
|
102
|
-
inputs: [],
|
|
103
|
-
name: 'getCurrentBlockGasLimit',
|
|
104
|
-
outputs: [
|
|
105
|
-
{
|
|
106
|
-
name: 'gaslimit',
|
|
107
|
-
type: 'uint256',
|
|
108
|
-
},
|
|
109
|
-
],
|
|
110
|
-
payable: false,
|
|
111
|
-
stateMutability: 'view',
|
|
112
|
-
type: 'function',
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
constant: true,
|
|
116
|
-
inputs: [],
|
|
117
|
-
name: 'getCurrentBlockCoinbase',
|
|
118
|
-
outputs: [
|
|
119
|
-
{
|
|
120
|
-
name: 'coinbase',
|
|
121
|
-
type: 'address',
|
|
122
|
-
},
|
|
123
|
-
],
|
|
124
|
-
payable: false,
|
|
125
|
-
stateMutability: 'view',
|
|
126
|
-
type: 'function',
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
constant: true,
|
|
130
|
-
inputs: [
|
|
131
|
-
{
|
|
132
|
-
name: 'blockNumber',
|
|
133
|
-
type: 'uint256',
|
|
134
|
-
},
|
|
135
|
-
],
|
|
136
|
-
name: 'getBlockHash',
|
|
137
|
-
outputs: [
|
|
138
|
-
{
|
|
139
|
-
name: 'blockHash',
|
|
140
|
-
type: 'bytes32',
|
|
141
|
-
},
|
|
142
|
-
],
|
|
143
|
-
payable: false,
|
|
144
|
-
stateMutability: 'view',
|
|
145
|
-
type: 'function',
|
|
146
|
-
},
|
|
147
|
-
],
|
|
148
|
-
};
|