Skip to content

Commit

Permalink
Merge pull request #530 from lidofinance/fix-zksync-bridge-balance
Browse files Browse the repository at this point in the history
feat: l2-bridge-zksync moved 🚨🚨🚨ZkSync bridge balance mismatch 🚨🚨🚨fro…
  • Loading branch information
TheDZhon authored Apr 17, 2024
2 parents 82e0226 + 2cb17ea commit 9efdd91
Show file tree
Hide file tree
Showing 32 changed files with 753 additions and 572 deletions.
15 changes: 15 additions & 0 deletions .github/workflows/test-l2-bridge-zksync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
name: Tests @ l2-bridge-zksync

on:
workflow_dispatch:
pull_request:
paths:
- "l2-bridge-zksync/**"

jobs:
tests:
uses: ./.github/workflows/_tests.yml
with:
path: ./l2-bridge-zksync
secrets: inherit
5 changes: 0 additions & 5 deletions l2-bridge-balance/src/agent-balance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,6 @@ export async function handleBlock(blockEvent: BlockEvent) {
findings,
BRIDGE_PARAMS_WSTETH.Optimism,
),
handleBridgeBalanceWstETH(
blockEvent,
findings,
BRIDGE_PARAMS_WSTETH.ZkSync,
),

handleBridgeBalanceLDO(blockEvent, findings, BRIDGE_PARAMS_LDO.Arbitrum),
handleBridgeBalanceLDO(blockEvent, findings, BRIDGE_PARAMS_LDO.Optimism),
Expand Down
3 changes: 0 additions & 3 deletions l2-bridge-balance/src/config/bot-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,5 @@
},
"Optimism": {
"RpcUrl": "https://mainnet.optimism.io"
},
"ZkSync": {
"RpcUrl": "https://mainnet.era.zksync.io"
}
}
7 changes: 0 additions & 7 deletions l2-bridge-balance/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ export interface BridgeParamWstETH {
export interface BridgeParamsWstETH {
Arbitrum: BridgeParamWstETH;
Optimism: BridgeParamWstETH;
ZkSync: BridgeParamWstETH;
}

export const BRIDGE_PARAMS_WSTETH: BridgeParamsWstETH = {
Expand All @@ -36,12 +35,6 @@ export const BRIDGE_PARAMS_WSTETH: BridgeParamsWstETH = {
wstEthBridged: "0x1f32b1c2345538c0c6f582fcb022739c4a194ebb",
rpcUrl: config.Optimism.RpcUrl,
},
ZkSync: {
name: "ZkSync",
l1Gateway: "0x41527B2d03844dB6b0945f25702cB958b6d55989",
wstEthBridged: "0x703b52F2b28fEbcB60E1372858AF5b18849FE867",
rpcUrl: config.ZkSync.RpcUrl,
},
};

export const LDO_ADDRESS = "0x5a98fcbea516cf06857215779fd812ca3bef1b32";
Expand Down
35 changes: 12 additions & 23 deletions l2-bridge-zksync/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,17 @@
3. 🚨 ZkSync: Proxy beacon upgraded
4. 🚨 ZkSync: Proxy owner transferred
3. Bridge Events
1. 🚨 ZkSync L2 Bridge: Role Admin changed
2. 🚨 ZkSync L2 Bridge: Withdrawals Disabled
3. 🚨 ZkSync L2 Bridge: Implementation initialized
4. 🚨 ZkSync L2 Bridge: Deposits Disabled
5. ⚠️ ZkSync L2 Bridge: Role granted
6. ⚠️ ZkSync L2 Bridge: Role revoked
7. ℹ️ ZkSync L2 Bridge: Deposits Enabled
8. ℹ️ ZkSync L2 Bridge: Withdrawals Enabled

### Withdrawals alerts

Alert on huge withdrawals

- ⚠️ ZkSync: Huge withdrawals during the last ...
1. 🚨🚨🚨 ZkSync bridge balance mismatch 🚨🚨🚨
2. 🚨 ZkSync L2 Bridge: Role Admin changed
3. 🚨 ZkSync L2 Bridge: Withdrawals Disabled
4. 🚨 ZkSync L2 Bridge: Implementation initialized
5. 🚨 ZkSync L2 Bridge: Deposits Disabled
6. ⚠️ ZkSync L2 Bridge: Role granted
7. ⚠️ ZkSync L2 Bridge: Role revoked
8. ℹ️ ZkSync L2 Bridge: Deposits Enabled
9. ℹ️ ZkSync L2 Bridge: Withdrawals Enabled
4. Withdrawals alerts
1. ⚠️ ZkSync: Huge withdrawals during the last ...

## Development

Expand All @@ -48,13 +45,5 @@ yarn install
Running in a live mode:

```
yarn start:dev
```

Testing on a specific block/range/transaction:

```
yarn block 5764029
yarn range '5764000..5764029'
yarn tx 0x5e7e3adcbe9645ca65703055bf3a5355225ee61eda0b24ebcad36f69869e7a01
yarn start
```
6 changes: 3 additions & 3 deletions l2-bridge-zksync/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@
"test": "jest",
"generate-types": "typechain --target=ethers-v5 --out-dir=./src/generated ./src/abi/*",
"eslint:lint": "eslint ./src ./tests",
"eslint:format": "eslint ./src ./tests --fix",
"prettier:check": "prettier --check ./src ./tests",
"prettier:format": "prettier --write ./src ./tests README.md",
"eslint:format": "eslint ./src --fix",
"prettier:check": "prettier --check ./src",
"prettier:format": "prettier --write ./src README.md",
"lint": "yarn run prettier:check && yarn run eslint:lint",
"format": "yarn run eslint:format && yarn run prettier:format",
"postinstall": "yarn generate-types"
Expand Down
34 changes: 34 additions & 0 deletions l2-bridge-zksync/src/abi/ERC20Short.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]
79 changes: 79 additions & 0 deletions l2-bridge-zksync/src/agent.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { App } from './app'
import * as E from 'fp-ts/Either'
import { Finding } from 'forta-agent'
import BigNumber from 'bignumber.js'

const TEST_TIMEOUT = 120_000

describe('agent-zkSync functional tests', () => {
test(
'should process handleBlocks',
async () => {
const app = await App.getInstance()

const l1BlockNumber = 19_668_703
const startL2BlockNumber = 31_653_586
const latestL2BlockNumber = 31_653_636

const l2BlocksDto = await app.zkSyncClient.fetchL2Blocks(startL2BlockNumber, latestL2BlockNumber)

for (const tProxyWatcher of app.tProxyWatchers) {
const tProxyWatcherErr = await tProxyWatcher.initialize(latestL2BlockNumber)
if (tProxyWatcherErr !== null) {
throw tProxyWatcherErr
}
}

const oProxyWorker = await app.oProxyWatcher.initialize(latestL2BlockNumber)
if (oProxyWorker !== null) {
throw oProxyWorker
}

const monitorWithdrawalsInitResp = await app.monitorWithdrawals.initialize(latestL2BlockNumber)
if (E.isLeft(monitorWithdrawalsInitResp)) {
throw monitorWithdrawalsInitResp.left
}

const l2Logs = await app.blockSrv.getL2Logs(l2BlocksDto)
if (E.isLeft(l2Logs)) {
throw new Error(l2Logs.left.name)
}

const bridgeEventFindings = app.bridgeWatcher.handleL2Logs(l2Logs.right)
const govEventFindings = app.govWatcher.handleL2Logs(l2Logs.right)
const proxyAdminEventFindings = app.proxyEventWatcher.handleL2Logs(l2Logs.right)
const monitorWithdrawalsFindings = app.monitorWithdrawals.handleBlocks(l2Logs.right, l2BlocksDto)

const l2BlockNumbersSet: Set<number> = new Set<number>()
for (const log of l2Logs.right) {
l2BlockNumbersSet.add(new BigNumber(log.blockNumber, 10).toNumber())
}
const l2BlockNumbers = Array.from(l2BlockNumbersSet).toSorted((a, b) => a - b)

const proxyWatcherFindings: Finding[] = []
for (const tProxyWatcher of app.tProxyWatchers) {
const findings = await tProxyWatcher.handleL2Blocks(l2BlockNumbers)
proxyWatcherFindings.push(...findings)
}

const [oProxyWatcherFindings, bridgeBalanceFindings] = await Promise.all([
app.oProxyWatcher.handleL2Blocks(l2BlockNumbers),
app.bridgeBalanceSrv.handleBlock(l1BlockNumber, l2BlockNumbers),
])

const findings: Finding[] = []
findings.push(
...bridgeEventFindings,
...govEventFindings,
...proxyAdminEventFindings,
...monitorWithdrawalsFindings,
...proxyWatcherFindings,
...oProxyWatcherFindings,
...bridgeBalanceFindings,
)

expect(findings.length).toEqual(0)
},
TEST_TIMEOUT,
)
})
54 changes: 29 additions & 25 deletions l2-bridge-zksync/src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ export function initialize(): Initialize {
return async function (): Promise<InitializeResponse | void> {
const app = await App.getInstance()

const latestBlock = await app.zkSyncClient.getLatestBlock()
if (E.isLeft(latestBlock)) {
app.logger.error(latestBlock.left)
const latestL2Block = await app.zkSyncClient.getLatestL2Block()
if (E.isLeft(latestL2Block)) {
app.logger.error(latestL2Block.left)

process.exit(1)
}

const agents: string[] = []
for (const tProxyWatcher of app.tProxyWatchers) {
const tProxyWatcherErr = await tProxyWatcher.initialize(latestBlock.right.number)
const tProxyWatcherErr = await tProxyWatcher.initialize(latestL2Block.right.number)
if (tProxyWatcherErr !== null) {
app.logger.error(tProxyWatcherErr)

Expand All @@ -42,7 +42,7 @@ export function initialize(): Initialize {
agents.push(tProxyWatcher.getName())
}

const oProxyWorker = await app.oProxyWatcher.initialize(latestBlock.right.number)
const oProxyWorker = await app.oProxyWatcher.initialize(latestL2Block.right.number)
if (oProxyWorker !== null) {
app.logger.error(oProxyWorker)

Expand All @@ -54,7 +54,7 @@ export function initialize(): Initialize {
metadata[`${app.oProxyWatcher.getName()}.isOssified`] = String(app.oProxyWatcher.isOssified())
agents.push(app.oProxyWatcher.getName())

const monitorWithdrawalsInitResp = await app.monitorWithdrawals.initialize(latestBlock.right.number)
const monitorWithdrawalsInitResp = await app.monitorWithdrawals.initialize(latestL2Block.right.number)
if (E.isLeft(monitorWithdrawalsInitResp)) {
app.logger.error(monitorWithdrawalsInitResp.left)

Expand Down Expand Up @@ -99,41 +99,44 @@ export const handleBlock = (): HandleBlock => {
findings.push(...findingsAsync)
}

const blocksDto = await app.blockSrv.getBlocks()
if (E.isLeft(blocksDto)) {
const l2BlocksDto = await app.blockSrv.getL2Blocks()
if (E.isLeft(l2BlocksDto)) {
isHandleBLockRunning = false
return [blocksDto.left]
return [l2BlocksDto.left]
}
app.logger.info(
`ETH block ${blockEvent.blockNumber.toString()}. Fetched zkSync blocks from ${blocksDto.right[0].number} to ${
blocksDto.right[blocksDto.right.length - 1].number
}. Total: ${blocksDto.right.length}`,
`ETH block ${blockEvent.blockNumber.toString()}. Fetched zkSync blocks from ${l2BlocksDto.right[0].number} to ${
l2BlocksDto.right[l2BlocksDto.right.length - 1].number
}. Total: ${l2BlocksDto.right.length}`,
)

const logs = await app.blockSrv.getLogs(blocksDto.right)
if (E.isLeft(logs)) {
const l2Logs = await app.blockSrv.getL2Logs(l2BlocksDto.right)
if (E.isLeft(l2Logs)) {
isHandleBLockRunning = false
return [logs.left]
return [l2Logs.left]
}

const bridgeEventFindings = app.bridgeWatcher.handleLogs(logs.right)
const govEventFindings = app.govWatcher.handleLogs(logs.right)
const proxyAdminEventFindings = app.proxyEventWatcher.handleLogs(logs.right)
const monitorWithdrawalsFindings = app.monitorWithdrawals.handleBlocks(logs.right, blocksDto.right)
const bridgeEventFindings = app.bridgeWatcher.handleL2Logs(l2Logs.right)
const govEventFindings = app.govWatcher.handleL2Logs(l2Logs.right)
const proxyAdminEventFindings = app.proxyEventWatcher.handleL2Logs(l2Logs.right)
const monitorWithdrawalsFindings = app.monitorWithdrawals.handleBlocks(l2Logs.right, l2BlocksDto.right)

const blockNumbers: Set<number> = new Set<number>()
for (const log of logs.right) {
blockNumbers.add(new BigNumber(log.blockNumber, 10).toNumber())
const l2BlockNumbersSet: Set<number> = new Set<number>()
for (const log of l2Logs.right) {
l2BlockNumbersSet.add(new BigNumber(log.blockNumber, 10).toNumber())
}
const l2BlockNumbers = Array.from(l2BlockNumbersSet).toSorted((a, b) => a - b)

const proxyWatcherFindings: Finding[] = []

for (const tProxyWatcher of app.tProxyWatchers) {
const findings = await tProxyWatcher.handleBlocks(Array.from(blockNumbers))
const findings = await tProxyWatcher.handleL2Blocks(l2BlockNumbers)
proxyWatcherFindings.push(...findings)
}

const oProxyWatcherFindings = await app.oProxyWatcher.handleBlocks(Array.from(blockNumbers))
const [oProxyWatcherFindings, bridgeBalanceFindings] = await Promise.all([
app.oProxyWatcher.handleL2Blocks(l2BlockNumbers),
app.bridgeBalanceSrv.handleBlock(blockEvent.block.number, l2BlockNumbers),
])

findings.push(
...bridgeEventFindings,
Expand All @@ -142,6 +145,7 @@ export const handleBlock = (): HandleBlock => {
...monitorWithdrawalsFindings,
...proxyWatcherFindings,
...oProxyWatcherFindings,
...bridgeBalanceFindings,
)

app.healthChecker.check(findings)
Expand Down
Loading

0 comments on commit 9efdd91

Please sign in to comment.