Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): add operator deregistration commands #498

Merged
merged 6 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions bolt-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,16 @@ pub enum EigenLayerSubcommand {
expiry: U256,
},

/// Deregister an EigenLayer operator from the bolt AVS.
mempirate marked this conversation as resolved.
Show resolved Hide resolved
Deregister {
/// The URL of the RPC to broadcast the transaction.
#[clap(long, env = "RPC_URL")]
rpc_url: Url,
/// The private key of the operator.
#[clap(long, env = "OPERATOR_PRIVATE_KEY")]
operator_private_key: B256,
},

/// Step 3: Check your operation registration in bolt
Status {
/// The URL of the RPC to broadcast the transaction.
Expand All @@ -253,6 +263,17 @@ pub enum SymbioticSubcommand {
#[clap(long, env = "OPERATOR_RPC")]
operator_rpc: Url,
},

/// Deregister a Symbiotic operator from bolt.
Deregister {
/// The URL of the RPC to broadcast the transaction.
#[clap(long, env = "RPC_URL")]
rpc_url: Url,
/// The private key of the operator.
#[clap(long, env = "OPERATOR_PRIVATE_KEY")]
operator_private_key: B256,
},

/// Check the status of a Symbiotic operator.
Status {
/// The URL of the RPC to broadcast the transaction.
Expand Down
104 changes: 103 additions & 1 deletion bolt-cli/src/commands/operators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,46 @@ impl OperatorsCommand {
eyre::bail!("Transaction failed: {:?}", receipt)
}

info!("Succesfully registered Symbiotic operator");
info!("Succesfully registered EigenLayer operator");

Ok(())
}
EigenLayerSubcommand::Deregister { rpc_url, operator_private_key } => {
let signer = PrivateKeySigner::from_bytes(&operator_private_key)
.wrap_err("valid private key")?;

let provider = ProviderBuilder::new()
.with_recommended_fillers()
.wallet(EthereumWallet::from(signer.clone()))
.on_http(rpc_url.clone());

let chain_id = provider.get_chain_id().await?;
let chain = Chain::from_id(chain_id)
.unwrap_or_else(|| panic!("chain id {} not supported", chain_id));

info!(operator = %signer.address(), ?chain, "Deregistering EigenLayer operator");

request_confirmation();

let deployments = deployments_for_chain(chain);

let bolt_avs_address = deployments.bolt.eigenlayer_middleware;
let bolt_eigenlayer_middleware =
BoltEigenLayerMiddleware::new(bolt_avs_address, provider.clone());
mempirate marked this conversation as resolved.
Show resolved Hide resolved

let result = bolt_eigenlayer_middleware.deregisterOperator().send().await?;

info!(
hash = ?result.tx_hash(),
"deregisterOperator transaction sent, awaiting receipt..."
);

let receipt = result.get_receipt().await?;
if !receipt.status() {
eyre::bail!("Transaction failed: {:?}", receipt)
}

info!("Succesfully deregistered EigenLayer operator");

Ok(())
}
Expand Down Expand Up @@ -245,6 +284,46 @@ impl OperatorsCommand {

Ok(())
}
SymbioticSubcommand::Deregister { rpc_url, operator_private_key } => {
let signer = PrivateKeySigner::from_bytes(&operator_private_key)
.wrap_err("valid private key")?;

let provider = ProviderBuilder::new()
.with_recommended_fillers()
.wallet(EthereumWallet::from(signer.clone()))
.on_http(rpc_url);

let chain_id = provider.get_chain_id().await?;
let chain = Chain::from_id(chain_id)
.unwrap_or_else(|| panic!("chain id {} not supported", chain_id));

let deployments = deployments_for_chain(chain);

info!(operator = %signer.address(), ?chain, "Deregistering Symbiotic operator");

request_confirmation();

let middleware = BoltSymbioticMiddleware::new(
deployments.bolt.symbiotic_middleware,
provider.clone(),
mempirate marked this conversation as resolved.
Show resolved Hide resolved
);

let pending = middleware.deregisterOperator().send().await?;

info!(
hash = ?pending.tx_hash(),
"deregisterOperator transaction sent, awaiting receipt..."
);

let receipt = pending.get_receipt().await?;
if !receipt.status() {
eyre::bail!("Transaction failed: {:?}", receipt)
}

info!("Succesfully deregistered Symbiotic operator");

Ok(())
}
SymbioticSubcommand::Status { rpc_url, address } => {
let provider = ProviderBuilder::new().on_http(rpc_url.clone());
let chain_id = provider.get_chain_id().await?;
Expand Down Expand Up @@ -292,6 +371,7 @@ mod tests {

#[tokio::test]
async fn test_eigenlayer_flow() {
let _ = tracing_subscriber::fmt().try_init();
let mut rnd = rand::thread_rng();
let secret_key = B256::from(rnd.gen::<[u8; 32]>());
let wallet = PrivateKeySigner::from_bytes(&secret_key).expect("valid private key");
Expand Down Expand Up @@ -401,6 +481,28 @@ mod tests {
};

check_operator_registration.run().await.expect("to check operator registration");

let deregister_operator = OperatorsCommand {
subcommand: OperatorsSubcommand::EigenLayer {
subcommand: EigenLayerSubcommand::Deregister {
rpc_url: anvil_url.parse().expect("valid url"),
operator_private_key: secret_key,
},
},
};

deregister_operator.run().await.expect("to deregister operator");

let check_operator_registration = OperatorsCommand {
subcommand: OperatorsSubcommand::EigenLayer {
subcommand: EigenLayerSubcommand::Status {
rpc_url: anvil_url.parse().expect("valid url"),
address: account,
},
},
};

check_operator_registration.run().await.expect("to check operator registration");
}

/// Ignored since it requires Symbiotic CLI: https://docs.symbiotic.fi/guides/cli/#installation
Expand Down
9 changes: 9 additions & 0 deletions bolt-cli/src/contracts/bolt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ sol! {
/// EigenLayer internally contains a mapping from `msg.sender` (our AVS contract) to the operator.
/// The msg.sender of this call will be the operator address.
function registerOperator(string calldata rpc, SignatureWithSaltAndExpiry calldata operatorSignature) public;

/// @notice Deregister an EigenLayer operator from working in Bolt Protocol.
/// @dev This requires calling the EigenLayer AVS Directory contract to deregister the operator.
/// EigenLayer internally contains a mapping from `msg.sender` (our AVS contract) to the operator.
function deregisterOperator() public;
}

#[allow(missing_docs)]
Expand All @@ -45,6 +50,10 @@ sol! {
/// msg.sender must be an operator in the Symbiotic network.
function registerOperator(string calldata rpc) public;

/// @notice Deregister a Symbiotic operator from working in Bolt Protocol.
/// @dev This does NOT deregister the operator from the Symbiotic network.
function deregisterOperator() public;

/// @notice Get the collaterals and amounts staked by an operator across the supported strategies.
///
/// @param operator The operator address to get the collaterals and amounts staked for.
Expand Down