Skip to content

Commit 648633c

Browse files
hweawerF4ever
andauthored
Release mellow main (#254)
* chore: set default strategy * Upgrade python to 3.12 * Upgrade poetry * upgrade curl * Mellow mvp (#224) * Mellow direct deposit, skip ABI * Prepare direct deposit transaction * Property checking * Fix linter * amount parameter in the contract * Fix comments * Check variable not set * Contract abi integration test * Add fixtures * Remove amount parameter from abi * Formatter changes * Formatter changes * Holesky mark in tests * Test balanceOf of weth * Renamings * Rename mark * block_identifier * Update src/variables.py Co-authored-by: Raman Siamionau <[email protected]> * Fix comments * Renamed env var in pipeline * Change module to deposit * Send mellow transaction * Change comment * DD description * Update README.md Co-authored-by: Raman Siamionau <[email protected]> * Refactor sending mellow transaction * Refactor sending mellow transaction * is_mellow_depositable unit test * Unit test for sending mellow tx * Formatting --------- Co-authored-by: Raman Siamionau <[email protected]> * Metric for modules (#229) * Expose modules metric * Reorder * Reorder * Update src/metrics/metrics.py Co-authored-by: Raman Siamionau <[email protected]> --------- Co-authored-by: Raman Siamionau <[email protected]> * Log env vars (#227) * Log public env vars * Add chain_id * Public env vars in prometheus metric * Add message to a log * Change info description * Update src/variables.py Co-authored-by: Raman Siamionau <[email protected]> * Update src/metrics/metrics.py Co-authored-by: Raman Siamionau <[email protected]> * Remove prefix, not assert * Fix imports --------- Co-authored-by: Raman Siamionau <[email protected]> * Fix Info metircs endpoint(#231) * Fix log string * Change forematting * Convert values to strings * remove convertion * Mellow deposit strategy (#230) * Change validation for mellow deposits * Load WQ contract from the locator * Refactor * Change log message * Beffered ether * Change ABI * Move check inside is_mellow_depositable * Add ping type to the rabbit messages in the unvetter * Mellow new ABIs * Remove old build metrics (#239) * Add mellow variable to examples (#237) * Add mellow variable to examples * Remove import * Update holesky address * Add account to variables (#241) * Add account to metrics * Fix field ref * Change to propery * Direct access property * Separate mellow flow (#235) * Separate mellow flow * Formatting * Rerun integration tests * Strategy return * Rewrite to abstract classes * Fix formatting * Fix bug with return * Restructure * remove init * _is_mellow * Fix tests * Fix signs test * Fix integration * Fix unit test * Mellow test * Update src/blockchain/deposit_strategy/base_deposit_strategy.py Co-authored-by: Raman Siamionau <[email protected]> * Refactor * Renamings * Imports * inject dependecies --------- Co-authored-by: Raman Siamionau <[email protected]> * Metric per module (#244) * Per module metric * FOrmatting * Fix error repr * Metrics for checks (#246) * Metrics for different check statuses * Formatting * Fix early returns (#248) * Mellow fallback (#250) * Mellow fallback * Fix unit tests * Fix DepositorBot constructor in test * Fix positional argument * Double max deposit count * Fix test * Improve test * Sender chain in integrations * Without sender chain * Reorder * Remove redundant function * New metric for mellow * Cast * Merge main --------- Co-authored-by: F4ever <[email protected]>
1 parent d73c534 commit 648633c

File tree

11 files changed

+149
-48
lines changed

11 files changed

+149
-48
lines changed

src/blockchain/contracts/deposit_security_module.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from blockchain.contracts.base_interface import ContractInterface
44
from eth_typing import ChecksumAddress, Hash32
5+
from metrics.metrics import CAN_DEPOSIT
56
from web3.contract.contract import ContractFunction
67
from web3.exceptions import ABIFunctionNotFound, ContractLogicError
78
from web3.types import BlockIdentifier
@@ -37,6 +38,7 @@ def can_deposit(self, staking_module_id: int, block_identifier: BlockIdentifier
3738
"""
3839
response = self.functions.canDeposit(staking_module_id).call(block_identifier=block_identifier)
3940
logger.info({'msg': f'Call `canDeposit({staking_module_id})`.', 'value': response, 'block_identifier': repr(block_identifier)})
41+
CAN_DEPOSIT.labels(staking_module_id).set(int(response))
4042
return response
4143

4244
def deposit_buffered_ether(

src/blockchain/deposit_strategy/base_deposit_strategy.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def deposited_keys_amount(self, module_id: int) -> int:
2828
module_id,
2929
depositable_ether,
3030
)
31-
POSSIBLE_DEPOSITS_AMOUNT.labels(module_id).set(possible_deposits_amount)
31+
POSSIBLE_DEPOSITS_AMOUNT.labels(module_id, 0).set(possible_deposits_amount)
3232
return possible_deposits_amount
3333

3434

@@ -44,3 +44,17 @@ def _depositable_ether(self) -> Wei:
4444
logger.info({'msg': 'Adding mellow vault balance to the depositable check', 'vault': additional_ether})
4545
depositable_ether += additional_ether
4646
return depositable_ether
47+
48+
def deposited_keys_amount(self, module_id: int) -> int:
49+
depositable_ether = self._depositable_ether()
50+
possible_deposits_amount_assumption = self.w3.lido.staking_router.get_staking_module_max_deposits_count(
51+
module_id,
52+
depositable_ether,
53+
)
54+
possible_deposited_eth = Web3.to_wei(32 * possible_deposits_amount_assumption, 'ether')
55+
possible_deposits_amount = self.w3.lido.staking_router.get_staking_module_max_deposits_count(
56+
module_id,
57+
possible_deposited_eth,
58+
)
59+
POSSIBLE_DEPOSITS_AMOUNT.labels(module_id, 1).set(possible_deposits_amount)
60+
return possible_deposits_amount if possible_deposits_amount_assumption == possible_deposits_amount else 0

src/blockchain/deposit_strategy/deposit_transaction_sender.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ def _prepare_signs_for_deposit(quorum: list[DepositMessage]) -> tuple[tuple[str,
2929
def prepare_and_send(
3030
self,
3131
quorum: list[DepositMessage],
32-
with_flashbots: bool,
3332
is_mellow: bool,
33+
with_flashbots: bool,
3434
) -> bool:
3535
tx = self._prepare_mellow_tx(quorum) if is_mellow else self._prepare_general_tx(quorum)
3636
return self._send_transaction(tx, with_flashbots)

src/blockchain/deposit_strategy/gas_price_calculator.py

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from blockchain.deposit_strategy.base_deposit_strategy import BaseDepositStrategy
99
from blockchain.typings import Web3
1010
from eth_typing import BlockNumber
11-
from metrics.metrics import GAS_FEE
11+
from metrics.metrics import DEPOSIT_AMOUNT_OK, GAS_FEE, GAS_OK
1212
from web3.types import Wei
1313

1414
logger = logging.getLogger(__name__)
@@ -30,12 +30,14 @@ def is_gas_price_ok(self, module_id: int) -> bool:
3030

3131
current_buffered_ether = self.w3.lido.lido.get_depositable_ether()
3232
if current_buffered_ether > variables.MAX_BUFFERED_ETHERS:
33-
return current_gas_fee <= variables.MAX_GAS_FEE
34-
35-
recommended_gas_fee = self._get_recommended_gas_fee()
36-
GAS_FEE.labels('recommended_fee', module_id).set(recommended_gas_fee)
37-
GAS_FEE.labels('max_fee', module_id).set(variables.MAX_GAS_FEE)
38-
return recommended_gas_fee >= current_gas_fee
33+
success = current_gas_fee <= variables.MAX_GAS_FEE
34+
else:
35+
recommended_gas_fee = self._get_recommended_gas_fee()
36+
GAS_FEE.labels('recommended_fee', module_id).set(recommended_gas_fee)
37+
GAS_FEE.labels('max_fee', module_id).set(variables.MAX_GAS_FEE)
38+
success = recommended_gas_fee >= current_gas_fee
39+
GAS_OK.labels(module_id).set(int(success))
40+
return success
3941

4042
def _get_pending_base_fee(self) -> Wei:
4143
base_fee_per_gas = self.w3.eth.get_block('pending')['baseFeePerGas']
@@ -44,6 +46,7 @@ def _get_pending_base_fee(self) -> Wei:
4446

4547
def calculate_deposit_recommendation(self, deposit_strategy: BaseDepositStrategy, module_id: int) -> bool:
4648
possible_keys = deposit_strategy.deposited_keys_amount(module_id)
49+
success = False
4750
if possible_keys < deposit_strategy.DEPOSITABLE_KEYS_THRESHOLD:
4851
logger.info(
4952
{
@@ -52,15 +55,15 @@ def calculate_deposit_recommendation(self, deposit_strategy: BaseDepositStrategy
5255
'threshold': deposit_strategy.DEPOSITABLE_KEYS_THRESHOLD,
5356
}
5457
)
55-
return False
56-
57-
recommended_max_gas = GasPriceCalculator._calculate_recommended_gas_based_on_deposit_amount(
58-
possible_keys,
59-
module_id,
60-
)
61-
base_fee_per_gas = self._get_pending_base_fee()
62-
success = recommended_max_gas >= base_fee_per_gas
63-
logger.info({'msg': 'Calculations deposit recommendations.', 'value': success})
58+
else:
59+
recommended_max_gas = GasPriceCalculator._calculate_recommended_gas_based_on_deposit_amount(
60+
possible_keys,
61+
module_id,
62+
)
63+
base_fee_per_gas = self._get_pending_base_fee()
64+
success = recommended_max_gas >= base_fee_per_gas
65+
logger.info({'msg': 'Calculations deposit recommendations.', 'value': success})
66+
DEPOSIT_AMOUNT_OK.labels(module_id).set(int(success))
6467
return success
6568

6669
@staticmethod

src/bots/depositor.py

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
from metrics.metrics import (
1515
ACCOUNT_BALANCE,
1616
CURRENT_QUORUM_SIZE,
17+
IS_DEPOSITABLE,
1718
MELLOW_VAULT_BALANCE,
1819
MODULE_TX_SEND,
20+
QUORUM,
1921
UNEXPECTED_EXCEPTIONS,
2022
)
2123
from metrics.transport_message_metrics import message_metrics_filter
@@ -33,8 +35,8 @@
3335

3436
def run_depositor(w3):
3537
logger.info({'msg': 'Initialize Depositor bot.'})
36-
gas_price_calculator = GasPriceCalculator(w3)
3738
sender = Sender(w3)
39+
gas_price_calculator = GasPriceCalculator(w3)
3840
mellow_deposit_strategy = MellowDepositStrategy(w3)
3941
base_deposit_strategy = BaseDepositStrategy(w3)
4042
depositor_bot = DepositorBot(w3, sender, gas_price_calculator, mellow_deposit_strategy, base_deposit_strategy)
@@ -66,8 +68,8 @@ def __init__(
6668
base_deposit_strategy: BaseDepositStrategy,
6769
):
6870
self.w3 = w3
69-
self._gas_price_calculator = gas_price_calcaulator
7071
self._sender = sender
72+
self._gas_price_calculator = gas_price_calcaulator
7173
self._mellow_strategy = mellow_deposit_strategy
7274
self._general_strategy = base_deposit_strategy
7375

@@ -137,23 +139,29 @@ def _is_mellow_depositable(
137139
{
138140
'msg': 'Mellow module check failed.',
139141
'contract_module': staking_module_contract.get_staking_module_id(),
140-
'tx_module': module_id
142+
'tx_module': module_id,
141143
}
142144
)
143145
return False
144146
balance = self.w3.lido.simple_dvt_staking_strategy.vault_balance()
145147
except Exception as e:
146148
logger.warning(
147149
{
148-
'msg': 'Failed to check if mellow depositable',
150+
'msg': 'Failed to check if mellow depositable.',
149151
'module_id': module_id,
150-
'err': repr(e)
152+
'err': repr(e),
151153
}
152154
)
153155
return False
154156
MELLOW_VAULT_BALANCE.labels(module_id).set(balance)
155157
if balance < variables.VAULT_DIRECT_DEPOSIT_THRESHOLD:
156-
logger.info({'msg': f'{balance} is less than VAULT_DIRECT_DEPOSIT_THRESHOLD while building mellow transaction.'})
158+
logger.info(
159+
{
160+
'msg': f'{balance} is less than VAULT_DIRECT_DEPOSIT_THRESHOLD while building mellow transaction.',
161+
'balance': balance,
162+
'threshold': variables.VAULT_DIRECT_DEPOSIT_THRESHOLD,
163+
}
164+
)
157165
return False
158166
logger.debug({'msg': 'Mellow module check succeeded.', 'tx_module': module_id})
159167
return True
@@ -186,22 +194,25 @@ def _deposit_to_module(self, module_id: int) -> bool:
186194

187195
if is_depositable and quorum and can_deposit and gas_is_ok and is_deposit_amount_ok:
188196
logger.info({'msg': 'Checks passed. Prepare deposit tx.', 'is_mellow': is_mellow})
189-
success = self.prepare_and_send_tx(quorum, is_mellow, self._flashbots_works)
197+
success = self.prepare_and_send_tx(module_id, quorum, is_mellow)
198+
if not success and is_mellow:
199+
success = self.prepare_and_send_tx(module_id, quorum, False)
190200
self._flashbots_works = not self._flashbots_works or success
191-
self._mellow_works = success
192201
return success
193202

194203
logger.info({'msg': 'Checks failed. Skip deposit.'})
195204
return False
196205

197206
def _select_strategy(self, module_id) -> tuple[BaseDepositStrategy, bool]:
198-
if self._mellow_works and self._is_mellow_depositable(module_id):
207+
if self._is_mellow_depositable(module_id):
199208
return self._mellow_strategy, True
200209
return self._general_strategy, False
201210

202211
def _check_module_status(self, module_id: int) -> bool:
203212
"""Returns True if module is ready for deposit"""
204-
return self.w3.lido.staking_router.is_staking_module_active(module_id)
213+
ready = self.w3.lido.staking_router.is_staking_module_active(module_id)
214+
IS_DEPOSITABLE.labels(module_id).set(int(ready))
215+
return ready
205216

206217
def _get_quorum(self, module_id: int) -> Optional[list[DepositMessage]]:
207218
"""Returns quorum messages or None is quorum is not ready"""
@@ -230,11 +241,13 @@ def _get_quorum(self, module_id: int) -> Optional[list[DepositMessage]]:
230241

231242
if quorum_size >= min_signs_to_deposit:
232243
CURRENT_QUORUM_SIZE.labels('current').set(quorum_size)
244+
QUORUM.labels(module_id).set(1)
233245
return list(unified_messages)
234246

235247
max_quorum_size = max(quorum_size, max_quorum_size)
236248

237249
CURRENT_QUORUM_SIZE.labels('current').set(max_quorum_size)
250+
QUORUM.labels(module_id).set(0)
238251

239252
def _get_message_actualize_filter(self) -> Callable[[DepositMessage], bool]:
240253
latest = self.w3.eth.get_block('latest')
@@ -275,13 +288,24 @@ def message_filter(message: DepositMessage) -> bool:
275288

276289
return message_filter
277290

278-
def prepare_and_send_tx(self, quorum: list[DepositMessage], is_mellow: bool, module_id: int) -> bool:
279-
success = self._sender.prepare_and_send(
280-
quorum,
281-
self._flashbots_works,
282-
is_mellow,
283-
)
291+
def prepare_and_send_tx(self, module_id: int, quorum: list[DepositMessage], is_mellow: bool) -> bool:
292+
if is_mellow:
293+
try:
294+
success = self._sender.prepare_and_send(
295+
quorum,
296+
is_mellow,
297+
self._flashbots_works,
298+
)
299+
except Exception as e:
300+
success = False
301+
logger.warning({'msg': 'Error while sending mellow transaction', 'err': repr(e)})
302+
else:
303+
success = self._sender.prepare_and_send(
304+
quorum,
305+
is_mellow,
306+
self._flashbots_works,
307+
)
284308
logger.info({'msg': f'Tx send. Result is {success}.'})
285309
label = 'success' if success else 'failure'
286-
MODULE_TX_SEND.labels(label, module_id).inc()
310+
MODULE_TX_SEND.labels(label, module_id, int(is_mellow)).inc()
287311
return success

src/metrics/metrics.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
MODULE_TX_SEND = Counter(
1313
'transactions',
1414
'Amount of send transaction from bot with per module distribution.',
15-
['status', 'module_id'],
15+
['status', 'module_id', 'is_mellow'],
1616
namespace=PROMETHEUS_PREFIX
1717
)
1818

@@ -55,7 +55,7 @@
5555
POSSIBLE_DEPOSITS_AMOUNT = Gauge(
5656
'possible_deposits_amount',
5757
'Possible deposits amount.',
58-
['module_id'],
58+
['module_id', 'is_mellow'],
5959
namespace=PROMETHEUS_PREFIX,
6060
)
6161

@@ -66,6 +66,41 @@
6666
namespace=PROMETHEUS_PREFIX,
6767
)
6868

69+
IS_DEPOSITABLE = Gauge(
70+
'is_depositable',
71+
'Represents is_depositable check.',
72+
['module_id'],
73+
namespace=PROMETHEUS_PREFIX,
74+
)
75+
76+
QUORUM = Gauge(
77+
'quorum',
78+
'Represents if quorum could be collected.',
79+
['module_id'],
80+
namespace=PROMETHEUS_PREFIX,
81+
)
82+
83+
CAN_DEPOSIT = Gauge(
84+
'can_deposit',
85+
'Represents can_deposit check.',
86+
['module_id'],
87+
namespace=PROMETHEUS_PREFIX,
88+
)
89+
90+
GAS_OK = Gauge(
91+
'is_gas_ok',
92+
'Represents is_gas_ok check.',
93+
['module_id'],
94+
namespace=PROMETHEUS_PREFIX,
95+
)
96+
97+
DEPOSIT_AMOUNT_OK = Gauge(
98+
'is_deposit_amount_ok',
99+
'Represents is_deposit_amount_ok check.',
100+
['module_id'],
101+
namespace=PROMETHEUS_PREFIX,
102+
)
103+
69104
ETH_RPC_REQUESTS_DURATION = Histogram('eth_rpc_requests_duration', 'Duration of requests to ETH1 RPC', namespace=PROMETHEUS_PREFIX)
70105

71106
ETH_RPC_REQUESTS = Counter(

tests/blockchain/deposit_strategy/test_base_deposit_strategy.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from unittest.mock import Mock
22

33
import pytest
4+
from web3 import Web3
45

56
MODULE_ID = 1
67

@@ -32,7 +33,11 @@ def test_deposited_keys_amount_mellow(mellow_deposit_strategy):
3233
mellow_deposit_strategy.w3.lido.staking_router.get_staking_module_max_deposits_count = Mock(return_value=possible_deposits)
3334

3435
assert mellow_deposit_strategy.deposited_keys_amount(MODULE_ID) == possible_deposits
35-
mellow_deposit_strategy.w3.lido.staking_router.get_staking_module_max_deposits_count.assert_called_once_with(
36+
mellow_deposit_strategy.w3.lido.staking_router.get_staking_module_max_deposits_count.assert_any_call(
3637
MODULE_ID,
3738
depositable_eth + vault_balance,
3839
)
40+
mellow_deposit_strategy.w3.lido.staking_router.get_staking_module_max_deposits_count.assert_any_call(
41+
MODULE_ID,
42+
Web3.to_wei(32 * possible_deposits, 'ether'),
43+
)

tests/blockchain/deposit_strategy/test_deposit_transaction_sender.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
from unittest.mock import Mock
22

33
import pytest
4+
from blockchain.deposit_strategy.deposit_transaction_sender import Sender
45
from transport.msg_types.deposit import DepositMessage
56

67
MODULE_ID = 1
78

89

910
@pytest.mark.unit
10-
def test_send_deposit_tx_not_mellow(deposit_transaction_sender):
11+
def test_send_deposit_tx_not_mellow(deposit_transaction_sender: Sender):
1112
deposit_transaction_sender._w3.transaction.check = Mock(return_value=False)
1213
messages = [DepositMessage(
1314
type='deposit',

0 commit comments

Comments
 (0)