@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import pjson from '../package.json';
|
|
2
2
|
import { FORK_MAPPING } from './types';
|
|
3
|
-
import {
|
|
3
|
+
import { HOLESKY_MULTICALL3_BYTECODE, HOLESKY_OWR_FACTORY_BYTECODE, HOLESKY_SPLITMAIN_BYTECODE, HOODI_MULTICALL3_BYTECODE, HOODI_OVM_FACTORY_BYTECODE, HOODI_OWR_FACTORY_BYTECODE, HOODI_SPLIT_V2_FACTORY_BYTECODE, HOODI_SPLITMAIN_BYTECODE, HOODI_WAREHOUSE_BYTECODE, MAINNET_MULTICALL3_BYTECODE, MAINNET_OVM_FACTORY_BYTECODE, MAINNET_OWR_FACTORY_BYTECODE, MAINNET_SPLIT_V2_FACTORY_BYTECODE, MAINNET_SPLITMAIN_BYTECODE, MAINNET_WAREHOUSE_BYTECODE, } from './bytecodes';
|
|
4
4
|
import * as dotenv from 'dotenv';
|
|
5
5
|
dotenv.config();
|
|
6
6
|
export const CONFLICT_ERROR_MSG = 'Conflict';
|
|
@@ -112,9 +112,9 @@ export const CHAIN_CONFIGURATION = {
|
|
|
112
112
|
address: '0x2ed6c4B5dA6378c7897AC67Ba9e43102Feb694EE',
|
|
113
113
|
bytecode: MAINNET_SPLITMAIN_BYTECODE,
|
|
114
114
|
},
|
|
115
|
-
|
|
116
|
-
address: '
|
|
117
|
-
bytecode:
|
|
115
|
+
MULTICALL3_CONTRACT: {
|
|
116
|
+
address: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
|
117
|
+
bytecode: MAINNET_MULTICALL3_BYTECODE,
|
|
118
118
|
},
|
|
119
119
|
OWR_FACTORY_CONTRACT: {
|
|
120
120
|
address: '0x119acd7844cbdd5fc09b1c6a4408f490c8f7f522',
|
|
@@ -140,15 +140,18 @@ export const CHAIN_CONFIGURATION = {
|
|
|
140
140
|
EOA_WITHDRAWAL_CONTRACT: {
|
|
141
141
|
address: '0x00000961Ef480Eb55e80D19ad83579A64c007002',
|
|
142
142
|
},
|
|
143
|
+
BATCH_DEPOSIT_CONTRACT: {
|
|
144
|
+
address: '0xcD7a6C118Ac8F6544BC5076F2D8Fb86D2C546756',
|
|
145
|
+
},
|
|
143
146
|
},
|
|
144
147
|
[FORK_MAPPING['0x01017000']]: {
|
|
145
148
|
SPLITMAIN_CONTRACT: {
|
|
146
149
|
address: '0xfC8a305728051367797DADE6Aa0344E0987f5286',
|
|
147
150
|
bytecode: HOLESKY_SPLITMAIN_BYTECODE,
|
|
148
151
|
},
|
|
149
|
-
|
|
152
|
+
MULTICALL3_CONTRACT: {
|
|
150
153
|
address: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
|
151
|
-
bytecode:
|
|
154
|
+
bytecode: HOLESKY_MULTICALL3_BYTECODE,
|
|
152
155
|
},
|
|
153
156
|
OWR_FACTORY_CONTRACT: {
|
|
154
157
|
address: '0xc0961353fcc43a99e3041db07ac646720e116256',
|
|
@@ -167,9 +170,9 @@ export const CHAIN_CONFIGURATION = {
|
|
|
167
170
|
address: '0xc05ae267291705ac16F75283572294ed2a91CBc7',
|
|
168
171
|
bytecode: HOODI_SPLITMAIN_BYTECODE,
|
|
169
172
|
},
|
|
170
|
-
|
|
173
|
+
MULTICALL3_CONTRACT: {
|
|
171
174
|
address: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
|
172
|
-
bytecode:
|
|
175
|
+
bytecode: HOODI_MULTICALL3_BYTECODE,
|
|
173
176
|
},
|
|
174
177
|
OWR_FACTORY_CONTRACT: {
|
|
175
178
|
address: '0x9ff0c649d0bf5fe7efa4d72e94bed7302ed5c8d7',
|
|
@@ -195,6 +198,9 @@ export const CHAIN_CONFIGURATION = {
|
|
|
195
198
|
EOA_WITHDRAWAL_CONTRACT: {
|
|
196
199
|
address: '0x00000961Ef480Eb55e80D19ad83579A64c007002',
|
|
197
200
|
},
|
|
201
|
+
BATCH_DEPOSIT_CONTRACT: {
|
|
202
|
+
address: '0x4c9506eE2fCd962f03022D9d8ebf6f7828abEfaf',
|
|
203
|
+
},
|
|
198
204
|
},
|
|
199
205
|
};
|
|
200
206
|
export const DEFAULT_RETROACTIVE_FUNDING_REWARDS_ONLY_SPLIT = 1;
|
package/dist/esm/src/eoa/eoa.js
CHANGED
|
@@ -7,9 +7,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { submitEOAWithdrawalRequest } from './eoaHelpers';
|
|
10
|
+
import { submitEOAWithdrawalRequest, submitEOABatchDeposit, } from './eoaHelpers';
|
|
11
11
|
import { validatePayload } from '../ajv';
|
|
12
|
-
import { eoaWithdrawalPayloadSchema } from '../schema';
|
|
12
|
+
import { eoaWithdrawalPayloadSchema, eoaDepositPayloadSchema } from '../schema';
|
|
13
13
|
import { CHAIN_CONFIGURATION } from '../constants';
|
|
14
14
|
/**
|
|
15
15
|
* EOA can be used for managing EOA (Externally Owned Account) operations like withdrawals.
|
|
@@ -76,4 +76,52 @@ export class EOA {
|
|
|
76
76
|
});
|
|
77
77
|
});
|
|
78
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Deposits to batch deposit contract.
|
|
81
|
+
*
|
|
82
|
+
* This method allows depositing multiple validators to the Ethereum beacon chain
|
|
83
|
+
* using the Pier Two batch deposit contract for gas efficiency.
|
|
84
|
+
* Each deposit includes validator public key, withdrawal credentials, signature, and amount.
|
|
85
|
+
*
|
|
86
|
+
* @remarks
|
|
87
|
+
* **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
|
|
88
|
+
* and not pushed to version control.
|
|
89
|
+
*
|
|
90
|
+
* **⚠️ Gas Limit:** Due to EVM constraints, it is recommended to deposit in batches of up to 500 at a time.
|
|
91
|
+
*
|
|
92
|
+
* @param {EOADepositPayload} payload - Data needed to deposit to batch contract
|
|
93
|
+
* @returns {Promise<{txHashes: string[]}>} Array of transaction hashes for all batches
|
|
94
|
+
* @throws Will throw an error if the signer is not provided, contract is not configured, or the deposit fails
|
|
95
|
+
*
|
|
96
|
+
* An example of how to use deposit:
|
|
97
|
+
* ```typescript
|
|
98
|
+
* const result = await client.eoa.deposit({
|
|
99
|
+
* deposits: [{
|
|
100
|
+
* pubKey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
101
|
+
* withdrawalCredentials: '0x1234567890123456789012345678901234567890',
|
|
102
|
+
* signature: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
103
|
+
* amount: '32000000000000000000' // 32 ETH in wei
|
|
104
|
+
* }]
|
|
105
|
+
* });
|
|
106
|
+
* console.log('Deposits completed:', result.txHashes);
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
deposit(payload) {
|
|
110
|
+
var _a;
|
|
111
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
112
|
+
if (!this.signer) {
|
|
113
|
+
throw new Error('Signer is required in deposit');
|
|
114
|
+
}
|
|
115
|
+
const chainConfig = CHAIN_CONFIGURATION[this.chainId];
|
|
116
|
+
if (!((_a = chainConfig === null || chainConfig === void 0 ? void 0 : chainConfig.BATCH_DEPOSIT_CONTRACT) === null || _a === void 0 ? void 0 : _a.address)) {
|
|
117
|
+
throw new Error(`Batch deposit contract is not configured for chain ${this.chainId}`);
|
|
118
|
+
}
|
|
119
|
+
const validatedPayload = validatePayload(payload, eoaDepositPayloadSchema);
|
|
120
|
+
return yield submitEOABatchDeposit({
|
|
121
|
+
deposits: validatedPayload.deposits,
|
|
122
|
+
batchDepositContractAddress: chainConfig.BATCH_DEPOSIT_CONTRACT.address,
|
|
123
|
+
signer: this.signer,
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
}
|
|
79
127
|
}
|
|
@@ -8,6 +8,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { ETHER_TO_GWEI } from '../constants';
|
|
11
|
+
import { Contract } from 'ethers';
|
|
12
|
+
import { BatchDepositContract } from '../abi/BatchDeposit';
|
|
11
13
|
/**
|
|
12
14
|
* Helper function to submit withdrawal request for EOA
|
|
13
15
|
*/
|
|
@@ -31,3 +33,44 @@ export function submitEOAWithdrawalRequest({ pubkey, allocation, withdrawalAddre
|
|
|
31
33
|
return { txHash: receipt.hash };
|
|
32
34
|
});
|
|
33
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Helper function to submit batch deposit request for EOA
|
|
38
|
+
*/
|
|
39
|
+
export function submitEOABatchDeposit({ deposits, batchDepositContractAddress, signer, }) {
|
|
40
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
if (!deposits || deposits.length === 0) {
|
|
42
|
+
throw new Error('No deposits provided');
|
|
43
|
+
}
|
|
44
|
+
// Create contract instance
|
|
45
|
+
const batchDepositContract = new Contract(batchDepositContractAddress, BatchDepositContract.abi, signer);
|
|
46
|
+
const BATCH_SIZE = 500;
|
|
47
|
+
const txHashes = [];
|
|
48
|
+
try {
|
|
49
|
+
// Process deposits in batches of 500
|
|
50
|
+
for (let i = 0; i < deposits.length; i += BATCH_SIZE) {
|
|
51
|
+
const batchDeposits = deposits.slice(i, i + BATCH_SIZE);
|
|
52
|
+
// Calculate total value needed for this batch
|
|
53
|
+
const totalValue = batchDeposits.reduce((sum, deposit) => sum + BigInt(deposit.amount), BigInt(0));
|
|
54
|
+
// Prepare deposit data for this batch
|
|
55
|
+
const depositData = batchDeposits.map(deposit => ({
|
|
56
|
+
pubKey: deposit.pubKey,
|
|
57
|
+
withdrawalCredentials: deposit.withdrawalCredentials,
|
|
58
|
+
signature: deposit.signature,
|
|
59
|
+
amount: BigInt(deposit.amount),
|
|
60
|
+
}));
|
|
61
|
+
// Execute batch deposit for this batch
|
|
62
|
+
const tx = yield batchDepositContract.batchDeposit(depositData, {
|
|
63
|
+
value: totalValue,
|
|
64
|
+
});
|
|
65
|
+
const receipt = yield tx.wait();
|
|
66
|
+
if (receipt === null || receipt === void 0 ? void 0 : receipt.hash) {
|
|
67
|
+
txHashes.push(receipt.hash);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return { txHashes };
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
throw new Error("Failed to submit batch deposit'}");
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
package/dist/esm/src/index.js
CHANGED
|
@@ -135,9 +135,9 @@ export class Client extends Base {
|
|
|
135
135
|
throw new Error(`SPLITMAIN_CONTRACT is not configured for chain ${this.chainId}`);
|
|
136
136
|
}
|
|
137
137
|
const checkSplitMainAddress = yield isContractAvailable(chainConfig.SPLITMAIN_CONTRACT.address, this.signer.provider, chainConfig.SPLITMAIN_CONTRACT.bytecode);
|
|
138
|
-
const
|
|
138
|
+
const checkMulticall3Address = yield isContractAvailable(chainConfig.MULTICALL3_CONTRACT.address, this.signer.provider, chainConfig.MULTICALL3_CONTRACT.bytecode);
|
|
139
139
|
const checkOWRFactoryAddress = yield isContractAvailable(chainConfig.OWR_FACTORY_CONTRACT.address, this.signer.provider, chainConfig.OWR_FACTORY_CONTRACT.bytecode);
|
|
140
|
-
if (!
|
|
140
|
+
if (!checkMulticall3Address ||
|
|
141
141
|
!checkSplitMainAddress ||
|
|
142
142
|
!checkOWRFactoryAddress) {
|
|
143
143
|
throw new Error(`Something isn not working as expected, check this issue with obol-sdk team on ${OBOL_SDK_EMAIL}`);
|
package/dist/esm/src/schema.js
CHANGED
|
@@ -255,3 +255,85 @@ export const eoaWithdrawalPayloadSchema = {
|
|
|
255
255
|
},
|
|
256
256
|
required: ['pubkey', 'allocation', 'requiredFee'],
|
|
257
257
|
};
|
|
258
|
+
export const ovmDepositPayloadSchema = {
|
|
259
|
+
type: 'object',
|
|
260
|
+
properties: {
|
|
261
|
+
ovmAddress: {
|
|
262
|
+
type: 'string',
|
|
263
|
+
pattern: '^0x[a-fA-F0-9]{40}$',
|
|
264
|
+
},
|
|
265
|
+
deposits: {
|
|
266
|
+
type: 'array',
|
|
267
|
+
minItems: 1,
|
|
268
|
+
items: {
|
|
269
|
+
type: 'object',
|
|
270
|
+
properties: {
|
|
271
|
+
pubkey: {
|
|
272
|
+
type: 'string',
|
|
273
|
+
pattern: '^0x[a-fA-F0-9]{96}$',
|
|
274
|
+
},
|
|
275
|
+
withdrawal_credentials: {
|
|
276
|
+
type: 'string',
|
|
277
|
+
pattern: '^0x[a-fA-F0-9]{64}$',
|
|
278
|
+
description: '32 bytes withdrawal credentials',
|
|
279
|
+
},
|
|
280
|
+
signature: {
|
|
281
|
+
type: 'string',
|
|
282
|
+
pattern: '^0x[a-fA-F0-9]{192}$',
|
|
283
|
+
description: '96 bytes signature (190 hex chars + 0x prefix)',
|
|
284
|
+
},
|
|
285
|
+
deposit_data_root: {
|
|
286
|
+
type: 'string',
|
|
287
|
+
pattern: '^0x[a-fA-F0-9]{64}$', // 32 bytes = 64 hex chars + 0x prefix
|
|
288
|
+
},
|
|
289
|
+
amount: {
|
|
290
|
+
type: 'string',
|
|
291
|
+
pattern: '^[0-9]+$',
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
required: [
|
|
295
|
+
'pubkey',
|
|
296
|
+
'withdrawal_credentials',
|
|
297
|
+
'signature',
|
|
298
|
+
'deposit_data_root',
|
|
299
|
+
'amount',
|
|
300
|
+
],
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
required: ['ovmAddress', 'deposits'],
|
|
305
|
+
};
|
|
306
|
+
export const eoaDepositPayloadSchema = {
|
|
307
|
+
type: 'object',
|
|
308
|
+
properties: {
|
|
309
|
+
deposits: {
|
|
310
|
+
type: 'array',
|
|
311
|
+
minItems: 1,
|
|
312
|
+
items: {
|
|
313
|
+
type: 'object',
|
|
314
|
+
properties: {
|
|
315
|
+
pubKey: {
|
|
316
|
+
type: 'string',
|
|
317
|
+
pattern: '^0x[a-fA-F0-9]{96}$',
|
|
318
|
+
},
|
|
319
|
+
withdrawalCredentials: {
|
|
320
|
+
type: 'string',
|
|
321
|
+
pattern: '^0x[a-fA-F0-9]{64}$',
|
|
322
|
+
description: '32 bytes withdrawal credentials',
|
|
323
|
+
},
|
|
324
|
+
signature: {
|
|
325
|
+
type: 'string',
|
|
326
|
+
pattern: '^0x[a-fA-F0-9]{192}$',
|
|
327
|
+
description: '96 bytes signature (190 hex chars + 0x prefix)',
|
|
328
|
+
},
|
|
329
|
+
amount: {
|
|
330
|
+
type: 'string',
|
|
331
|
+
pattern: '^[0-9]+$',
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
required: ['pubKey', 'withdrawalCredentials', 'signature', 'amount'],
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
required: ['deposits'],
|
|
339
|
+
};
|
|
@@ -11,9 +11,9 @@ import { Contract, Interface, parseEther, ZeroAddress } from 'ethers';
|
|
|
11
11
|
import { OWRContract, OWRFactoryContract } from '../abi/OWR';
|
|
12
12
|
import { OVMFactoryContract, OVMContract } from '../abi/OVMFactory';
|
|
13
13
|
import { splitMainEthereumAbi } from '../abi/SplitMain';
|
|
14
|
-
import { MultiCallContract } from '../abi/Multicall';
|
|
15
14
|
import { CHAIN_CONFIGURATION, ETHER_TO_GWEI } from '../constants';
|
|
16
15
|
import { splitV2FactoryAbi } from '../abi/splitV2FactoryAbi';
|
|
16
|
+
import { MultiCall3Contract } from '../abi/Multicall3';
|
|
17
17
|
const splitMainContractInterface = new Interface(splitMainEthereumAbi);
|
|
18
18
|
const owrFactoryContractInterface = new Interface(OWRFactoryContract.abi);
|
|
19
19
|
const ovmFactoryContractInterface = new Interface(OVMFactoryContract.abi);
|
|
@@ -125,7 +125,7 @@ export const handleDeployOWRAndSplitter = ({ signer, isSplitterDeployed, predict
|
|
|
125
125
|
splitterAddress = result.splitterAddress;
|
|
126
126
|
}
|
|
127
127
|
catch (error) {
|
|
128
|
-
throw new Error(`Failed to deploy both splitter and OWR contracts: ${(_e = error.message) !== null && _e !== void 0 ? _e : '
|
|
128
|
+
throw new Error(`Failed to deploy both splitter and OWR contracts: ${(_e = error.message) !== null && _e !== void 0 ? _e : 'Multicall3 contract deployment failed'}`);
|
|
129
129
|
}
|
|
130
130
|
return {
|
|
131
131
|
withdrawal_address: owrAddress,
|
|
@@ -242,7 +242,7 @@ export const deploySplitterAndOWRContracts = ({ owrArgs, splitterArgs, signer, c
|
|
|
242
242
|
target: getChainConfig(chainId).OWR_FACTORY_CONTRACT.address,
|
|
243
243
|
callData: owrTxData,
|
|
244
244
|
});
|
|
245
|
-
const executeMultiCalls = yield
|
|
245
|
+
const executeMultiCalls = yield multicall3(executeCalls, signer, chainId);
|
|
246
246
|
const splitAddressData = (_s = executeMultiCalls === null || executeMultiCalls === void 0 ? void 0 : executeMultiCalls.logs[0]) === null || _s === void 0 ? void 0 : _s.topics[1];
|
|
247
247
|
const formattedSplitterAddress = '0x' + (splitAddressData === null || splitAddressData === void 0 ? void 0 : splitAddressData.slice(26, 66));
|
|
248
248
|
const owrAddressData = (_t = executeMultiCalls === null || executeMultiCalls === void 0 ? void 0 : executeMultiCalls.logs[1]) === null || _t === void 0 ? void 0 : _t.topics[1];
|
|
@@ -282,39 +282,39 @@ export const getOWRTranches = ({ owrAddress, signer, }) => __awaiter(void 0, voi
|
|
|
282
282
|
throw new Error(`Unexpected error in getOWRTranches: ${(_v = error.message) !== null && _v !== void 0 ? _v : 'Unknown error while fetching OWR tranche data'}`);
|
|
283
283
|
}
|
|
284
284
|
});
|
|
285
|
-
export const
|
|
285
|
+
export const multicall3 = (calls, signer, chainId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
286
286
|
var _w, _x, _y;
|
|
287
287
|
try {
|
|
288
288
|
const chainConfig = getChainConfig(chainId);
|
|
289
|
-
const
|
|
290
|
-
const
|
|
289
|
+
const multicall3Address = chainConfig.MULTICALL3_CONTRACT.address;
|
|
290
|
+
const multiCall3ContractInstance = new Contract(multicall3Address, MultiCall3Contract.abi, signer);
|
|
291
291
|
let tx;
|
|
292
292
|
try {
|
|
293
|
-
tx = yield
|
|
293
|
+
tx = yield multiCall3ContractInstance.aggregate(calls);
|
|
294
294
|
}
|
|
295
295
|
catch (error) {
|
|
296
|
-
throw new Error(`Failed to submit
|
|
296
|
+
throw new Error(`Failed to submit multicall3 transaction: ${(_w = error.message) !== null && _w !== void 0 ? _w : 'Transaction submission failed'}`);
|
|
297
297
|
}
|
|
298
298
|
let receipt;
|
|
299
299
|
try {
|
|
300
300
|
receipt = yield tx.wait();
|
|
301
301
|
}
|
|
302
302
|
catch (error) {
|
|
303
|
-
throw new Error(`
|
|
303
|
+
throw new Error(`Multicall3 transaction failed or was reverted: ${(_x = error.message) !== null && _x !== void 0 ? _x : 'Transaction execution failed'}`);
|
|
304
304
|
}
|
|
305
305
|
if (!receipt) {
|
|
306
|
-
throw new Error('
|
|
306
|
+
throw new Error('Multicall3 transaction succeeded but no receipt was returned');
|
|
307
307
|
}
|
|
308
308
|
return receipt;
|
|
309
309
|
}
|
|
310
310
|
catch (error) {
|
|
311
311
|
// Re-throw if it's already our custom error
|
|
312
312
|
if (error.message.includes('Failed to') ||
|
|
313
|
-
error.message.includes('
|
|
313
|
+
error.message.includes('Multicall3 transaction')) {
|
|
314
314
|
throw error;
|
|
315
315
|
}
|
|
316
316
|
// Handle unexpected errors
|
|
317
|
-
throw new Error(`Unexpected error in
|
|
317
|
+
throw new Error(`Unexpected error in multicall3: ${(_y = error.message) !== null && _y !== void 0 ? _y : 'Unknown error during multicall3 execution'}`);
|
|
318
318
|
}
|
|
319
319
|
});
|
|
320
320
|
const encodeCreateSplitTxData = (accounts, percentAllocations, distributorFee, controller) => {
|
|
@@ -446,8 +446,8 @@ export const deployOVMAndSplitV2 = ({ ovmArgs, rewardRecipients, isRewardsSplitt
|
|
|
446
446
|
target: chainConfig.OVM_FACTORY_CONTRACT.address,
|
|
447
447
|
callData: ovmTxData,
|
|
448
448
|
});
|
|
449
|
-
// Execute
|
|
450
|
-
const executeMultiCalls = yield
|
|
449
|
+
// Execute multicall3
|
|
450
|
+
const executeMultiCalls = yield multicall3(executeCalls, signer, chainId);
|
|
451
451
|
// Extract addresses from events
|
|
452
452
|
let ovmAddress;
|
|
453
453
|
const logsCount = ((_7 = executeMultiCalls === null || executeMultiCalls === void 0 ? void 0 : executeMultiCalls.logs) === null || _7 === void 0 ? void 0 : _7.length) || 0;
|
|
@@ -461,7 +461,7 @@ export const deployOVMAndSplitV2 = ({ ovmArgs, rewardRecipients, isRewardsSplitt
|
|
|
461
461
|
ovmAddress = '0x' + ((_13 = (_12 = executeMultiCalls === null || executeMultiCalls === void 0 ? void 0 : executeMultiCalls.logs[7]) === null || _12 === void 0 ? void 0 : _12.topics[1]) === null || _13 === void 0 ? void 0 : _13.slice(26, 66));
|
|
462
462
|
}
|
|
463
463
|
if (!ovmAddress) {
|
|
464
|
-
throw new Error('Failed to extract contract addresses from
|
|
464
|
+
throw new Error('Failed to extract contract addresses from multicall3 events');
|
|
465
465
|
}
|
|
466
466
|
return ovmAddress;
|
|
467
467
|
}
|
|
@@ -493,7 +493,6 @@ const getChainConfig = (chainId) => {
|
|
|
493
493
|
* @returns Promise that resolves to the transaction hash
|
|
494
494
|
*/
|
|
495
495
|
export const requestWithdrawalFromOVM = ({ ovmAddress, pubKeys, amounts, withdrawalFees, signer, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
496
|
-
var _15;
|
|
497
496
|
try {
|
|
498
497
|
// Convert string amounts to bigint
|
|
499
498
|
const bigintAmounts = amounts.map(amount => BigInt(amount));
|
|
@@ -505,6 +504,51 @@ export const requestWithdrawalFromOVM = ({ ovmAddress, pubKeys, amounts, withdra
|
|
|
505
504
|
return { txHash: receipt.hash };
|
|
506
505
|
}
|
|
507
506
|
catch (error) {
|
|
508
|
-
|
|
507
|
+
const errorMessage = error instanceof Error ? error.message : 'Request withdrawal failed';
|
|
508
|
+
throw new Error(`Failed to request withdrawal from OVM: ${errorMessage}`);
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
/**
|
|
512
|
+
* Deposits to OVM contract using multicall3 for batch operations
|
|
513
|
+
* @param ovmAddress - The address of the OVM contract
|
|
514
|
+
* @param deposits - Array of deposit objects with all required parameters
|
|
515
|
+
* @param signer - The signer to use for the transaction
|
|
516
|
+
* @returns Promise that resolves to an array of transaction hashes
|
|
517
|
+
*/
|
|
518
|
+
export const depositWithMulticall3 = ({ ovmAddress, deposits, signer, chainId, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
519
|
+
try {
|
|
520
|
+
const ovmContract = new Contract(ovmAddress, OVMContract.abi, signer);
|
|
521
|
+
const chainConfig = getChainConfig(chainId);
|
|
522
|
+
const multicall3Address = chainConfig.MULTICALL3_CONTRACT.address;
|
|
523
|
+
const multiCall3ContractInstance = new Contract(multicall3Address, MultiCall3Contract.abi, signer);
|
|
524
|
+
const BATCH_SIZE = 500;
|
|
525
|
+
const txHashes = [];
|
|
526
|
+
// Process deposits in batches of 500
|
|
527
|
+
for (let i = 0; i < deposits.length; i += BATCH_SIZE) {
|
|
528
|
+
const batchDeposits = deposits.slice(i, i + BATCH_SIZE);
|
|
529
|
+
// Use Multicall3 aggregate3Value (payable per-call)
|
|
530
|
+
const callsWithValue = batchDeposits.map(deposit => ({
|
|
531
|
+
target: ovmAddress,
|
|
532
|
+
allowFailure: false,
|
|
533
|
+
callData: ovmContract.interface.encodeFunctionData('deposit', [
|
|
534
|
+
deposit.pubkey,
|
|
535
|
+
deposit.withdrawal_credentials,
|
|
536
|
+
deposit.signature,
|
|
537
|
+
deposit.deposit_data_root,
|
|
538
|
+
]),
|
|
539
|
+
value: BigInt(deposit.amount),
|
|
540
|
+
}));
|
|
541
|
+
const totalBatchValue = callsWithValue.reduce((sum, c) => sum + c.value, BigInt(0));
|
|
542
|
+
const tx = yield multiCall3ContractInstance.aggregate3Value(callsWithValue, { value: totalBatchValue });
|
|
543
|
+
const receipt = yield tx.wait();
|
|
544
|
+
if (receipt === null || receipt === void 0 ? void 0 : receipt.hash) {
|
|
545
|
+
txHashes.push(receipt.hash);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
return { txHashes };
|
|
549
|
+
}
|
|
550
|
+
catch (error) {
|
|
551
|
+
const errorMessage = error instanceof Error ? error.message : 'Deposit failed';
|
|
552
|
+
throw new Error(`Failed to deposit to OVM with multicall3: ${errorMessage}`);
|
|
509
553
|
}
|
|
510
554
|
});
|
|
@@ -7,9 +7,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { formatRecipientsForSplitV2, predictSplitV2Address, isSplitV2Deployed, deployOVMContract, deployOVMAndSplitV2, requestWithdrawalFromOVM, } from './splitHelpers';
|
|
10
|
+
import { formatRecipientsForSplitV2, predictSplitV2Address, isSplitV2Deployed, deployOVMContract, deployOVMAndSplitV2, requestWithdrawalFromOVM, depositWithMulticall3, } from './splitHelpers';
|
|
11
11
|
import { CHAIN_CONFIGURATION, SPLITS_V2_SALT, DEFAULT_RETROACTIVE_FUNDING_REWARDS_ONLY_SPLIT, isChainSupportedForSplitters, } from '../constants';
|
|
12
|
-
import { ovmRewardsSplitPayloadSchema, ovmTotalSplitPayloadSchema, ovmRequestWithdrawalPayloadSchema, } from '../schema';
|
|
12
|
+
import { ovmRewardsSplitPayloadSchema, ovmTotalSplitPayloadSchema, ovmRequestWithdrawalPayloadSchema, ovmDepositPayloadSchema, } from '../schema';
|
|
13
13
|
import { validatePayload } from '../ajv';
|
|
14
14
|
import { isContractAvailable } from '../utils';
|
|
15
15
|
/**
|
|
@@ -62,21 +62,21 @@ export class ObolSplits {
|
|
|
62
62
|
}
|
|
63
63
|
const ovmFactoryConfig = chainConfig.OVM_FACTORY_CONTRACT;
|
|
64
64
|
const splitV2FactoryConfig = chainConfig.SPLIT_V2_FACTORY_CONTRACT;
|
|
65
|
-
const
|
|
65
|
+
const multiCall3Config = chainConfig.MULTICALL3_CONTRACT;
|
|
66
66
|
if (!(ovmFactoryConfig === null || ovmFactoryConfig === void 0 ? void 0 : ovmFactoryConfig.address) ||
|
|
67
67
|
!(ovmFactoryConfig === null || ovmFactoryConfig === void 0 ? void 0 : ovmFactoryConfig.bytecode) ||
|
|
68
68
|
!(splitV2FactoryConfig === null || splitV2FactoryConfig === void 0 ? void 0 : splitV2FactoryConfig.address) ||
|
|
69
69
|
!(splitV2FactoryConfig === null || splitV2FactoryConfig === void 0 ? void 0 : splitV2FactoryConfig.bytecode) ||
|
|
70
|
-
!(
|
|
71
|
-
!(
|
|
70
|
+
!(multiCall3Config === null || multiCall3Config === void 0 ? void 0 : multiCall3Config.address) ||
|
|
71
|
+
!(multiCall3Config === null || multiCall3Config === void 0 ? void 0 : multiCall3Config.bytecode)) {
|
|
72
72
|
throw new Error(`Contracts configuration is incomplete for chain ${this.chainId}`);
|
|
73
73
|
}
|
|
74
74
|
const checkOVMFactoryContract = yield isContractAvailable(ovmFactoryConfig.address, this.provider, ovmFactoryConfig.bytecode);
|
|
75
75
|
const checkSplitV2FactoryContract = yield isContractAvailable(splitV2FactoryConfig.address, this.provider, splitV2FactoryConfig.bytecode);
|
|
76
|
-
const
|
|
76
|
+
const checkMultiCall3Contract = yield isContractAvailable(multiCall3Config.address, this.provider, multiCall3Config.bytecode);
|
|
77
77
|
if (!checkOVMFactoryContract ||
|
|
78
78
|
!checkSplitV2FactoryContract ||
|
|
79
|
-
!
|
|
79
|
+
!checkMultiCall3Contract) {
|
|
80
80
|
throw new Error(`Splitter contract is not deployed or available on chain ${this.chainId}`);
|
|
81
81
|
}
|
|
82
82
|
const retroActiveFundingRecipient = {
|
|
@@ -178,21 +178,21 @@ export class ObolSplits {
|
|
|
178
178
|
}
|
|
179
179
|
const ovmFactoryConfig = chainConfig.OVM_FACTORY_CONTRACT;
|
|
180
180
|
const splitV2FactoryConfig = chainConfig.SPLIT_V2_FACTORY_CONTRACT;
|
|
181
|
-
const
|
|
181
|
+
const multiCall3Config = chainConfig.MULTICALL3_CONTRACT;
|
|
182
182
|
if (!(ovmFactoryConfig === null || ovmFactoryConfig === void 0 ? void 0 : ovmFactoryConfig.address) ||
|
|
183
183
|
!(ovmFactoryConfig === null || ovmFactoryConfig === void 0 ? void 0 : ovmFactoryConfig.bytecode) ||
|
|
184
184
|
!(splitV2FactoryConfig === null || splitV2FactoryConfig === void 0 ? void 0 : splitV2FactoryConfig.address) ||
|
|
185
185
|
!(splitV2FactoryConfig === null || splitV2FactoryConfig === void 0 ? void 0 : splitV2FactoryConfig.bytecode) ||
|
|
186
|
-
!(
|
|
187
|
-
!(
|
|
186
|
+
!(multiCall3Config === null || multiCall3Config === void 0 ? void 0 : multiCall3Config.address) ||
|
|
187
|
+
!(multiCall3Config === null || multiCall3Config === void 0 ? void 0 : multiCall3Config.bytecode)) {
|
|
188
188
|
throw new Error(`Contracts configuration is incomplete for chain ${this.chainId}`);
|
|
189
189
|
}
|
|
190
190
|
const checkOVMFactoryContract = yield isContractAvailable(ovmFactoryConfig.address, this.provider, ovmFactoryConfig.bytecode);
|
|
191
191
|
const checkSplitV2FactoryContract = yield isContractAvailable(splitV2FactoryConfig.address, this.provider, splitV2FactoryConfig.bytecode);
|
|
192
|
-
const
|
|
192
|
+
const checkMultiCall3Contract = yield isContractAvailable(multiCall3Config.address, this.provider, multiCall3Config.bytecode);
|
|
193
193
|
if (!checkOVMFactoryContract ||
|
|
194
194
|
!checkSplitV2FactoryContract ||
|
|
195
|
-
!
|
|
195
|
+
!checkMultiCall3Contract) {
|
|
196
196
|
throw new Error(`Splitter contract is not deployed or available on chain ${this.chainId}`);
|
|
197
197
|
}
|
|
198
198
|
const retroActiveFundingRecipient = {
|
|
@@ -252,7 +252,7 @@ export class ObolSplits {
|
|
|
252
252
|
};
|
|
253
253
|
}
|
|
254
254
|
else {
|
|
255
|
-
// Use
|
|
255
|
+
// Use multicall3 to deploy any contracts that aren't deployed
|
|
256
256
|
const ovmAddress = yield deployOVMAndSplitV2({
|
|
257
257
|
ovmArgs: {
|
|
258
258
|
OVMOwnerAddress: validatedPayload.OVMOwnerAddress,
|
|
@@ -316,4 +316,47 @@ export class ObolSplits {
|
|
|
316
316
|
});
|
|
317
317
|
});
|
|
318
318
|
}
|
|
319
|
+
/**
|
|
320
|
+
* Deposits to OVM contract using multicall3 for batch operations.
|
|
321
|
+
*
|
|
322
|
+
* This method allows depositing to an OVM contract using multicall3 for efficient batch processing.
|
|
323
|
+
* Each deposit includes validator public key, withdrawal credentials, signature, deposit data root, and amount.
|
|
324
|
+
*
|
|
325
|
+
* @remarks
|
|
326
|
+
* **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
|
|
327
|
+
* and not pushed to version control.
|
|
328
|
+
*
|
|
329
|
+
* @param {OVMDepositPayload} payload - Data needed to deposit to OVM
|
|
330
|
+
* @returns {Promise<{txHashes: string[]}>} Array of transaction hashes for all batches
|
|
331
|
+
* @throws Will throw an error if the signer is not provided, OVM address is invalid, or the deposit fails
|
|
332
|
+
*
|
|
333
|
+
* An example of how to use deposit:
|
|
334
|
+
* ```typescript
|
|
335
|
+
* const result = await client.splits.deposit({
|
|
336
|
+
* ovmAddress: '0x1234567890123456789012345678901234567890',
|
|
337
|
+
* deposits: [{
|
|
338
|
+
* pubkey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
339
|
+
* withdrawal_credentials: '0x1234567890123456789012345678901234567890',
|
|
340
|
+
* signature: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
341
|
+
* deposit_data_root: '0x1234567890123456789012345678901234567890123456789012345678901234',
|
|
342
|
+
* amount: '32000000000000000000' // 32 ETH in wei
|
|
343
|
+
* }]
|
|
344
|
+
* });
|
|
345
|
+
* console.log('Deposits completed:', result.txHashes);
|
|
346
|
+
* ```
|
|
347
|
+
*/
|
|
348
|
+
deposit(payload) {
|
|
349
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
350
|
+
if (!this.signer) {
|
|
351
|
+
throw new Error('Signer is required in deposit');
|
|
352
|
+
}
|
|
353
|
+
const validatedPayload = validatePayload(payload, ovmDepositPayloadSchema);
|
|
354
|
+
return yield depositWithMulticall3({
|
|
355
|
+
ovmAddress: validatedPayload.ovmAddress,
|
|
356
|
+
deposits: validatedPayload.deposits,
|
|
357
|
+
signer: this.signer,
|
|
358
|
+
chainId: this.chainId,
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
}
|
|
319
362
|
}
|
|
@@ -8,10 +8,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { EOA } from '../../src/eoa/eoa';
|
|
11
|
-
import { submitEOAWithdrawalRequest } from '../../src/eoa/eoaHelpers';
|
|
11
|
+
import { submitEOAWithdrawalRequest, submitEOABatchDeposit, } from '../../src/eoa/eoaHelpers';
|
|
12
12
|
// Mock the helper function
|
|
13
13
|
jest.mock('../../src/eoa/eoaHelpers', () => ({
|
|
14
14
|
submitEOAWithdrawalRequest: jest.fn(),
|
|
15
|
+
submitEOABatchDeposit: jest.fn(),
|
|
15
16
|
}));
|
|
16
17
|
describe('EOA', () => {
|
|
17
18
|
let eoa;
|
|
@@ -93,4 +94,78 @@ describe('EOA', () => {
|
|
|
93
94
|
expect(result).toEqual(mockResult);
|
|
94
95
|
}));
|
|
95
96
|
});
|
|
97
|
+
describe('deposit', () => {
|
|
98
|
+
const mockDeposits = [
|
|
99
|
+
{
|
|
100
|
+
pubKey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
101
|
+
withdrawalCredentials: '0x1234567890123456789012345678901234567890123456789012345678901234',
|
|
102
|
+
signature: '0x121234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012000000000000000000',
|
|
103
|
+
amount: '32000000000000000000', // 32 ETH in wei
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
it('should successfully deposit to batch contract', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
107
|
+
const mockPayload = {
|
|
108
|
+
deposits: mockDeposits,
|
|
109
|
+
};
|
|
110
|
+
const mockResult = {
|
|
111
|
+
txHashes: [
|
|
112
|
+
'0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
|
|
113
|
+
],
|
|
114
|
+
};
|
|
115
|
+
submitEOABatchDeposit.mockResolvedValue(mockResult);
|
|
116
|
+
const result = yield eoa.deposit(mockPayload);
|
|
117
|
+
expect(submitEOABatchDeposit).toHaveBeenCalledWith({
|
|
118
|
+
deposits: mockDeposits,
|
|
119
|
+
batchDepositContractAddress: '0xcD7a6C118Ac8F6544BC5076F2D8Fb86D2C546756',
|
|
120
|
+
signer: mockSigner,
|
|
121
|
+
});
|
|
122
|
+
expect(result).toEqual(mockResult);
|
|
123
|
+
}));
|
|
124
|
+
it('should throw error when signer is not provided', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
125
|
+
const eoaWithoutSigner = new EOA(undefined, 1, mockProvider);
|
|
126
|
+
const mockPayload = {
|
|
127
|
+
deposits: mockDeposits,
|
|
128
|
+
};
|
|
129
|
+
yield expect(eoaWithoutSigner.deposit(mockPayload)).rejects.toThrow('Signer is required in deposit');
|
|
130
|
+
}));
|
|
131
|
+
it('should throw error when batch deposit contract is not configured for chain', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
132
|
+
const eoaUnsupportedChain = new EOA(mockSigner, 999, mockProvider);
|
|
133
|
+
const mockPayload = {
|
|
134
|
+
deposits: mockDeposits,
|
|
135
|
+
};
|
|
136
|
+
yield expect(eoaUnsupportedChain.deposit(mockPayload)).rejects.toThrow('Batch deposit contract is not configured for chain 999');
|
|
137
|
+
}));
|
|
138
|
+
it('should handle multiple deposits', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
139
|
+
const multipleDeposits = [
|
|
140
|
+
{
|
|
141
|
+
pubKey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
142
|
+
withdrawalCredentials: '0x1234567890123456789012345678901234567890123456789012345678901234',
|
|
143
|
+
signature: '0x121234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012000000000000000000',
|
|
144
|
+
amount: '32000000000000000000',
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
pubKey: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdcd',
|
|
148
|
+
withdrawalCredentials: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd',
|
|
149
|
+
signature: '0x121234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012000000000000000000',
|
|
150
|
+
amount: '16000000000000000000',
|
|
151
|
+
},
|
|
152
|
+
];
|
|
153
|
+
const mockPayload = {
|
|
154
|
+
deposits: multipleDeposits,
|
|
155
|
+
};
|
|
156
|
+
const mockResult = {
|
|
157
|
+
txHashes: [
|
|
158
|
+
'0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
|
|
159
|
+
],
|
|
160
|
+
};
|
|
161
|
+
submitEOABatchDeposit.mockResolvedValue(mockResult);
|
|
162
|
+
const result = yield eoa.deposit(mockPayload);
|
|
163
|
+
expect(submitEOABatchDeposit).toHaveBeenCalledWith({
|
|
164
|
+
deposits: multipleDeposits,
|
|
165
|
+
batchDepositContractAddress: '0xcD7a6C118Ac8F6544BC5076F2D8Fb86D2C546756',
|
|
166
|
+
signer: mockSigner,
|
|
167
|
+
});
|
|
168
|
+
expect(result).toEqual(mockResult);
|
|
169
|
+
}));
|
|
170
|
+
});
|
|
96
171
|
});
|