From 0ccc9f89b146aeb9849aa418575b5c75d2fc4325 Mon Sep 17 00:00:00 2001 From: Birdmannn Date: Sat, 29 Mar 2025 13:30:41 +0100 Subject: [PATCH] fix --- src/components/sales.cairo | 58 +++++++++++++++++++++++++++++++++++++ src/components/voting.cairo | 16 ++++++++-- src/interfaces/sales.cairo | 24 +++++++++++++++ src/interfaces/voting.cairo | 1 + src/lib.cairo | 2 ++ src/mock_contract.cairo | 12 +++++++- 6 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 src/components/sales.cairo create mode 100644 src/interfaces/sales.cairo diff --git a/src/components/sales.cairo b/src/components/sales.cairo new file mode 100644 index 0000000..23730bb --- /dev/null +++ b/src/components/sales.cairo @@ -0,0 +1,58 @@ +#[starknet::component] +pub mod SalesComponent { + use starknet::storage::{ + Map, StoragePathEntry, StoragePointerReadAccess, StoragePointerWriteAccess, + }; + use crate::interfaces::{SalesStatus, SaleEvent}; + use starknet::{ContractAddress, get_caller_address}; + use crate::interfaces::sales::ISales; + + #[storage] + pub struct Storage { + pub sales: Map, + } + + #[event] + #[derive(Drop, starknet::Event)] + pub enum Event { + SaleEvent: SaleEvent + } + + #[embeddable_as(SalesImpl)] + pub impl Sales< + TContractState, +HasComponent, + > of ISales> { + fn buy(ref self: ComponentState, item_id: u256) { + let caller = get_caller_address(); + let current_status = self.sales.read(item_id); + + assert( + current_status == SalesStatus::None || + matches!(current_status, SalesStatus::Sold(_)), + 'Item not available for purchase' + ); + + self.sales.write(item_id, SalesStatus::Bought(caller)); + self.emit(SaleEvent { item_id, status: SalesStatus::Bought(caller), caller }); + } + + fn sell(ref self: ComponentState, item_id: u256) { + let caller = get_caller_address(); + let current_status = self.sales.read(item_id); + + assert( + current_status == SalesStatus::None || + (matches!(current_status, SalesStatus::Bought(owner)) && owner == caller), + 'You cannot sell this item' + ); + + self.sales.write(item_id, SalesStatus::Sold(caller)); + self.emit(SaleEvent { item_id, status: SalesStatus::Sold(caller), caller }); + } + + + fn get_status(self: @ComponentState, item_id: u256) -> SalesStatus { + self.sales.read(item_id) + } + } +} \ No newline at end of file diff --git a/src/components/voting.cairo b/src/components/voting.cairo index 7202dc0..5c55bcf 100644 --- a/src/components/voting.cairo +++ b/src/components/voting.cairo @@ -4,6 +4,7 @@ pub mod VotingComponent { Map, StoragePathEntry, StoragePointerReadAccess, StoragePointerWriteAccess, }; use starknet::{ContractAddress, get_caller_address}; + use crate::components::sales::{SalesImpl, SalesStatus}; use crate::interfaces::voting::{DEFAULT_THRESHOLD, IVote, Poll, PollTrait, Voted}; #[storage] @@ -11,6 +12,7 @@ pub mod VotingComponent { pub polls: Map, pub voters: Map<(ContractAddress, u256), bool>, pub nonce: u256, + pub sales: SalesImpl, } #[event] @@ -24,13 +26,14 @@ pub mod VotingComponent { TContractState, +HasComponent, > of IVote> { fn create_poll( - ref self: ComponentState, name: ByteArray, desc: ByteArray, + ref self: ComponentState, name: ByteArray, desc: ByteArray,item_id: u256 ) -> u256 { let id = self.nonce.read() + 1; assert(name != "" && desc != "", 'NAME OR DESC IS EMPTY'); let mut poll: Poll = Default::default(); poll.name = name; poll.desc = desc; + poll.linked_item = item_id; self.polls.entry(id).write(poll); self.nonce.write(id); id @@ -46,7 +49,16 @@ pub mod VotingComponent { match support { true => poll.yes_votes += 1, - _ => poll.no_votes += 1, + false => { + poll.no_votes += 1; + // Check if this "no" vote caused the threshold to be reached + let vote_count = poll.yes_votes + poll.no_votes; + if vote_count >= DEFAULT_THRESHOLD && poll.no_votes > poll.yes_votes { + // Immediately trigger sale if voting failed + self.sales.sell(poll.linked_item); + poll.status = PollStatus::Finished(false); + } + } } let vote_count = poll.yes_votes + poll.no_votes; diff --git a/src/interfaces/sales.cairo b/src/interfaces/sales.cairo new file mode 100644 index 0000000..1fed34e --- /dev/null +++ b/src/interfaces/sales.cairo @@ -0,0 +1,24 @@ +use starknet::ContractAddress; + +#[starknet::interface] +pub trait ISales { + fn buy(ref self: TContractState, item_id: u256); + fn sell(ref self: TContractState, item_id: u256); + fn get_status(self: @TContractState, item_id: u256) -> SalesStatus; +} + +#[derive(Drop, Copy, Serde, starknet::Store, PartialEq)] +pub enum SalesStatus { + #[default] + None, + Bought: ContractAddress, + Sold: ContractAddress +} + +#[derive(Drop, starknet::Event)] +pub struct SaleEvent { + #[key] + pub item_id: u256, + pub status: SalesStatus, + pub caller: ContractAddress +} \ No newline at end of file diff --git a/src/interfaces/voting.cairo b/src/interfaces/voting.cairo index b2d94b0..3737056 100644 --- a/src/interfaces/voting.cairo +++ b/src/interfaces/voting.cairo @@ -15,6 +15,7 @@ pub struct Poll { pub yes_votes: u256, pub no_votes: u256, pub status: PollStatus, + pub linked_item: u256, } #[generate_trait] diff --git a/src/lib.cairo b/src/lib.cairo index 6eb22f7..a11ebe1 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -1,9 +1,11 @@ pub mod interfaces { pub mod voting; + pub mod sales; } pub mod components { pub mod voting; + pub mod sales; } pub mod mock_contract; diff --git a/src/mock_contract.cairo b/src/mock_contract.cairo index d0a961f..2ca4504 100644 --- a/src/mock_contract.cairo +++ b/src/mock_contract.cairo @@ -1,12 +1,20 @@ #[starknet::contract] pub mod MockContract { use crate::components::voting::VotingComponent; + use crate::components::sales::SalesComponent; #[abi(embed_v0)] pub impl VotingImpl = VotingComponent::VotingImpl; + #[abi(embed_v0)] + pub impl SalesImpl = SalesComponent::SalesImpl; + #[storage] pub struct Storage { + #[substorage(v0)] + pub voting: VotingComponent::Storage, + #[substorage(v0)] + pub sales: SalesComponent::Storage, } #[event] @@ -14,7 +22,9 @@ pub mod MockContract { pub enum Event { #[flat] VotingEvent: VotingComponent::Event, - } + #[flat] + SalesEvent: SalesComponent::Event, + } } \ No newline at end of file