diff --git a/src/mods/errors.cairo b/src/mods/errors.cairo index 8d43d89..e841697 100644 --- a/src/mods/errors.cairo +++ b/src/mods/errors.cairo @@ -16,4 +16,5 @@ pub mod Errors { pub const ALREADY_IN_PROTOCOL_CAMPAIGN: felt252 = 'ALREADY_IN_PROTOCOL_CAMPAIGN'; pub const TASK_ALREADY_EXIST: felt252 = 'TASK_ALREADY_EXIST'; pub const TASK_NOT_YET_COMPLETED: felt252 = 'TASK_NOT_YET_COMPLETED'; + pub const INVALID_PROTOCOL_ID: felt252 = 'INVALID_PROTOCOL_ID'; } diff --git a/src/mods/events.cairo b/src/mods/events.cairo index b998caa..010662d 100644 --- a/src/mods/events.cairo +++ b/src/mods/events.cairo @@ -12,12 +12,6 @@ pub struct UserRegistered { pub user: ContractAddress, } -#[derive(Copy, Drop, Debug, PartialEq, starknet::Event)] -pub struct ProtocolRegistered { - #[key] - pub user: ContractAddress, -} - #[derive(Copy, Drop, Debug, PartialEq, starknet::Event)] pub struct TaskMinted { @@ -26,3 +20,4 @@ pub struct TaskMinted { #[key] pub user: ContractAddress, } + diff --git a/src/mods/interfaces/IWeaver.cairo b/src/mods/interfaces/IWeaver.cairo index 00c77db..c011f2b 100644 --- a/src/mods/interfaces/IWeaver.cairo +++ b/src/mods/interfaces/IWeaver.cairo @@ -18,6 +18,5 @@ pub trait IWeaver { fn erc_721(self: @TContractState) -> ContractAddress; fn mint(ref self: TContractState, task_id: u256); fn get_task_info(self: @TContractState, task_id: u256) -> TaskInfo; - fn protocol_register(ref self: TContractState, protocol_name: ByteArray); fn get_registered_protocols(self: @TContractState, address: ContractAddress) -> ProtocolInfo; } diff --git a/src/mods/interfaces/Iprotocol.cairo b/src/mods/interfaces/Iprotocol.cairo index b3bf346..7f94992 100644 --- a/src/mods/interfaces/Iprotocol.cairo +++ b/src/mods/interfaces/Iprotocol.cairo @@ -15,6 +15,7 @@ pub trait IProtocol { fn join_protocol_campaign(ref self: TState, campaign_user: ContractAddress, protocol_id: u256); fn set_protocol_matadata_uri(ref self: TState, protocol_id: u256, matadata_uri: ByteArray); fn create_task(ref self: TState, task_description: ByteArray) -> u256; + fn protocol_register(ref self: TState, protocol_Details: ByteArray); // ************************************************************************* @@ -36,4 +37,6 @@ pub trait IProtocol { fn get_protocol_task_descriptions(self: @TState, task_id: u256) -> ByteArray; fn get_protocol_campaign_users(self: @TState, protocol_id: u256) -> u256; + + fn get_campaign_members(self: @TState, protocol_id: u256) -> CampaignMembers; } diff --git a/src/mods/protocol/protocolcomponent.cairo b/src/mods/protocol/protocolcomponent.cairo index 22ff4a7..74df316 100644 --- a/src/mods/protocol/protocolcomponent.cairo +++ b/src/mods/protocol/protocolcomponent.cairo @@ -17,17 +17,19 @@ pub mod ProtocolCampagin { use crate::mods::interfaces::Iprotocol::IProtocol; use crate::mods::interfaces::ICustomNFT::{ICustomNFTDispatcher, ICustomNFTDispatcherTrait}; + use crate::mods::interfaces::IWeaverNFT::{IWeaverNFTDispatcher, IWeaverNFTDispatcherTrait}; use crate::mods::errors::Errors; use crate::mods::types::ProtocolDetails; use crate::mods::types::CampaignMembers; use crate::mods::types::ProtocolCreateTask; + use crate::mods::types::ProtocolInfo; #[storage] pub struct Storage { pub protocol_id: u256, - protocol_counter: u256, + pub protocol_counter: u256, pub protocol_nft_class_hash: ClassHash, // The protocol nft class hash protocol_owner: Map, // map the owner address and the protocol id protocols: Map, // map the protocol details and the protocol id @@ -52,6 +54,9 @@ pub mod ProtocolCampagin { task_completetion: Map< (u256, ContractAddress), bool >, // Map (task_id, user_address) to completion status + protocol_register: Map< + ContractAddress, ProtocolInfo + >, // map the protocol owner to the protocol info } @@ -66,6 +71,7 @@ pub mod ProtocolCampagin { JoinProtocolCampaign: JoinProtocolCampaign, DeployProtocolNft: DeployProtocolNft, CreateTask: CreateTask, + ProtocolRegistered: ProtocolRegistered, } @@ -103,6 +109,21 @@ pub mod ProtocolCampagin { pub block_timestamp: u64, } + #[derive(Copy, Drop, Serde)] + pub enum UserEventType { + Register, + Verify + } + + + #[derive(Drop, starknet::Event)] + pub struct ProtocolRegistered { + pub protocol_id: u256, + pub protocol_owner: ContractAddress, + pub event_type: UserEventType, + pub block_timestamp: u64, + } + // ************************************************************************* // EXTERNAL FUNCTIONS @@ -115,10 +136,46 @@ pub mod ProtocolCampagin { +Drop, impl Ownable: OwnableComponent::HasComponent > of IProtocol> { + ///@ protocol registeration + + fn protocol_register( + ref self: ComponentState, protocol_Details: ByteArray + ) { + let caller = get_caller_address(); + assert( + !self.protocol_register.read(caller).registered, Errors::PROTOCOL_ALREADY_REGISTERED + ); + let protocol_id = self.protocol_id.read() + 1; + let protocol_info = ProtocolInfo { + protocol_name: protocol_Details, + registered: true, + verified: false, + protocol_id: protocol_id, + protocol_owner: caller, + }; + + self.protocol_register.write(caller, protocol_info); + self.protocol_owner.write(protocol_id, caller); + self.protocol_counter.write(protocol_id); + + self + .emit( + ProtocolRegistered { + protocol_id: protocol_id, + protocol_owner: caller, + event_type: UserEventType::Register, + block_timestamp: get_block_timestamp() + } + ); + } + + /// @notice Create a new protocol campaign fn create_protocol_campaign( ref self: ComponentState, protocol_id: u256, protocol_info: ByteArray ) -> u256 { + assert(protocol_id.is_non_zero(), Errors::INVALID_PROTOCOL_ID); + assert(protocol_info.len() > 0, Errors::INVALID_PROTOCOL_NAME); let protocol_owner = get_caller_address(); let protocol_nft_class_hash = self.protocol_nft_class_hash.read(); let protocol_initialized = self.protocol_initialized.read(protocol_id); @@ -150,6 +207,7 @@ pub mod ProtocolCampagin { campaign_user: ContractAddress, protocol_id: u256 ) { + assert(protocol_id.is_non_zero(), Errors::INVALID_PROTOCOL_ID); assert(!campaign_user.is_zero(), Errors::INVALID_ADDRESS); let caller = get_caller_address(); assert(caller == campaign_user, Errors::UNAUTHORIZED); @@ -171,7 +229,8 @@ pub mod ProtocolCampagin { fn create_task( ref self: ComponentState, task_description: ByteArray ) -> u256 { - let protocol_owner = get_caller_address(); + let protocol_owner = self.protocol_owner.read(self.protocol_id.read()); + assert(protocol_owner == get_caller_address(), Errors::UNAUTHORIZED); let task_id = self.protocol_task_id.read() + 1; @@ -179,9 +238,6 @@ pub mod ProtocolCampagin { assert(!task_exists, Errors::TASK_ALREADY_EXIST); let protocol_id = self.protocol_id.read(); - let protocol_owner_stored = self.protocol_owner.read(protocol_id); - assert(protocol_owner == protocol_owner_stored, Errors::UNAUTHORIZED); - self._create_task(protocol_id, task_id, task_description, protocol_owner); return task_id; @@ -286,6 +342,17 @@ pub mod ProtocolCampagin { } + fn get_campaign_members( + self: @ComponentState, protocol_id: u256 + ) -> CampaignMembers { + let protocol = self.protocols.read(protocol_id); + let campaign_members = self + .Campaign_members + .read((protocol_id, protocol.protocol_owner)); + return campaign_members; + } + + /// @notice get the particular protocol matadata uri /// protocol_id: id of the returned community /// @return ByteArray metadata uri @@ -366,7 +433,7 @@ pub mod ProtocolCampagin { self.protocols.write(protocol_id, protocol_details); self.protocol_initialized.write(protocol_id, true); - self.protocol_owner.write(protocol_id, protocol_owner); + self.protocol_owner.write(key: protocol_id, value: protocol_owner); self.protocol_counter.write(protocol_id); self.protocol_info.write(protocol_id, protocol_info); diff --git a/src/mods/types.cairo b/src/mods/types.cairo index 4d211ba..45a241e 100644 --- a/src/mods/types.cairo +++ b/src/mods/types.cairo @@ -15,6 +15,10 @@ pub struct TaskInfo { #[derive(Drop, Serde, Debug, PartialEq, starknet::Store)] pub struct ProtocolInfo { pub protocol_name: ByteArray, + pub registered: bool, + pub verified: bool, + pub protocol_id: u256, + pub protocol_owner: ContractAddress, } diff --git a/src/mods/weaver_contract/weaver.cairo b/src/mods/weaver_contract/weaver.cairo index 1f2109c..e297683 100644 --- a/src/mods/weaver_contract/weaver.cairo +++ b/src/mods/weaver_contract/weaver.cairo @@ -17,7 +17,7 @@ pub mod Weaver { }; use crate::mods::types::{ProtocolInfo, TaskInfo, User}; - use crate::mods::events::{ProtocolRegistered, TaskMinted, Upgraded, UserRegistered}; + use crate::mods::events::{TaskMinted, Upgraded, UserRegistered}; use crate::mods::errors::Errors; use crate::mods::interfaces::IWeaver::IWeaver; use crate::mods::interfaces::IWeaverNFT::{IWeaverNFTDispatcher, IWeaverNFTDispatcherTrait}; @@ -47,7 +47,6 @@ pub mod Weaver { pub enum Event { Upgraded: Upgraded, UserRegistered: UserRegistered, - ProtocolRegistered: ProtocolRegistered, TaskMinted: TaskMinted, } @@ -100,24 +99,6 @@ pub mod Weaver { } - fn protocol_register(ref self: ContractState, protocol_name: ByteArray) { - assert(protocol_name.len() > 0, Errors::INVALID_PROTOCOL_NAME); - - let protocol_info = self.protocol_registrations.read(get_caller_address()); - assert(protocol_info.protocol_name.len() == 0, Errors::PROTOCOL_ALREADY_REGISTERED); - self.protocol_registrations.write(get_caller_address(), ProtocolInfo { protocol_name }); - - // Dispatch the mint_weaver_nft call to the NFT contract - let weaver_nft_dispatcher = IWeaverNFTDispatcher { - contract_address: self.weaver_nft_address.read(), - }; - weaver_nft_dispatcher.mint_weaver_nft(get_caller_address()); - self.emit(Event::ProtocolRegistered(ProtocolRegistered { user: get_caller_address() })); - } - - - // add a verify function - // Getter functions fn owner(self: @ContractState) -> ContractAddress { diff --git a/tests/test_weaver_contract.cairo b/tests/test_weaver_contract.cairo index e93dc20..a126c77 100644 --- a/tests/test_weaver_contract.cairo +++ b/tests/test_weaver_contract.cairo @@ -14,7 +14,7 @@ use weaver_contract::mods::interfaces::IWeaver::{IWeaverDispatcher, IWeaverDispa use weaver_contract::mods::interfaces::IWeaverNFT::{ IWeaverNFTDispatcher, IWeaverNFTDispatcherTrait }; -use weaver_contract::mods::events::{UserRegistered, ProtocolRegistered, TaskMinted}; +use weaver_contract::mods::events::{UserRegistered, TaskMinted}; use weaver_contract::mods::weaver_contract::weaver::Weaver::{Event}; @@ -139,131 +139,6 @@ fn test_mint_unregistered_user_panics() { stop_cheat_caller_address(weaver_contract_address); } -#[test] -fn test_protocol_register() { - let weaver_contract_address = __setup__(); - let weaver_contract = IWeaverDispatcher { contract_address: weaver_contract_address }; - - let user: ContractAddress = USER(); - start_cheat_caller_address(weaver_contract_address, user); - - let protocol_name: ByteArray = "Weaver Protocol"; - weaver_contract.protocol_register(protocol_name); - - let protocol_info = weaver_contract.get_registered_protocols(user); - assert!(protocol_info.protocol_name == "Weaver Protocol", "Protocol should be registered"); - - stop_cheat_caller_address(weaver_contract_address); -} - - -#[test] -fn test_protocol_register_emit_event() { - let weaver_contract_address = __setup__(); - let weaver_contract = IWeaverDispatcher { contract_address: weaver_contract_address }; - - let user: ContractAddress = USER(); - let mut spy = spy_events(); - start_cheat_caller_address(weaver_contract_address, user); - - let protocol_name: ByteArray = "Weaver Protocol"; - weaver_contract.protocol_register(protocol_name); - - let protocol_info = weaver_contract.get_registered_protocols(user); - assert!(protocol_info.protocol_name == "Weaver Protocol", "Protocol should be registered"); - - let expected_event = Event::ProtocolRegistered(ProtocolRegistered { user: user }); - spy.assert_emitted(@array![(weaver_contract_address, expected_event)]); - - stop_cheat_caller_address(weaver_contract_address); -} - - -#[test] -fn test_nft_minted_on_protocol_register() { - let weaver_contract_address = __setup__(); - let weaver_contract = IWeaverDispatcher { contract_address: weaver_contract_address }; - let nft_dispatcher = IWeaverNFTDispatcher { contract_address: weaver_contract.erc_721() }; - - let user: ContractAddress = USER(); - start_cheat_caller_address(weaver_contract_address, user); - - let protocol_name: ByteArray = "Weaver Protocol"; - weaver_contract.protocol_register(protocol_name); - - let minted_token_id = nft_dispatcher.get_user_token_id(user); - assert!(minted_token_id > 0, "NFT NOT Minted!"); - - let last_minted_id = nft_dispatcher.get_last_minted_id(); - assert_eq!(minted_token_id, last_minted_id, "Minted token ID should match the last minted ID"); - - let mint_timestamp = nft_dispatcher.get_token_mint_timestamp(minted_token_id); - let current_block_timestamp = get_block_timestamp(); - assert_eq!(mint_timestamp, current_block_timestamp, "Mint timestamp not matched"); - - stop_cheat_caller_address(weaver_contract_address); -} - -#[test] -#[should_panic(expected: 'PROTOCOL_ALREADY_REGISTERED')] -fn test_protocol_register_already_registered() { - let weaver_contract_address = __setup__(); - let weaver_contract = IWeaverDispatcher { contract_address: weaver_contract_address }; - - let user: ContractAddress = USER(); - start_cheat_caller_address(weaver_contract_address, user); - - let protocol_name: ByteArray = "Weaver Protocol"; - weaver_contract.protocol_register(protocol_name); - - weaver_contract.protocol_register("Weaver Protocol"); - - stop_cheat_caller_address(weaver_contract_address); -} - -#[test] -#[should_panic(expected: 'INVALID_PROTOCOL_NAME')] -fn test_invalid_protocol_name_should_panic() { - let weaver_contract_address = __setup__(); - let weaver_contract = IWeaverDispatcher { contract_address: weaver_contract_address }; - - let user: ContractAddress = USER(); - start_cheat_caller_address(weaver_contract_address, user); - - let invalid_protocol_name: ByteArray = ""; // Empty protocol name - weaver_contract.protocol_register(invalid_protocol_name); - - stop_cheat_caller_address(weaver_contract_address); -} - -#[test] -#[should_panic(expected: 'TASK_ALREADY_EXISTS')] -fn test_mint_nft_duplicate_id_should_panic() { - let weaver_contract_address = __setup__(); - - let weaver_contract = IWeaverDispatcher { contract_address: weaver_contract_address }; - let nft_dispatcher = IWeaverNFTDispatcher { contract_address: weaver_contract.erc_721() }; - let user: ContractAddress = USER(); - - start_cheat_caller_address(weaver_contract_address, user); - - let details: ByteArray = "Testx User"; - weaver_contract.register_User(details); - - let protocol_name: ByteArray = "Weavers Protocol"; - weaver_contract.protocol_register(protocol_name); - - let task_id = 1; - - weaver_contract.mint(task_id); - - let minted_token_id = nft_dispatcher.get_user_token_id(user); - assert!(minted_token_id > 0, "First NFT mint failed!"); - - weaver_contract.mint(task_id); - - stop_cheat_caller_address(weaver_contract_address); -} #[test] fn test_mint_nft() { @@ -303,124 +178,6 @@ fn test_mint_nft() { stop_cheat_caller_address(weaver_contract_address); } -#[test] -#[should_panic(expected: "Task should NOT be completed")] -fn test_mint_nft_task_not_completed_should_panic() { - let weaver_contract_address = __setup__(); - let weaver_contract = IWeaverDispatcher { contract_address: weaver_contract_address }; - let user: ContractAddress = USER(); - - start_cheat_caller_address(weaver_contract_address, user); - - let details: ByteArray = "Testx User"; - weaver_contract.register_User(details); - - let protocol_name: ByteArray = "Weavers Protocol"; - weaver_contract.protocol_register(protocol_name); - - let task_id = 999; - - let mut task_info = weaver_contract.get_task_info(task_id); - - task_info.is_completed = false; - - assert!(task_info.is_completed, "Task should NOT be completed"); - - weaver_contract.mint(task_id); - - println!("Mint function did not panic!"); - - stop_cheat_caller_address(weaver_contract_address); -} - -#[test] -fn test_mint_nft_after_task_completed() { - // Set up the contracts - let weaver_contract_address = __setup__(); - let weaver_contract = IWeaverDispatcher { contract_address: weaver_contract_address }; - let nft_dispatcher = IWeaverNFTDispatcher { contract_address: weaver_contract.erc_721() }; - - // Define the user address - let user: ContractAddress = USER(); - - // Start the contract as the user - start_cheat_caller_address(weaver_contract_address, user); - - // Register the user - let details: ByteArray = "Test User"; - weaver_contract.register_User(details); - - // Verify user registration - let is_registered = weaver_contract.get_register_user(user); - assert!(is_registered.Details == "Test User", "User should be registered"); - - // Register the protocol - let protocol_name: ByteArray = "Weaver Protocol"; - weaver_contract.protocol_register(protocol_name); - - // Verify protocol registration - let protocol_info = weaver_contract.get_registered_protocols(user); - assert!(protocol_info.protocol_name == "Weaver Protocol", "Protocol should be registered"); - - // Define the task ID to mint - let task_id = 1; - - // Retrieve and mark the task as completed - let mut task_info = weaver_contract.get_task_info(task_id); - task_info.is_completed = true; - - // Ensure task is completed - assert!(task_info.is_completed, "Task should be completed"); - - // Now, mint the NFT for the task - weaver_contract.mint(task_id); - - // Get the minted token ID for the user - let minted_token_id = nft_dispatcher.get_user_token_id(user); - assert!(minted_token_id > 0, "NFT NOT Minted!"); - - // Ensure that the minted token ID matches the last minted ID - let last_minted_id = nft_dispatcher.get_last_minted_id(); - assert_eq!(minted_token_id, last_minted_id, "Minted token ID should match the last minted ID"); - - // Ensure the mint timestamp is correct - let mint_timestamp = nft_dispatcher.get_token_mint_timestamp(minted_token_id); - let current_block_timestamp = get_block_timestamp(); - assert_eq!(mint_timestamp, current_block_timestamp, "Mint timestamp does not match"); - - // Stop the contract after the test - stop_cheat_caller_address(weaver_contract_address); -} - - -#[test] -#[should_panic(expected: 'TASK_ALREADY_EXISTS')] -fn test_mint_task_already_exists() { - let weaver_contract_address = __setup__(); - let weaver_contract = IWeaverDispatcher { contract_address: weaver_contract_address }; - let user: ContractAddress = USER(); - - // Set up the caller address - start_cheat_caller_address(weaver_contract_address, user); - - // Register user first (required) - let details: ByteArray = "Test User"; - weaver_contract.register_User(details); - - // Register protocol (required before minting) - let protocol_name: ByteArray = "Test Protocol"; - weaver_contract.protocol_register(protocol_name); - - // First mint should succeed - let task_id = 1; - weaver_contract.mint(task_id); - - // Second mint with same task_id should panic - weaver_contract.mint(task_id); - - stop_cheat_caller_address(weaver_contract_address); -} - #[test] fn test_nft_was_minted_after_user_registers() { @@ -447,29 +204,3 @@ fn test_nft_was_minted_after_user_registers() { stop_cheat_caller_address(weaver_contract_address); } - -#[test] -fn test_nft_was_minted_after_protocol_registers() { - let weaver_contract_address = __setup__(); - let weaver_contract = IWeaverDispatcher { contract_address: weaver_contract_address }; - let nft_dispatcher = IWeaverNFTDispatcher { contract_address: weaver_contract.erc_721() }; - - let user: ContractAddress = USER(); - start_cheat_caller_address(weaver_contract_address, user); - - let protocol_name: ByteArray = "Weaver Protocol"; - weaver_contract.protocol_register(protocol_name); - - let minted_token_id = nft_dispatcher.get_user_token_id(user); - assert!(minted_token_id > 0, "NFT NOT Minted!"); - - let last_minted_id = nft_dispatcher.get_last_minted_id(); - assert_eq!(minted_token_id, last_minted_id, "Minted token ID should match the last minted ID"); - - let mint_timestamp = nft_dispatcher.get_token_mint_timestamp(minted_token_id); - let current_block_timestamp = get_block_timestamp(); - assert_eq!(mint_timestamp, current_block_timestamp, "Mint timestamp not matched"); - - stop_cheat_caller_address(weaver_contract_address); -} -