diff --git a/contracts/mystery-box/interaction/devnet.snippets.sh b/contracts/mystery-box/interaction/devnet.snippets.sh index 2d56a02b..df1c5e8a 100644 --- a/contracts/mystery-box/interaction/devnet.snippets.sh +++ b/contracts/mystery-box/interaction/devnet.snippets.sh @@ -4,7 +4,7 @@ CHAIN_ID="D" MB_WASM_PATH="~/mx-contracts-rs/contracts/mystery-box/output/mystery-box.wasm" -CONTRACT_ADDRESS="erd1qqqqqqqqqqqqqpgql3ustfa2ac3d47y496865xkfrcxy48465dsqfzmxx5" +CONTRACT_ADDRESS="erd1qqqqqqqqqqqqqpgqwewz976lq7g68g4eaddkntru6dh28dpm5dsqnc6lvv" MB_TOKEN=0x4d425346542d663538616430 #MBSFT-f58ad0 deployMysteryBoxSC() { @@ -36,57 +36,78 @@ upgradeMysteryBoxSC() { ## eg. setSpecialRole@4d425346542d663538616430@00000000000000000500fc7905a7aaee22daf8952e8faa1ac91e0c4a9ebaa360@45534454526f6c654e4654437265617465@45534454526f6c654e46544275726e@45534454526f6c654e46544164645175616e74697479 ###PARAMS + +# Cooldown types +## None - 0 +## Lifetime - 1 +## ResetOnCooldown - 2 + #1 Experience points XP_TYPE=1 XP_REWARD_TOKEN=str:EGLD XP_VALUE=75 XP_DESCRIPTION=str:ExperiencePoints XP_CHANCE=4000 -DEFAULT_GLOBAL_COOLDOWN=0x00 +XP_COOLDOWN_TYPE=0 +XP_WINS_PER_COOLDOWN=0x00 +XP_COOLDOWN_EPOCHS=0x00 #2 Mystery box MB_TYPE=2 MB_TOKEN=str:MBSFT-f58ad0 MB_VALUE=1 MB_DESCRIPTION=str:MysteryBox -MB_CHANCE=3999 +MB_CHANCE=3998 +MB_COOLDOWN_TYPE=0 +MB_WINS_PER_COOLDOWN=0x00 +MB_COOLDOWN_EPOCHS=0x00 #3 SFT SFT_TYPE=3 SFT_TOKEN=str:MBSFT-f58ad0 SFT_VALUE=1 SFT_DESCRIPTION=str:SFT SFT_CHANCE=500 +SFT_COOLDOWN_TYPE=0 +SFT_WINS_PER_COOLDOWN=0x00 +SFT_COOLDOWN_EPOCHS=0x00 #4 PercentValue PERCENT_TYPE=4 PERCENT_TOKEN=str:EGLD PERCENT_VALUE=300 PERCENT_DESCRIPTION=str:PercentReward PERCENT_CHANCE=1000 +PERCENT_COOLDOWN_TYPE=0 +PERCENT_WINS_PER_COOLDOWN=0x00 +PERCENT_COOLDOWN_EPOCHS=0x00 #5 FixedValue FV_TYPE=5 FV_TOKEN=str:EGLD -FV_VALUE=50000000000000000000 +FV_VALUE=400000000000000000000 FV_DESCRIPTION=str:FixedValueReward -FV_CHANCE=1 -FV_GLOBAL_COOLDOWN=1 +FV_CHANCE=2 +FV_COOLDOWN_TYPE=1 +FV_WINS_PER_COOLDOWN=0x01 +FV_COOLDOWN_EPOCHS=0x00 #6 Custom reward CUSTOM_TYPE=6 CUSTOM_TOKEN=str:EGLD -CUSTOM_VALUE=1 -CUSTOM_DESCRIPTION=str:Combo1 +CUSTOM_VALUE=10000000000000000000 +CUSTOM_DESCRIPTION=str:BigPrize CUSTOM_CHANCE=500 -CUSTOM_GLOBAL_COOLDOWN=1 +CUSTOM_COOLDOWN_TYPE=2 +CUSTOM_WINS_PER_COOLDOWN=0x0a ## 10 +CUSTOM_COOLDOWN_EPOCHS=0x01 setupMysteryBox() { mxpy --verbose contract call ${CONTRACT_ADDRESS} --recall-nonce \ --pem=${WALLET_PEM} \ - --gas-limit=10000000 \ + --gas-limit=100000000 \ --proxy=${PROXY} --chain=${CHAIN_ID} \ --function="setupMysteryBox" \ - --arguments $XP_TYPE $XP_REWARD_TOKEN $XP_VALUE $XP_DESCRIPTION $XP_CHANCE $DEFAULT_GLOBAL_COOLDOWN \ - $MB_TYPE $MB_TOKEN $MB_VALUE $MB_DESCRIPTION $MB_CHANCE $DEFAULT_GLOBAL_COOLDOWN \ - $SFT_TYPE $SFT_TOKEN $SFT_VALUE $SFT_DESCRIPTION $SFT_CHANCE $DEFAULT_GLOBAL_COOLDOWN \ - $PERCENT_TYPE $PERCENT_TOKEN $PERCENT_VALUE $PERCENT_DESCRIPTION $PERCENT_CHANCE $DEFAULT_GLOBAL_COOLDOWN \ - $FV_TYPE $FV_TOKEN $FV_VALUE $FV_DESCRIPTION $FV_CHANCE $FV_GLOBAL_COOLDOWN \ - $CUSTOM_TYPE $CUSTOM_TOKEN $CUSTOM_VALUE $CUSTOM_DESCRIPTION $CUSTOM_CHANCE $CUSTOM_GLOBAL_COOLDOWN \ + --arguments $XP_TYPE $XP_REWARD_TOKEN $XP_VALUE $XP_DESCRIPTION $XP_CHANCE $XP_COOLDOWN_TYPE $XP_WINS_PER_COOLDOWN $XP_COOLDOWN_EPOCHS \ + $MB_TYPE $MB_TOKEN $MB_VALUE $MB_DESCRIPTION $MB_CHANCE $MB_COOLDOWN_TYPE $MB_WINS_PER_COOLDOWN $MB_COOLDOWN_EPOCHS \ + $SFT_TYPE $SFT_TOKEN $SFT_VALUE $SFT_DESCRIPTION $SFT_CHANCE $SFT_COOLDOWN_TYPE $SFT_WINS_PER_COOLDOWN $SFT_COOLDOWN_EPOCHS \ + $PERCENT_TYPE $PERCENT_TOKEN $PERCENT_VALUE $PERCENT_DESCRIPTION $PERCENT_CHANCE $PERCENT_COOLDOWN_TYPE $PERCENT_WINS_PER_COOLDOWN $PERCENT_COOLDOWN_EPOCHS \ + $FV_TYPE $FV_TOKEN $FV_VALUE $FV_DESCRIPTION $FV_CHANCE $FV_COOLDOWN_TYPE $FV_WINS_PER_COOLDOWN $FV_COOLDOWN_EPOCHS \ + $CUSTOM_TYPE $CUSTOM_TOKEN $CUSTOM_VALUE $CUSTOM_DESCRIPTION $CUSTOM_CHANCE $CUSTOM_COOLDOWN_TYPE $CUSTOM_WINS_PER_COOLDOWN $CUSTOM_COOLDOWN_EPOCHS \ --send || return } diff --git a/contracts/mystery-box/src/config.rs b/contracts/mystery-box/src/config.rs index 29a07d9c..2521673a 100644 --- a/contracts/mystery-box/src/config.rs +++ b/contracts/mystery-box/src/config.rs @@ -23,23 +23,23 @@ pub enum RewardType { ManagedVecItem, NestedEncode, NestedDecode, TopEncode, TopDecode, PartialEq, Eq, TypeAbi, Clone, )] pub struct Reward { + pub reward_id: usize, pub reward_type: RewardType, pub reward_token_id: EgldOrEsdtTokenIdentifier, pub value: BigUint, pub description: ManagedBuffer, pub percentage_chance: u64, - pub epochs_cooldown: u64, } impl Default for Reward { fn default() -> Self { Self { + reward_id: 0usize, reward_type: RewardType::None, reward_token_id: EgldOrEsdtTokenIdentifier::egld(), value: BigUint::zero(), description: ManagedBuffer::new(), percentage_chance: 0u64, - epochs_cooldown: 0u64, } } } @@ -47,20 +47,71 @@ impl Default for Reward { impl Reward { #[inline] pub fn new( + reward_id: usize, reward_type: RewardType, reward_token_id: EgldOrEsdtTokenIdentifier, value: BigUint, description: ManagedBuffer, percentage_chance: u64, - epochs_cooldown: u64, ) -> Self { Reward { + reward_id, reward_type, reward_token_id, value, description, percentage_chance, - epochs_cooldown, + } + } +} + +#[derive( + ManagedVecItem, NestedEncode, NestedDecode, TopEncode, TopDecode, PartialEq, Eq, TypeAbi, Clone, +)] +pub enum CooldownType { + None, + Lifetime, + ResetOnCooldown, +} + +#[derive( + ManagedVecItem, NestedEncode, NestedDecode, TopEncode, TopDecode, PartialEq, Eq, TypeAbi, Clone, +)] +pub struct RewardCooldown { + pub cooldown_type: CooldownType, + pub wins_per_cooldown: u64, + pub cooldown_epochs: u64, + pub remaining_epoch_wins: u64, + pub last_update_epoch: u64, +} + +impl Default for RewardCooldown { + fn default() -> Self { + Self { + cooldown_type: CooldownType::Lifetime, + wins_per_cooldown: 0u64, + cooldown_epochs: 0u64, + remaining_epoch_wins: 0u64, + last_update_epoch: 0u64, + } + } +} + +impl RewardCooldown { + #[inline] + pub fn new( + cooldown_type: CooldownType, + wins_per_cooldown: u64, + cooldown_epochs: u64, + remaining_epoch_wins: u64, + last_update_epoch: u64, + ) -> Self { + RewardCooldown { + cooldown_type, + wins_per_cooldown, + cooldown_epochs, + remaining_epoch_wins, + last_update_epoch, } } } @@ -71,9 +122,13 @@ pub trait ConfigModule { #[storage_mapper("mysteryBoxTokenIdentifier")] fn mystery_box_token_id(&self) -> SingleValueMapper; - #[view(getGlobalCooldownEpoch)] - #[storage_mapper("globalCooldownEpoch")] - fn global_cooldown_epoch(&self, reward: &RewardType) -> SingleValueMapper; + #[view(getLastRewardId)] + #[storage_mapper("lastRewardId")] + fn last_reward_id(&self) -> SingleValueMapper; + + #[view(getRewardCooldown)] + #[storage_mapper("rewardCooldown")] + fn reward_cooldown(&self, reward_id: usize) -> SingleValueMapper; #[view(getWinningRates)] #[storage_mapper("winningRates")] diff --git a/contracts/mystery-box/src/lib.rs b/contracts/mystery-box/src/lib.rs index 956dba04..d717ef0a 100644 --- a/contracts/mystery-box/src/lib.rs +++ b/contracts/mystery-box/src/lib.rs @@ -8,8 +8,8 @@ pub mod events; pub mod rewards; pub mod token_attributes; -use crate::config::SFT_AMOUNT; -use config::{Reward, RewardType, MAX_PERCENTAGE}; +use crate::config::{RewardCooldown, SFT_AMOUNT}; +use config::{CooldownType, Reward, RewardType, MAX_PERCENTAGE}; use multiversx_sc_modules::only_admin; #[multiversx_sc::contract] @@ -36,10 +36,21 @@ pub trait MysteryBox: fn setup_mystery_box( &self, winning_rates_list: MultiValueEncoded< - MultiValue6, + MultiValue8< + RewardType, + EgldOrEsdtTokenIdentifier, + BigUint, + ManagedBuffer, + u64, + CooldownType, + u64, + u64, + >, >, ) { self.require_caller_is_admin(); + let current_epoch = self.blockchain().get_block_epoch(); + let mut reward_id = self.last_reward_id().get(); let mut accumulated_percentage = 0u64; let mut winning_rates = ManagedVec::new(); for winning_rate in winning_rates_list.into_iter() { @@ -49,25 +60,38 @@ pub trait MysteryBox: value, description, percentage_chance, - epochs_cooldown, + cooldown_type, + wins_per_cooldown, + cooldown_epochs, ) = winning_rate.into_tuple(); accumulated_percentage += percentage_chance; + reward_id += 1; let reward = Reward::new( + reward_id, reward_type, reward_token_id, value, description, percentage_chance, - epochs_cooldown, ); - self.check_reward_validity(&reward); + let reward_cooldown = RewardCooldown::new( + cooldown_type, + wins_per_cooldown, + cooldown_epochs, + wins_per_cooldown, + current_epoch, + ); + self.check_reward_validity(&reward, &reward_cooldown); winning_rates.push(reward); + + self.reward_cooldown(reward_id).set(reward_cooldown); } require!( accumulated_percentage == MAX_PERCENTAGE, "The total percentage must be 100%" ); + self.last_reward_id().set(reward_id); self.winning_rates().set(winning_rates); self.mystery_box_uris().set_if_empty(ManagedVec::new()); } @@ -129,7 +153,7 @@ pub trait MysteryBox: let mut winning_reward = Reward::default(); while active_cooldown { winning_reward = self.get_winning_reward(&attributes); - active_cooldown = self.check_global_cooldown(current_epoch, &winning_reward); + active_cooldown = self.check_reward_cooldown(current_epoch, &winning_reward); } // We send the mystery box rewards directly to the user diff --git a/contracts/mystery-box/src/rewards.rs b/contracts/mystery-box/src/rewards.rs index e67107d5..2e53aef4 100644 --- a/contracts/mystery-box/src/rewards.rs +++ b/contracts/mystery-box/src/rewards.rs @@ -1,7 +1,7 @@ multiversx_sc::imports!(); multiversx_sc::derive_imports!(); -use crate::config::{self, Reward, RewardType, MAX_PERCENTAGE}; +use crate::config::{self, CooldownType, Reward, RewardCooldown, RewardType, MAX_PERCENTAGE}; #[multiversx_sc::module] pub trait RewardsModule: config::ConfigModule { @@ -29,7 +29,19 @@ pub trait RewardsModule: config::ConfigModule { winning_reward } - fn check_reward_validity(&self, reward: &Reward) { + fn check_reward_validity(&self, reward: &Reward, reward_cooldown: &RewardCooldown) { + if reward_cooldown.cooldown_type == CooldownType::ResetOnCooldown { + require!( + reward_cooldown.wins_per_cooldown > 0 && reward_cooldown.cooldown_epochs > 0, + "Invalid cooldown input for resettable cooldown type" + ); + } + if reward_cooldown.cooldown_epochs > 0 { + require!( + reward_cooldown.wins_per_cooldown > 0, + "Wins per cooldown must be greater than 0 for rewards with cooldown" + ); + } match reward.reward_type { RewardType::ExperiencePoints => { require!( @@ -68,17 +80,33 @@ pub trait RewardsModule: config::ConfigModule { } } - fn check_global_cooldown(&self, current_epoch: u64, reward: &Reward) -> bool { - let global_cooldown_epoch = self.global_cooldown_epoch(&reward.reward_type).get(); + fn check_reward_cooldown(&self, current_epoch: u64, reward: &Reward) -> bool { + let reward_cooldown_mapper = self.reward_cooldown(reward.reward_id); + if reward_cooldown_mapper.is_empty() { + return false; + }; + + let mut reward_cooldown = reward_cooldown_mapper.get(); + if reward_cooldown.cooldown_type == CooldownType::None { + return false; + }; + + let mut cooldown_check = true; - if reward.epochs_cooldown == 0 { - false - } else if global_cooldown_epoch <= current_epoch { - self.global_cooldown_epoch(&reward.reward_type) - .set(current_epoch + reward.epochs_cooldown); - false - } else { - true + if reward_cooldown.cooldown_type == CooldownType::ResetOnCooldown + && current_epoch >= reward_cooldown.last_update_epoch + reward_cooldown.cooldown_epochs + { + reward_cooldown.last_update_epoch = current_epoch; + reward_cooldown.remaining_epoch_wins = reward_cooldown.wins_per_cooldown; } + + if reward_cooldown.remaining_epoch_wins > 0 { + reward_cooldown.remaining_epoch_wins -= 1; + cooldown_check = false; + } + + reward_cooldown_mapper.set(reward_cooldown); + + cooldown_check } } diff --git a/contracts/mystery-box/tests/mystery_box_setup/mod.rs b/contracts/mystery-box/tests/mystery_box_setup/mod.rs index 219e2cc8..55e7b951 100644 --- a/contracts/mystery-box/tests/mystery_box_setup/mod.rs +++ b/contracts/mystery-box/tests/mystery_box_setup/mod.rs @@ -2,7 +2,10 @@ use multiversx_sc::types::{Address, EgldOrEsdtTokenIdentifier, EsdtLocalRole, Mu use multiversx_sc_scenario::{ managed_biguint, managed_buffer, managed_token_id, rust_biguint, whitebox::*, DebugApi, }; -use mystery_box::{config::RewardType, MysteryBox}; +use mystery_box::{ + config::{CooldownType, RewardType}, + MysteryBox, +}; pub const MYSTERY_BOX_WASM_PATH: &str = "mystery-box/output/mystery-box.wasm"; pub const MB_TOKEN_ID: &[u8] = b"MBTOK-abcdef"; @@ -50,25 +53,7 @@ where &mb_token_roles[..], ); - Self::internal_setup_mystery_box( - 900, - 5_999, - 1, - 3_000, - 0, - 1_500, - 1_000, - 0, - 50, - 1, - 1, - 1, - 0, - 0, - &owner_addr, - &mystery_box_wrapper, - &mut b_mock, - ); + Self::internal_setup_mystery_box(&owner_addr, &mystery_box_wrapper, &mut b_mock); MysteryBoxSetup { b_mock, @@ -79,20 +64,6 @@ where #[allow(clippy::too_many_arguments)] pub fn internal_setup_mystery_box( - experience_points_amount: u64, - experience_points_percentage: u64, - experience_points_cooldown: u64, - sft_reward_percentage: u64, - sft_reward_cooldown: u64, - percent_reward_amount: u64, - percent_reward_percentage: u64, - percent_reward_cooldown: u64, - fixed_value_reward_amount: u64, - fixed_value_reward_percentage: u64, - fixed_value_reward_cooldown: u64, - custom_reward_amount: u64, - custom_reward_percentage: u64, - custom_reward_cooldown: u64, owner_address: &Address, mb_wrapper: &ContractObjWrapper, MysteryBoxObjBuilder>, b_mock: &mut BlockchainStateWrapper, @@ -105,10 +76,12 @@ where let mut reward = ( RewardType::ExperiencePoints, EgldOrEsdtTokenIdentifier::egld(), - managed_biguint!(experience_points_amount), + managed_biguint!(10_000), managed_buffer!(b"ExperiencePoints"), - experience_points_percentage, - experience_points_cooldown, + 2_000u64, + CooldownType::None, + 0, + 0, ) .into(); rewards_list.push(reward); @@ -118,8 +91,10 @@ where EgldOrEsdtTokenIdentifier::esdt(managed_token_id!(MB_TOKEN_ID)), managed_biguint!(1), managed_buffer!(b"MysteryBox"), - sft_reward_percentage, - sft_reward_cooldown, + 1_500u64, + CooldownType::None, + 0, + 0, ) .into(); rewards_list.push(reward); @@ -127,10 +102,12 @@ where reward = ( RewardType::PercentValue, EgldOrEsdtTokenIdentifier::egld(), - managed_biguint!(percent_reward_amount), + managed_biguint!(1_500u64), managed_buffer!(b"Percent"), - percent_reward_percentage, - percent_reward_cooldown, + 1_000u64, + CooldownType::None, + 0, + 0, ) .into(); rewards_list.push(reward); @@ -138,10 +115,12 @@ where reward = ( RewardType::FixedValue, EgldOrEsdtTokenIdentifier::egld(), - managed_biguint!(fixed_value_reward_amount), + managed_biguint!(10u64), managed_buffer!(b"FixedValue"), - fixed_value_reward_percentage, - fixed_value_reward_cooldown, + 4_000u64, + CooldownType::ResetOnCooldown, + 2, + 2, ) .into(); rewards_list.push(reward); @@ -149,10 +128,12 @@ where reward = ( RewardType::CustomReward, EgldOrEsdtTokenIdentifier::egld(), - managed_biguint!(custom_reward_amount), + managed_biguint!(400u64), managed_buffer!(b"CustomText"), - custom_reward_percentage, - custom_reward_cooldown, + 1_500u64, + CooldownType::Lifetime, + 1, + 0, ) .into(); rewards_list.push(reward); @@ -202,38 +183,8 @@ where } #[allow(clippy::too_many_arguments)] - pub fn setup_mystery_box( - &mut self, - experience_points_amount: u64, - experience_points_percentage: u64, - experience_points_cooldown: u64, - sft_reward_percentage: u64, - sft_reward_cooldown: u64, - percent_reward_amount: u64, - percent_reward_percentage: u64, - percent_reward_cooldown: u64, - fixed_value_reward_amount: u64, - fixed_value_reward_percentage: u64, - fixed_value_reward_cooldown: u64, - custom_reward_amount: u64, - custom_reward_percentage: u64, - custom_reward_cooldown: u64, - ) { + pub fn setup_mystery_box(&mut self) { Self::internal_setup_mystery_box( - experience_points_amount, - experience_points_percentage, - experience_points_cooldown, - sft_reward_percentage, - sft_reward_cooldown, - percent_reward_amount, - percent_reward_percentage, - percent_reward_cooldown, - fixed_value_reward_amount, - fixed_value_reward_percentage, - fixed_value_reward_cooldown, - custom_reward_amount, - custom_reward_percentage, - custom_reward_cooldown, &self.owner_address, &self.mystery_box_wrapper, &mut self.b_mock, diff --git a/contracts/mystery-box/tests/mystery_box_test.rs b/contracts/mystery-box/tests/mystery_box_test.rs index df42c2f0..aca41c07 100644 --- a/contracts/mystery-box/tests/mystery_box_test.rs +++ b/contracts/mystery-box/tests/mystery_box_test.rs @@ -19,9 +19,7 @@ fn test_mb_token_nonce_stacking() { mb_setup.b_mock.set_block_epoch(2); mb_setup.open_mystery_box(second_mb_token_nonce); - mb_setup.setup_mystery_box( - 1_500, 5_999, 1, 3_000, 0, 1_500, 1_000, 0, 50, 1, 1, 0, 0, 0, - ); + mb_setup.setup_mystery_box(); let third_mb_token_nonce = mb_setup.create_mystery_box(1); // Should be different, as they were with different attributes @@ -36,22 +34,39 @@ fn test_open_multiple_mystery_box() { let mut mb_setup = MysteryBoxSetup::new(mystery_box::contract_obj); mb_setup.b_mock.set_block_epoch(1); - let mb_token_nonce = mb_setup.create_mystery_box(3); + let mb_token_nonce = mb_setup.create_mystery_box(10); - // We need to change the block random seed to properly test the RandomnessSource functionality - mb_setup.b_mock.set_block_epoch(2); + // We change the block random seed to properly test the RandomnessSource functionality + mb_setup.b_mock.set_block_epoch(3); mb_setup.b_mock.set_block_random_seed(Box::from([2u8; 48])); mb_setup.open_mystery_box(mb_token_nonce); - // We're still in epoch 2 - // The first chosen reward (ExperiencePoints) is on global cooldown, - // So a MysteryBox reward is chosen next (which has no cooldown) - // The user receives directly a new MysteryBox, with a different nonce (new epoch) + // Change the block random seed mb_setup.b_mock.set_block_random_seed(Box::from([3u8; 48])); mb_setup.open_mystery_box(mb_token_nonce); + // Keep the block random seed the same for 3 mystery boxes (ResetOnCooldown) + // This should select the same reward, which allows 2 wins per cooldown mb_setup.b_mock.set_block_epoch(4); mb_setup.b_mock.set_block_random_seed(Box::from([4u8; 48])); mb_setup.open_mystery_box(mb_token_nonce); mb_setup.open_mystery_box(mb_token_nonce); + + // Now a new prize is selected, as the initial one is on cooldown + // A lifetime prize is opened, so it should not be won again from now on + mb_setup.open_mystery_box(mb_token_nonce); + + // The 2 epochs cooldown has passed, ResetOnCooldown prize can be won again + mb_setup.b_mock.set_block_epoch(6); + mb_setup.b_mock.set_block_random_seed(Box::from([6u8; 48])); + mb_setup.open_mystery_box(mb_token_nonce); + mb_setup.open_mystery_box(mb_token_nonce); + + // The ResetOnCooldown prize cannot be won the third time during the cooldown, so a new one is selected + mb_setup.open_mystery_box(mb_token_nonce); + + // The lifetime reward is selected again, but it can't be won again, so a new prize is selected + mb_setup.b_mock.set_block_epoch(7); + mb_setup.b_mock.set_block_random_seed(Box::from([7u8; 48])); + mb_setup.open_mystery_box(mb_token_nonce); } diff --git a/contracts/mystery-box/wasm/src/lib.rs b/contracts/mystery-box/wasm/src/lib.rs index aeb81d7a..7800b529 100644 --- a/contracts/mystery-box/wasm/src/lib.rs +++ b/contracts/mystery-box/wasm/src/lib.rs @@ -5,9 +5,9 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 12 +// Endpoints: 13 // Async Callback (empty): 1 -// Total number of exported functions: 14 +// Total number of exported functions: 15 #![no_std] #![feature(lang_items)] @@ -23,7 +23,8 @@ multiversx_sc_wasm_adapter::endpoints! { createMysteryBox openMysteryBox getMysteryBoxTokenIdentifier - getGlobalCooldownEpoch + getLastRewardId + getRewardCooldown getWinningRates getMysteryBoxUris isAdmin