From ff4b225496fa7bbf111d5721cf15273163ae0830 Mon Sep 17 00:00:00 2001 From: MrJeleika Date: Mon, 29 Sep 2025 11:49:34 +0300 Subject: [PATCH 1/2] midas adapter --- constants/midas.py | 18 +++++ constants/summary_columns.py | 2 + integrations/integration_ids.py | 3 + integrations/midas_integration.py | 105 ++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+) create mode 100644 constants/midas.py create mode 100644 integrations/midas_integration.py diff --git a/constants/midas.py b/constants/midas.py new file mode 100644 index 0000000..3ef45bd --- /dev/null +++ b/constants/midas.py @@ -0,0 +1,18 @@ +from web3 import Web3 + +from utils.web3_utils import w3 +import json + +PAGINATION_SIZE = 2000 + +MIDAS_MWILDUSD_ADDRESS = Web3.to_checksum_address("0x605A84861EE603e385b01B9048BEa6A86118DB0a") +MIDAS_MWILDUSD_START_BLOCK = 23441782 +ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" + +with open("abi/ERC20_abi.json") as f: + ERC20_ABI = json.load(f) + +MIDAS_MWILDUSD_CONTRACT = w3.eth.contract( + address=MIDAS_MWILDUSD_ADDRESS, + abi=ERC20_ABI, +) diff --git a/constants/summary_columns.py b/constants/summary_columns.py index 395ad99..3151fad 100644 --- a/constants/summary_columns.py +++ b/constants/summary_columns.py @@ -104,6 +104,8 @@ class SummaryColumn(Enum): SummaryColumnType.ETHENA_PTS, ) + MIDAS_MWILDUSD_PTS = ("midas_mwildusd_pts", SummaryColumnType.ETHENA_PTS) + THRUSTER_POOL_PTS = ("thruster_pool_pts", SummaryColumnType.ETHENA_PTS) def __init__(self, column_name: str, col_type: SummaryColumnType): diff --git a/integrations/integration_ids.py b/integrations/integration_ids.py index 2c4541f..94b5923 100644 --- a/integrations/integration_ids.py +++ b/integrations/integration_ids.py @@ -561,6 +561,9 @@ class IntegrationID(Enum): Token.USDE, ) + # Midas + MIDAS_MWILDUSD = ("midas_mwildusd", "Midas mWildUSD", Token.USDE) + def __init__(self, column_name: str, description: str, token: Token = Token.USDE): self.column_name = column_name self.description = description diff --git a/integrations/midas_integration.py b/integrations/midas_integration.py new file mode 100644 index 0000000..08db9ca --- /dev/null +++ b/integrations/midas_integration.py @@ -0,0 +1,105 @@ +from copy import deepcopy +import logging + +from typing import Dict, List, Optional + +from constants.midas import MIDAS_MWILDUSD_CONTRACT, MIDAS_MWILDUSD_START_BLOCK, PAGINATION_SIZE, ZERO_ADDRESS +from constants.summary_columns import SummaryColumn +from eth_typing import ChecksumAddress + +from constants.chains import Chain +from integrations.integration_ids import IntegrationID +from integrations.cached_balances_integration import CachedBalancesIntegration +from utils.web3_utils import fetch_events_logs_with_retry + + +class MidasIntegration(CachedBalancesIntegration): + def __init__( + self, + integration_id: IntegrationID, + start_block: int, + chain: Chain = Chain.ETHEREUM, + summary_cols: Optional[List[SummaryColumn]] = None, + reward_multiplier: int = 1, + ): + super().__init__( + integration_id, + start_block, + chain, + summary_cols, + reward_multiplier, + ) + + def get_block_balances( + self, cached_data: Dict[int, Dict[ChecksumAddress, float]], blocks: List[int] + ) -> Dict[int, Dict[ChecksumAddress, float]]: + logging.info("Getting block data for Midas") + new_block_data: Dict[int, Dict[ChecksumAddress, float]] = {} + if not blocks: + logging.error("No blocks provided to Midas get_block_balances") + return new_block_data + sorted_blocks = sorted(blocks) + cache_copy: Dict[int, Dict[ChecksumAddress, float]] = deepcopy(cached_data) + for block in sorted_blocks: + # find the closest prev block in the data + # list keys parsed as ints and in descending order + sorted_existing_blocks = sorted( + cache_copy, + reverse=True, + ) + # loop through the sorted blocks and find the closest previous block + prev_block = self.start_block + start = prev_block + bals = {} + for existing_block in sorted_existing_blocks: + if existing_block < block: + prev_block = existing_block + start = existing_block + 1 + bals = deepcopy(cache_copy[prev_block]) + break + # parse transfer events since and update bals + while start <= block: + to_block = min(start + PAGINATION_SIZE, block) + transfers = fetch_events_logs_with_retry( + "Token transfers Midas", + MIDAS_MWILDUSD_CONTRACT.events.Transfer(), + start, + to_block, + ) + for transfer in transfers: + if transfer["args"]["from"] != ZERO_ADDRESS: + continue + user = transfer["args"]["to"] + if user not in bals: + bals[user] = 0 + bals[user] += round(transfer["args"]["value"] / 10**18, 4) + start = to_block + 1 + new_block_data[block] = bals + cache_copy[block] = bals + return new_block_data + + +if __name__ == "__main__": + midas_integration = MidasIntegration( + integration_id=IntegrationID.MIDAS_MWILDUSD, + start_block=MIDAS_MWILDUSD_START_BLOCK, + summary_cols=[SummaryColumn.MIDAS_MWILDUSD_PTS], + reward_multiplier=20, + ) + + # Without cached data + without_cached_data_output = midas_integration.get_block_balances( + cached_data={}, blocks=[23441782,23441783] + ) + + print("=" * 120) + print("Run without cached data", without_cached_data_output) + print("=" * 120, "\n" * 5) + + # With cached data, using the previous output so there is no need + # to fetch the previous blocks again + with_cached_data_output = midas_integration.get_block_balances( + cached_data=without_cached_data_output, blocks=[23441782,23441783] + ) + print("Run with cached data", with_cached_data_output) + print("=" * 120) From db68c22c859a7ae7117cf890208622f0d79e718e Mon Sep 17 00:00:00 2001 From: MrJeleika Date: Mon, 29 Sep 2025 22:20:20 +0300 Subject: [PATCH 2/2] midas adapter track all transfers --- integrations/midas_integration.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/integrations/midas_integration.py b/integrations/midas_integration.py index 08db9ca..32a2bb3 100644 --- a/integrations/midas_integration.py +++ b/integrations/midas_integration.py @@ -67,12 +67,17 @@ def get_block_balances( to_block, ) for transfer in transfers: - if transfer["args"]["from"] != ZERO_ADDRESS: + userTo = transfer["args"]["to"] + if userTo not in bals: + bals[userTo] = 0 + bals[userTo] += round(transfer["args"]["value"] / 10**18, 4) + + userFrom = transfer["args"]["from"] + if userFrom == ZERO_ADDRESS: continue - user = transfer["args"]["to"] - if user not in bals: - bals[user] = 0 - bals[user] += round(transfer["args"]["value"] / 10**18, 4) + if userFrom not in bals: + bals[userFrom] = 0 + bals[userFrom] -= round(transfer["args"]["value"] / 10**18, 4) start = to_block + 1 new_block_data[block] = bals cache_copy[block] = bals @@ -89,7 +94,7 @@ def get_block_balances( # Without cached data without_cached_data_output = midas_integration.get_block_balances( - cached_data={}, blocks=[23441782,23441783] + cached_data={}, blocks=[23441782,23442447] ) print("=" * 120) @@ -99,7 +104,7 @@ def get_block_balances( # With cached data, using the previous output so there is no need # to fetch the previous blocks again with_cached_data_output = midas_integration.get_block_balances( - cached_data=without_cached_data_output, blocks=[23441782,23441783] + cached_data=without_cached_data_output, blocks=[23441782,23442447] ) print("Run with cached data", with_cached_data_output) print("=" * 120)