diff --git a/onchain/src/lib.cairo b/onchain/src/lib.cairo index 158e7378..5c6a3325 100644 --- a/onchain/src/lib.cairo +++ b/onchain/src/lib.cairo @@ -3,6 +3,7 @@ pub mod interfaces; use art_peace::ArtPeace; use interfaces::{IArtPeace, IArtPeaceDispatcher, IArtPeaceDispatcherTrait, Pixel}; + mod quests { pub mod interfaces; pub mod pixel_quest; @@ -33,6 +34,14 @@ mod nfts { }; } +mod username_store { + pub mod interfaces; + pub mod username_store; + + use interfaces::{IUsernameStore, IUsernameStoreDispatcher, IUsernameStoreDispatcherTrait}; + use username_store::UsernameStore; +} + mod mocks { pub mod erc20_mock; } @@ -40,5 +49,7 @@ mod mocks { #[cfg(test)] mod tests { mod art_peace; + mod username_store; pub(crate) mod utils; } + diff --git a/onchain/src/tests/username_store.cairo b/onchain/src/tests/username_store.cairo new file mode 100644 index 00000000..f4f4ee38 --- /dev/null +++ b/onchain/src/tests/username_store.cairo @@ -0,0 +1,36 @@ +use snforge_std::{declare, ContractClassTrait}; +use art_peace::username_store::interfaces::{ + IUsernameStoreDispatcher, IUsernameStoreDispatcherTrait +}; +use starknet::{ContractAddress, get_caller_address, get_contract_address, contract_address_const}; + +fn deploy_contract() -> ContractAddress { + let contract = declare("UsernameStore"); + + return contract.deploy(@ArrayTrait::new()).unwrap(); +} + +#[test] +fn test_claim_username() { + let contract_address = deploy_contract(); + let dispatcher = IUsernameStoreDispatcher { contract_address }; + dispatcher.claim_username('deal'); + + let username_address = dispatcher.get_username('deal'); + + assert(contract_address != username_address, 'Username not claimed'); +} +#[test] +fn test_transfer_username() { + let contract_address = deploy_contract(); + let dispatcher = IUsernameStoreDispatcher { contract_address }; + dispatcher.claim_username('devsweet'); + + let second_contract_address = contract_address_const::<1>(); + + dispatcher.transfer_username('devsweet', second_contract_address); + + let username_address = dispatcher.get_username('devsweet'); + + assert(username_address == second_contract_address, 'Username not Transferred'); +} diff --git a/onchain/src/username_store/interfaces.cairo b/onchain/src/username_store/interfaces.cairo new file mode 100644 index 00000000..04ea5850 --- /dev/null +++ b/onchain/src/username_store/interfaces.cairo @@ -0,0 +1,8 @@ +use starknet::ContractAddress; + +#[starknet::interface] +pub trait IUsernameStore { + fn claim_username(ref self: TContractState, key: felt252); + fn transfer_username(ref self: TContractState, key: felt252, new_Address: ContractAddress); + fn get_username(ref self: TContractState, key: felt252) -> ContractAddress; +} diff --git a/onchain/src/username_store/username_store.cairo b/onchain/src/username_store/username_store.cairo new file mode 100644 index 00000000..309a5fe2 --- /dev/null +++ b/onchain/src/username_store/username_store.cairo @@ -0,0 +1,79 @@ +pub mod UserNameClaimErrors { + pub const USERNAME_CLAIMED: felt252 = 'username_claimed'; + pub const USERNAME_CANNOT_BE_TRANSFER: felt252 = 'username_cannot_be_transferred'; +} + +#[starknet::contract] +pub mod UsernameStore { + use starknet::{get_caller_address, ContractAddress, contract_address_const}; + use art_peace::username_store::IUsernameStore; + use super::UserNameClaimErrors; + + #[storage] + struct Storage { + usernames: LegacyMap:: + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + UserNameClaimed: UserNameClaimed, + UserNameTransferred: UserNameTransferred + } + + #[derive(Drop, starknet::Event)] + struct UserNameClaimed { + #[key] + username: felt252, + address: ContractAddress + } + + #[derive(Drop, starknet::Event)] + struct UserNameTransferred { + #[key] + username: felt252, + address: ContractAddress + } + + #[abi(embed_v0)] + pub impl UsernameStore of IUsernameStore { + fn claim_username(ref self: ContractState, key: felt252) { + let mut username_address = self.usernames.read(key); + + assert( + username_address == contract_address_const::<0>(), + UserNameClaimErrors::USERNAME_CLAIMED + ); + + self.usernames.write(key, get_caller_address()); + + self + .emit( + Event::UserNameClaimed( + UserNameClaimed { username: key, address: get_caller_address() } + ) + ) + } + + fn transfer_username(ref self: ContractState, key: felt252, new_Address: ContractAddress) { + let username_address = self.usernames.read(key); + + if username_address != get_caller_address() { + core::panic_with_felt252(UserNameClaimErrors::USERNAME_CANNOT_BE_TRANSFER); + } + + self.usernames.write(key, new_Address); + + self + .emit( + Event::UserNameTransferred( + UserNameTransferred { username: key, address: new_Address } + ) + ) + } + + fn get_username(ref self: ContractState, key: felt252) -> ContractAddress { + self.usernames.read(key) + } + } +}