Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: l2-bridge-base moved 🚨🚨🚨 Base bridge balance mismatch 🚨🚨🚨from l… #527

Merged
merged 3 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/test-l2-bridge-base.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
name: Tests @ l2-bridge-base

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

jobs:
tests:
uses: ./.github/workflows/_tests.yml
with:
path: ./l2-bridge-base
secrets: inherit
1 change: 0 additions & 1 deletion l2-bridge-balance/src/agent-balance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ export async function handleBlock(blockEvent: BlockEvent) {
findings,
BRIDGE_PARAMS_WSTETH.Optimism,
),
handleBridgeBalanceWstETH(blockEvent, findings, BRIDGE_PARAMS_WSTETH.Base),
handleBridgeBalanceWstETH(
blockEvent,
findings,
Expand Down
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;
Base: BridgeParamWstETH;
ZkSync: BridgeParamWstETH;
Mantle: BridgeParamWstETH;
}
Expand All @@ -38,12 +37,6 @@ export const BRIDGE_PARAMS_WSTETH: BridgeParamsWstETH = {
wstEthBridged: "0x1f32b1c2345538c0c6f582fcb022739c4a194ebb",
rpcUrl: config.Optimism.RpcUrl,
},
Base: {
name: "Base",
l1Gateway: "0x9de443AdC5A411E83F1878Ef24C3F52C61571e72",
wstEthBridged: "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452",
rpcUrl: config.Base.RpcUrl,
},
ZkSync: {
name: "ZkSync",
l1Gateway: "0x41527B2d03844dB6b0945f25702cB958b6d55989",
Expand Down
11 changes: 6 additions & 5 deletions l2-bridge-base/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
## Alerts

1. Bridge events
1. 🚨 Base L2 Bridge: Role Admin changed
1. 🚨🚨🚨 Base bridge balance mismatch 🚨🚨🚨
2. 🚨 Base L2 Bridge: Withdrawals Disabled
3. 🚨 Base L2 Bridge: Implementation initialized
4. 🚨 Base L2 Bridge: Deposits Disabled
5. ⚠️ Base L2 Bridge: Role granted
6. ⚠️ Base L2 Bridge: Role revoked
7. ℹ️ Base L2 Bridge: Deposits Enabled
8. ℹ️ Base L2 Bridge: Withdrawals Enabled
5. 🚨 Base L2 Bridge: Role Admin changed
6. ⚠️ Base L2 Bridge: Role granted
7. ⚠️ Base L2 Bridge: Role revoked
8. ℹ️ Base L2 Bridge: Deposits Enabled
9. ℹ️ Base L2 Bridge: Withdrawals Enabled
2. Gov Events
1. 🚨 Base Gov Bridge: Ethereum Governance Executor Updated
2. 🚨 Base Gov Bridge: Guardian Updated
Expand Down
15 changes: 9 additions & 6 deletions l2-bridge-base/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "lido-l2-bridge-base-bot",
"name": "lido-l2-bridge-base",
"version": "0.0.1",
"description": "Lido Detection Bot for base part of L2 bridge",
"license": "MIT",
Expand All @@ -12,6 +12,9 @@
"target": 5
}
},
"engines": {
"node": ">=20.0"
},
"scripts": {
"update-version": "node ../utils/write-version.js",
"build": "tsc && yarn run copy-version",
Expand All @@ -35,10 +38,10 @@
"stake": "forta-agent stake",
"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:lint": "eslint ./src ",
"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 Expand Up @@ -76,7 +79,7 @@
"ts-generator": "^0.1.1",
"ts-jest": "^29.1.1",
"typechain": "^8.3.2",
"typescript": "^5.3.2"
"typescript": "^5.3.3"
},
"packageManager": "[email protected]"
}
64 changes: 64 additions & 0 deletions l2-bridge-base/src/agent.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { App } from './app'
import * as E from 'fp-ts/Either'
import { Finding } from 'forta-agent'
import BigNumber from 'bignumber.js'

describe('agent-base functional test', () => {
test('should process app on 13_022_644 and 13_022_720 (25 l2 blocks)', async () => {
const app = await App.getInstance()

const l1Block = 19_632_237
const l2StartBlock = 13_022_720
const l2EndBlock = 13_022_745
const l2BlocksDto = await app.baseClient.fetchL2Blocks(l2StartBlock, l2EndBlock)

for (const proxyWatcher of app.proxyWatchers) {
const err = await proxyWatcher.initialize(l2StartBlock)
if (err !== null) {
throw null
}
}

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

const l2logs = await app.blockSrv.getL2Logs(l2BlocksDto)
if (E.isLeft(l2logs)) {
throw l2logs.left
}

const l2BlockNumberSet: Set<number> = new Set<number>()
for (const l2log of l2logs.right) {
l2BlockNumberSet.add(new BigNumber(l2log.blockNumber, 10).toNumber())
}

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.handleL2Blocks(l2logs.right, l2BlocksDto)
const proxyWatcherFindings: Finding[] = []

const l2BlockNumbers = Array.from(l2BlockNumberSet).toSorted((a, b) => a - b)

for (const proxyWatcher of app.proxyWatchers) {
const fnds = await proxyWatcher.handleL2Blocks(l2BlockNumbers)
proxyWatcherFindings.push(...fnds)
}

const bridgeBalanceFindings = await app.bridgeBalanceSrc.handleBlock(l1Block, l2BlockNumbers)

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

expect(findings.length).toEqual(0)
}, 360_000)
})
23 changes: 13 additions & 10 deletions l2-bridge-base/src/agent.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BlockEvent, decodeJwt, Finding, FindingSeverity, FindingType, HandleBlock, HealthCheck } from 'forta-agent'
import { BlockEvent, Finding, FindingSeverity, FindingType, HandleBlock, HealthCheck } from 'forta-agent'
import * as process from 'process'
import { InitializeResponse } from 'forta-agent/dist/sdk/initialize.response'
import { Initialize } from 'forta-agent/dist/sdk/handlers'
Expand Down Expand Up @@ -59,11 +59,10 @@ export function initialize(): Initialize {
agents.push(app.monitorWithdrawals.getName())

metadata.agents = '[' + agents.toString() + ']'
const decodedJwt = decodeJwt(token.right)

await app.findingsRW.write([
Finding.fromObject({
name: `Agent launched, ScannerId: ${decodedJwt.payload.sub}`,
name: `Agent launched`,
description: `Version: ${VERSION.desc}`,
alertId: 'LIDO-AGENT-LAUNCHED',
severity: FindingSeverity.Info,
Expand Down Expand Up @@ -110,29 +109,33 @@ export const handleBlock = (): HandleBlock => {
return [l2logs.left]
}

const bridgeEventFindings = app.bridgeWatcher.handleLogs(l2logs.right)
const govEventFindings = app.govWatcher.handleLogs(l2logs.right)
const proxyAdminEventFindings = app.proxyEventWatcher.handleLogs(l2logs.right)
const monitorWithdrawalsFindings = app.monitorWithdrawals.handleBlocks(l2logs.right, l2blocksDto.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.handleL2Blocks(l2logs.right, l2blocksDto.right)

const l2BlockNumbers: Set<number> = new Set<number>()
const l2BlockNumberSet: Set<number> = new Set<number>()
for (const l2log of l2logs.right) {
l2BlockNumbers.add(new BigNumber(l2log.blockNumber, 10).toNumber())
l2BlockNumberSet.add(new BigNumber(l2log.blockNumber, 10).toNumber())
}

const l2BlockNumbers = Array.from(l2BlockNumberSet).toSorted((a, b) => a - b)
const proxyWatcherFindings: Finding[] = []

for (const proxyWatcher of app.proxyWatchers) {
const fnds = await proxyWatcher.handleBlocks(Array.from(l2BlockNumbers))
const fnds = await proxyWatcher.handleL2Blocks(l2BlockNumbers)
proxyWatcherFindings.push(...fnds)
}

const bridgeBalanceFindings = await app.bridgeBalanceSrc.handleBlock(blockEvent.block.number, l2BlockNumbers)

findings.push(
...bridgeEventFindings,
...govEventFindings,
...proxyAdminEventFindings,
...monitorWithdrawalsFindings,
...proxyWatcherFindings,
...bridgeBalanceFindings,
)

app.healthChecker.check(findings)
Expand Down
56 changes: 38 additions & 18 deletions l2-bridge-base/src/app.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { FortaGuardClient } from './clients/forta_guard_client'
import { ethers, fetchJwt } from 'forta-agent'
import { IProvider, BaseProvider } from './clients/base_provider'
import { ethers, fetchJwt, getJsonRpcUrl } from 'forta-agent'
import { BaseClient } from './clients/base_client'
import { EventWatcher } from './services/event_watcher'
import { getL2BridgeEvents } from './utils/events/bridge_events'
import { getGovEvents } from './utils/events/gov_events'
import { getProxyAdminEvents } from './utils/events/proxy_admin_events'
import { ProxyContractClient } from './clients/proxy_contract_client'
import { Address } from './utils/constants'
import { L2Bridge__factory, ProxyShortABI__factory } from './generated'
import { ERC20Short__factory, L2Bridge__factory, ProxyShortABI__factory } from './generated'
import { BlockClient } from './clients/base_block_client'
import { ProxyWatcher } from './services/proxy_watcher'
import { MonitorWithdrawals } from './services/monitor_withdrawals'
Expand All @@ -17,13 +16,17 @@ import { Logger } from 'winston'
import { BorderTime, HealthChecker, MaxNumberErrorsPerBorderTime } from './services/health-checker/health-checker.srv'
import { verifyJwt } from 'forta-agent/dist/sdk/jwt'
import * as E from 'fp-ts/Either'
import { BridgeBalanceSrv } from './services/bridge_balance'
import { ETHProvider } from './clients/eth_provider_client'

export type Container = {
baseClient: IProvider
ethClient: ETHProvider
baseClient: BaseClient
proxyWatchers: ProxyWatcher[]
monitorWithdrawals: MonitorWithdrawals
blockSrv: BlockClient
bridgeWatcher: EventWatcher
bridgeBalanceSrc: BridgeBalanceSrv
govWatcher: EventWatcher
proxyEventWatcher: EventWatcher
findingsRW: FindingsRW
Expand Down Expand Up @@ -65,54 +68,71 @@ export class App {
transports: [new Winston.transports.Console()],
})

const baseRpcURL = FortaGuardClient.getSecret()

const baseNetworkID = 8453
const nodeClient = new ethers.providers.JsonRpcProvider(baseRpcURL, baseNetworkID)
const baseProvider = new ethers.providers.JsonRpcProvider('https://base.llamarpc.com', baseNetworkID)
const adr: Address = Address
TheDZhon marked this conversation as resolved.
Show resolved Hide resolved

const l2Bridge = L2Bridge__factory.connect(adr.L2_ERC20_TOKEN_GATEWAY_ADDRESS, nodeClient)
const baseClient = new BaseProvider(nodeClient, l2Bridge, logger)
const l2Bridge = L2Bridge__factory.connect(adr.BASE_L2ERC20_TOKEN_BRIDGE_ADDRESS, baseProvider)
const bridgedWSthEthRunner = ERC20Short__factory.connect(adr.BASE_WSTETH_ADDRESS, baseProvider)
const baseClient = new BaseClient(baseProvider, l2Bridge, logger, bridgedWSthEthRunner)

const bridgeEventWatcher = new EventWatcher(
'BridgeEventWatcher',
getL2BridgeEvents(adr.L2_ERC20_TOKEN_GATEWAY, adr.RolesMap),
getL2BridgeEvents(adr.BASE_L2ERC20_TOKEN_BRIDGED, adr.RolesMap),
logger,
)
const govEventWatcher = new EventWatcher('GovEventWatcher', getGovEvents(adr.GOV_BRIDGE_ADDRESS), logger)
const govEventWatcher = new EventWatcher('GovEventWatcher', getGovEvents(adr.BASE_GOV_EXECUTOR_ADDRESS), logger)
const proxyEventWatcher = new EventWatcher(
'ProxyEventWatcher',
getProxyAdminEvents(adr.L2_ERC20_TOKEN_GATEWAY, adr.BASE_WST_ETH_BRIDGED),
getProxyAdminEvents(adr.BASE_L2ERC20_TOKEN_BRIDGED, adr.BASE_WSTETH_BRIDGED),
logger,
)

const proxyWatchers: ProxyWatcher[] = [
new ProxyWatcher(
new ProxyContractClient(
adr.L2_ERC20_TOKEN_GATEWAY,
ProxyShortABI__factory.connect(adr.L2_ERC20_TOKEN_GATEWAY.address, nodeClient),
adr.BASE_L2ERC20_TOKEN_BRIDGED,
ProxyShortABI__factory.connect(adr.BASE_L2ERC20_TOKEN_BRIDGED.address, baseProvider),
),
logger,
),
new ProxyWatcher(
new ProxyContractClient(
adr.BASE_WST_ETH_BRIDGED,
ProxyShortABI__factory.connect(adr.BASE_WST_ETH_BRIDGED.address, nodeClient),
adr.BASE_WSTETH_BRIDGED,
ProxyShortABI__factory.connect(adr.BASE_WSTETH_BRIDGED.address, baseProvider),
),
logger,
),
]

const blockSrv: BlockClient = new BlockClient(baseClient, logger)

const monitorWithdrawals = new MonitorWithdrawals(baseClient, adr.L2_ERC20_TOKEN_GATEWAY_ADDRESS, logger)
const monitorWithdrawals = new MonitorWithdrawals(baseClient, adr.BASE_L2ERC20_TOKEN_BRIDGE_ADDRESS, logger)

const mainnet = 1
const drpcUrl = 'https://eth.drpc.org/'
const ethProvider = new ethers.providers.FallbackProvider([
new ethers.providers.JsonRpcProvider(getJsonRpcUrl(), mainnet),
new ethers.providers.JsonRpcProvider(drpcUrl, mainnet),
])

const wSthEthRunner = ERC20Short__factory.connect(adr.L1_WSTETH_ADDRESS, ethProvider)
const ethClient = new ETHProvider(logger, wSthEthRunner)
const bridgeBalanceSrv = new BridgeBalanceSrv(
logger,
ethClient,
adr.BASE_L1ERC20_TOKEN_BRIDGE_ADDRESS,
baseClient,
)

App.instance = {
ethClient: ethClient,
baseClient: baseClient,
proxyWatchers: proxyWatchers,
monitorWithdrawals: monitorWithdrawals,
blockSrv: blockSrv,
bridgeWatcher: bridgeEventWatcher,
bridgeBalanceSrc: bridgeBalanceSrv,
govWatcher: govEventWatcher,
proxyEventWatcher: proxyEventWatcher,
findingsRW: new FindingsRW([]),
Expand Down
8 changes: 4 additions & 4 deletions l2-bridge-base/src/clients/base_block_client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BlockDto } from 'src/entity/blockDto'
import { IProvider } from './base_provider'
import { BlockDto } from '../entity/blockDto'
import { IBaseClient } from './base_client'
import { Log } from '@ethersproject/abstract-provider'
import { Finding } from 'forta-agent'
import * as E from 'fp-ts/Either'
Expand All @@ -8,11 +8,11 @@ import { elapsedTime } from '../utils/time'
import { networkAlert } from '../utils/finding.helpers'

export class BlockClient {
private provider: IProvider
private provider: IBaseClient
private logger: Logger
private cachedBlockDto: BlockDto | undefined = undefined

constructor(provider: IProvider, logger: Logger) {
constructor(provider: IBaseClient, logger: Logger) {
this.provider = provider
this.logger = logger
}
Expand Down
Loading
Loading