diff --git a/contracts/collections/src/contract.rs b/contracts/collections/src/contract.rs index a5978efd..24fc0f08 100644 --- a/contracts/collections/src/contract.rs +++ b/contracts/collections/src/contract.rs @@ -15,13 +15,8 @@ pub struct Collections; impl Collections { // takes an address and uses it as an administrator #[allow(dead_code)] - pub fn initialize( - env: Env, - admin: Address, - name: String, - image: URIValue, - ) -> Result<(), ContractError> { - let config = Config { name, image }; + pub fn initialize(env: Env, admin: Address, name: String) -> Result<(), ContractError> { + let config = Config { name }; save_config(&env, config)?; save_admin(&env, &admin)?; diff --git a/contracts/collections/src/storage.rs b/contracts/collections/src/storage.rs index 3fb03351..b0231b2c 100644 --- a/contracts/collections/src/storage.rs +++ b/contracts/collections/src/storage.rs @@ -46,7 +46,6 @@ pub struct URIValue { #[contracttype] pub struct Config { pub name: String, - pub image: URIValue, } pub const ADMIN: Symbol = symbol_short!("admin"); diff --git a/contracts/collections/src/test/setup.rs b/contracts/collections/src/test/setup.rs index 1badc2af..cf79886b 100644 --- a/contracts/collections/src/test/setup.rs +++ b/contracts/collections/src/test/setup.rs @@ -1,29 +1,21 @@ -use soroban_sdk::{testutils::Address as _, Address, Bytes, Env, String}; +use soroban_sdk::{testutils::Address as _, Address, Env, String}; -use crate::{ - contract::{Collections, CollectionsClient}, - storage::URIValue, -}; +use crate::contract::{Collections, CollectionsClient}; pub fn initialize_collection_contract<'a>( env: &Env, admin: Option<&Address>, name: Option<&String>, - image: Option<&URIValue>, ) -> CollectionsClient<'a> { let collections = CollectionsClient::new(env, &env.register_contract(None, Collections {})); let alt_admin = &Address::generate(env); let alt_name = &String::from_str(env, "Stellar kitties"); - let alt_image = URIValue { - uri: Bytes::from_slice(env, &[64]), - }; let admin = admin.unwrap_or(alt_admin); let name = name.unwrap_or(alt_name); - let image = image.unwrap_or(&alt_image); - collections.initialize(admin, name, image); + collections.initialize(admin, name); collections } diff --git a/contracts/collections/src/test/tests.rs b/contracts/collections/src/test/tests.rs index 86a5978a..e55ad109 100644 --- a/contracts/collections/src/test/tests.rs +++ b/contracts/collections/src/test/tests.rs @@ -10,26 +10,18 @@ fn proper_initialization() { env.mock_all_auths(); let admin = Address::generate(&env); - let uri_value = URIValue { - uri: Bytes::from_slice(&env, &[64]), - }; let name = &String::from_str(&env, "Stellar kitties"); - let collections_client = - initialize_collection_contract(&env, Some(&admin), Some(name), Some(&uri_value)); + let collections_client = initialize_collection_contract(&env, Some(&admin), Some(name)); let actual_admin_addr = collections_client.show_admin(); assert_eq!(admin, actual_admin_addr); let actual_config = collections_client.show_config(); - let expected_config = Config { - name: name.clone(), - image: uri_value, - }; + let expected_config = Config { name: name.clone() }; assert_eq!(actual_config.name, expected_config.name); - assert_eq!(actual_config.image, expected_config.image); } #[test] @@ -40,7 +32,7 @@ fn mint_and_check_balance() { let admin = Address::generate(&env); let user = Address::generate(&env); - let collections_client = initialize_collection_contract(&env, Some(&admin), None, None); + let collections_client = initialize_collection_contract(&env, Some(&admin), None); collections_client.mint(&admin, &user, &1, &10); @@ -60,7 +52,7 @@ fn mint_batch_and_balance_of_batch() { let id_list = vec![&env, 1, 2, 3, 4, 5]; let amounts_list = vec![&env, 10, 20, 30, 40, 50]; - let collections_client = initialize_collection_contract(&env, Some(&admin), None, None); + let collections_client = initialize_collection_contract(&env, Some(&admin), None); collections_client.mint_batch(&admin, &user, &id_list, &amounts_list); @@ -87,7 +79,7 @@ fn approval_tests() { let user = Address::generate(&env); let operator = Address::generate(&env); - let collectoins_client = initialize_collection_contract(&env, None, None, None); + let collectoins_client = initialize_collection_contract(&env, None, None); collectoins_client.set_approval_for_all(&user, &operator, &true); @@ -102,7 +94,7 @@ fn burning() { let admin = Address::generate(&env); let user = Address::generate(&env); - let collectoins_client = initialize_collection_contract(&env, Some(&admin), None, None); + let collectoins_client = initialize_collection_contract(&env, Some(&admin), None); collectoins_client.mint(&admin, &user, &1, &2); assert_eq!(collectoins_client.balance_of(&user, &1), 2); @@ -119,7 +111,7 @@ fn batch_burning() { let admin = Address::generate(&env); let user = Address::generate(&env); - let collections_client = initialize_collection_contract(&env, Some(&admin), None, None); + let collections_client = initialize_collection_contract(&env, Some(&admin), None); collections_client.mint_batch( &admin, @@ -173,7 +165,7 @@ fn test_uri() { let admin = Address::generate(&env); let user = Address::generate(&env); - let collections_client = initialize_collection_contract(&env, Some(&admin), None, None); + let collections_client = initialize_collection_contract(&env, Some(&admin), None); collections_client.mint(&admin, &user, &1, &5); diff --git a/contracts/deployer/Cargo.toml b/contracts/deployer/Cargo.toml new file mode 100644 index 00000000..6fcf9738 --- /dev/null +++ b/contracts/deployer/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "phoenix-multisig-deployer" +version = { workspace = true } +authors = ["Jakub ) { + if is_initialized(&env) { + log!( + &env, + "Multisig Deployer: Initialize: initializing the contract twice is not allowed" + ); + panic!("Multisig Deployer: Initialize: initializing the contract twice is not allowed"); + } + set_initialized(&env); + + set_wasm_hash(&env, &collections_wasm_hash); + } + + #[allow(dead_code)] + pub fn deploy_new_collection( + env: Env, + salt: BytesN<32>, + admin: Address, + name: String, + ) -> Address { + admin.require_auth(); + let collections_wasm_hash = get_wasm_hash(&env); + + let deployed_multisig = env + .deployer() + .with_address(admin.clone(), salt) + .deploy(collections_wasm_hash); + + let init_fn = Symbol::new(&env, "initialize"); + let init_fn_args: Vec = vec![&env, admin.into_val(&env), name.into_val(&env)]; + let _: Val = env.invoke_contract(&deployed_multisig, &init_fn, init_fn_args); + + save_collection_with_generic_key(&env, name.clone()); + save_collection_with_admin_key(&env, name, admin); + + deployed_multisig + } +} + +// ---------- Storage types ---------- + +#[contracttype] +#[derive(Clone)] +pub enum DataKey { + IsInitialized, + CollectionsWasmHash, + AllCollections, + AdminId(Address), +} + +pub fn set_initialized(env: &Env) { + env.storage().instance().set(&DataKey::IsInitialized, &()); +} + +pub fn is_initialized(env: &Env) -> bool { + env.storage() + .instance() + .get::<_, ()>(&DataKey::IsInitialized) + .is_some() +} + +pub fn set_wasm_hash(env: &Env, hash: &BytesN<32>) { + env.storage() + .instance() + .set(&DataKey::CollectionsWasmHash, hash); +} + +pub fn get_wasm_hash(env: &Env) -> BytesN<32> { + env.storage() + .instance() + .get(&DataKey::CollectionsWasmHash) + .unwrap() +} + +pub fn save_collection_with_generic_key(env: &Env, name: String) { + let mut existent_collection: Vec = env + .storage() + .persistent() + .get(&DataKey::AllCollections) + .unwrap_or(vec![&env]); + + existent_collection.push_back(name); + + env.storage() + .persistent() + .set(&DataKey::AllCollections, &existent_collection); +} + +pub fn save_collection_with_admin_key(env: &Env, name: String, admin: Address) { + let mut existent_collection: Vec = env + .storage() + .persistent() + .get(&DataKey::AdminId(admin.clone())) + .unwrap_or(vec![&env]); + + existent_collection.push_back(name); + + env.storage() + .persistent() + .set(&DataKey::AdminId(admin), &existent_collection); +} +