Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
37ed84de
Unverified
Commit
37ed84de
authored
Jun 14, 2023
by
OptimismBot
Committed by
GitHub
Jun 14, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #6008 from ethereum-optimism/jm/tfr-mon
feat(c-mon): Add wallet-mon service
parents
a541c8a8
8ab436a5
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
233 additions
and
0 deletions
+233
-0
moody-foxes-enjoy.md
.changeset/moody-foxes-enjoy.md
+6
-0
Dockerfile.packages
ops/docker/Dockerfile.packages
+4
-0
.env.example
packages/chain-mon/.env.example
+11
-0
package.json
packages/chain-mon/package.json
+2
-0
index.ts
packages/chain-mon/src/index.ts
+1
-0
service.ts
packages/chain-mon/src/wallet-mon/service.ts
+198
-0
misc.ts
packages/core-utils/src/common/misc.ts
+11
-0
No files found.
.changeset/moody-foxes-enjoy.md
0 → 100644
View file @
37ed84de
---
'
@eth-optimism/chain-mon'
:
minor
'
@eth-optimism/core-utils'
:
patch
---
Added a new service wallet-mon to identify unexpected transfers from key accounts
ops/docker/Dockerfile.packages
View file @
37ed84de
...
...
@@ -89,3 +89,7 @@ ENTRYPOINT ["npm", "run", "start:drippie-mon"]
FROM base as wd-mon
WORKDIR /opt/optimism/packages/chain-mon
ENTRYPOINT ["yarn", "run", "start:wd-mon"]
FROM base as wallet-mon
WORKDIR /opt/optimism/packages/chain-mon
ENTRYPOINT ["yarn", "run", "start:wallet-mon"]
packages/chain-mon/.env.example
View file @
37ed84de
...
...
@@ -8,6 +8,17 @@ BALANCE_MON__RPC=
# JSON array in the format [{ "address": <address>, "nickname": <nickname> }, ... ]
BALANCE_MON__ACCOUNTS=
###############################################################################
# ↓ wallet-mon ↓ #
###############################################################################
# RPC pointing to network to monitor
WALLET_MON__RPC=
# The block number to start monitoring from
# Defaults to the first bedrock block if unset.
WALLET_MON__START_BLOCK_NUMBER=
###############################################################################
# ↓ drippie-mon ↓ #
###############################################################################
...
...
packages/chain-mon/package.json
View file @
37ed84de
...
...
@@ -10,6 +10,7 @@
],
"scripts"
:
{
"start:balance-mon"
:
"ts-node ./src/balance-mon/service.ts"
,
"start:wallet-mon"
:
"ts-node ./src/wallet-mon/service.ts"
,
"start:drippie-mon"
:
"ts-node ./src/drippie-mon/service.ts"
,
"start:wd-mon"
:
"ts-node ./src/wd-mon/service.ts"
,
"test:coverage"
:
"echo 'No tests defined.'"
,
...
...
@@ -35,6 +36,7 @@
"dependencies"
:
{
"@eth-optimism/common-ts"
:
"0.8.1"
,
"@eth-optimism/contracts-periphery"
:
"1.0.8"
,
"@eth-optimism/contracts-bedrock"
:
"0.14.0"
,
"@eth-optimism/core-utils"
:
"0.12.0"
,
"@eth-optimism/sdk"
:
"2.1.0"
,
"ethers"
:
"^5.7.0"
,
...
...
packages/chain-mon/src/index.ts
View file @
37ed84de
export
*
from
'
./balance-mon/service
'
export
*
from
'
./drippie-mon/service
'
export
*
from
'
./wd-mon/service
'
export
*
from
'
./wallet-mon/service
'
packages/chain-mon/src/wallet-mon/service.ts
0 → 100644
View file @
37ed84de
import
{
BaseServiceV2
,
StandardOptions
,
Gauge
,
Counter
,
validators
,
waitForProvider
,
}
from
'
@eth-optimism/common-ts
'
import
{
getChainId
,
compareAddrs
}
from
'
@eth-optimism/core-utils
'
import
{
Provider
}
from
'
@ethersproject/abstract-provider
'
import
mainnetConfig
from
'
@eth-optimism/contracts-bedrock/deploy-config/mainnet.json
'
import
goerliConfig
from
'
@eth-optimism/contracts-bedrock/deploy-config/goerli.json
'
import
l2OutputOracleArtifactsMainnet
from
'
@eth-optimism/contracts-bedrock/deployments/mainnet/L2OutputOracleProxy.json
'
import
l2OutputOracleArtifactsGoerli
from
'
@eth-optimism/contracts-bedrock/deployments/goerli/L2OutputOracleProxy.json
'
import
{
version
}
from
'
../../package.json
'
const
networks
=
{
1
:
{
name
:
'
mainnet
'
,
l1StartingBlockTag
:
mainnetConfig
.
l1StartingBlockTag
,
accounts
:
[
{
label
:
'
Proposer
'
,
wallet
:
mainnetConfig
.
l2OutputOracleProposer
,
target
:
l2OutputOracleArtifactsMainnet
.
address
,
},
{
label
:
'
Batcher
'
,
wallet
:
mainnetConfig
.
batchSenderAddress
,
target
:
mainnetConfig
.
batchInboxAddress
,
},
],
},
10
:
{
name
:
'
goerli
'
,
l1StartingBlockTag
:
goerliConfig
.
l1StartingBlockTag
,
accounts
:
[
{
label
:
'
Proposer
'
,
wallet
:
goerliConfig
.
l2OutputOracleProposer
,
target
:
l2OutputOracleArtifactsGoerli
.
address
,
},
{
label
:
'
Batcher
'
,
wallet
:
goerliConfig
.
batchSenderAddress
,
target
:
goerliConfig
.
batchInboxAddress
,
},
],
},
}
type
WalletMonOptions
=
{
rpc
:
Provider
startBlockNumber
:
number
}
type
WalletMonMetrics
=
{
validatedCalls
:
Counter
unexpectedCalls
:
Counter
unexpectedRpcErrors
:
Counter
}
type
WalletMonState
=
{
chainId
:
number
highestUncheckedBlockNumber
:
number
}
export
class
WalletMonService
extends
BaseServiceV2
<
WalletMonOptions
,
WalletMonMetrics
,
WalletMonState
>
{
constructor
(
options
?:
Partial
<
WalletMonOptions
&
StandardOptions
>
)
{
super
({
version
,
name
:
'
wallet-mon
'
,
loop
:
true
,
options
:
{
loopIntervalMs
:
1000
,
...
options
,
},
optionsSpec
:
{
rpc
:
{
validator
:
validators
.
provider
,
desc
:
'
Provider for network to monitor balances on
'
,
},
startBlockNumber
:
{
validator
:
validators
.
num
,
default
:
-
1
,
desc
:
'
L1 block number to start checking from
'
,
public
:
true
,
},
},
metricsSpec
:
{
validatedCalls
:
{
type
:
Gauge
,
desc
:
'
Transactions from the account checked
'
,
labels
:
[
'
wallet
'
,
'
target
'
,
'
nickname
'
],
},
unexpectedCalls
:
{
type
:
Counter
,
desc
:
'
Number of unexpected wallets
'
,
labels
:
[
'
wallet
'
,
'
target
'
,
'
nickname
'
],
},
unexpectedRpcErrors
:
{
type
:
Counter
,
desc
:
'
Number of unexpected RPC errors
'
,
labels
:
[
'
section
'
,
'
name
'
],
},
},
})
}
protected
async
init
():
Promise
<
void
>
{
// Connect to L1.
await
waitForProvider
(
this
.
options
.
rpc
,
{
logger
:
this
.
logger
,
name
:
'
L1
'
,
})
this
.
state
.
chainId
=
await
getChainId
(
this
.
options
.
rpc
)
const
l1StartingBlockTag
=
networks
[
this
.
state
.
chainId
].
l1StartingBlockTag
if
(
this
.
options
.
startBlockNumber
===
-
1
)
{
const
block
=
await
this
.
options
.
rpc
.
getBlock
(
l1StartingBlockTag
)
this
.
state
.
highestUncheckedBlockNumber
=
block
.
number
}
else
{
this
.
state
.
highestUncheckedBlockNumber
=
this
.
options
.
startBlockNumber
}
}
protected
async
main
():
Promise
<
void
>
{
if
(
(
await
this
.
options
.
rpc
.
getBlockNumber
())
<
this
.
state
.
highestUncheckedBlockNumber
)
{
this
.
logger
.
info
(
'
Waiting for new blocks
'
)
return
}
const
network
=
networks
[
this
.
state
.
chainId
]
const
accounts
=
network
.
accounts
const
block
=
await
this
.
options
.
rpc
.
getBlock
(
this
.
state
.
highestUncheckedBlockNumber
)
this
.
logger
.
info
(
'
Checking block
'
,
{
number
:
block
.
number
,
})
const
transactions
=
[]
for
(
const
txHash
of
block
.
transactions
)
{
const
t
=
await
this
.
options
.
rpc
.
getTransaction
(
txHash
)
transactions
.
push
(
t
)
}
for
(
const
transaction
of
transactions
)
{
for
(
const
account
of
accounts
)
{
if
(
compareAddrs
(
account
.
wallet
,
transaction
.
from
))
{
if
(
compareAddrs
(
account
.
target
,
transaction
.
to
))
{
this
.
metrics
.
validatedCalls
.
inc
({
nickname
:
account
.
label
,
wallet
:
account
.
address
,
target
:
account
.
target
,
})
this
.
logger
.
info
(
'
validated call
'
,
{
nickname
:
account
.
label
,
wallet
:
account
.
address
,
target
:
account
.
target
,
})
}
else
{
this
.
metrics
.
unexpectedCalls
.
inc
({
nickname
:
account
.
label
,
wallet
:
account
.
address
,
target
:
transaction
.
to
,
})
this
.
logger
.
error
(
'
Unexpected call detected
'
,
{
nickname
:
account
.
label
,
address
:
account
.
address
,
target
:
transaction
.
to
,
})
}
}
}
}
this
.
logger
.
info
(
'
Checked block
'
,
{
number
:
this
.
state
.
highestUncheckedBlockNumber
,
})
this
.
state
.
highestUncheckedBlockNumber
++
}
}
if
(
require
.
main
===
module
)
{
const
service
=
new
WalletMonService
()
service
.
run
()
}
packages/core-utils/src/common/misc.ts
View file @
37ed84de
...
...
@@ -48,3 +48,14 @@ export const reqenv = (name: string): string => {
export
const
getenv
=
(
name
:
string
,
fallback
?:
string
):
string
|
undefined
=>
{
return
process
.
env
[
name
]
||
fallback
}
/**
* Returns true if the given string is a valid address.
*
* @param a First address to check.
* @param b Second address to check.
* @returns True if the given addresses match.
*/
export
const
compareAddrs
=
(
a
:
string
,
b
:
string
):
boolean
=>
{
return
a
.
toLowerCase
()
===
b
.
toLowerCase
()
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment