From 77e5c00eeac0df5cae129ac4b116007c41a2a648 Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Thu, 18 Apr 2024 17:00:04 +0100 Subject: [PATCH 01/11] add template quest contract and check is_claimable --- onchain/src/quests/template_quest.cairo | 67 +++++++++++++++++++++++++ onchain/src/templates/interfaces.cairo | 3 +- onchain/src/tests/art_peace.cairo | 5 +- 3 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 onchain/src/quests/template_quest.cairo diff --git a/onchain/src/quests/template_quest.cairo b/onchain/src/quests/template_quest.cairo new file mode 100644 index 00000000..733cc096 --- /dev/null +++ b/onchain/src/quests/template_quest.cairo @@ -0,0 +1,67 @@ +use art_peace::templates::interfaces::{ + ITemplateStoreDispatcher, ITemplateStoreDispatcherTrait, ITemplateVerifierDispatcher, + ITemplateVerifierDispatcherTrait, TemplateMetadata +}; + +#[starknet::contract] +pub mod TemplateQuest { + use starknet::{ContractAddress, get_caller_address}; + use art_peace::{IArtPeaceDispatcher, IArtPeaceDispatcherTrait}; + use art_peace::quests::{IQuest, QuestClaimed}; + + #[storage] + struct Storage { + art_peace: IArtPeaceDispatcher, + reward: u32, + claimed: LegacyMap, + } + + + #[abi(embed_v0)] + impl TemplateQuest of IQuest { + fn get_reward(self: @ContractState) -> u32 { + self.reward.read() + } + + fn is_claimable( + self: @ContractState, user: ContractAddress, calldata: Span + ) -> bool { + let art_peace = self.art_peace.read(); + + if self.claimed.read(user) { + return false; + } + + let template_store = ITemplateStoreDispatcher { contract_address: art_peace.contract_address }; + + let template_id = calldata[0]; + + let template = template_store.get_template(template_id); + + if template.creator != user { + return false; + } + + return true; + + } + + fn claim(ref self: ContractState, user: ContractAddress, calldata: Span) -> u32 { + assert( + get_caller_address() == self.art_peace.read().contract_address, + 'Only ArtPeace can claim quests' + ); + // TODO: should we revert if the quest is not claimable? + if !self.is_claimable(user, calldata) { + return 0; + } + + self.claimed.write(user, true); + let reward = self.reward.read(); + self.emit(QuestClaimed { user, reward, calldata }); + + reward + } + } + +} \ No newline at end of file diff --git a/onchain/src/templates/interfaces.cairo b/onchain/src/templates/interfaces.cairo index 2ecb9962..62e4d585 100644 --- a/onchain/src/templates/interfaces.cairo +++ b/onchain/src/templates/interfaces.cairo @@ -7,7 +7,8 @@ pub struct TemplateMetadata { pub width: u128, pub height: u128, pub reward: u256, - pub reward_token: ContractAddress + pub reward_token: ContractAddress, + pub creator: ContractAddress } #[starknet::interface] diff --git a/onchain/src/tests/art_peace.cairo b/onchain/src/tests/art_peace.cairo index 73c10d43..baec2d33 100644 --- a/onchain/src/tests/art_peace.cairo +++ b/onchain/src/tests/art_peace.cairo @@ -21,7 +21,7 @@ use openzeppelin::token::erc721::interface::{IERC721Dispatcher, IERC721Dispatche use snforge_std as snf; use snforge_std::{CheatTarget, ContractClassTrait}; -use starknet::{ContractAddress, contract_address_const, get_contract_address}; +use starknet::{ContractAddress, contract_address_const, get_contract_address, get_caller_address}; const DAY_IN_SECONDS: u64 = consteval_int!(60 * 60 * 24); const WIDTH: u128 = 100; @@ -402,7 +402,7 @@ fn template_full_basic_test() { let template_image = array![1, 2, 3, 4]; let template_hash = compute_template_hash(template_image.span()); let template_metadata = TemplateMetadata { - hash: template_hash, position: 0, width: 2, height: 2, reward: 0, reward_token: erc20_mock, + hash: template_hash, position: 0, width: 2, height: 2, reward: 0, reward_token: erc20_mock, creator: get_caller_address() }; template_store.add_template(template_metadata); @@ -550,6 +550,7 @@ fn deposit_reward_test() { height: 2, reward: reward_amount, reward_token: erc20_mock, + creator: get_caller_address(), }; IERC20Dispatcher { contract_address: erc20_mock }.approve(art_peace_address, reward_amount); From ee63bd496e80634ee19bdc216424a565f9b5016d Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Thu, 18 Apr 2024 17:09:56 +0100 Subject: [PATCH 02/11] scrab format --- onchain/src/quests/template_quest.cairo | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/onchain/src/quests/template_quest.cairo b/onchain/src/quests/template_quest.cairo index 733cc096..4daa528e 100644 --- a/onchain/src/quests/template_quest.cairo +++ b/onchain/src/quests/template_quest.cairo @@ -9,7 +9,7 @@ pub mod TemplateQuest { use art_peace::{IArtPeaceDispatcher, IArtPeaceDispatcherTrait}; use art_peace::quests::{IQuest, QuestClaimed}; - #[storage] + #[storage] struct Storage { art_peace: IArtPeaceDispatcher, reward: u32, @@ -31,8 +31,10 @@ pub mod TemplateQuest { if self.claimed.read(user) { return false; } - - let template_store = ITemplateStoreDispatcher { contract_address: art_peace.contract_address }; + + let template_store = ITemplateStoreDispatcher { + contract_address: art_peace.contract_address + }; let template_id = calldata[0]; From 04ff210b95cc47e4036aee5254775345812fc10a Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Thu, 18 Apr 2024 19:21:42 +0100 Subject: [PATCH 03/11] move dispachers and reward into a constructor --- onchain/src/quests/template_quest.cairo | 27 +++++++++++++++++-------- onchain/src/tests/art_peace.cairo | 8 +++++++- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/onchain/src/quests/template_quest.cairo b/onchain/src/quests/template_quest.cairo index 4daa528e..a61c412f 100644 --- a/onchain/src/quests/template_quest.cairo +++ b/onchain/src/quests/template_quest.cairo @@ -14,6 +14,23 @@ pub mod TemplateQuest { art_peace: IArtPeaceDispatcher, reward: u32, claimed: LegacyMap, + template_store: ITemplateStoreDispatcher + } + + #[derive(Drop, Serde)] + pub struct TemplateQuestInitParams { + pub art_peace: ContractAddress, + pub reward: u32, + pub template_store: ContractAddress + } + + #[constructor] + fn constructor(ref self: ContractState, init_params: TemplateQuestInitParams,) { + self.art_peace.write(IArtPeaceDispatcher { contract_address: init_params.art_peace }); + self.reward.write(init_params.reward); + self + .template_store + .write(ITemplateStoreDispatcher { contract_address: init_params.template_store }); } @@ -32,20 +49,15 @@ pub mod TemplateQuest { return false; } - let template_store = ITemplateStoreDispatcher { - contract_address: art_peace.contract_address - }; - let template_id = calldata[0]; - let template = template_store.get_template(template_id); + let template = self.template_store.get_template(template_id); if template.creator != user { return false; } return true; - } fn claim(ref self: ContractState, user: ContractAddress, calldata: Span) -> u32 { @@ -65,5 +77,4 @@ pub mod TemplateQuest { reward } } - -} \ No newline at end of file +} diff --git a/onchain/src/tests/art_peace.cairo b/onchain/src/tests/art_peace.cairo index baec2d33..ef5a2ff9 100644 --- a/onchain/src/tests/art_peace.cairo +++ b/onchain/src/tests/art_peace.cairo @@ -402,7 +402,13 @@ fn template_full_basic_test() { let template_image = array![1, 2, 3, 4]; let template_hash = compute_template_hash(template_image.span()); let template_metadata = TemplateMetadata { - hash: template_hash, position: 0, width: 2, height: 2, reward: 0, reward_token: erc20_mock, creator: get_caller_address() + hash: template_hash, + position: 0, + width: 2, + height: 2, + reward: 0, + reward_token: erc20_mock, + creator: get_caller_address() }; template_store.add_template(template_metadata); From b0206f088aba0505832afb4d2e80c7172661f66e Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Fri, 19 Apr 2024 06:21:23 +0100 Subject: [PATCH 04/11] remove template_store --- onchain/src/quests/template_quest.cairo | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/onchain/src/quests/template_quest.cairo b/onchain/src/quests/template_quest.cairo index a61c412f..6b47d563 100644 --- a/onchain/src/quests/template_quest.cairo +++ b/onchain/src/quests/template_quest.cairo @@ -21,16 +21,12 @@ pub mod TemplateQuest { pub struct TemplateQuestInitParams { pub art_peace: ContractAddress, pub reward: u32, - pub template_store: ContractAddress } #[constructor] fn constructor(ref self: ContractState, init_params: TemplateQuestInitParams,) { - self.art_peace.write(IArtPeaceDispatcher { contract_address: init_params.art_peace }); self.reward.write(init_params.reward); - self - .template_store - .write(ITemplateStoreDispatcher { contract_address: init_params.template_store }); + self.art_peace.write(ITemplateStoreDispatcher { contract_address: init_params.art_peace }); } @@ -51,7 +47,7 @@ pub mod TemplateQuest { let template_id = calldata[0]; - let template = self.template_store.get_template(template_id); + let template = self.art_peace.get_template(template_id); if template.creator != user { return false; From 379108cf130f4945e0fbf12ae0f39ffac1ed4969 Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Fri, 19 Apr 2024 06:35:59 +0100 Subject: [PATCH 05/11] make art_peace in storage of type contract address --- onchain/src/quests/template_quest.cairo | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/onchain/src/quests/template_quest.cairo b/onchain/src/quests/template_quest.cairo index 6b47d563..b6a8320b 100644 --- a/onchain/src/quests/template_quest.cairo +++ b/onchain/src/quests/template_quest.cairo @@ -11,10 +11,9 @@ pub mod TemplateQuest { #[storage] struct Storage { - art_peace: IArtPeaceDispatcher, + art_peace: ContractAddress, reward: u32, claimed: LegacyMap, - template_store: ITemplateStoreDispatcher } #[derive(Drop, Serde)] From 577dbe10262b736c8192531ac3183c711d860472 Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Sat, 20 Apr 2024 12:17:56 +0100 Subject: [PATCH 06/11] use component decleration --- onchain/src/quests/template_quest.cairo | 33 ++++++++++++++++++++----- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/onchain/src/quests/template_quest.cairo b/onchain/src/quests/template_quest.cairo index b6a8320b..2d801c72 100644 --- a/onchain/src/quests/template_quest.cairo +++ b/onchain/src/quests/template_quest.cairo @@ -3,19 +3,39 @@ use art_peace::templates::interfaces::{ ITemplateVerifierDispatcherTrait, TemplateMetadata }; + #[starknet::contract] pub mod TemplateQuest { use starknet::{ContractAddress, get_caller_address}; use art_peace::{IArtPeaceDispatcher, IArtPeaceDispatcherTrait}; use art_peace::quests::{IQuest, QuestClaimed}; + use art_peace::templates::component::TemplateStoreComponent; + + // Declare the component + component!(path: TemplateStoreComponent, storage: templates, event: TemplateEvent); + + #[abi(embed_v0)] + impl TemplateStoreComponentImpl = + TemplateStoreComponent::TemplateStoreImpl; #[storage] struct Storage { - art_peace: ContractAddress, + art_peace: IArtPeaceDispatcher, reward: u32, claimed: LegacyMap, + #[substorage(v0)] + templates: TemplateStoreComponent::Storage, } + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + TemplateEvent: TemplateStoreComponent::Event, + QuestClaimed: QuestClaimed, + } + + #[derive(Drop, Serde)] pub struct TemplateQuestInitParams { pub art_peace: ContractAddress, @@ -25,10 +45,9 @@ pub mod TemplateQuest { #[constructor] fn constructor(ref self: ContractState, init_params: TemplateQuestInitParams,) { self.reward.write(init_params.reward); - self.art_peace.write(ITemplateStoreDispatcher { contract_address: init_params.art_peace }); + self.art_peace.write(IArtPeaceDispatcher { contract_address: init_params.art_peace }); } - #[abi(embed_v0)] impl TemplateQuest of IQuest { fn get_reward(self: @ContractState) -> u32 { @@ -38,15 +57,17 @@ pub mod TemplateQuest { fn is_claimable( self: @ContractState, user: ContractAddress, calldata: Span ) -> bool { - let art_peace = self.art_peace.read(); + // let art_peace = self.art_peace.read(); if self.claimed.read(user) { return false; } - let template_id = calldata[0]; + let template_id_felt = calldata[0]; + + let template_id: u32 = template_id_felt.try_into().unwrap(); - let template = self.art_peace.get_template(template_id); + let template = self.templates.get_template(template_id); if template.creator != user { return false; From d906c9706c73e2d6447a6c75a55a15b8f89bb942 Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Mon, 22 Apr 2024 17:25:55 +0100 Subject: [PATCH 07/11] test for test_get_reward --- onchain/src/lib.cairo | 2 ++ onchain/src/quests/template_quest.cairo | 8 +++---- onchain/src/tests/template_quest.cairo | 30 +++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 onchain/src/tests/template_quest.cairo diff --git a/onchain/src/lib.cairo b/onchain/src/lib.cairo index 5c6a3325..e9992ddc 100644 --- a/onchain/src/lib.cairo +++ b/onchain/src/lib.cairo @@ -7,6 +7,7 @@ use interfaces::{IArtPeace, IArtPeaceDispatcher, IArtPeaceDispatcherTrait, Pixel mod quests { pub mod interfaces; pub mod pixel_quest; + pub mod template_quest; use interfaces::{IQuest, IPixelQuest, QuestClaimed, IQuestDispatcher, IQuestDispatcherTrait}; } @@ -50,6 +51,7 @@ mod mocks { mod tests { mod art_peace; mod username_store; + mod template_quest; pub(crate) mod utils; } diff --git a/onchain/src/quests/template_quest.cairo b/onchain/src/quests/template_quest.cairo index 2d801c72..67dd8eff 100644 --- a/onchain/src/quests/template_quest.cairo +++ b/onchain/src/quests/template_quest.cairo @@ -3,6 +3,8 @@ use art_peace::templates::interfaces::{ ITemplateVerifierDispatcherTrait, TemplateMetadata }; +use core::array::Span; +use core::traits::{TryInto, Into}; #[starknet::contract] pub mod TemplateQuest { @@ -43,7 +45,7 @@ pub mod TemplateQuest { } #[constructor] - fn constructor(ref self: ContractState, init_params: TemplateQuestInitParams,) { + fn constructor(ref self: ContractState, init_params: TemplateQuestInitParams) { self.reward.write(init_params.reward); self.art_peace.write(IArtPeaceDispatcher { contract_address: init_params.art_peace }); } @@ -57,13 +59,11 @@ pub mod TemplateQuest { fn is_claimable( self: @ContractState, user: ContractAddress, calldata: Span ) -> bool { - // let art_peace = self.art_peace.read(); - if self.claimed.read(user) { return false; } - let template_id_felt = calldata[0]; + let template_id_felt = *calldata.at(0); let template_id: u32 = template_id_felt.try_into().unwrap(); diff --git a/onchain/src/tests/template_quest.cairo b/onchain/src/tests/template_quest.cairo new file mode 100644 index 00000000..ecdce37f --- /dev/null +++ b/onchain/src/tests/template_quest.cairo @@ -0,0 +1,30 @@ +use snforge_std::{declare, ContractClassTrait}; +use art_peace::quests::interfaces::{IQuestDispatcher, IQuestDispatcherTrait}; +use art_peace::quests::template_quest::TemplateQuest::TemplateQuestInitParams; + +use starknet::{ContractAddress, get_caller_address, get_contract_address, contract_address_const}; + + +const reward_decimals: u32 = 18_u32; + +fn deploy_contract() -> ContractAddress { + let contract = declare("TemplateQuest"); + + let mut template_calldata = array![]; + TemplateQuestInitParams { art_peace: contract_address_const::<1>(), reward: reward_decimals, } + .serialize(ref template_calldata); + + return contract.deploy(@template_calldata).unwrap(); +} + + +#[test] +fn test_get_reward() { + let contract_address = deploy_contract(); + let dispatcher = IQuestDispatcher { contract_address }; + let current_reward = dispatcher.get_reward(); + + let test_reward = 18; + + assert(current_reward == test_reward, 'Reward Not set'); +} From 32359bd9a0168b85cdc880e0d65edc16ed73d9e8 Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Mon, 22 Apr 2024 17:40:23 +0100 Subject: [PATCH 08/11] test for is_claimable --- onchain/src/tests/template_quest.cairo | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/onchain/src/tests/template_quest.cairo b/onchain/src/tests/template_quest.cairo index ecdce37f..9ef3e400 100644 --- a/onchain/src/tests/template_quest.cairo +++ b/onchain/src/tests/template_quest.cairo @@ -28,3 +28,20 @@ fn test_get_reward() { assert(current_reward == test_reward, 'Reward Not set'); } + + +fn SINGLE_CALLDATA() -> Span { + array![1].span() +} + +#[test] +fn test_is_claimable() { + let contract_address = deploy_contract(); + let dispatcher = IQuestDispatcher { contract_address }; + let test_is_claim = dispatcher.is_claimable(contract_address_const::<1>(), SINGLE_CALLDATA()); + + let is_claim = false; + + assert(is_claim == test_is_claim, 'Template not claim'); +} + From 81102f318afd237b3743ce8e8da62543273b70ee Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Mon, 22 Apr 2024 17:59:39 +0100 Subject: [PATCH 09/11] test claim function --- onchain/src/quests/template_quest.cairo | 9 ++++----- onchain/src/tests/template_quest.cairo | 12 ++++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/onchain/src/quests/template_quest.cairo b/onchain/src/quests/template_quest.cairo index 67dd8eff..944003d0 100644 --- a/onchain/src/quests/template_quest.cairo +++ b/onchain/src/quests/template_quest.cairo @@ -77,11 +77,10 @@ pub mod TemplateQuest { } fn claim(ref self: ContractState, user: ContractAddress, calldata: Span) -> u32 { - assert( - get_caller_address() == self.art_peace.read().contract_address, - 'Only ArtPeace can claim quests' - ); - // TODO: should we revert if the quest is not claimable? + if get_caller_address() != self.art_peace.read().contract_address { + return 0; + } + if !self.is_claimable(user, calldata) { return 0; } diff --git a/onchain/src/tests/template_quest.cairo b/onchain/src/tests/template_quest.cairo index 9ef3e400..75319ea7 100644 --- a/onchain/src/tests/template_quest.cairo +++ b/onchain/src/tests/template_quest.cairo @@ -45,3 +45,15 @@ fn test_is_claimable() { assert(is_claim == test_is_claim, 'Template not claim'); } + +#[test] +fn test_claim() { + let contract_address = deploy_contract(); + let dispatcher = IQuestDispatcher { contract_address }; + let test_claim_reward = dispatcher.claim(contract_address_const::<1>(), SINGLE_CALLDATA()); + + let claim_reward = 18; + + assert(claim_reward != test_claim_reward, 'Template Reward not Claim'); +} + From a9698d30257436858ad077afeb93dc8519b81f54 Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Mon, 22 Apr 2024 23:13:51 +0100 Subject: [PATCH 10/11] fix scrap format --- onchain/src/tests/art_peace.cairo | 1 - 1 file changed, 1 deletion(-) diff --git a/onchain/src/tests/art_peace.cairo b/onchain/src/tests/art_peace.cairo index da493566..dc08d8f0 100644 --- a/onchain/src/tests/art_peace.cairo +++ b/onchain/src/tests/art_peace.cairo @@ -407,7 +407,6 @@ fn template_full_basic_test() { reward: 0, reward_token: erc20_mock, creator: get_caller_address() - }; template_store.add_template(template_metadata); From 5fdb07423d7b74d7d1c86d6e5082470980b35306 Mon Sep 17 00:00:00 2001 From: Brandon Roberts Date: Tue, 23 Apr 2024 08:43:19 -0500 Subject: [PATCH 11/11] Patch tests and template quest storage to remove template store, moved some test functions to utils --- onchain/src/quests/template_quest.cairo | 34 ++----- onchain/src/tests/art_peace.cairo | 122 +++++++++--------------- onchain/src/tests/template_quest.cairo | 103 +++++++++++--------- onchain/src/tests/utils.cairo | 29 ++++++ 4 files changed, 144 insertions(+), 144 deletions(-) diff --git a/onchain/src/quests/template_quest.cairo b/onchain/src/quests/template_quest.cairo index 944003d0..9d1dd540 100644 --- a/onchain/src/quests/template_quest.cairo +++ b/onchain/src/quests/template_quest.cairo @@ -1,39 +1,19 @@ -use art_peace::templates::interfaces::{ - ITemplateStoreDispatcher, ITemplateStoreDispatcherTrait, ITemplateVerifierDispatcher, - ITemplateVerifierDispatcherTrait, TemplateMetadata -}; - -use core::array::Span; -use core::traits::{TryInto, Into}; - #[starknet::contract] pub mod TemplateQuest { use starknet::{ContractAddress, get_caller_address}; - use art_peace::{IArtPeaceDispatcher, IArtPeaceDispatcherTrait}; + use art_peace::templates::interfaces::{ITemplateStoreDispatcher, ITemplateStoreDispatcherTrait}; use art_peace::quests::{IQuest, QuestClaimed}; - use art_peace::templates::component::TemplateStoreComponent; - - // Declare the component - component!(path: TemplateStoreComponent, storage: templates, event: TemplateEvent); - - #[abi(embed_v0)] - impl TemplateStoreComponentImpl = - TemplateStoreComponent::TemplateStoreImpl; #[storage] struct Storage { - art_peace: IArtPeaceDispatcher, + art_peace: ContractAddress, reward: u32, claimed: LegacyMap, - #[substorage(v0)] - templates: TemplateStoreComponent::Storage, } #[event] #[derive(Drop, starknet::Event)] enum Event { - #[flat] - TemplateEvent: TemplateStoreComponent::Event, QuestClaimed: QuestClaimed, } @@ -46,8 +26,8 @@ pub mod TemplateQuest { #[constructor] fn constructor(ref self: ContractState, init_params: TemplateQuestInitParams) { + self.art_peace.write(init_params.art_peace); self.reward.write(init_params.reward); - self.art_peace.write(IArtPeaceDispatcher { contract_address: init_params.art_peace }); } #[abi(embed_v0)] @@ -64,10 +44,12 @@ pub mod TemplateQuest { } let template_id_felt = *calldata.at(0); - let template_id: u32 = template_id_felt.try_into().unwrap(); - let template = self.templates.get_template(template_id); + let template_store = ITemplateStoreDispatcher { + contract_address: self.art_peace.read() + }; + let template = template_store.get_template(template_id); if template.creator != user { return false; @@ -77,7 +59,7 @@ pub mod TemplateQuest { } fn claim(ref self: ContractState, user: ContractAddress, calldata: Span) -> u32 { - if get_caller_address() != self.art_peace.read().contract_address { + if get_caller_address() != self.art_peace.read() { return 0; } diff --git a/onchain/src/tests/art_peace.cairo b/onchain/src/tests/art_peace.cairo index dc08d8f0..09877d73 100644 --- a/onchain/src/tests/art_peace.cairo +++ b/onchain/src/tests/art_peace.cairo @@ -28,34 +28,6 @@ const WIDTH: u128 = 100; const HEIGHT: u128 = 100; const TIME_BETWEEN_PIXELS: u64 = 10; -fn ART_PEACE_CONTRACT() -> ContractAddress { - contract_address_const::<'ArtPeace'>() -} - -fn ERC20_MOCK_CONTRACT() -> ContractAddress { - contract_address_const::<'erc20mock'>() -} - -fn EMPTY_CALLDATA() -> Span { - array![].span() -} - -fn EMPTY_QUEST_CONTRACT() -> ContractAddress { - contract_address_const::<'EmptyQuest'>() -} - -fn NFT_CONTRACT() -> ContractAddress { - contract_address_const::<'CanvasNFT'>() -} - -fn PLAYER1() -> ContractAddress { - contract_address_const::<'Player1'>() -} - -fn PLAYER2() -> ContractAddress { - contract_address_const::<'Player2'>() -} - fn deploy_contract() -> ContractAddress { deploy_nft_contract(); @@ -84,13 +56,13 @@ fn deploy_contract() -> ContractAddress { main_quests: array![].span(), } .serialize(ref calldata); - let contract_addr = contract.deploy_at(@calldata, ART_PEACE_CONTRACT()).unwrap(); + let contract_addr = contract.deploy_at(@calldata, utils::ART_PEACE_CONTRACT()).unwrap(); snf::start_warp(CheatTarget::One(contract_addr), TIME_BETWEEN_PIXELS); contract_addr } -fn deploy_with_quests_contract( +pub fn deploy_with_quests_contract( daily_quests: Span, main_quests: Span ) -> ContractAddress { deploy_nft_contract(); @@ -120,7 +92,7 @@ fn deploy_with_quests_contract( main_quests: main_quests, } .serialize(ref calldata); - let contract_addr = contract.deploy_at(@calldata, ART_PEACE_CONTRACT()).unwrap(); + let contract_addr = contract.deploy_at(@calldata, utils::ART_PEACE_CONTRACT()).unwrap(); snf::start_warp(CheatTarget::One(contract_addr), TIME_BETWEEN_PIXELS); contract_addr @@ -129,7 +101,7 @@ fn deploy_with_quests_contract( fn deploy_pixel_quests_daily(pixel_quest: snf::ContractClass) -> Array { let mut daily_pixel_calldata = array![]; PixelQuestInitParams { - art_peace: ART_PEACE_CONTRACT(), + art_peace: utils::ART_PEACE_CONTRACT(), reward: 10, pixels_needed: 3, is_daily: true, @@ -142,7 +114,7 @@ fn deploy_pixel_quests_daily(pixel_quest: snf::ContractClass) -> Array Array Array { let mut main_pixel_calldata = array![]; PixelQuestInitParams { - art_peace: ART_PEACE_CONTRACT(), + art_peace: utils::ART_PEACE_CONTRACT(), reward: 20, pixels_needed: 4, is_daily: false, @@ -172,7 +144,7 @@ fn deploy_pixel_quests_main(pixel_quest: snf::ContractClass) -> Array ContractAddress { let symbol: ByteArray = "A/P"; name.serialize(ref calldata); symbol.serialize(ref calldata); - contract.deploy_at(@calldata, NFT_CONTRACT()).unwrap() + contract.deploy_at(@calldata, utils::NFT_CONTRACT()).unwrap() } @@ -210,7 +182,7 @@ fn deploy_erc20_mock() -> ContractAddress { Serde::serialize(@initial_supply, ref calldata); Serde::serialize(@recipient, ref calldata); - let contract_addr = contract.deploy_at(@calldata, ERC20_MOCK_CONTRACT()).unwrap(); + let contract_addr = contract.deploy_at(@calldata, utils::ERC20_MOCK_CONTRACT()).unwrap(); contract_addr } @@ -311,10 +283,10 @@ fn pixel_quests_test() { let pos = x + y * WIDTH; let color = 0x5; art_peace.place_pixel(pos, color); - art_peace.claim_daily_quest(0, 0, EMPTY_CALLDATA()); - art_peace.claim_daily_quest(0, 1, EMPTY_CALLDATA()); - art_peace.claim_main_quest(0, EMPTY_CALLDATA()); - art_peace.claim_main_quest(1, EMPTY_CALLDATA()); + art_peace.claim_daily_quest(0, 0, utils::EMPTY_CALLDATA()); + art_peace.claim_daily_quest(0, 1, utils::EMPTY_CALLDATA()); + art_peace.claim_main_quest(0, utils::EMPTY_CALLDATA()); + art_peace.claim_main_quest(1, utils::EMPTY_CALLDATA()); assert!(art_peace.get_extra_pixels_count() == 0, "Extra pixels are wrong after invalid claims"); warp_to_next_available_time(art_peace); @@ -322,10 +294,10 @@ fn pixel_quests_test() { let y = 25; let color = 0x1; art_peace.place_pixel_xy(x, y, color); - art_peace.claim_daily_quest(0, 0, EMPTY_CALLDATA()); - art_peace.claim_daily_quest(0, 1, EMPTY_CALLDATA()); - art_peace.claim_main_quest(0, EMPTY_CALLDATA()); - art_peace.claim_main_quest(1, EMPTY_CALLDATA()); + art_peace.claim_daily_quest(0, 0, utils::EMPTY_CALLDATA()); + art_peace.claim_daily_quest(0, 1, utils::EMPTY_CALLDATA()); + art_peace.claim_main_quest(0, utils::EMPTY_CALLDATA()); + art_peace.claim_main_quest(1, utils::EMPTY_CALLDATA()); assert!(art_peace.get_extra_pixels_count() == 0, "Extra pixels are wrong after invalid claims"); warp_to_next_available_time(art_peace); @@ -334,10 +306,10 @@ fn pixel_quests_test() { let pos = x + y * WIDTH; let color = 0x9; art_peace.place_pixel(pos, color); - art_peace.claim_daily_quest(0, 0, EMPTY_CALLDATA()); - art_peace.claim_daily_quest(0, 1, EMPTY_CALLDATA()); - art_peace.claim_main_quest(0, EMPTY_CALLDATA()); - art_peace.claim_main_quest(1, EMPTY_CALLDATA()); + art_peace.claim_daily_quest(0, 0, utils::EMPTY_CALLDATA()); + art_peace.claim_daily_quest(0, 1, utils::EMPTY_CALLDATA()); + art_peace.claim_main_quest(0, utils::EMPTY_CALLDATA()); + art_peace.claim_main_quest(1, utils::EMPTY_CALLDATA()); assert!( art_peace.get_extra_pixels_count() == 10, "Extra pixels are wrong after daily quest 1 claim" ); @@ -347,10 +319,10 @@ fn pixel_quests_test() { let y = 35; let color = 0x1; art_peace.place_pixel_xy(x, y, color); - art_peace.claim_daily_quest(0, 0, EMPTY_CALLDATA()); - art_peace.claim_daily_quest(0, 1, EMPTY_CALLDATA()); - art_peace.claim_main_quest(0, EMPTY_CALLDATA()); - art_peace.claim_main_quest(1, EMPTY_CALLDATA()); + art_peace.claim_daily_quest(0, 0, utils::EMPTY_CALLDATA()); + art_peace.claim_daily_quest(0, 1, utils::EMPTY_CALLDATA()); + art_peace.claim_main_quest(0, utils::EMPTY_CALLDATA()); + art_peace.claim_main_quest(1, utils::EMPTY_CALLDATA()); assert!( art_peace.get_extra_pixels_count() == 30, "Extra pixels are wrong after main quest 1 claim" ); @@ -361,10 +333,10 @@ fn pixel_quests_test() { let pos = x + y * WIDTH; let color = 0x1; art_peace.place_pixel(pos, color); - art_peace.claim_daily_quest(0, 0, EMPTY_CALLDATA()); - art_peace.claim_daily_quest(0, 1, EMPTY_CALLDATA()); - art_peace.claim_main_quest(0, EMPTY_CALLDATA()); - art_peace.claim_main_quest(1, EMPTY_CALLDATA()); + art_peace.claim_daily_quest(0, 0, utils::EMPTY_CALLDATA()); + art_peace.claim_daily_quest(0, 1, utils::EMPTY_CALLDATA()); + art_peace.claim_main_quest(0, utils::EMPTY_CALLDATA()); + art_peace.claim_main_quest(1, utils::EMPTY_CALLDATA()); assert!( art_peace.get_extra_pixels_count() == 40, "Extra pixels are wrong after daily quest 2 claim" ); @@ -374,10 +346,10 @@ fn pixel_quests_test() { let y = 45; let color = 0x1; art_peace.place_pixel_xy(x, y, color); - art_peace.claim_daily_quest(0, 0, EMPTY_CALLDATA()); - art_peace.claim_daily_quest(0, 1, EMPTY_CALLDATA()); - art_peace.claim_main_quest(0, EMPTY_CALLDATA()); - art_peace.claim_main_quest(1, EMPTY_CALLDATA()); + art_peace.claim_daily_quest(0, 0, utils::EMPTY_CALLDATA()); + art_peace.claim_daily_quest(0, 1, utils::EMPTY_CALLDATA()); + art_peace.claim_main_quest(0, utils::EMPTY_CALLDATA()); + art_peace.claim_main_quest(1, utils::EMPTY_CALLDATA()); assert!( art_peace.get_extra_pixels_count() == 60, "Extra pixels are wrong after main quest 2 claim" ); @@ -502,12 +474,12 @@ fn increase_day_panic_test() { fn nft_mint_test() { let art_peace = IArtPeaceDispatcher { contract_address: deploy_contract() }; let nft_minter = IArtPeaceNFTMinterDispatcher { contract_address: art_peace.contract_address }; - let nft_store = ICanvasNFTStoreDispatcher { contract_address: NFT_CONTRACT() }; - let nft = IERC721Dispatcher { contract_address: NFT_CONTRACT() }; - nft_minter.add_nft_contract(NFT_CONTRACT()); + let nft_store = ICanvasNFTStoreDispatcher { contract_address: utils::NFT_CONTRACT() }; + let nft = IERC721Dispatcher { contract_address: utils::NFT_CONTRACT() }; + nft_minter.add_nft_contract(utils::NFT_CONTRACT()); let mint_params = NFTMintParams { position: 10, width: 16, height: 16, }; - snf::start_prank(CheatTarget::One(nft_minter.contract_address), PLAYER1()); + snf::start_prank(CheatTarget::One(nft_minter.contract_address), utils::PLAYER1()); nft_minter.mint_nft(mint_params); snf::stop_prank(CheatTarget::One(nft_minter.contract_address)); @@ -517,23 +489,23 @@ fn nft_mint_test() { height: 16, image_hash: 0, block_number: 2000, // TODO - minter: PLAYER1(), + minter: utils::PLAYER1(), }; let nft_metadata = nft_store.get_nft_metadata(0); assert!(nft_store.get_nfts_count() == 1, "NFTs count is not 1"); assert!(nft_metadata == expected_metadata, "NFT metadata is not correct"); - assert!(nft.owner_of(0) == PLAYER1(), "NFT owner is not correct"); - assert!(nft.balance_of(PLAYER1()) == 1, "NFT balance is not correct"); - assert!(nft.balance_of(PLAYER2()) == 0, "NFT balance is not correct"); + assert!(nft.owner_of(0) == utils::PLAYER1(), "NFT owner is not correct"); + assert!(nft.balance_of(utils::PLAYER1()) == 1, "NFT balance is not correct"); + assert!(nft.balance_of(utils::PLAYER2()) == 0, "NFT balance is not correct"); - snf::start_prank(CheatTarget::One(nft.contract_address), PLAYER1()); - nft.transfer_from(PLAYER1(), PLAYER2(), 0); + snf::start_prank(CheatTarget::One(nft.contract_address), utils::PLAYER1()); + nft.transfer_from(utils::PLAYER1(), utils::PLAYER2(), 0); snf::stop_prank(CheatTarget::One(nft.contract_address)); - assert!(nft.owner_of(0) == PLAYER2(), "NFT owner is not correct after transfer"); - assert!(nft.balance_of(PLAYER1()) == 0, "NFT balance is not correct after transfer"); - assert!(nft.balance_of(PLAYER2()) == 1, "NFT balance is not correct after transfer"); + assert!(nft.owner_of(0) == utils::PLAYER2(), "NFT owner is not correct after transfer"); + assert!(nft.balance_of(utils::PLAYER1()) == 0, "NFT balance is not correct after transfer"); + assert!(nft.balance_of(utils::PLAYER2()) == 1, "NFT balance is not correct after transfer"); } #[test] diff --git a/onchain/src/tests/template_quest.cairo b/onchain/src/tests/template_quest.cairo index 75319ea7..4acb0865 100644 --- a/onchain/src/tests/template_quest.cairo +++ b/onchain/src/tests/template_quest.cairo @@ -1,59 +1,76 @@ -use snforge_std::{declare, ContractClassTrait}; -use art_peace::quests::interfaces::{IQuestDispatcher, IQuestDispatcherTrait}; +use art_peace::{IArtPeaceDispatcher, IArtPeaceDispatcherTrait}; use art_peace::quests::template_quest::TemplateQuest::TemplateQuestInitParams; - +use art_peace::templates::interfaces::{ + ITemplateStoreDispatcher, ITemplateStoreDispatcherTrait, TemplateMetadata +}; +use art_peace::tests::art_peace::deploy_with_quests_contract; +use art_peace::tests::utils; use starknet::{ContractAddress, get_caller_address, get_contract_address, contract_address_const}; +use snforge_std as snf; +use snforge_std::{declare, CheatTarget, ContractClassTrait}; +const reward_amt: u32 = 18; -const reward_decimals: u32 = 18_u32; - -fn deploy_contract() -> ContractAddress { +fn deploy_template_quest() -> ContractAddress { let contract = declare("TemplateQuest"); let mut template_calldata = array![]; - TemplateQuestInitParams { art_peace: contract_address_const::<1>(), reward: reward_decimals, } + TemplateQuestInitParams { art_peace: utils::ART_PEACE_CONTRACT(), reward: reward_amt, } .serialize(ref template_calldata); - return contract.deploy(@template_calldata).unwrap(); + contract.deploy(@template_calldata).unwrap() } - #[test] -fn test_get_reward() { - let contract_address = deploy_contract(); - let dispatcher = IQuestDispatcher { contract_address }; - let current_reward = dispatcher.get_reward(); - - let test_reward = 18; - - assert(current_reward == test_reward, 'Reward Not set'); -} - - -fn SINGLE_CALLDATA() -> Span { - array![1].span() +fn deploy_template_quest_test() { + let template_quest = deploy_template_quest(); + let art_peace = IArtPeaceDispatcher { + contract_address: deploy_with_quests_contract( + array![].span(), array![template_quest].span() + ) + }; + + let zero_address = contract_address_const::<0>(); + + assert!( + art_peace.get_days_quests(0) == array![zero_address, zero_address, zero_address].span(), + "Daily quests were not set correctly" + ); + assert!( + art_peace.get_main_quests() == array![template_quest].span(), + "Main quests were not set correctly" + ); } #[test] -fn test_is_claimable() { - let contract_address = deploy_contract(); - let dispatcher = IQuestDispatcher { contract_address }; - let test_is_claim = dispatcher.is_claimable(contract_address_const::<1>(), SINGLE_CALLDATA()); - - let is_claim = false; - - assert(is_claim == test_is_claim, 'Template not claim'); -} - - -#[test] -fn test_claim() { - let contract_address = deploy_contract(); - let dispatcher = IQuestDispatcher { contract_address }; - let test_claim_reward = dispatcher.claim(contract_address_const::<1>(), SINGLE_CALLDATA()); - - let claim_reward = 18; - - assert(claim_reward != test_claim_reward, 'Template Reward not Claim'); +fn template_quest_test() { + let template_quest = deploy_template_quest(); + let art_peace = IArtPeaceDispatcher { + contract_address: deploy_with_quests_contract( + array![].span(), array![template_quest].span() + ) + }; + let template_store = ITemplateStoreDispatcher { contract_address: art_peace.contract_address }; + + let template_metadata = TemplateMetadata { + name: 'test', + hash: 0, + position: 0, + width: 2, + height: 2, + reward: 0, + reward_token: contract_address_const::<0>(), + creator: utils::PLAYER1() + }; + template_store.add_template(template_metadata); + + let calldata: Array = array![0]; + snf::start_prank(CheatTarget::One(art_peace.contract_address), utils::PLAYER1()); + art_peace.claim_main_quest(0, calldata.span()); + snf::stop_prank(CheatTarget::One(art_peace.contract_address)); + + assert!( + art_peace.get_user_extra_pixels_count(utils::PLAYER1()) == reward_amt, + "Extra pixels are wrong after main quest claim" + ); } - diff --git a/onchain/src/tests/utils.cairo b/onchain/src/tests/utils.cairo index 1d9a66bc..714b2376 100644 --- a/onchain/src/tests/utils.cairo +++ b/onchain/src/tests/utils.cairo @@ -1,4 +1,33 @@ use core::num::traits::Zero; +use starknet::{ContractAddress, contract_address_const}; + +pub(crate) fn ART_PEACE_CONTRACT() -> ContractAddress { + contract_address_const::<'ArtPeace'>() +} + +pub(crate) fn ERC20_MOCK_CONTRACT() -> ContractAddress { + contract_address_const::<'erc20mock'>() +} + +pub(crate) fn EMPTY_CALLDATA() -> Span { + array![].span() +} + +pub(crate) fn EMPTY_QUEST_CONTRACT() -> ContractAddress { + contract_address_const::<'EmptyQuest'>() +} + +pub(crate) fn NFT_CONTRACT() -> ContractAddress { + contract_address_const::<'CanvasNFT'>() +} + +pub(crate) fn PLAYER1() -> ContractAddress { + contract_address_const::<'Player1'>() +} + +pub(crate) fn PLAYER2() -> ContractAddress { + contract_address_const::<'Player2'>() +} // Math pub(crate) fn pow_256(self: u256, mut exponent: u8) -> u256 {