From 3089d9ff12d8d8e90c9046bedf54ab36f27e57cb Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Sun, 17 Nov 2024 05:19:39 +0800 Subject: [PATCH] feat: add service context for restaking delegations/metadata from services --- blueprints/examples/src/eigen_context.rs | 4 +- blueprints/examples/src/lib.rs | 2 + blueprints/examples/src/main.rs | 3 +- blueprints/examples/src/services_context.rs | 63 ++++++++ macros/context-derive/src/services.rs | 156 +++++++++++++------- sdk/src/ctx.rs | 14 +- 6 files changed, 173 insertions(+), 69 deletions(-) create mode 100644 blueprints/examples/src/services_context.rs diff --git a/blueprints/examples/src/eigen_context.rs b/blueprints/examples/src/eigen_context.rs index ecc478b0..92a9900d 100644 --- a/blueprints/examples/src/eigen_context.rs +++ b/blueprints/examples/src/eigen_context.rs @@ -41,7 +41,7 @@ pub async fn constructor( get_provider_http(&env.http_rpc_endpoint), ); - Ok(FetchDetailsEventHandler::new( + Ok(HandleJobEventHandler::new( example_task_manager, ExampleEigenContext { std_config: env.clone(), @@ -59,7 +59,7 @@ pub async fn constructor( pre_processor = handle_events, ), )] -pub async fn fetch_details( +pub async fn handle_job( ctx: ExampleEigenContext, event: ExampleTaskManager::NewTaskCreated, log: alloy_rpc_types::Log, diff --git a/blueprints/examples/src/lib.rs b/blueprints/examples/src/lib.rs index fe46f449..05d04440 100644 --- a/blueprints/examples/src/lib.rs +++ b/blueprints/examples/src/lib.rs @@ -1,5 +1,7 @@ pub mod eigen_context; pub mod periodic_web_poller; pub mod raw_tangle_events; +pub mod services_context; + #[cfg(test)] mod tests; diff --git a/blueprints/examples/src/main.rs b/blueprints/examples/src/main.rs index a6e81e0b..3ffeff51 100644 --- a/blueprints/examples/src/main.rs +++ b/blueprints/examples/src/main.rs @@ -1,4 +1,4 @@ -use blueprint_examples::{eigen_context, periodic_web_poller, raw_tangle_events}; +use blueprint_examples::{eigen_context, periodic_web_poller, raw_tangle_events, services_context}; use gadget_sdk::info; use gadget_sdk::runners::eigenlayer::EigenlayerConfig; use gadget_sdk::runners::{tangle::TangleConfig, BlueprintRunner}; @@ -19,6 +19,7 @@ async fn main() -> Result<(), Box> { BlueprintRunner::new(TangleConfig::default(), env.clone()) .job(raw_tangle_events::constructor(env.clone()).await?) .job(periodic_web_poller::constructor()) + .job(services_context::constructor(env.clone()).await?) .run() .await?; } diff --git a/blueprints/examples/src/services_context.rs b/blueprints/examples/src/services_context.rs new file mode 100644 index 00000000..5c52de2e --- /dev/null +++ b/blueprints/examples/src/services_context.rs @@ -0,0 +1,63 @@ +use gadget_sdk::ctx::TangleClientContext; +use gadget_sdk::event_listener::tangle::jobs::{services_post_processor, services_pre_processor}; +use gadget_sdk::event_listener::tangle::TangleEventListener; +use gadget_sdk::event_utils::InitializableEventHandler; +use gadget_sdk::job; +use gadget_sdk::subxt_core::utils::AccountId32; +use gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::services::events::JobCalled; +use gadget_sdk::{config::StdGadgetConfiguration, ctx::ServicesContext}; + +#[derive(Clone, ServicesContext, TangleClientContext)] +pub struct ExampleServiceContext { + #[config] + sdk_config: StdGadgetConfiguration, +} + +pub async fn constructor( + env: StdGadgetConfiguration, +) -> color_eyre::Result { + use gadget_sdk::subxt_core::tx::signer::Signer; + + let signer = env + .clone() + .first_sr25519_signer() + .map_err(|e| color_eyre::eyre::eyre!(e))?; + + gadget_sdk::info!("Starting the event watcher for {} ...", signer.account_id()); + HandleJobEventHandler::new(&env.clone(), ExampleServiceContext { sdk_config: env }) + .await + .map_err(|e| color_eyre::eyre::eyre!(e)) +} + +#[job( + id = 2, + params(job_details), + event_listener( + listener = TangleEventListener, + pre_processor = services_pre_processor, + post_processor = services_post_processor + ), +)] +pub async fn handle_job( + job_details: Vec, + context: ExampleServiceContext, +) -> Result { + let client = context.tangle_client().await.unwrap(); + let blueprint_owner = context.current_blueprint_owner(&client).await.unwrap(); + let blueprint = context.current_blueprint(&client).await.unwrap(); + let operators_and_percents = context.current_service_operators(&client).await.unwrap(); + let operators = operators_and_percents + .iter() + .map(|(op, per)| op) + .cloned() + .collect::>(); + let restaking_delegations = context + .get_operator_delegations(&client, operators.clone()) + .await + .unwrap(); + let operators_metadata = context + .get_operators_metadata(&client, operators) + .await + .unwrap(); + Ok(0) +} diff --git a/macros/context-derive/src/services.rs b/macros/context-derive/src/services.rs index 74724484..3fe5ed2f 100644 --- a/macros/context-derive/src/services.rs +++ b/macros/context-derive/src/services.rs @@ -31,14 +31,20 @@ pub fn generate_context_impl( gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::ServiceBlueprint, gadget_sdk::ext::subxt::Error > - > { - use gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api; + >{ use gadget_sdk::ext::subxt; + use gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api; async move { let blueprint_id = match #field_access.protocol_specific { - gadget_sdk::config::ProtocolSpecificSettings::Tangle(settings) => settings.blueprint_id, - _ => return Err(subxt::Error::Other("Blueprint id is only available for Tangle protocol".to_string())), + gadget_sdk::config::ProtocolSpecificSettings::Tangle(settings) => { + settings.blueprint_id + } + _ => { + return Err(subxt::Error::Other( + "Blueprint id is only available for Tangle protocol".to_string(), + )) + } }; let blueprint = api::storage().services().blueprints(blueprint_id); let storage = client.storage().at_latest().await?; @@ -55,13 +61,21 @@ pub fn generate_context_impl( fn current_blueprint_owner( &self, client: &gadget_sdk::ext::subxt::OnlineClient, - ) -> impl core::future::Future> { - use gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api; + ) -> impl core::future::Future< + Output = Result, + > { use gadget_sdk::ext::subxt; + use gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api; async move { let blueprint_id = match #field_access.protocol_specific { - gadget_sdk::config::ProtocolSpecificSettings::Tangle(settings) => settings.blueprint_id, - _ => return Err(subxt::Error::Other("Blueprint id is only available for Tangle protocol".to_string())), + gadget_sdk::config::ProtocolSpecificSettings::Tangle(settings) => { + settings.blueprint_id + } + _ => { + return Err(subxt::Error::Other( + "Blueprint id is only available for Tangle protocol".to_string(), + )) + } }; let blueprint = api::storage().services().blueprints(blueprint_id); let storage = client.storage().at_latest().await?; @@ -86,18 +100,28 @@ pub fn generate_context_impl( )>, gadget_sdk::ext::subxt::Error > - > { - use gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api; + >{ use gadget_sdk::ext::subxt; + use gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api; async move { let service_instance_id = match #field_access.protocol_specific { - gadget_sdk::config::ProtocolSpecificSettings::Tangle(settings) => settings.service_id, - _ => return Err(subxt::Error::Other("Service instance id is only available for Tangle protocol".to_string())), + gadget_sdk::config::ProtocolSpecificSettings::Tangle(settings) => { + settings.service_id + } + _ => { + return Err(subxt::Error::Other( + "Service instance id is only available for Tangle protocol".to_string(), + )) + } }; let service_id = match service_instance_id { - Some(service_instance_id) => service_instance_id, - None => return Err(subxt::Error::Other("Service instance id is not set. Running in Registration mode?".to_string())), + Some(service_instance_id) => service_instance_id, + None => { + return Err(subxt::Error::Other( + "Service instance id is not set. Running in Registration mode?".to_string(), + )) + } }; let service_instance = api::storage().services().instances(service_id); let storage = client.storage().at_latest().await?; @@ -119,20 +143,25 @@ pub fn generate_context_impl( Output = Result< Vec<( gadget_sdk::ext::subxt::utils::AccountId32, - gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::runtime_types::pallet_multi_asset_delegation::types::OperatorMetadata, + gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::pallet_multi_asset_delegation::types::operator::OperatorMetadata< + gadget_sdk::ext::subxt::utils::AccountId32, // delegator + gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::assets::events::force_created::AssetId, + gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::assets::events::burned::Balance, + >, )>, gadget_sdk::ext::subxt::Error > - > { + >{ use gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api; - use gadget_sdk::ext::subxt; async move { let storage = client.storage().at_latest().await?; let mut operator_metadata = Vec::new(); for operator in operators { - let metadata_storage_key = api::storage().multi_asset_delegation().operators(operator.clone()); + let metadata_storage_key = api::storage() + .multi_asset_delegation() + .operators(operator.clone()); let operator_metadata_result = storage.fetch(&metadata_storage_key).await?; if let Some(metadata) = operator_metadata_result { operator_metadata.push((operator, metadata)); @@ -148,11 +177,16 @@ pub fn generate_context_impl( client: &gadget_sdk::ext::subxt::OnlineClient, operator: gadget_sdk::ext::subxt::utils::AccountId32, ) -> Result< - Option, + Option< + gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::pallet_multi_asset_delegation::types::operator::OperatorMetadata< + gadget_sdk::ext::subxt::utils::AccountId32, // delegator + gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::assets::events::force_created::AssetId, + gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::assets::events::burned::Balance, + > + >, gadget_sdk::ext::subxt::Error, - > { + >{ use gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api; - use gadget_sdk::ext::subxt; let storage = client.storage().at_latest().await?; let metadata_storage_key = api::storage().multi_asset_delegation().operators(operator); @@ -166,35 +200,35 @@ pub fn generate_context_impl( ) -> Result< Vec<( gadget_sdk::ext::subxt::utils::AccountId32, // operator - gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::runtime_types::sp_std::collections::btree_map::BTreeMap< - gadget_sdk::ext::subxt::utils::AccountId32, // delegator - gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::runtime_types::sp_std::collections::btree_map::BTreeMap< - gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::runtime_types::pallet_assets::types::AssetId, - gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::runtime_types::pallet_balances::types::Balance, + Option< + gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::pallet_multi_asset_delegation::types::delegator::DelegatorMetadata< + gadget_sdk::ext::subxt::utils::AccountId32, + gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::assets::events::force_created::AssetId, + gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::assets::events::burned::Balance, > > )>, gadget_sdk::ext::subxt::Error, - > { + >{ use gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api; - use gadget_sdk::ext::subxt; use gadget_sdk::ext::subxt::utils::AccountId32; - use gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::runtime_types::{ - sp_std::collections::btree_map::BTreeMap, - pallet_assets::types::AssetId, - pallet_balances::types::Balance, - }; + use gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::assets::events::force_created::AssetId; + use gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::assets::events::burned::Balance; + use gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::pallet_multi_asset_delegation::types::delegator::DelegatorMetadata; let storage = client.storage().at_latest().await?; - let mut operator_delegations: Vec<(AccountId32, BTreeMap>)> = Vec::new(); + let mut operator_delegations: Vec<( + AccountId32, + Option>, + )> = Vec::new(); for operator in operators { - let delegations_storage_key = api::storage().multi_asset_delegation().delegations_to(operator.clone()); + let delegations_storage_key = api::storage() + .multi_asset_delegation() + .delegators(operator.clone()); let delegations_result = storage.fetch(&delegations_storage_key).await?; - if let Some(delegations) = delegations_result { - operator_delegations.push((operator, delegations.0)); - } + operator_delegations.push((operator, delegations_result)) } Ok(operator_delegations) @@ -205,45 +239,55 @@ pub fn generate_context_impl( client: &gadget_sdk::ext::subxt::OnlineClient, operator: gadget_sdk::ext::subxt::utils::AccountId32, ) -> Result< - gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::runtime_types::sp_std::collections::btree_map::BTreeMap< - gadget_sdk::ext::subxt::utils::AccountId32, // delegator - gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::runtime_types::sp_std::collections::btree_map::BTreeMap< - gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::runtime_types::pallet_assets::types::AssetId, - gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::runtime_types::pallet_balances::types::Balance, + Option< + gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::pallet_multi_asset_delegation::types::delegator::DelegatorMetadata< + gadget_sdk::ext::subxt::utils::AccountId32, + gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::assets::events::force_created::AssetId, + gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::assets::events::burned::Balance, > >, gadget_sdk::ext::subxt::Error, - > { + >{ use gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api; - use gadget_sdk::ext::subxt; let storage = client.storage().at_latest().await?; - let delegations_storage_key = api::storage().multi_asset_delegation().delegations_to(operator); + let delegations_storage_key = api::storage().multi_asset_delegation().delegators(operator); let delegations_result = storage.fetch(&delegations_storage_key).await?; - match delegations_result { - Some(delegations) => Ok(delegations.0), - None => Ok(Default::default()), - } + Ok(delegations_result) } async fn get_service_instance( &self, client: &gadget_sdk::ext::subxt::OnlineClient, ) -> Result< - gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::runtime_types::pallet_services::types::Service, + gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::Service< + gadget_sdk::ext::subxt::utils::AccountId32, + gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::system::storage::types::number::Number, + gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api::assets::events::force_created::AssetId, + >, gadget_sdk::ext::subxt::Error, - > { - use gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api; + >{ use gadget_sdk::ext::subxt; + use gadget_sdk::ext::tangle_subxt::tangle_testnet_runtime::api; let service_instance_id = match &#field_access.protocol_specific { - gadget_sdk::config::ProtocolSpecificSettings::Tangle(settings) => settings.service_instance_id, - _ => return Err(subxt::Error::Other("Service instance id is only available for Tangle protocol".to_string())), + gadget_sdk::config::ProtocolSpecificSettings::Tangle(settings) => { + settings.service_id + } + _ => { + return Err(subxt::Error::Other( + "Service instance id is only available for Tangle protocol".to_string(), + )) + } }; let service_id = match service_instance_id { Some(service_instance_id) => service_instance_id, - None => return Err(subxt::Error::Other("Service instance id is not set. Running in Registration mode?".to_string())), + None => { + return Err(subxt::Error::Other( + "Service instance id is not set. Running in Registration mode?".to_string(), + )) + } }; let service_instance = api::storage().services().instances(service_id); let storage = client.storage().at_latest().await?; diff --git a/sdk/src/ctx.rs b/sdk/src/ctx.rs index a2812944..8e3def31 100644 --- a/sdk/src/ctx.rs +++ b/sdk/src/ctx.rs @@ -47,10 +47,10 @@ //! ``` use crate::keystore::backend::GenericKeyStore; -use alloc::collections::BTreeMap; use alloy_primitives::{Address, Bytes, FixedBytes, U256}; use tangle_subxt::tangle_testnet_runtime::api::assets::events::accounts_destroyed::AssetId; use tangle_subxt::tangle_testnet_runtime::api::assets::events::burned::Balance; +use tangle_subxt::tangle_testnet_runtime::api::runtime_types::pallet_multi_asset_delegation::types::delegator::DelegatorMetadata; use tangle_subxt::tangle_testnet_runtime::api::runtime_types::pallet_multi_asset_delegation::types::operator::OperatorMetadata; use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::Service; use tangle_subxt::tangle_testnet_runtime::api::system::storage::types::number::Number; @@ -150,7 +150,7 @@ pub trait ServicesContext { operator: subxt::utils::AccountId32, ) -> impl Future< Output = Result< - OperatorMetadata, + Option>, subxt::Error, >, >; @@ -170,10 +170,7 @@ pub trait ServicesContext { Output = Result< Vec<( subxt::utils::AccountId32, // operator - BTreeMap< - subxt::utils::AccountId32, // delegator - BTreeMap, - >, + Option>, )>, subxt::Error, >, @@ -186,10 +183,7 @@ pub trait ServicesContext { operator: subxt::utils::AccountId32, ) -> impl Future< Output = Result< - BTreeMap< - subxt::utils::AccountId32, // delegator - BTreeMap, - >, + Option>, subxt::Error, >, >;