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/packages/ociswap-v2-adapter-v1/src/lib.rs b/packages/ociswap-v2-adapter-v1/src/lib.rs index 3ad18d58..7e03d93d 100644 --- a/packages/ociswap-v2-adapter-v1/src/lib.rs +++ b/packages/ociswap-v2-adapter-v1/src/lib.rs @@ -171,12 +171,24 @@ pub mod adapter { let (receipt, change_x, change_y) = pool.add_liquidity(lower_tick, upper_tick, bucket_x, bucket_y); + let non_fungible = receipt + .as_non_fungible() + .non_fungible::(); + let non_fungible_data = non_fungible.data(); + let non_fungible_global_id = non_fungible.global_id().clone(); + OpenLiquidityPositionOutput { pool_units: IndexedBuckets::from_bucket(receipt), change: IndexedBuckets::from_buckets([change_x, change_y]), others: Default::default(), - adapter_specific_information: AnyValue::from_typed(&()) - .expect(UNEXPECTED_ERROR), + adapter_specific_information: AnyValue::from_typed( + &OciswapV2AdapterSpecificInformation { + liquidity_receipt_non_fungible_global_id: + non_fungible_global_id, + liquidity_receipt_data: non_fungible_data, + }, + ) + .expect(UNEXPECTED_ERROR), } } @@ -246,10 +258,28 @@ pub mod adapter { } #[derive(ScryptoSbor, Debug, Clone)] -pub struct OciswapV2AdapterSpecificInformation {} +pub struct OciswapV2AdapterSpecificInformation { + /// Stores the non-fungible global id of the liquidity receipt. + pub liquidity_receipt_non_fungible_global_id: NonFungibleGlobalId, + + /// The data of the underlying liquidity receipt + pub liquidity_receipt_data: LiquidityPosition, +} impl From for AnyValue { fn from(value: OciswapV2AdapterSpecificInformation) -> Self { AnyValue::from_typed(&value).unwrap() } } + +#[derive(NonFungibleData, ScryptoSbor, Debug, Clone)] +pub struct LiquidityPosition { + liquidity: PreciseDecimal, + left_bound: i32, + right_bound: i32, + shape_id: Option, + x_fee_checkpoint: PreciseDecimal, + y_fee_checkpoint: PreciseDecimal, + x_total_fee_checkpoint: PreciseDecimal, + y_total_fee_checkpoint: PreciseDecimal, +} diff --git a/tools/publishing-tool/Cargo.toml b/tools/publishing-tool/Cargo.toml index a3d462e3..70229bb8 100644 --- a/tools/publishing-tool/Cargo.toml +++ b/tools/publishing-tool/Cargo.toml @@ -43,6 +43,14 @@ 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 + +[lib] +crate-type = ["cdylib", "lib"] + +[[bin]] +name = "publishing-tool" +path = "src/cli/bin.rs" \ No newline at end of file diff --git a/tools/publishing-tool/src/cli/bin.rs b/tools/publishing-tool/src/cli/bin.rs new file mode 100644 index 00000000..083e5238 --- /dev/null +++ b/tools/publishing-tool/src/cli/bin.rs @@ -0,0 +1,29 @@ +#![allow(dead_code, clippy::enum_variant_names, clippy::wrong_self_convention)] + +mod default_configurations; +mod publish; + +use clap::Parser; +use publishing_tool::error::*; +use radix_engine_common::prelude::*; +use transaction::prelude::*; + +fn main() -> Result<(), Error> { + env_logger::init(); + let mut out = std::io::stdout(); + let cli = ::parse(); + cli.run(&mut out) +} + +#[derive(Parser, Debug)] +pub enum Cli { + Publish(publish::Publish), +} + +impl Cli { + pub fn run(self, out: &mut O) -> Result<(), Error> { + match self { + Self::Publish(cmd) => cmd.run(out), + } + } +} 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..e03ae788 100644 --- a/tools/publishing-tool/src/cli/default_configurations/mainnet_testing.rs +++ b/tools/publishing-tool/src/cli/default_configurations/mainnet_testing.rs @@ -1,7 +1,9 @@ use common::prelude::*; - -use self::utils::*; -use crate::*; +use publishing_tool::publishing::*; +use publishing_tool::utils::*; +use publishing_tool::*; +use radix_engine_interface::prelude::*; +use transaction::prelude::*; pub fn mainnet_testing( notary_private_key: &PrivateKey, @@ -297,8 +299,8 @@ pub fn mainnet_testing( }), }, additional_information: AdditionalInformation { - ociswap_v2_registry_component: None, + ociswap_v2_registry_component_and_dapp_definition: None, }, - // cSpell:enable + 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..d5f6e946 100644 --- a/tools/publishing-tool/src/cli/default_configurations/mod.rs +++ b/tools/publishing-tool/src/cli/default_configurations/mod.rs @@ -1,10 +1,14 @@ -use crate::*; -use clap::*; mod mainnet_testing; +mod stokenet_testing; + +use clap::*; +use publishing_tool::publishing::*; +use transaction::prelude::*; #[derive(ValueEnum, Clone, Copy, Debug)] pub enum ConfigurationSelector { MainnetTesting, + StokenetTesting, } impl ConfigurationSelector { @@ -16,18 +20,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..eee3d1f6 --- /dev/null +++ b/tools/publishing-tool/src/cli/default_configurations/stokenet_testing.rs @@ -0,0 +1,255 @@ +use common::prelude::*; +use publishing_tool::publishing::*; +use publishing_tool::utils::*; +use publishing_tool::*; +use radix_engine_interface::prelude::*; +use transaction::prelude::*; + +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_and_dapp_definition: Some(( + component_address!( + "component_tdx_2_1cpwm3sjxr48gmsnh7lgmh5de3eqqzthqkazztc4qv6n3fvedgjepwk" + ), + component_address!( + "account_tdx_2_12yhfrtak5j0pmaju5l3p752wpye4z4nzua679ypns0094hmu66p2yk" + ), + )), + }, + additional_operation_flags: + AdditionalOperationFlags::SUBMIT_ORACLE_PRICES_OF_ONE + .union(AdditionalOperationFlags::PROVIDE_INITIAL_IGNITION_LIQUIDITY) + .union( + AdditionalOperationFlags::PROVIDE_INITIAL_LIQUIDITY_TO_OCISWAP_BY_MINTING_USER_RESOURCE + ) + } + // cSpell:enable +} diff --git a/tools/publishing-tool/src/cli/mod.rs b/tools/publishing-tool/src/cli/mod.rs deleted file mode 100644 index e9eb4a83..00000000 --- a/tools/publishing-tool/src/cli/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -mod default_configurations; -mod publish; - -use crate::Error; -use clap::Parser; - -#[derive(Parser, Debug)] -pub enum Cli { - Publish(publish::Publish), -} - -impl Cli { - pub fn run(self, out: &mut O) -> Result<(), Error> { - match self { - Self::Publish(cmd) => cmd.run(out), - } - } -} diff --git a/tools/publishing-tool/src/cli/publish.rs b/tools/publishing-tool/src/cli/publish.rs index 3815d301..51faba50 100644 --- a/tools/publishing-tool/src/cli/publish.rs +++ b/tools/publishing-tool/src/cli/publish.rs @@ -1,7 +1,9 @@ -use super::default_configurations::*; -use crate::utils::*; +use crate::default_configurations::*; use crate::*; use clap::Parser; +use publishing_tool::network_connection_provider::*; +use publishing_tool::publishing::*; +use publishing_tool::utils::*; use radix_engine_common::prelude::*; use state_manager::RocksDBStore; use std::path::*; @@ -12,11 +14,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 +39,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 +72,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..d428f402 100644 --- a/tools/publishing-tool/src/error.rs +++ b/tools/publishing-tool/src/error.rs @@ -1,10 +1,14 @@ -use crate::*; +use crate::network_connection_provider::*; +use crate::publishing::*; +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/lib.rs b/tools/publishing-tool/src/lib.rs new file mode 100644 index 00000000..57f31540 --- /dev/null +++ b/tools/publishing-tool/src/lib.rs @@ -0,0 +1,6 @@ +pub mod database_overlay; +pub mod error; +pub mod macros; +pub mod network_connection_provider; +pub mod publishing; +pub mod utils; diff --git a/tools/publishing-tool/src/main.rs b/tools/publishing-tool/src/main.rs deleted file mode 100644 index dd1d9a88..00000000 --- a/tools/publishing-tool/src/main.rs +++ /dev/null @@ -1,23 +0,0 @@ -#![allow(dead_code, clippy::enum_variant_names, clippy::wrong_self_convention)] - -mod cli; -mod database_overlay; -mod error; -mod network_connection_provider; -mod publishing; -mod utils; -#[macro_use] -mod macros; - -use error::*; -use network_connection_provider::*; -use publishing::*; -use radix_engine_common::prelude::*; -use transaction::prelude::*; - -fn main() -> Result<(), Error> { - env_logger::init(); - let mut out = std::io::stdout(); - let cli = ::parse(); - cli.run(&mut out) -} diff --git a/tools/publishing-tool/src/publishing/configuration.rs b/tools/publishing-tool/src/publishing/configuration.rs index 9125fe9a..1defbba4 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,30 @@ 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; + + /// Provides initial liquidity to ociswap v2 pools by minting the user + /// asset. If the protocol asset is mintable then it mints them in the + /// process and if they're not then it gets them from the faucet. + const PROVIDE_INITIAL_LIQUIDITY_TO_OCISWAP_BY_MINTING_USER_RESOURCE = 0b00000100; + } } #[derive(Debug, Clone, ScryptoSbor)] @@ -71,7 +99,8 @@ pub struct ProtocolConfigurationReceipt { } pub struct AdditionalInformation { - pub ociswap_v2_registry_component: Option, + pub ociswap_v2_registry_component_and_dapp_definition: + Option<(ComponentAddress, ComponentAddress)>, } pub struct ProtocolConfiguration { diff --git a/tools/publishing-tool/src/publishing/handler.rs b/tools/publishing-tool/src/publishing/handler.rs index 769af58e..98c170c6 100644 --- a/tools/publishing-tool/src/publishing/handler.rs +++ b/tools/publishing-tool/src/publishing/handler.rs @@ -3,6 +3,7 @@ use defiplaza_v2_adapter_v1::*; use ignition::{InitializationParametersManifest, PoolBlueprintInformation}; use itertools::*; +use ociswap_v2_adapter_v1::OciswapV2PoolInterfaceManifestBuilderExtensionTrait; use package_loader::*; use radix_engine::blueprints::package::*; use radix_engine::types::node_modules::*; @@ -927,6 +928,168 @@ 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)?; + } + + // Seeding Ignition with the initial set of XRD if requested. + if configuration.additional_operation_flags.contains( + AdditionalOperationFlags::PROVIDE_INITIAL_IGNITION_LIQUIDITY, + ) { + let total_amount_of_protocol_resource = dec!(10_000); + let mut manifest_builder = ManifestBuilder::new() + .create_proof_from_account_of_amount( + resolved_badges.protocol_owner_badge.0, + resolved_badges.protocol_owner_badge.1, + dec!(1), + ); + if configuration.protocol_configuration.protocol_resource == XRD { + manifest_builder = manifest_builder.get_free_xrd_from_faucet() + } else { + manifest_builder = manifest_builder.mint_fungible( + configuration.protocol_configuration.protocol_resource, + total_amount_of_protocol_resource, + ) + } + + let manifest = manifest_builder + .take_from_worktop( + XRD, + total_amount_of_protocol_resource / 2, + "volatile", + ) + .take_from_worktop( + XRD, + total_amount_of_protocol_resource / 2, + "non_volatile", + ) + .with_name_lookup(|builder, _| { + let volatile = builder.bucket("volatile"); + let non_volatile = builder.bucket("non_volatile"); + + builder + .call_method( + resolved_entity_component_addresses + .protocol_entities + .ignition, + "deposit_protocol_resources", + (volatile, common::prelude::Volatility::Volatile), + ) + .call_method( + resolved_entity_component_addresses + .protocol_entities + .ignition, + "deposit_protocol_resources", + ( + non_volatile, + common::prelude::Volatility::NonVolatile, + ), + ) + }) + .build(); + execution_service.execute_manifest(manifest)?; + } + + // Contributing initial liquidity to Ociswap if requested + if configuration.additional_operation_flags.contains( + AdditionalOperationFlags::PROVIDE_INITIAL_LIQUIDITY_TO_OCISWAP_BY_MINTING_USER_RESOURCE, + ) { + if let Some(ExchangeInformation { pools, .. }) = resolved_exchange_data.ociswap_v2 { + for (pool_address, user_resource_address) in + pools.zip_borrowed(&resolved_user_resources).iter() + { + let (pool_address, user_resource_address) = + (*pool_address, **user_resource_address); + + let mut manifest_builder = ManifestBuilder::new(); + if configuration.protocol_configuration.protocol_resource == XRD { + manifest_builder = manifest_builder.get_free_xrd_from_faucet() + } else { + manifest_builder = manifest_builder.mint_fungible( + configuration.protocol_configuration.protocol_resource, + dec!(10_000), + ) + } + let manifest = manifest_builder + .mint_fungible(user_resource_address, dec!(10_000)) + .take_all_from_worktop( + configuration.protocol_configuration.protocol_resource, + "protocol", + ) + .take_all_from_worktop(user_resource_address, "user") + .then(|builder| { + let protocol_resource = builder.bucket("protocol"); + let user_resource = builder.bucket("user"); + + let (x_bucket, y_bucket) = + if configuration.protocol_configuration.protocol_resource + < user_resource_address + { + (protocol_resource, user_resource) + } else { + (user_resource, protocol_resource) + }; + + builder.ociswap_v2_pool_add_liquidity( + pool_address, + -3921i32, + 9942i32, + x_bucket, + y_bucket, + ) + }) + .try_deposit_entire_worktop_or_abort(ephemeral_account, None) + .build(); + execution_service.execute_manifest(manifest)?; + } + } + } + } + // Depositing the created badges into their accounts. { let mut manifest_builder = ManifestBuilder::new(); @@ -993,6 +1156,7 @@ pub fn publish( information.as_ref().map(|information| information.pools) }), }, + badges: resolved_badges.map(|(_, address)| *address), }) } @@ -1013,7 +1177,11 @@ fn handle_ociswap_v2_exchange_information( > { // No ociswap registry component is passed even through it is needed. let AdditionalInformation { - ociswap_v2_registry_component: Some(ociswap_v2_registry_component), + ociswap_v2_registry_component_and_dapp_definition: + Some(( + ociswap_v2_registry_component, + ociswap_v2_dapp_definition_account, + )), } = additional_information else { return Ok(None); @@ -1080,8 +1248,7 @@ fn handle_ociswap_v2_exchange_information( ManifestBucket, )>::new( ), - // TODO: Specify their dapp definition? - FAUCET, + ociswap_v2_dapp_definition_account, ), ) .build();