Skip to main content

eigen_client_elcontracts/
reader.rs

1use crate::error::ElContractsError;
2use alloy::{
3    primitives::{Address, FixedBytes, U256},
4    providers::Provider,
5};
6use eigen_common::{get_provider, SdkProvider};
7use eigen_utils::slashing::core::allocation_manager::AllocationManager::{self, OperatorSet};
8use eigen_utils::slashing::{
9    core::{
10        avs_directory::AVSDirectory,
11        delegation_manager::DelegationManager,
12        i_rewards_coordinator::{
13            IRewardsCoordinator::{self},
14            IRewardsCoordinatorTypes::{DistributionRoot, RewardsMerkleClaim},
15        },
16        i_strategy::IStrategy::{self, IStrategyInstance},
17        permission_controller::PermissionController,
18    },
19    middleware::ierc20::IERC20::{self, IERC20Instance},
20};
21#[derive(Debug, Clone)]
22pub struct ELChainReader {
23    allocation_manager: Option<Address>,
24    pub(crate) delegation_manager: Address,
25    avs_directory: Address,
26    permission_controller: Option<Address>,
27    rewards_coordinator: Address,
28    // TODO: we should make this private
29    pub provider: String,
30}
31
32impl ELChainReader {
33    /// Creates a new `ELChainReader` instance with the given parameters.
34    ///
35    /// # Arguments
36    ///
37    /// * `allocation_manager` - The address of the allocation manager contract.
38    /// * `delegation_manager` - The address of the delegation manager contract.
39    /// * `rewards_coordinator` - The address of the rewards coordinator contract.
40    /// * `avs_directory` - The address of the avs directory contract.
41    /// * `permission_controller` - The address of the permission controller contract.
42    /// * `provider` - The provider to use for the RPC client.
43    ///
44    /// # Returns
45    ///
46    /// A new `ELChainReader` instance.
47    pub fn new(
48        allocation_manager: Option<Address>,
49        delegation_manager: Address,
50        rewards_coordinator: Address,
51        avs_directory: Address,
52        permission_controller: Option<Address>,
53        provider: String,
54    ) -> Self {
55        ELChainReader {
56            allocation_manager,
57            delegation_manager,
58            rewards_coordinator,
59            avs_directory,
60            permission_controller,
61            provider,
62        }
63    }
64
65    /// Builds a new `ELChainReader` instance, getting the AllocationManager and PermissionController addresses
66    /// from the delegation manager.
67    ///
68    /// # Arguments
69    ///
70    /// * `delegation_manager` - The address of the delegation manager contract.
71    /// * `avs_directory` - The address of the avs directory contract.
72    /// * `rewards_coordinator` - The address of the rewards coordinator contract.
73    /// * `client` - The provider to use for the RPC client to call the contracts.
74    ///
75    /// # Returns
76    ///
77    /// A new `ELChainReader` instance.
78    ///
79    /// # Errors
80    pub async fn build(
81        delegation_manager: Address,
82        avs_directory: Address,
83        rewards_coordinator: Address,
84        client: &String,
85    ) -> Result<Self, ElContractsError> {
86        let provider = get_provider(client);
87
88        let contract_delegation_manager = DelegationManager::new(delegation_manager, provider);
89        let is_operator_set = contract_delegation_manager.allocationManager().call().await;
90        if is_operator_set.is_err() {
91            Ok(Self {
92                allocation_manager: None,
93                delegation_manager,
94                avs_directory,
95                permission_controller: None,
96                rewards_coordinator,
97                provider: client.to_string(),
98            })
99        } else {
100            let allocation_manager = contract_delegation_manager
101                .allocationManager()
102                .call()
103                .await
104                .map_err(ElContractsError::AlloyContractError)?;
105            let permission_controller = contract_delegation_manager
106                .permissionController()
107                .call()
108                .await
109                .map_err(ElContractsError::AlloyContractError)?;
110
111            Ok(Self {
112                avs_directory,
113                allocation_manager: Some(allocation_manager),
114                delegation_manager,
115                rewards_coordinator,
116                permission_controller: Some(permission_controller),
117                provider: client.to_string(),
118            })
119        }
120    }
121
122    /// Calculate the delegation approval digest hash
123    ///
124    /// # Arguments
125    ///
126    /// * `staker` - The staker's address
127    /// * `operator` - The operator's address
128    /// * `delegation_approver` - The delegation approver's address
129    /// * `approve_salt` - The approve salt
130    /// * `expiry` - The expiry
131    ///
132    /// # Returns
133    ///
134    /// * `FixedBytes<32>` - The delegation approval digest hash
135    ///
136    /// # Errors
137    ///
138    /// * `ElContractsError` - if the call to the contract fails
139    pub async fn calculate_delegation_approval_digest_hash(
140        &self,
141        staker: Address,
142        operator: Address,
143        delegation_approver: Address,
144        approve_salt: FixedBytes<32>,
145        expiry: U256,
146    ) -> Result<FixedBytes<32>, ElContractsError> {
147        let provider = get_provider(&self.provider);
148        let contract_delegation_manager = DelegationManager::new(self.delegation_manager, provider);
149        contract_delegation_manager
150            .calculateDelegationApprovalDigestHash(
151                staker,
152                operator,
153                delegation_approver,
154                approve_salt,
155                expiry,
156            )
157            .call()
158            .await
159            .map_err(ElContractsError::AlloyContractError)
160    }
161
162    /// Calculate the operator avs registration digest hash
163    ///
164    /// # Arguments
165    ///
166    /// * `operator` - The operator's address
167    /// * `avs` - The avs's address
168    /// * `salt` - The salt
169    /// * `expiry` - The expiry
170    ///
171    /// # Returns
172    ///
173    /// * `FixedBytes<32>` - The operator avs registration digest hash
174    ///
175    /// # Errors
176    ///
177    /// * `ElContractsError` - if the call to the contract fails
178    pub async fn calculate_operator_avs_registration_digest_hash(
179        &self,
180        operator: Address,
181        avs: Address,
182        salt: FixedBytes<32>,
183        expiry: U256,
184    ) -> Result<FixedBytes<32>, ElContractsError> {
185        let provider = get_provider(&self.provider);
186
187        let contract_avs_directory = AVSDirectory::new(self.avs_directory, provider);
188
189        contract_avs_directory
190            .calculateOperatorAVSRegistrationDigestHash(operator, avs, salt, expiry)
191            .call()
192            .await
193            .map_err(ElContractsError::AlloyContractError)
194    }
195
196    /// Get the length of the distribution roots.
197    ///
198    /// # Returns
199    ///
200    /// * `Result<U256, ElContractsError>` - The length of the distribution roots if the call is successful,
201    ///   otherwise an error.
202    ///
203    /// # Errors
204    ///
205    /// * `ElContractsError` - if the call to the contract fails.
206    pub async fn get_distribution_roots_length(&self) -> Result<U256, ElContractsError> {
207        let provider = get_provider(&self.provider);
208
209        let contract_rewards_coordinator =
210            IRewardsCoordinator::new(self.rewards_coordinator, &provider);
211
212        contract_rewards_coordinator
213            .getDistributionRootsLength()
214            .call()
215            .await
216            .map_err(ElContractsError::AlloyContractError)
217    }
218
219    /// Get the current rewards calculation end timestamp (the timestamp until which rewards have been calculated).
220    ///
221    /// # Returns
222    ///
223    /// * `Result<u32, ElContractsError>` - The current rewards calculation
224    ///   end timestamp if the call is successful.
225    ///
226    /// # Errors
227    ///
228    /// * `ElContractsError` - if the call to the contract fails.
229    pub async fn curr_rewards_calculation_end_timestamp(&self) -> Result<u32, ElContractsError> {
230        let provider = get_provider(&self.provider);
231
232        let contract_rewards_coordinator =
233            IRewardsCoordinator::new(self.rewards_coordinator, &provider);
234
235        contract_rewards_coordinator
236            .currRewardsCalculationEndTimestamp()
237            .call()
238            .await
239            .map_err(ElContractsError::AlloyContractError)
240    }
241
242    /// Get the latest claimable distribution root.
243    ///
244    /// # Returns
245    /// * `Result<DistributionRoot, ElContractsError>` - The latest claimable distribution root if the call is successful.
246    ///
247    /// # Errors
248    /// * `ElContractsError` - if the call to the contract fails.
249    pub async fn get_current_claimable_distribution_root(
250        &self,
251    ) -> Result<DistributionRoot, ElContractsError> {
252        let provider = get_provider(&self.provider);
253
254        let contract_rewards_coordinator =
255            IRewardsCoordinator::new(self.rewards_coordinator, &provider);
256
257        contract_rewards_coordinator
258            .getCurrentClaimableDistributionRoot()
259            .call()
260            .await
261            .map_err(ElContractsError::AlloyContractError)
262    }
263
264    /// Get the root index from a given hash.
265    ///
266    /// # Arguments
267    ///
268    /// * `hash` - The hash to get the root index from.
269    ///
270    /// # Returns
271    ///
272    /// * `Result<u32, ElContractsError>` - The root index if the
273    ///   call is successful.
274    ///
275    /// # Errors
276    ///
277    /// * `ElContractsError` - if the call to the contract fails.
278    pub async fn get_root_index_from_hash(
279        &self,
280        hash: FixedBytes<32>,
281    ) -> Result<u32, ElContractsError> {
282        let provider = get_provider(&self.provider);
283
284        let contract_rewards_coordinator =
285            IRewardsCoordinator::new(self.rewards_coordinator, &provider);
286
287        contract_rewards_coordinator
288            .getRootIndexFromHash(hash)
289            .call()
290            .await
291            .map_err(ElContractsError::AlloyContractError)
292    }
293
294    /// Get the cumulative claimed amount for a given earner address and token.
295    ///
296    /// # Arguments
297    ///
298    /// * `earner_address` - The address of the earner.
299    /// * `token` - The address of the token.
300    ///
301    /// # Returns
302    ///
303    /// * `Result<U256, ElContractsError>` - The cumulative claimed amount if the call is successful.
304    ///
305    /// # Errors
306    ///
307    /// * `ElContractsError` - if the call to the contract fails.
308    pub async fn get_cumulative_claimed(
309        &self,
310        earner_address: Address,
311        token: Address,
312    ) -> Result<U256, ElContractsError> {
313        let provider = get_provider(&self.provider);
314
315        let contract_rewards_coordinator =
316            IRewardsCoordinator::new(self.rewards_coordinator, &provider);
317
318        contract_rewards_coordinator
319            .cumulativeClaimed(earner_address, token)
320            .call()
321            .await
322            .map_err(ElContractsError::AlloyContractError)
323    }
324
325    /// Check if a claim would currently pass the validations in `process_claim`
326    ///
327    /// # Arguments
328    ///
329    /// * `claim` - The claim to check
330    ///
331    /// # Returns
332    ///
333    /// * `Result<bool, ElContractsError>` - True if the claim would pass the validations, false otherwise
334    ///
335    /// # Errors
336    ///
337    /// * `ElContractsError` - if the call to the contract fails. Also fails if no root has been submitted yet.
338    pub async fn check_claim(&self, claim: RewardsMerkleClaim) -> Result<bool, ElContractsError> {
339        let provider = get_provider(&self.provider);
340
341        let contract_rewards_coordinator =
342            IRewardsCoordinator::new(self.rewards_coordinator, &provider);
343
344        contract_rewards_coordinator
345            .checkClaim(claim)
346            .call()
347            .await
348            .map_err(ElContractsError::AlloyContractError)
349    }
350
351    /// Gets the split of a specific `operator` for a specific `avs`
352    ///
353    /// # Arguments
354    ///
355    /// * `operator` - The operator address
356    /// * `avs` - The AVS address
357    ///
358    /// # Returns
359    ///
360    /// * u16 - The split of the operator for the AVS, if the call is successful
361    ///
362    /// # Errors
363    ///
364    /// * `ElContractsError` - if the call to the contract fails.
365    pub async fn get_operator_avs_split(
366        &self,
367        operator: Address,
368        avs: Address,
369    ) -> Result<u16, ElContractsError> {
370        let provider = get_provider(&self.provider);
371
372        let rewards_coordinator = IRewardsCoordinator::new(self.rewards_coordinator, provider);
373
374        rewards_coordinator
375            .getOperatorAVSSplit(operator, avs)
376            .call()
377            .await
378            .map_err(ElContractsError::AlloyContractError)
379    }
380
381    /// Gets the split of a specific `operator` for Programmatic Incentives
382    ///
383    /// # Arguments
384    ///
385    /// * `operator` - The operator address
386    ///
387    /// # Returns
388    ///
389    /// * u16 - The split of the operator for PI, if the call is successful
390    ///
391    /// # Errors
392    ///
393    /// * `ElContractsError` - if the call to the contract fails.
394    pub async fn get_operator_pi_split(&self, operator: Address) -> Result<u16, ElContractsError> {
395        let provider = get_provider(&self.provider);
396
397        let rewards_coordinator = IRewardsCoordinator::new(self.rewards_coordinator, provider);
398
399        rewards_coordinator
400            .getOperatorPISplit(operator)
401            .call()
402            .await
403            .map_err(ElContractsError::AlloyContractError)
404    }
405
406    /// Gets the split for a specific `operator` for a given `OperatorSet`
407    ///
408    /// # Arguments
409    ///
410    /// * `operator` - The operator address
411    /// * `OperatorSet` - The operator set which consists of avs address and id.
412    ///
413    /// # Returns
414    ///
415    /// * u16 - The split for a specific `operator` for a given `OperatorSet`, if the call is successful
416    ///
417    /// # Errors
418    ///
419    /// * `ElContractsError` - if the call to the contract fails.
420    pub async fn get_operator_set_split(
421        &self,
422        operator: Address,
423        operator_set: eigen_utils::slashing::core::i_rewards_coordinator::IRewardsCoordinator::OperatorSet,
424    ) -> Result<u16, ElContractsError> {
425        let provider = get_provider(&self.provider);
426
427        let rewards_coordinator = IRewardsCoordinator::new(self.rewards_coordinator, provider);
428
429        rewards_coordinator
430            .getOperatorSetSplit(operator, operator_set)
431            .call()
432            .await
433            .map_err(ElContractsError::AlloyContractError)
434    }
435
436    /// Get the operator's shares in a strategy
437    ///
438    /// # Arguments
439    ///
440    /// * `operator_addr` - The operator's address
441    /// * `strategy_addr` - The strategy's address
442    ///
443    /// # Returns
444    ///
445    /// * `U256` - The operator's shares in the strategy
446    ///
447    /// # Errors
448    ///
449    /// * `ElContractsError` - if the call to the contract fails
450    pub async fn get_operator_shares_in_strategy(
451        &self,
452        operator_addr: Address,
453        strategy_addr: Address,
454    ) -> Result<U256, ElContractsError> {
455        let provider = get_provider(&self.provider);
456
457        let contract_delegation_manager = DelegationManager::new(self.delegation_manager, provider);
458
459        contract_delegation_manager
460            .operatorShares(operator_addr, strategy_addr)
461            .call()
462            .await
463            .map_err(ElContractsError::AlloyContractError)
464    }
465
466    /// Get strategy and underlying ERC-20 token
467    ///
468    /// # Arguments
469    ///
470    /// * `strategy_addr` - The strategy's address
471    ///
472    /// # Returns
473    ///
474    /// - the strategy contract,
475    /// - the erc20 bindings for the underlying token
476    /// - and the underlying token address
477    ///
478    /// # Errors
479    ///
480    /// * `ElContractsError` - if the call to the contract fails
481    pub async fn get_strategy_and_underlying_erc20_token(
482        &self,
483        strategy_addr: Address,
484    ) -> Result<
485        (
486            IStrategyInstance<SdkProvider>,
487            IERC20Instance<SdkProvider>,
488            Address,
489        ),
490        ElContractsError,
491    > {
492        let (contract_strategy, underlying_token) = self
493            .get_strategy_and_underlying_token(strategy_addr)
494            .await?;
495
496        let token_contract = IERC20::new(underlying_token, contract_strategy.provider().to_owned());
497
498        Ok((contract_strategy, token_contract, underlying_token))
499    }
500
501    /// Check if the operator is registered
502    ///
503    /// # Arguments
504    ///
505    /// * `operator` - The operator's address
506    ///
507    /// # Returns
508    ///
509    /// * `bool` - true if the operator is registered, false otherwise
510    ///
511    /// # Errors
512    ///
513    /// * `ElContractsError` - if the call to the contract fails
514    pub async fn is_operator_registered(
515        &self,
516        operator: Address,
517    ) -> Result<bool, ElContractsError> {
518        let provider = get_provider(&self.provider);
519
520        let contract_delegation_manager = DelegationManager::new(self.delegation_manager, provider);
521
522        contract_delegation_manager
523            .isOperator(operator)
524            .call()
525            .await
526            .map_err(ElContractsError::AlloyContractError)
527    }
528
529    /// Get the staker's shares in all of the strategies in which they have nonzero shares
530    /// # Arguments
531    /// * `staker_address` - The staker's address
532    /// * `block_number` - The block number
533    ///
534    /// # Returns
535    /// * `Vec<Address>` - An array of strategy addresses
536    /// * `Vec<U256>` - An array with the amount of shares the staker has in each strategy
537    ///
538    /// # Errors
539    /// * `ElContractsError` - if the call to the contract fails
540    pub async fn get_staker_shares(
541        &self,
542        staker_address: Address,
543    ) -> Result<(Vec<Address>, Vec<U256>), ElContractsError> {
544        let provider = get_provider(&self.provider);
545
546        let contract_delegation_manager = DelegationManager::new(self.delegation_manager, provider);
547
548        let deposited_shares = contract_delegation_manager
549            .getDepositedShares(staker_address)
550            .call()
551            .await
552            .map_err(ElContractsError::AlloyContractError)?;
553
554        let DelegationManager::getDepositedSharesReturn {
555            _0: addresses,
556            _1: shares,
557        } = deposited_shares;
558
559        Ok((addresses, shares))
560    }
561
562    /// Get the delegated operator
563    /// # Arguments
564    /// * `staker_address` - The staker's address
565    /// * `block_number` - The block number
566    ///
567    /// # Returns
568    /// * `Address` - The address of the operator to whom the staker has delegated their shares
569    ///
570    /// # Errors
571    /// * `ElContractsError` - if the call to the contract fails
572    pub async fn get_delegated_operator(
573        &self,
574        staker_address: Address,
575    ) -> Result<Address, ElContractsError> {
576        let provider = get_provider(&self.provider);
577
578        let contract_delegation_manager = DelegationManager::new(self.delegation_manager, provider);
579
580        contract_delegation_manager
581            .delegatedTo(staker_address)
582            .call()
583            .await
584            .map_err(ElContractsError::AlloyContractError)
585    }
586
587    /// # Returns the strategy contract and the underlying token address.
588    ///
589    /// # Arguments
590    ///
591    /// * `strategy_addr` - The strategy's address
592    ///
593    /// # Returns
594    ///
595    /// - the strategy contract address,
596    /// - and the underlying token address
597    ///
598    /// # Errors
599    ///
600    /// * `ElContractsError` - if the call to the contract fails
601    pub async fn get_strategy_and_underlying_token(
602        &self,
603        strategy_addr: Address,
604    ) -> Result<(IStrategyInstance<SdkProvider>, Address), ElContractsError> {
605        let provider = get_provider(&self.provider);
606
607        let contract_strategy = IStrategy::new(strategy_addr, provider);
608
609        let underlying_token = contract_strategy
610            .underlyingToken()
611            .call()
612            .await
613            .map_err(ElContractsError::AlloyContractError)?;
614
615        Ok((contract_strategy, underlying_token))
616    }
617
618    /// For a strategy, get the amount of magnitude not currently allocated to any operator set
619    /// # Arguments
620    /// * `operator_address` - The operator's address to query
621    /// * `strategy_address` - The strategy's address to get allocatable magnitude for
622    /// # Returns
623    /// * `u64` - The magnitude available to be allocated to an operator set
624    /// # Errors
625    /// * `ElContractsError` - if the call to the contract fails
626    pub async fn get_allocatable_magnitude(
627        &self,
628        operator_address: Address,
629        strategy_address: Address,
630    ) -> Result<u64, ElContractsError> {
631        let provider = get_provider(&self.provider);
632
633        let contract_allocation_manager = AllocationManager::new(
634            self.allocation_manager
635                .ok_or(ElContractsError::MissingParameter)?,
636            provider,
637        );
638
639        contract_allocation_manager
640            .getAllocatableMagnitude(operator_address, strategy_address)
641            .call()
642            .await
643            .map_err(ElContractsError::AlloyContractError)
644    }
645
646    /// Get the maximum magnitude an operator can allocate for the given strategies
647    /// # Arguments
648    /// * `operator_address` - The operator's address to query
649    /// * `strategy_addresses` - The strategy's addresses to get max magnitudes for
650    /// # Returns
651    /// * `Vec<u64>` - The maximum magnitudes for the strategies
652    /// # Errors
653    /// * `ElContractsError` - if the call to the contract fails
654    pub async fn get_max_magnitudes(
655        &self,
656        operator_address: Address,
657        strategy_addresses: Vec<Address>,
658    ) -> Result<Vec<u64>, ElContractsError> {
659        let provider = get_provider(&self.provider);
660
661        let contract_allocation_manager = AllocationManager::new(
662            self.allocation_manager
663                .ok_or(ElContractsError::MissingParameter)?,
664            provider,
665        );
666
667        contract_allocation_manager
668            .getMaxMagnitudes_1(operator_address, strategy_addresses)
669            .call()
670            .await
671            .map_err(ElContractsError::AlloyContractError)
672    }
673
674    /// Get the allocation info given a strategy and an operator. Returns the info for each operator set where an operator has allocation.
675    /// # Arguments
676    /// * `operator_address` - The operator's address to query
677    /// * `strategy_address` - The strategy's address to get allocation info for
678    /// # Returns
679    /// * `Vec<AllocationInfo>` - The allocation info for each operator set
680    /// # Errors
681    /// * `ElContractsError` - if the call to the contract fails
682    pub async fn get_allocation_info(
683        &self,
684        operator_address: Address,
685        strategy_address: Address,
686    ) -> Result<Vec<AllocationInfo>, ElContractsError> {
687        let provider = get_provider(&self.provider);
688
689        let contract_allocation_manager = AllocationManager::new(
690            self.allocation_manager
691                .ok_or(ElContractsError::MissingParameter)?,
692            provider,
693        );
694
695        let allocations = contract_allocation_manager
696            .getStrategyAllocations(operator_address, strategy_address)
697            .call()
698            .await
699            .map_err(ElContractsError::AlloyContractError)?;
700
701        let AllocationManager::getStrategyAllocationsReturn {
702            _0: operator_sets,
703            _1: allocation_info,
704        } = allocations;
705
706        let mut allocations_info = vec![];
707        for (i, operator_set) in operator_sets.iter().enumerate() {
708            allocations_info.push(AllocationInfo {
709                operator_set: operator_set.clone(),
710                current_magnitude: U256::from(allocation_info[i].currentMagnitude),
711                pending_diff: U256::from(allocation_info[i].pendingDiff),
712                effect_block: allocation_info[i].effectBlock,
713            });
714        }
715
716        Ok(allocations_info)
717    }
718
719    /// Get the shares that an operator owns in a set of strategies
720    /// # Arguments
721    /// * `operator_address` - The operator's address to get shares for
722    /// * `strategy_addresses` - The strategy's addresses to get shares for
723    /// # Returns
724    /// * `Vec<U256>` - The list of shares for each strategy
725    /// # Errors
726    /// * `ElContractsError` - if the call to the contract fails
727    pub async fn get_operator_shares(
728        &self,
729        operator_address: Address,
730        strategy_addresses: Vec<Address>,
731    ) -> Result<Vec<U256>, ElContractsError> {
732        let provider = get_provider(&self.provider);
733
734        let contract_delegation_manager = DelegationManager::new(self.delegation_manager, provider);
735
736        contract_delegation_manager
737            .getOperatorShares(operator_address, strategy_addresses)
738            .call()
739            .await
740            .map_err(ElContractsError::AlloyContractError)
741    }
742
743    /// Get the shares that a list of operators own in a set of strategies
744    /// # Arguments
745    /// * `operator_addresses` - The list of operators' addresses to get shares for
746    /// * `strategy_addresses` - The strategy's addresses to get shares for
747    /// # Returns
748    /// * `Vec<Vec<U256>>` - The list of shares for each operator
749    /// # Errors
750    /// * `ElContractsError` - if the call to the contract fails
751    pub async fn get_operators_shares(
752        &self,
753        operator_addresses: Vec<Address>,
754        strategy_addresses: Vec<Address>,
755    ) -> Result<Vec<Vec<U256>>, ElContractsError> {
756        let provider = get_provider(&self.provider);
757
758        let contract_delegation_manager = DelegationManager::new(self.delegation_manager, provider);
759
760        contract_delegation_manager
761            .getOperatorsShares(operator_addresses, strategy_addresses)
762            .call()
763            .await
764            .map_err(ElContractsError::AlloyContractError)
765    }
766
767    /// Get the number of operator sets that an operator is part of. Doesn't include M2 AVSs
768    /// # Arguments
769    /// * `operator_addr` - The operator's address to query
770    /// # Returns
771    /// * `U256` - The number of operator sets the operator is part of
772    /// # Errors
773    /// * `ElContractsError` - if the call to the contract fails
774    pub async fn get_num_operator_sets_for_operator(
775        &self,
776        operator_addr: Address,
777    ) -> Result<U256, ElContractsError> {
778        self.get_operator_sets_for_operator(operator_addr)
779            .await
780            .map(|operator_sets| U256::from(operator_sets.len() as u64))
781    }
782
783    /// Get the operator sets that an operator is part of. Doesn't include M2 AVSs
784    /// # Arguments
785    /// * `operator_addr` - The operator's address to query
786    /// # Returns
787    /// * `Vec<OperatorSet>` - The operator sets the operator is part of
788    /// # Errors
789    /// * `ElContractsError` - if the call to the contract fails
790    pub async fn get_operator_sets_for_operator(
791        &self,
792        operator_addr: Address,
793    ) -> Result<Vec<OperatorSet>, ElContractsError> {
794        let provider = get_provider(&self.provider);
795
796        let contract_allocation_manager = AllocationManager::new(
797            self.allocation_manager
798                .ok_or(ElContractsError::MissingParameter)?,
799            provider,
800        );
801
802        contract_allocation_manager
803            .getAllocatedSets(operator_addr)
804            .call()
805            .await
806            .map_err(ElContractsError::AlloyContractError)
807    }
808
809    /// Check if an operator is registered with a specific operator set
810    /// # Arguments
811    /// * `operator_address` - The operator's address to query
812    /// * `operator_set` - The operator set to check if the operator is registered with
813    /// # Returns
814    /// * `bool` - true if the operator is registered with the operator set, false otherwise
815    /// # Errors
816    /// * `ElContractsError` - if the call to the contract fails
817    pub async fn is_operator_registered_with_operator_set(
818        &self,
819        operator_address: Address,
820        operator_set: OperatorSet,
821    ) -> Result<bool, ElContractsError> {
822        let provider = get_provider(&self.provider);
823
824        let contract_allocation_manager = AllocationManager::new(
825            self.allocation_manager
826                .ok_or(ElContractsError::MissingParameter)?,
827            provider,
828        );
829        let registered_operator_sets = contract_allocation_manager
830            .getRegisteredSets(operator_address)
831            .call()
832            .await
833            .map_err(ElContractsError::AlloyContractError)?;
834
835        let is_registered = registered_operator_sets
836            .iter()
837            .any(|registered_operator_set| {
838                registered_operator_set.id == operator_set.id
839                    && registered_operator_set.avs == operator_set.avs
840            });
841        Ok(is_registered)
842    }
843
844    /// Get the operators in a specific operator set. Not supported for M2 AVSs
845    /// # Arguments
846    /// * `operator_set` - The operator set to query
847    /// # Returns
848    /// * `Vec<Address>` - The list of operator's addresses in the operator set
849    /// # Errors
850    /// * `ElContractsError` - if the call to the contract fails
851    pub async fn get_operators_for_operator_set(
852        &self,
853        operator_set: OperatorSet,
854    ) -> Result<Vec<Address>, ElContractsError> {
855        let provider = get_provider(&self.provider);
856
857        let contract_allocation_manager = AllocationManager::new(
858            self.allocation_manager
859                .ok_or(ElContractsError::MissingParameter)?,
860            provider,
861        );
862
863        contract_allocation_manager
864            .getMembers(operator_set)
865            .call()
866            .await
867            .map_err(ElContractsError::AlloyContractError)
868    }
869
870    /// Get the number of operators in a specific operator set. Not supported for M2 AVSs
871    /// # Arguments
872    /// * `operator_set` - The operator set to query
873    /// # Returns
874    /// * `U256` - The number of operators in the operator set
875    /// # Errors
876    /// * `ElContractsError` - if the call to the contract fails
877    pub async fn get_num_operators_for_operator_set(
878        &self,
879        operator_set: OperatorSet,
880    ) -> Result<U256, ElContractsError> {
881        let provider = get_provider(&self.provider);
882
883        let contract_allocation_manager = AllocationManager::new(
884            self.allocation_manager
885                .ok_or(ElContractsError::MissingParameter)?,
886            provider,
887        );
888
889        contract_allocation_manager
890            .getMemberCount(operator_set)
891            .call()
892            .await
893            .map_err(ElContractsError::AlloyContractError)
894    }
895
896    /// Get the strategies in a specific operator set. Not supported for M2 AVSs
897    /// # Arguments
898    /// * `operator_set` - The operator set to query
899    /// # Returns
900    /// * `Vec<Address>` - The list of strategy's addresses in the operator set
901    /// # Errors
902    pub async fn get_strategies_for_operator_set(
903        &self,
904        operator_set: OperatorSet,
905    ) -> Result<Vec<Address>, ElContractsError> {
906        let provider = get_provider(&self.provider);
907
908        let contract_allocation_manager = AllocationManager::new(
909            self.allocation_manager
910                .ok_or(ElContractsError::MissingParameter)?,
911            provider,
912        );
913
914        contract_allocation_manager
915            .getStrategiesInOperatorSet(operator_set)
916            .call()
917            .await
918            .map_err(ElContractsError::AlloyContractError)
919    }
920
921    /// Get the slashable shares for an operator.
922    /// # Arguments
923    /// * `operator_address` - The operator's address to query
924    /// * `operator_set` - The operator set to query
925    /// * `strategies` - The strategies to query
926    /// # Returns
927    /// * `Vec<U256>` - The amount of slashable shares for each strategy
928    /// # Errors
929    /// * `ElContractsError` - if the call to the contract fails
930    pub async fn get_slashable_shares(
931        &self,
932        operator_address: Address,
933        operator_set: OperatorSet,
934        strategies: Vec<Address>,
935    ) -> Result<Vec<U256>, ElContractsError> {
936        let provider = get_provider(&self.provider);
937        let current_block_number = provider.get_block_number().await.map_err(|e| {
938            ElContractsError::AlloyContractError(alloy::contract::Error::TransportError(e))
939        })?;
940
941        let contract_allocation_manager = AllocationManager::new(
942            self.allocation_manager
943                .ok_or(ElContractsError::MissingParameter)?,
944            provider,
945        );
946        let slashable_stake = contract_allocation_manager
947            .getMinimumSlashableStake(
948                operator_set,
949                vec![operator_address],
950                strategies.clone(),
951                current_block_number as u32,
952            )
953            .call()
954            .await
955            .map_err(ElContractsError::AlloyContractError)?;
956
957        let Some(slashable_operator_stake) = slashable_stake.first() else {
958            return Err(ElContractsError::NoSlashableSharesFound);
959        };
960
961        Ok(slashable_operator_stake.clone())
962    }
963
964    /// Get the minimum amount of shares that are slashable by the operator sets. Not supported for M2 AVSs.
965    /// # Arguments
966    /// * `operator_sets` - The operator sets to query
967    /// # Returns
968    /// * `Vec<OperatorSetStakes>` - The operator sets, their strategies, operators, and slashable stakes
969    /// # Errors
970    /// * `ElContractsError` - if the call to the contract fails
971    pub async fn get_slashable_shares_for_operator_sets(
972        &self,
973        operator_sets: Vec<OperatorSet>,
974    ) -> Result<Vec<OperatorSetStakes>, ElContractsError> {
975        let provider = get_provider(&self.provider);
976        let current_block_number = provider.get_block_number().await.map_err(|e| {
977            ElContractsError::AlloyContractError(alloy::contract::Error::TransportError(e))
978        })?;
979        self.get_slashable_shares_for_operator_sets_before(
980            operator_sets,
981            current_block_number as u32,
982        )
983        .await
984    }
985
986    /// Given a list of operator sets, for each one get:
987    /// - the operators,
988    /// - the strategies,
989    /// - the minimum amount of shares that are slashable before a given block.
990    ///   Not supported for M2 AVSs.
991    /// # Arguments
992    /// * `operator_sets` - The operator sets to query
993    /// * `future_block` - The block at which to get allocation information. It must be greater that the current block number.
994    /// # Returns
995    /// * `Vec<OperatorSetStakes>` - The operator sets, their strategies, operators, and slashable stakes
996    /// # Errors
997    /// * `ElContractsError` - if the call to the contract fails
998    pub async fn get_slashable_shares_for_operator_sets_before(
999        &self,
1000        operator_sets: Vec<OperatorSet>,
1001        future_block: u32,
1002    ) -> Result<Vec<OperatorSetStakes>, ElContractsError> {
1003        let provider = get_provider(&self.provider);
1004        let mut operator_set_stakes = vec![];
1005        let contract_allocation_manager = AllocationManager::new(
1006            self.allocation_manager
1007                .ok_or(ElContractsError::MissingParameter)?,
1008            provider,
1009        );
1010
1011        for operator_set in operator_sets {
1012            let operators = self
1013                .get_operators_for_operator_set(operator_set.clone())
1014                .await?;
1015            let strategies = self
1016                .get_strategies_for_operator_set(operator_set.clone())
1017                .await?;
1018
1019            let slashable_stakes = contract_allocation_manager
1020                .getMinimumSlashableStake(
1021                    operator_set.clone(),
1022                    operators.clone(),
1023                    strategies.clone(),
1024                    future_block,
1025                )
1026                .call()
1027                .await?;
1028            operator_set_stakes.push(OperatorSetStakes {
1029                operator_set,
1030                strategies,
1031                operators,
1032                slashable_stakes,
1033            });
1034        }
1035        Ok(operator_set_stakes)
1036    }
1037
1038    /// Get the allocation delay for an operator. Is the number of blocks between an operator allocating slashable magnitude and the magnitude becoming slashable.
1039    /// # Arguments
1040    /// * `operator_address` - The operator's address to query
1041    /// # Returns
1042    /// * `u32` - The allocation delay
1043    /// # Errors
1044    /// * `ElContractsError` - if the call to the contract fails
1045    /// * `AllocationDelayNotSet` - if the allocation delay is not set
1046    pub async fn get_allocation_delay(
1047        &self,
1048        operator_address: Address,
1049    ) -> Result<u32, ElContractsError> {
1050        let provider = get_provider(&self.provider);
1051
1052        let contract_allocation_manager = AllocationManager::new(
1053            self.allocation_manager
1054                .ok_or(ElContractsError::MissingParameter)?,
1055            provider,
1056        );
1057
1058        let allocation_delay = contract_allocation_manager
1059            .getAllocationDelay(operator_address)
1060            .call()
1061            .await
1062            .map_err(ElContractsError::AlloyContractError)?;
1063
1064        let AllocationManager::getAllocationDelayReturn {
1065            _0: is_set,
1066            _1: delay,
1067        } = allocation_delay;
1068
1069        if !is_set {
1070            return Err(ElContractsError::AllocationDelayNotSet);
1071        }
1072
1073        Ok(delay)
1074    }
1075
1076    /// Get the operator sets that the operator is registered for
1077    /// # Arguments
1078    /// * `operator_address` - The operator's address to query
1079    /// # Returns
1080    /// * `Vec<OperatorSet>` - The operator sets the operator is registered for
1081    /// # Errors
1082    /// * `ElContractsError` - if the call to the contract fails
1083    pub async fn get_registered_sets(
1084        &self,
1085        operator_address: Address,
1086    ) -> Result<Vec<OperatorSet>, ElContractsError> {
1087        let provider = get_provider(&self.provider);
1088
1089        let contract_allocation_manager = AllocationManager::new(
1090            self.allocation_manager
1091                .ok_or(ElContractsError::MissingParameter)?,
1092            provider,
1093        );
1094
1095        contract_allocation_manager
1096            .getRegisteredSets(operator_address)
1097            .call()
1098            .await
1099            .map_err(ElContractsError::AlloyContractError)
1100    }
1101
1102    /// Check if the given caller has permissions to call the function
1103    ///
1104    /// # Arguments
1105    ///
1106    /// * `account_address` - The account address to check
1107    /// * `appointee_address` - The caller address to check permissions for
1108    /// * `target` - The target address to check permissions for
1109    /// * `selector` - The selector of the function to check permissions for
1110    ///
1111    /// # Returns
1112    ///
1113    /// * `bool` - true if the account has permissions to call the function, false otherwise
1114    ///
1115    /// # Errors
1116    ///
1117    /// * `ElContractsError` - if the call to the contract fails
1118    pub async fn can_call(
1119        &self,
1120        account_address: Address,
1121        appointee_address: Address,
1122        target: Address,
1123        selector: FixedBytes<4>,
1124    ) -> Result<bool, ElContractsError> {
1125        let provider = get_provider(&self.provider);
1126
1127        let contract_permission_controller =
1128            PermissionController::new(self.permission_controller.unwrap(), provider);
1129
1130        contract_permission_controller
1131            .canCall(account_address, appointee_address, target, selector)
1132            .call()
1133            .await
1134            .map_err(ElContractsError::AlloyContractError)
1135    }
1136
1137    /// Get the list of appointees for a given account and function
1138    /// # Arguments
1139    /// * `account_address` - The account address to get appointees for
1140    /// * `target` - The target address to get appointees for
1141    /// * `selector` - The selector of the function to get appointees for
1142    /// # Returns
1143    /// * `Vec<Address>` - The list of appointees
1144    /// # Errors
1145    /// * `ElContractsError` - if the call to the contract fails
1146    pub async fn list_appointees(
1147        &self,
1148        account_address: Address,
1149        target: Address,
1150        selector: FixedBytes<4>,
1151    ) -> Result<Vec<Address>, ElContractsError> {
1152        let provider = get_provider(&self.provider);
1153
1154        let contract_permission_controller =
1155            PermissionController::new(self.permission_controller.unwrap(), provider);
1156
1157        contract_permission_controller
1158            .getAppointees(account_address, target, selector)
1159            .call()
1160            .await
1161            .map_err(ElContractsError::AlloyContractError)
1162    }
1163
1164    /// Get the list of permissions of an appointee for a given account
1165    /// # Arguments
1166    /// * `account_address` - The account address to get appointee permissions for
1167    /// * `appointee_address` - The appointee address to get permissions
1168    /// # Returns
1169    /// * `Vec<Address>` - The list of targets
1170    /// * `Vec<FixedBytes<4>>` - The list of selectors
1171    /// # Errors
1172    /// * `ElContractsError` - if the call to the contract fails
1173    pub async fn list_appointee_permissions(
1174        &self,
1175        account_address: Address,
1176        appointee_address: Address,
1177    ) -> Result<(Vec<Address>, Vec<FixedBytes<4>>), ElContractsError> {
1178        let provider = get_provider(&self.provider);
1179
1180        let contract_permission_controller =
1181            PermissionController::new(self.permission_controller.unwrap(), provider);
1182
1183        let appointee_permissions = contract_permission_controller
1184            .getAppointeePermissions(account_address, appointee_address)
1185            .call()
1186            .await
1187            .map_err(ElContractsError::AlloyContractError)?;
1188
1189        let PermissionController::getAppointeePermissionsReturn {
1190            _0: targets,
1191            _1: selectors,
1192        } = appointee_permissions;
1193
1194        Ok((targets, selectors))
1195    }
1196
1197    /// Get the list of pending admins of a given account
1198    /// # Arguments
1199    /// * `account_address` - The account address to get pending admins of
1200    /// # Returns
1201    /// * `Vec<Address>` - The list of pending admins
1202    /// # Errors
1203    /// * `ElContractsError` - if the call to the contract fails
1204    pub async fn list_pending_admins(
1205        &self,
1206        account_address: Address,
1207    ) -> Result<Vec<Address>, ElContractsError> {
1208        let provider = get_provider(&self.provider);
1209
1210        let contract_permission_controller =
1211            PermissionController::new(self.permission_controller.unwrap(), provider);
1212
1213        contract_permission_controller
1214            .getPendingAdmins(account_address)
1215            .call()
1216            .await
1217            .map_err(ElContractsError::AlloyContractError)
1218    }
1219
1220    /// Get the list of admins of a given account
1221    /// # Arguments
1222    /// * `account_address` - The account address
1223    /// # Returns
1224    /// * `Vec<Address>` - The list of admins
1225    /// # Errors
1226    /// * `ElContractsError` - if the call to the contract fails
1227    pub async fn list_admins(
1228        &self,
1229        account_address: Address,
1230    ) -> Result<Vec<Address>, ElContractsError> {
1231        let provider = get_provider(&self.provider);
1232
1233        let contract_permission_controller =
1234            PermissionController::new(self.permission_controller.unwrap(), provider);
1235
1236        contract_permission_controller
1237            .getAdmins(account_address)
1238            .call()
1239            .await
1240            .map_err(ElContractsError::AlloyContractError)
1241    }
1242
1243    /// Check if an address is a pending admin of another account
1244    /// # Arguments
1245    /// * `account_address` - The account address
1246    /// * `pending_admin_address` - The pending admin address to check
1247    /// # Returns
1248    /// * `bool` - true if the pending_admin_address is a pending admin, false otherwise
1249    /// # Errors
1250    /// * `ElContractsError` - if the call to the contract fails
1251    pub async fn is_pending_admin(
1252        &self,
1253        account_address: Address,
1254        pending_admin_address: Address,
1255    ) -> Result<bool, ElContractsError> {
1256        let provider = get_provider(&self.provider);
1257
1258        let contract_permission_controller =
1259            PermissionController::new(self.permission_controller.unwrap(), provider);
1260
1261        contract_permission_controller
1262            .isPendingAdmin(account_address, pending_admin_address)
1263            .call()
1264            .await
1265            .map_err(ElContractsError::AlloyContractError)
1266    }
1267
1268    /// Check if an address is an admin of another account
1269    /// # Arguments
1270    /// * `account_address` - The account address
1271    /// * `admin_address` - The admin address to check
1272    /// # Returns
1273    /// * `bool` - true if the admin_address is an admin, false otherwise
1274    /// # Errors
1275    /// * `ElContractsError` - if the call to the contract fails
1276    pub async fn is_admin(
1277        &self,
1278        account_address: Address,
1279        admin_address: Address,
1280    ) -> Result<bool, ElContractsError> {
1281        let provider = get_provider(&self.provider);
1282
1283        let contract_permission_controller =
1284            PermissionController::new(self.permission_controller.unwrap(), provider);
1285
1286        contract_permission_controller
1287            .isAdmin(account_address, admin_address)
1288            .call()
1289            .await
1290            .map_err(ElContractsError::AlloyContractError)
1291    }
1292
1293    /// Checks if an operator is slashable by an operator set.
1294    /// # Arguments
1295    /// * `operator_address` - The operator to check slashability for
1296    /// * `operator_set` - The operator set to check slashability for
1297    /// # Returns
1298    /// * [`bool`] - true if the operator is registered or their slashableUntil block has not passed.
1299    ///   This is because even when operators are deregistered, they still remain slashable for a period of time.
1300    /// # Errors
1301    /// * [`ElContractsError`] - if the call to the contract fails
1302    pub async fn is_operator_slashable(
1303        &self,
1304        operator_address: Address,
1305        operator_set: OperatorSet,
1306    ) -> Result<bool, ElContractsError> {
1307        let provider = get_provider(&self.provider);
1308
1309        let contract_allocation_manager =
1310            AllocationManager::new(self.allocation_manager.unwrap(), provider);
1311
1312        contract_allocation_manager
1313            .isOperatorSlashable(operator_address, operator_set)
1314            .call()
1315            .await
1316            .map_err(ElContractsError::AlloyContractError)
1317    }
1318
1319    /// Returns the current allocated stake, irrespective of the operator's slashable status for the [`OperatorSet`].
1320    /// # Arguments
1321    /// * `operators` - The operators to query
1322    /// * `operator_set` - The operator set to query
1323    /// * `strategies` - The strategies to query
1324    /// # Returns
1325    /// * [`Vec<Vec<U256>>`] - Current Allocated Stake
1326    /// # Errors
1327    /// * [`ElContractsError`] - if the call to the contract fails
1328    pub async fn get_allocated_stake(
1329        &self,
1330        operator_set: OperatorSet,
1331        operators: Vec<Address>,
1332        strategies: Vec<Address>,
1333    ) -> Result<Vec<Vec<U256>>, ElContractsError> {
1334        let provider = get_provider(&self.provider);
1335
1336        let contract_allocation_manager =
1337            AllocationManager::new(self.allocation_manager.unwrap(), provider);
1338
1339        contract_allocation_manager
1340            .getAllocatedStake(operator_set, operators, strategies)
1341            .call()
1342            .await
1343            .map_err(ElContractsError::AlloyContractError)
1344    }
1345
1346    /// For a strategy, get the amount of magnitude that is allocated across one or more operator sets
1347    /// # Arguments
1348    /// * `operator` - The operator to query
1349    /// * `strategy_address` - The strategy to get allocatable magnitude for
1350    /// # Returns
1351    /// [`u64`] - currently allocated magnitude
1352    pub async fn get_encumbered_magnitude(
1353        &self,
1354        operator: Address,
1355        strategy_address: Address,
1356    ) -> Result<u64, ElContractsError> {
1357        let provider = get_provider(&self.provider);
1358
1359        let contract_allocation_manager =
1360            AllocationManager::new(self.allocation_manager.unwrap(), provider);
1361
1362        contract_allocation_manager
1363            .getEncumberedMagnitude(operator, strategy_address)
1364            .call()
1365            .await
1366            .map_err(ElContractsError::AlloyContractError)
1367    }
1368}
1369
1370// TODO: move to types.rs?
1371
1372#[derive(Clone)]
1373pub struct OperatorSetStakes {
1374    pub operator_set: OperatorSet,
1375    pub strategies: Vec<Address>,
1376    pub operators: Vec<Address>,
1377    pub slashable_stakes: Vec<Vec<U256>>,
1378}
1379
1380#[derive(Clone)]
1381pub struct AllocationInfo {
1382    pub current_magnitude: U256,
1383    pub pending_diff: U256,
1384    pub effect_block: u32,
1385    pub operator_set: OperatorSet,
1386}
1387
1388#[cfg(test)]
1389mod tests {
1390    use super::*;
1391    use alloy::eips::eip1898::BlockNumberOrTag::Number;
1392    use alloy::primitives::{address, keccak256, Address, FixedBytes, U256};
1393    use alloy::providers::Provider;
1394    use eigen_testing_utils::anvil_constants::get_erc20_mock_strategy;
1395    use eigen_testing_utils::{
1396        anvil::start_anvil_container,
1397        anvil_constants::{get_avs_directory_address, get_delegation_manager_address},
1398        chain_clients::{build_el_chain_reader, new_test_claim, OPERATOR_ADDRESS},
1399    };
1400    use eigen_utils::slashing::core::{
1401        avs_directory::AVSDirectory, delegation_manager::DelegationManager,
1402    };
1403
1404    #[tokio::test]
1405    async fn test_calculate_delegation_approval_digest_hash() {
1406        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1407        let provider = get_provider(&http_endpoint);
1408        let el_chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1409        let operator: Address = address!("5eb15C0992734B5e77c888D713b4FC67b3D679A2");
1410
1411        let staker = operator;
1412
1413        let delegation_approver = Address::ZERO;
1414
1415        let approve_salt: FixedBytes<32> = FixedBytes::from([0x02; 32]);
1416        let current_block_number = provider.get_block_number().await.unwrap();
1417        let block_info = provider
1418            .get_block_by_number(Number(current_block_number))
1419            .await
1420            .unwrap();
1421
1422        let block = block_info.unwrap();
1423        let timestamp = block.header.timestamp;
1424        let expiry = U256::from::<u64>(timestamp + 100);
1425        let calculate_digest_hash = el_chain_reader
1426            .calculate_delegation_approval_digest_hash(
1427                staker,
1428                operator,
1429                delegation_approver,
1430                approve_salt,
1431                expiry,
1432            )
1433            .await
1434            .unwrap();
1435
1436        // Directly calling the function through bindings to compare with the sdk .
1437        let delegation_manager_address = get_delegation_manager_address(http_endpoint).await;
1438        let delegation_manager_contract =
1439            DelegationManager::new(delegation_manager_address, provider);
1440
1441        let hash = delegation_manager_contract
1442            .calculateDelegationApprovalDigestHash(
1443                staker,
1444                operator,
1445                delegation_approver,
1446                approve_salt,
1447                expiry,
1448            )
1449            .call()
1450            .await
1451            .unwrap();
1452        assert_eq!(hash, calculate_digest_hash);
1453    }
1454
1455    #[tokio::test]
1456    async fn test_calculate_operator_avs_registration_digest_hash() {
1457        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1458        let provider = get_provider(&http_endpoint);
1459        let el_chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1460        let operator: Address = address!("5eb15C0992734B5e77c888D713b4FC67b3D679A2");
1461        let avs = Address::from_slice(&keccak256("avs ")[0..20]);
1462        let salt: FixedBytes<32> = FixedBytes::from([0x02; 32]);
1463        let current_block_number = provider.get_block_number().await.unwrap();
1464        let block_info = provider
1465            .get_block_by_number(Number(current_block_number))
1466            .await
1467            .unwrap();
1468        let block = block_info.unwrap();
1469
1470        let timestamp = block.header.timestamp;
1471        let expiry = U256::from::<u64>(timestamp + 100);
1472        let operator_hash = el_chain_reader
1473            .calculate_operator_avs_registration_digest_hash(operator, avs, salt, expiry)
1474            .await
1475            .unwrap();
1476
1477        // Using bindings directly to compare with sdk's output
1478        let avs_directory_address = get_avs_directory_address(http_endpoint.clone()).await;
1479        let avs_registry_contract = AVSDirectory::new(avs_directory_address, provider.clone());
1480        let operator_hash_from_bindings = avs_registry_contract
1481            .calculateOperatorAVSRegistrationDigestHash(operator, avs, salt, expiry)
1482            .call()
1483            .await
1484            .unwrap();
1485
1486        assert_eq!(operator_hash_from_bindings, operator_hash);
1487    }
1488
1489    #[tokio::test]
1490    async fn test_get_distribution_roots_length() {
1491        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1492        let el_chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1493
1494        let distribution_roots_length_ret = el_chain_reader
1495            .get_distribution_roots_length()
1496            .await
1497            .unwrap();
1498
1499        assert_eq!(distribution_roots_length_ret, U256::from(0));
1500
1501        _ = new_test_claim(&http_endpoint).await;
1502
1503        let distribution_roots_length_ret = el_chain_reader
1504            .get_distribution_roots_length()
1505            .await
1506            .unwrap();
1507
1508        assert_eq!(distribution_roots_length_ret, U256::from(1));
1509    }
1510
1511    #[tokio::test]
1512    async fn test_curr_rewards_calculation_end_timestamp() {
1513        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1514        let el_chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1515
1516        let end_timestamp = el_chain_reader
1517            .curr_rewards_calculation_end_timestamp()
1518            .await
1519            .unwrap();
1520
1521        assert_eq!(end_timestamp, 0);
1522
1523        _ = new_test_claim(&http_endpoint).await;
1524
1525        let end_timestamp = el_chain_reader
1526            .curr_rewards_calculation_end_timestamp()
1527            .await
1528            .unwrap();
1529
1530        assert_eq!(end_timestamp, 1);
1531    }
1532
1533    #[tokio::test]
1534    async fn test_get_current_claimable_distribution_root() {
1535        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1536        let el_chain_reader = build_el_chain_reader(http_endpoint.to_string()).await;
1537
1538        let distribution_root = el_chain_reader
1539            .get_current_claimable_distribution_root()
1540            .await
1541            .unwrap();
1542        // The root starts being zero
1543        assert_eq!(distribution_root.root, FixedBytes::ZERO);
1544
1545        let (root, _) = new_test_claim(&http_endpoint).await;
1546
1547        let distribution_root = el_chain_reader
1548            .get_current_claimable_distribution_root()
1549            .await
1550            .unwrap();
1551
1552        assert_eq!(distribution_root.root, root);
1553    }
1554
1555    #[tokio::test]
1556    async fn test_get_root_index_from_hash() {
1557        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1558        let el_chain_reader = build_el_chain_reader(http_endpoint.to_string()).await;
1559        let (root, _) = new_test_claim(&http_endpoint).await;
1560
1561        let index = el_chain_reader
1562            .get_root_index_from_hash(root)
1563            .await
1564            .unwrap();
1565
1566        assert_eq!(index, 0);
1567    }
1568
1569    #[tokio::test]
1570    async fn test_get_cumulative_claimed() {
1571        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1572        let el_chain_reader = build_el_chain_reader(http_endpoint.to_string()).await;
1573
1574        let earner_address = address!("F2288D736d27C1584Ebf7be5f52f9E4d47251AeE");
1575        let (_, _, token_address) = el_chain_reader
1576            .get_strategy_and_underlying_erc20_token(
1577                get_erc20_mock_strategy(http_endpoint.clone()).await,
1578            )
1579            .await
1580            .unwrap();
1581
1582        let cumulative_claimed_ret = el_chain_reader
1583            .get_cumulative_claimed(earner_address, token_address)
1584            .await
1585            .unwrap();
1586
1587        // No claims so cumulative claimed should be zero
1588        assert_eq!(cumulative_claimed_ret, U256::from(0));
1589    }
1590
1591    #[tokio::test]
1592    async fn test_check_claim() {
1593        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1594        let el_chain_reader = build_el_chain_reader(http_endpoint.to_string()).await;
1595        let (_, claim) = new_test_claim(&http_endpoint).await;
1596
1597        let valid_claim = el_chain_reader.check_claim(claim.clone()).await.unwrap();
1598        assert!(valid_claim);
1599    }
1600
1601    #[tokio::test]
1602    async fn test_is_operator_registered() {
1603        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1604        let chain_reader = build_el_chain_reader(http_endpoint).await;
1605
1606        let is_registered = chain_reader
1607            .is_operator_registered(OPERATOR_ADDRESS)
1608            .await
1609            .unwrap();
1610
1611        assert!(is_registered);
1612    }
1613
1614    #[tokio::test]
1615    async fn test_get_staker_shares() {
1616        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1617        let chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1618
1619        let (strategies, shares) = chain_reader
1620            .get_staker_shares(OPERATOR_ADDRESS)
1621            .await
1622            .unwrap();
1623
1624        let expected_strategies: Vec<Address> = vec![get_erc20_mock_strategy(http_endpoint).await];
1625
1626        assert!(strategies.len() == shares.len());
1627        assert_eq!(strategies, expected_strategies);
1628    }
1629
1630    #[tokio::test]
1631    async fn test_get_delegated_operator() {
1632        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1633        let chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1634
1635        let operator_addr = chain_reader
1636            .get_delegated_operator(OPERATOR_ADDRESS)
1637            .await
1638            .unwrap();
1639
1640        assert_eq!(operator_addr, OPERATOR_ADDRESS); // operator is delegated to himself
1641    }
1642
1643    #[tokio::test]
1644    async fn test_get_strategy_and_underlying_token() {
1645        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1646        let strategy_addr = get_erc20_mock_strategy(http_endpoint.clone()).await;
1647        let chain_reader = build_el_chain_reader(http_endpoint).await;
1648
1649        let (strategy_contract_addr, underlying_token_addr) = chain_reader
1650            .get_strategy_and_underlying_token(strategy_addr)
1651            .await
1652            .unwrap();
1653
1654        let underlying_token_addr_str = underlying_token_addr.to_string();
1655        assert_eq!(
1656            underlying_token_addr_str,
1657            "0x36C02dA8a0983159322a80FFE9F24b1acfF8B570"
1658        );
1659
1660        let strategy_contract_addr_str = strategy_contract_addr.address().to_string();
1661        assert_eq!(
1662            strategy_contract_addr_str,
1663            "0xeC4cFde48EAdca2bC63E94BB437BbeAcE1371bF3"
1664        );
1665    }
1666
1667    #[tokio::test]
1668    async fn test_get_allocatable_magnitude_and_max_magnitude() {
1669        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1670        let strategy_addr = get_erc20_mock_strategy(http_endpoint.clone()).await;
1671        let chain_reader = build_el_chain_reader(http_endpoint).await;
1672
1673        let allocatable_magnitude = chain_reader
1674            .get_allocatable_magnitude(OPERATOR_ADDRESS, strategy_addr)
1675            .await
1676            .unwrap();
1677
1678        assert!(allocatable_magnitude > 0);
1679
1680        // Since the operator has no encumbered magnitude, the max magnitude should be the same as the allocatable magnitude
1681        let max_magnitude = chain_reader
1682            .get_max_magnitudes(OPERATOR_ADDRESS, vec![strategy_addr])
1683            .await
1684            .unwrap()[0];
1685
1686        assert_eq!(allocatable_magnitude, max_magnitude);
1687    }
1688
1689    #[tokio::test]
1690    async fn test_get_allocation_info() {
1691        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1692        let strategy_addr = get_erc20_mock_strategy(http_endpoint.clone()).await;
1693        let chain_reader = build_el_chain_reader(http_endpoint).await;
1694
1695        let allocations_info = chain_reader
1696            .get_allocation_info(OPERATOR_ADDRESS, strategy_addr)
1697            .await
1698            .unwrap();
1699
1700        assert!(allocations_info.is_empty());
1701    }
1702
1703    #[tokio::test]
1704    async fn test_get_operator_shares() {
1705        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1706        let strategy_addr = get_erc20_mock_strategy(http_endpoint.clone()).await;
1707        let chain_reader = build_el_chain_reader(http_endpoint).await;
1708
1709        let operator_shares = chain_reader
1710            .get_operator_shares(OPERATOR_ADDRESS, vec![strategy_addr])
1711            .await
1712            .unwrap();
1713
1714        assert_eq!(operator_shares.len(), 1);
1715        assert_eq!(operator_shares[0], U256::from(10e18));
1716    }
1717
1718    #[tokio::test]
1719    async fn test_get_operators_shares() {
1720        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1721        let strategy_addr = get_erc20_mock_strategy(http_endpoint.clone()).await;
1722        let chain_reader = build_el_chain_reader(http_endpoint).await;
1723
1724        let operator_shares = chain_reader
1725            .get_operators_shares(vec![OPERATOR_ADDRESS], vec![strategy_addr])
1726            .await
1727            .unwrap();
1728
1729        assert_eq!(operator_shares.len(), 1);
1730        assert_eq!(operator_shares[0].len(), 1);
1731        assert_eq!(operator_shares[0][0], U256::from(10e18));
1732    }
1733
1734    #[tokio::test]
1735    async fn test_get_num_operator_sets_for_operator() {
1736        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1737        let chain_reader = build_el_chain_reader(http_endpoint).await;
1738
1739        let num_operator_sets = chain_reader
1740            .get_num_operator_sets_for_operator(OPERATOR_ADDRESS)
1741            .await
1742            .unwrap();
1743
1744        assert_eq!(num_operator_sets, U256::from(0));
1745    }
1746
1747    #[tokio::test]
1748    async fn test_get_operator_sets_for_operator() {
1749        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1750        let chain_reader = build_el_chain_reader(http_endpoint).await;
1751
1752        let operator_sets = chain_reader
1753            .get_operator_sets_for_operator(OPERATOR_ADDRESS)
1754            .await
1755            .unwrap();
1756
1757        assert_eq!(operator_sets.len(), 0);
1758    }
1759
1760    #[tokio::test]
1761    async fn test_is_operator_registered_with_operator_set() {
1762        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1763        let chain_reader = build_el_chain_reader(http_endpoint).await;
1764
1765        let operator_set = OperatorSet {
1766            id: 1,
1767            avs: Address::ZERO,
1768        };
1769
1770        let is_registered = chain_reader
1771            .is_operator_registered_with_operator_set(OPERATOR_ADDRESS, operator_set)
1772            .await
1773            .unwrap();
1774
1775        assert!(!is_registered);
1776    }
1777
1778    #[tokio::test]
1779    async fn test_get_operators_for_operator_set() {
1780        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1781        let chain_reader = build_el_chain_reader(http_endpoint).await;
1782
1783        let operator_set = OperatorSet {
1784            id: 1,
1785            avs: Address::ZERO,
1786        };
1787
1788        let operators = chain_reader
1789            .get_operators_for_operator_set(operator_set)
1790            .await
1791            .unwrap();
1792
1793        assert_eq!(operators.len(), 0);
1794    }
1795
1796    #[tokio::test]
1797    async fn test_get_num_operators_for_operator_set() {
1798        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1799        let chain_reader = build_el_chain_reader(http_endpoint).await;
1800
1801        let operator_set = OperatorSet {
1802            id: 1,
1803            avs: Address::ZERO,
1804        };
1805
1806        let num_operators = chain_reader
1807            .get_num_operators_for_operator_set(operator_set)
1808            .await
1809            .unwrap();
1810
1811        assert_eq!(num_operators, U256::from(0));
1812    }
1813
1814    #[tokio::test]
1815    async fn test_get_strategies_for_operator_set() {
1816        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1817        let chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1818
1819        let operator_set = OperatorSet {
1820            id: 1,
1821            avs: Address::ZERO,
1822        };
1823
1824        let strategies = chain_reader
1825            .get_strategies_for_operator_set(operator_set)
1826            .await
1827            .unwrap();
1828
1829        assert_eq!(strategies.len(), 0);
1830    }
1831
1832    #[tokio::test]
1833    async fn test_get_slashable_shares() {
1834        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1835        let chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1836
1837        let operator_set = OperatorSet {
1838            id: 1,
1839            avs: Address::ZERO,
1840        };
1841
1842        let strategies = vec![get_erc20_mock_strategy(http_endpoint).await];
1843        let slashable_shares = chain_reader
1844            .get_slashable_shares(OPERATOR_ADDRESS, operator_set, strategies)
1845            .await
1846            .unwrap();
1847
1848        assert_eq!(slashable_shares.len(), 1);
1849        assert_eq!(slashable_shares[0], U256::ZERO);
1850    }
1851
1852    #[tokio::test]
1853    async fn test_is_operator_slashable() {
1854        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1855        let chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1856
1857        let operator_set = OperatorSet {
1858            id: 1,
1859            avs: Address::ZERO,
1860        };
1861
1862        let is_slashable = chain_reader
1863            .is_operator_slashable(OPERATOR_ADDRESS, operator_set)
1864            .await
1865            .unwrap();
1866        assert!(!is_slashable);
1867    }
1868
1869    #[tokio::test]
1870    async fn test_get_slashable_shares_for_operator_sets() {
1871        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1872        let chain_reader = build_el_chain_reader(http_endpoint).await;
1873
1874        let operator_set = OperatorSet {
1875            id: 1,
1876            avs: Address::ZERO,
1877        };
1878
1879        let slashable_shares = chain_reader
1880            .get_slashable_shares_for_operator_sets(vec![operator_set])
1881            .await
1882            .unwrap();
1883
1884        assert_eq!(slashable_shares.len(), 1);
1885        assert_eq!(slashable_shares[0].operator_set.id, 1);
1886        assert_eq!(slashable_shares[0].operators.len(), 0);
1887        assert_eq!(slashable_shares[0].slashable_stakes.len(), 0);
1888    }
1889
1890    #[tokio::test]
1891    async fn test_get_delegated_and_slashable_shares_for_operator_sets_before() {
1892        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1893        let chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1894
1895        let operator_set = OperatorSet {
1896            id: 1,
1897            avs: Address::ZERO,
1898        };
1899
1900        let current_block_number = get_provider(&http_endpoint)
1901            .get_block_number()
1902            .await
1903            .unwrap() as u32;
1904        let slashable_shares = chain_reader
1905            .get_slashable_shares_for_operator_sets_before(
1906                vec![operator_set],
1907                current_block_number + 1,
1908            )
1909            .await
1910            .unwrap();
1911
1912        assert_eq!(slashable_shares.len(), 1);
1913        assert_eq!(slashable_shares[0].operator_set.id, 1);
1914        assert_eq!(slashable_shares[0].operators.len(), 0);
1915        assert_eq!(slashable_shares[0].slashable_stakes.len(), 0);
1916    }
1917
1918    #[tokio::test]
1919    async fn test_get_allocation_delay() {
1920        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1921        let chain_reader = build_el_chain_reader(http_endpoint).await;
1922
1923        let allocation_delay = chain_reader
1924            .get_allocation_delay(OPERATOR_ADDRESS)
1925            .await
1926            .unwrap();
1927
1928        assert_eq!(allocation_delay, 1);
1929    }
1930
1931    #[tokio::test]
1932    async fn test_get_registered_sets() {
1933        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1934        let chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1935
1936        let ret = chain_reader
1937            .get_registered_sets(OPERATOR_ADDRESS)
1938            .await
1939            .unwrap();
1940
1941        assert_eq!(ret.len(), 0);
1942    }
1943
1944    #[tokio::test]
1945    async fn test_list_appointee() {
1946        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1947        let chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1948
1949        let target = Address::ZERO;
1950        let selector = FixedBytes::from([0x00; 4]);
1951        let appointees = chain_reader
1952            .list_appointees(OPERATOR_ADDRESS, target, selector)
1953            .await
1954            .unwrap();
1955
1956        assert!(appointees.is_empty());
1957    }
1958
1959    #[tokio::test]
1960    async fn test_list_appointee_permissions() {
1961        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1962        let chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1963
1964        let account_address = OPERATOR_ADDRESS;
1965        let appointee_address = OPERATOR_ADDRESS;
1966        let (targets, selectors) = chain_reader
1967            .list_appointee_permissions(account_address, appointee_address)
1968            .await
1969            .unwrap();
1970
1971        assert!(targets.is_empty());
1972        assert!(selectors.is_empty());
1973    }
1974
1975    #[tokio::test]
1976    async fn test_list_pending_admins() {
1977        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1978        let chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1979
1980        let pending_admins = chain_reader
1981            .list_pending_admins(OPERATOR_ADDRESS)
1982            .await
1983            .unwrap();
1984
1985        assert!(pending_admins.is_empty());
1986    }
1987
1988    #[tokio::test]
1989    async fn test_list_admins() {
1990        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1991        let chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1992
1993        let admins = chain_reader.list_admins(OPERATOR_ADDRESS).await.unwrap();
1994
1995        assert_eq!(admins, vec![OPERATOR_ADDRESS]);
1996    }
1997
1998    #[tokio::test]
1999    async fn test_is_pending_admin() {
2000        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
2001        let chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
2002
2003        let is_pending_admin = chain_reader
2004            .is_pending_admin(OPERATOR_ADDRESS, OPERATOR_ADDRESS)
2005            .await
2006            .unwrap();
2007
2008        assert!(!is_pending_admin);
2009    }
2010
2011    #[tokio::test]
2012    async fn test_is_admin() {
2013        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
2014        let chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
2015
2016        let is_admin = chain_reader
2017            .is_admin(OPERATOR_ADDRESS, OPERATOR_ADDRESS)
2018            .await
2019            .unwrap();
2020
2021        assert!(is_admin);
2022    }
2023
2024    #[tokio::test]
2025    async fn test_get_allocated_stake() {
2026        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
2027        let chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
2028
2029        let operator_set = OperatorSet {
2030            id: 1,
2031            avs: Address::ZERO,
2032        };
2033        let operators = vec![OPERATOR_ADDRESS];
2034        let strategies = vec![get_erc20_mock_strategy(http_endpoint.to_string()).await];
2035        let slashable_stake = chain_reader
2036            .get_allocated_stake(operator_set, operators, strategies)
2037            .await
2038            .unwrap();
2039        assert_eq!(slashable_stake[0][0], "0".parse().unwrap());
2040    }
2041
2042    #[tokio::test]
2043    async fn test_get_encumbered_magnitude() {
2044        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
2045        let chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
2046
2047        let magnitude = chain_reader
2048            .get_encumbered_magnitude(
2049                OPERATOR_ADDRESS,
2050                get_erc20_mock_strategy(http_endpoint.to_string()).await,
2051            )
2052            .await
2053            .unwrap();
2054        assert_eq!(magnitude, 0);
2055    }
2056}