@@ -20,9 +20,11 @@ export const L1_DEFAULT_ETH_PER_ACCOUNT = ethers.parseEther('0.08');
2020// Stress tests for L1->L2 transactions on localhost require a lot of upfront payment, but these are skipped during tests on normal environments
2121export const L1_EXTENDED_TESTS_ETH_PER_ACCOUNT = ethers . parseEther ( '0.5' ) ;
2222export const L2_DEFAULT_ETH_PER_ACCOUNT = ethers . parseEther ( '0.5' ) ;
23+ export const L2_SECOND_CHAIN_ETH_PER_ACCOUNT = ethers . parseEther ( '0.05' ) ;
2324
2425// Stress tests on local host may require a lot of additiomal funds, but these are skipped during tests on normal environments
2526export const L2_EXTENDED_TESTS_ETH_PER_ACCOUNT = ethers . parseEther ( '50' ) ;
27+ export const L2_SECOND_CHAIN_EXTENDED_TESTS_ETH_PER_ACCOUNT = ethers . parseEther ( '5' ) ;
2628export const ERC20_PER_ACCOUNT = ethers . parseEther ( '10000.0' ) ;
2729
2830interface VmPlaygroundHealth {
@@ -79,9 +81,11 @@ export class TestContextOwner {
7981
8082 private mainEthersWallet : ethers . Wallet ;
8183 private mainSyncWallet : zksync . Wallet ;
84+ private secondChainMainSyncWallet : zksync . Wallet | undefined ;
8285
8386 private l1Provider : ethers . JsonRpcProvider ;
8487 private l2Provider : zksync . Provider ;
88+ private l2ProviderSecondChain : zksync . Provider | undefined ;
8589
8690 private reporter : Reporter = new Reporter ( ) ;
8791
@@ -109,6 +113,28 @@ export class TestContextOwner {
109113
110114 this . mainEthersWallet = new ethers . Wallet ( env . mainWalletPK , this . l1Provider ) ;
111115 this . mainSyncWallet = new zksync . Wallet ( env . mainWalletPK , this . l2Provider , this . l1Provider ) ;
116+
117+ if ( env . l2ChainIdSecondChain ) {
118+ this . reporter . message ( 'Using second chain L2 provider: ' + env . l2NodeUrlSecondChain ) ;
119+ this . l2ProviderSecondChain = new RetryProvider (
120+ {
121+ url : env . l2NodeUrlSecondChain ! ,
122+ timeout : 1200 * 1000
123+ } ,
124+ undefined ,
125+ this . reporter
126+ ) ;
127+
128+ if ( isLocalHost ( env . network ) ) {
129+ this . l2ProviderSecondChain . pollingInterval = 100 ;
130+ }
131+
132+ this . secondChainMainSyncWallet = new zksync . Wallet (
133+ env . mainWalletPK ,
134+ this . l2ProviderSecondChain ,
135+ this . l1Provider
136+ ) ;
137+ }
112138 }
113139
114140 // Returns the required amount of L1 ETH
@@ -121,6 +147,13 @@ export class TestContextOwner {
121147 return isLocalHost ( this . env . network ) ? L2_EXTENDED_TESTS_ETH_PER_ACCOUNT : L2_DEFAULT_ETH_PER_ACCOUNT ;
122148 }
123149
150+ // Returns the required amount of L2 ETH for the second chain
151+ requiredL2ETHPerAccountSecondChain ( ) {
152+ return isLocalHost ( this . env . network )
153+ ? L2_SECOND_CHAIN_EXTENDED_TESTS_ETH_PER_ACCOUNT
154+ : L2_SECOND_CHAIN_ETH_PER_ACCOUNT ;
155+ }
156+
124157 /**
125158 * Performs the test context initialization.
126159 *
@@ -228,14 +261,20 @@ export class TestContextOwner {
228261 // `+ 1 for the main account (it has to send all these transactions).
229262 const accountsAmount = BigInt ( suites . length ) + 1n ;
230263
231- const l2ETHAmountToDeposit = await this . ensureBalances ( accountsAmount ) ;
264+ const { l2ETHAmountToDeposit, l2ETHAmountToDepositSecondChain } = await this . ensureBalances ( accountsAmount ) ;
232265 const l2ERC20AmountToDeposit = ERC20_PER_ACCOUNT * accountsAmount ;
233266 const wallets = this . createTestWallets ( suites ) ;
234267 const bridgehubContract = await this . mainSyncWallet . getBridgehubContract ( ) ;
235268 const baseTokenAddress = await bridgehubContract . baseToken ( this . env . l2ChainId ) ;
236269 await this . distributeL1BaseToken ( wallets , l2ERC20AmountToDeposit , baseTokenAddress ) ;
237270 await this . cancelAllowances ( ) ;
238- await this . distributeL1Tokens ( wallets , l2ETHAmountToDeposit , l2ERC20AmountToDeposit , baseTokenAddress ) ;
271+ await this . distributeL1Tokens (
272+ wallets ,
273+ l2ETHAmountToDeposit ,
274+ l2ETHAmountToDepositSecondChain ,
275+ l2ERC20AmountToDeposit ,
276+ baseTokenAddress
277+ ) ;
239278 await this . distributeL2Tokens ( wallets ) ;
240279
241280 this . reporter . finishAction ( ) ;
@@ -245,7 +284,9 @@ export class TestContextOwner {
245284 /**
246285 * Checks the operator account balances on L1 and L2 and deposits funds if required.
247286 */
248- private async ensureBalances ( accountsAmount : bigint ) : Promise < bigint > {
287+ private async ensureBalances (
288+ accountsAmount : bigint
289+ ) : Promise < { l2ETHAmountToDeposit : bigint ; l2ETHAmountToDepositSecondChain : bigint } > {
249290 this . reporter . startAction ( `Checking main account balance` ) ;
250291
251292 this . reporter . message ( `Operator address is ${ this . mainEthersWallet . address } ` ) ;
@@ -254,11 +295,26 @@ export class TestContextOwner {
254295 const actualL2ETHAmount = await this . mainSyncWallet . getBalance ( ) ;
255296 this . reporter . message ( `Operator balance on L2 is ${ ethers . formatEther ( actualL2ETHAmount ) } ETH` ) ;
256297
298+ let l2ETHAmountToDepositSecondChain = 0n ;
299+ if ( this . env . l2ChainIdSecondChain ) {
300+ // We only need enough funds for a single test suite
301+ const requiredL2SecondChainETHAmount = this . requiredL2ETHPerAccountSecondChain ( ) * accountsAmount ;
302+ const actualL2SecondChainETHAmount = await this . secondChainMainSyncWallet ! . getBalance ( ) ;
303+ this . reporter . message (
304+ `Operator balance on second chain is ${ ethers . formatEther ( actualL2SecondChainETHAmount ) } ETH`
305+ ) ;
306+ if ( requiredL2SecondChainETHAmount > actualL2SecondChainETHAmount ) {
307+ l2ETHAmountToDepositSecondChain = requiredL2SecondChainETHAmount - actualL2SecondChainETHAmount ;
308+ }
309+ }
310+
257311 // We may have enough funds in L2. If that's the case, no need to deposit more than required.
258312 const l2ETHAmountToDeposit =
259313 requiredL2ETHAmount > actualL2ETHAmount ? requiredL2ETHAmount - actualL2ETHAmount : 0n ;
260314
261- const requiredL1ETHAmount = this . requiredL1ETHPerAccount ( ) * accountsAmount + l2ETHAmountToDeposit ;
315+ const requiredL1ETHAmount =
316+ this . requiredL1ETHPerAccount ( ) * accountsAmount + l2ETHAmountToDeposit + l2ETHAmountToDepositSecondChain ;
317+ // Both mainSyncWallet and secondChainMainSyncWallet share the same L1 wallet
262318 const actualL1ETHAmount = await this . mainSyncWallet . getBalanceL1 ( ) ;
263319 this . reporter . message ( `Operator balance on L1 is ${ ethers . formatEther ( actualL1ETHAmount ) } ETH` ) ;
264320
@@ -270,7 +326,7 @@ export class TestContextOwner {
270326 }
271327 this . reporter . finishAction ( ) ;
272328
273- return l2ETHAmountToDeposit ;
329+ return { l2ETHAmountToDeposit, l2ETHAmountToDepositSecondChain } ;
274330 }
275331
276332 /**
@@ -386,6 +442,7 @@ export class TestContextOwner {
386442 private async distributeL1Tokens (
387443 wallets : TestWallets ,
388444 l2ETHAmountToDeposit : bigint ,
445+ l2ETHAmountToDepositSecondChain : bigint ,
389446 l2erc20DepositAmount : bigint ,
390447 baseTokenAddress : zksync . types . Address
391448 ) {
@@ -430,6 +487,30 @@ export class TestContextOwner {
430487 ) ;
431488 await depositHandle ;
432489 }
490+
491+ // Deposit L2 tokens on the second chain (if needed).
492+ if ( l2ETHAmountToDepositSecondChain != 0n ) {
493+ // Given that we've already sent a number of transactions,
494+ // we have to correctly send nonce.
495+ const depositHandle = this . secondChainMainSyncWallet ! . deposit ( {
496+ token : zksync . utils . ETH_ADDRESS ,
497+ amount : l2ETHAmountToDepositSecondChain as BigNumberish ,
498+ overrides : {
499+ nonce,
500+ gasPrice
501+ }
502+ } ) . then ( ( tx ) => {
503+ const amount = ethers . formatEther ( l2ETHAmountToDeposit ) ;
504+ this . reporter . debug (
505+ `Sent ETH deposit on second chain. Nonce ${ tx . nonce } , amount: ${ amount } , hash: ${ tx . hash } `
506+ ) ;
507+ return tx . wait ( ) ;
508+ } ) ;
509+ nonce = nonce + 1 ;
510+ this . reporter . debug ( `Nonce changed by 1 for ETH deposit on second chain, new nonce: ${ nonce } ` ) ;
511+ await depositHandle ;
512+ }
513+
433514 // Define values for handling ERC20 transfers/deposits.
434515 const erc20Token = this . env . erc20Token . l1Address ;
435516 const erc20MintAmount = l2erc20DepositAmount * 100n ;
@@ -546,6 +627,21 @@ export class TestContextOwner {
546627 ) ;
547628 l2startNonce += l2TxPromises . length ;
548629
630+ let l2TxPromisesSecondChain : Promise < any > [ ] = [ ] ;
631+ if ( this . env . l2ChainIdSecondChain ) {
632+ const l2startNonceSecondChain = await this . secondChainMainSyncWallet ! . getNonce ( ) ;
633+ // ETH transfers on second chain.
634+ l2TxPromisesSecondChain = await sendTransfers (
635+ zksync . utils . ETH_ADDRESS ,
636+ this . secondChainMainSyncWallet ! ,
637+ wallets ,
638+ this . requiredL2ETHPerAccountSecondChain ( ) ,
639+ l2startNonceSecondChain ,
640+ undefined ,
641+ this . reporter
642+ ) ;
643+ }
644+
549645 // ERC20 transfers.
550646 const l2TokenAddress = await this . mainSyncWallet . l2TokenAddress ( this . env . erc20Token . l1Address ) ;
551647 const erc20Promises = await sendTransfers (
@@ -557,7 +653,7 @@ export class TestContextOwner {
557653 undefined ,
558654 this . reporter
559655 ) ;
560- l2TxPromises . push ( ...erc20Promises ) ;
656+ l2TxPromises . push ( ...l2TxPromisesSecondChain , ... erc20Promises ) ;
561657 await Promise . all ( l2TxPromises ) ;
562658
563659 this . reporter . finishAction ( ) ;
@@ -659,6 +755,7 @@ export class TestContextOwner {
659755 }
660756 try {
661757 this . l2Provider . destroy ( ) ;
758+ this . l2ProviderSecondChain ?. destroy ( ) ;
662759 } catch ( err : any ) {
663760 // Catch any request cancellation errors that propagate here after destroying L2 provider
664761 console . log ( `Caught error while destroying L2 provider: ${ err } ` ) ;
@@ -677,6 +774,11 @@ export class TestContextOwner {
677774 await killPidWithAllChilds ( this . env . l2NodePid , 9 ) ;
678775 this . reporter . finishAction ( ) ;
679776 }
777+ if ( this . env . l2NodePidSecondChain !== undefined ) {
778+ this . reporter . startAction ( `Terminating L2 node process` ) ;
779+ await killPidWithAllChilds ( this . env . l2NodePidSecondChain , 9 ) ;
780+ this . reporter . finishAction ( ) ;
781+ }
680782 }
681783
682784 /**
0 commit comments