Skip to main content

eigen_client_elcontracts/
writer.rs

1use std::str::FromStr;
2
3use crate::error::ElContractsError;
4use crate::reader::ELChainReader;
5use alloy::dyn_abi::DynSolValue;
6use alloy::primitives::{Address, Bytes, FixedBytes, Signature, TxHash, U256};
7use alloy::signers::local::PrivateKeySigner;
8use alloy::signers::Signer;
9use alloy::sol;
10use eigen_common::{get_provider, get_signer};
11use eigen_crypto_bls::{
12    alloy_g1_point_slashing_to_g1_affine, alloy_g1_point_to_g1_affine, convert_to_g1_point,
13    convert_to_g2_point, BlsKeyPair,
14};
15use eigen_types::operator::operator_id_from_g1_pub_key;
16pub use eigen_types::operator::Operator;
17
18use eigen_utils::convert_allocation_operator_set_to_rewards_operator_set;
19use eigen_utils::rewardsv2::core::delegation_manager::DelegationManager as RewardsV2DelegationManager;
20use eigen_utils::rewardsv2::core::delegation_manager::IDelegationManager::OperatorDetails;
21use eigen_utils::slashing::core::allocation_manager::AllocationManager::OperatorSet;
22
23use eigen_utils::slashing::middleware::registry_coordinator::BN254::{G1Point, G2Point};
24use eigen_utils::slashing::middleware::slashing_registry_coordinator::ISlashingRegistryCoordinatorTypes::OperatorKickParam;
25use eigen_utils::slashing::middleware::slashing_registry_coordinator::SlashingRegistryCoordinator;
26use eigen_utils::{
27    slashing::core::{
28        allocation_manager::{AllocationManager, IAllocationManagerTypes},
29        delegation_manager::DelegationManager,
30        i_rewards_coordinator::{IRewardsCoordinator, IRewardsCoordinatorTypes::RewardsMerkleClaim},
31        permission_controller::PermissionController,
32        strategy_manager::StrategyManager,
33    },
34    slashing::middleware::{ierc20::IERC20, registry_coordinator::RegistryCoordinator},
35};
36use tracing::info;
37
38/// Gas limit for registerAsOperator in [`DelegationManager`]
39pub const GAS_LIMIT_REGISTER_AS_OPERATOR_DELEGATION_MANAGER: u128 = 300000;
40
41sol! {
42    #[allow(missing_docs)]
43    #[derive(Debug)]
44    /// Bar
45    enum RegistrationType {
46        NORMAL,
47        CHURN,
48    }
49}
50/// Chain Writer to interact with EigenLayer contracts onchain
51#[derive(Debug, Clone)]
52pub struct ELChainWriter {
53    strategy_manager: Address,
54    rewards_coordinator: Address,
55    permission_controller: Option<Address>,
56    allocation_manager: Option<Address>,
57    registry_coordinator: Address,
58    el_chain_reader: ELChainReader,
59    provider: String,
60    signer: String,
61}
62
63impl ELChainWriter {
64    #[allow(clippy::too_many_arguments)]
65    pub fn new(
66        strategy_manager: Address,
67        rewards_coordinator: Address,
68        permission_controller: Option<Address>,
69        allocation_manager: Option<Address>,
70        registry_coordinator: Address,
71        el_chain_reader: ELChainReader,
72        provider: String,
73        signer: String,
74    ) -> Self {
75        Self {
76            strategy_manager,
77            rewards_coordinator,
78            permission_controller,
79            allocation_manager,
80            registry_coordinator,
81            el_chain_reader,
82            provider,
83            signer,
84        }
85    }
86
87    /// Sets signer for ELChainWriter
88    ///
89    /// # Arguments
90    ///
91    /// * `signer`: signer string
92    ///
93    pub fn set_signer(&mut self, signer: String) {
94        self.signer = signer;
95    }
96
97    pub async fn register_as_operator_preslashing(
98        &self,
99        operator: Operator,
100    ) -> Result<TxHash, ElContractsError> {
101        info!("registering operator {:?} to EigenLayer", operator.address);
102        let provider = get_signer(&self.signer.clone(), &self.provider);
103
104        if let Some(staker_opt_out_blocks) = operator.staker_opt_out_window_blocks {
105            let contract_delegation_manager =
106                RewardsV2DelegationManager::new(self.el_chain_reader.delegation_manager, provider);
107            let operator_details = OperatorDetails {
108                __deprecated_earningsReceiver: operator
109                    ._deprecated_earnings_receiver_address
110                    .unwrap_or(Address::ZERO),
111                delegationApprover: operator.delegation_approver_address,
112                stakerOptOutWindowBlocks: staker_opt_out_blocks,
113            };
114            let binding = {
115                let contract_call = contract_delegation_manager
116                    .registerAsOperator(operator_details, operator.metadata_url);
117                contract_call.gas(300000)
118            };
119            let binding_tx = binding
120                .send()
121                .await
122                .map_err(ElContractsError::AlloyContractError)?;
123
124            let receipt = binding_tx
125                .get_receipt()
126                .await
127                .map_err(ElContractsError::AlloyPendingTransactionError)?;
128
129            let tx_status = receipt.status();
130            let hash = receipt.transaction_hash;
131            if tx_status {
132                info!(tx_hash = %receipt.transaction_hash, "tx successfully included");
133            } else {
134                info!(tx_hash = %receipt.transaction_hash, "failed to register operator");
135            };
136            Ok(hash)
137        } else {
138            Err(ElContractsError::StakerOptOutWindowBlocksNotSet)
139        }
140    }
141
142    /// Register an operator to EigenLayer, and wait for the transaction to be mined.
143    ///
144    /// # Arguments
145    ///
146    /// * `operator` - The operator to register
147    ///
148    /// # Returns
149    ///
150    /// * `TxHash` - The transaction hash if successful, otherwise an error
151    ///
152    /// # Errors
153    ///
154    /// * `ElContractsError` - if the call to the contract fails
155    pub async fn register_as_operator(
156        &self,
157        operator: Operator,
158    ) -> Result<TxHash, ElContractsError> {
159        info!("registering operator {:?} to EigenLayer", operator.address);
160        let provider = get_signer(&self.signer.clone(), &self.provider);
161
162        let contract_delegation_manager =
163            DelegationManager::new(self.el_chain_reader.delegation_manager, provider);
164
165        if let Some(allocation_delay) = operator.allocation_delay {
166            let binding = {
167                let contract_call = contract_delegation_manager.registerAsOperator(
168                    operator.address,
169                    allocation_delay,
170                    operator.metadata_url,
171                );
172                contract_call.gas(300000)
173            };
174
175            let binding_tx = binding
176                .send()
177                .await
178                .map_err(ElContractsError::AlloyContractError)?;
179
180            let receipt = binding_tx
181                .get_receipt()
182                .await
183                .map_err(ElContractsError::AlloyPendingTransactionError)?;
184
185            let tx_status = receipt.status();
186            let hash = receipt.transaction_hash;
187            if tx_status {
188                info!(tx_hash = %receipt.transaction_hash, "tx successfully included");
189            } else {
190                info!(tx_hash = %receipt.transaction_hash, "failed to register operator");
191            };
192            Ok(hash)
193        } else {
194            Err(ElContractsError::AllocationDelayNotSet)
195        }
196    }
197
198    /// Update operator details on EigenLayer
199    ///
200    /// # Arguments
201    ///
202    /// * `operator` - The operator to update
203    ///
204    /// # Returns
205    ///
206    /// * `TxHash` - The transaction hash if successful, otherwise an error
207    ///
208    /// # Errors
209    ///
210    /// * `ElContractsError` - if the call to the contract fails
211    pub async fn update_operator_details(
212        &self,
213        operator: Operator,
214    ) -> Result<TxHash, ElContractsError> {
215        info!(
216            "updating operator detils of operator {:?} to EigenLayer",
217            operator.address
218        );
219
220        let provider = get_signer(&self.signer.clone(), &self.provider);
221
222        let contract_delegation_manager =
223            DelegationManager::new(self.el_chain_reader.delegation_manager, provider);
224
225        let contract_call_modify_operator_details = contract_delegation_manager
226            .modifyOperatorDetails(operator.address, operator.delegation_approver_address);
227
228        let modify_operator_tx = contract_call_modify_operator_details
229            .send()
230            .await
231            .map_err(ElContractsError::AlloyContractError)?;
232
233        info!(tx_hash = %modify_operator_tx.tx_hash(), operator = %operator.address, "updated operator details tx");
234
235        let contract_call_update_metadata_uri = contract_delegation_manager
236            .updateOperatorMetadataURI(operator.address, operator.metadata_url);
237
238        let metadata_tx = contract_call_update_metadata_uri.send().await?;
239
240        Ok(*metadata_tx.tx_hash())
241    }
242
243    /// Deposit ERC20 tokens into a strategy on EigenLayer
244    ///
245    /// # Arguments
246    ///
247    /// * `strategy_addr` - The address of the strategy to deposit into
248    /// * `amount` - The amount of tokens to deposit
249    ///
250    /// # Returns
251    ///
252    /// * `TxHash` - The transaction hash if successful, otherwise an error
253    ///
254    /// # Errors
255    ///
256    /// * `ElContractsError` - if the call to the contract fails
257    pub async fn deposit_erc20_into_strategy(
258        &self,
259        strategy_addr: Address,
260        amount: U256,
261    ) -> Result<TxHash, ElContractsError> {
262        info!("depositing {amount:?} tokens into strategy {strategy_addr:?}");
263        let (_strategy, token_address) = self
264            .el_chain_reader
265            .get_strategy_and_underlying_token(strategy_addr)
266            .await?;
267        let provider = get_signer(&self.signer.clone(), &self.provider);
268        let token_contract = IERC20::new(token_address, &provider);
269
270        let contract_call = token_contract.approve(self.strategy_manager, amount);
271
272        let _approve = contract_call.send().await?;
273
274        let contract_strategy_manager = StrategyManager::new(self.strategy_manager, &provider);
275
276        let deposit_contract_call =
277            contract_strategy_manager.depositIntoStrategy(strategy_addr, token_address, amount);
278
279        let tx = deposit_contract_call.send().await?;
280
281        info!("deposited {amount:?} tokens into strategy {strategy_addr:?}");
282        Ok(*tx.tx_hash())
283    }
284
285    /// Set a claimer for a given address on EigenLayer
286    ///
287    /// # Arguments
288    ///
289    /// * `claimer` - The address to set as the claimer
290    ///
291    /// # Returns
292    ///
293    /// * `FixedBytes<32>` - The transaction hash if the operation is sent, otherwise an error
294    ///
295    /// # Errors
296    ///
297    /// * `ElContractsError` - if the call to the contract fails
298    pub async fn set_claimer_for(
299        &self,
300        claimer: Address,
301    ) -> Result<FixedBytes<32>, ElContractsError> {
302        let provider = get_signer(&self.signer, &self.provider);
303
304        let contract_rewards_coordinator =
305            IRewardsCoordinator::new(self.rewards_coordinator, &provider);
306
307        let set_claimer_for_call = contract_rewards_coordinator.setClaimerFor_0(claimer);
308
309        let tx = set_claimer_for_call.send().await?;
310        Ok(*tx.tx_hash())
311    }
312
313    /// Process a claim for rewards for a given earner address. Checks the claim against a given root
314    /// (determined by the root_index on the claim). Earnings are cumulative so earners can claim to
315    /// the latest distribution root and the contract will compute the difference between their earning
316    /// and claimed amounts. The difference is transferred to the earner address.
317    /// If a claimer has not been set (see [`Self::set_claimer_for`]), only the earner can claim. Otherwise, only
318    /// the claimer can claim.
319    ///
320    /// # Arguments
321    ///
322    /// * `claim` - The RewardsMerkleClaim object containing the claim.
323    /// * `earner_address` - The address of the earner for whom to process the claim.
324    ///
325    /// # Returns
326    ///
327    /// * `Result<FixedBytes<32>, ElContractsError>` - The transaction hash if the claim is sent, otherwise an error.
328    ///
329    /// # Errors
330    ///
331    /// * `ElContractsError` - if the call to the contract fails. Also fails if no root has been submitted yet.
332    pub async fn process_claim(
333        &self,
334        claim: RewardsMerkleClaim,
335        earner_address: Address,
336    ) -> Result<FixedBytes<32>, ElContractsError> {
337        let provider = get_signer(&self.signer, &self.provider);
338
339        let contract_rewards_coordinator =
340            IRewardsCoordinator::new(self.rewards_coordinator, &provider);
341
342        let process_claim_call = contract_rewards_coordinator.processClaim(claim, earner_address);
343
344        let tx = process_claim_call.send().await?;
345        Ok(*tx.tx_hash())
346    }
347
348    /// Process multiple claim for rewards for a given earner address. Checks the claim against a given root
349    /// (determined by the root_index on the claim). Earnings are cumulative so earners can claim to
350    /// the latest distribution root and the contract will compute the difference between their earning
351    /// and claimed amounts. The difference is transferred to the earner address.
352    /// If a claimer has not been set (see [`Self::set_claimer_for`]), only the earner can claim. Otherwise, only
353    /// the claimer can claim.
354    ///
355    /// # Arguments
356    ///
357    /// * `claims` - A [`Vec`] of RewardsMerkleClaim objects containing the claims.
358    /// * `earnerAddress` - The address of the earner for whom to process the claims.
359    ///
360    /// # Returns
361    ///
362    /// * `Result<FixedBytes<32>, ElContractsError>` - The transaction hash if the claim is sent, otherwise an error.
363    ///
364    /// # Errors
365    ///
366    /// * `ElContractsError` - if the call to the contract fails. Also fails if no root has been submitted yet.
367    pub async fn process_claims(
368        &self,
369        claims: Vec<RewardsMerkleClaim>,
370        earner_address: Address,
371    ) -> Result<FixedBytes<32>, ElContractsError> {
372        let provider = get_signer(&self.signer, &self.provider);
373
374        let contract_rewards_coordinator =
375            IRewardsCoordinator::new(self.rewards_coordinator, &provider);
376
377        let process_claim_call = contract_rewards_coordinator.processClaims(claims, earner_address);
378
379        let tx = process_claim_call.send().await?;
380        Ok(*tx.tx_hash())
381    }
382
383    /// Sets the split of a specific `operator` for a specific `avs`
384    ///
385    /// # Arguments
386    ///
387    /// * `operator` - The operator address
388    /// * `avs` - The AVS address
389    /// * `split` - The new split of the operator for the AVS
390    ///
391    /// # Returns
392    ///
393    /// * `Result<FixedBytes<32>, ElContractsError>` - The transaction hash if the transaction is sent, otherwise an error.
394    ///
395    /// # Errors
396    ///
397    /// * `ElContractsError` - if the call to the contract fails.
398    pub async fn set_operator_avs_split(
399        &self,
400        operator: Address,
401        avs: Address,
402        split: u16,
403    ) -> Result<FixedBytes<32>, ElContractsError> {
404        let signer = get_signer(&self.signer, &self.provider);
405
406        let rewards_coordinator = IRewardsCoordinator::new(self.rewards_coordinator, signer);
407
408        let tx = rewards_coordinator
409            .setOperatorAVSSplit(operator, avs, split)
410            .send()
411            .await
412            .map_err(ElContractsError::AlloyContractError)?;
413
414        Ok(*tx.tx_hash())
415    }
416
417    /// Sets the split for a specific `operator` for a specific `operatorSet`
418    ///
419    /// # Arguments
420    ///
421    /// * `operator` - The operator address
422    /// * `OperatorSet` - The operator set which consists of avs address and id.
423    /// * `split` - The split for the operator for the specific operatorSet in bips.
424    ///
425    /// # Returns
426    ///
427    /// * `Result<FixedBytes<32>, ElContractsError>` - The transaction hash if the transaction is sent, otherwise an error.
428    ///
429    /// # Errors
430    ///
431    /// * `ElContractsError` - if the call to the contract fails.
432    pub async fn set_operator_set_split(
433        &self,
434        operator: Address,
435        operator_set: OperatorSet,
436        split: u16,
437    ) -> Result<FixedBytes<32>, ElContractsError> {
438        let signer = get_signer(&self.signer, &self.provider);
439
440        let rewards_coordinator = IRewardsCoordinator::new(self.rewards_coordinator, signer);
441        let operator_set_rewards =
442            convert_allocation_operator_set_to_rewards_operator_set(operator_set);
443        let tx = rewards_coordinator
444            .setOperatorSetSplit(operator, operator_set_rewards, split)
445            .send()
446            .await
447            .map_err(ElContractsError::AlloyContractError)?;
448
449        Ok(*tx.tx_hash())
450    }
451
452    /// sets the split of a specific `operator` for Programmatic Incentives
453    ///
454    /// # Arguments
455    ///
456    /// * `operator` - The operator address
457    /// * `split` - The new split of the operator for PI
458    ///
459    /// # Returns
460    ///
461    /// * `Result<FixedBytes<32>, ElContractsError>` - The transaction hash if the transaction is sent, otherwise an error.
462    ///
463    /// # Errors
464    ///
465    /// * `ElContractsError` - if the call to the contract fails.
466    pub async fn set_operator_pi_split(
467        &self,
468        operator: Address,
469        split: u16,
470    ) -> Result<FixedBytes<32>, ElContractsError> {
471        let signer = get_signer(&self.signer, &self.provider);
472
473        let rewards_coordinator = IRewardsCoordinator::new(self.rewards_coordinator, signer);
474
475        let tx = rewards_coordinator
476            .setOperatorPISplit(operator, split)
477            .send()
478            .await
479            .map_err(ElContractsError::AlloyContractError)?;
480
481        Ok(*tx.tx_hash())
482    }
483
484    /// Removes permission of an appointee on a target contract, given an account address.
485    ///
486    /// # Arguments
487    ///
488    /// * `account_address` - account address from which to remove permission
489    /// * `appointee_address` - Address to remove
490    /// * `target` - contract address that the appointee has permission to
491    /// * `selector` - The selector of the function to remove permissions for
492    ///
493    /// # Returns
494    ///
495    /// * `TxHash` - The transaction hash of the generated transaction.
496    ///
497    /// # Errors
498    ///
499    /// * `ElContractsError` - if the call to the contract fails.
500    pub async fn remove_permission(
501        &self,
502        account_address: Address,
503        appointee_address: Address,
504        target: Address,
505        selector: FixedBytes<4>,
506    ) -> Result<TxHash, ElContractsError> {
507        let provider = get_signer(&self.signer, &self.provider);
508        let permission_controller_contract = PermissionController::new(
509            self.permission_controller
510                .ok_or(ElContractsError::MissingParameter)?,
511            provider,
512        );
513
514        let tx = permission_controller_contract
515            .removeAppointee(account_address, appointee_address, target, selector)
516            .send()
517            .await
518            .map_err(ElContractsError::AlloyContractError)?;
519
520        Ok(*tx.tx_hash())
521    }
522
523    /// Set an appointee for a given account. Only the admin of the account can set an appointee.
524    /// The appointee will be able to call the target contract function with the given selector.
525    /// # Arguments
526    /// * `account_address` - account address set appointee for
527    /// * `appointee_address` - appointee address to set
528    /// * `target` - target contract address
529    /// * `selector` - function selector
530    /// # Returns
531    /// * `TxHash` - The transaction hash of the generated transaction.
532    /// # Errors
533    /// * `ElContractsError` - if the call to the contract fails.
534    pub async fn set_permission(
535        &self,
536        account_address: Address,
537        appointee_address: Address,
538        target: Address,
539        selector: FixedBytes<4>,
540    ) -> Result<TxHash, ElContractsError> {
541        let provider = get_signer(&self.signer, &self.provider);
542        let permission_controller_contract = PermissionController::new(
543            self.permission_controller
544                .ok_or(ElContractsError::MissingParameter)?,
545            provider,
546        );
547
548        let tx = permission_controller_contract
549            .setAppointee(account_address, appointee_address, target, selector)
550            .send()
551            .await
552            .map_err(ElContractsError::AlloyContractError)?;
553
554        Ok(*tx.tx_hash())
555    }
556
557    /// Remove pending admin. Only the admin of the account can remove a pending admin
558    ///
559    /// # Arguments
560    ///
561    /// * `account_address` - account address
562    /// * `admin_address` - admin address to remove
563    ///
564    /// # Returns
565    ///
566    /// * `TxHash` - The transaction hash of the generated transaction.
567    pub async fn remove_pending_admin(
568        &self,
569        account_address: Address,
570        admin_address: Address,
571    ) -> Result<TxHash, ElContractsError> {
572        let provider = get_signer(&self.signer, &self.provider);
573        let permission_controller_contract = PermissionController::new(
574            self.permission_controller
575                .ok_or(ElContractsError::MissingParameter)?,
576            provider,
577        );
578
579        let tx = permission_controller_contract
580            .removePendingAdmin(account_address, admin_address)
581            .send()
582            .await
583            .map_err(ElContractsError::AlloyContractError)?;
584
585        Ok(*tx.tx_hash())
586    }
587
588    /// Set a pending admin. Multiple admins can be set for an account.
589    /// The caller must be an admin. If the account does not have an admin, the caller must be the account.
590    ///
591    /// # Arguments
592    ///
593    /// * `account_address` - account address
594    /// * `admin_address` - admin address to set
595    ///
596    /// # Returns
597    ///
598    /// * `TxHash` - The transaction hash of the generated transaction.
599    pub async fn add_pending_admin(
600        &self,
601        account_address: Address,
602        admin_address: Address,
603    ) -> Result<TxHash, ElContractsError> {
604        let provider = get_signer(&self.signer, &self.provider);
605        let permission_controller_contract = PermissionController::new(
606            self.permission_controller
607                .ok_or(ElContractsError::MissingParameter)?,
608            provider,
609        );
610
611        let tx = permission_controller_contract
612            .addPendingAdmin(account_address, admin_address)
613            .send()
614            .await
615            .map_err(ElContractsError::AlloyContractError)?;
616
617        Ok(*tx.tx_hash())
618    }
619
620    /// Accept a pending admin. The sender of the transaction must be the pending admin.
621    ///
622    /// # Arguments
623    ///
624    /// * `account` - account to accept admin for
625    ///
626    /// # Returns
627    ///
628    /// * `TxHash` - The transaction hash of the generated transaction.
629    ///
630    /// # Errors
631    ///
632    /// * `ElContractsError` - if the call to the contract fails.
633    pub async fn accept_admin(&self, account: Address) -> Result<TxHash, ElContractsError> {
634        let provider = get_signer(&self.signer, &self.provider);
635        let permission_controller_contract = PermissionController::new(
636            self.permission_controller
637                .ok_or(ElContractsError::MissingParameter)?,
638            provider,
639        );
640
641        let tx = permission_controller_contract
642            .acceptAdmin(account)
643            .send()
644            .await
645            .map_err(ElContractsError::AlloyContractError)?;
646
647        Ok(*tx.tx_hash())
648    }
649
650    /// Remove an admin. The sender of the transaction must be an admin.
651    ///
652    /// # Arguments
653    ///
654    /// * `account` - account to remove admin from
655    /// * `admin` - admin to remove
656    ///
657    /// # Returns
658    ///
659    /// * `TxHash` - The transaction hash of the generated transaction.
660    ///
661    /// # Errors
662    ///
663    /// * `ElContractsError` - if the call to the contract fails. Fails if the admin being removed is the only admin.
664    pub async fn remove_admin(
665        &self,
666        account: Address,
667        admin: Address,
668    ) -> Result<TxHash, ElContractsError> {
669        let provider = get_signer(&self.signer, &self.provider);
670        let permission_controller_contract = PermissionController::new(
671            self.permission_controller
672                .ok_or(ElContractsError::MissingParameter)?,
673            provider,
674        );
675
676        let tx = permission_controller_contract
677            .removeAdmin(account, admin)
678            .send()
679            .await
680            .map_err(ElContractsError::AlloyContractError)?;
681
682        Ok(*tx.tx_hash())
683    }
684
685    /// Register an operator for one or more operator sets for an AVS. If the operator
686    /// has any stake allocated to these operator sets, it immediately becomes slashable.
687    ///
688    /// # Arguments
689    ///
690    /// * `operator_address` - operator address to register
691    /// * `avs_address` - AVS address
692    /// * `operator_set_ids` - operator set ids to register on
693    ///
694    /// # Returns
695    ///
696    /// * `TxHash` - The transaction hash of the generated transaction.
697    ///
698    /// # Errors
699    ///
700    /// * `ElContractsError` - if the call to the contract fails.
701    pub async fn register_for_operator_sets(
702        &self,
703        operator_address: Address,
704        avs_address: Address,
705        operator_set_ids: Vec<u32>,
706        bls_key_pair: BlsKeyPair,
707        socket: &str,
708    ) -> Result<TxHash, ElContractsError> {
709        let provider = get_signer(&self.signer, &self.provider);
710        let contract_allocation_manager = AllocationManager::new(
711            self.allocation_manager
712                .ok_or(ElContractsError::MissingParameter)?,
713            provider.clone(),
714        );
715        let contract_registry_coordinator =
716            RegistryCoordinator::new(self.registry_coordinator, provider);
717
718        let g1_hashed_msg_to_sign = contract_registry_coordinator
719            .pubkeyRegistrationMessageHash(operator_address)
720            .call()
721            .await?;
722
723        let sig = bls_key_pair
724            .sign_hashed_to_curve_message(alloy_g1_point_to_g1_affine(g1_hashed_msg_to_sign))
725            .g1_point();
726        let alloy_g1_point_signed_msg =
727            convert_to_g1_point(sig.g1()).map_err(|_| ElContractsError::BLSKeyPairInvalid)?;
728        let g1_pub_key_bn254 = convert_to_g1_point(bls_key_pair.public_key().g1())
729            .map_err(|_| ElContractsError::BLSKeyPairInvalid)?;
730        let g2_pub_key_bn254 = convert_to_g2_point(bls_key_pair.public_key_g2().g2())
731            .map_err(|_| ElContractsError::BLSKeyPairInvalid)?;
732
733        let g2_point_x: Vec<DynSolValue> = vec![
734            DynSolValue::Uint(g2_pub_key_bn254.X[0], 256),
735            DynSolValue::Uint(g2_pub_key_bn254.X[1], 256),
736        ];
737        let g2_point_y: Vec<DynSolValue> = vec![
738            DynSolValue::Uint(g2_pub_key_bn254.Y[0], 256),
739            DynSolValue::Uint(g2_pub_key_bn254.Y[1], 256),
740        ];
741        let encoded_params_with_socket = DynSolValue::Tuple(vec![
742            DynSolValue::Uint(U256::from(0), 256),
743            DynSolValue::String(socket.to_string()),
744            DynSolValue::Uint(alloy_g1_point_signed_msg.X, 256),
745            DynSolValue::Uint(alloy_g1_point_signed_msg.Y, 256),
746            DynSolValue::Uint(g1_pub_key_bn254.X, 256),
747            DynSolValue::Uint(g1_pub_key_bn254.Y, 256),
748            DynSolValue::FixedArray(g2_point_x),
749            DynSolValue::FixedArray(g2_point_y),
750        ])
751        .abi_encode_params();
752
753        let params = IAllocationManagerTypes::RegisterParams {
754            avs: avs_address,
755            operatorSetIds: operator_set_ids,
756            data: encoded_params_with_socket.into(),
757        };
758        let tx = contract_allocation_manager
759            .registerForOperatorSets(operator_address, params)
760            .send()
761            .await?;
762
763        Ok(*tx.tx_hash())
764    }
765
766    /// Register with churn an operator for one or more operator sets for an AVS
767    /// while replacing existing operators in full quorums. If the operator
768    /// has any stake allocated to these operator sets, it immediately becomes slashable.
769    ///
770    /// This method performs similar steps to [`Self::register_for_operator_sets`], except that
771    /// for each quorum where the new Operator total exceeds the `maxOperatorCount`,
772    /// the `operatorKickParams` are used to deregister a current Operator to make room for the new one.
773    ///
774    /// # Arguments
775    ///
776    /// * `operator_address` - operator address to register
777    /// * `bls_key_pair` - bls key pair of the operator
778    /// * `avs_address` - AVS address
779    /// * `operator_set_ids` - operator set ids to register on
780    /// * `socket` - socket used for calling the contract with `registerOperator` function
781    /// * `quorum_numbers` - quorum numbers to register the new operator
782    /// * `operators_to_kick` - operators to kick if quorum is full
783    /// * `churn_signer_private_key` - private key of the churn signer
784    /// * `churn_sig_salt` - churn signature salt
785    /// * `churn_sig_expiry` - churn signature expiry
786    ///
787    /// # Returns
788    ///
789    /// * `TxHash` - The transaction hash of the generated transaction.
790    ///
791    /// # Errors
792    ///
793    /// * `ElContractsError` - if the call to the contract fails.
794    #[allow(clippy::too_many_arguments)]
795    pub async fn register_for_operator_sets_with_churn(
796        &self,
797        operator: Address,
798        bls_key_pair: BlsKeyPair,
799        avs_address: Address,
800        operator_set_ids: Vec<u32>,
801        socket: String,
802        quorum_numbers: Bytes,
803        operators_to_kick: Vec<Address>,
804        churn_signer_private_key: String,
805        churn_sig_salt: FixedBytes<32>,
806        churn_sig_expiry: U256,
807    ) -> Result<TxHash, ElContractsError> {
808        let provider = get_signer(&self.signer, &self.provider);
809
810        let allocation_manager = AllocationManager::new(
811            self.allocation_manager
812                .ok_or(ElContractsError::MissingParameter)?,
813            &provider,
814        );
815
816        let (alloy_g1_point_signed_msg, g1_pub_key_bn254, g2_pub_key_bn254) =
817            prepare_bls_keys_for_registration(
818                &self.provider,
819                self.registry_coordinator,
820                operator,
821                &bls_key_pair,
822            )
823            .await?;
824
825        let operators_to_kick_params =
826            build_operator_kick_params(&operators_to_kick, &quorum_numbers);
827
828        let churn_signature = sign_churn_digest(
829            &self.provider,
830            self.registry_coordinator,
831            &bls_key_pair,
832            operator,
833            &operators_to_kick_params,
834            churn_signer_private_key,
835            churn_sig_salt,
836            churn_sig_expiry,
837        )
838        .await?;
839
840        let encoded_data = encode_registration_data(
841            socket,
842            alloy_g1_point_signed_msg,
843            g1_pub_key_bn254,
844            g2_pub_key_bn254,
845            operators_to_kick_params,
846            churn_signature,
847            churn_sig_salt,
848            churn_sig_expiry,
849        );
850
851        let register_params = IAllocationManagerTypes::RegisterParams {
852            avs: avs_address,
853            operatorSetIds: operator_set_ids,
854            data: encoded_data.into(),
855        };
856
857        let tx = allocation_manager
858            .registerForOperatorSets(operator, register_params)
859            .send()
860            .await
861            .map_err(ElContractsError::AlloyContractError)?;
862
863        Ok(*tx.tx_hash())
864    }
865
866    /// Deregister an operator from one or more of the AVS's operator sets. If the operator
867    /// has any slashable stake allocated to the AVS, it remains slashable until the deallocation delay has passed.
868    ///
869    /// # Arguments
870    ///
871    /// * `operator_address` - operator address to deregister
872    /// * `avs_address` - AVS address
873    /// * `operator_set_ids` - operator set ids to deregister from
874    ///
875    /// # Returns
876    ///
877    /// * `TxHash` - The transaction hash of the generated transaction.
878    ///
879    /// # Errors
880    ///
881    /// * `ElContractsError` - if the call to the contract fails.
882    pub async fn deregister_from_operator_sets(
883        &self,
884        operator_address: Address,
885        avs_address: Address,
886        operator_set_ids: Vec<u32>,
887    ) -> Result<TxHash, ElContractsError> {
888        let provider = get_signer(&self.signer, &self.provider);
889        let contract_allocation_manager = AllocationManager::new(
890            self.allocation_manager
891                .ok_or(ElContractsError::MissingParameter)?,
892            provider,
893        );
894
895        let params = IAllocationManagerTypes::DeregisterParams {
896            operator: operator_address,
897            avs: avs_address,
898            operatorSetIds: operator_set_ids,
899        };
900        let tx = contract_allocation_manager
901            .deregisterFromOperatorSets(params)
902            .send()
903            .await
904            .map_err(ElContractsError::AlloyContractError)?;
905
906        Ok(*tx.tx_hash())
907    }
908
909    /// Set the allocation delay for an operator. It is the number of blocks between an operator
910    /// allocating magnitude to an operator set, and the magnitude becoming slashable
911    ///
912    /// # Arguments
913    ///
914    /// * `operator_address` - operator address to set allocation delay for
915    /// * `delay` - delay in blocks
916    ///
917    /// # Returns
918    ///
919    /// * `TxHash` - The transaction hash of the generated transaction.
920    ///
921    /// # Errors
922    ///
923    /// * `ElContractsError` - if the call to the contract fails.
924    pub async fn set_allocation_delay(
925        &self,
926        operator_address: Address,
927        delay: u32,
928    ) -> Result<TxHash, ElContractsError> {
929        let provider = get_signer(&self.signer, &self.provider);
930        let contract_allocation_manager = AllocationManager::new(
931            self.allocation_manager
932                .ok_or(ElContractsError::MissingParameter)?,
933            provider,
934        );
935
936        let tx = contract_allocation_manager
937            .setAllocationDelay(operator_address, delay)
938            .send()
939            .await
940            .map_err(ElContractsError::AlloyContractError)?;
941
942        Ok(*tx.tx_hash())
943    }
944
945    /// Modifiy the proportions of slashable stake allocated to an operator set from a list of strategies.
946    /// # Arguments
947    /// * `operator_address` - operator address to modify allocations for
948    /// * `allocations` - list of magnitude adjustments for one or more operator sets
949    /// # Returns
950    /// * `TxHash` - The transaction hash of the generated transaction.
951    /// # Errors
952    /// * `ElContractsError` - if the call to the contract fails.
953    pub async fn modify_allocations(
954        &self,
955        operator_address: Address,
956        allocations: Vec<IAllocationManagerTypes::AllocateParams>,
957    ) -> Result<TxHash, ElContractsError> {
958        let provider = get_signer(&self.signer, &self.provider);
959        let contract_allocation_manager = AllocationManager::new(
960            self.allocation_manager
961                .ok_or(ElContractsError::MissingParameter)?,
962            provider,
963        );
964
965        let tx = contract_allocation_manager
966            .modifyAllocations(operator_address, allocations)
967            .send()
968            .await
969            .map_err(ElContractsError::AlloyContractError)?;
970
971        Ok(*tx.tx_hash())
972    }
973
974    /// Removes from the deallocationQueue all clearable deallocations up to max `num_to_clear` number of deallocations.
975    ///
976    /// `len(strategies)` must be equal to `len(num_to_clear)`
977    ///
978    /// # Arguments
979    /// * `operator` - operator address to clear deallocations for
980    /// * `strategies` - list of strategies to clear deallocations for
981    /// * `num_to_clear` - list of number of pending deallocations to clear for each strategy
982    ///
983    /// # Returns
984    /// * `TxHash` - The transaction hash of the generated transaction.
985    ///
986    /// # Errors
987    /// * `ElContractsError` - if the call to the contract fails.
988    pub async fn clear_deallocation_queue(
989        &self,
990        operator: Address,
991        strategies: Vec<Address>,
992        num_to_clear: Vec<u16>,
993    ) -> Result<TxHash, ElContractsError> {
994        let provider = get_signer(&self.signer, &self.provider);
995        let allocation_manager_contract = AllocationManager::new(
996            self.allocation_manager
997                .ok_or(ElContractsError::MissingParameter)?,
998            provider,
999        );
1000
1001        allocation_manager_contract
1002            .clearDeallocationQueue(operator, strategies, num_to_clear)
1003            .send()
1004            .await
1005            .map_err(ElContractsError::AlloyContractError)
1006            .map(|tx| *tx.tx_hash())
1007    }
1008}
1009
1010/// Generates the G1 and G2 points for the operator registration message hash
1011/// Prepares the BLS keys for registration by signing a hashed message and converting the public keys
1012/// to the required BN254 curve format.
1013///
1014/// # Arguments
1015///
1016/// * `rpc_url` - rpc url used to create the provider.
1017/// * `registry_coordinator_address` - registry coordinator address
1018/// * `operator` - operator address
1019/// * `bls_key_pair` - bls key pair of the operator
1020///
1021/// # Returns
1022///
1023/// * `(G1Point, G1Point, G2Point)` - alloy g1 point signed msg, g1 pub key bn254, g2 pub key bn254
1024///
1025/// # Errors
1026/// * `ElContractsError` - if the call to the contract fails.
1027async fn prepare_bls_keys_for_registration(
1028    rpc_url: &str,
1029    registry_coordinator_address: Address,
1030    operator: Address,
1031    bls_key_pair: &BlsKeyPair,
1032) -> Result<(G1Point, G1Point, G2Point), ElContractsError> {
1033    let provider = get_provider(rpc_url);
1034    let contract_registry_coordinator =
1035        SlashingRegistryCoordinator::new(registry_coordinator_address, &provider);
1036
1037    let g1_hashed_msg_to_sign = contract_registry_coordinator
1038        .pubkeyRegistrationMessageHash(operator)
1039        .call()
1040        .await?;
1041
1042    let sig = bls_key_pair
1043        .sign_hashed_to_curve_message(alloy_g1_point_slashing_to_g1_affine(g1_hashed_msg_to_sign))
1044        .g1_point();
1045
1046    let alloy_g1_point_signed_msg =
1047        convert_to_g1_point(sig.g1()).map_err(|_| ElContractsError::BLSKeyPairInvalid)?;
1048    let g1_pub_key_bn254 = convert_to_g1_point(bls_key_pair.public_key().g1())
1049        .map_err(|_| ElContractsError::BLSKeyPairInvalid)?;
1050    let g2_pub_key_bn254 = convert_to_g2_point(bls_key_pair.public_key_g2().g2())
1051        .map_err(|_| ElContractsError::BLSKeyPairInvalid)?;
1052
1053    Ok((
1054        alloy_g1_point_signed_msg,
1055        g1_pub_key_bn254,
1056        g2_pub_key_bn254,
1057    ))
1058}
1059
1060/// Builds the operator kick params for [`register_for_operator_sets_with_churn`]
1061/// The operator kick params are used to specify the operators to kick if the quorum is full.
1062///
1063/// # Arguments
1064///
1065/// * `operators_to_kick` - operators to kick
1066/// * `quorum_numbers` - quorum numbers
1067///
1068/// # Returns
1069///
1070/// * `Vec<OperatorKickParam>` - operator kick params
1071fn build_operator_kick_params(
1072    operators_to_kick: &[Address],
1073    quorum_numbers: &Bytes,
1074) -> Vec<OperatorKickParam> {
1075    operators_to_kick
1076        .iter()
1077        .zip(quorum_numbers.iter())
1078        .map(|(address, &quorum_number)| OperatorKickParam {
1079            operator: *address,
1080            quorumNumber: quorum_number,
1081        })
1082        .collect()
1083}
1084
1085/// Signs the churn digest hash for [`register_for_operator_sets_with_churn`].
1086///
1087/// # Arguments
1088///
1089/// * `rpc_url` - rpc url used to create the provider.
1090/// * `registry_coordinator_address` - registry coordinator address
1091/// * `bls_key_pair` - bls key pair of the operator
1092/// * `operator` - operator address
1093/// * `operators_to_kick_params` - operators to kick params
1094/// * `churn_signer_private_key` - private key of the churn signer
1095/// * `churn_sig_salt` - churn signature salt
1096/// * `churn_sig_expiry` - churn signature expiry
1097///
1098/// # Returns
1099/// * `Signature` - signed churn digest hash
1100///
1101/// # Errors
1102/// * `ElContractsError` - if the call to the contract fails.
1103#[allow(clippy::too_many_arguments)]
1104async fn sign_churn_digest(
1105    rpc_url: &str,
1106    registry_coordinator_address: Address,
1107    bls_key_pair: &BlsKeyPair,
1108    operator: Address,
1109    operators_to_kick_params: &[OperatorKickParam],
1110    churn_signer_private_key: String,
1111    churn_sig_salt: FixedBytes<32>,
1112    churn_sig_expiry: U256,
1113) -> Result<Signature, ElContractsError> {
1114    let provider = get_provider(rpc_url);
1115    let contract_registry_coordinator =
1116        SlashingRegistryCoordinator::new(registry_coordinator_address, &provider);
1117
1118    let churn_wallet = PrivateKeySigner::from_str(&churn_signer_private_key)
1119        .map_err(|_| ElContractsError::InvalidSignature)?;
1120
1121    let operator_id = operator_id_from_g1_pub_key(bls_key_pair.public_key())
1122        .map_err(|_| ElContractsError::InvalidSignature)?;
1123
1124    let churn_digest_hash = contract_registry_coordinator
1125        .calculateOperatorChurnApprovalDigestHash(
1126            operator,
1127            operator_id,
1128            operators_to_kick_params.to_vec(),
1129            churn_sig_salt,
1130            churn_sig_expiry,
1131        )
1132        .call()
1133        .await?;
1134
1135    let signature = churn_wallet
1136        .sign_hash(&churn_digest_hash)
1137        .await
1138        .map_err(|_| ElContractsError::InvalidSignature)?;
1139
1140    Ok(signature)
1141}
1142
1143/// Encodes the registration data for [`register_for_operator_sets_with_churn`]
1144///
1145/// # Arguments
1146/// * `socket` - socket
1147/// * `alloy_g1_point_signed_msg` - alloy g1 point signed msg
1148/// * `g1_pub_key_bn254` - g1 pub key bn254
1149/// * `g2_pub_key_bn254` - g2 pub key bn254
1150/// * `operators_to_kick_params` - operators to kick params
1151/// * `churn_signature` - churn signature
1152/// * `churn_sig_salt` - churn signature salt
1153/// * `churn_sig_expiry` - churn signature expiry
1154///
1155/// # Returns
1156///
1157/// * `Vec<u8>` - encoded registration data
1158#[allow(clippy::too_many_arguments)]
1159fn encode_registration_data(
1160    socket: String,
1161    alloy_g1_point_signed_msg: G1Point,
1162    g1_pub_key_bn254: G1Point,
1163    g2_pub_key_bn254: G2Point,
1164    operators_to_kick_params: Vec<OperatorKickParam>,
1165    churn_signature: Signature,
1166    churn_sig_salt: FixedBytes<32>,
1167    churn_sig_expiry: U256,
1168) -> Vec<u8> {
1169    let g2_point_x = vec![
1170        DynSolValue::Uint(g2_pub_key_bn254.X[0], 256),
1171        DynSolValue::Uint(g2_pub_key_bn254.X[1], 256),
1172    ];
1173    let g2_point_y = vec![
1174        DynSolValue::Uint(g2_pub_key_bn254.Y[0], 256),
1175        DynSolValue::Uint(g2_pub_key_bn254.Y[1], 256),
1176    ];
1177
1178    let pubkey_registration_params = DynSolValue::Tuple(vec![
1179        DynSolValue::Tuple(vec![
1180            DynSolValue::Uint(alloy_g1_point_signed_msg.X, 256),
1181            DynSolValue::Uint(alloy_g1_point_signed_msg.Y, 256),
1182        ]),
1183        DynSolValue::Tuple(vec![
1184            DynSolValue::Uint(g1_pub_key_bn254.X, 256),
1185            DynSolValue::Uint(g1_pub_key_bn254.Y, 256),
1186        ]),
1187        DynSolValue::Tuple(vec![
1188            DynSolValue::FixedArray(g2_point_x),
1189            DynSolValue::FixedArray(g2_point_y),
1190        ]),
1191    ]);
1192
1193    let operator_kick_params = DynSolValue::Array(
1194        operators_to_kick_params
1195            .into_iter()
1196            .map(|param| {
1197                DynSolValue::Tuple(vec![
1198                    DynSolValue::Uint(U256::from(param.quorumNumber), 8),
1199                    DynSolValue::Address(param.operator),
1200                ])
1201            })
1202            .collect(),
1203    );
1204
1205    let signature_with_salt = DynSolValue::Tuple(vec![
1206        DynSolValue::Bytes(churn_signature.as_bytes().into()),
1207        DynSolValue::FixedBytes(churn_sig_salt, 32),
1208        DynSolValue::Uint(churn_sig_expiry, 256),
1209    ]);
1210
1211    DynSolValue::Tuple(vec![
1212        DynSolValue::Uint(U256::from(1), 8), // RegistrationType.CHURN = 1
1213        DynSolValue::String(socket),
1214        pubkey_registration_params,
1215        operator_kick_params,
1216        signature_with_salt,
1217    ])
1218    .abi_encode_params()
1219}
1220
1221#[cfg(test)]
1222mod tests {
1223    use alloy::{
1224        primitives::{address, ruint::aliases::U256, Address, Bytes, FixedBytes},
1225        providers::{Provider, WalletProvider},
1226    };
1227    use eigen_common::{get_provider, get_signer};
1228    use eigen_crypto_bls::BlsKeyPair;
1229    use eigen_testing_utils::{
1230        anvil::{
1231            mine_anvil_blocks, set_account_balance, start_anvil_container, start_m2_anvil_container,
1232        },
1233        anvil_constants::{
1234            get_erc20_mock_strategy, get_registry_coordinator_address, get_service_manager_address,
1235            FIRST_ADDRESS, FIRST_PRIVATE_KEY, OPERATOR_BLS_KEY_2, SECOND_ADDRESS,
1236            SECOND_PRIVATE_KEY,
1237        },
1238        chain_clients::{
1239            build_el_chain_reader, create_operator_set, create_total_delegated_stake_operator_set,
1240            new_claim, new_test_writer, new_test_writer_preslashing, OPERATOR_ADDRESS,
1241            OPERATOR_PRIVATE_KEY,
1242        },
1243        transaction::wait_transaction,
1244    };
1245    use eigen_types::operator::Operator;
1246    use eigen_utils::{
1247        convert_allocation_operator_set_to_rewards_operator_set,
1248        slashing::{
1249            core::allocation_manager::{AllocationManager::OperatorSet, IAllocationManagerTypes},
1250            middleware::slashing_registry_coordinator::{
1251                ISlashingRegistryCoordinatorTypes::OperatorSetParam as OperatorSetParamSlashing,
1252                SlashingRegistryCoordinator,
1253            },
1254        },
1255    };
1256    use std::str::FromStr;
1257
1258    #[tokio::test]
1259    async fn test_register_operator() {
1260        let (container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1261
1262        // Use arbitrary non-default wallet because first 100 default addresses are already registered
1263        let new_operator_sk = "0x7ff6d852bfd83bb0e21a575a765bc2f197efeb97f04cf9454d4078d5eca9a726";
1264        let new_operator_address = get_signer(new_operator_sk, &http_endpoint)
1265            .signer_addresses()
1266            .next()
1267            .unwrap();
1268
1269        set_account_balance(&container, &new_operator_address.to_string()).await;
1270
1271        let el_chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1272        let el_chain_writer =
1273            new_test_writer(http_endpoint.to_string(), new_operator_sk.to_string()).await;
1274
1275        let operator = Operator {
1276            address: new_operator_address,
1277            delegation_approver_address: new_operator_address,
1278            metadata_url: "metadata_uri".to_string(),
1279            allocation_delay: Some(1),
1280            _deprecated_earnings_receiver_address: None,
1281            staker_opt_out_window_blocks: None,
1282        };
1283
1284        let tx_hash = el_chain_writer
1285            .register_as_operator(operator)
1286            .await
1287            .unwrap();
1288
1289        let tx_status = wait_transaction(&http_endpoint, tx_hash)
1290            .await
1291            .unwrap()
1292            .status();
1293        assert!(tx_status);
1294
1295        let is_registered = el_chain_reader
1296            .is_operator_registered(FIRST_ADDRESS)
1297            .await
1298            .unwrap();
1299        assert!(is_registered);
1300    }
1301
1302    #[tokio::test]
1303    async fn test_register_operator_preslashing() {
1304        let (container, http_endpoint, _ws_endpoint) = start_m2_anvil_container().await;
1305
1306        // Use arbitrary non-default wallet because first 100 default addresses are already registered
1307        let new_operator_sk = "0x7ff6d852bfd83bb0e21a575a765bc2f197efeb97f04cf9454d4078d5eca9a726";
1308        let new_operator_address = get_signer(new_operator_sk, &http_endpoint)
1309            .signer_addresses()
1310            .next()
1311            .unwrap();
1312
1313        set_account_balance(&container, &new_operator_address.to_string()).await;
1314
1315        let el_chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1316        let el_chain_writer =
1317            new_test_writer_preslashing(http_endpoint.to_string(), new_operator_sk.to_string())
1318                .await;
1319
1320        let operator = Operator {
1321            address: FIRST_ADDRESS, // can only register the address corresponding to the signer used in the writer
1322            delegation_approver_address: FIRST_ADDRESS,
1323            metadata_url: "metadata_uri".to_string(),
1324            allocation_delay: None,
1325            _deprecated_earnings_receiver_address: None,
1326            staker_opt_out_window_blocks: Some(0u32),
1327        };
1328        let tx_hash = el_chain_writer
1329            .register_as_operator_preslashing(operator)
1330            .await
1331            .unwrap();
1332
1333        let tx_status = wait_transaction(&http_endpoint, tx_hash)
1334            .await
1335            .unwrap()
1336            .status();
1337        assert!(tx_status);
1338
1339        let is_registered = el_chain_reader
1340            .is_operator_registered(FIRST_ADDRESS)
1341            .await
1342            .unwrap();
1343        assert!(is_registered);
1344    }
1345
1346    #[tokio::test]
1347    async fn test_register_and_update_operator() {
1348        let (container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1349        let provider = get_provider(&http_endpoint);
1350
1351        let address_str = "009440d62dc85c73dbf889b7ad1f4da8b231d2ef";
1352        let private_key = "6b35c6d8110c888de06575b45181bf3f9e6c73451fa5cde812c95a6b31e66ddf";
1353        let el_chain_writer =
1354            new_test_writer(http_endpoint.to_string(), private_key.to_string()).await;
1355
1356        set_account_balance(&container, address_str).await;
1357        let address = Address::from_str(address_str).unwrap();
1358
1359        let operator = Operator {
1360            address,
1361            delegation_approver_address: Address::ZERO,
1362            metadata_url: "eigensdk-rs".to_string(),
1363            allocation_delay: Some(1),
1364            _deprecated_earnings_receiver_address: None,
1365            staker_opt_out_window_blocks: None,
1366        };
1367
1368        // First test: register as an operator
1369        let tx_hash = el_chain_writer
1370            .register_as_operator(operator)
1371            .await
1372            .unwrap();
1373
1374        let receipt = provider.get_transaction_receipt(tx_hash).await.unwrap();
1375        assert!(receipt.unwrap().status());
1376
1377        let operator_modified = Operator {
1378            address,
1379            delegation_approver_address: Address::ZERO,
1380            metadata_url: "new-metadata".to_string(),
1381            allocation_delay: Some(1),
1382            staker_opt_out_window_blocks: None,
1383            _deprecated_earnings_receiver_address: None,
1384        };
1385
1386        // Second test: update operator details
1387        let tx_hash = el_chain_writer
1388            .update_operator_details(operator_modified)
1389            .await
1390            .unwrap();
1391        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1392        assert!(receipt.status());
1393    }
1394
1395    #[tokio::test]
1396    async fn test_deposit_erc20_into_strategy() {
1397        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1398        let el_chain_writer =
1399            new_test_writer(http_endpoint.to_string(), FIRST_PRIVATE_KEY.to_string()).await;
1400
1401        let amount = U256::from_str("100").unwrap();
1402        let strategy_addr = get_erc20_mock_strategy(http_endpoint.clone()).await;
1403        let tx_hash = el_chain_writer
1404            .deposit_erc20_into_strategy(strategy_addr, amount)
1405            .await
1406            .unwrap();
1407
1408        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1409        assert!(receipt.status());
1410    }
1411
1412    #[tokio::test]
1413    async fn test_set_claimer_for() {
1414        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1415        let el_chain_writer =
1416            new_test_writer(http_endpoint.to_string(), FIRST_PRIVATE_KEY.to_string()).await;
1417
1418        let claimer = address!("5eb15C0992734B5e77c888D713b4FC67b3D679A2");
1419
1420        let tx_hash = el_chain_writer.set_claimer_for(claimer).await.unwrap();
1421
1422        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1423        assert!(receipt.status());
1424    }
1425
1426    #[tokio::test]
1427    async fn test_process_claim() {
1428        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1429        let el_chain_writer =
1430            new_test_writer(http_endpoint.to_string(), FIRST_PRIVATE_KEY.to_string()).await;
1431
1432        let (_root, claim) = new_claim(&http_endpoint, U256::from(42)).await;
1433
1434        let tx_hash = el_chain_writer
1435            .process_claim(claim, FIRST_ADDRESS)
1436            .await
1437            .unwrap();
1438
1439        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1440        assert!(receipt.status());
1441    }
1442
1443    #[tokio::test]
1444    async fn test_process_claims() {
1445        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1446        let el_chain_writer =
1447            new_test_writer(http_endpoint.to_string(), FIRST_PRIVATE_KEY.to_string()).await;
1448
1449        let (_root, claim0) = new_claim(&http_endpoint, U256::from(42)).await;
1450        let (_root, claim1) = new_claim(&http_endpoint, U256::from(4256)).await;
1451
1452        let tx_hash = el_chain_writer
1453            .process_claims(vec![claim0, claim1], FIRST_ADDRESS)
1454            .await
1455            .unwrap();
1456
1457        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1458        assert!(receipt.status());
1459    }
1460
1461    #[tokio::test]
1462    async fn test_add_and_remove_pending_admin() {
1463        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1464        let el_chain_writer =
1465            new_test_writer(http_endpoint.to_string(), FIRST_PRIVATE_KEY.to_string()).await;
1466        let el_chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1467
1468        let pending_admin = address!("009440d62dc85c73dbf889b7ad1f4da8b231d2ef");
1469        let tx_hash = el_chain_writer
1470            .add_pending_admin(FIRST_ADDRESS, pending_admin)
1471            .await
1472            .unwrap();
1473        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1474        assert!(receipt.status());
1475
1476        let is_pending_admin = el_chain_reader
1477            .is_pending_admin(FIRST_ADDRESS, pending_admin)
1478            .await
1479            .unwrap();
1480        assert!(is_pending_admin);
1481
1482        let tx_hash = el_chain_writer
1483            .remove_pending_admin(FIRST_ADDRESS, pending_admin)
1484            .await
1485            .unwrap();
1486        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1487        assert!(receipt.status());
1488
1489        let is_admin = el_chain_reader
1490            .is_pending_admin(FIRST_ADDRESS, pending_admin)
1491            .await
1492            .unwrap();
1493        assert!(!is_admin);
1494    }
1495
1496    #[tokio::test]
1497    async fn test_accept_admin() {
1498        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1499        let account_writer =
1500            new_test_writer(http_endpoint.to_string(), FIRST_PRIVATE_KEY.to_string()).await;
1501
1502        let pending_admin = address!("14dC79964da2C08b23698B3D3cc7Ca32193d9955");
1503        let pending_admin_key =
1504            "0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356";
1505
1506        let tx_hash = account_writer
1507            .add_pending_admin(FIRST_ADDRESS, pending_admin)
1508            .await
1509            .unwrap();
1510
1511        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1512        assert!(receipt.status());
1513
1514        let admin_writer =
1515            new_test_writer(http_endpoint.to_string(), pending_admin_key.to_string()).await;
1516        let el_chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1517
1518        let tx_hash = admin_writer.accept_admin(FIRST_ADDRESS).await.unwrap();
1519
1520        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1521        assert!(receipt.status());
1522
1523        let is_admin = el_chain_reader
1524            .is_admin(FIRST_ADDRESS, pending_admin)
1525            .await
1526            .unwrap();
1527        assert!(is_admin);
1528    }
1529
1530    #[tokio::test]
1531    async fn test_remove_admin() {
1532        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1533        let el_chain_writer =
1534            new_test_writer(http_endpoint.to_string(), FIRST_PRIVATE_KEY.to_string()).await;
1535        let el_chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1536
1537        let pending_admin_1 = address!("14dC79964da2C08b23698B3D3cc7Ca32193d9955");
1538        let pending_admin_1_key =
1539            "0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356";
1540
1541        let pending_admin_2 = address!("23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f");
1542        let pending_admin_2_key =
1543            "0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97";
1544
1545        // Adding two admins and removing one. Cannot remove the last admin, so one must remain
1546        let tx_hash = el_chain_writer
1547            .add_pending_admin(FIRST_ADDRESS, pending_admin_1)
1548            .await
1549            .unwrap();
1550        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1551        assert!(receipt.status());
1552
1553        let tx_hash = el_chain_writer
1554            .add_pending_admin(FIRST_ADDRESS, pending_admin_2)
1555            .await
1556            .unwrap();
1557        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1558        assert!(receipt.status());
1559
1560        let admin_1_writer =
1561            new_test_writer(http_endpoint.to_string(), pending_admin_1_key.to_string()).await;
1562        admin_1_writer.accept_admin(FIRST_ADDRESS).await.unwrap();
1563        let admin_2_writer =
1564            new_test_writer(http_endpoint.to_string(), pending_admin_2_key.to_string()).await;
1565        admin_2_writer.accept_admin(FIRST_ADDRESS).await.unwrap();
1566
1567        let tx_hash = admin_1_writer
1568            .remove_admin(FIRST_ADDRESS, pending_admin_2)
1569            .await
1570            .unwrap();
1571
1572        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1573        assert!(receipt.status());
1574
1575        let is_admin = el_chain_reader
1576            .is_admin(FIRST_ADDRESS, pending_admin_2)
1577            .await
1578            .unwrap();
1579        assert!(!is_admin);
1580    }
1581
1582    #[tokio::test]
1583    async fn test_set_and_remove_permission() {
1584        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1585        let account_address = FIRST_ADDRESS;
1586        let appointee_address = address!("009440d62dc85c73dbf889b7ad1f4da8b231d2ef");
1587        let target = address!("14dC79964da2C08b23698B3D3cc7Ca32193d9955");
1588        let selector = [0, 1, 2, 3].into();
1589
1590        // add an admin
1591        let account_writer =
1592            new_test_writer(http_endpoint.to_string(), FIRST_PRIVATE_KEY.to_string()).await;
1593        let el_chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1594
1595        // set permission
1596        let tx_hash = account_writer
1597            .set_permission(account_address, appointee_address, target, selector)
1598            .await
1599            .unwrap();
1600        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1601        assert!(receipt.status());
1602
1603        // check if appointee can call the set target
1604        let can_call = el_chain_reader
1605            .can_call(account_address, appointee_address, target, selector)
1606            .await
1607            .unwrap();
1608        assert!(can_call);
1609
1610        // test remove permission
1611        let el_chain_writer =
1612            new_test_writer(http_endpoint.to_string(), FIRST_PRIVATE_KEY.to_string()).await;
1613
1614        let tx_hash = el_chain_writer
1615            .remove_permission(account_address, appointee_address, target, selector)
1616            .await
1617            .unwrap();
1618
1619        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1620        assert!(receipt.status());
1621    }
1622
1623    #[tokio::test]
1624    async fn test_register_for_operator_sets() {
1625        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1626        let avs_address = get_service_manager_address(http_endpoint.clone()).await;
1627        let operator_set_id = 0;
1628        create_operator_set(http_endpoint.as_str(), avs_address).await;
1629
1630        let operator_addr = OPERATOR_ADDRESS;
1631        let operator_private_key = OPERATOR_PRIVATE_KEY;
1632        let el_chain_writer =
1633            new_test_writer(http_endpoint.clone(), operator_private_key.to_string()).await;
1634        let el_chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1635
1636        let bls_key = BlsKeyPair::new("1".to_string()).unwrap();
1637
1638        let tx_hash = el_chain_writer
1639            .register_for_operator_sets(
1640                operator_addr,
1641                avs_address,
1642                vec![operator_set_id],
1643                bls_key,
1644                "socket",
1645            )
1646            .await
1647            .unwrap();
1648
1649        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1650        assert!(receipt.status());
1651
1652        let operator_set = OperatorSet {
1653            avs: avs_address,
1654            id: operator_set_id,
1655        };
1656        let is_registered = el_chain_reader
1657            .is_operator_registered_with_operator_set(operator_addr, operator_set.clone())
1658            .await
1659            .unwrap();
1660        assert!(is_registered);
1661
1662        let tx_hash = el_chain_writer
1663            .deregister_from_operator_sets(operator_addr, avs_address, vec![operator_set_id])
1664            .await
1665            .unwrap();
1666        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1667        assert!(receipt.status());
1668
1669        let is_registered = el_chain_reader
1670            .is_operator_registered_with_operator_set(operator_addr, operator_set.clone())
1671            .await
1672            .unwrap();
1673        assert!(!is_registered);
1674    }
1675
1676    #[tokio::test]
1677    async fn test_set_allocation_delay() {
1678        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1679        let el_chain_writer =
1680            new_test_writer(http_endpoint.to_string(), FIRST_PRIVATE_KEY.to_string()).await;
1681        let el_chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1682
1683        let delay = 10;
1684
1685        let tx_hash = el_chain_writer
1686            .set_allocation_delay(FIRST_ADDRESS, delay)
1687            .await
1688            .unwrap();
1689        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1690        assert!(receipt.status());
1691        let current_block = get_provider(&http_endpoint)
1692            .get_block_number()
1693            .await
1694            .unwrap();
1695        mine_anvil_blocks(&_container, (current_block as u32) + 2).await;
1696        let allocation_delay = el_chain_reader
1697            .get_allocation_delay(FIRST_ADDRESS)
1698            .await
1699            .unwrap();
1700
1701        assert_eq!(allocation_delay, delay);
1702    }
1703
1704    #[tokio::test]
1705    async fn test_modify_allocations() {
1706        let (container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1707        let el_chain_writer =
1708            new_test_writer(http_endpoint.to_string(), FIRST_PRIVATE_KEY.to_string()).await;
1709        let el_chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1710
1711        let operator_address = FIRST_ADDRESS;
1712        let strategy_addr = get_erc20_mock_strategy(http_endpoint.clone()).await;
1713
1714        let avs_address = get_service_manager_address(http_endpoint.clone()).await;
1715        let operator_set_id = 0;
1716        create_operator_set(http_endpoint.as_str(), avs_address).await;
1717
1718        let new_allocation = 100;
1719        let allocate_params = IAllocationManagerTypes::AllocateParams {
1720            strategies: vec![strategy_addr],
1721            operatorSet:
1722                eigen_utils::slashing::core::allocation_manager::AllocationManager::OperatorSet {
1723                    avs: avs_address,
1724                    id: operator_set_id,
1725                },
1726            newMagnitudes: vec![new_allocation],
1727        };
1728        let tx_hash = el_chain_writer
1729            .modify_allocations(operator_address, vec![allocate_params])
1730            .await
1731            .unwrap();
1732        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1733        assert!(receipt.status());
1734
1735        let allocation_info = el_chain_reader
1736            .get_allocation_info(operator_address, strategy_addr)
1737            .await
1738            .unwrap();
1739
1740        // Allocation should be pending
1741        assert_eq!(allocation_info[0].pending_diff, U256::from(new_allocation));
1742
1743        let allocation_delay = el_chain_reader
1744            .get_allocation_delay(FIRST_ADDRESS)
1745            .await
1746            .unwrap();
1747        mine_anvil_blocks(&container, allocation_delay).await;
1748
1749        let allocation_info = el_chain_reader
1750            .get_allocation_info(operator_address, strategy_addr)
1751            .await
1752            .unwrap();
1753
1754        // After the allocation delay blocks, the allocation should be set
1755        assert_eq!(
1756            allocation_info[0].current_magnitude,
1757            U256::from(new_allocation)
1758        );
1759    }
1760
1761    #[tokio::test]
1762    async fn test_set_operator_avs_split() {
1763        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1764        let el_chain_writer =
1765            new_test_writer(http_endpoint.to_string(), FIRST_PRIVATE_KEY.to_string()).await;
1766        let el_chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1767        let new_split = 5;
1768        let avs_address = get_service_manager_address(http_endpoint.clone()).await;
1769
1770        let split = el_chain_reader
1771            .get_operator_avs_split(FIRST_ADDRESS, avs_address)
1772            .await
1773            .unwrap();
1774
1775        assert_eq!(split, 1); // not initialized case
1776
1777        let tx_hash = el_chain_writer
1778            .set_operator_avs_split(FIRST_ADDRESS, avs_address, new_split)
1779            .await
1780            .unwrap();
1781
1782        let tx_status = wait_transaction(&http_endpoint, tx_hash)
1783            .await
1784            .unwrap()
1785            .status();
1786        assert!(tx_status);
1787
1788        let split = el_chain_reader
1789            .get_operator_avs_split(FIRST_ADDRESS, avs_address)
1790            .await
1791            .unwrap();
1792        assert_eq!(split, 5); // initialized && activated
1793    }
1794
1795    #[tokio::test]
1796    async fn test_set_operator_set_split() {
1797        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1798        let avs_address = get_service_manager_address(http_endpoint.clone()).await;
1799        let operator_set_id = 0;
1800        create_operator_set(http_endpoint.as_str(), avs_address).await;
1801
1802        let operator_addr = OPERATOR_ADDRESS;
1803        let operator_private_key = OPERATOR_PRIVATE_KEY;
1804        let el_chain_writer =
1805            new_test_writer(http_endpoint.clone(), operator_private_key.to_string()).await;
1806        let el_chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1807        let bls_key = BlsKeyPair::new("1".to_string()).unwrap();
1808
1809        let tx_hash = el_chain_writer
1810            .register_for_operator_sets(
1811                operator_addr,
1812                avs_address,
1813                vec![operator_set_id],
1814                bls_key,
1815                "socket",
1816            )
1817            .await
1818            .unwrap();
1819
1820        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1821        assert!(receipt.status());
1822        let operator_set = OperatorSet {
1823            avs: avs_address,
1824            id: 0,
1825        };
1826
1827        let new_split = 5;
1828        let tx_hash = el_chain_writer
1829            .set_operator_set_split(OPERATOR_ADDRESS, operator_set.clone(), new_split)
1830            .await
1831            .unwrap();
1832        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1833        assert!(receipt.status());
1834        let rewards_operator_set =
1835            convert_allocation_operator_set_to_rewards_operator_set(operator_set.clone());
1836        let split = el_chain_reader
1837            .get_operator_set_split(OPERATOR_ADDRESS, rewards_operator_set.clone())
1838            .await
1839            .unwrap();
1840
1841        assert_eq!(split, new_split); // initialized && activated
1842    }
1843
1844    #[tokio::test]
1845    async fn test_set_operator_pi_split() {
1846        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1847        let el_chain_writer =
1848            new_test_writer(http_endpoint.to_string(), FIRST_PRIVATE_KEY.to_string()).await;
1849        let el_chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1850        let new_split = 5;
1851
1852        let split = el_chain_reader
1853            .get_operator_pi_split(FIRST_ADDRESS)
1854            .await
1855            .unwrap();
1856
1857        assert_eq!(split, 1); // not initialized case
1858
1859        let tx_hash = el_chain_writer
1860            .set_operator_pi_split(FIRST_ADDRESS, new_split)
1861            .await
1862            .unwrap();
1863
1864        let receipt = wait_transaction(&http_endpoint, tx_hash).await.unwrap();
1865        assert!(receipt.status());
1866
1867        let split = el_chain_reader
1868            .get_operator_pi_split(FIRST_ADDRESS)
1869            .await
1870            .unwrap();
1871
1872        assert_eq!(split, new_split);
1873    }
1874
1875    #[tokio::test]
1876    async fn test_clear_deallocation_queue() {
1877        let (_contianer, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1878        let el_chain_writer =
1879            new_test_writer(http_endpoint.to_string(), FIRST_PRIVATE_KEY.to_string()).await;
1880        let el_chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1881        let avs_address = get_service_manager_address(http_endpoint.clone()).await;
1882        create_operator_set(http_endpoint.as_str(), avs_address).await;
1883
1884        let operator_address = FIRST_ADDRESS;
1885        let strategy_addr = get_erc20_mock_strategy(http_endpoint.clone()).await;
1886        let operator_set_id = 0;
1887
1888        let new_allocation = 100;
1889        let allocate_params = IAllocationManagerTypes::AllocateParams {
1890            strategies: vec![strategy_addr],
1891            operatorSet: OperatorSet {
1892                avs: avs_address,
1893                id: operator_set_id,
1894            },
1895            newMagnitudes: vec![new_allocation],
1896        };
1897        let tx_hash_alloc = el_chain_writer
1898            .modify_allocations(operator_address, vec![allocate_params.clone()])
1899            .await
1900            .unwrap();
1901        let receipt_alloc = wait_transaction(&http_endpoint, tx_hash_alloc)
1902            .await
1903            .unwrap();
1904        assert!(receipt_alloc.status());
1905
1906        let allocation_info_before = el_chain_reader
1907            .get_allocation_info(operator_address, strategy_addr)
1908            .await
1909            .unwrap();
1910
1911        assert_eq!(
1912            allocation_info_before[0].pending_diff,
1913            U256::from(new_allocation)
1914        );
1915
1916        let tx_hash_clear = el_chain_writer
1917            .clear_deallocation_queue(
1918                operator_address,
1919                vec![strategy_addr],
1920                vec![new_allocation as u16],
1921            )
1922            .await
1923            .unwrap();
1924        let receipt_clear = wait_transaction(&http_endpoint, tx_hash_clear)
1925            .await
1926            .unwrap();
1927        assert!(receipt_clear.status(),);
1928
1929        let allocation_info_after = el_chain_reader
1930            .get_allocation_info(operator_address, strategy_addr)
1931            .await
1932            .unwrap();
1933
1934        assert_eq!(allocation_info_after[0].pending_diff, U256::ZERO);
1935        assert_eq!(
1936            allocation_info_after[0].current_magnitude,
1937            U256::from(new_allocation)
1938        );
1939    }
1940
1941    #[tokio::test]
1942    async fn test_register_for_operator_sets_with_churn() {
1943        let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await;
1944        let default_signer = get_signer(FIRST_PRIVATE_KEY, &http_endpoint);
1945        let avs_address = get_service_manager_address(http_endpoint.clone()).await;
1946        let operator_set_id = 0;
1947
1948        // Create operator set
1949        create_total_delegated_stake_operator_set(
1950            &http_endpoint,
1951            get_erc20_mock_strategy(http_endpoint.clone()).await,
1952            avs_address,
1953        )
1954        .await;
1955
1956        // Register FIRST_ADDRESS to operator set
1957        let el_chain_writer =
1958            new_test_writer(http_endpoint.clone(), FIRST_PRIVATE_KEY.to_string()).await;
1959        let el_chain_reader = build_el_chain_reader(http_endpoint.clone()).await;
1960        let bls_key = BlsKeyPair::new("1".to_string()).unwrap();
1961        let tx_hash = el_chain_writer
1962            .register_for_operator_sets_with_churn(
1963                FIRST_ADDRESS,
1964                bls_key,
1965                avs_address,
1966                vec![operator_set_id],
1967                "socket".to_string(),
1968                Bytes::from([0]),
1969                vec![FIRST_ADDRESS],
1970                FIRST_PRIVATE_KEY.to_string(),
1971                FixedBytes::from([0x03; 32]),
1972                U256::MAX,
1973            )
1974            .await
1975            .unwrap();
1976
1977        assert!(wait_transaction(&http_endpoint, tx_hash)
1978            .await
1979            .unwrap()
1980            .status());
1981
1982        // Verify FIRST_ADDRESS registration
1983        assert!(el_chain_reader
1984            .is_operator_registered_with_operator_set(
1985                FIRST_ADDRESS,
1986                OperatorSet {
1987                    avs: avs_address,
1988                    id: operator_set_id
1989                }
1990            )
1991            .await
1992            .unwrap());
1993
1994        // Set maxOperatorCount to 1 so only one operator can be registered to the operator set
1995        let slashing_registry_coordinator = SlashingRegistryCoordinator::new(
1996            get_registry_coordinator_address(http_endpoint.clone()).await,
1997            default_signer.clone(),
1998        );
1999        let operator_set_params = OperatorSetParamSlashing {
2000            maxOperatorCount: 1,
2001            kickBIPsOfOperatorStake: 10,
2002            kickBIPsOfTotalStake: 10000,
2003        };
2004        assert!(slashing_registry_coordinator
2005            .setOperatorSetParams(0, operator_set_params)
2006            .send()
2007            .await
2008            .unwrap()
2009            .get_receipt()
2010            .await
2011            .unwrap()
2012            .status());
2013
2014        // Register SECOND_ADDRESS to operator set with churn. FIRST_ADDRESS will be kicked
2015        let el_chain_writer_2 =
2016            new_test_writer(http_endpoint.clone(), SECOND_PRIVATE_KEY.to_string()).await;
2017        let tx_hash = el_chain_writer_2
2018            .register_for_operator_sets_with_churn(
2019                SECOND_ADDRESS,
2020                BlsKeyPair::new(OPERATOR_BLS_KEY_2.to_string()).unwrap(),
2021                avs_address,
2022                vec![operator_set_id],
2023                "socket".to_string(),
2024                Bytes::from([0]),
2025                vec![FIRST_ADDRESS],
2026                FIRST_PRIVATE_KEY.to_string(),
2027                FixedBytes::from([0x05; 32]),
2028                U256::MAX,
2029            )
2030            .await
2031            .unwrap();
2032
2033        assert!(wait_transaction(&http_endpoint, tx_hash)
2034            .await
2035            .unwrap()
2036            .status());
2037
2038        // Verify FIRST_ADDRESS is not registered
2039        assert!(!el_chain_reader
2040            .is_operator_registered_with_operator_set(
2041                FIRST_ADDRESS,
2042                OperatorSet {
2043                    avs: avs_address,
2044                    id: operator_set_id
2045                }
2046            )
2047            .await
2048            .unwrap());
2049
2050        // Verify SECOND_ADDRESS is registered
2051        assert!(el_chain_reader
2052            .is_operator_registered_with_operator_set(
2053                SECOND_ADDRESS,
2054                OperatorSet {
2055                    avs: avs_address,
2056                    id: operator_set_id
2057                }
2058            )
2059            .await
2060            .unwrap());
2061    }
2062}