@@ -8,17 +8,16 @@ import { IMonitorWithdrawalsClient } from '../clients/scroll_client'
8
8
import { NetworkError } from '../utils/error'
9
9
import { elapsedTime } from '../utils/time'
10
10
import { getUniqueKey } from '../utils/finding.helpers'
11
- import { Constants } from '../utils/constants'
11
+ import { Constants , ETH_DECIMALS } from '../utils/constants'
12
+ import { formatAddress } from 'forta-agent/dist/cli/utils'
12
13
13
- const ETH_DECIMALS = new BigNumber ( 10 ) . pow ( 18 )
14
14
// 10k wstETH
15
15
const MAX_WITHDRAWALS_SUM = 10_000
16
16
17
17
export type MonitorWithdrawalsInitResp = {
18
18
currentWithdrawals : string
19
19
}
20
- export const TWO_DAYS = 60 * 60 * 24 * 2
21
-
20
+ export const HOURS_48 = 60 * 60 * 24 * 2
22
21
23
22
export class MonitorWithdrawals {
24
23
private readonly name : string = 'WithdrawalsMonitor'
@@ -30,7 +29,7 @@ export class MonitorWithdrawals {
30
29
private readonly l2Erc20TokenGatewayAddress : string
31
30
private readonly withdrawalsClient : IMonitorWithdrawalsClient
32
31
33
- private withdrawalsCache : WithdrawalRecord [ ] = [ ]
32
+ private withdrawalsStore : WithdrawalRecord [ ] = [ ]
34
33
private lastReportedTooManyWithdrawalsTimestamp = 0
35
34
36
35
constructor ( withdrawalsClient : IMonitorWithdrawalsClient , l2Erc20TokenGatewayAddress : string , logger : Logger ) {
@@ -44,7 +43,7 @@ export class MonitorWithdrawals {
44
43
}
45
44
46
45
public async initialize ( currentBlock : number ) : Promise < E . Either < NetworkError , MonitorWithdrawalsInitResp > > {
47
- const pastBlock = currentBlock - Math . ceil ( TWO_DAYS / Constants . SCROLL_APPROX_BLOCK_TIME_3_SECONDS )
46
+ const pastBlock = currentBlock - Math . ceil ( HOURS_48 / Constants . SCROLL_APPROX_BLOCK_TIME_3_SECONDS )
48
47
49
48
const withdrawalEvents = await this . withdrawalsClient . getWithdrawalEvents ( pastBlock , currentBlock - 1 )
50
49
if ( E . isLeft ( withdrawalEvents ) ) {
@@ -59,7 +58,7 @@ export class MonitorWithdrawals {
59
58
const withdrawalsSum = new BigNumber ( 0 )
60
59
for ( const wc of withdrawalRecords . right ) {
61
60
withdrawalsSum . plus ( wc . amount )
62
- this . withdrawalsCache . push ( wc )
61
+ this . withdrawalsStore . push ( wc )
63
62
}
64
63
65
64
this . logger . info ( `${ MonitorWithdrawals . name } started on block ${ currentBlock } ` )
@@ -68,37 +67,40 @@ export class MonitorWithdrawals {
68
67
} )
69
68
}
70
69
71
- public handleBlocks ( logs : Log [ ] , blocksDto : BlockDto [ ] ) : Finding [ ] {
70
+ public handleBlocks ( l2Logs : Log [ ] , l2BlocksDto : BlockDto [ ] ) : Finding [ ] {
72
71
const start = new Date ( ) . getTime ( )
73
72
74
73
// adds records into withdrawalsCache
75
- const withdrawalRecords = this . getWithdrawalRecords ( logs , blocksDto )
76
- this . withdrawalsCache . push ( ...withdrawalRecords )
74
+ const withdrawalRecords = this . getWithdrawalRecords ( l2Logs , l2BlocksDto )
75
+ if ( withdrawalRecords . length !== 0 ) {
76
+ this . logger . info ( `Withdrawals count = ${ withdrawalRecords . length } ` )
77
+ }
78
+ this . withdrawalsStore . push ( ...withdrawalRecords )
77
79
78
80
const out : Finding [ ] = [ ]
79
81
80
- for ( const block of blocksDto ) {
82
+ for ( const l2Block of l2BlocksDto ) {
81
83
// remove withdrawals records older than MAX_WITHDRAWALS_WINDOW
82
84
const withdrawalsCache : WithdrawalRecord [ ] = [ ]
83
- for ( const wc of this . withdrawalsCache ) {
84
- if ( wc . time > block . timestamp - TWO_DAYS ) {
85
+ for ( const wc of this . withdrawalsStore ) {
86
+ if ( wc . time > l2Block . timestamp - HOURS_48 ) {
85
87
withdrawalsCache . push ( wc )
86
88
}
87
89
}
88
90
89
- this . withdrawalsCache = withdrawalsCache
91
+ this . withdrawalsStore = withdrawalsCache
90
92
91
93
const withdrawalsSum = new BigNumber ( 0 )
92
- for ( const wc of this . withdrawalsCache ) {
94
+ for ( const wc of this . withdrawalsStore ) {
93
95
withdrawalsSum . plus ( wc . amount )
94
96
}
95
97
96
98
// block number condition is meant to "sync" agents alerts
97
- if ( withdrawalsSum . div ( ETH_DECIMALS ) . isGreaterThanOrEqualTo ( MAX_WITHDRAWALS_SUM ) && block . number % 10 === 0 ) {
99
+ if ( withdrawalsSum . div ( ETH_DECIMALS ) . isGreaterThanOrEqualTo ( MAX_WITHDRAWALS_SUM ) && l2Block . number % 10 === 0 ) {
98
100
const period =
99
- block . timestamp - this . lastReportedTooManyWithdrawalsTimestamp < TWO_DAYS
100
- ? block . timestamp - this . lastReportedTooManyWithdrawalsTimestamp
101
- : TWO_DAYS
101
+ l2Block . timestamp - this . lastReportedTooManyWithdrawalsTimestamp < HOURS_48
102
+ ? l2Block . timestamp - this . lastReportedTooManyWithdrawalsTimestamp
103
+ : HOURS_48
102
104
103
105
const uniqueKey = `C167F276-D519-4906-90CB-C4455E9ABBD4`
104
106
@@ -110,45 +112,45 @@ export class MonitorWithdrawals {
110
112
alertId : 'HUGE-WITHDRAWALS-FROM-L2' ,
111
113
severity : FindingSeverity . Medium ,
112
114
type : FindingType . Suspicious ,
113
- uniqueKey : getUniqueKey ( uniqueKey , block . number ) ,
115
+ uniqueKey : getUniqueKey ( uniqueKey , l2Block . number ) ,
114
116
} )
115
117
116
118
out . push ( finding )
117
119
118
- this . lastReportedTooManyWithdrawalsTimestamp = block . timestamp
120
+ this . lastReportedTooManyWithdrawalsTimestamp = l2Block . timestamp
119
121
120
122
const tmp : WithdrawalRecord [ ] = [ ]
121
- for ( const wc of this . withdrawalsCache ) {
122
- if ( wc . time > block . timestamp - this . lastReportedTooManyWithdrawalsTimestamp ) {
123
+ for ( const wc of this . withdrawalsStore ) {
124
+ if ( wc . time > l2Block . timestamp - this . lastReportedTooManyWithdrawalsTimestamp ) {
123
125
tmp . push ( wc )
124
126
}
125
127
}
126
128
127
- this . withdrawalsCache = tmp
129
+ this . withdrawalsStore = tmp
128
130
}
129
131
}
130
132
131
133
this . logger . info ( elapsedTime ( MonitorWithdrawals . name + '.' + this . handleBlocks . name , start ) )
132
134
return out
133
135
}
134
136
135
- private getWithdrawalRecords ( logs : Log [ ] , blocksDto : BlockDto [ ] ) : WithdrawalRecord [ ] {
137
+ private getWithdrawalRecords ( l2Logs : Log [ ] , l2BlocksDto : BlockDto [ ] ) : WithdrawalRecord [ ] {
136
138
const blockNumberToBlock = new Map < number , BlockDto > ( )
137
139
const logIndexToLogs = new Map < number , Log > ( )
138
- const addresses : string [ ] = [ ]
140
+ const addresses = new Set < string > ( )
139
141
140
- for ( const log of logs ) {
141
- logIndexToLogs . set ( log . logIndex , log )
142
- addresses . push ( log . address )
142
+ for ( const l2Log of l2Logs ) {
143
+ logIndexToLogs . set ( l2Log . logIndex , l2Log )
144
+ addresses . add ( l2Log . address . toLowerCase ( ) )
143
145
}
144
146
145
- for ( const blockDto of blocksDto ) {
146
- blockNumberToBlock . set ( blockDto . number , blockDto )
147
+ for ( const l2BlockDto of l2BlocksDto ) {
148
+ blockNumberToBlock . set ( l2BlockDto . number , l2BlockDto )
147
149
}
148
150
149
151
const out : WithdrawalRecord [ ] = [ ]
150
- if ( this . l2Erc20TokenGatewayAddress in addresses ) {
151
- const events = filterLog ( logs , this . withdrawalInitiatedEvent , this . l2Erc20TokenGatewayAddress )
152
+ if ( formatAddress ( this . l2Erc20TokenGatewayAddress ) in addresses ) {
153
+ const events = filterLog ( l2Logs , this . withdrawalInitiatedEvent , formatAddress ( this . l2Erc20TokenGatewayAddress ) )
152
154
153
155
for ( const event of events ) {
154
156
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
0 commit comments