diff --git a/Cargo.lock b/Cargo.lock index bc616164..f7e93e1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5427,6 +5427,7 @@ dependencies = [ "bech32 0.11.0", "config", "cosmos-grpc-client", + "cosmwasm-crypto 2.1.4", "cosmwasm-schema 2.1.4", "cosmwasm-std 2.1.4", "cw-ownable", @@ -5440,6 +5441,7 @@ dependencies = [ "once_cell", "prost 0.12.6", "prost-types 0.12.6", + "rand_core 0.6.4", "serde", "serde_json", "serde_json_any_key", @@ -5454,9 +5456,11 @@ dependencies = [ "valence-authorization", "valence-authorization-utils", "valence-forwarder-library", + "valence-generic-ibc-transfer-library", "valence-library-base", "valence-library-utils", "valence-macros", + "valence-neutron-ibc-transfer-library", "valence-osmosis-cl-lper", "valence-osmosis-cl-withdrawer", "valence-osmosis-gamm-lper", diff --git a/Cargo.toml b/Cargo.toml index 63b77532..7fb54bc3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ overflow-checks = true anyhow = "1.0.86" cosmwasm-std = { version = "2.1.3" } cosmwasm-schema = "2.1.3" +cosmwasm-crypto = "2.1.3" cw-denom = { package = "cw-denom", git = "https://github.com/DA0-DA0/dao-contracts", branch = "cw-std-2" } cw-ownable = "2.0.0" cw-utils = "2.0.0" diff --git a/local-interchaintest/examples/manager_test.rs b/local-interchaintest/examples/manager_test.rs index 279d81c3..c44530ca 100644 --- a/local-interchaintest/examples/manager_test.rs +++ b/local-interchaintest/examples/manager_test.rs @@ -270,7 +270,6 @@ fn main() -> Result<(), Box> { &authorization_addr, format!("update_library_{}", library_1.get_library_id()).as_str(), ); - contract_execute( test_ctx .get_request_builder() diff --git a/local-interchaintest/examples/test.rs b/local-interchaintest/examples/test.rs new file mode 100644 index 00000000..b1694b65 --- /dev/null +++ b/local-interchaintest/examples/test.rs @@ -0,0 +1,109 @@ +use std::error::Error; + +use local_interchaintest::utils::{ + manager::{setup_manager, use_manager_init, SPLITTER_NAME}, + LOGS_FILE_PATH, NEUTRON_CONFIG_FILE, VALENCE_ARTIFACTS_PATH, +}; +use localic_utils::{ + ConfigChainBuilder, TestContextBuilder, GAIA_CHAIN_NAME, LOCAL_IC_API_URL, + NEUTRON_CHAIN_ADMIN_ADDR, NEUTRON_CHAIN_NAME, +}; +use valence_authorization_utils::{ + authorization_message::{Message, MessageDetails, MessageType, ParamRestriction}, + builders::{AtomicFunctionBuilder, AtomicSubroutineBuilder, AuthorizationBuilder}, +}; +use valence_library_utils::denoms::UncheckedDenom; +use valence_program_manager::{ + account::{AccountInfo, AccountType}, + library::{LibraryConfig, LibraryInfo}, + program_config_builder::ProgramConfigBuilder, +}; +use valence_splitter_library::msg::{UncheckedSplitAmount, UncheckedSplitConfig}; + +fn main() -> Result<(), Box> { + env_logger::init(); + + let mut test_ctx = TestContextBuilder::default() + .with_unwrap_raw_logs(true) + .with_api_url(LOCAL_IC_API_URL) + .with_artifacts_dir(VALENCE_ARTIFACTS_PATH) + .with_chain(ConfigChainBuilder::default_neutron().build()?) + .with_log_file_path(LOGS_FILE_PATH) + .build()?; + + setup_manager( + &mut test_ctx, + NEUTRON_CONFIG_FILE, + vec![GAIA_CHAIN_NAME], + vec![SPLITTER_NAME], + )?; + + let mut builder = ProgramConfigBuilder::new(NEUTRON_CHAIN_ADMIN_ADDR.to_string()); + let neutron_domain = + valence_program_manager::domain::Domain::CosmosCosmwasm(NEUTRON_CHAIN_NAME.to_string()); + + let account_1 = builder.add_account(AccountInfo::new( + "test_1".to_string(), + &neutron_domain, + AccountType::default(), + )); + let account_2 = builder.add_account(AccountInfo::new( + "test_2".to_string(), + &neutron_domain, + AccountType::default(), + )); + + let library_config = valence_splitter_library::msg::LibraryConfig { + input_addr: account_1.clone(), + splits: vec![UncheckedSplitConfig { + denom: UncheckedDenom::Native("test".to_string()), + account: account_2.clone(), + amount: UncheckedSplitAmount::FixedAmount(1000_u128.into()), + }], + }; + + let library_1 = builder.add_library(LibraryInfo::new( + "test_splitter".to_string(), + &neutron_domain, + LibraryConfig::ValenceSplitterLibrary(library_config.clone()), + )); + + builder.add_link(&library_1, vec![&account_1], vec![&account_2]); + + let action_label = "swap"; + builder.add_authorization( + AuthorizationBuilder::new() + .with_label(action_label) + .with_subroutine( + AtomicSubroutineBuilder::new() + .with_function( + AtomicFunctionBuilder::new() + .with_contract_address(library_1.clone()) + .with_message_details(MessageDetails { + message_type: MessageType::CosmwasmExecuteMsg, + message: Message { + name: "process_function".to_string(), + params_restrictions: Some(vec![ + ParamRestriction::MustBeIncluded(vec![ + "process_function".to_string(), + "split".to_string(), + ]), + ]), + }, + }) + .build(), + ) + .build(), + ) + .build(), + ); + + let mut program_config = builder.build(); + let mut program_config2 = program_config.clone(); + + use_manager_init(&mut program_config)?; + + use_manager_init(&mut program_config2)?; + + Ok(()) +} diff --git a/packages/valence-macros/src/lib.rs b/packages/valence-macros/src/lib.rs index fb3aeefa..24ef111e 100644 --- a/packages/valence-macros/src/lib.rs +++ b/packages/valence-macros/src/lib.rs @@ -158,7 +158,7 @@ pub fn manager_impl_library_configs(_attr: TokenStream, input: TokenStream) -> T let mut update_msg_matches = Vec::new(); let mut replace_config_matches = Vec::new(); let mut get_instantiate_msg_matches = Vec::new(); - let mut per_validate_matches = Vec::new(); + let mut pre_validate_matches = Vec::new(); let mut get_account_ids_matches = Vec::new(); for variant in variants { @@ -181,7 +181,7 @@ pub fn manager_impl_library_configs(_attr: TokenStream, input: TokenStream) -> T get_instantiate_msg_matches.push(quote! { #enum_ident::None => return Err(LibraryError::NoLibraryConfig) }); - per_validate_matches.push(quote! { + pre_validate_matches.push(quote! { #enum_ident::None => Err(LibraryError::NoLibraryConfig) }); get_account_ids_matches.push(quote! { @@ -238,8 +238,8 @@ pub fn manager_impl_library_configs(_attr: TokenStream, input: TokenStream) -> T }) }); - // Add per_validate_config match - per_validate_matches.push(quote! { + // Add pre_validate_config match + pre_validate_matches.push(quote! { #enum_ident::#variant_ident(config) => { config.pre_validate(api)?; Ok(()) @@ -310,9 +310,9 @@ pub fn manager_impl_library_configs(_attr: TokenStream, input: TokenStream) -> T .map_err(LibraryError::SerdeJsonError) } - pub fn per_validate_config(&self, api: &dyn cosmwasm_std::Api) -> LibraryResult<()> { + pub fn pre_validate_config(&self, api: &dyn cosmwasm_std::Api) -> LibraryResult<()> { match self { - #(#per_validate_matches,)* + #(#pre_validate_matches,)* } } diff --git a/program-manager/Cargo.toml b/program-manager/Cargo.toml index 94c28830..e20bc53f 100644 --- a/program-manager/Cargo.toml +++ b/program-manager/Cargo.toml @@ -10,6 +10,7 @@ repository = { workspace = true } [dependencies] cosmwasm-std = { workspace = true } cosmwasm-schema = { workspace = true } +cosmwasm-crypto = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } thiserror = { workspace = true } @@ -17,6 +18,7 @@ anyhow = { workspace = true } cw-ownable = { workspace = true } env_logger = { workspace = true } log = { workspace = true } +rand_core = "0.6.4" valence-library-utils = { workspace = true } valence-macros = { workspace = true } @@ -25,19 +27,21 @@ valence-processor-utils = { workspace = true } valence-program-registry-utils = { workspace = true } valence-library-base = { workspace = true } -valence-splitter-library = { workspace = true } -valence-reverse-splitter-library = { workspace = true } -valence-astroport-lper = { workspace = true } -valence-astroport-withdrawer = { workspace = true } -valence-account-utils = { workspace = true } -valence-authorization = { workspace = true } -valence-processor = { workspace = true } -valence-program-registry = { workspace = true } -valence-forwarder-library = { workspace = true } -valence-osmosis-gamm-lper = { workspace = true } -valence-osmosis-gamm-withdrawer = { workspace = true } -valence-osmosis-cl-lper = { workspace = true } -valence-osmosis-cl-withdrawer = { workspace = true } +valence-splitter-library = { workspace = true } +valence-reverse-splitter-library = { workspace = true } +valence-astroport-lper = { workspace = true } +valence-astroport-withdrawer = { workspace = true } +valence-account-utils = { workspace = true } +valence-authorization = { workspace = true } +valence-processor = { workspace = true } +valence-program-registry = { workspace = true } +valence-forwarder-library = { workspace = true } +valence-osmosis-gamm-lper = { workspace = true } +valence-osmosis-gamm-withdrawer = { workspace = true } +valence-osmosis-cl-lper = { workspace = true } +valence-osmosis-cl-withdrawer = { workspace = true } +valence-generic-ibc-transfer-library = { workspace = true } +valence-neutron-ibc-transfer-library = { workspace = true } tokio = { workspace = true } aho-corasick = "1.1" diff --git a/program-manager/schema/valence-program-manager.json b/program-manager/schema/valence-program-manager.json index b0b27243..75894f5d 100644 --- a/program-manager/schema/valence-program-manager.json +++ b/program-manager/schema/valence-program-manager.json @@ -611,6 +611,28 @@ }, "additionalProperties": false }, + "IbcTransferAmount": { + "oneOf": [ + { + "type": "string", + "enum": [ + "full_amount" + ] + }, + { + "type": "object", + "required": [ + "fixed_amount" + ], + "properties": { + "fixed_amount": { + "$ref": "#/definitions/Uint128" + } + }, + "additionalProperties": false + } + ] + }, "Int64": { "description": "An implementation of i64 that is using strings for JSON encoding/decoding, such that the full i64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `i64` to get the value out:\n\n``` # use cosmwasm_std::Int64; let a = Int64::from(258i64); assert_eq!(a.i64(), 258); ```", "type": "string" @@ -752,6 +774,30 @@ }, "additionalProperties": false }, + { + "type": "object", + "required": [ + "ValenceGenericIbcTransferLibrary" + ], + "properties": { + "ValenceGenericIbcTransferLibrary": { + "$ref": "#/definitions/LibraryConfigUpdate9" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "ValenceNeutronIbcTransferLibrary" + ], + "properties": { + "ValenceNeutronIbcTransferLibrary": { + "$ref": "#/definitions/LibraryConfigUpdate9" + } + }, + "additionalProperties": false + }, { "type": "object", "required": [ @@ -759,7 +805,7 @@ ], "properties": { "ValenceOsmosisClLper": { - "$ref": "#/definitions/LibraryConfigUpdate9" + "$ref": "#/definitions/LibraryConfigUpdate10" } }, "additionalProperties": false @@ -771,7 +817,7 @@ ], "properties": { "ValenceOsmosisClWithdrawer": { - "$ref": "#/definitions/LibraryConfigUpdate10" + "$ref": "#/definitions/LibraryConfigUpdate11" } }, "additionalProperties": false @@ -779,6 +825,42 @@ ] }, "LibraryConfigUpdate10": { + "type": "object", + "properties": { + "input_addr": { + "anyOf": [ + { + "$ref": "#/definitions/LibraryAccountType" + }, + { + "type": "null" + } + ] + }, + "lp_config": { + "anyOf": [ + { + "$ref": "#/definitions/LiquidityProviderConfig3" + }, + { + "type": "null" + } + ] + }, + "output_addr": { + "anyOf": [ + { + "$ref": "#/definitions/LibraryAccountType" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, + "LibraryConfigUpdate11": { "type": "object", "properties": { "input_addr": { @@ -1078,27 +1160,34 @@ "LibraryConfigUpdate9": { "type": "object", "properties": { - "input_addr": { + "amount": { "anyOf": [ { - "$ref": "#/definitions/LibraryAccountType" + "$ref": "#/definitions/IbcTransferAmount" }, { "type": "null" } ] }, - "lp_config": { + "denom": { "anyOf": [ { - "$ref": "#/definitions/LiquidityProviderConfig3" + "$ref": "#/definitions/UncheckedDenom" }, { "type": "null" } ] }, - "output_addr": { + "denom_to_pfm_map": { + "type": [ + "object", + "null" + ], + "additionalProperties": false + }, + "input_addr": { "anyOf": [ { "$ref": "#/definitions/LibraryAccountType" @@ -1107,6 +1196,28 @@ "type": "null" } ] + }, + "memo": { + "type": [ + "string", + "null" + ] + }, + "output_addr": { + "type": [ + "string", + "null" + ] + }, + "remote_chain_info": { + "anyOf": [ + { + "$ref": "#/definitions/RemoteChainInfo" + }, + { + "type": "null" + } + ] } }, "additionalProperties": false @@ -1381,6 +1492,26 @@ }, "additionalProperties": false }, + "PacketForwardMiddlewareConfig": { + "type": "object", + "required": [ + "hop_chain_receiver_address", + "hop_to_destination_chain_channel_id", + "local_to_hop_chain_channel_id" + ], + "properties": { + "hop_chain_receiver_address": { + "type": "string" + }, + "hop_to_destination_chain_channel_id": { + "type": "string" + }, + "local_to_hop_chain_channel_id": { + "type": "string" + } + }, + "additionalProperties": false + }, "PairType": { "oneOf": [ { @@ -1743,6 +1874,28 @@ }, "additionalProperties": false }, + "RemoteChainInfo": { + "type": "object", + "required": [ + "channel_id" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "ibc_transfer_timeout": { + "anyOf": [ + { + "$ref": "#/definitions/Uint64" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, "RetryLogic": { "type": "object", "required": [ diff --git a/program-manager/src/domain/cosmos_cw.rs b/program-manager/src/domain/cosmos_cw.rs index e6dd233c..4c7e27d6 100644 --- a/program-manager/src/domain/cosmos_cw.rs +++ b/program-manager/src/domain/cosmos_cw.rs @@ -8,8 +8,8 @@ use crate::{ account::{AccountType, InstantiateAccountData}, bridge::PolytoneSingleChainInfo, config::{ChainInfo, ConfigError, GLOBAL_CONFIG}, - helpers::{addr_canonicalize, addr_humanize}, library::{LibraryConfig, LibraryError}, + mock_api::MockApi, program_config::ProgramConfig, NEUTRON_CHAIN, }; @@ -26,7 +26,7 @@ use cosmos_grpc_client::{ cosmrs::bip32::secp256k1::sha2::{digest::Update, Digest, Sha256, Sha512}, BroadcastMode, Decimal, GrpcClient, ProstMsgNameToAny, Wallet, }; -use cosmwasm_std::{from_json, instantiate2_address, to_json_binary}; +use cosmwasm_std::{from_json, instantiate2_address, to_json_binary, Api}; use futures::future::BoxFuture; use serde_json::to_vec; use strum::VariantNames; @@ -86,7 +86,7 @@ pub struct CosmosCosmwasmConnector { wallet: Wallet, code_ids: HashMap, chain_name: String, - prefix: String, + api: MockApi, } impl fmt::Debug for CosmosCosmwasmConnector { @@ -132,7 +132,7 @@ impl CosmosCosmwasmConnector { wallet, code_ids: code_ids.clone(), chain_name: chain_info.name.clone(), - prefix: chain_info.prefix.clone(), + api: MockApi::new(chain_info.prefix.clone()), }) } } @@ -217,14 +217,20 @@ impl Connector for CosmosCosmwasmConnector { let addr_canonical = instantiate2_address( &checksum, - &addr_canonicalize(&self.prefix, self.wallet.account_address.as_str()).unwrap(), + &self + .api + .addr_canonicalize(self.wallet.account_address.as_str()) + .unwrap(), &salt, ) .context("Failed to instantiate2 address") .map_err(CosmosCosmwasmError::Error)?; - let addr = - addr_humanize(&self.prefix, &addr_canonical).map_err(CosmosCosmwasmError::Error)?; + let addr = self + .api + .addr_humanize(&addr_canonical) + .map_err(CosmosCosmwasmError::CosmwasmStdError)? + .to_string(); Ok((addr, salt.to_vec())) } @@ -258,18 +264,20 @@ impl Connector for CosmosCosmwasmConnector { let addr_canonical = instantiate2_address( &checksum, - &addr_canonicalize( - &self.prefix, - receiving_chain_bridge_info.voice_addr.as_str(), - ) - .unwrap(), + &self + .api + .addr_canonicalize(receiving_chain_bridge_info.voice_addr.as_str()) + .unwrap(), &salt, ) .context("Failed to instantiate2 address") .map_err(CosmosCosmwasmError::Error)?; - let addr = - addr_humanize(&self.prefix, &addr_canonical).map_err(CosmosCosmwasmError::Error)?; + let addr = self + .api + .addr_humanize(&addr_canonical) + .map_err(CosmosCosmwasmError::CosmwasmStdError)? + .to_string(); Ok(addr) } @@ -878,6 +886,10 @@ impl Connector for CosmosCosmwasmConnector { Ok(from_json::(&res.program_config) .map_err(CosmosCosmwasmError::CosmwasmStdError)?) } + + fn get_api(&self) -> &MockApi { + &self.api + } } // Helpers diff --git a/program-manager/src/domain/mod.rs b/program-manager/src/domain/mod.rs index d6070da5..02c8e3af 100644 --- a/program-manager/src/domain/mod.rs +++ b/program-manager/src/domain/mod.rs @@ -16,7 +16,7 @@ use valence_authorization_utils::authorization::AuthorizationInfo; use crate::{ account::InstantiateAccountData, config::ConfigError, library::LibraryConfig, - program_config::ProgramConfig, + mock_api::MockApi, program_config::ProgramConfig, }; pub type ConnectorResult = Result; @@ -174,6 +174,7 @@ pub trait Connector: fmt::Debug + Send + Sync { // Verify the bridge account was instantiated async fn verify_bridge_account(&mut self, bridge_addr: String) -> ConnectorResult<()>; + fn get_api(&self) -> &MockApi; // --------------------------------------------------------------------------------------- // Below are functions that sohuld only be implemented on a specific domain // For example authorization contract methods should only be implemented on the main domain diff --git a/program-manager/src/helpers.rs b/program-manager/src/helpers.rs index 9409dbc2..d2fb1212 100644 --- a/program-manager/src/helpers.rs +++ b/program-manager/src/helpers.rs @@ -1,42 +1,7 @@ use std::collections::HashMap; -use anyhow::anyhow; -use bech32::{encode, primitives::decode::CheckedHrpstring, Bech32, Hrp}; -use cosmwasm_std::CanonicalAddr; - use crate::config::{ConfigResult, GLOBAL_CONFIG}; -fn validate_length(bytes: &[u8]) -> Result<(), anyhow::Error> { - match bytes.len() { - 1..=255 => Ok(()), - _ => Err(anyhow!("Invalid canonical address length")), - } -} - -pub fn addr_canonicalize(prefix: &str, input: &str) -> Result { - let hrp_str = - CheckedHrpstring::new::(input).map_err(|_| anyhow!("Error decoding bech32"))?; - - if !hrp_str - .hrp() - .as_bytes() - .eq_ignore_ascii_case(prefix.as_bytes()) - { - return Err(anyhow!("Wrong bech32 prefix")); - } - - let bytes: Vec = hrp_str.byte_iter().collect(); - validate_length(&bytes)?; - Ok(bytes.into()) -} - -pub fn addr_humanize(prefix: &str, canonical: &CanonicalAddr) -> Result { - validate_length(canonical.as_ref())?; - - let prefix = Hrp::parse(prefix).map_err(|_| anyhow!("Invalid bech32 prefix"))?; - encode::(prefix, canonical.as_slice()).map_err(|_| anyhow!("Bech32 encoding error")) -} - pub async fn get_polytone_info( main_chain: &str, other_chain: &str, diff --git a/program-manager/src/lib.rs b/program-manager/src/lib.rs index b505c6da..317630c1 100644 --- a/program-manager/src/lib.rs +++ b/program-manager/src/lib.rs @@ -7,6 +7,7 @@ pub mod error; pub mod helpers; pub mod library; pub mod macros; +pub mod mock_api; pub mod program_config; pub mod program_config_builder; pub mod program_migration; diff --git a/program-manager/src/library.rs b/program-manager/src/library.rs index d71cb431..5e8c4d33 100644 --- a/program-manager/src/library.rs +++ b/program-manager/src/library.rs @@ -83,12 +83,12 @@ pub enum LibraryConfig { ValenceAstroportWithdrawer(valence_astroport_withdrawer::msg::LibraryConfig), ValenceOsmosisGammLper(valence_osmosis_gamm_lper::msg::LibraryConfig), ValenceOsmosisGammWithdrawer(valence_osmosis_gamm_withdrawer::msg::LibraryConfig), + ValenceGenericIbcTransferLibrary(valence_generic_ibc_transfer_library::msg::LibraryConfig), + ValenceNeutronIbcTransferLibrary(valence_neutron_ibc_transfer_library::msg::LibraryConfig), ValenceOsmosisClLper(valence_osmosis_cl_lper::msg::LibraryConfig), ValenceOsmosisClWithdrawer(valence_osmosis_cl_withdrawer::msg::LibraryConfig), } -// TODO: create macro for the methods that work the same over all of the configs -// We are delegating a lot of the methods to the specific config, so most of the methods can be under the macro impl LibraryConfig { /// Helper to find account ids in the json string fn find_account_ids(ac: AhoCorasick, json: String) -> LibraryResult> { diff --git a/program-manager/src/mock_api.rs b/program-manager/src/mock_api.rs new file mode 100644 index 00000000..07a091e2 --- /dev/null +++ b/program-manager/src/mock_api.rs @@ -0,0 +1,185 @@ +use bech32::{encode, primitives::decode::CheckedHrpstring, Bech32, Hrp}; +use cosmwasm_std::{ + Addr, Api, CanonicalAddr, HashFunction, RecoverPubkeyError, StdError, StdResult, + VerificationError, +}; +use rand_core::OsRng; + +pub struct MockApi { + bech32_prefix: String, +} + +impl MockApi { + pub fn new(bech32_prefix: String) -> Self { + MockApi { bech32_prefix } + } +} + +impl Api for MockApi { + fn addr_validate(&self, input: &str) -> StdResult { + let canonical = self.addr_canonicalize(input)?; + let normalized = self.addr_humanize(&canonical)?; + if input != normalized.as_str() { + return Err(StdError::generic_err( + "Invalid input: address not normalized", + )); + } + Ok(Addr::unchecked(input)) + } + + fn addr_canonicalize(&self, input: &str) -> StdResult { + let hrp_str = CheckedHrpstring::new::(input) + .map_err(|_| StdError::generic_err("Error decoding bech32"))?; + + if !hrp_str + .hrp() + .as_bytes() + .eq_ignore_ascii_case(self.bech32_prefix.as_bytes()) + { + return Err(StdError::generic_err("Wrong bech32 prefix")); + } + + let bytes: Vec = hrp_str.byte_iter().collect(); + validate_length(&bytes)?; + Ok(bytes.into()) + } + + fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { + validate_length(canonical.as_ref())?; + + let prefix = Hrp::parse(&self.bech32_prefix) + .map_err(|_| StdError::generic_err("Invalid bech32 prefix"))?; + encode::(prefix, canonical.as_slice()) + .map(Addr::unchecked) + .map_err(|_| StdError::generic_err("Bech32 encoding error")) + } + + fn bls12_381_aggregate_g1(&self, g1s: &[u8]) -> Result<[u8; 48], VerificationError> { + cosmwasm_crypto::bls12_381_aggregate_g1(g1s).map_err(Into::into) + } + + fn bls12_381_aggregate_g2(&self, g2s: &[u8]) -> Result<[u8; 96], VerificationError> { + cosmwasm_crypto::bls12_381_aggregate_g2(g2s).map_err(Into::into) + } + + fn bls12_381_pairing_equality( + &self, + ps: &[u8], + qs: &[u8], + r: &[u8], + s: &[u8], + ) -> Result { + cosmwasm_crypto::bls12_381_pairing_equality(ps, qs, r, s).map_err(Into::into) + } + + fn bls12_381_hash_to_g1( + &self, + hash_function: HashFunction, + msg: &[u8], + dst: &[u8], + ) -> Result<[u8; 48], VerificationError> { + Ok(cosmwasm_crypto::bls12_381_hash_to_g1( + hash_function.into(), + msg, + dst, + )) + } + + fn bls12_381_hash_to_g2( + &self, + hash_function: HashFunction, + msg: &[u8], + dst: &[u8], + ) -> Result<[u8; 96], VerificationError> { + Ok(cosmwasm_crypto::bls12_381_hash_to_g2( + hash_function.into(), + msg, + dst, + )) + } + + fn secp256k1_verify( + &self, + message_hash: &[u8], + signature: &[u8], + public_key: &[u8], + ) -> Result { + Ok(cosmwasm_crypto::secp256k1_verify( + message_hash, + signature, + public_key, + )?) + } + + fn secp256k1_recover_pubkey( + &self, + message_hash: &[u8], + signature: &[u8], + recovery_param: u8, + ) -> Result, RecoverPubkeyError> { + let pubkey = + cosmwasm_crypto::secp256k1_recover_pubkey(message_hash, signature, recovery_param)?; + Ok(pubkey.to_vec()) + } + + fn secp256r1_verify( + &self, + message_hash: &[u8], + signature: &[u8], + public_key: &[u8], + ) -> Result { + Ok(cosmwasm_crypto::secp256r1_verify( + message_hash, + signature, + public_key, + )?) + } + + fn secp256r1_recover_pubkey( + &self, + message_hash: &[u8], + signature: &[u8], + recovery_param: u8, + ) -> Result, RecoverPubkeyError> { + let pubkey = + cosmwasm_crypto::secp256r1_recover_pubkey(message_hash, signature, recovery_param)?; + Ok(pubkey.to_vec()) + } + + fn ed25519_verify( + &self, + message: &[u8], + signature: &[u8], + public_key: &[u8], + ) -> Result { + Ok(cosmwasm_crypto::ed25519_verify( + message, signature, public_key, + )?) + } + + fn ed25519_batch_verify( + &self, + messages: &[&[u8]], + signatures: &[&[u8]], + public_keys: &[&[u8]], + ) -> Result { + Ok(cosmwasm_crypto::ed25519_batch_verify( + &mut OsRng, + messages, + signatures, + public_keys, + )?) + } + + fn debug(&self, #[allow(unused)] message: &str) { + println!("{message}"); + } +} + +/// Does basic validation of the number of bytes in a canonical address +fn validate_length(bytes: &[u8]) -> StdResult<()> { + match bytes.len() { + 1..=255 => Ok(()), + _ => Err(StdError::generic_err("Invalid canonical address length")), + } +} diff --git a/program-manager/src/program_config.rs b/program-manager/src/program_config.rs index 9418008e..76b5dacf 100644 --- a/program-manager/src/program_config.rs +++ b/program-manager/src/program_config.rs @@ -305,6 +305,8 @@ impl ProgramConfig { account.addr = Some(addr); } + let mut libraries_salts: BTreeMap> = BTreeMap::new(); + // We first predict the library addresses // Then we update the library configs with the account predicted addresses // for all input accounts we add the library address to the approved libraries list @@ -326,6 +328,8 @@ impl ProgramConfig { link.library_id, library_addr, library.domain ); + libraries_salts.insert(link.library_id, salt); + let mut patterns = Vec::with_capacity(link.input_accounts_id.len() + link.output_accounts_id.len()); let mut replace_with = @@ -360,6 +364,9 @@ impl ProgramConfig { } library.config.replace_config(patterns, replace_with)?; + library + .config + .pre_validate_config(domain_connector.get_api())?; library.addr = Some(library_addr); debug!( @@ -368,9 +375,20 @@ impl ProgramConfig { ); self.save_library(link.library_id, &library); + } + + // We run over all libraries and instantiate them + for (_, link) in self.links.clone().iter() { + let library = self.get_library(link.library_id)?; + + let mut domain_connector = connectors.get_or_create_connector(&library.domain).await?; // Get processor address for this domain let processor_addr = self.get_processor_account_on_domain(library.domain.clone())?; + let salt = libraries_salts + .get(&link.library_id) + .expect("Library salt not found") + .clone(); // init the library domain_connector @@ -580,12 +598,6 @@ impl ProgramConfig { ManagerError::AccountIdNotFoundLibraryConfig(accounts) ); - // Run the soft_validate method on each library config - for _library in self.libraries.values() { - // TODO: mock api for the connector - // library.config.soft_validate_config()?; - } - Ok(()) }