From 04d93fd2f0348c1ac7322ef84d4d19a20483716b Mon Sep 17 00:00:00 2001 From: Fraser Hutchison Date: Wed, 8 Jan 2025 22:15:08 +0000 Subject: [PATCH] create price feed enum action and nest relevant actions inside --- .../src/generated/astria.protocol.fees.v1.rs | 21 +- .../astria.protocol.fees.v1.serde.rs | 124 +---- .../generated/astria.protocol.genesis.v1.rs | 8 +- .../astria.protocol.genesis.v1.serde.rs | 44 +- .../astria.protocol.transaction.v1.rs | 76 ++- .../astria.protocol.transaction.v1.serde.rs | 491 ++++++++++++------ crates/astria-core/src/protocol/fees/v1.rs | 6 +- ...ol__genesis__v1__tests__genesis_state.snap | 6 +- crates/astria-core/src/protocol/genesis/v1.rs | 37 +- .../transaction/v1/action/group/mod.rs | 83 +-- .../src/protocol/transaction/v1/action/mod.rs | 253 ++++----- .../src/genesis_example.rs | 6 +- .../impls/add_currency_pairs.rs | 187 ------- .../src/action_handler/impls/fee_change.rs | 7 +- .../src/action_handler/impls/mod.rs | 3 +- .../src/action_handler/impls/price_feed.rs | 298 +++++++++++ .../impls/remove_currency_pairs.rs | 170 ------ .../src/action_handler/impls/transaction.rs | 15 +- .../src/app/benchmark_and_test_utils.rs | 18 +- ...breaking_changes__app_hash_at_genesis.snap | 60 +-- ...hanges__app_hash_execute_every_action.snap | 64 +-- ...king_changes__app_hash_finalize_block.snap | 60 +-- .../src/app/tests_breaking_changes.rs | 25 +- .../src/app/tests_execute_transaction.rs | 14 +- crates/astria-sequencer/src/fees/component.rs | 15 +- crates/astria-sequencer/src/fees/mod.rs | 29 +- crates/astria-sequencer/src/fees/query.rs | 16 +- .../src/fees/storage/values.rs | 9 +- .../src/transaction/checks.rs | 3 +- .../astria/protocol/fees/v1/types.proto | 7 +- .../astria/protocol/genesis/v1/types.proto | 3 +- .../protocol/transaction/v1/action.proto | 27 +- 32 files changed, 1032 insertions(+), 1153 deletions(-) delete mode 100644 crates/astria-sequencer/src/action_handler/impls/add_currency_pairs.rs create mode 100644 crates/astria-sequencer/src/action_handler/impls/price_feed.rs delete mode 100644 crates/astria-sequencer/src/action_handler/impls/remove_currency_pairs.rs diff --git a/crates/astria-core/src/generated/astria.protocol.fees.v1.rs b/crates/astria-core/src/generated/astria.protocol.fees.v1.rs index 7fec6ae51..b0bee8e3b 100644 --- a/crates/astria-core/src/generated/astria.protocol.fees.v1.rs +++ b/crates/astria-core/src/generated/astria.protocol.fees.v1.rs @@ -225,29 +225,14 @@ impl ::prost::Name for IbcSudoChangeFeeComponents { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct AddCurrencyPairsFeeComponents { +pub struct PriceFeedFeeComponents { #[prost(message, optional, tag = "1")] pub base: ::core::option::Option, #[prost(message, optional, tag = "2")] pub multiplier: ::core::option::Option, } -impl ::prost::Name for AddCurrencyPairsFeeComponents { - const NAME: &'static str = "AddCurrencyPairsFeeComponents"; - const PACKAGE: &'static str = "astria.protocol.fees.v1"; - fn full_name() -> ::prost::alloc::string::String { - ::prost::alloc::format!("astria.protocol.fees.v1.{}", Self::NAME) - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct RemoveCurrencyPairsFeeComponents { - #[prost(message, optional, tag = "1")] - pub base: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub multiplier: ::core::option::Option, -} -impl ::prost::Name for RemoveCurrencyPairsFeeComponents { - const NAME: &'static str = "RemoveCurrencyPairsFeeComponents"; +impl ::prost::Name for PriceFeedFeeComponents { + const NAME: &'static str = "PriceFeedFeeComponents"; const PACKAGE: &'static str = "astria.protocol.fees.v1"; fn full_name() -> ::prost::alloc::string::String { ::prost::alloc::format!("astria.protocol.fees.v1.{}", Self::NAME) diff --git a/crates/astria-core/src/generated/astria.protocol.fees.v1.serde.rs b/crates/astria-core/src/generated/astria.protocol.fees.v1.serde.rs index b7fe2cf02..92475909c 100644 --- a/crates/astria-core/src/generated/astria.protocol.fees.v1.serde.rs +++ b/crates/astria-core/src/generated/astria.protocol.fees.v1.serde.rs @@ -1,111 +1,3 @@ -impl serde::Serialize for AddCurrencyPairsFeeComponents { - #[allow(deprecated)] - fn serialize(&self, serializer: S) -> std::result::Result - where - S: serde::Serializer, - { - use serde::ser::SerializeStruct; - let mut len = 0; - if self.base.is_some() { - len += 1; - } - if self.multiplier.is_some() { - len += 1; - } - let mut struct_ser = serializer.serialize_struct("astria.protocol.fees.v1.AddCurrencyPairsFeeComponents", len)?; - if let Some(v) = self.base.as_ref() { - struct_ser.serialize_field("base", v)?; - } - if let Some(v) = self.multiplier.as_ref() { - struct_ser.serialize_field("multiplier", v)?; - } - struct_ser.end() - } -} -impl<'de> serde::Deserialize<'de> for AddCurrencyPairsFeeComponents { - #[allow(deprecated)] - fn deserialize(deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - const FIELDS: &[&str] = &[ - "base", - "multiplier", - ]; - - #[allow(clippy::enum_variant_names)] - enum GeneratedField { - Base, - Multiplier, - } - impl<'de> serde::Deserialize<'de> for GeneratedField { - fn deserialize(deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - struct GeneratedVisitor; - - impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { - type Value = GeneratedField; - - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(formatter, "expected one of: {:?}", &FIELDS) - } - - #[allow(unused_variables)] - fn visit_str(self, value: &str) -> std::result::Result - where - E: serde::de::Error, - { - match value { - "base" => Ok(GeneratedField::Base), - "multiplier" => Ok(GeneratedField::Multiplier), - _ => Err(serde::de::Error::unknown_field(value, FIELDS)), - } - } - } - deserializer.deserialize_identifier(GeneratedVisitor) - } - } - struct GeneratedVisitor; - impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { - type Value = AddCurrencyPairsFeeComponents; - - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str("struct astria.protocol.fees.v1.AddCurrencyPairsFeeComponents") - } - - fn visit_map(self, mut map_: V) -> std::result::Result - where - V: serde::de::MapAccess<'de>, - { - let mut base__ = None; - let mut multiplier__ = None; - while let Some(k) = map_.next_key()? { - match k { - GeneratedField::Base => { - if base__.is_some() { - return Err(serde::de::Error::duplicate_field("base")); - } - base__ = map_.next_value()?; - } - GeneratedField::Multiplier => { - if multiplier__.is_some() { - return Err(serde::de::Error::duplicate_field("multiplier")); - } - multiplier__ = map_.next_value()?; - } - } - } - Ok(AddCurrencyPairsFeeComponents { - base: base__, - multiplier: multiplier__, - }) - } - } - deserializer.deserialize_struct("astria.protocol.fees.v1.AddCurrencyPairsFeeComponents", FIELDS, GeneratedVisitor) - } -} impl serde::Serialize for BridgeLockFeeComponents { #[allow(deprecated)] fn serialize(&self, serializer: S) -> std::result::Result @@ -1186,7 +1078,7 @@ impl<'de> serde::Deserialize<'de> for InitBridgeAccountFeeComponents { deserializer.deserialize_struct("astria.protocol.fees.v1.InitBridgeAccountFeeComponents", FIELDS, GeneratedVisitor) } } -impl serde::Serialize for RemoveCurrencyPairsFeeComponents { +impl serde::Serialize for PriceFeedFeeComponents { #[allow(deprecated)] fn serialize(&self, serializer: S) -> std::result::Result where @@ -1200,7 +1092,7 @@ impl serde::Serialize for RemoveCurrencyPairsFeeComponents { if self.multiplier.is_some() { len += 1; } - let mut struct_ser = serializer.serialize_struct("astria.protocol.fees.v1.RemoveCurrencyPairsFeeComponents", len)?; + let mut struct_ser = serializer.serialize_struct("astria.protocol.fees.v1.PriceFeedFeeComponents", len)?; if let Some(v) = self.base.as_ref() { struct_ser.serialize_field("base", v)?; } @@ -1210,7 +1102,7 @@ impl serde::Serialize for RemoveCurrencyPairsFeeComponents { struct_ser.end() } } -impl<'de> serde::Deserialize<'de> for RemoveCurrencyPairsFeeComponents { +impl<'de> serde::Deserialize<'de> for PriceFeedFeeComponents { #[allow(deprecated)] fn deserialize(deserializer: D) -> std::result::Result where @@ -1257,13 +1149,13 @@ impl<'de> serde::Deserialize<'de> for RemoveCurrencyPairsFeeComponents { } struct GeneratedVisitor; impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { - type Value = RemoveCurrencyPairsFeeComponents; + type Value = PriceFeedFeeComponents; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str("struct astria.protocol.fees.v1.RemoveCurrencyPairsFeeComponents") + formatter.write_str("struct astria.protocol.fees.v1.PriceFeedFeeComponents") } - fn visit_map(self, mut map_: V) -> std::result::Result + fn visit_map(self, mut map_: V) -> std::result::Result where V: serde::de::MapAccess<'de>, { @@ -1285,13 +1177,13 @@ impl<'de> serde::Deserialize<'de> for RemoveCurrencyPairsFeeComponents { } } } - Ok(RemoveCurrencyPairsFeeComponents { + Ok(PriceFeedFeeComponents { base: base__, multiplier: multiplier__, }) } } - deserializer.deserialize_struct("astria.protocol.fees.v1.RemoveCurrencyPairsFeeComponents", FIELDS, GeneratedVisitor) + deserializer.deserialize_struct("astria.protocol.fees.v1.PriceFeedFeeComponents", FIELDS, GeneratedVisitor) } } impl serde::Serialize for RollupDataSubmissionFeeComponents { diff --git a/crates/astria-core/src/generated/astria.protocol.genesis.v1.rs b/crates/astria-core/src/generated/astria.protocol.genesis.v1.rs index 93d8b795d..a6e8aa564 100644 --- a/crates/astria-core/src/generated/astria.protocol.genesis.v1.rs +++ b/crates/astria-core/src/generated/astria.protocol.genesis.v1.rs @@ -148,12 +148,8 @@ pub struct GenesisFees { super::super::fees::v1::ValidatorUpdateFeeComponents, >, #[prost(message, optional, tag = "15")] - pub add_currency_pairs: ::core::option::Option< - super::super::fees::v1::AddCurrencyPairsFeeComponents, - >, - #[prost(message, optional, tag = "16")] - pub remove_currency_pairs: ::core::option::Option< - super::super::fees::v1::RemoveCurrencyPairsFeeComponents, + pub price_feed: ::core::option::Option< + super::super::fees::v1::PriceFeedFeeComponents, >, } impl ::prost::Name for GenesisFees { diff --git a/crates/astria-core/src/generated/astria.protocol.genesis.v1.serde.rs b/crates/astria-core/src/generated/astria.protocol.genesis.v1.serde.rs index acfcfa6c8..6c6cb1c03 100644 --- a/crates/astria-core/src/generated/astria.protocol.genesis.v1.serde.rs +++ b/crates/astria-core/src/generated/astria.protocol.genesis.v1.serde.rs @@ -643,10 +643,7 @@ impl serde::Serialize for GenesisFees { if self.validator_update.is_some() { len += 1; } - if self.add_currency_pairs.is_some() { - len += 1; - } - if self.remove_currency_pairs.is_some() { + if self.price_feed.is_some() { len += 1; } let mut struct_ser = serializer.serialize_struct("astria.protocol.genesis.v1.GenesisFees", len)?; @@ -692,11 +689,8 @@ impl serde::Serialize for GenesisFees { if let Some(v) = self.validator_update.as_ref() { struct_ser.serialize_field("validatorUpdate", v)?; } - if let Some(v) = self.add_currency_pairs.as_ref() { - struct_ser.serialize_field("addCurrencyPairs", v)?; - } - if let Some(v) = self.remove_currency_pairs.as_ref() { - struct_ser.serialize_field("removeCurrencyPairs", v)?; + if let Some(v) = self.price_feed.as_ref() { + struct_ser.serialize_field("priceFeed", v)?; } struct_ser.end() } @@ -735,10 +729,8 @@ impl<'de> serde::Deserialize<'de> for GenesisFees { "transfer", "validator_update", "validatorUpdate", - "add_currency_pairs", - "addCurrencyPairs", - "remove_currency_pairs", - "removeCurrencyPairs", + "price_feed", + "priceFeed", ]; #[allow(clippy::enum_variant_names)] @@ -757,8 +749,7 @@ impl<'de> serde::Deserialize<'de> for GenesisFees { SudoAddressChange, Transfer, ValidatorUpdate, - AddCurrencyPairs, - RemoveCurrencyPairs, + PriceFeed, } impl<'de> serde::Deserialize<'de> for GeneratedField { fn deserialize(deserializer: D) -> std::result::Result @@ -794,8 +785,7 @@ impl<'de> serde::Deserialize<'de> for GenesisFees { "sudoAddressChange" | "sudo_address_change" => Ok(GeneratedField::SudoAddressChange), "transfer" => Ok(GeneratedField::Transfer), "validatorUpdate" | "validator_update" => Ok(GeneratedField::ValidatorUpdate), - "addCurrencyPairs" | "add_currency_pairs" => Ok(GeneratedField::AddCurrencyPairs), - "removeCurrencyPairs" | "remove_currency_pairs" => Ok(GeneratedField::RemoveCurrencyPairs), + "priceFeed" | "price_feed" => Ok(GeneratedField::PriceFeed), _ => Err(serde::de::Error::unknown_field(value, FIELDS)), } } @@ -829,8 +819,7 @@ impl<'de> serde::Deserialize<'de> for GenesisFees { let mut sudo_address_change__ = None; let mut transfer__ = None; let mut validator_update__ = None; - let mut add_currency_pairs__ = None; - let mut remove_currency_pairs__ = None; + let mut price_feed__ = None; while let Some(k) = map_.next_key()? { match k { GeneratedField::BridgeLock => { @@ -917,17 +906,11 @@ impl<'de> serde::Deserialize<'de> for GenesisFees { } validator_update__ = map_.next_value()?; } - GeneratedField::AddCurrencyPairs => { - if add_currency_pairs__.is_some() { - return Err(serde::de::Error::duplicate_field("addCurrencyPairs")); - } - add_currency_pairs__ = map_.next_value()?; - } - GeneratedField::RemoveCurrencyPairs => { - if remove_currency_pairs__.is_some() { - return Err(serde::de::Error::duplicate_field("removeCurrencyPairs")); + GeneratedField::PriceFeed => { + if price_feed__.is_some() { + return Err(serde::de::Error::duplicate_field("priceFeed")); } - remove_currency_pairs__ = map_.next_value()?; + price_feed__ = map_.next_value()?; } } } @@ -946,8 +929,7 @@ impl<'de> serde::Deserialize<'de> for GenesisFees { sudo_address_change: sudo_address_change__, transfer: transfer__, validator_update: validator_update__, - add_currency_pairs: add_currency_pairs__, - remove_currency_pairs: remove_currency_pairs__, + price_feed: price_feed__, }) } } diff --git a/crates/astria-core/src/generated/astria.protocol.transaction.v1.rs b/crates/astria-core/src/generated/astria.protocol.transaction.v1.rs index 27d3782a5..7da223c23 100644 --- a/crates/astria-core/src/generated/astria.protocol.transaction.v1.rs +++ b/crates/astria-core/src/generated/astria.protocol.transaction.v1.rs @@ -3,7 +3,7 @@ pub struct Action { #[prost( oneof = "action::Value", - tags = "1, 2, 11, 12, 13, 14, 21, 22, 50, 51, 52, 53, 55, 56, 71, 72" + tags = "1, 2, 11, 12, 13, 14, 21, 22, 50, 51, 52, 53, 55, 56, 71" )] pub value: ::core::option::Option, } @@ -46,11 +46,9 @@ pub mod action { FeeChange(super::FeeChange), #[prost(message, tag = "56")] IbcSudoChange(super::IbcSudoChange), - /// Oracle actions are defined on 71-80 + /// Price feed actions are defined on 71-80 #[prost(message, tag = "71")] - AddCurrencyPairs(super::AddCurrencyPairs), - #[prost(message, tag = "72")] - RemoveCurrencyPairs(super::RemoveCurrencyPairs), + PriceFeed(super::PriceFeed), } } impl ::prost::Name for Action { @@ -407,7 +405,7 @@ pub struct FeeChange { /// the new fee components values #[prost( oneof = "fee_change::FeeComponents", - tags = "1, 2, 3, 4, 5, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16" + tags = "1, 2, 3, 4, 5, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15" )] pub fee_components: ::core::option::Option, } @@ -448,11 +446,7 @@ pub mod fee_change { #[prost(message, tag = "14")] ValidatorUpdate(super::super::super::fees::v1::ValidatorUpdateFeeComponents), #[prost(message, tag = "15")] - AddCurrencyPairs(super::super::super::fees::v1::AddCurrencyPairsFeeComponents), - #[prost(message, tag = "16")] - RemoveCurrencyPairs( - super::super::super::fees::v1::RemoveCurrencyPairsFeeComponents, - ), + PriceFeed(super::super::super::fees::v1::PriceFeedFeeComponents), } } impl ::prost::Name for FeeChange { @@ -475,16 +469,64 @@ impl ::prost::Name for IbcSudoChange { ::prost::alloc::format!("astria.protocol.transaction.v1.{}", Self::NAME) } } +/// A transaction that modifies the price feed oracle settings. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PriceFeed { + #[prost(oneof = "price_feed::Value", tags = "1")] + pub value: ::core::option::Option, +} +/// Nested message and enum types in `PriceFeed`. +pub mod price_feed { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Value { + #[prost(message, tag = "1")] + Oracle(super::CurrencyPairsChange), + } +} +impl ::prost::Name for PriceFeed { + const NAME: &'static str = "PriceFeed"; + const PACKAGE: &'static str = "astria.protocol.transaction.v1"; + fn full_name() -> ::prost::alloc::string::String { + ::prost::alloc::format!("astria.protocol.transaction.v1.{}", Self::NAME) + } +} +/// Add or remove currency pairs to/from the price feed oracle. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CurrencyPairsChange { + #[prost(oneof = "currency_pairs_change::Value", tags = "1, 2")] + pub value: ::core::option::Option, +} +/// Nested message and enum types in `CurrencyPairsChange`. +pub mod currency_pairs_change { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Value { + #[prost(message, tag = "1")] + Addition(super::CurrencyPairsToAdd), + #[prost(message, tag = "2")] + Removal(super::CurrencyPairsToRemove), + } +} +impl ::prost::Name for CurrencyPairsChange { + const NAME: &'static str = "CurrencyPairsChange"; + const PACKAGE: &'static str = "astria.protocol.transaction.v1"; + fn full_name() -> ::prost::alloc::string::String { + ::prost::alloc::format!("astria.protocol.transaction.v1.{}", Self::NAME) + } +} #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct AddCurrencyPairs { +pub struct CurrencyPairsToAdd { #[prost(message, repeated, tag = "1")] pub pairs: ::prost::alloc::vec::Vec< super::super::super::super::connect::types::v2::CurrencyPair, >, } -impl ::prost::Name for AddCurrencyPairs { - const NAME: &'static str = "AddCurrencyPairs"; +impl ::prost::Name for CurrencyPairsToAdd { + const NAME: &'static str = "CurrencyPairsToAdd"; const PACKAGE: &'static str = "astria.protocol.transaction.v1"; fn full_name() -> ::prost::alloc::string::String { ::prost::alloc::format!("astria.protocol.transaction.v1.{}", Self::NAME) @@ -492,14 +534,14 @@ impl ::prost::Name for AddCurrencyPairs { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct RemoveCurrencyPairs { +pub struct CurrencyPairsToRemove { #[prost(message, repeated, tag = "1")] pub pairs: ::prost::alloc::vec::Vec< super::super::super::super::connect::types::v2::CurrencyPair, >, } -impl ::prost::Name for RemoveCurrencyPairs { - const NAME: &'static str = "RemoveCurrencyPairs"; +impl ::prost::Name for CurrencyPairsToRemove { + const NAME: &'static str = "CurrencyPairsToRemove"; const PACKAGE: &'static str = "astria.protocol.transaction.v1"; fn full_name() -> ::prost::alloc::string::String { ::prost::alloc::format!("astria.protocol.transaction.v1.{}", Self::NAME) diff --git a/crates/astria-core/src/generated/astria.protocol.transaction.v1.serde.rs b/crates/astria-core/src/generated/astria.protocol.transaction.v1.serde.rs index a17822602..878ab70aa 100644 --- a/crates/astria-core/src/generated/astria.protocol.transaction.v1.serde.rs +++ b/crates/astria-core/src/generated/astria.protocol.transaction.v1.serde.rs @@ -54,11 +54,8 @@ impl serde::Serialize for Action { action::Value::IbcSudoChange(v) => { struct_ser.serialize_field("ibcSudoChange", v)?; } - action::Value::AddCurrencyPairs(v) => { - struct_ser.serialize_field("addCurrencyPairs", v)?; - } - action::Value::RemoveCurrencyPairs(v) => { - struct_ser.serialize_field("removeCurrencyPairs", v)?; + action::Value::PriceFeed(v) => { + struct_ser.serialize_field("priceFeed", v)?; } } } @@ -98,10 +95,8 @@ impl<'de> serde::Deserialize<'de> for Action { "feeChange", "ibc_sudo_change", "ibcSudoChange", - "add_currency_pairs", - "addCurrencyPairs", - "remove_currency_pairs", - "removeCurrencyPairs", + "price_feed", + "priceFeed", ]; #[allow(clippy::enum_variant_names)] @@ -120,8 +115,7 @@ impl<'de> serde::Deserialize<'de> for Action { FeeAssetChange, FeeChange, IbcSudoChange, - AddCurrencyPairs, - RemoveCurrencyPairs, + PriceFeed, } impl<'de> serde::Deserialize<'de> for GeneratedField { fn deserialize(deserializer: D) -> std::result::Result @@ -157,8 +151,7 @@ impl<'de> serde::Deserialize<'de> for Action { "feeAssetChange" | "fee_asset_change" => Ok(GeneratedField::FeeAssetChange), "feeChange" | "fee_change" => Ok(GeneratedField::FeeChange), "ibcSudoChange" | "ibc_sudo_change" => Ok(GeneratedField::IbcSudoChange), - "addCurrencyPairs" | "add_currency_pairs" => Ok(GeneratedField::AddCurrencyPairs), - "removeCurrencyPairs" | "remove_currency_pairs" => Ok(GeneratedField::RemoveCurrencyPairs), + "priceFeed" | "price_feed" => Ok(GeneratedField::PriceFeed), _ => Err(serde::de::Error::unknown_field(value, FIELDS)), } } @@ -279,18 +272,11 @@ impl<'de> serde::Deserialize<'de> for Action { value__ = map_.next_value::<::std::option::Option<_>>()?.map(action::Value::IbcSudoChange) ; } - GeneratedField::AddCurrencyPairs => { - if value__.is_some() { - return Err(serde::de::Error::duplicate_field("addCurrencyPairs")); - } - value__ = map_.next_value::<::std::option::Option<_>>()?.map(action::Value::AddCurrencyPairs) -; - } - GeneratedField::RemoveCurrencyPairs => { + GeneratedField::PriceFeed => { if value__.is_some() { - return Err(serde::de::Error::duplicate_field("removeCurrencyPairs")); + return Err(serde::de::Error::duplicate_field("priceFeed")); } - value__ = map_.next_value::<::std::option::Option<_>>()?.map(action::Value::RemoveCurrencyPairs) + value__ = map_.next_value::<::std::option::Option<_>>()?.map(action::Value::PriceFeed) ; } } @@ -303,97 +289,6 @@ impl<'de> serde::Deserialize<'de> for Action { deserializer.deserialize_struct("astria.protocol.transaction.v1.Action", FIELDS, GeneratedVisitor) } } -impl serde::Serialize for AddCurrencyPairs { - #[allow(deprecated)] - fn serialize(&self, serializer: S) -> std::result::Result - where - S: serde::Serializer, - { - use serde::ser::SerializeStruct; - let mut len = 0; - if !self.pairs.is_empty() { - len += 1; - } - let mut struct_ser = serializer.serialize_struct("astria.protocol.transaction.v1.AddCurrencyPairs", len)?; - if !self.pairs.is_empty() { - struct_ser.serialize_field("pairs", &self.pairs)?; - } - struct_ser.end() - } -} -impl<'de> serde::Deserialize<'de> for AddCurrencyPairs { - #[allow(deprecated)] - fn deserialize(deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - const FIELDS: &[&str] = &[ - "pairs", - ]; - - #[allow(clippy::enum_variant_names)] - enum GeneratedField { - Pairs, - } - impl<'de> serde::Deserialize<'de> for GeneratedField { - fn deserialize(deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - struct GeneratedVisitor; - - impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { - type Value = GeneratedField; - - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(formatter, "expected one of: {:?}", &FIELDS) - } - - #[allow(unused_variables)] - fn visit_str(self, value: &str) -> std::result::Result - where - E: serde::de::Error, - { - match value { - "pairs" => Ok(GeneratedField::Pairs), - _ => Err(serde::de::Error::unknown_field(value, FIELDS)), - } - } - } - deserializer.deserialize_identifier(GeneratedVisitor) - } - } - struct GeneratedVisitor; - impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { - type Value = AddCurrencyPairs; - - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str("struct astria.protocol.transaction.v1.AddCurrencyPairs") - } - - fn visit_map(self, mut map_: V) -> std::result::Result - where - V: serde::de::MapAccess<'de>, - { - let mut pairs__ = None; - while let Some(k) = map_.next_key()? { - match k { - GeneratedField::Pairs => { - if pairs__.is_some() { - return Err(serde::de::Error::duplicate_field("pairs")); - } - pairs__ = Some(map_.next_value()?); - } - } - } - Ok(AddCurrencyPairs { - pairs: pairs__.unwrap_or_default(), - }) - } - } - deserializer.deserialize_struct("astria.protocol.transaction.v1.AddCurrencyPairs", FIELDS, GeneratedVisitor) - } -} impl serde::Serialize for BridgeLock { #[allow(deprecated)] fn serialize(&self, serializer: S) -> std::result::Result @@ -901,6 +796,297 @@ impl<'de> serde::Deserialize<'de> for BridgeUnlock { deserializer.deserialize_struct("astria.protocol.transaction.v1.BridgeUnlock", FIELDS, GeneratedVisitor) } } +impl serde::Serialize for CurrencyPairsChange { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.value.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("astria.protocol.transaction.v1.CurrencyPairsChange", len)?; + if let Some(v) = self.value.as_ref() { + match v { + currency_pairs_change::Value::Addition(v) => { + struct_ser.serialize_field("addition", v)?; + } + currency_pairs_change::Value::Removal(v) => { + struct_ser.serialize_field("removal", v)?; + } + } + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for CurrencyPairsChange { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "addition", + "removal", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Addition, + Removal, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "addition" => Ok(GeneratedField::Addition), + "removal" => Ok(GeneratedField::Removal), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = CurrencyPairsChange; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct astria.protocol.transaction.v1.CurrencyPairsChange") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut value__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Addition => { + if value__.is_some() { + return Err(serde::de::Error::duplicate_field("addition")); + } + value__ = map_.next_value::<::std::option::Option<_>>()?.map(currency_pairs_change::Value::Addition) +; + } + GeneratedField::Removal => { + if value__.is_some() { + return Err(serde::de::Error::duplicate_field("removal")); + } + value__ = map_.next_value::<::std::option::Option<_>>()?.map(currency_pairs_change::Value::Removal) +; + } + } + } + Ok(CurrencyPairsChange { + value: value__, + }) + } + } + deserializer.deserialize_struct("astria.protocol.transaction.v1.CurrencyPairsChange", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for CurrencyPairsToAdd { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.pairs.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("astria.protocol.transaction.v1.CurrencyPairsToAdd", len)?; + if !self.pairs.is_empty() { + struct_ser.serialize_field("pairs", &self.pairs)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for CurrencyPairsToAdd { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "pairs", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Pairs, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "pairs" => Ok(GeneratedField::Pairs), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = CurrencyPairsToAdd; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct astria.protocol.transaction.v1.CurrencyPairsToAdd") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut pairs__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Pairs => { + if pairs__.is_some() { + return Err(serde::de::Error::duplicate_field("pairs")); + } + pairs__ = Some(map_.next_value()?); + } + } + } + Ok(CurrencyPairsToAdd { + pairs: pairs__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("astria.protocol.transaction.v1.CurrencyPairsToAdd", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for CurrencyPairsToRemove { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.pairs.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("astria.protocol.transaction.v1.CurrencyPairsToRemove", len)?; + if !self.pairs.is_empty() { + struct_ser.serialize_field("pairs", &self.pairs)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for CurrencyPairsToRemove { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "pairs", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Pairs, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "pairs" => Ok(GeneratedField::Pairs), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = CurrencyPairsToRemove; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct astria.protocol.transaction.v1.CurrencyPairsToRemove") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut pairs__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Pairs => { + if pairs__.is_some() { + return Err(serde::de::Error::duplicate_field("pairs")); + } + pairs__ = Some(map_.next_value()?); + } + } + } + Ok(CurrencyPairsToRemove { + pairs: pairs__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("astria.protocol.transaction.v1.CurrencyPairsToRemove", FIELDS, GeneratedVisitor) + } +} impl serde::Serialize for FeeAssetChange { #[allow(deprecated)] fn serialize(&self, serializer: S) -> std::result::Result @@ -1064,11 +1250,8 @@ impl serde::Serialize for FeeChange { fee_change::FeeComponents::ValidatorUpdate(v) => { struct_ser.serialize_field("validatorUpdate", v)?; } - fee_change::FeeComponents::AddCurrencyPairs(v) => { - struct_ser.serialize_field("addCurrencyPairs", v)?; - } - fee_change::FeeComponents::RemoveCurrencyPairs(v) => { - struct_ser.serialize_field("removeCurrencyPairs", v)?; + fee_change::FeeComponents::PriceFeed(v) => { + struct_ser.serialize_field("priceFeed", v)?; } } } @@ -1109,10 +1292,8 @@ impl<'de> serde::Deserialize<'de> for FeeChange { "transfer", "validator_update", "validatorUpdate", - "add_currency_pairs", - "addCurrencyPairs", - "remove_currency_pairs", - "removeCurrencyPairs", + "price_feed", + "priceFeed", ]; #[allow(clippy::enum_variant_names)] @@ -1131,8 +1312,7 @@ impl<'de> serde::Deserialize<'de> for FeeChange { SudoAddressChange, Transfer, ValidatorUpdate, - AddCurrencyPairs, - RemoveCurrencyPairs, + PriceFeed, } impl<'de> serde::Deserialize<'de> for GeneratedField { fn deserialize(deserializer: D) -> std::result::Result @@ -1168,8 +1348,7 @@ impl<'de> serde::Deserialize<'de> for FeeChange { "sudoAddressChange" | "sudo_address_change" => Ok(GeneratedField::SudoAddressChange), "transfer" => Ok(GeneratedField::Transfer), "validatorUpdate" | "validator_update" => Ok(GeneratedField::ValidatorUpdate), - "addCurrencyPairs" | "add_currency_pairs" => Ok(GeneratedField::AddCurrencyPairs), - "removeCurrencyPairs" | "remove_currency_pairs" => Ok(GeneratedField::RemoveCurrencyPairs), + "priceFeed" | "price_feed" => Ok(GeneratedField::PriceFeed), _ => Err(serde::de::Error::unknown_field(value, FIELDS)), } } @@ -1290,18 +1469,11 @@ impl<'de> serde::Deserialize<'de> for FeeChange { fee_components__ = map_.next_value::<::std::option::Option<_>>()?.map(fee_change::FeeComponents::ValidatorUpdate) ; } - GeneratedField::AddCurrencyPairs => { + GeneratedField::PriceFeed => { if fee_components__.is_some() { - return Err(serde::de::Error::duplicate_field("addCurrencyPairs")); + return Err(serde::de::Error::duplicate_field("priceFeed")); } - fee_components__ = map_.next_value::<::std::option::Option<_>>()?.map(fee_change::FeeComponents::AddCurrencyPairs) -; - } - GeneratedField::RemoveCurrencyPairs => { - if fee_components__.is_some() { - return Err(serde::de::Error::duplicate_field("removeCurrencyPairs")); - } - fee_components__ = map_.next_value::<::std::option::Option<_>>()?.map(fee_change::FeeComponents::RemoveCurrencyPairs) + fee_components__ = map_.next_value::<::std::option::Option<_>>()?.map(fee_change::FeeComponents::PriceFeed) ; } } @@ -2066,7 +2238,7 @@ impl<'de> serde::Deserialize<'de> for InitBridgeAccount { deserializer.deserialize_struct("astria.protocol.transaction.v1.InitBridgeAccount", FIELDS, GeneratedVisitor) } } -impl serde::Serialize for RemoveCurrencyPairs { +impl serde::Serialize for PriceFeed { #[allow(deprecated)] fn serialize(&self, serializer: S) -> std::result::Result where @@ -2074,29 +2246,33 @@ impl serde::Serialize for RemoveCurrencyPairs { { use serde::ser::SerializeStruct; let mut len = 0; - if !self.pairs.is_empty() { + if self.value.is_some() { len += 1; } - let mut struct_ser = serializer.serialize_struct("astria.protocol.transaction.v1.RemoveCurrencyPairs", len)?; - if !self.pairs.is_empty() { - struct_ser.serialize_field("pairs", &self.pairs)?; + let mut struct_ser = serializer.serialize_struct("astria.protocol.transaction.v1.PriceFeed", len)?; + if let Some(v) = self.value.as_ref() { + match v { + price_feed::Value::Oracle(v) => { + struct_ser.serialize_field("oracle", v)?; + } + } } struct_ser.end() } } -impl<'de> serde::Deserialize<'de> for RemoveCurrencyPairs { +impl<'de> serde::Deserialize<'de> for PriceFeed { #[allow(deprecated)] fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { const FIELDS: &[&str] = &[ - "pairs", + "oracle", ]; #[allow(clippy::enum_variant_names)] enum GeneratedField { - Pairs, + Oracle, } impl<'de> serde::Deserialize<'de> for GeneratedField { fn deserialize(deserializer: D) -> std::result::Result @@ -2118,7 +2294,7 @@ impl<'de> serde::Deserialize<'de> for RemoveCurrencyPairs { E: serde::de::Error, { match value { - "pairs" => Ok(GeneratedField::Pairs), + "oracle" => Ok(GeneratedField::Oracle), _ => Err(serde::de::Error::unknown_field(value, FIELDS)), } } @@ -2128,33 +2304,34 @@ impl<'de> serde::Deserialize<'de> for RemoveCurrencyPairs { } struct GeneratedVisitor; impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { - type Value = RemoveCurrencyPairs; + type Value = PriceFeed; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str("struct astria.protocol.transaction.v1.RemoveCurrencyPairs") + formatter.write_str("struct astria.protocol.transaction.v1.PriceFeed") } - fn visit_map(self, mut map_: V) -> std::result::Result + fn visit_map(self, mut map_: V) -> std::result::Result where V: serde::de::MapAccess<'de>, { - let mut pairs__ = None; + let mut value__ = None; while let Some(k) = map_.next_key()? { match k { - GeneratedField::Pairs => { - if pairs__.is_some() { - return Err(serde::de::Error::duplicate_field("pairs")); + GeneratedField::Oracle => { + if value__.is_some() { + return Err(serde::de::Error::duplicate_field("oracle")); } - pairs__ = Some(map_.next_value()?); + value__ = map_.next_value::<::std::option::Option<_>>()?.map(price_feed::Value::Oracle) +; } } } - Ok(RemoveCurrencyPairs { - pairs: pairs__.unwrap_or_default(), + Ok(PriceFeed { + value: value__, }) } } - deserializer.deserialize_struct("astria.protocol.transaction.v1.RemoveCurrencyPairs", FIELDS, GeneratedVisitor) + deserializer.deserialize_struct("astria.protocol.transaction.v1.PriceFeed", FIELDS, GeneratedVisitor) } } impl serde::Serialize for RollupDataSubmission { diff --git a/crates/astria-core/src/protocol/fees/v1.rs b/crates/astria-core/src/protocol/fees/v1.rs index 22e103306..7c015cd24 100644 --- a/crates/astria-core/src/protocol/fees/v1.rs +++ b/crates/astria-core/src/protocol/fees/v1.rs @@ -14,7 +14,6 @@ use crate::{ generated::astria::protocol::fees::v1 as raw, primitive::v1::asset, protocol::transaction::v1::action::{ - AddCurrencyPairs, BridgeLock, BridgeSudoChange, BridgeUnlock, @@ -24,7 +23,7 @@ use crate::{ IbcSudoChange, Ics20Withdrawal, InitBridgeAccount, - RemoveCurrencyPairs, + PriceFeed, RollupDataSubmission, SudoAddressChange, Transfer, @@ -110,8 +109,7 @@ impl_protobuf_for_fee_components!( FeeComponents => raw::FeeChangeFeeComponents, FeeComponents => raw::SudoAddressChangeFeeComponents, FeeComponents => raw::IbcSudoChangeFeeComponents, - FeeComponents => raw::AddCurrencyPairsFeeComponents, - FeeComponents => raw::RemoveCurrencyPairsFeeComponents, + FeeComponents => raw::PriceFeedFeeComponents, ); pub struct FeeComponents { diff --git a/crates/astria-core/src/protocol/genesis/snapshots/astria_core__protocol__genesis__v1__tests__genesis_state.snap b/crates/astria-core/src/protocol/genesis/snapshots/astria_core__protocol__genesis__v1__tests__genesis_state.snap index 004306d1e..0719922b3 100644 --- a/crates/astria-core/src/protocol/genesis/snapshots/astria_core__protocol__genesis__v1__tests__genesis_state.snap +++ b/crates/astria-core/src/protocol/genesis/snapshots/astria_core__protocol__genesis__v1__tests__genesis_state.snap @@ -132,11 +132,7 @@ expression: genesis_state() "base": {}, "multiplier": {} }, - "addCurrencyPairs": { - "base": {}, - "multiplier": {} - }, - "removeCurrencyPairs": { + "priceFeed": { "base": {}, "multiplier": {} } diff --git a/crates/astria-core/src/protocol/genesis/v1.rs b/crates/astria-core/src/protocol/genesis/v1.rs index 283bbcb10..df3ecfe30 100644 --- a/crates/astria-core/src/protocol/genesis/v1.rs +++ b/crates/astria-core/src/protocol/genesis/v1.rs @@ -26,7 +26,6 @@ use crate::{ FeeComponents, }, transaction::v1::action::{ - AddCurrencyPairs, BridgeLock, BridgeSudoChange, BridgeUnlock, @@ -36,7 +35,7 @@ use crate::{ IbcSudoChange, Ics20Withdrawal, InitBridgeAccount, - RemoveCurrencyPairs, + PriceFeed, RollupDataSubmission, SudoAddressChange, Transfer, @@ -765,8 +764,7 @@ pub struct GenesisFees { pub ibc_relayer_change: Option>, pub sudo_address_change: Option>, pub ibc_sudo_change: Option>, - pub add_currency_pairs: Option>, - pub remove_currency_pairs: Option>, + pub price_feed: Option>, } impl Protobuf for GenesisFees { @@ -793,8 +791,7 @@ impl Protobuf for GenesisFees { ibc_relayer_change, sudo_address_change, ibc_sudo_change, - add_currency_pairs, - remove_currency_pairs, + price_feed, } = raw; let rollup_data_submission = rollup_data_submission .clone() @@ -881,17 +878,11 @@ impl Protobuf for GenesisFees { .transpose() .map_err(|e| FeesError::fee_components("ibc_sudo_change", e))?; - let add_currency_pairs = add_currency_pairs + let price_feed = price_feed .clone() - .map(FeeComponents::::try_from_raw) + .map(FeeComponents::::try_from_raw) .transpose() - .map_err(|e| FeesError::fee_components("add_currency_pairs", e))?; - - let remove_currency_pairs = remove_currency_pairs - .clone() - .map(FeeComponents::::try_from_raw) - .transpose() - .map_err(|e| FeesError::fee_components("remove_currency_pairs", e))?; + .map_err(|e| FeesError::fee_components("price_feed", e))?; Ok(Self { rollup_data_submission, @@ -908,8 +899,7 @@ impl Protobuf for GenesisFees { ibc_relayer_change, sudo_address_change, ibc_sudo_change, - add_currency_pairs, - remove_currency_pairs, + price_feed, }) } @@ -929,8 +919,7 @@ impl Protobuf for GenesisFees { ibc_relayer_change, sudo_address_change, ibc_sudo_change, - add_currency_pairs, - remove_currency_pairs, + price_feed, } = self; Self::Raw { transfer: transfer.map(|act| FeeComponents::::to_raw(&act)), @@ -956,10 +945,7 @@ impl Protobuf for GenesisFees { .map(|act| FeeComponents::::to_raw(&act)), ibc_sudo_change: ibc_sudo_change .map(|act| FeeComponents::::to_raw(&act)), - add_currency_pairs: add_currency_pairs - .map(|act| FeeComponents::::to_raw(&act)), - remove_currency_pairs: remove_currency_pairs - .map(|act| FeeComponents::::to_raw(&act)), + price_feed: price_feed.map(|act| FeeComponents::::to_raw(&act)), } } } @@ -1146,10 +1132,7 @@ mod tests { ibc_relayer_change: Some(FeeComponents::::new(0, 0).to_raw()), sudo_address_change: Some(FeeComponents::::new(0, 0).to_raw()), ibc_sudo_change: Some(FeeComponents::::new(0, 0).to_raw()), - add_currency_pairs: Some(FeeComponents::::new(0, 0).to_raw()), - remove_currency_pairs: Some( - FeeComponents::::new(0, 0).to_raw(), - ), + price_feed: Some(FeeComponents::::new(0, 0).to_raw()), }), connect: Some( ConnectGenesis { diff --git a/crates/astria-core/src/protocol/transaction/v1/action/group/mod.rs b/crates/astria-core/src/protocol/transaction/v1/action/group/mod.rs index 0cb105d3c..fe382499b 100644 --- a/crates/astria-core/src/protocol/transaction/v1/action/group/mod.rs +++ b/crates/astria-core/src/protocol/transaction/v1/action/group/mod.rs @@ -6,80 +6,33 @@ use std::fmt::{ Debug, }; -use penumbra_ibc::IbcRelay; - use super::{ Action, ActionName, - AddCurrencyPairs, - BridgeLock, - BridgeSudoChange, - BridgeUnlock, - FeeAssetChange, - FeeChange, - IbcRelayerChange, - IbcSudoChange, - Ics20Withdrawal, - InitBridgeAccount, - RemoveCurrencyPairs, - RollupDataSubmission, - SudoAddressChange, - Transfer, - ValidatorUpdate, + PriceFeed, }; -trait BelongsToGroup { - const GROUP: Group; -} +impl Action { + pub const fn group(&self) -> Group { + match self { + Action::SudoAddressChange(_) | Action::IbcSudoChange(_) => Group::UnbundleableSudo, -macro_rules! impl_belong_to_group { - ($(($act:ty, $group:expr)),*$(,)?) => { - $( - impl BelongsToGroup for $act { - const GROUP: Group = $group; + Action::IbcRelayerChange(_) | Action::FeeChange(_) | Action::FeeAssetChange(_) => { + Group::BundleableSudo } - )* - } -} -impl_belong_to_group!( - (RollupDataSubmission, Group::BundleableGeneral), - (Transfer, Group::BundleableGeneral), - (ValidatorUpdate, Group::BundleableGeneral), - (SudoAddressChange, Group::UnbundleableSudo), - (IbcRelayerChange, Group::BundleableSudo), - (Ics20Withdrawal, Group::BundleableGeneral), - (InitBridgeAccount, Group::UnbundleableGeneral), - (BridgeLock, Group::BundleableGeneral), - (BridgeUnlock, Group::BundleableGeneral), - (BridgeSudoChange, Group::UnbundleableGeneral), - (FeeChange, Group::BundleableSudo), - (FeeAssetChange, Group::BundleableSudo), - (IbcRelay, Group::BundleableGeneral), - (IbcSudoChange, Group::UnbundleableSudo), - (AddCurrencyPairs, Group::BundleableGeneral), - (RemoveCurrencyPairs, Group::BundleableGeneral), -); + Action::InitBridgeAccount(_) | Action::BridgeSudoChange(_) => { + Group::UnbundleableGeneral + } -impl Action { - pub const fn group(&self) -> Group { - match self { - Action::RollupDataSubmission(_) => RollupDataSubmission::GROUP, - Action::Transfer(_) => Transfer::GROUP, - Action::ValidatorUpdate(_) => ValidatorUpdate::GROUP, - Action::SudoAddressChange(_) => SudoAddressChange::GROUP, - Action::IbcRelayerChange(_) => IbcRelayerChange::GROUP, - Action::Ics20Withdrawal(_) => Ics20Withdrawal::GROUP, - Action::InitBridgeAccount(_) => InitBridgeAccount::GROUP, - Action::BridgeLock(_) => BridgeLock::GROUP, - Action::BridgeUnlock(_) => BridgeUnlock::GROUP, - Action::BridgeSudoChange(_) => BridgeSudoChange::GROUP, - Action::FeeChange(_) => FeeChange::GROUP, - Action::FeeAssetChange(_) => FeeAssetChange::GROUP, - Action::Ibc(_) => IbcRelay::GROUP, - Action::IbcSudoChange(_) => IbcSudoChange::GROUP, - Action::AddCurrencyPairs(_) => AddCurrencyPairs::GROUP, - Action::RemoveCurrencyPairs(_) => RemoveCurrencyPairs::GROUP, + Action::RollupDataSubmission(_) + | Action::Transfer(_) + | Action::ValidatorUpdate(_) + | Action::Ics20Withdrawal(_) + | Action::BridgeLock(_) + | Action::BridgeUnlock(_) + | Action::Ibc(_) + | Action::PriceFeed(PriceFeed::Oracle(_)) => Group::BundleableGeneral, } } } diff --git a/crates/astria-core/src/protocol/transaction/v1/action/mod.rs b/crates/astria-core/src/protocol/transaction/v1/action/mod.rs index 95d6a007d..042e55d4a 100644 --- a/crates/astria-core/src/protocol/transaction/v1/action/mod.rs +++ b/crates/astria-core/src/protocol/transaction/v1/action/mod.rs @@ -55,8 +55,7 @@ pub enum Action { BridgeUnlock(BridgeUnlock), BridgeSudoChange(BridgeSudoChange), FeeChange(FeeChange), - AddCurrencyPairs(AddCurrencyPairs), - RemoveCurrencyPairs(RemoveCurrencyPairs), + PriceFeed(PriceFeed), } impl Protobuf for Action { @@ -81,8 +80,7 @@ impl Protobuf for Action { Action::BridgeUnlock(act) => Value::BridgeUnlock(act.to_raw()), Action::BridgeSudoChange(act) => Value::BridgeSudoChange(act.to_raw()), Action::FeeChange(act) => Value::FeeChange(act.to_raw()), - Action::AddCurrencyPairs(act) => Value::AddCurrencyPairs(act.to_raw()), - Action::RemoveCurrencyPairs(act) => Value::RemoveCurrencyPairs(act.to_raw()), + Action::PriceFeed(act) => Value::PriceFeed(act.to_raw()), }; raw::Action { value: Some(kind), @@ -156,12 +154,9 @@ impl Protobuf for Action { Value::FeeChange(act) => { Self::FeeChange(FeeChange::try_from_raw_ref(&act).map_err(Error::fee_change)?) } - Value::AddCurrencyPairs(act) => Self::AddCurrencyPairs( - AddCurrencyPairs::try_from_raw(act).map_err(Error::add_currency_pairs)?, - ), - Value::RemoveCurrencyPairs(act) => Self::RemoveCurrencyPairs( - RemoveCurrencyPairs::try_from_raw(act).map_err(Error::remove_currency_pairs)?, - ), + Value::PriceFeed(act) => { + Self::PriceFeed(PriceFeed::try_from_raw(act).map_err(Error::price_feed)?) + } }; Ok(action) } @@ -272,15 +267,9 @@ impl From for Action { } } -impl From for Action { - fn from(value: AddCurrencyPairs) -> Self { - Self::AddCurrencyPairs(value) - } -} - -impl From for Action { - fn from(value: RemoveCurrencyPairs) -> Self { - Self::RemoveCurrencyPairs(value) +impl From for Action { + fn from(value: PriceFeed) -> Self { + Self::PriceFeed(value) } } @@ -321,8 +310,7 @@ impl ActionName for Action { Action::BridgeUnlock(_) => "BridgeUnlock", Action::BridgeSudoChange(_) => "BridgeSudoChange", Action::FeeChange(_) => "FeeChange", - Action::AddCurrencyPairs(_) => "AddCurrencyPairs", - Action::RemoveCurrencyPairs(_) => "RemoveCurrencyPairs", + Action::PriceFeed(_) => "PriceFeed", } } } @@ -392,12 +380,8 @@ impl Error { Self(ActionErrorKind::FeeChange(inner)) } - fn add_currency_pairs(inner: AddCurrencyPairsError) -> Self { - Self(ActionErrorKind::AddCurrencyPairs(inner)) - } - - fn remove_currency_pairs(inner: RemoveCurrencyPairsError) -> Self { - Self(ActionErrorKind::RemoveCurrencyPairs(inner)) + fn price_feed(inner: PriceFeedError) -> Self { + Self(ActionErrorKind::PriceFeed(inner)) } } @@ -433,10 +417,8 @@ enum ActionErrorKind { BridgeSudoChange(#[source] BridgeSudoChangeError), #[error("fee change action was not valid")] FeeChange(#[source] FeeChangeError), - #[error("add currency pairs action was not valid")] - AddCurrencyPairs(#[source] AddCurrencyPairsError), - #[error("remove currency pairs action was not valid")] - RemoveCurrencyPairs(#[source] RemoveCurrencyPairsError), + #[error("price feed action was not valid")] + PriceFeed(#[source] PriceFeedError), } #[derive(Debug, thiserror::Error)] @@ -1983,8 +1965,7 @@ pub enum FeeChange { IbcRelayerChange(FeeComponents), SudoAddressChange(FeeComponents), IbcSudoChange(FeeComponents), - AddCurrencyPairs(FeeComponents), - RemoveCurrencyPairs(FeeComponents), + PriceFeed(FeeComponents), } impl Protobuf for FeeChange { @@ -2037,11 +2018,8 @@ impl Protobuf for FeeChange { Self::IbcSudoChange(fee_change) => { raw::fee_change::FeeComponents::IbcSudoChange(fee_change.to_raw()) } - Self::AddCurrencyPairs(fee_change) => { - raw::fee_change::FeeComponents::AddCurrencyPairs(fee_change.to_raw()) - } - Self::RemoveCurrencyPairs(fee_change) => { - raw::fee_change::FeeComponents::RemoveCurrencyPairs(fee_change.to_raw()) + Self::PriceFeed(fee_change) => { + raw::fee_change::FeeComponents::PriceFeed(fee_change.to_raw()) } }), } @@ -2113,15 +2091,8 @@ impl Protobuf for FeeChange { Some(raw::fee_change::FeeComponents::IbcSudoChange(fee_change)) => Self::IbcSudoChange( FeeComponents::::try_from_raw_ref(fee_change)?, ), - Some(raw::fee_change::FeeComponents::AddCurrencyPairs(fee_change)) => { - Self::AddCurrencyPairs(FeeComponents::::try_from_raw_ref( - fee_change, - )?) - } - Some(raw::fee_change::FeeComponents::RemoveCurrencyPairs(fee_change)) => { - Self::RemoveCurrencyPairs(FeeComponents::::try_from_raw_ref( - fee_change, - )?) + Some(raw::fee_change::FeeComponents::PriceFeed(fee_change)) => { + Self::PriceFeed(FeeComponents::::try_from_raw_ref(fee_change)?) } None => return Err(FeeChangeError::field_unset("fee_components")), }) @@ -2129,137 +2100,181 @@ impl Protobuf for FeeChange { } #[derive(Debug, Clone)] -pub struct AddCurrencyPairs { - pub pairs: Vec, +pub enum PriceFeed { + Oracle(CurrencyPairsChange), } -impl Protobuf for AddCurrencyPairs { - type Error = AddCurrencyPairsError; - type Raw = raw::AddCurrencyPairs; +impl Protobuf for PriceFeed { + type Error = PriceFeedError; + type Raw = raw::PriceFeed; #[must_use] - fn into_raw(self) -> raw::AddCurrencyPairs { - raw::AddCurrencyPairs { - pairs: self.pairs.into_iter().map(CurrencyPair::into_raw).collect(), + fn into_raw(self) -> Self::Raw { + match self { + PriceFeed::Oracle(currency_pairs_change) => { + let raw = raw::price_feed::Value::Oracle(currency_pairs_change.into_raw()); + Self::Raw { + value: Some(raw), + } + } } } #[must_use] - fn to_raw(&self) -> raw::AddCurrencyPairs { - raw::AddCurrencyPairs { - pairs: self.pairs.iter().map(CurrencyPair::to_raw).collect(), - } + fn to_raw(&self) -> Self::Raw { + self.clone().into_raw() } - /// Convert from a raw, unchecked protobuf [`raw::AddCurrencyPairsAction`]. + /// Convert from a raw, unchecked protobuf [`raw::PriceFeed`]. /// /// # Errors /// - /// - if any of the `pairs` field is invalid - fn try_from_raw(proto: raw::AddCurrencyPairs) -> Result { - let pairs = proto - .pairs - .into_iter() - .map(CurrencyPair::try_from_raw) - .collect::>() - .map_err(AddCurrencyPairsError::invalid_currency_pair)?; - Ok(Self { - pairs, - }) + /// - if the raw value is `None` + /// - if converting the nested data fails. + fn try_from_raw(raw: raw::PriceFeed) -> Result { + match raw.value { + Some(raw::price_feed::Value::Oracle(currency_pairs_change)) => { + let currency_pairs_change = + CurrencyPairsChange::try_from_raw(currency_pairs_change) + .map_err(Self::Error::oracle)?; + Ok(Self::Oracle(currency_pairs_change)) + } + None => Err(Self::Error::unset()), + } } - /// Convert from a reference to a raw, unchecked protobuf [`raw::AddCurrencyPairsAction`]. + /// Convert from a reference to a raw, unchecked protobuf [`raw::PriceFeed`]. /// /// # Errors /// + /// - if the raw value is `None` /// - if any of the `pairs` field is invalid - fn try_from_raw_ref(proto: &raw::AddCurrencyPairs) -> Result { - Self::try_from_raw(proto.clone()) + fn try_from_raw_ref(raw: &raw::PriceFeed) -> Result { + Self::try_from_raw(raw.clone()) } } #[derive(Debug, thiserror::Error)] #[error(transparent)] -pub struct AddCurrencyPairsError(AddCurrencyPairsErrorKind); +pub struct PriceFeedError(PriceFeedErrorKind); -impl AddCurrencyPairsError { +impl PriceFeedError { #[must_use] - fn invalid_currency_pair(err: CurrencyPairError) -> Self { - Self(AddCurrencyPairsErrorKind::InvalidCurrencyPair(err)) + fn unset() -> Self { + Self(PriceFeedErrorKind::Unset) + } + + #[must_use] + fn oracle(err: CurrencyPairsChangeError) -> Self { + Self(PriceFeedErrorKind::Oracle(err)) } } #[derive(Debug, thiserror::Error)] -enum AddCurrencyPairsErrorKind { - #[error("a currency pair was invalid")] - InvalidCurrencyPair(#[from] CurrencyPairError), +enum PriceFeedErrorKind { + #[error("required action value was not set")] + Unset, + #[error(transparent)] + Oracle(CurrencyPairsChangeError), } #[derive(Debug, Clone)] -pub struct RemoveCurrencyPairs { - pub pairs: Vec, +pub enum CurrencyPairsChange { + Addition(Vec), + Removal(Vec), } -impl Protobuf for RemoveCurrencyPairs { - type Error = RemoveCurrencyPairsError; - type Raw = raw::RemoveCurrencyPairs; +impl Protobuf for CurrencyPairsChange { + type Error = CurrencyPairsChangeError; + type Raw = raw::CurrencyPairsChange; #[must_use] - fn into_raw(self) -> raw::RemoveCurrencyPairs { - raw::RemoveCurrencyPairs { - pairs: self.pairs.into_iter().map(CurrencyPair::into_raw).collect(), + fn into_raw(self) -> Self::Raw { + let raw = match self { + CurrencyPairsChange::Addition(pairs) => { + raw::currency_pairs_change::Value::Addition(raw::CurrencyPairsToAdd { + pairs: pairs.into_iter().map(CurrencyPair::into_raw).collect(), + }) + } + CurrencyPairsChange::Removal(pairs) => { + raw::currency_pairs_change::Value::Removal(raw::CurrencyPairsToRemove { + pairs: pairs.into_iter().map(CurrencyPair::into_raw).collect(), + }) + } + }; + Self::Raw { + value: Some(raw), } } #[must_use] - fn to_raw(&self) -> raw::RemoveCurrencyPairs { - raw::RemoveCurrencyPairs { - pairs: self.pairs.iter().map(CurrencyPair::to_raw).collect(), - } + fn to_raw(&self) -> Self::Raw { + self.clone().into_raw() } - /// Convert from a raw, unchecked protobuf [`raw::RemoveCurrencyPairsAction`]. + /// Convert from a raw, unchecked protobuf [`raw::CurrencyPairsChange`]. /// /// # Errors /// + /// - if the raw value is `None` /// - if any of the `pairs` field is invalid - fn try_from_raw(proto: raw::RemoveCurrencyPairs) -> Result { - let pairs = proto - .pairs - .into_iter() - .map(CurrencyPair::try_from_raw) - .collect::>() - .map_err(RemoveCurrencyPairsError::invalid_currency_pair)?; - Ok(Self { - pairs, - }) + fn try_from_raw(raw: raw::CurrencyPairsChange) -> Result { + match raw.value { + Some(raw::currency_pairs_change::Value::Addition(raw::CurrencyPairsToAdd { + pairs, + })) => { + let pairs = pairs + .into_iter() + .map(CurrencyPair::try_from_raw) + .collect::>() + .map_err(Self::Error::invalid_currency_pair)?; + Ok(Self::Addition(pairs)) + } + Some(raw::currency_pairs_change::Value::Removal(raw::CurrencyPairsToRemove { + pairs, + })) => { + let pairs = pairs + .into_iter() + .map(CurrencyPair::try_from_raw) + .collect::>() + .map_err(Self::Error::invalid_currency_pair)?; + Ok(Self::Removal(pairs)) + } + None => Err(Self::Error::unset()), + } } - /// Convert from a reference to a raw, unchecked protobuf [`raw::RemoveCurrencyPairsAction`]. + /// Convert from a reference to a raw, unchecked protobuf [`raw::PriceFeed`]. /// /// # Errors /// + /// - if the raw value is `None` /// - if any of the `pairs` field is invalid - fn try_from_raw_ref( - proto: &raw::RemoveCurrencyPairs, - ) -> Result { - Self::try_from_raw(proto.clone()) + fn try_from_raw_ref(raw: &raw::CurrencyPairsChange) -> Result { + Self::try_from_raw(raw.clone()) } } #[derive(Debug, thiserror::Error)] #[error(transparent)] -pub struct RemoveCurrencyPairsError(RemoveCurrencyPairsErrorKind); +pub struct CurrencyPairsChangeError(CurrencyPairsChangeErrorKind); + +impl CurrencyPairsChangeError { + #[must_use] + fn unset() -> Self { + Self(CurrencyPairsChangeErrorKind::Unset) + } -impl RemoveCurrencyPairsError { #[must_use] fn invalid_currency_pair(err: CurrencyPairError) -> Self { - Self(RemoveCurrencyPairsErrorKind::InvalidCurrencyPair(err)) + Self(CurrencyPairsChangeErrorKind::InvalidCurrencyPair(err)) } } #[derive(Debug, thiserror::Error)] -enum RemoveCurrencyPairsErrorKind { +enum CurrencyPairsChangeErrorKind { + #[error("required action value was not set")] + Unset, #[error("a currency pair was invalid")] InvalidCurrencyPair(#[from] CurrencyPairError), } @@ -2348,14 +2363,8 @@ impl From> for FeeChange { } } -impl From> for FeeChange { - fn from(fee: FeeComponents) -> Self { - FeeChange::AddCurrencyPairs(fee) - } -} - -impl From> for FeeChange { - fn from(fee: FeeComponents) -> Self { - FeeChange::RemoveCurrencyPairs(fee) +impl From> for FeeChange { + fn from(fee: FeeComponents) -> Self { + FeeChange::PriceFeed(fee) } } diff --git a/crates/astria-sequencer-utils/src/genesis_example.rs b/crates/astria-sequencer-utils/src/genesis_example.rs index 60e8906b1..426e5265b 100644 --- a/crates/astria-sequencer-utils/src/genesis_example.rs +++ b/crates/astria-sequencer-utils/src/genesis_example.rs @@ -33,7 +33,6 @@ use astria_core::{ GenesisAppState, }, transaction::v1::action::{ - AddCurrencyPairs, BridgeLock, BridgeSudoChange, BridgeUnlock, @@ -43,7 +42,7 @@ use astria_core::{ IbcSudoChange, Ics20Withdrawal, InitBridgeAccount, - RemoveCurrencyPairs, + PriceFeed, RollupDataSubmission, SudoAddressChange, Transfer, @@ -245,8 +244,7 @@ fn proto_genesis_state() -> astria_core::generated::astria::protocol::genesis::v ibc_relayer_change: Some(FeeComponents::::new(0, 0).to_raw()), sudo_address_change: Some(FeeComponents::::new(0, 0).to_raw()), ibc_sudo_change: Some(FeeComponents::::new(0, 0).to_raw()), - add_currency_pairs: Some(FeeComponents::::new(0, 0).to_raw()), - remove_currency_pairs: Some(FeeComponents::::new(0, 0).to_raw()), + price_feed: Some(FeeComponents::::new(0, 0).to_raw()), }), } } diff --git a/crates/astria-sequencer/src/action_handler/impls/add_currency_pairs.rs b/crates/astria-sequencer/src/action_handler/impls/add_currency_pairs.rs deleted file mode 100644 index 048bdc86f..000000000 --- a/crates/astria-sequencer/src/action_handler/impls/add_currency_pairs.rs +++ /dev/null @@ -1,187 +0,0 @@ -use astria_core::{ - connect::{ - oracle::v2::CurrencyPairState, - types::v2::CurrencyPairNonce, - }, - protocol::transaction::v1::action::AddCurrencyPairs, -}; -use astria_eyre::eyre::{ - ensure, - OptionExt as _, - Result, - WrapErr as _, -}; -use async_trait::async_trait; -use cnidarium::StateWrite; -use tracing::debug; - -use crate::{ - action_handler::ActionHandler, - connect::{ - market_map::state_ext::StateReadExt as _, - oracle::state_ext::{ - StateReadExt as _, - StateWriteExt as _, - }, - }, - transaction::StateReadExt as _, -}; - -#[async_trait] -impl ActionHandler for AddCurrencyPairs { - async fn check_stateless(&self) -> Result<()> { - Ok(()) - } - - async fn check_and_execute(&self, mut state: S) -> Result<()> { - // TODO: should we use the market map admin here, or a different admin? - let admin = state - .get_params() - .await? - .ok_or_eyre("market map params not set")? - .admin; - let from = state - .get_transaction_context() - .expect("transaction source must be present in state when executing an action") - .address_bytes(); - ensure!( - from == admin.bytes(), - "only the market map admin can add currency pairs" - ); - - let mut next_currency_pair_id = state - .get_next_currency_pair_id() - .await - .wrap_err("failed to get next currency pair id")?; - let mut num_currency_pairs = state - .get_num_currency_pairs() - .await - .wrap_err("failed to get number of currency pairs")?; - - for pair in &self.pairs { - if state - .get_currency_pair_state(pair) - .await - .wrap_err("failed to get currency pair state")? - .is_some() - { - debug!("currency pair {} already exists, skipping", pair); - continue; - } - - let currency_pair_state = CurrencyPairState { - price: None, - nonce: CurrencyPairNonce::new(0), - id: next_currency_pair_id, - }; - state - .put_currency_pair_state(pair.clone(), currency_pair_state) - .wrap_err("failed to put currency pair state")?; - num_currency_pairs = num_currency_pairs - .checked_add(1) - .ok_or_eyre("overflow when incrementing number of currency pairs")?; - next_currency_pair_id = next_currency_pair_id - .increment() - .ok_or_eyre("overflow when incrementing next currency pair id")?; - } - - state - .put_next_currency_pair_id(next_currency_pair_id) - .wrap_err("failed to put next currency pair id")?; - state - .put_num_currency_pairs(num_currency_pairs) - .wrap_err("failed to put number of currency pairs")?; - Ok(()) - } -} - -#[cfg(test)] -mod test { - use astria_core::{ - connect::{ - market_map::v2::Params, - oracle::v2::CurrencyPairState, - types::v2::CurrencyPairId, - }, - primitive::v1::TransactionId, - protocol::transaction::v1::action::AddCurrencyPairs, - }; - use cnidarium::StateDelta; - - use super::*; - use crate::{ - app::test_utils::get_alice_signing_key, - benchmark_and_test_utils::astria_address, - connect::market_map::state_ext::StateWriteExt as _, - transaction::{ - StateWriteExt, - TransactionContext, - }, - }; - - #[tokio::test] - async fn add_currency_pairs_with_duplicate() { - let storage = cnidarium::TempStorage::new().await.unwrap(); - let snapshot = storage.latest_snapshot(); - let mut state = StateDelta::new(snapshot); - - let alice = get_alice_signing_key(); - let alice_address = astria_address(&alice.address_bytes()); - state.put_transaction_context(TransactionContext { - address_bytes: alice.address_bytes(), - transaction_id: TransactionId::new([0; 32]), - position_in_transaction: 0, - }); - - state - .put_params(Params { - market_authorities: vec![], - admin: alice_address, - }) - .unwrap(); - state - .put_next_currency_pair_id(CurrencyPairId::new(0)) - .unwrap(); - state.put_num_currency_pairs(0).unwrap(); - - let pairs = vec![ - "BTC/USD".parse().unwrap(), - "ETH/USD".parse().unwrap(), - "BTC/USD".parse().unwrap(), - ]; - let action = AddCurrencyPairs { - pairs: pairs.clone(), - }; - action.check_and_execute(&mut state).await.unwrap(); - - assert_eq!( - state - .get_currency_pair_state(&pairs[0]) - .await - .unwrap() - .unwrap(), - CurrencyPairState { - price: None, - nonce: CurrencyPairNonce::new(0), - id: CurrencyPairId::new(0), - } - ); - assert_eq!( - state - .get_currency_pair_state(&pairs[1]) - .await - .unwrap() - .unwrap(), - CurrencyPairState { - price: None, - nonce: CurrencyPairNonce::new(0), - id: CurrencyPairId::new(1), - } - ); - assert_eq!( - state.get_next_currency_pair_id().await.unwrap(), - CurrencyPairId::new(2) - ); - assert_eq!(state.get_num_currency_pairs().await.unwrap(), 2); - } -} diff --git a/crates/astria-sequencer/src/action_handler/impls/fee_change.rs b/crates/astria-sequencer/src/action_handler/impls/fee_change.rs index a11bf584c..7551e6d80 100644 --- a/crates/astria-sequencer/src/action_handler/impls/fee_change.rs +++ b/crates/astria-sequencer/src/action_handler/impls/fee_change.rs @@ -82,12 +82,9 @@ impl ActionHandler for FeeChange { Self::IbcSudoChange(fees) => state .put_fees(*fees) .wrap_err("failed to put ibc sudo change fees"), - Self::AddCurrencyPairs(fees) => state + Self::PriceFeed(fees) => state .put_fees(*fees) - .wrap_err("failed to put add currency pairs fees"), - Self::RemoveCurrencyPairs(fees) => state - .put_fees(*fees) - .wrap_err("failed to put remove currency pairs fees"), + .wrap_err("failed to put price feed fees"), } } } diff --git a/crates/astria-sequencer/src/action_handler/impls/mod.rs b/crates/astria-sequencer/src/action_handler/impls/mod.rs index 040c3c8c0..32632c4fb 100644 --- a/crates/astria-sequencer/src/action_handler/impls/mod.rs +++ b/crates/astria-sequencer/src/action_handler/impls/mod.rs @@ -1,4 +1,3 @@ -pub(crate) mod add_currency_pairs; pub(crate) mod bridge_lock; pub(crate) mod bridge_sudo_change; pub(crate) mod bridge_unlock; @@ -8,7 +7,7 @@ pub(crate) mod ibc_relayer_change; pub(crate) mod ibc_sudo_change; pub(crate) mod ics20_withdrawal; pub(crate) mod init_bridge_account; -pub(crate) mod remove_currency_pairs; +pub(crate) mod price_feed; pub(crate) mod rollup_data_submission; pub(crate) mod sudo_address_change; #[cfg(test)] diff --git a/crates/astria-sequencer/src/action_handler/impls/price_feed.rs b/crates/astria-sequencer/src/action_handler/impls/price_feed.rs new file mode 100644 index 000000000..283a5ea46 --- /dev/null +++ b/crates/astria-sequencer/src/action_handler/impls/price_feed.rs @@ -0,0 +1,298 @@ +use astria_core::{ + connect::{ + oracle::v2::CurrencyPairState, + types::v2::{ + CurrencyPair, + CurrencyPairNonce, + }, + }, + protocol::transaction::v1::action::{ + CurrencyPairsChange, + PriceFeed, + }, +}; +use astria_eyre::eyre::{ + ensure, + OptionExt as _, + Result, + WrapErr as _, +}; +use async_trait::async_trait; +use cnidarium::StateWrite; +use tracing::debug; + +use crate::{ + action_handler::ActionHandler, + connect::{ + market_map::state_ext::StateReadExt as _, + oracle::state_ext::{ + StateReadExt as _, + StateWriteExt as _, + }, + }, + transaction::StateReadExt as _, +}; + +#[async_trait] +impl ActionHandler for PriceFeed { + async fn check_stateless(&self) -> Result<()> { + Ok(()) + } + + async fn check_and_execute(&self, state: S) -> Result<()> { + // TODO: should we use the market map admin here, or a different admin? + let admin = state + .get_params() + .await? + .ok_or_eyre("market map params not set")? + .admin; + let from = state + .get_transaction_context() + .expect("transaction source must be present in state when executing an action") + .address_bytes(); + ensure!( + from == admin.bytes(), + "only the market map admin can add currency pairs" + ); + + match self { + PriceFeed::Oracle(CurrencyPairsChange::Addition(currency_pairs)) => { + check_and_execute_currency_pairs_addition(state, currency_pairs).await + } + PriceFeed::Oracle(CurrencyPairsChange::Removal(currency_pairs)) => { + check_and_execute_currency_pairs_removal(state, currency_pairs).await + } + } + } +} + +async fn check_and_execute_currency_pairs_addition( + mut state: S, + currency_pairs: &[CurrencyPair], +) -> Result<()> { + let mut next_currency_pair_id = state + .get_next_currency_pair_id() + .await + .wrap_err("failed to get next currency pair id")?; + let mut num_currency_pairs = state + .get_num_currency_pairs() + .await + .wrap_err("failed to get number of currency pairs")?; + + for pair in currency_pairs { + if state + .get_currency_pair_state(pair) + .await + .wrap_err("failed to get currency pair state")? + .is_some() + { + debug!("currency pair {} already exists, skipping", pair); + continue; + } + + let currency_pair_state = CurrencyPairState { + price: None, + nonce: CurrencyPairNonce::new(0), + id: next_currency_pair_id, + }; + state + .put_currency_pair_state(pair.clone(), currency_pair_state) + .wrap_err("failed to put currency pair state")?; + num_currency_pairs = num_currency_pairs + .checked_add(1) + .ok_or_eyre("overflow when incrementing number of currency pairs")?; + next_currency_pair_id = next_currency_pair_id + .increment() + .ok_or_eyre("overflow when incrementing next currency pair id")?; + } + + state + .put_next_currency_pair_id(next_currency_pair_id) + .wrap_err("failed to put next currency pair id")?; + state + .put_num_currency_pairs(num_currency_pairs) + .wrap_err("failed to put number of currency pairs") +} + +async fn check_and_execute_currency_pairs_removal( + mut state: S, + currency_pairs: &[CurrencyPair], +) -> Result<()> { + let mut num_currency_pairs = state + .get_num_currency_pairs() + .await + .wrap_err("failed to get number of currency pairs")?; + ensure!( + num_currency_pairs >= currency_pairs.len() as u64, + "cannot remove more currency pairs than exist", + ); + + for pair in currency_pairs { + if state + .remove_currency_pair(pair) + .await + .wrap_err("failed to delete currency pair")? + { + num_currency_pairs = num_currency_pairs + .checked_sub(1) + .ok_or_eyre("failed to decrement number of currency pairs")?; + } + } + + state + .put_num_currency_pairs(num_currency_pairs) + .wrap_err("failed to put number of currency pairs") +} + +#[cfg(test)] +mod test { + use astria_core::{ + connect::{ + market_map::v2::Params, + oracle::v2::CurrencyPairState, + types::v2::CurrencyPairId, + }, + primitive::v1::TransactionId, + protocol::transaction::v1::action::PriceFeed, + }; + use cnidarium::StateDelta; + + use super::*; + use crate::{ + app::test_utils::get_alice_signing_key, + benchmark_and_test_utils::astria_address, + connect::market_map::state_ext::StateWriteExt as _, + transaction::{ + StateWriteExt, + TransactionContext, + }, + }; + + #[tokio::test] + async fn add_currency_pairs_with_duplicate() { + let storage = cnidarium::TempStorage::new().await.unwrap(); + let snapshot = storage.latest_snapshot(); + let mut state = StateDelta::new(snapshot); + + let alice = get_alice_signing_key(); + let alice_address = astria_address(&alice.address_bytes()); + state.put_transaction_context(TransactionContext { + address_bytes: alice.address_bytes(), + transaction_id: TransactionId::new([0; 32]), + position_in_transaction: 0, + }); + + state + .put_params(Params { + market_authorities: vec![], + admin: alice_address, + }) + .unwrap(); + state + .put_next_currency_pair_id(CurrencyPairId::new(0)) + .unwrap(); + state.put_num_currency_pairs(0).unwrap(); + + let pairs = vec![ + "BTC/USD".parse().unwrap(), + "ETH/USD".parse().unwrap(), + "BTC/USD".parse().unwrap(), + ]; + let action = PriceFeed::Oracle(CurrencyPairsChange::Addition(pairs.clone())); + action.check_and_execute(&mut state).await.unwrap(); + + assert_eq!( + state + .get_currency_pair_state(&pairs[0]) + .await + .unwrap() + .unwrap(), + CurrencyPairState { + price: None, + nonce: CurrencyPairNonce::new(0), + id: CurrencyPairId::new(0), + } + ); + assert_eq!( + state + .get_currency_pair_state(&pairs[1]) + .await + .unwrap() + .unwrap(), + CurrencyPairState { + price: None, + nonce: CurrencyPairNonce::new(0), + id: CurrencyPairId::new(1), + } + ); + assert_eq!( + state.get_next_currency_pair_id().await.unwrap(), + CurrencyPairId::new(2) + ); + assert_eq!(state.get_num_currency_pairs().await.unwrap(), 2); + } + + #[tokio::test] + async fn remove_currency_pairs_with_duplicate() { + let storage = cnidarium::TempStorage::new().await.unwrap(); + let snapshot = storage.latest_snapshot(); + let mut state = StateDelta::new(snapshot); + + let alice = get_alice_signing_key(); + let alice_address = astria_address(&alice.address_bytes()); + state.put_transaction_context(TransactionContext { + address_bytes: alice.address_bytes(), + transaction_id: TransactionId::new([0; 32]), + position_in_transaction: 0, + }); + + let pairs: Vec = vec![ + "BTC/USD".parse().unwrap(), + "ETH/USD".parse().unwrap(), + "BTC/USD".parse().unwrap(), + ]; + + state + .put_params(Params { + market_authorities: vec![], + admin: alice_address, + }) + .unwrap(); + state.put_num_currency_pairs(3).unwrap(); + state + .put_currency_pair_state( + pairs[0].clone(), + CurrencyPairState { + price: None, + nonce: CurrencyPairNonce::new(0), + id: CurrencyPairId::new(0), + }, + ) + .unwrap(); + state + .put_currency_pair_state( + pairs[1].clone(), + CurrencyPairState { + price: None, + nonce: CurrencyPairNonce::new(0), + id: CurrencyPairId::new(1), + }, + ) + .unwrap(); + state + .put_currency_pair_state( + "TIA/USD".parse().unwrap(), + CurrencyPairState { + price: None, + nonce: CurrencyPairNonce::new(0), + id: CurrencyPairId::new(2), + }, + ) + .unwrap(); + + let action = PriceFeed::Oracle(CurrencyPairsChange::Removal(pairs.clone())); + action.check_and_execute(&mut state).await.unwrap(); + + assert_eq!(state.get_num_currency_pairs().await.unwrap(), 1); + } +} diff --git a/crates/astria-sequencer/src/action_handler/impls/remove_currency_pairs.rs b/crates/astria-sequencer/src/action_handler/impls/remove_currency_pairs.rs deleted file mode 100644 index b717c7378..000000000 --- a/crates/astria-sequencer/src/action_handler/impls/remove_currency_pairs.rs +++ /dev/null @@ -1,170 +0,0 @@ -use astria_core::protocol::transaction::v1::action::RemoveCurrencyPairs; -use astria_eyre::eyre::{ - ensure, - OptionExt as _, - Result, - WrapErr as _, -}; -use async_trait::async_trait; -use cnidarium::StateWrite; - -use crate::{ - action_handler::ActionHandler, - connect::{ - market_map::state_ext::StateReadExt as _, - oracle::state_ext::{ - StateReadExt as _, - StateWriteExt, - }, - }, - transaction::StateReadExt as _, -}; - -#[async_trait] -impl ActionHandler for RemoveCurrencyPairs { - async fn check_stateless(&self) -> Result<()> { - Ok(()) - } - - async fn check_and_execute(&self, mut state: S) -> Result<()> { - // TODO: should we use the market map admin here, or a different admin? - let admin = state - .get_params() - .await? - .ok_or_eyre("market map params not set")? - .admin; - let from = state - .get_transaction_context() - .expect("transaction source must be present in state when executing an action") - .address_bytes(); - ensure!( - from == admin.bytes(), - "only the market map admin can add currency pairs" - ); - - let mut num_currency_pairs = state - .get_num_currency_pairs() - .await - .wrap_err("failed to get number of currency pairs")?; - ensure!( - num_currency_pairs >= self.pairs.len() as u64, - "cannot remove more currency pairs than exist", - ); - - for pair in &self.pairs { - if state - .remove_currency_pair(pair) - .await - .wrap_err("failed to delete currency pair")? - { - num_currency_pairs = num_currency_pairs - .checked_sub(1) - .ok_or_eyre("failed to decrement number of currency pairs")?; - } - } - - state - .put_num_currency_pairs(num_currency_pairs) - .wrap_err("failed to put number of currency pairs")?; - - Ok(()) - } -} - -#[cfg(test)] -mod test { - use astria_core::{ - connect::{ - market_map::v2::Params, - oracle::v2::CurrencyPairState, - types::v2::{ - CurrencyPair, - CurrencyPairId, - CurrencyPairNonce, - }, - }, - primitive::v1::TransactionId, - protocol::transaction::v1::action::RemoveCurrencyPairs, - }; - use cnidarium::StateDelta; - - use super::*; - use crate::{ - app::test_utils::get_alice_signing_key, - benchmark_and_test_utils::astria_address, - connect::{ - market_map::state_ext::StateWriteExt as _, - oracle::state_ext::StateWriteExt as _, - }, - transaction::{ - StateWriteExt, - TransactionContext, - }, - }; - - #[tokio::test] - async fn remove_currency_pairs_with_duplicate() { - let storage = cnidarium::TempStorage::new().await.unwrap(); - let snapshot = storage.latest_snapshot(); - let mut state = StateDelta::new(snapshot); - - let alice = get_alice_signing_key(); - let alice_address = astria_address(&alice.address_bytes()); - state.put_transaction_context(TransactionContext { - address_bytes: alice.address_bytes(), - transaction_id: TransactionId::new([0; 32]), - position_in_transaction: 0, - }); - - let pairs: Vec = vec![ - "BTC/USD".parse().unwrap(), - "ETH/USD".parse().unwrap(), - "BTC/USD".parse().unwrap(), - ]; - - state - .put_params(Params { - market_authorities: vec![], - admin: alice_address, - }) - .unwrap(); - state.put_num_currency_pairs(3).unwrap(); - state - .put_currency_pair_state( - pairs[0].clone(), - CurrencyPairState { - price: None, - nonce: CurrencyPairNonce::new(0), - id: CurrencyPairId::new(0), - }, - ) - .unwrap(); - state - .put_currency_pair_state( - pairs[1].clone(), - CurrencyPairState { - price: None, - nonce: CurrencyPairNonce::new(0), - id: CurrencyPairId::new(1), - }, - ) - .unwrap(); - state - .put_currency_pair_state( - "TIA/USD".parse().unwrap(), - CurrencyPairState { - price: None, - nonce: CurrencyPairNonce::new(0), - id: CurrencyPairId::new(2), - }, - ) - .unwrap(); - - let action = RemoveCurrencyPairs { - pairs: pairs.clone(), - }; - action.check_and_execute(&mut state).await.unwrap(); - - assert_eq!(state.get_num_currency_pairs().await.unwrap(), 1); - } -} diff --git a/crates/astria-sequencer/src/action_handler/impls/transaction.rs b/crates/astria-sequencer/src/action_handler/impls/transaction.rs index 67f483819..fdfa626d3 100644 --- a/crates/astria-sequencer/src/action_handler/impls/transaction.rs +++ b/crates/astria-sequencer/src/action_handler/impls/transaction.rs @@ -146,14 +146,10 @@ impl ActionHandler for Transaction { .check_stateless() .await .wrap_err("stateless check failed for BridgeSudoChange action")?, - Action::AddCurrencyPairs(act) => act + Action::PriceFeed(act) => act .check_stateless() .await - .wrap_err("stateless check failed for AddCurrencyPairs action")?, - Action::RemoveCurrencyPairs(act) => act - .check_stateless() - .await - .wrap_err("stateless check failed for RemoveCurrencyPairs action")?, + .wrap_err("stateless check failed for PriceFeed action")?, } } Ok(()) @@ -280,12 +276,9 @@ impl ActionHandler for Transaction { Action::BridgeSudoChange(act) => check_execute_and_pay_fees(act, &mut state) .await .wrap_err("failed executing bridge sudo change")?, - Action::AddCurrencyPairs(act) => check_execute_and_pay_fees(act, &mut state) - .await - .wrap_err("failed executing add currency pairs")?, - Action::RemoveCurrencyPairs(act) => check_execute_and_pay_fees(act, &mut state) + Action::PriceFeed(act) => check_execute_and_pay_fees(act, &mut state) .await - .wrap_err("failed executing remove currency pairs")?, + .wrap_err("failed executing price feed")?, } } diff --git a/crates/astria-sequencer/src/app/benchmark_and_test_utils.rs b/crates/astria-sequencer/src/app/benchmark_and_test_utils.rs index ceeeb5748..4cfa2e0d8 100644 --- a/crates/astria-sequencer/src/app/benchmark_and_test_utils.rs +++ b/crates/astria-sequencer/src/app/benchmark_and_test_utils.rs @@ -18,7 +18,6 @@ use astria_core::{ GenesisAppState, }, transaction::v1::action::{ - AddCurrencyPairs, BridgeLock, BridgeSudoChange, BridgeUnlock, @@ -28,7 +27,7 @@ use astria_core::{ IbcSudoChange, Ics20Withdrawal, InitBridgeAccount, - RemoveCurrencyPairs, + PriceFeed, RollupDataSubmission, SudoAddressChange, Transfer, @@ -93,8 +92,7 @@ pub(crate) fn default_fees() -> astria_core::protocol::genesis::v1::GenesisFees ibc_relayer_change: Some(FeeComponents::::new(0, 0)), sudo_address_change: Some(FeeComponents::::new(0, 0)), ibc_sudo_change: Some(FeeComponents::::new(0, 0)), - add_currency_pairs: Some(FeeComponents::::new(0, 0)), - remove_currency_pairs: Some(FeeComponents::::new(0, 0)), + price_feed: Some(FeeComponents::::new(0, 0)), } } @@ -394,16 +392,10 @@ pub(crate) async fn mock_state_getter() -> StateDelta { .wrap_err("failed to initiate ibc sudo change fee components") .unwrap(); - let add_currency_pairs_fees = FeeComponents::::new(0, 0); + let price_feed_fees = FeeComponents::::new(0, 0); state - .put_fees(add_currency_pairs_fees) - .wrap_err("failed to initiate add currency pairs fee components") - .unwrap(); - - let remove_currency_pairs_fees = FeeComponents::::new(0, 0); - state - .put_fees(remove_currency_pairs_fees) - .wrap_err("failed to initiate remove currency pairs fee components") + .put_fees(price_feed_fees) + .wrap_err("failed to initiate price feed fee components") .unwrap(); // put denoms as allowed fee asset diff --git a/crates/astria-sequencer/src/app/snapshots/astria_sequencer__app__tests_breaking_changes__app_hash_at_genesis.snap b/crates/astria-sequencer/src/app/snapshots/astria_sequencer__app__tests_breaking_changes__app_hash_at_genesis.snap index 94ae75bee..080589c20 100644 --- a/crates/astria-sequencer/src/app/snapshots/astria_sequencer__app__tests_breaking_changes__app_hash_at_genesis.snap +++ b/crates/astria-sequencer/src/app/snapshots/astria_sequencer__app__tests_breaking_changes__app_hash_at_genesis.snap @@ -3,36 +3,36 @@ source: crates/astria-sequencer/src/app/tests_breaking_changes.rs expression: app.app_hash.as_bytes() --- [ - 131, - 167, - 88, - 101, - 218, - 254, - 19, + 25, + 202, + 16, + 32, + 252, + 173, 102, - 147, - 63, - 205, - 234, - 31, - 196, - 47, - 222, - 20, - 84, - 53, - 174, - 172, - 189, - 174, + 131, + 153, + 236, + 185, + 158, + 85, + 213, + 241, 154, - 139, - 244, - 239, - 59, - 70, - 251, - 95, - 70 + 205, + 152, + 116, + 249, + 83, + 162, + 101, + 198, + 178, + 72, + 175, + 194, + 82, + 48, + 144, + 202 ] diff --git a/crates/astria-sequencer/src/app/snapshots/astria_sequencer__app__tests_breaking_changes__app_hash_execute_every_action.snap b/crates/astria-sequencer/src/app/snapshots/astria_sequencer__app__tests_breaking_changes__app_hash_execute_every_action.snap index 091c59ce7..cab8ccc37 100644 --- a/crates/astria-sequencer/src/app/snapshots/astria_sequencer__app__tests_breaking_changes__app_hash_execute_every_action.snap +++ b/crates/astria-sequencer/src/app/snapshots/astria_sequencer__app__tests_breaking_changes__app_hash_execute_every_action.snap @@ -3,36 +3,36 @@ source: crates/astria-sequencer/src/app/tests_breaking_changes.rs expression: app.app_hash.as_bytes() --- [ - 153, - 195, - 17, - 228, - 25, - 148, - 197, - 236, - 36, - 26, - 230, - 230, - 127, - 10, - 235, - 212, - 172, - 12, - 247, - 81, - 31, - 207, - 9, - 46, - 5, - 124, - 216, - 184, - 167, - 175, - 212, - 152 + 141, + 135, + 210, + 187, + 173, + 122, + 103, + 225, + 89, + 154, + 223, + 152, + 90, + 227, + 149, + 121, + 220, + 2, + 219, + 82, + 18, + 59, + 44, + 41, + 238, + 7, + 64, + 70, + 108, + 227, + 35, + 213 ] diff --git a/crates/astria-sequencer/src/app/snapshots/astria_sequencer__app__tests_breaking_changes__app_hash_finalize_block.snap b/crates/astria-sequencer/src/app/snapshots/astria_sequencer__app__tests_breaking_changes__app_hash_finalize_block.snap index 24b0fb555..21721cb60 100644 --- a/crates/astria-sequencer/src/app/snapshots/astria_sequencer__app__tests_breaking_changes__app_hash_finalize_block.snap +++ b/crates/astria-sequencer/src/app/snapshots/astria_sequencer__app__tests_breaking_changes__app_hash_finalize_block.snap @@ -3,36 +3,36 @@ source: crates/astria-sequencer/src/app/tests_breaking_changes.rs expression: app.app_hash.as_bytes() --- [ - 247, - 161, - 143, - 121, - 170, - 69, - 5, - 151, - 193, - 59, - 28, - 146, - 221, - 210, - 102, - 243, - 221, - 51, - 5, - 90, - 88, 208, - 47, - 18, - 92, + 98, + 88, 248, - 211, - 103, - 156, - 26, - 127, - 58 + 190, + 250, + 213, + 195, + 138, + 18, + 42, + 240, + 54, + 98, + 29, + 183, + 96, + 171, + 138, + 18, + 254, + 228, + 141, + 157, + 74, + 11, + 45, + 225, + 86, + 63, + 244, + 103 ] diff --git a/crates/astria-sequencer/src/app/tests_breaking_changes.rs b/crates/astria-sequencer/src/app/tests_breaking_changes.rs index 709bcfc43..228ac7f24 100644 --- a/crates/astria-sequencer/src/app/tests_breaking_changes.rs +++ b/crates/astria-sequencer/src/app/tests_breaking_changes.rs @@ -25,13 +25,13 @@ use astria_core::{ genesis::v1::Account, transaction::v1::{ action::{ - AddCurrencyPairs, BridgeLock, BridgeSudoChange, BridgeUnlock, + CurrencyPairsChange, IbcRelayerChange, IbcSudoChange, - RemoveCurrencyPairs, + PriceFeed, RollupDataSubmission, Transfer, ValidatorUpdate, @@ -369,9 +369,10 @@ async fn app_execute_transaction_with_every_action_snapshot() { let currency_pair_eth = CurrencyPair::from_str("ETH/USD").unwrap(); let tx = TransactionBody::builder() .actions(vec![ - AddCurrencyPairs { - pairs: vec![currency_pair_tia.clone(), currency_pair_eth.clone()], - } + PriceFeed::Oracle(CurrencyPairsChange::Addition(vec![ + currency_pair_tia.clone(), + currency_pair_eth.clone(), + ])) .into(), ]) .chain_id("test") @@ -381,20 +382,6 @@ async fn app_execute_transaction_with_every_action_snapshot() { let signed_tx = Arc::new(tx.sign(&alice)); app.execute_transaction(signed_tx).await.unwrap(); - let tx = TransactionBody::builder() - .actions(vec![ - RemoveCurrencyPairs { - pairs: vec![currency_pair_tia.clone()], - } - .into(), - ]) - .chain_id("test") - .nonce(5) - .try_build() - .unwrap(); - let signed_tx = Arc::new(tx.sign(&alice)); - app.execute_transaction(signed_tx).await.unwrap(); - let sudo_address = app.state.get_sudo_address().await.unwrap(); app.end_block(1, &sudo_address).await.unwrap(); diff --git a/crates/astria-sequencer/src/app/tests_execute_transaction.rs b/crates/astria-sequencer/src/app/tests_execute_transaction.rs index c4790b130..e3c2a2812 100644 --- a/crates/astria-sequencer/src/app/tests_execute_transaction.rs +++ b/crates/astria-sequencer/src/app/tests_execute_transaction.rs @@ -16,12 +16,12 @@ use astria_core::{ genesis::v1::GenesisAppState, transaction::v1::{ action::{ - AddCurrencyPairs, BridgeLock, BridgeUnlock, + CurrencyPairsChange, IbcRelayerChange, IbcSudoChange, - RemoveCurrencyPairs, + PriceFeed, RollupDataSubmission, SudoAddressChange, Transfer, @@ -1345,10 +1345,7 @@ async fn test_app_execute_transaction_add_and_remove_currency_pairs() { let tx = TransactionBody::builder() .actions(vec![ - AddCurrencyPairs { - pairs: vec![currency_pair.clone()], - } - .into(), + PriceFeed::Oracle(CurrencyPairsChange::Addition(vec![currency_pair.clone()])).into(), ]) .chain_id("test") .try_build() @@ -1368,10 +1365,7 @@ async fn test_app_execute_transaction_add_and_remove_currency_pairs() { let tx = TransactionBody::builder() .actions(vec![ - RemoveCurrencyPairs { - pairs: vec![currency_pair.clone()], - } - .into(), + PriceFeed::Oracle(CurrencyPairsChange::Removal(vec![currency_pair.clone()])).into(), ]) .chain_id("test") .nonce(1) diff --git a/crates/astria-sequencer/src/fees/component.rs b/crates/astria-sequencer/src/fees/component.rs index a76049a3b..3bd47fcf4 100644 --- a/crates/astria-sequencer/src/fees/component.rs +++ b/crates/astria-sequencer/src/fees/component.rs @@ -130,18 +130,11 @@ impl Component for FeesComponent { .wrap_err("failed to store ibc sudo change fee components")?; } - let add_currency_pairs_fees = app_state.fees().add_currency_pairs; - if let Some(add_currency_pairs_fees) = add_currency_pairs_fees { + let price_feed_fees = app_state.fees().price_feed; + if let Some(price_feed_fees) = price_feed_fees { state - .put_fees(add_currency_pairs_fees) - .wrap_err("failed to store add currency pairs fee components")?; - } - - let remove_currency_pairs_fees = app_state.fees().remove_currency_pairs; - if let Some(remove_currency_pairs_fees) = remove_currency_pairs_fees { - state - .put_fees(remove_currency_pairs_fees) - .wrap_err("failed to store remove currency pairs fee components")?; + .put_fees(price_feed_fees) + .wrap_err("failed to store price feed fee components")?; } Ok(()) diff --git a/crates/astria-sequencer/src/fees/mod.rs b/crates/astria-sequencer/src/fees/mod.rs index d93bcea51..3596ec078 100644 --- a/crates/astria-sequencer/src/fees/mod.rs +++ b/crates/astria-sequencer/src/fees/mod.rs @@ -3,7 +3,6 @@ use astria_core::{ protocol::{ fees::v1::FeeComponents, transaction::v1::action::{ - AddCurrencyPairs, BridgeLock, BridgeSudoChange, BridgeUnlock, @@ -13,7 +12,7 @@ use astria_core::{ IbcSudoChange, Ics20Withdrawal, InitBridgeAccount, - RemoveCurrencyPairs, + PriceFeed, RollupDataSubmission, SudoAddressChange, Transfer, @@ -460,7 +459,7 @@ impl FeeHandler for IbcRelay { } } -impl FeeHandler for AddCurrencyPairs { +impl FeeHandler for PriceFeed { fn name() -> &'static str { ::Raw::NAME } @@ -470,29 +469,7 @@ impl FeeHandler for AddCurrencyPairs { } fn snake_case_name() -> &'static str { - "add_currency_pairs" - } - - fn variable_component(&self) -> u128 { - 0 - } - - fn fee_asset(&self) -> Option<&asset::Denom> { - None - } -} - -impl FeeHandler for RemoveCurrencyPairs { - fn name() -> &'static str { - ::Raw::NAME - } - - fn full_name() -> String { - ::full_name() - } - - fn snake_case_name() -> &'static str { - "remove_currency_pairs" + "price_feed" } fn variable_component(&self) -> u128 { diff --git a/crates/astria-sequencer/src/fees/query.rs b/crates/astria-sequencer/src/fees/query.rs index 0f8dee7a5..f8d83ddaa 100644 --- a/crates/astria-sequencer/src/fees/query.rs +++ b/crates/astria-sequencer/src/fees/query.rs @@ -15,7 +15,6 @@ use astria_core::{ fees::v1::FeeComponents, transaction::v1::{ action::{ - AddCurrencyPairs, BridgeLock, BridgeSudoChange, BridgeUnlock, @@ -25,7 +24,7 @@ use astria_core::{ IbcSudoChange, Ics20Withdrawal, InitBridgeAccount, - RemoveCurrencyPairs, + PriceFeed, RollupDataSubmission, SudoAddressChange, Transfer, @@ -304,10 +303,7 @@ pub(crate) async fn get_fees_for_transaction( OnceCell::new(); let fee_asset_change_fees: OnceCell>> = OnceCell::new(); let fee_change_fees: OnceCell>> = OnceCell::new(); - let add_currency_pairs_fees: OnceCell>> = - OnceCell::new(); - let remove_currency_pairs_fees: OnceCell>> = - OnceCell::new(); + let price_feed_fees: OnceCell>> = OnceCell::new(); let mut fees_by_asset = HashMap::new(); for action in tx.actions() { @@ -368,12 +364,8 @@ pub(crate) async fn get_fees_for_transaction( let fees = get_or_init_fees(state, &fee_change_fees).await?; calculate_and_add_fees(act, &mut fees_by_asset, fees); } - Action::AddCurrencyPairs(act) => { - let fees = get_or_init_fees(state, &add_currency_pairs_fees).await?; - calculate_and_add_fees(act, &mut fees_by_asset, fees); - } - Action::RemoveCurrencyPairs(act) => { - let fees = get_or_init_fees(state, &remove_currency_pairs_fees).await?; + Action::PriceFeed(act) => { + let fees = get_or_init_fees(state, &price_feed_fees).await?; calculate_and_add_fees(act, &mut fees_by_asset, fees); } } diff --git a/crates/astria-sequencer/src/fees/storage/values.rs b/crates/astria-sequencer/src/fees/storage/values.rs index edf6b3ca8..a9dc3ca9f 100644 --- a/crates/astria-sequencer/src/fees/storage/values.rs +++ b/crates/astria-sequencer/src/fees/storage/values.rs @@ -1,7 +1,6 @@ use astria_core::protocol::{ fees::v1::FeeComponents as DomainFeeComponents, transaction::v1::action::{ - AddCurrencyPairs, BridgeLock, BridgeSudoChange, BridgeUnlock, @@ -11,7 +10,7 @@ use astria_core::protocol::{ IbcSudoChange, Ics20Withdrawal, InitBridgeAccount, - RemoveCurrencyPairs, + PriceFeed, RollupDataSubmission, SudoAddressChange, Transfer, @@ -48,8 +47,7 @@ enum ValueImpl { IbcRelayerChangeFees(FeeComponents), IbcSudoChangeFees(FeeComponents), SudoAddressChangeFees(FeeComponents), - AddCurrencyPairsFees(FeeComponents), - RemoveCurrencyPairsFees(FeeComponents), + PriceFeedFees(FeeComponents), } macro_rules! impl_from_for_fee_storage { @@ -113,6 +111,5 @@ impl_from_for_fee_storage!( DomainFeeComponents => IbcRelayerChangeFees, DomainFeeComponents => IbcSudoChangeFees, DomainFeeComponents => SudoAddressChangeFees, - DomainFeeComponents => AddCurrencyPairsFees, - DomainFeeComponents => RemoveCurrencyPairsFees, + DomainFeeComponents => PriceFeedFees, ); diff --git a/crates/astria-sequencer/src/transaction/checks.rs b/crates/astria-sequencer/src/transaction/checks.rs index 788f2c992..e8df0128b 100644 --- a/crates/astria-sequencer/src/transaction/checks.rs +++ b/crates/astria-sequencer/src/transaction/checks.rs @@ -118,8 +118,7 @@ pub(crate) async fn get_total_transaction_cost( | Action::IbcRelayerChange(_) | Action::FeeAssetChange(_) | Action::FeeChange(_) - | Action::AddCurrencyPairs(_) - | Action::RemoveCurrencyPairs(_) => { + | Action::PriceFeed(_) => { continue; } } diff --git a/proto/protocolapis/astria/protocol/fees/v1/types.proto b/proto/protocolapis/astria/protocol/fees/v1/types.proto index 5f5cdedef..9ee981729 100644 --- a/proto/protocolapis/astria/protocol/fees/v1/types.proto +++ b/proto/protocolapis/astria/protocol/fees/v1/types.proto @@ -79,12 +79,7 @@ message IbcSudoChangeFeeComponents { astria.primitive.v1.Uint128 multiplier = 2; } -message AddCurrencyPairsFeeComponents { - astria.primitive.v1.Uint128 base = 1; - astria.primitive.v1.Uint128 multiplier = 2; -} - -message RemoveCurrencyPairsFeeComponents { +message PriceFeedFeeComponents { astria.primitive.v1.Uint128 base = 1; astria.primitive.v1.Uint128 multiplier = 2; } diff --git a/proto/protocolapis/astria/protocol/genesis/v1/types.proto b/proto/protocolapis/astria/protocol/genesis/v1/types.proto index d6eb4f26b..550fc7d33 100644 --- a/proto/protocolapis/astria/protocol/genesis/v1/types.proto +++ b/proto/protocolapis/astria/protocol/genesis/v1/types.proto @@ -59,8 +59,7 @@ message GenesisFees { astria.protocol.fees.v1.SudoAddressChangeFeeComponents sudo_address_change = 12; astria.protocol.fees.v1.TransferFeeComponents transfer = 13; astria.protocol.fees.v1.ValidatorUpdateFeeComponents validator_update = 14; - astria.protocol.fees.v1.AddCurrencyPairsFeeComponents add_currency_pairs = 15; - astria.protocol.fees.v1.RemoveCurrencyPairsFeeComponents remove_currency_pairs = 16; + astria.protocol.fees.v1.PriceFeedFeeComponents price_feed = 15; } message ConnectGenesis { diff --git a/proto/protocolapis/astria/protocol/transaction/v1/action.proto b/proto/protocolapis/astria/protocol/transaction/v1/action.proto index 03177e55c..a673db098 100644 --- a/proto/protocolapis/astria/protocol/transaction/v1/action.proto +++ b/proto/protocolapis/astria/protocol/transaction/v1/action.proto @@ -32,9 +32,8 @@ message Action { FeeChange fee_change = 55; IbcSudoChange ibc_sudo_change = 56; - // Oracle actions are defined on 71-80 - AddCurrencyPairs add_currency_pairs = 71; - RemoveCurrencyPairs remove_currency_pairs = 72; + // Price feed actions are defined on 71-80 + PriceFeed price_feed = 71; } } @@ -233,8 +232,7 @@ message FeeChange { astria.protocol.fees.v1.SudoAddressChangeFeeComponents sudo_address_change = 12; astria.protocol.fees.v1.TransferFeeComponents transfer = 13; astria.protocol.fees.v1.ValidatorUpdateFeeComponents validator_update = 14; - astria.protocol.fees.v1.AddCurrencyPairsFeeComponents add_currency_pairs = 15; - astria.protocol.fees.v1.RemoveCurrencyPairsFeeComponents remove_currency_pairs = 16; + astria.protocol.fees.v1.PriceFeedFeeComponents price_feed = 15; } } @@ -242,10 +240,25 @@ message IbcSudoChange { astria.primitive.v1.Address new_address = 1; } -message AddCurrencyPairs { +// A transaction that modifies the price feed oracle settings. +message PriceFeed { + oneof value { + CurrencyPairsChange oracle = 1; + } +} + +// Add or remove currency pairs to/from the price feed oracle. +message CurrencyPairsChange { + oneof value { + CurrencyPairsToAdd addition = 1; + CurrencyPairsToRemove removal = 2; + } +} + +message CurrencyPairsToAdd { repeated connect.types.v2.CurrencyPair pairs = 1; } -message RemoveCurrencyPairs { +message CurrencyPairsToRemove { repeated connect.types.v2.CurrencyPair pairs = 1; }