@@ -8,19 +8,19 @@ import { loadConfig } from 'utils/build/file-configs';
88import { sleep } from 'zksync-ethers/build/utils' ;
99import { L2_NATIVE_TOKEN_VAULT_ADDRESS } from 'utils/src/constants' ;
1010import * as fs from 'fs' ;
11- import { migrateToGatewayIfNeeded , startServer } from '../src' ;
11+ import { executeCommand , migrateToGatewayIfNeeded , startServer } from '../src' ;
1212import { initTestWallet } from '../src/run-integration-tests' ;
1313
1414const RICH_WALLET_L1_BALANCE = ethers . parseEther ( '10.0' ) ;
1515const RICH_WALLET_L2_BALANCE = RICH_WALLET_L1_BALANCE ;
1616const TEST_SUITE_NAME = 'Token Balance Migration Test' ;
1717const pathToHome = path . join ( __dirname , '../../../..' ) ;
1818
19- function readArtifact ( contractName : string , outFolder : string = 'out' ) {
19+ function readArtifact ( contractName : string , outFolder : string = 'out' , fileName : string = contractName ) {
2020 return JSON . parse (
2121 fs
2222 . readFileSync (
23- path . join ( pathToHome , `./contracts/l1-contracts/${ outFolder } /${ contractName } .sol/${ contractName } .json` )
23+ path . join ( pathToHome , `./contracts/l1-contracts/${ outFolder } /${ contractName } .sol/${ fileName } .json` )
2424 )
2525 . toString ( )
2626 ) ;
@@ -50,7 +50,7 @@ export async function generateChainRichWallet(chainName: string): Promise<zksync
5050
5151 if ( contractsConfig . l1 . base_token_addr !== zksync . utils . ETH_ADDRESS_IN_CONTRACTS ) {
5252 const l1Token = new ethers . Contract ( contractsConfig . l1 . base_token_addr , ERC20_ABI , richWallet . ethWallet ( ) ) ;
53- const mintTx = await l1Token . mint ( richWallet . address , RICH_WALLET_L2_BALANCE ) ;
53+ const mintTx = await l1Token . mint ( richWallet . address , 2n * RICH_WALLET_L2_BALANCE ) ;
5454 await mintTx . wait ( ) ;
5555 }
5656
@@ -76,6 +76,8 @@ export class ChainHandler {
7676 public inner : TestChain ;
7777 public l2RichWallet : zksync . Wallet ;
7878 public l1Ntv : ethers . Contract ;
79+ public l1GettersContract : ethers . Contract ;
80+ public gwGettersContract : zksync . Contract ;
7981
8082 constructor ( inner : TestChain , l2RichWallet : zksync . Wallet ) {
8183 this . inner = inner ;
@@ -87,44 +89,68 @@ export class ChainHandler {
8789 readArtifact ( 'L1NativeTokenVault' ) . abi ,
8890 l2RichWallet . ethWallet ( )
8991 ) ;
92+
93+ this . l1GettersContract = new ethers . Contract (
94+ contractsConfig . l1 . diamond_proxy_addr ,
95+ readArtifact ( 'Getters' , 'out' , 'GettersFacet' ) . abi ,
96+ l2RichWallet . ethWallet ( )
97+ ) ;
9098 }
9199
92100 async stopServer ( ) {
93101 await this . inner . mainNode . kill ( ) ;
94102 }
95103
96104 async migrateToGateway ( ) {
97- const pauseDepositsCmd = `zkstack chain pause-deposits --chain ${ this . inner . chainName } ` ;
98- await utils . spawn ( pauseDepositsCmd ) ;
105+ // Pause deposits before initiating migration
106+ await utils . spawn ( `zkstack chain pause-deposits --chain ${ this . inner . chainName } ` ) ;
107+ //await utils.spawn(`zkstack chain gateway notify-about-to-gateway-update --chain ${this.inner.chainName}`);
108+ // Wait for all batches to be executed and stop the server
109+ // Priority queue should be empty as all deposits have already been processed
110+ await this . inner . waitForAllBatchesToBeExecuted ( ) ;
99111 await this . stopServer ( ) ;
100- // By now, the priority queue should be empty, so we can migrate straight away
112+ // We can now reliably migrate to gateway
101113 await migrateToGatewayIfNeeded ( this . inner . chainName ) ;
102- // Restart the server
114+
103115 await startServer ( this . inner . chainName ) ;
116+ // We can now define the gateway getters contract
117+ const gatewayConfig = loadConfig ( { pathToHome, chain : this . inner . chainName , config : 'gateway_chain.yaml' } ) ;
118+ this . gwGettersContract = new zksync . Contract (
119+ gatewayConfig . diamond_proxy_addr ,
120+ readArtifact ( 'Getters' , 'out' , 'GettersFacet' ) . abi ,
121+ this . l2RichWallet
122+ ) ;
104123 }
105124
106125 async migrateFromGateway ( ) {
107- const pauseDepositsCmd = `zkstack chain pause-deposits --chain ${ this . inner . chainName } ` ;
108- await utils . spawn ( pauseDepositsCmd ) ;
126+ // Pause deposits before initiating migration
127+ await utils . spawn ( `zkstack chain pause-deposits --chain ${ this . inner . chainName } ` ) ;
128+ // Notify server
129+ // Wait for all batches to be executed
130+ await this . inner . waitForAllBatchesToBeExecuted ( ) ;
109131 // Migrate from gateway
110132 await utils . spawn (
111133 `zkstack chain gateway migrate-from-gateway --gateway-chain-name gateway --chain ${ this . inner . chainName } `
112134 ) ;
113135 }
114136
115137 async migrateTokenBalancesToGateway ( ) {
116- const migrationCmd = `zkstack chain gateway migrate-token-balances --to-gateway true --gateway-chain-name gateway --chain ${ this . inner . chainName } ` ;
117-
118- // Migration might sometimes fail, so we retry a few times.
119- for ( let attempt = 1 ; attempt <= 3 ; attempt ++ ) {
120- try {
121- await utils . spawn ( migrationCmd ) ;
122- break ;
123- } catch ( e ) {
124- if ( attempt === 3 ) throw e ;
125- await utils . sleep ( 2 * attempt ) ;
126- }
127- }
138+ await executeCommand (
139+ 'zkstack' ,
140+ [
141+ 'chain' ,
142+ 'gateway' ,
143+ 'migrate-token-balances' ,
144+ '--to-gateway' ,
145+ 'true' ,
146+ '--gateway-chain-name' ,
147+ 'gateway' ,
148+ '--chain' ,
149+ this . inner . chainName
150+ ] ,
151+ this . inner . chainName ,
152+ 'token_balance_migration_to_gateway'
153+ ) ;
128154 }
129155
130156 async migrateTokenBalancesToL1 ( ) {
@@ -145,10 +171,10 @@ export class ChainHandler {
145171
146172 static async createNewChain ( chainType : ChainType ) : Promise < ChainHandler > {
147173 const testChain = await createChainAndStartServer ( chainType , TEST_SUITE_NAME , false ) ;
148- await initTestWallet ( testChain . chainName ) ;
149174
150175 // Need to wait for a bit before the server works fully
151176 await sleep ( 2000 ) ;
177+ await initTestWallet ( testChain . chainName ) ;
152178
153179 return new ChainHandler ( testChain , await generateChainRichWallet ( testChain . chainName ) ) ;
154180 }
@@ -189,7 +215,11 @@ export class ERC20Handler {
189215 return assetId ;
190216 }
191217
192- async deposit ( chainHandler : ChainHandler , amount : bigint = DEFAULT_SMALL_AMOUNT ) : Promise < bigint > {
218+ async deposit (
219+ chainHandler : ChainHandler ,
220+ awaitDeposit = false ,
221+ amount : bigint = DEFAULT_SMALL_AMOUNT
222+ ) : Promise < bigint > {
193223 const depositAmount = amount ?? ethers . parseUnits ( ( Math . floor ( Math . random ( ) * 900 ) + 100 ) . toString ( ) , 'gwei' ) ;
194224 const depositTx = await this . wallet . deposit ( {
195225 token : await this . l1Contract ! . getAddress ( ) ,
@@ -200,6 +230,7 @@ export class ERC20Handler {
200230 await depositTx . wait ( ) ;
201231
202232 await this . setL2Contract ( chainHandler ) ;
233+ if ( awaitDeposit ) await waitForBalanceNonZero ( this . l2Contract ! , this . wallet ) ;
203234
204235 return depositAmount ;
205236 }
@@ -307,7 +338,7 @@ export class WithdrawalHandler {
307338 throw new Error ( 'Receipt' ) ;
308339 }
309340
310- await waitForL2ToL1LogProof ( l2Wallet . provider , receipt . blockNumber , this . txHash ) ;
341+ await waitForL2ToL1LogProof ( l2Wallet , receipt . blockNumber , this . txHash ) ;
311342
312343 await ( await l2Wallet . finalizeWithdrawal ( this . txHash ) ) . wait ( ) ;
313344 }
@@ -323,87 +354,43 @@ export class MigrationHandler {
323354 async finalizeMigration ( l1RichWallet : ethers . Wallet ) { }
324355}
325356
326- export class Tester {
327- public runningFee : Map < zksync . types . Address , bigint > ;
328- constructor (
329- public ethProvider : ethers . Provider ,
330- public ethWallet : ethers . Wallet ,
331- public syncWallet : zksync . Wallet ,
332- public web3Provider : zksync . Provider
333- ) {
334- this . runningFee = new Map ( ) ;
335- }
336-
337- // prettier-ignore
338- static async init ( ethProviderAddress : string , web3JsonRpc : string ) {
339- const ethProvider = new ethers . JsonRpcProvider ( ethProviderAddress ) ;
340-
341- const chainName = process . env . CHAIN_NAME ! ! ;
342- let ethWallet = new ethers . Wallet ( getMainWalletPk ( chainName ) ) ;
343-
344- ethWallet = ethWallet . connect ( ethProvider ) ;
345- const web3Provider = new zksync . Provider ( web3JsonRpc ) ;
346- web3Provider . pollingInterval = 100 ; // It's OK to keep it low even on stage.
347- const syncWallet = new zksync . Wallet ( ethWallet . privateKey , web3Provider , ethProvider ) ;
348-
349-
350- // Since some tx may be pending on stage, we don't want to get stuck because of it.
351- // In order to not get stuck transactions, we manually cancel all the pending txs.
352- const latestNonce = await ethWallet . getNonce ( 'latest' ) ;
353- const pendingNonce = await ethWallet . getNonce ( 'pending' ) ;
354- const cancellationTxs = [ ] ;
355- for ( let nonce = latestNonce ; nonce != pendingNonce ; nonce ++ ) {
356- // For each transaction to override it, we need to provide greater fee.
357- // We would manually provide a value high enough (for a testnet) to be both valid
358- // and higher than the previous one. It's OK as we'll only be charged for the bass fee
359- // anyways. We will also set the miner's tip to 5 gwei, which is also much higher than the normal one.
360- const maxFeePerGas = ethers . parseEther ( "0.00000025" ) ; // 250 gwei
361- const maxPriorityFeePerGas = ethers . parseEther ( "0.000000005" ) ; // 5 gwei
362- cancellationTxs . push ( ethWallet . sendTransaction ( { to : ethWallet . address , nonce, maxFeePerGas, maxPriorityFeePerGas } ) . then ( ( tx ) => tx . wait ( ) ) ) ;
363- }
364- if ( cancellationTxs . length > 0 ) {
365- await Promise . all ( cancellationTxs ) ;
366- console . log ( `Canceled ${ cancellationTxs . length } pending transactions` ) ;
367- }
368-
369- return new Tester ( ethProvider , ethWallet , syncWallet , web3Provider ) ;
370- }
371-
372- emptyWallet ( ) {
373- const walletHD = zksync . Wallet . createRandom ( ) ;
374- return new zksync . Wallet ( walletHD . privateKey , this . web3Provider , this . ethProvider ) ;
357+ async function waitForBalanceNonZero ( contract : ethers . Contract | zksync . Contract , wallet : zksync . Wallet ) {
358+ let balance ;
359+ while ( true ) {
360+ balance = await contract . balanceOf ( wallet . address ) ;
361+ console . log ( 'Waiting for balance to be non-zero' , balance ) ;
362+ if ( balance !== 0n ) break ;
363+ await zksync . utils . sleep ( wallet . provider . pollingInterval ) ;
375364 }
376365}
377366
378- export async function waitUntilBlockFinalized ( provider : zksync . Provider , blockNumber : number ) {
379- console . log ( 'Waiting for block to be finalized...' , blockNumber ) ;
367+ async function waitUntilBlockFinalized ( wallet : zksync . Wallet , blockNumber : number ) {
380368 let printedBlockNumber = 0 ;
381369 while ( true ) {
382- const block = await provider . getBlock ( 'finalized' ) ;
370+ const block = await wallet . provider . getBlock ( 'finalized' ) ;
371+ console . log ( 'block number' , block . number , blockNumber ) ;
383372 if ( blockNumber <= block . number ) {
384373 break ;
385374 } else {
386375 if ( printedBlockNumber < block . number ) {
387- console . log ( 'Waiting for block to be finalized...' , blockNumber , block . number ) ;
388- console . log ( 'time' , new Date ( ) . toISOString ( ) ) ;
389376 printedBlockNumber = block . number ;
390377 }
391- await zksync . utils . sleep ( provider . pollingInterval ) ;
378+ await zksync . utils . sleep ( wallet . provider . pollingInterval ) ;
392379 }
393380 }
394381}
395382
396- export async function waitForL2ToL1LogProof ( provider : zksync . Provider , blockNumber : number , txHash : string ) {
383+ async function waitForL2ToL1LogProof ( wallet : zksync . Wallet , blockNumber : number , txHash : string ) {
397384 console . log ( 'waiting for block to be finalized' ) ;
398385 // First, we wait for block to be finalized.
399- await waitUntilBlockFinalized ( provider , blockNumber ) ;
386+ await waitUntilBlockFinalized ( wallet , blockNumber ) ;
400387
401388 console . log ( 'waiting for log proof' ) ;
402389 // Second, we wait for the log proof.
403390 let i = 0 ;
404- while ( ( await provider . getLogProof ( txHash ) ) == null ) {
391+ while ( ( await wallet . provider . getLogProof ( txHash ) ) == null ) {
405392 console . log ( `Waiting for log proof... ${ i } ` ) ;
406- await zksync . utils . sleep ( provider . pollingInterval ) ;
393+ await zksync . utils . sleep ( wallet . provider . pollingInterval ) ;
407394 i ++ ;
408395 }
409396}
0 commit comments