diff --git a/onchain/src/art_peace.cairo b/onchain/src/art_peace.cairo index 11f79653..288604f8 100644 --- a/onchain/src/art_peace.cairo +++ b/onchain/src/art_peace.cairo @@ -29,6 +29,7 @@ pub mod ArtPeace { creation_time: u64, end_time: u64, day_index: u32, + start_day_time: u64, // Map: (day_index, quest_id) -> quest contract address daily_quests: LegacyMap::<(u32, u32), ContractAddress>, main_quests_count: u32, @@ -43,11 +44,18 @@ pub mod ArtPeace { #[event] #[derive(Drop, starknet::Event)] enum Event { + Newday: NewDay, PixelPlaced: PixelPlaced, #[flat] TemplateEvent: TemplateStoreComponent::Event, } + #[derive(Drop, starknet::Event)] + struct NewDay { + #[key] + day_index: u32, + } + #[derive(Drop, starknet::Event)] struct PixelPlaced { #[key] @@ -71,6 +79,8 @@ pub mod ArtPeace { pub main_quests: Span, } + const DAY_IN_SECONDS: u64 = consteval_int!(60 * 60 * 24); + #[constructor] fn constructor(ref self: ContractState, init_params: InitParams) { self.canvas_width.write(init_params.canvas_width); @@ -88,6 +98,7 @@ pub mod ArtPeace { }; self.creation_time.write(starknet::get_block_timestamp()); + self.start_day_time.write(starknet::get_block_timestamp()); self.end_time.write(init_params.end_time); self.day_index.write(0); @@ -246,6 +257,17 @@ pub mod ArtPeace { self.day_index.read() } + fn increase_day_index(ref self: ContractState) { + let block_timestamp = starknet::get_block_timestamp(); + let start_day_time = self.start_day_time.read(); + + assert(block_timestamp >= start_day_time + DAY_IN_SECONDS, 'day has not passed'); + + self.day_index.write(self.day_index.read() + 1); + self.start_day_time.write(block_timestamp); + self.emit(NewDay { day_index: self.day_index.read() }); + } + fn get_daily_quest_count(self: @ContractState) -> core::zeroable::NonZero:: { // TODO: hardcoded 3 daily quests 3 @@ -425,3 +447,4 @@ pub mod ArtPeace { } } } + diff --git a/onchain/src/interface.cairo b/onchain/src/interface.cairo index 5d1b785a..9882ff36 100644 --- a/onchain/src/interface.cairo +++ b/onchain/src/interface.cairo @@ -40,6 +40,9 @@ pub trait IArtPeace { fn get_end_time(self: @TContractState) -> u64; fn get_day(self: @TContractState) -> u32; + // Start a new day + fn increase_day_index(ref self: TContractState); + // Get quest info fn get_daily_quest_count(self: @TContractState) -> core::zeroable::NonZero::; fn get_daily_quest( diff --git a/onchain/src/tests/art_peace.cairo b/onchain/src/tests/art_peace.cairo index ce0fa0a9..eff84e67 100644 --- a/onchain/src/tests/art_peace.cairo +++ b/onchain/src/tests/art_peace.cairo @@ -5,10 +5,14 @@ use art_peace::templates::{ ITemplateVerifierDispatcherTrait, TemplateMetadata }; +use core::poseidon::PoseidonTrait; +use core::hash::{HashStateTrait, HashStateExTrait}; + use snforge_std as snf; use snforge_std::{CheatTarget, ContractClassTrait}; use starknet::{ContractAddress, contract_address_const}; +const DAY_IN_SECONDS: u64 = consteval_int!(60 * 60 * 24); const WIDTH: u128 = 100; const HEIGHT: u128 = 100; const TIME_BETWEEN_PIXELS: u64 = 10; @@ -98,6 +102,21 @@ fn warp_to_next_available_time(art_peace: IArtPeaceDispatcher) { snf::start_warp(CheatTarget::One(art_peace.contract_address), last_time + TIME_BETWEEN_PIXELS); } +fn compute_template_hash(template: Span) -> felt252 { + let template_len = template.len(); + if template_len == 0 { + return 0; + } + + let mut hasher = PoseidonTrait::new(); + let mut i = 0; + while i < template_len { + hasher = hasher.update_with(*template.at(i)); + i += 1; + }; + hasher.finalize() +} + #[test] fn deploy_test() { let art_peace = IArtPeaceDispatcher { contract_address: deploy_contract() }; @@ -212,25 +231,6 @@ fn pixel_quest_test() { ); } -use core::poseidon::PoseidonTrait; -use core::hash::{HashStateTrait, HashStateExTrait}; - -// TODO: Move to src -fn compute_template_hash(template: Span) -> felt252 { - let template_len = template.len(); - if template_len == 0 { - return 0; - } - - let mut hasher = PoseidonTrait::new(); - let mut i = 0; - while i < template_len { - hasher = hasher.update_with(*template.at(i)); - i += 1; - }; - hasher.finalize() -} - #[test] fn template_full_basic_test() { let art_peace = IArtPeaceDispatcher { contract_address: deploy_contract() }; @@ -310,6 +310,34 @@ fn template_full_basic_test() { "Template is not completed after it should be" ); } + +#[test] +fn increase_day_test() { + let art_peace_address = deploy_contract(); + let art_peace = IArtPeaceDispatcher { contract_address: art_peace_address }; + + let current_day_index = art_peace.get_day(); + assert!(current_day_index == 0, "day index wrongly initialized"); + + snf::start_warp(CheatTarget::One(art_peace_address), DAY_IN_SECONDS); + art_peace.increase_day_index(); + let current_day_index = art_peace.get_day(); + assert!(current_day_index == 1, "day index not updated"); + snf::stop_warp(CheatTarget::One(art_peace_address)); +} + +#[test] +#[should_panic(expected: ('day has not passed',))] +fn increase_day_panic_test() { + let art_peace_address = deploy_contract(); + let art_peace = IArtPeaceDispatcher { contract_address: art_peace_address }; + + let current_day_index = art_peace.get_day(); + assert!(current_day_index == 0, "day index wrongly initialized"); + + snf::start_warp(CheatTarget::One(art_peace_address), DAY_IN_SECONDS - 1); + art_peace.increase_day_index(); +} // TODO: test invalid template inputs