Skip to content

Commit

Permalink
Merge pull request #459 from lidofinance/eth-steth
Browse files Browse the repository at this point in the history
Eth steth
  • Loading branch information
sergeyWh1te authored Jan 29, 2024
2 parents ccb071d + 7eeb120 commit e0d4f98
Show file tree
Hide file tree
Showing 56 changed files with 13,615 additions and 8 deletions.
3 changes: 3 additions & 0 deletions ethereum-steth-v2/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
dist/
forta.config.json
14 changes: 14 additions & 0 deletions ethereum-steth-v2/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"parser": "@typescript-eslint/parser",
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
"plugins": ["@typescript-eslint", "prettier"],
"env": {
"node": true,
"es6": true
},
"rules": {
"prettier/prettier": "error",
"curly": "error",
"semi": "off"
}
}
9 changes: 9 additions & 0 deletions ethereum-steth-v2/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
node_modules
dist
forta.config.json
.yarn/*
!.yarn/releases/
*.log
version.json
.DS_Store
/coverage/
7 changes: 7 additions & 0 deletions ethereum-steth-v2/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"semi": false,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 120,
"tabWidth": 2
}
24 changes: 24 additions & 0 deletions ethereum-steth-v2/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Build stage: compile Typescript to Javascript
FROM node:20.10.0-alpine3.18 AS base

FROM base as builder

WORKDIR /app

COPY . .
RUN yarn install --immutable && yarn run build
# Build app
RUN yarn run build

# Final stage: copy compiled Javascript from previous stage and install production dependencies
FROM base as production
LABEL "network.forta.settings.agent-logs.enable"="true"
ENV NODE_ENV=production
WORKDIR /app

COPY package*.json yarn.lock ./
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./src
COPY version.json ./

CMD ["yarn", "run", "start:prod"]
107 changes: 107 additions & 0 deletions ethereum-steth-v2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Lido Ethereum StETH bot

## Supported chains

- Ethereum mainnet

## Alerts

1. StETH operations
1. HandleBlock
1. 🚨🚨🚨 Buffered ETH drain (checks each block)
2. 🚨 Huge depositable ETH amount (checks every 100 blocks)
3. ⚠️ High depositable ETH amount (checks every 100 blocks)
4. ⚠️ Low deposit executor balance (checks every 100 blocks)
5. ⚠️ Unspent staking limit below 10% (checks every 25 blocks)
6. 📉 Unspent staking limit below 30% (checks every 25 blocks)
2. HandleTransaction
1. Deposit Security events
2. 🚨 Deposit Security: Deposits paused
3. 🚨 Deposit Security: Guardian quorum changed
4. 🚨 Deposit Security: Owner changed
5. ⚠️ Deposit Security: Deposits resumed
6. ⚠️ Deposit Security: Guardian added
7. ⚠️ Deposit Security: Guardian removed
8. ⚠️ Deposit Security: Max deposits changed
9. ⚠️ Deposit Security: Min deposit block distance changed
3. Lido events
1. 🚨🚨🚨 Lido: Stopped 🚨🚨🚨
2. 🚨🚨🚨 Share rate unexpected has changed
3. 🚨 Lido: Staking limit removed
4. 🚨 Lido: Locator set
5. ⚠️ Lido: Resumed
6. 🚨 Lido: Staking paused
7. ⚠️ Lido: Staking resumed
8. ⚠️ Lido: Staking limit set
9. ⚠️ Lido: Funds recovered to vault
10. ⚠️ Lido: Contract version set
11. ℹ️ Lido: Token rebased
4. Insurance fund events
1. 🚨 Insurance fund: ERC20 transferred
2. 🚨 Insurance fund: Ownership transferred
3. ⚠️ Insurance fund: ETH transferred
4. ⚠️ Insurance fund: ERC1155 transferred
5. ⚠️ Insurance fund: ERC721 transferred
5. Burner events
1. ℹ️ Lido Burner: ERC20 recovered
2. ℹ️ Lido Burner: ERC721 recovered
2. Withdrawals
1. HandleBlock runs on each 100-th block or one per 20 minutes
1. ⚠️ Withdrawals: <limitRate>% of stake limit is spent and unfinalized queue is on par with drained stake
limit
2. ⚠️ Withdrawals: unfinalized queue is more than 100_000 stETH
3. ⚠️ Withdrawals: unfinalized queue wait time is <hours> more than 1 day
4. ⚠️ Withdrawals: ${unclaimedSizeRate.times(100).toFixed(2)}% of finalized requests are unclaimed
5. ⚠️ Withdrawals: unclaimed requests size is more than withdrawal queue balance
2. HandleTransaction
1. 🚨 Withdrawals: BUNKER MODE ON! 🚨
2. 🚨 Withdrawals: contract was paused
3. ⚠️ Withdrawals: BUNKER MODE OFF! ✅
4. ℹ️ Huge stETH withdrawal requests batch
5. ⚠️ Withdrawals: the sum of received withdrawal requests since the last rebase greater than 150_000 stETH (max
staking limit)
6. ⚠️ Withdrawals: claimed amount is more than requested
7. ⚠️ Withdrawals: contract was unpaused
3. GateSeal
1. HandleBlock runs on each next block
1. 🚨 GateSeal: actual address doesn't have PAUSE_ROLE for contracts
2. 🚨 GateSeal: is expired!
3. 🚨️ GateSeal: is expired. Update code!
4. ⚠️ GateSeal: default GateSeal address in forta agent is expired
5. ⚠️️ GateSeal: default GateSeal address in forta agent doesn't have PAUSE_ROLE for contracts
6. ⚠️ GateSeal: is about to be expired
2. HandleTransaction
1. 🚨🚨🚨 GateSeal: is sealed 🚨🚨🚨
2. 🚨 GateSeal: is expired
4. Vaults
1. Handleblock
1. 🚨🚨🚨 Withdrawal Vault balance mismatch. [without oracle report]
2. 🚨🚨🚨 Withdrawal Vault balance mismatch. [within oracle report]
3. 🚨🚨🚨 EL Vault balance mismatch. [without oracle report]
4. 🚨🚨🚨 EL Vault balance mismatch. [within oracle report]
5. 💵 Withdrawal Vault Balance significant change (checks every on 100-th block)
6. 💵 EL Vault Balance significant change
2. HandleTransaction
1. 🚨 Burner shares transfer

## Development (Forta specific)

Edit `alerting-forta/<SUBMODULE>/forta.config.json` and set `jsonRpcUrl` to your JSON-RPC provider. Install deps:

```
yarn install
```

Running in a live mode:

```
yarn start:dev
```

Testing on a specific block/range/transaction:

```
yarn block 13626668
yarn range '13626667..13626668'
yarn tx 0x2d2774c04e3faf9f17cd26e0978bb812081b9d0b5cc6fd8bf04cc441f92c0a8c
```
6 changes: 6 additions & 0 deletions ethereum-steth-v2/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/** @type {import("ts-jest").JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testPathIgnorePatterns: ['dist'],
}
87 changes: 87 additions & 0 deletions ethereum-steth-v2/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"name": "lido-steth-forta-bot",
"version": "1.0.0",
"description": "Forta Bot for Lido stETH",
"repository": {
"type": "git",
"directory": "https://github.com/lidofinance/alerting-forta/tree/main/ethereum-steth"
},
"license": "MIT",
"chainIds": [
1
],
"husky": {
"hooks": {
"pre-commit": "yarn run lint"
}
},
"scripts": {
"update-version": "node ../utils/write-version.js",
"build": "tsc && yarn run copy-version",
"copy-version": "cp version.json dist",
"start": "yarn run update-version && yarn run start:dev",
"start:dev": "nodemon --watch src --watch forta.config.json -e js,ts,json --exec \"yarn run build && yarn run copy-version && forta-agent run\"",
"start:prod": "forta-agent run --prod",
"tx": "yarn run build && forta-agent run --tx",
"block": "yarn run build && forta-agent run --block",
"range": "yarn run build && forta-agent run --range",
"alert": "yarn run build && forta-agent run --alert",
"sequence": "yarn run build && forta-agent run --sequence",
"file": "yarn run build && forta-agent run --file",
"publish": "yarn run update-version && forta-agent publish",
"info": "forta-agent info",
"logs": "forta-agent logs",
"push": "yarn run update-version && forta-agent push",
"disable": "forta-agent disable",
"enable": "forta-agent enable",
"keyfile": "forta-agent keyfile",
"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",
"lint": "yarn run prettier:check && yarn run eslint:lint",
"format": "yarn run eslint:format && yarn run prettier:format",
"postinstall": "yarn generate-types"
},
"dependencies": {
"@types/lodash": "^4.14.202",
"async-mutex": "^0.4.0",
"bignumber.js": "^9.1.2",
"ethers": "^5.5.1",
"forta-agent": "^0.1.48",
"fp-ts": "^2.16.1",
"lodash": "^4.17.21",
"ts-retry": "^4.2.4",
"winston": "^3.11.0",
"@ethersproject/abi": "^5.0.0",
"@ethersproject/providers": "^5.0.0"
},
"devDependencies": {
"@faker-js/faker": "^8.3.1",
"@jest/globals": "^29.7.0",
"@tsconfig/node20": "^20.1.2",
"@typechain/ethers-v5": "^11.1.2",
"@types/jest": "^29.5.11",
"@types/nodemon": "^1.19.0",
"@types/ws": "^8.5.10",
"@typescript-eslint/eslint-plugin": "^6.12.0",
"@typescript-eslint/parser": "^6.12.0",
"eslint": "^8.54.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-jest": "^27.6.0",
"eslint-plugin-prettier": "^5.0.1",
"husky": "^8.0.3",
"jest": "^29.7.0",
"nodemon": "^3.0.1",
"postinstall": "^0.8.0",
"prettier": "^3.1.0",
"ts-generator": "^0.1.1",
"ts-jest": "^29.1.2",
"typechain": "^8.3.2",
"typescript": "^5.3.2"
},
"packageManager": "yarn@1.22.21"
}
67 changes: 67 additions & 0 deletions ethereum-steth-v2/src/abi/GateSeal.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
[
{
"name": "Sealed",
"inputs": [
{ "name": "gate_seal", "type": "address", "indexed": false },
{ "name": "sealed_by", "type": "address", "indexed": false },
{ "name": "sealed_for", "type": "uint256", "indexed": false },
{ "name": "sealable", "type": "address", "indexed": false },
{ "name": "sealed_at", "type": "uint256", "indexed": false }
],
"anonymous": false,
"type": "event"
},
{
"stateMutability": "nonpayable",
"type": "constructor",
"inputs": [
{ "name": "_sealing_committee", "type": "address" },
{ "name": "_seal_duration_seconds", "type": "uint256" },
{ "name": "_sealables", "type": "address[]" },
{ "name": "_expiry_timestamp", "type": "uint256" }
],
"outputs": []
},
{
"stateMutability": "view",
"type": "function",
"name": "get_sealing_committee",
"inputs": [],
"outputs": [{ "name": "", "type": "address" }]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_seal_duration_seconds",
"inputs": [],
"outputs": [{ "name": "", "type": "uint256" }]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_sealables",
"inputs": [],
"outputs": [{ "name": "", "type": "address[]" }]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_expiry_timestamp",
"inputs": [],
"outputs": [{ "name": "", "type": "uint256" }]
},
{
"stateMutability": "view",
"type": "function",
"name": "is_expired",
"inputs": [],
"outputs": [{ "name": "", "type": "bool" }]
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "seal",
"inputs": [{ "name": "_sealables", "type": "address[]" }],
"outputs": []
}
]
33 changes: 33 additions & 0 deletions ethereum-steth-v2/src/abi/GateSealFactory.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[
{
"name": "GateSealCreated",
"inputs": [{ "name": "gate_seal", "type": "address", "indexed": false }],
"anonymous": false,
"type": "event"
},
{
"stateMutability": "nonpayable",
"type": "constructor",
"inputs": [{ "name": "_blueprint", "type": "address" }],
"outputs": []
},
{
"stateMutability": "view",
"type": "function",
"name": "get_blueprint",
"inputs": [],
"outputs": [{ "name": "", "type": "address" }]
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "create_gate_seal",
"inputs": [
{ "name": "_sealing_committee", "type": "address" },
{ "name": "_seal_duration_seconds", "type": "uint256" },
{ "name": "_sealables", "type": "address[]" },
{ "name": "_expiry_timestamp", "type": "uint256" }
],
"outputs": []
}
]
Loading

0 comments on commit e0d4f98

Please sign in to comment.