From 0098d960f49c2498d1236d2e6133db47c5f6fd51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Obrok?= Date: Thu, 22 Sep 2022 15:19:36 +0200 Subject: [PATCH 1/5] Transfer all tickets to market on button reset --- contracts/button/Cargo.lock | 20 ++++++ contracts/button/Cargo.toml | 2 + contracts/button/lib.rs | 118 ++++++++++++++++++++++++++++------ contracts/marketplace/lib.rs | 4 +- contracts/scripts/deploy.sh | 20 +++--- contracts/ticket_token/lib.rs | 21 +----- 6 files changed, 135 insertions(+), 50 deletions(-) diff --git a/contracts/button/Cargo.lock b/contracts/button/Cargo.lock index 2c36ea0f76..25242cb242 100644 --- a/contracts/button/Cargo.lock +++ b/contracts/button/Cargo.lock @@ -93,6 +93,7 @@ dependencies = [ "ink_prelude", "ink_primitives", "ink_storage", + "marketplace", "openbrush", "parity-scale-codec", "scale-info", @@ -529,6 +530,25 @@ version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +[[package]] +name = "marketplace" +version = "0.1.0" +dependencies = [ + "access_control", + "game_token", + "ink_engine", + "ink_env", + "ink_lang", + "ink_metadata", + "ink_prelude", + "ink_primitives", + "ink_storage", + "openbrush", + "parity-scale-codec", + "scale-info", + "ticket_token", +] + [[package]] name = "num-traits" version = "0.2.15" diff --git a/contracts/button/Cargo.toml b/contracts/button/Cargo.toml index 20f1a7c429..b82e32e98d 100644 --- a/contracts/button/Cargo.toml +++ b/contracts/button/Cargo.toml @@ -18,6 +18,7 @@ scale-info = { version = "2", default-features = false, features = ["derive"], o access_control = { path = "../access_control", default-features = false, features = ["ink-as-dependency"] } game_token = { path = "../game_token", default-features = false, features = ["ink-as-dependency"] } ticket_token = { path = "../ticket_token", default-features = false, features = ["ink-as-dependency"] } +marketplace = { path = "../marketplace", default-features = false, features = ["ink-as-dependency"] } openbrush = { git = "https://github.com/Supercolony-net/openbrush-contracts.git", rev = "8a20f95", default-features = false, features = ["psp22"] } [lib] @@ -42,6 +43,7 @@ std = [ "access_control/std", "game_token/std", "ticket_token/std", + "marketplace/std", "openbrush/std", ] ink-as-dependency = [] diff --git a/contracts/button/lib.rs b/contracts/button/lib.rs index 343acef407..467c0c1936 100644 --- a/contracts/button/lib.rs +++ b/contracts/button/lib.rs @@ -15,9 +15,10 @@ mod button_game { use ink_lang::{codegen::EmitEvent, reflect::ContractEventBase}; use ink_prelude::{format, vec}; use ink_storage::traits::{PackedLayout, SpreadLayout}; + use marketplace::RESET_SELECTOR as MARKETPLACE_RESET_SELECTOR; use openbrush::contracts::psp22::PSP22Error; use scale::{Decode, Encode}; - use ticket_token::TRANSFER_FROM_SELECTOR; + use ticket_token::{BALANCE_OF_SELECTOR, TRANSFER_FROM_SELECTOR, TRANSFER_SELECTOR}; use crate::errors::GameError; @@ -89,6 +90,8 @@ mod button_game { pub ticket_token: AccountId, /// access control contract pub access_control: AccountId, + /// ticket marketplace contract + pub marketplace: AccountId, /// scoring strategy pub scoring: Scoring, } @@ -102,6 +105,7 @@ mod button_game { pub fn new( ticket_token: AccountId, reward_token: AccountId, + marketplace: AccountId, button_lifetime: BlockNumber, scoring: Scoring, ) -> Self { @@ -113,7 +117,13 @@ mod button_game { let access_control = AccountId::from(ACCESS_CONTROL_PUBKEY); match ButtonGame::check_role(&access_control, &caller, required_role) { - Ok(_) => Self::init(ticket_token, reward_token, button_lifetime, scoring), + Ok(_) => Self::init( + ticket_token, + reward_token, + marketplace, + button_lifetime, + scoring, + ), Err(why) => panic!("Could not initialize the contract {:?}", why), } } @@ -157,6 +167,12 @@ mod button_game { self.ticket_token } + /// Returns the address of the marketplace for exchanging this game's rewards for tickets. + #[ink(message)] + pub fn marketplace(&self) -> AccountId { + self.marketplace + } + /// Returns own code hash #[ink(message)] pub fn code_hash(&self) -> ButtonResult { @@ -212,24 +228,11 @@ mod button_game { /// Can only be called after button's deadline #[ink(message)] pub fn reset(&mut self) -> ButtonResult<()> { - if !self.is_dead() { - return Err(GameError::BeforeDeadline); - } - - let now = self.env().block_number(); + self.ensure_dead()?; + self.reward_pressiah()?; + self.reset_state(); + self.dump_tickets_in_marketplace()?; - // reward the Pressiah - if let Some(pressiah) = self.last_presser { - let reward = self.pressiah_score(); - self.mint_reward(pressiah, reward)??; - }; - - self.presses = 0; - self.last_presser = None; - self.last_press = now; - self.total_rewards = 0; - - Self::emit_event(self.env(), Event::GameReset(GameReset { when: now })); Ok(()) } @@ -264,6 +267,7 @@ mod button_game { fn init( ticket_token: AccountId, reward_token: AccountId, + marketplace: AccountId, button_lifetime: BlockNumber, scoring: Scoring, ) -> Self { @@ -275,6 +279,7 @@ mod button_game { button_lifetime, reward_token, ticket_token, + marketplace, last_press: now, scoring, last_presser: None, @@ -295,6 +300,81 @@ mod button_game { contract } + fn reset_state(&mut self) { + let now = self.env().block_number(); + + self.presses = 0; + self.last_presser = None; + self.last_press = now; + self.total_rewards = 0; + + Self::emit_event(self.env(), Event::GameReset(GameReset { when: now })); + } + + fn reward_pressiah(&self) -> ButtonResult<()> { + if let Some(pressiah) = self.last_presser { + let reward = self.pressiah_score(); + self.mint_reward(pressiah, reward)??; + }; + + Ok(()) + } + + fn ensure_dead(&self) -> ButtonResult<()> { + if !self.is_dead() { + return Err(GameError::BeforeDeadline); + } else { + Ok(()) + } + } + + fn dump_tickets_in_marketplace(&self) -> ButtonResult<()> { + self.transfer_tickets_to_marketplace()?; + self.reset_marketplace()?; + Ok(()) + } + + fn transfer_tickets_to_marketplace(&self) -> ButtonResult<()> { + build_call::() + .call_type(Call::new().callee(self.ticket_token)) + .exec_input( + ExecutionInput::new(Selector::new(TRANSFER_SELECTOR)) + .push_arg(self.marketplace) + .push_arg(self.held_tickets()?) + .push_arg(vec![0x0]), + ) + .call_flags(CallFlags::default().set_allow_reentry(true)) + .returns::>() + .fire()??; + + Ok(()) + } + + fn held_tickets(&self) -> ButtonResult { + let result = build_call::() + .call_type(Call::new().callee(self.ticket_token)) + .exec_input( + ExecutionInput::new(Selector::new(BALANCE_OF_SELECTOR)) + .push_arg(self.env().account_id()), + ) + .returns::() + .fire()?; + + Ok(result) + } + + fn reset_marketplace(&self) -> ButtonResult<()> { + build_call::() + .call_type(Call::new().callee(self.marketplace)) + .exec_input(ExecutionInput::new(Selector::new( + MARKETPLACE_RESET_SELECTOR, + ))) + .returns::>() + .fire()??; + + Ok(()) + } + fn check_role( access_control: &AccountId, account: &AccountId, diff --git a/contracts/marketplace/lib.rs b/contracts/marketplace/lib.rs index 7c85f6d876..a41fdbee08 100644 --- a/contracts/marketplace/lib.rs +++ b/contracts/marketplace/lib.rs @@ -21,6 +21,8 @@ use ink_lang as ink; +pub const RESET_SELECTOR: [u8; 4] = [0x00, 0x00, 0x00, 0x01]; + #[ink::contract] pub mod marketplace { use access_control::{traits::AccessControlled, Role, ACCESS_CONTROL_PUBKEY}; @@ -225,7 +227,7 @@ pub mod marketplace { /// Note that this will keep the average estimate from previous auctions. /// /// Requires `Role::Admin`. - #[ink(message)] + #[ink(message, selector = 0x00000001)] pub fn reset(&mut self) -> Result<(), Error> { Self::ensure_role(self.admin())?; diff --git a/contracts/scripts/deploy.sh b/contracts/scripts/deploy.sh index 87148062aa..9bd7c6196b 100755 --- a/contracts/scripts/deploy.sh +++ b/contracts/scripts/deploy.sh @@ -99,13 +99,14 @@ function deploy_button_game { local game_type=$2 local ticket_token=$3 local game_token=$4 - local salt=$5 + local marketplace=$5 + local salt=$6 # --- CREATE AN INSTANCE OF THE CONTRACT cd "$CONTRACTS_PATH"/button - local contract_address=$(cargo contract instantiate --url "$NODE" --constructor new --args "$ticket_token" "$game_token" "$LIFETIME" "$game_type" --suri "$AUTHORITY_SEED" --salt "$salt") + local contract_address=$(cargo contract instantiate --url "$NODE" --constructor new --args "$ticket_token" "$game_token" "$marketplace" "$LIFETIME" "$game_type" --suri "$AUTHORITY_SEED" --salt "$salt") local contract_address=$(echo "$contract_address" | grep Contract | tail -1 | cut -c 15-) echo "$game_type contract instance address: $contract_address" @@ -115,6 +116,7 @@ function deploy_button_game { cd "$CONTRACTS_PATH"/access_control cargo contract call --url "$NODE" --contract "$ACCESS_CONTROL" --message grant_role --args "$AUTHORITY" 'Owner('"$contract_address"')' --suri "$AUTHORITY_SEED" + cargo contract call --url "$NODE" --contract "$ACCESS_CONTROL" --message grant_role --args "$contract_address" 'Admin('"$marketplace"')' --suri "$AUTHORITY_SEED" eval "$__resultvar='$contract_address'" } @@ -126,7 +128,6 @@ function deploy_marketplace { local salt=$4 local ticket_token=$5 local game_token=$6 - local game=$7 # --- CREATE AN INSTANCE OF THE CONTRACT @@ -151,7 +152,6 @@ function deploy_marketplace { cargo contract call --url "$NODE" --contract "$ACCESS_CONTROL" --message grant_role --args "$AUTHORITY" 'Owner('"$contract_address"')' --suri "$AUTHORITY_SEED" cargo contract call --url "$NODE" --contract "$ACCESS_CONTROL" --message grant_role --args "$AUTHORITY" 'Admin('"$contract_address"')' --suri "$AUTHORITY_SEED" - cargo contract call --url "$NODE" --contract "$ACCESS_CONTROL" --message grant_role --args "$game" 'Admin('"$contract_address"')' --suri "$AUTHORITY_SEED" eval "$__resultvar='$contract_address'" } @@ -219,8 +219,8 @@ echo "Early Bird Special" salt="0x4561726C79426972645370656369616C" deploy_ticket_token EARLY_BIRD_SPECIAL_TICKET early_bird_special_ticket EBST $salt deploy_game_token EARLY_BIRD_SPECIAL_TOKEN early_bird_special EBS $salt -deploy_button_game EARLY_BIRD_SPECIAL EarlyBirdSpecial $EARLY_BIRD_SPECIAL_TICKET $EARLY_BIRD_SPECIAL_TOKEN $salt -deploy_marketplace EARLY_BIRD_SPECIAL_MARKETPLACE "$MARKETPLACE_CODE_HASH" early_bird_special "$salt" "$EARLY_BIRD_SPECIAL_TICKET" "$EARLY_BIRD_SPECIAL_TOKEN" "$EARLY_BIRD_SPECIAL" +deploy_marketplace EARLY_BIRD_SPECIAL_MARKETPLACE "$MARKETPLACE_CODE_HASH" early_bird_special "$salt" "$EARLY_BIRD_SPECIAL_TICKET" "$EARLY_BIRD_SPECIAL_TOKEN" +deploy_button_game EARLY_BIRD_SPECIAL EarlyBirdSpecial $EARLY_BIRD_SPECIAL_TICKET $EARLY_BIRD_SPECIAL_TOKEN $EARLY_BIRD_SPECIAL_MARKETPLACE $salt # # --- BACK_TO_THE_FUTURE GAME @@ -230,8 +230,8 @@ echo "Back To The Future" salt="0x4261636B546F546865467574757265" deploy_ticket_token BACK_TO_THE_FUTURE_TICKET back_to_the_future_ticket BTFT $salt deploy_game_token BACK_TO_THE_FUTURE_TOKEN back_to_the_future BTF $salt -deploy_button_game BACK_TO_THE_FUTURE BackToTheFuture $BACK_TO_THE_FUTURE_TICKET $BACK_TO_THE_FUTURE_TOKEN $salt -deploy_marketplace BACK_TO_THE_FUTURE_MARKETPLACE "$MARKETPLACE_CODE_HASH" back_to_the_future "$salt" "$BACK_TO_THE_FUTURE_TICKET" "$BACK_TO_THE_FUTURE_TOKEN" "$BACK_TO_THE_FUTURE" +deploy_marketplace BACK_TO_THE_FUTURE_MARKETPLACE "$MARKETPLACE_CODE_HASH" back_to_the_future "$salt" "$BACK_TO_THE_FUTURE_TICKET" "$BACK_TO_THE_FUTURE_TOKEN" +deploy_button_game BACK_TO_THE_FUTURE BackToTheFuture $BACK_TO_THE_FUTURE_TICKET $BACK_TO_THE_FUTURE_TOKEN $BACK_TO_THE_FUTURE_MARKETPLACE $salt # # --- THE_PRESSIAH_COMETH GAME @@ -241,8 +241,8 @@ echo "The Pressiah Cometh" salt="0x7468655F70726573736961685F636F6D657468" deploy_ticket_token THE_PRESSIAH_COMETH_TICKET the_pressiah_cometh_ticket TPCT $salt deploy_game_token THE_PRESSIAH_COMETH_TOKEN the_pressiah_cometh TPC $salt -deploy_button_game THE_PRESSIAH_COMETH ThePressiahCometh $THE_PRESSIAH_COMETH_TICKET $THE_PRESSIAH_COMETH_TOKEN $salt -deploy_marketplace THE_PRESSIAH_COMETH_MARKETPLACE "$MARKETPLACE_CODE_HASH" the_pressiah_cometh "$salt" "$THE_PRESSIAH_COMETH_TICKET" "$THE_PRESSIAH_COMETH_TOKEN" "$THE_PRESSIAH_COMETH" +deploy_marketplace THE_PRESSIAH_COMETH_MARKETPLACE "$MARKETPLACE_CODE_HASH" the_pressiah_cometh "$salt" "$THE_PRESSIAH_COMETH_TICKET" "$THE_PRESSIAH_COMETH_TOKEN" +deploy_button_game THE_PRESSIAH_COMETH ThePressiahCometh $THE_PRESSIAH_COMETH_TICKET $THE_PRESSIAH_COMETH_TOKEN $THE_PRESSIAH_COMETH_MARKETPLACE $salt # spit adresses to a JSON file cd "$CONTRACTS_PATH" diff --git a/contracts/ticket_token/lib.rs b/contracts/ticket_token/lib.rs index 07ffd2b7d6..8a21c42af2 100644 --- a/contracts/ticket_token/lib.rs +++ b/contracts/ticket_token/lib.rs @@ -14,7 +14,7 @@ pub mod ticket_token { use ink_prelude::{format, string::String}; use ink_storage::traits::SpreadAllocate; use openbrush::{ - contracts::psp22::{extensions::metadata::*, Internal, Transfer}, + contracts::psp22::{extensions::metadata::*, Internal}, traits::Storage, }; @@ -37,25 +37,6 @@ pub mod ticket_token { impl PSP22Metadata for TicketToken {} - impl Transfer for TicketToken { - fn _before_token_transfer( - &mut self, - from: Option<&AccountId>, - to: Option<&AccountId>, - amount: &Balance, - ) -> core::result::Result<(), PSP22Error> { - // if from is None this is an initial mint in the constructor - // and we don't want to enforce it there - if from.is_some() && to.is_some() && !amount.eq(&1u128) { - return Err(PSP22Error::Custom(String::from( - "Only single ticket can be transferred at once", - ))); - } - - Ok(()) - } - } - impl Internal for TicketToken { fn _emit_transfer_event( &self, From ef58baff4386eb431e7d949270bf81e4ee115648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Obrok?= Date: Thu, 22 Sep 2022 16:24:11 +0200 Subject: [PATCH 2/5] Update contracts/button/lib.rs Co-authored-by: kostekIV <27210860+kostekIV@users.noreply.github.com> --- contracts/button/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/button/lib.rs b/contracts/button/lib.rs index 467c0c1936..6b81184035 100644 --- a/contracts/button/lib.rs +++ b/contracts/button/lib.rs @@ -330,8 +330,7 @@ mod button_game { fn dump_tickets_in_marketplace(&self) -> ButtonResult<()> { self.transfer_tickets_to_marketplace()?; - self.reset_marketplace()?; - Ok(()) + self.reset_marketplace() } fn transfer_tickets_to_marketplace(&self) -> ButtonResult<()> { From 2f6987a025f1008339385bd3c8b7bb899d87d5c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Obrok?= Date: Thu, 22 Sep 2022 16:24:16 +0200 Subject: [PATCH 3/5] Update contracts/button/lib.rs Co-authored-by: kostekIV <27210860+kostekIV@users.noreply.github.com> --- contracts/button/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/button/lib.rs b/contracts/button/lib.rs index 6b81184035..e11f87850a 100644 --- a/contracts/button/lib.rs +++ b/contracts/button/lib.rs @@ -231,7 +231,7 @@ mod button_game { self.ensure_dead()?; self.reward_pressiah()?; self.reset_state(); - self.dump_tickets_in_marketplace()?; + self.dump_tickets_in_marketplace() Ok(()) } From 8b31acd97dc24fea0ec06e4991d1c57068c1040f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Obrok?= Date: Thu, 22 Sep 2022 17:01:06 +0200 Subject: [PATCH 4/5] Fix misapplied suggestion --- contracts/button/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/contracts/button/lib.rs b/contracts/button/lib.rs index e11f87850a..5696b7469e 100644 --- a/contracts/button/lib.rs +++ b/contracts/button/lib.rs @@ -232,8 +232,6 @@ mod button_game { self.reward_pressiah()?; self.reset_state(); self.dump_tickets_in_marketplace() - - Ok(()) } /// Sets new access control contract address From ccd266a98f63260cf5fd977a4d167ebb222ec5f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Obrok?= Date: Tue, 4 Oct 2022 11:00:19 +0200 Subject: [PATCH 5/5] Inline function --- contracts/button/lib.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/contracts/button/lib.rs b/contracts/button/lib.rs index 5696b7469e..6f4030525b 100644 --- a/contracts/button/lib.rs +++ b/contracts/button/lib.rs @@ -231,7 +231,8 @@ mod button_game { self.ensure_dead()?; self.reward_pressiah()?; self.reset_state(); - self.dump_tickets_in_marketplace() + self.transfer_tickets_to_marketplace()?; + self.reset_marketplace() } /// Sets new access control contract address @@ -326,11 +327,6 @@ mod button_game { } } - fn dump_tickets_in_marketplace(&self) -> ButtonResult<()> { - self.transfer_tickets_to_marketplace()?; - self.reset_marketplace() - } - fn transfer_tickets_to_marketplace(&self) -> ButtonResult<()> { build_call::() .call_type(Call::new().callee(self.ticket_token))