From e150d04bc8289128a0f4e776403e8ed469e5d1ce Mon Sep 17 00:00:00 2001 From: Omar Date: Tue, 5 Mar 2024 16:37:04 +0300 Subject: [PATCH] [Publishing Tool]: Allow the publishing tool to run against stokenet --- Cargo.lock | 1 + tools/publishing-tool/Cargo.toml | 1 + .../default_configurations/mainnet_testing.rs | 1 + .../src/cli/default_configurations/mod.rs | 7 + .../stokenet_testing.rs | 243 ++++++++++++++++++ tools/publishing-tool/src/cli/publish.rs | 53 ++-- tools/publishing-tool/src/error.rs | 3 + .../src/publishing/configuration.rs | 23 ++ .../publishing-tool/src/publishing/handler.rs | 50 ++++ 9 files changed, 360 insertions(+), 22 deletions(-) create mode 100644 tools/publishing-tool/src/cli/default_configurations/stokenet_testing.rs diff --git a/Cargo.lock b/Cargo.lock index 617daa46..13486e6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2050,6 +2050,7 @@ dependencies = [ name = "publishing-tool" version = "0.1.0" dependencies = [ + "bitflags 2.4.2", "caviarnine-v1-adapter-v1", "clap", "common", diff --git a/tools/publishing-tool/Cargo.toml b/tools/publishing-tool/Cargo.toml index a3d462e3..c7735f98 100644 --- a/tools/publishing-tool/Cargo.toml +++ b/tools/publishing-tool/Cargo.toml @@ -43,6 +43,7 @@ hex-literal = "0.4.1" itertools = "0.12.1" serde_json = "1.0.114" clap = { version = "4.5.1", features = ["derive"] } +bitflags = "2.4.2" [lints] workspace = true diff --git a/tools/publishing-tool/src/cli/default_configurations/mainnet_testing.rs b/tools/publishing-tool/src/cli/default_configurations/mainnet_testing.rs index f22b1969..20d6f239 100644 --- a/tools/publishing-tool/src/cli/default_configurations/mainnet_testing.rs +++ b/tools/publishing-tool/src/cli/default_configurations/mainnet_testing.rs @@ -299,6 +299,7 @@ pub fn mainnet_testing( additional_information: AdditionalInformation { ociswap_v2_registry_component: None, }, + additional_operation_flags: AdditionalOperationFlags::empty() // cSpell:enable } } diff --git a/tools/publishing-tool/src/cli/default_configurations/mod.rs b/tools/publishing-tool/src/cli/default_configurations/mod.rs index 49a6f636..fa6d4188 100644 --- a/tools/publishing-tool/src/cli/default_configurations/mod.rs +++ b/tools/publishing-tool/src/cli/default_configurations/mod.rs @@ -1,10 +1,12 @@ use crate::*; use clap::*; mod mainnet_testing; +mod stokenet_testing; #[derive(ValueEnum, Clone, Copy, Debug)] pub enum ConfigurationSelector { MainnetTesting, + StokenetTesting, } impl ConfigurationSelector { @@ -16,18 +18,23 @@ impl ConfigurationSelector { Self::MainnetTesting => { mainnet_testing::mainnet_testing(notary_private_key) } + Self::StokenetTesting => { + stokenet_testing::stokenet_testing(notary_private_key) + } } } pub fn gateway_base_url(self) -> String { match self { Self::MainnetTesting => "https://mainnet.radixdlt.com".to_owned(), + Self::StokenetTesting => "https://stokenet.radixdlt.com".to_owned(), } } pub fn network_definition(self) -> NetworkDefinition { match self { Self::MainnetTesting => NetworkDefinition::mainnet(), + Self::StokenetTesting => NetworkDefinition::stokenet(), } } } diff --git a/tools/publishing-tool/src/cli/default_configurations/stokenet_testing.rs b/tools/publishing-tool/src/cli/default_configurations/stokenet_testing.rs new file mode 100644 index 00000000..9a273334 --- /dev/null +++ b/tools/publishing-tool/src/cli/default_configurations/stokenet_testing.rs @@ -0,0 +1,243 @@ +use common::prelude::*; + +use self::utils::*; +use crate::*; + +pub fn stokenet_testing( + notary_private_key: &PrivateKey, +) -> PublishingConfiguration { + let notary_account_address = + ComponentAddress::virtual_account_from_public_key( + ¬ary_private_key.public_key(), + ); + + // cSpell:disable + PublishingConfiguration { + protocol_configuration: ProtocolConfiguration { + protocol_resource: XRD, + user_resource_volatility: UserResourceIndexedData { + bitcoin: Volatility::Volatile, + ethereum: Volatility::Volatile, + usdc: Volatility::NonVolatile, + usdt: Volatility::NonVolatile, + }, + reward_rates: indexmap! { + LockupPeriod::from_minutes(0).unwrap() => dec!(0.125), // 12.5% + LockupPeriod::from_minutes(1).unwrap() => dec!(0.15), // 15.0% + }, + allow_opening_liquidity_positions: true, + allow_closing_liquidity_positions: true, + maximum_allowed_price_staleness: i64::MAX, + maximum_allowed_price_difference_percentage: Decimal::MAX, + entities_metadata: Entities { + protocol_entities: ProtocolIndexedData { + ignition: metadata_init! { + "name" => "Ignition", updatable; + "description" => "The main entrypoint into the Ignition liquidity incentive program.", updatable; + // Dapp definition will be automatically added by the + // publisher accordingly. + }, + simple_oracle: metadata_init! { + "name" => "Ignition Oracle", updatable; + "description" => "The oracle used by the Ignition protocol.", updatable; + "tags" => vec!["oracle"], updatable; + // Dapp definition will be automatically added by the + // publisher accordingly. + }, + }, + exchange_adapter_entities: ExchangeIndexedData { + ociswap_v2: metadata_init! { + "name" => "Ignition Ociswap v2 Adapter", updatable; + "description" => "An adapter used by the Ignition protocol to communicate with Ociswap v2 pools.", updatable; + // Dapp definition will be automatically added by the + // publisher accordingly. + }, + defiplaza_v2: metadata_init! { + "name" => "Ignition DefiPlaza v2 Adapter", updatable; + "description" => "An adapter used by the Ignition protocol to communicate with DefiPlaza v2 pools.", updatable; + // Dapp definition will be automatically added by the + // publisher accordingly. + }, + caviarnine_v1: metadata_init! { + "name" => "Ignition Caviarnine v1 Adapter", updatable; + "description" => "An adapter used by the Ignition protocol to communicate with Caviarnine v1 pools.", updatable; + // Dapp definition will be automatically added by the + // publisher accordingly. + }, + }, + }, + }, + dapp_definition_metadata: indexmap! { + "name".to_owned() => MetadataValue::String("Project Ignition".to_owned()), + "description".to_owned() => MetadataValue::String("A Radix liquidity incentives program, offered in partnership with select decentralized exchange dApps in the Radix ecosystem.".to_owned()), + "icon_url".to_owned() => MetadataValue::Url(UncheckedUrl::of("https://assets.radixdlt.com/icons/icon-Ignition-LP.png")) + }, + transaction_configuration: TransactionConfiguration { + notary: clone_private_key(notary_private_key), + fee_payer_information: AccountAndControllingKey::new_virtual_account( + clone_private_key(notary_private_key), + ), + }, + // TODO: Determine where they should be sent to. + badges: BadgeIndexedData { + oracle_manager_badge: BadgeHandling::CreateAndSend { + account_address: notary_account_address, + metadata_init: metadata_init! { + "name" => "Ignition Oracle Manager", updatable; + "symbol" => "IGNOM", updatable; + "description" => "A badge with the authority to update the Oracle prices of the Ignition oracle.", updatable; + "tags" => vec!["badge"], updatable; + // Dapp definition will be automatically added by the + // publisher accordingly. + }, + }, + protocol_manager_badge: BadgeHandling::CreateAndSend { + account_address: notary_account_address, + metadata_init: metadata_init! { + "name" => "Ignition Protocol Manager", updatable; + "symbol" => "IGNPM", updatable; + "description" => "A badge with the authority to manage the Ignition protocol.", updatable; + "tags" => vec!["badge"], updatable; + // Dapp definition will be automatically added by the + // publisher accordingly. + }, + }, + protocol_owner_badge: BadgeHandling::CreateAndSend { + account_address: notary_account_address, + metadata_init: metadata_init! { + "name" => "Ignition Protocol Owner", updatable; + "symbol" => "IGNPO", updatable; + "description" => "A badge with owner authority over the Ignition protocol.", updatable; + "tags" => vec!["badge"], updatable; + // Dapp definition will be automatically added by the + // publisher accordingly. + }, + }, + }, + // TODO: Not real resources, just the notXYZ resources. + user_resources: UserResourceIndexedData { + bitcoin: UserResourceHandling::UseExisting { + resource_address: resource_address!( + "resource_tdx_2_1thltk578jr4v7axqpu5ceznhlha6ca2qtzcflqdmytgtf37xncu7l9" + ), + }, + ethereum: UserResourceHandling::UseExisting { + resource_address: resource_address!( + "resource_tdx_2_1t59gx963vzd6u6fz63h5de2zh9nmgwxc8y832edmr6pxvz98wg6zu3" + ), + }, + usdc: UserResourceHandling::UseExisting { + resource_address: resource_address!( + "resource_tdx_2_1thfv477eqwlh8x4wt6xsc62myt4z0zxmdpr4ea74fa8jnxh243y60r" + ), + }, + usdt: UserResourceHandling::UseExisting { + resource_address: resource_address!( + "resource_tdx_2_1t4p3ytx933n576pdps4ua7jkjh36zrh36a543u0tfcsu2vthavlqg8" + ), + }, + }, + packages: Entities { + protocol_entities: ProtocolIndexedData { + ignition: PackageHandling::LoadAndPublish { + crate_package_name: "ignition".to_owned(), + metadata: metadata_init! { + "name" => "Ignition Package", updatable; + "description" => "The implementation of the Ignition protocol.", updatable; + "tags" => Vec::::new(), updatable; + // Dapp definition will be automatically added by the + // publisher accordingly. + }, + blueprint_name: "Ignition".to_owned(), + }, + simple_oracle: PackageHandling::LoadAndPublish { + crate_package_name: "simple-oracle".to_owned(), + metadata: metadata_init! { + "name" => "Ignition Simple Oracle Package", updatable; + "description" => "The implementation of the Oracle used by the Ignition protocol.", updatable; + "tags" => vec!["oracle"], updatable; + // Dapp definition will be automatically added by the + // publisher accordingly. + }, + blueprint_name: "SimpleOracle".to_owned(), + }, + }, + exchange_adapter_entities: ExchangeIndexedData { + ociswap_v2: PackageHandling::LoadAndPublish { + crate_package_name: "ociswap-v2-adapter-v1".to_owned(), + metadata: metadata_init! { + "name" => "Ignition Ociswap v2 Adapter Package", updatable; + "description" => "The implementation of an adapter for Ociswap v2 for the Ignition protocol.", updatable; + "tags" => vec!["adapter"], updatable; + // Dapp definition will be automatically added by the + // publisher accordingly. + }, + blueprint_name: "OciswapV2Adapter".to_owned(), + }, + defiplaza_v2: PackageHandling::LoadAndPublish { + crate_package_name: "defiplaza-v2-adapter-v1".to_owned(), + metadata: metadata_init! { + "name" => "Ignition DefiPlaza v2 Adapter Package", updatable; + "description" => "The implementation of an adapter for DefiPlaza v1 for the Ignition protocol.", updatable; + "tags" => vec!["adapter"], updatable; + // Dapp definition will be automatically added by the + // publisher accordingly. + }, + blueprint_name: "DefiPlazaV2Adapter".to_owned(), + }, + caviarnine_v1: PackageHandling::LoadAndPublish { + crate_package_name: "caviarnine-v1-adapter-v1".to_owned(), + metadata: metadata_init! { + "name" => "Ignition Caviarnine v1 Adapter Package", updatable; + "description" => "The implementation of an adapter for Caviarnine v1 for the Ignition protocol.", updatable; + "tags" => vec!["adapter"], updatable; + // Dapp definition will be automatically added by the + // publisher accordingly. + }, + blueprint_name: "CaviarnineV1Adapter".to_owned(), + }, + }, + }, + exchange_information: ExchangeIndexedData { + // No ociswap v2 currently on mainnet. + ociswap_v2: Some(ExchangeInformation { + blueprint_id: BlueprintId { + package_address: package_address!( + "package_tdx_2_1phgf5er6zx60wu4jjhtps97akqjpv787f6k7rjqkxgdpacng89a4uz" + ), + blueprint_name: "LiquidityPool".to_owned(), + }, + pools: UserResourceIndexedData { + bitcoin: PoolHandling::Create, + ethereum: PoolHandling::Create, + usdc: PoolHandling::Create, + usdt: PoolHandling::Create, + }, + liquidity_receipt: LiquidityReceiptHandling::CreateNew { + non_fungible_schema: + NonFungibleDataSchema::new_local_without_self_package_replacement::< + LiquidityReceipt, + >(), + metadata: metadata_init! { + "name" => "Ignition LP: Ociswap", updatable; + "description" => "Represents a particular contribution of liquidity to Ociswap through the Ignition liquidity incentives program. See the redeem_url metadata for where to redeem these NFTs.", updatable; + "tags" => vec!["lp token"], updatable; + "icon_url" => UncheckedUrl::of("https://assets.radixdlt.com/icons/icon-Ignition-LP.png"), updatable; + "DEX" => "Ociswap", updatable; + // TODO: Must get this from the DEX + "redeem_url" => UncheckedUrl::of("https://www.google.com"), updatable; + }, + }, + }), + caviarnine_v1: None, + defiplaza_v2: None, + }, + additional_information: AdditionalInformation { + ociswap_v2_registry_component: Some(component_address!( + "component_tdx_2_1cpwm3sjxr48gmsnh7lgmh5de3eqqzthqkazztc4qv6n3fvedgjepwk" + )), + }, + additional_operation_flags: AdditionalOperationFlags::SUBMIT_ORACLE_PRICES_OF_ONE + // cSpell:enable + } +} diff --git a/tools/publishing-tool/src/cli/publish.rs b/tools/publishing-tool/src/cli/publish.rs index 3815d301..31e1daeb 100644 --- a/tools/publishing-tool/src/cli/publish.rs +++ b/tools/publishing-tool/src/cli/publish.rs @@ -12,11 +12,15 @@ pub struct Publish { /// The configuration that the user wants to use when publishing. configuration_selector: ConfigurationSelector, - /// The path to the state manager database. - state_manager_database_path: PathBuf, - /// The hex-encoded private key of the notary. notary_ed25519_private_key_hex: String, + + /// The path to the state manager database. If no path is provided for the + /// state manager database then it will be assumed that the user does not + /// wish to do a simulation before publishing and is comfortable doing an + /// actual run straightaway. + #[clap(short, long)] + state_manager_database_path: Option, } impl Publish { @@ -33,18 +37,31 @@ impl Publish { let configuration = self .configuration_selector .configuration(¬ary_private_key); - - // Creating the network connection providers to use for the deployments let network_definition = self.configuration_selector.network_definition(); + + // Creating the network connection providers to use for the deployments + if let Some(state_manager_database_path) = + self.state_manager_database_path + { + let database = + RocksDBStore::new_read_only(state_manager_database_path) + .map_err(Error::RocksDbOpenError)?; + + let mut simulator_network_provider = SimulatorNetworkConnector::new( + &database, + network_definition.clone(), + ); + + // Running a dry run of the publishing process against the simulator + // network provider. + log::info!("Publishing against the simulator"); + publish(&configuration, &mut simulator_network_provider)?; + } + + // Running the transactions against the network. + log::info!("Publishing against the gateway"); let gateway_base_url = self.configuration_selector.gateway_base_url(); - let database = - RocksDBStore::new_read_only(self.state_manager_database_path) - .unwrap(); - let mut simulator_network_provider = SimulatorNetworkConnector::new( - &database, - network_definition.clone(), - ); let mut gateway_network_provider = GatewayNetworkConnector::new( gateway_base_url, network_definition.clone(), @@ -53,16 +70,8 @@ impl Publish { retries: 10, }, ); - - // Running a dry run of the publishing process against the simulator - // network provider. - log::info!("Publishing against the simulator"); - publish(&configuration, &mut simulator_network_provider)?; - - // Running the transactions against the network. - log::info!("Publishing against the gateway"); let receipt = publish(&configuration, &mut gateway_network_provider)?; - writeln!(f, "{}", to_json(&receipt, &network_definition)).unwrap(); - Ok(()) + writeln!(f, "{}", to_json(&receipt, &network_definition)) + .map_err(Error::IoError) } } diff --git a/tools/publishing-tool/src/error.rs b/tools/publishing-tool/src/error.rs index 42cdceaa..20ecbca7 100644 --- a/tools/publishing-tool/src/error.rs +++ b/tools/publishing-tool/src/error.rs @@ -1,10 +1,13 @@ use crate::*; +use state_manager::traits::*; #[derive(Debug)] pub enum Error { PrivateKeyError, GatewayExecutorError(PublishingError), SimulatorExecutorError(PublishingError), + IoError(std::io::Error), + RocksDbOpenError(DatabaseConfigValidationError), } impl From> for Error { diff --git a/tools/publishing-tool/src/publishing/configuration.rs b/tools/publishing-tool/src/publishing/configuration.rs index 9125fe9a..510734d2 100644 --- a/tools/publishing-tool/src/publishing/configuration.rs +++ b/tools/publishing-tool/src/publishing/configuration.rs @@ -44,6 +44,10 @@ pub struct PublishingConfiguration { /// Additional information that doesn't quite fit into any of the above /// categories nicely. pub additional_information: AdditionalInformation, + + /// Bit flags for additional operations that can be done by the publishing + /// logic during the publishing process. + pub additional_operation_flags: AdditionalOperationFlags, } #[derive(Debug, Clone, ScryptoSbor)] @@ -54,6 +58,25 @@ pub struct PublishingReceipt { Option>, >, pub protocol_configuration: ProtocolConfigurationReceipt, + pub badges: BadgeIndexedData, +} + +bitflags::bitflags! { + /// Additional operations that the publishing process can be instructed to + /// perform. + #[repr(transparent)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct AdditionalOperationFlags: u8 { + /// Submits prices to the oracle that are just one for all of the assets + /// supported in the deployment. + const SUBMIT_ORACLE_PRICES_OF_ONE = 0b00000001; + + /// Provide initial liquidity to Ignition. How this is done depends on + /// the selected protocol resource. If it is XRD then the publisher will + /// attempt to get the XRD from the faucet. If otherwise then it will + /// attempt to mint it. + const PROVIDE_INITIAL_IGNITION_LIQUIDITY = 0b00000010; + } } #[derive(Debug, Clone, ScryptoSbor)] diff --git a/tools/publishing-tool/src/publishing/handler.rs b/tools/publishing-tool/src/publishing/handler.rs index 769af58e..f53e9358 100644 --- a/tools/publishing-tool/src/publishing/handler.rs +++ b/tools/publishing-tool/src/publishing/handler.rs @@ -927,6 +927,55 @@ pub fn publish( execution_service.execute_manifest(manifest)?; } + // Processing the additional operations specified in the publishing config + { + // Submitting prices to the oracle with (user_asset, protocol_asset) + // and (protocol_asset, user_asset) where the price of both is equal + // to one. + if configuration + .additional_operation_flags + .contains(AdditionalOperationFlags::SUBMIT_ORACLE_PRICES_OF_ONE) + { + let price_updates = resolved_user_resources + .iter() + .copied() + .flat_map(|address| { + [ + ( + address, + configuration + .protocol_configuration + .protocol_resource, + ), + ( + configuration + .protocol_configuration + .protocol_resource, + address, + ), + ] + }) + .map(|address_pair| (address_pair, dec!(1))) + .collect::>(); + + let manifest = ManifestBuilder::new() + .create_proof_from_account_of_amount( + resolved_badges.oracle_manager_badge.0, + resolved_badges.oracle_manager_badge.1, + dec!(1), + ) + .call_method( + resolved_entity_component_addresses + .protocol_entities + .simple_oracle, + "set_price_batch", + (price_updates,), + ) + .build(); + execution_service.execute_manifest(manifest)?; + } + } + // Depositing the created badges into their accounts. { let mut manifest_builder = ManifestBuilder::new(); @@ -993,6 +1042,7 @@ pub fn publish( information.as_ref().map(|information| information.pools) }), }, + badges: resolved_badges.map(|(_, address)| *address), }) }