Skip to content

Commit

Permalink
Add operator registration to EL and optin for ClientApp
Browse files Browse the repository at this point in the history
  • Loading branch information
chalex-eth committed Oct 21, 2024
1 parent ef2d9d2 commit 6af1499
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 35 deletions.
19 changes: 14 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,28 @@
help:
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

# RPC URLs
HOLESKY_RPC_URL=https://eth-holesky.g.alchemy.com/v2/8lbq3evplhjE7rP48rxeMXcpDNTGz0Hf
ANVIL_RPC_URL=http://localhost:8545

# CONTRACTS ADDRESSES
GIZA_AVS_ADDRESS=0x68d2Ecd85bDEbfFd075Fb6D87fFD829AD025DD5C
TASK_REGISTRY_ADDRESS=0x6Da3D07a6BF01F02fB41c02984a49B5d9Aa6ea92
CLIENT_APP_REGISTRY_ADDRESS=0xa8d297D643a11cE83b432e87eEBce6bee0fd2bAb
AVS_DIRECTORY_ADDRESS=0x055733000064333CaDDbC92763c58BF0192fFeBf
OPERATOR_UJI_ADDRESS=0x37893031A8484066232AcBE6bFe7E2a7A4411a7d

#UTILS
DEPLOYER_PK=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
GIZA_AVS_ADDRESS=0x6Da3D07a6BF01F02fB41c02984a49B5d9Aa6ea92
TASK_REGISTRY_ADDRESS=0xa8d297D643a11cE83b432e87eEBce6bee0fd2bAb
CLIENT_APP_REGISTRY_ADDRESS=0xb4e9A5BC64DC07f890367F72941403EEd7faDCbB
OPERATOR_UJI_PK=0x2a7f875389f0ce57b6d3200fb88e9a95e864a2ff589e8b1b11e56faff32a1fc5
TASK_ID=0xc86aab04e8ef18a63006f43fa41a2a0150bae3dbe276d581fa8b5cde0ccbc966

-----------------------------: ##

___CONTRACTS___: ##

anvil: ## starts anvil
anvil --ipc --fork-url $(HOLESKY_RPC_URL)
anvil --ipc --fork-url $(HOLESKY_RPC_URL) --fork-block-number 2577255

build-contracts: ## builds all contracts
cd contracts && forge build
Expand All @@ -30,4 +38,5 @@ deploy-contracts: ## deploy contracts (you need to run anvil first in a separat

__TASKS__: ##
create-task: ## create a task (you need to run anvil first in a separate terminal and the contract deployed)
cast send $(TASK_REGISTRY_ADDRESS) "createTask(bytes32)" $(TASK_ID) --private-key $(DEPLOYER_PK) --rpc-url $(RPC_URL)
cast send $(TASK_REGISTRY_ADDRESS) "createTask(bytes32)" $(TASK_ID) --private-key $(DEPLOYER_PK) --rpc-url $(ANVIL_RPC_URL)

22 changes: 17 additions & 5 deletions contract-bindings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
use alloy::sol;
use alloy_primitives::{address, Address};

pub const TASK_REGISTRY_ADDRESS: Address = address!("e7f1725E7734CE288F8367e1Bb143E90bb3F0512");
pub const TASK_REGISTRY_ADDRESS: Address = address!("6Da3D07a6BF01F02fB41c02984a49B5d9Aa6ea92");
pub const CLIENT_APP_REGISTRY_ADDRESS: Address =
address!("5FbDB2315678afecb367f032d93F642f64180aa3");

// TODO(chalex-eth): For now we provide the path to the compiled contract, but once the contract is
// "frozen" we can provide static ABI
address!("a8d297D643a11cE83b432e87eEBce6bee0fd2bAb");
pub const AVS_DIRECTORY_ADDRESS: Address = address!("055733000064333CaDDbC92763c58BF0192fFeBf");
pub const GIZA_AVS_ADDRESS: Address = address!("68d2Ecd85bDEbfFd075Fb6D87fFD829AD025DD5C");
pub const OPERATOR_UJI_ADDRESS: Address = address!("37893031A8484066232AcBE6bFe7E2a7A4411a7d");

sol!(
#[sol(rpc)]
Expand Down Expand Up @@ -59,6 +59,18 @@ sol!(
"../contracts/out/ClientAppRegistry.sol/ClientAppRegistry.json"
);

sol!(
#[sol(rpc)]
GizaAVS,
"../contracts/out/GizaAVS.sol/GizaAVS.json"
);

sol! {
#[sol(rpc)]
interface AVSDirectory {
function calculateOperatorAVSRegistrationDigestHash(address operator, address avs, bytes32 salt, uint256 expiry) external view returns (bytes32);
}}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
142 changes: 117 additions & 25 deletions operator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ use alloy::{
BlobGasFiller, ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller,
WalletFiller,
},
Identity, IpcConnect, Provider, ProviderBuilder, RootProvider,
Identity, IpcConnect, ProviderBuilder, RootProvider,
},
pubsub::PubSubFrontend,
signers::{local::PrivateKeySigner, Signer},
transports::http::{Client, Http},
};
use alloy_primitives::{Address, Bytes, FixedBytes, U256};
use alloy_primitives::{Address, FixedBytes, U256};
use contract_bindings::{
AVSDirectory::{self, AVSDirectoryInstance},
ClientAppRegistry::{self, ClientAppMetadata, ClientAppRegistryInstance},
GizaAVS::{self, GizaAVSInstance},
AVSDirectory::AVSDirectoryInstance,
ClientAppRegistry::{ClientAppMetadata, ClientAppRegistryInstance},
GizaAVS::GizaAVSInstance,
ISignatureUtils::SignatureWithSaltAndExpiry,
TaskRegistry::{self, TaskRegistryInstance},
AVS_DIRECTORY_ADDRESS, CLIENT_APP_REGISTRY_ADDRESS, GIZA_AVS_ADDRESS, TASK_REGISTRY_ADDRESS,
Expand All @@ -30,21 +30,6 @@ use tokio::{
};
use tracing::{error, info, warn};

pub type PubSubProviderWithSigner = Arc<
FillProvider<
JoinFill<
JoinFill<
Identity,
JoinFill<GasFiller, JoinFill<BlobGasFiller, JoinFill<NonceFiller, ChainIdFiller>>>,
>,
WalletFiller<EthereumWallet>,
>,
RootProvider<PubSubFrontend>,
PubSubFrontend,
Ethereum,
>,
>;

pub type HttpProviderWithSigner = Arc<
FillProvider<
JoinFill<
Expand All @@ -66,7 +51,7 @@ const QUEUE_CAPACITY: usize = 100;
#[derive(Clone)]
pub struct Operator {
operator_address: Address,
pubsub_provider: PubSubProviderWithSigner,
pubsub_provider: Arc<RootProvider<PubSubFrontend>>,
http_provider: HttpProviderWithSigner,
signer: PrivateKeySigner,
}
Expand All @@ -84,10 +69,8 @@ impl Operator {
//Create PubSubProvider
let ipc_path = "/tmp/anvil.ipc";
let ipc = IpcConnect::new(ipc_path.to_string());
let pubsub_provider = Arc::new(
let pubsub_provider: Arc<RootProvider<PubSubFrontend>> = Arc::new(
ProviderBuilder::new()
.with_recommended_fillers()
.wallet(wallet.clone())
.on_ipc(ipc)
.await
.wrap_err("Failed to create provider")?,
Expand Down Expand Up @@ -115,7 +98,7 @@ impl Operator {
pub async fn run(&self) -> Result<()> {
info!("Starting operator...");

// self.register_operator().await?;
self.register_operator_in_avs().await?;

self.fetch_client_app().await?;

Expand All @@ -136,6 +119,115 @@ impl Operator {
Ok(())
}

async fn register_operator_in_avs(&self) -> Result<()> {
let giza_avs = GizaAVSInstance::new(GIZA_AVS_ADDRESS, self.http_provider.clone());
let avs_directory =
AVSDirectoryInstance::new(AVS_DIRECTORY_ADDRESS, self.http_provider.clone());

// Register operator in GizaAVS
let is_operator_registered = giza_avs
.isOperatorRegistered(self.operator_address)
.call()
.await?
.isRegistered;

if is_operator_registered {
info!("Operator already registered");
return Ok(());
}

let salt = FixedBytes::<32>::from_str(
"0x2ef06b8bbad022ca2dd29795902ceb588d06d1cfd10cb6e687db0dbb837865e9",
)
.unwrap();
let expiry = U256::from(1779248899);

// Eigenlayer provide a view function to calculate the digest hash that needs to be signed
let digest_hash = avs_directory
.calculateOperatorAVSRegistrationDigestHash(
self.operator_address,
GIZA_AVS_ADDRESS,
salt,
expiry,
)
.call()
.await?
._0;

// We signed the hash
let signed_digest = self.signer.sign_hash(&digest_hash).await?;

// Broadcast tx to register in EL contracts and GizaAVS contracts
let tx = giza_avs
.registerOperatorToAVS(
self.operator_address,
SignatureWithSaltAndExpiry {
signature: signed_digest.as_bytes().into(),
salt,
expiry,
},
)
.send()
.await?
.watch()
.await?;
info!("GizaAVS registration submitted {:?}", tx);

// Check if the operator is registered
let is_operator_registered = giza_avs
.isOperatorRegistered(self.operator_address)
.call()
.await?
.isRegistered;

match is_operator_registered {
true => info!("Successfully registered operator in GizaAVS"),
false => {
return Err(eyre::eyre!("Operator registration failed"));
}
}

// Register client app in GizaAVS
let client_app_id: FixedBytes<32> = FixedBytes::<32>::from_str(
"0xc86aab04e8ef18a63006f43fa41a2a0150bae3dbe276d581fa8b5cde0ccbc966",
)
.unwrap();

let is_client_app_registered = giza_avs
.operatorClientAppIdRegistrationStatus(self.operator_address, client_app_id.clone())
.call()
.await?
.isRegistered;

if is_client_app_registered {
info!("Client app already registered");
return Ok(());
}

let tx = giza_avs
.optInClientAppId(client_app_id)
.send()
.await?
.watch()
.await?;
info!("Client app registration submitted {:?}", tx);

let is_client_app_registered = giza_avs
.operatorClientAppIdRegistrationStatus(self.operator_address, client_app_id.clone())
.call()
.await?
.isRegistered;

match is_client_app_registered {
true => info!("Successfully registered client app in GizaAVS"),
false => {
return Err(eyre::eyre!("Client app registration failed"));
}
}

Ok(())
}

async fn fetch_client_app(&self) -> Result<()> {
let client_app_registry =
ClientAppRegistryInstance::new(CLIENT_APP_REGISTRY_ADDRESS, self.http_provider.clone());
Expand Down

0 comments on commit 6af1499

Please sign in to comment.