diff --git a/Cargo.toml b/Cargo.toml index 93e74297..05451ba3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,4 +67,6 @@ members = [ "contracts/seed-nft-minter/meta", "contracts/token-release", "contracts/token-release/meta", + "contracts/mvx-game-sc", + "contracts/mvx-game-sc/meta" ] diff --git a/contracts/mvx-game-sc/.gitignore b/contracts/mvx-game-sc/.gitignore new file mode 100644 index 00000000..dd49a952 --- /dev/null +++ b/contracts/mvx-game-sc/.gitignore @@ -0,0 +1,10 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +*/target/ + +# The mxpy output +/output*/ + +# Mandos test trace +trace*.scen.json diff --git a/contracts/mvx-game-sc/Cargo.toml b/contracts/mvx-game-sc/Cargo.toml new file mode 100644 index 00000000..94d8a570 --- /dev/null +++ b/contracts/mvx-game-sc/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "mvx-game-sc" +version = "0.0.0" +authors = [ "Mihai Calin Luca calin.luca@multiversx.com",] +edition = "2018" +publish = false + +[lib] +path = "src/lib.rs" + +[dependencies.multiversx-sc] +version = "0.43.4" + +[dev-dependencies.multiversx-sc-scenario] +version = "0.43.4" diff --git a/contracts/mvx-game-sc/README.md b/contracts/mvx-game-sc/README.md new file mode 100644 index 00000000..064dcfce --- /dev/null +++ b/contracts/mvx-game-sc/README.md @@ -0,0 +1,3 @@ +# lib + +`lib` is a simple Smart Contract. diff --git a/contracts/mvx-game-sc/meta/Cargo.toml b/contracts/mvx-game-sc/meta/Cargo.toml new file mode 100644 index 00000000..77f0a821 --- /dev/null +++ b/contracts/mvx-game-sc/meta/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "mvx-game-sc-meta" +version = "0.0.0" +edition = "2018" +publish = false +authors = [ "you",] + +[dev-dependencies] + +[dependencies.mvx-game-sc] +path = ".." + +[dependencies.multiversx-sc-meta] +version = "0.43.4" diff --git a/contracts/mvx-game-sc/meta/src/main.rs b/contracts/mvx-game-sc/meta/src/main.rs new file mode 100644 index 00000000..22154128 --- /dev/null +++ b/contracts/mvx-game-sc/meta/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + multiversx_sc_meta::cli_main::(); +} diff --git a/contracts/mvx-game-sc/multiversx.json b/contracts/mvx-game-sc/multiversx.json new file mode 100644 index 00000000..73655396 --- /dev/null +++ b/contracts/mvx-game-sc/multiversx.json @@ -0,0 +1,3 @@ +{ + "language": "rust" +} \ No newline at end of file diff --git a/contracts/mvx-game-sc/src/lib.rs b/contracts/mvx-game-sc/src/lib.rs new file mode 100644 index 00000000..d5699b0c --- /dev/null +++ b/contracts/mvx-game-sc/src/lib.rs @@ -0,0 +1,87 @@ +#![no_std] + +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +pub mod owner; +pub mod private; +pub mod storage; +pub mod types; + +#[multiversx_sc::contract] +pub trait MvxGameSc: storage::StorageModule + owner::OwnerModule + private::PrivateModule { + #[init] + fn init( + &self, + enabled_opt: OptionalValue, + game_start_fee_opt: OptionalValue, + token_id_opt: OptionalValue, + ) { + match enabled_opt { + OptionalValue::Some(_) => self.enabled().set(true), + OptionalValue::None => {} + } + + match game_start_fee_opt { + OptionalValue::Some(val) => self.game_start_fee().set(val), + OptionalValue::None => { + require!(!self.game_start_fee().is_empty(), "game start fee not set") + } + } + + match token_id_opt { + OptionalValue::Some(val) => self.token_id().set(val), + OptionalValue::None => require!(!self.token_id().is_empty(), "fee token id not set"), + } + } + + #[payable("*")] + #[endpoint(createGame)] + fn create_game( + &self, + waiting_time: u64, + number_of_players_min: u64, + number_of_players_max: u64, + wager: BigUint, + ) { + self.require_enabled(); + + let (token_id, amount) = self.call_value().single_fungible_esdt(); + self.validate_create_game_payment(&token_id, &amount, &wager, waiting_time); + + let (min, max) = self.get_min_max(number_of_players_min, number_of_players_max); + + let caller = self.blockchain().get_caller(); + self.create_new_game(caller, waiting_time, min, max, wager); + } + + #[payable("*")] + #[endpoint(joinGame)] + fn join_game(&self, game_id: u64) { + self.require_enabled(); + + let (token_id, amount) = self.call_value().single_fungible_esdt(); + let now = self.blockchain().get_block_timestamp(); + let caller = self.blockchain().get_caller(); + + let game_settings = self.validate_join_game(&caller, now, &token_id, &amount, game_id); + + self.add_player(caller, game_id); + + self.refresh_game_status(game_id, game_settings); + } + + //manually claim back wager if the game is invalid + #[endpoint(claimBackWager)] + fn claim_back_wager(&self, game_id: u64) { + self.require_enabled(); + + let caller = self.blockchain().get_caller(); + let wager = self.validate_claim_wager(&caller, game_id); + + let token_id = self.token_id().get(); + self.send().direct(&caller, &token_id, 0u64, &wager); + + self.remove_player(caller, game_id); + } +} diff --git a/contracts/mvx-game-sc/src/owner.rs b/contracts/mvx-game-sc/src/owner.rs new file mode 100644 index 00000000..6d0f69eb --- /dev/null +++ b/contracts/mvx-game-sc/src/owner.rs @@ -0,0 +1,75 @@ +use crate::types::Status; + +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +#[multiversx_sc::module] +pub trait OwnerModule: crate::private::PrivateModule + crate::storage::StorageModule { + //u64 is percentage * 100 + //function called by the owner when the winners have been decided + #[only_owner] + #[endpoint(sendReward)] + fn send_reward( + &self, + game_id: u64, + winners: OptionalValue>, + ) { + self.require_enabled(); + + let game_settings = self.validate_send_reward(game_id); + let token_id = self.token_id().get(); + + match game_settings.status { + Status::Invalid => { + self.send_back_wager(game_id, &game_settings.wager, &token_id); + + let game_creation_fee = self.game_start_fee().get(); + self.send() + .direct(&game_settings.creator, &token_id, 0u64, &game_creation_fee); + } + Status::Valid => { + match winners { + OptionalValue::Some(val) => { + let len = self.players(game_id).len(); + let total_wager = &BigUint::from(len) * &game_settings.wager; + + for (winner, percentage) in val.into_iter() { + let reward_per_winner = + &BigUint::from(percentage) * &total_wager / &BigUint::from(100u64); + self.send() + .direct(&winner, &token_id, 0u64, &reward_per_winner); + } + } + //tie/draw + OptionalValue::None => { + self.send_back_wager(game_id, &game_settings.wager, &token_id); + } + } + } + } + } + + #[only_owner] + #[endpoint(enableSC)] + fn enable_sc(&self) { + self.enabled().set(true) + } + + #[only_owner] + #[endpoint(disableSC)] + fn disable_sc(&self) { + self.enabled().clear() + } + + #[only_owner] + #[endpoint(setTokenId)] + fn set_token_id(&self, token_id: EgldOrEsdtTokenIdentifier) { + self.token_id().set(token_id) + } + + #[only_owner] + #[endpoint(setGameStartFee)] + fn set_game_start_fee(&self, amount: BigUint) { + self.game_start_fee().set(amount) + } +} diff --git a/contracts/mvx-game-sc/src/private.rs b/contracts/mvx-game-sc/src/private.rs new file mode 100644 index 00000000..3edce017 --- /dev/null +++ b/contracts/mvx-game-sc/src/private.rs @@ -0,0 +1,175 @@ +use crate::types::{GameSettings, Status}; + +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +#[multiversx_sc::module] +pub trait PrivateModule: crate::storage::StorageModule { + //game + fn create_new_game( + &self, + caller: ManagedAddress, + waiting_time: u64, + min: u64, + max: u64, + wager: BigUint, + ) { + let new_id = self.get_new_game_id(); + self.last_game_id().set(new_id); + let now = self.blockchain().get_block_timestamp(); + + let time_limit = now + waiting_time; + let game_settings = GameSettings { + time_limit, + number_of_players_min: min, + number_of_players_max: max, + wager, + creator: caller, + status: Status::Invalid, + }; + self.game_settings(new_id).set(game_settings); + } + + fn add_player(&self, caller: ManagedAddress, game_id: u64) { + self.games_per_user(&caller).insert(game_id); + self.players(game_id).insert(caller); + } + + fn remove_player(&self, caller: ManagedAddress, game_id: u64) { + self.games_per_user(&caller).swap_remove(&game_id); + self.players(game_id).swap_remove(&caller); + } + + fn refresh_game_status(&self, game_id: u64, game_settings: GameSettings) { + let len = self.players(game_id).len() as u64; + if game_settings.number_of_players_min <= len { + self.game_settings(game_id) + .update(|val| val.status = Status::Valid); + } + } + + fn send_back_wager(&self, game_id: u64, wager: &BigUint, token_id: &EgldOrEsdtTokenIdentifier) { + for player in self.players(game_id).iter() { + self.send().direct(&player, token_id, 0u64, wager); + } + } + + //requires + fn validate_create_game_payment( + &self, + token_id: &TokenIdentifier, + amount: &BigUint, + wager: &BigUint, + waiting_time: u64, + ) { + require!(wager > &BigUint::zero(), "wager can't be 0"); + require!(waiting_time > 0u64, "waiting time can't be 0"); + + let approved_token_id = self.token_id().get(); + let start_fee = self.game_start_fee().get(); + + require!(token_id == &approved_token_id, "wrong token id"); + require!(amount == &start_fee, "start game payment amount not right"); + } + + fn validate_join_game( + &self, + caller: &ManagedAddress, + now: u64, + token_id: &TokenIdentifier, + amount: &BigUint, + game_id: u64, + ) -> GameSettings { + require!( + !self.game_settings(game_id).is_empty(), + "no settings for game id" + ); + let game_settings = self.game_settings(game_id).get(); + let accepted_token_id = self.token_id().get(); + + require!( + !self.games_per_user(caller).contains(&game_id), + "user already joined this game" + ); + + require!(now <= game_settings.time_limit, "waiting time has passed"); + + let len = self.players(game_id).len() as u64; + require!( + len < game_settings.number_of_players_max, + "max number of players reached" + ); + + require!(token_id == &accepted_token_id, "wrong token sent"); + require!(amount == &game_settings.wager, "wrong amount paid"); + + game_settings + } + + fn validate_claim_wager(&self, caller: &ManagedAddress, game_id: u64) -> BigUint { + require!( + !self.game_settings(game_id).is_empty(), + "no settings for game id" + ); + + require!( + self.games_per_user(caller).contains(&game_id), + "caller has not joined the game" + ); + + let game_settings = self.game_settings(game_id).get(); + let now = self.blockchain().get_block_timestamp(); + + require!( + now > game_settings.time_limit, + "waiting time is not over yet" + ); + + require!( + game_settings.status == Status::Invalid, + "can manually claim back wager only if the game is invalid" + ); + + game_settings.wager + } + + fn validate_send_reward(&self, game_id: u64) -> GameSettings { + require!( + !self.game_settings(game_id).is_empty(), + "no settings for game id" + ); + + let game_settings = self.game_settings(game_id).get(); + let now = self.blockchain().get_block_timestamp(); + + require!( + now > game_settings.time_limit, + "waiting time is not over yet" + ); + + game_settings + } + + fn require_enabled(&self) { + require!(!self.enabled().is_empty(), "maintenance") + } + + //helper + fn get_new_game_id(&self) -> u64 { + if self.last_game_id().is_empty() { + return 1u64; + } + let last_id = self.last_game_id().get(); + last_id + 1u64 + } + + fn get_min_max(&self, a: u64, b: u64) -> (u64, u64) { + require!(a != 0u64 && b != 0u64, "number of players cannot be 0"); + + if a > b { + return (b, a); + } + + (a, b) + } +} diff --git a/contracts/mvx-game-sc/src/storage.rs b/contracts/mvx-game-sc/src/storage.rs new file mode 100644 index 00000000..35383377 --- /dev/null +++ b/contracts/mvx-game-sc/src/storage.rs @@ -0,0 +1,38 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +use crate::types::GameSettings; + +#[multiversx_sc::module] +pub trait StorageModule { + //GENERAL SETTINGS + #[view(getTokenId)] + #[storage_mapper("tokenId")] + fn token_id(&self) -> SingleValueMapper; + + #[view(getGameStartFee)] + #[storage_mapper("gameStartFee")] + fn game_start_fee(&self) -> SingleValueMapper; + + #[view(getEnabled)] + #[storage_mapper("enabled")] + fn enabled(&self) -> SingleValueMapper; + + //GAME + #[view(getLastGameId)] + #[storage_mapper("lastGameId")] + fn last_game_id(&self) -> SingleValueMapper; + + #[view(getGameSettings)] + #[storage_mapper("gameSettings")] + fn game_settings(&self, game_id: u64) -> SingleValueMapper>; + + #[view(getPlayers)] + #[storage_mapper("players")] + fn players(&self, game_id: u64) -> UnorderedSetMapper; + + //USERS + #[view(getGamesPerUser)] + #[storage_mapper("gamesPerUser")] + fn games_per_user(&self, user: &ManagedAddress) -> UnorderedSetMapper; +} diff --git a/contracts/mvx-game-sc/src/types.rs b/contracts/mvx-game-sc/src/types.rs new file mode 100644 index 00000000..e4e61392 --- /dev/null +++ b/contracts/mvx-game-sc/src/types.rs @@ -0,0 +1,39 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + + +#[derive( + TopEncode, + TopDecode, + TypeAbi, + NestedEncode, + NestedDecode, + Clone, + ManagedVecItem, + Debug, + PartialEq, +)] +pub enum Status { + Valid, + Invalid, +} + +#[derive( + TopEncode, + TopDecode, + TypeAbi, + NestedEncode, + NestedDecode, + Clone, + ManagedVecItem, + Debug, + PartialEq, +)] +pub struct GameSettings { + pub time_limit: u64, //start_time + waiting time + pub number_of_players_min: u64, //min and max + pub number_of_players_max: u64, + pub wager: BigUint, + pub creator: ManagedAddress, + pub status: Status +} diff --git a/contracts/mvx-game-sc/tests/game_sc_blackbox_tests.rs b/contracts/mvx-game-sc/tests/game_sc_blackbox_tests.rs new file mode 100644 index 00000000..41c0b50e --- /dev/null +++ b/contracts/mvx-game-sc/tests/game_sc_blackbox_tests.rs @@ -0,0 +1,207 @@ +use multiversx_sc::{ + codec::multi_types::OptionalValue, + storage::mappers::SingleValue, + types::{EgldOrEsdtTokenIdentifier, TokenIdentifier}, +}; +use multiversx_sc_scenario::{api::StaticApi, num_bigint::BigUint, scenario_model::*, *}; +use mvx_game_sc::{ + storage::ProxyTrait, + types::{GameSettings, Status}, + ProxyTrait as _, +}; + +const GAME_SC_PATH: &str = "file:output/mvx-game-sc.wasm"; +const BALANCE: u64 = 100_000_000u64; +const TOKEN_ID: &str = "str:GAME-123456"; +const TOKEN_ID_BY: &[u8] = b"GAME-123456"; +const STARTING_FEE: u64 = 20u64; +const USER1_ADDR: &str = "address:user1"; +const USER2_ADDR: &str = "address:user2"; +const OWNER_ADDR: &str = "address:owner"; +const GAME_SC_ADDR: &str = "sc:mvx_game_sc"; + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + blockchain.set_current_dir_from_workspace("contracts/mvx-game-sc"); + + blockchain.register_contract(GAME_SC_PATH, mvx_game_sc::ContractBuilder); + blockchain +} + +struct GameContractState { + world: ScenarioWorld, + user1: AddressValue, + user2: AddressValue, + owner: AddressValue, +} + +impl GameContractState { + fn new() -> Self { + let mut world = world(); + world.start_trace().set_state_step( + SetStateStep::new() + .put_account( + OWNER_ADDR, + Account::new() + .nonce(1) + .balance(BALANCE) + .esdt_balance(TOKEN_ID, BALANCE), + ) + .put_account( + USER1_ADDR, + Account::new() + .nonce(2) + .balance(BALANCE) + .esdt_balance(TOKEN_ID, BALANCE), + ) + .put_account( + USER2_ADDR, + Account::new() + .nonce(3) + .balance(BALANCE) + .esdt_balance(TOKEN_ID, BALANCE), + ), + ); + + let user1 = AddressValue::from(USER1_ADDR); + let user2 = AddressValue::from(USER2_ADDR); + let owner = AddressValue::from(OWNER_ADDR); + + Self { + world, + user1, + user2, + owner, + } + } + + fn deploy(&mut self, game_sc: &mut ContractInfo>) -> &mut Self { + let game_sc_code = self.world.code_expression(GAME_SC_PATH); + + self.world + .set_state_step(SetStateStep::new().new_address(OWNER_ADDR, 1, GAME_SC_ADDR)) + .sc_deploy( + ScDeployStep::new() + .from(OWNER_ADDR) + .code(game_sc_code) + .call(game_sc.init( + OptionalValue::Some(true), + OptionalValue::Some(BigUint::from(STARTING_FEE)), + OptionalValue::Some(EgldOrEsdtTokenIdentifier::esdt( + TokenIdentifier::from(TOKEN_ID_BY), + )), + )) + .expect(TxExpect::ok().no_result()), + ); + + self + } + + fn create_game( + &mut self, + waiting_time: u64, + number_of_players_min: u64, + number_of_players_max: u64, + wager: BigUint, + caller: &str, + game_sc: &mut ContractInfo>, + ) -> &mut Self { + self.world.sc_call( + ScCallStep::new() + .from(caller) + .to(GAME_SC_ADDR) + .esdt_transfer(TOKEN_ID, 0u64, BigUint::from(STARTING_FEE)) + .call(game_sc.create_game( + waiting_time, + number_of_players_min, + number_of_players_max, + wager, + )) + .expect(TxExpect::ok().no_result()), + ); + + self + } + + fn join_game( + &mut self, + game_id: u64, + caller: &str, + amount: &BigUint, + game_sc: &mut ContractInfo>, + ) -> &mut Self { + self.world.sc_call( + ScCallStep::new() + .from(caller) + .to(GAME_SC_ADDR) + .esdt_transfer(TOKEN_ID, 0u64, amount) + .call(game_sc.join_game(game_id)) + .expect(TxExpect::ok().no_result()), + ); + self + } +} + +#[test] +fn game_sc_deploy_test() { + let mut state = GameContractState::new(); + let mut game_sc = ContractInfo::>::new(GAME_SC_ADDR); + + state.deploy(&mut game_sc); +} + +#[test] +fn game_sc_simple_game_flow() { + let mut state = GameContractState::new(); + let mut game_sc = ContractInfo::>::new(GAME_SC_ADDR); + + let waiting_time = 100u64; + let number_of_players_min = 1u64; + let number_of_players_max = 4u64; + let wager = BigUint::from(100u64); + let _ = state.user1; + let _ = state.user2; + let _ = state.owner; + + //deploy + state.deploy(&mut game_sc); + + //check last game id before creation + state.world.sc_query( + ScQueryStep::new() + .to(GAME_SC_ADDR) + .function("getLastGameId") + .expect(TxExpect::ok().result("")), + ); + + //create first game + state.create_game( + waiting_time, + number_of_players_min, + number_of_players_max, + wager.clone(), + OWNER_ADDR, + &mut game_sc, + ); + + //check last game id, needs to be 1 + state.world.sc_query( + ScQueryStep::new() + .to(GAME_SC_ADDR) + .function("getLastGameId") + .expect(TxExpect::ok().result("1")), + ); + + //user1 tries to join the game, timestamp is ok, max players not reached, should work + state.join_game(1u64, USER1_ADDR, &wager, &mut game_sc); + + //min number of players reached, game should be valid + let game_settings: SingleValue> = game_sc + .game_settings(1u64) + .into_vm_query() + .expect(TxExpect::ok()) + .execute(&mut state.world); + + assert_eq!(game_settings.into().status, Status::Valid); +} + diff --git a/contracts/mvx-game-sc/wasm/Cargo.lock b/contracts/mvx-game-sc/wasm/Cargo.lock new file mode 100644 index 00000000..abc2a424 --- /dev/null +++ b/contracts/mvx-game-sc/wasm/Cargo.lock @@ -0,0 +1,219 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "multiversx-sc" +version = "0.43.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "406939660d0c79dd191c6677f4b048df873a95f4531d8abafc9cdbe282bf1725" +dependencies = [ + "bitflags", + "hashbrown", + "hex-literal", + "multiversx-sc-codec", + "multiversx-sc-derive", + "num-traits", +] + +[[package]] +name = "multiversx-sc-codec" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1e15b46c17b87c0c7cdd79b041a4abd7f3a2b45f3c993f6ce38c0f233e82b6" +dependencies = [ + "arrayvec", + "multiversx-sc-codec-derive", +] + +[[package]] +name = "multiversx-sc-codec-derive" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a7bc0762cd6d88f8bc54805bc652b042a61cd7fbc2d0a325010f088b78fb2ac" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "multiversx-sc-derive" +version = "0.43.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e006240993963b482fe0682ae49b2d07255495e3c86706925d119137376cdfc" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "radix_trie", + "syn", +] + +[[package]] +name = "multiversx-sc-wasm-adapter" +version = "0.43.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40e721d1bc80de2ede4099a9040519486c3c1139cb0287d8fc4f9fc3e8a3f19e" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "mvx-game-sc" +version = "0.0.0" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "mvx-game-sc-wasm" +version = "0.0.0" +dependencies = [ + "multiversx-sc-wasm-adapter", + "mvx-game-sc", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "proc-macro2" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "smallvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" diff --git a/contracts/mvx-game-sc/wasm/Cargo.toml b/contracts/mvx-game-sc/wasm/Cargo.toml new file mode 100644 index 00000000..bc6eb69b --- /dev/null +++ b/contracts/mvx-game-sc/wasm/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "mvx-game-sc-wasm" +version = "0.0.0" +authors = [ "you",] +edition = "2018" +publish = false + +[lib] +crate-type = [ "cdylib",] + +[workspace] +members = [ ".",] + +[dev-dependencies] + +[profile.release] +codegen-units = 1 +opt-level = "z" +lto = true +debug = false +panic = "abort" + +[dependencies.mvx-game-sc] +path = ".." + +[dependencies.multiversx-sc-wasm-adapter] +version = "0.43.4" diff --git a/contracts/mvx-game-sc/wasm/src/lib.rs b/contracts/mvx-game-sc/wasm/src/lib.rs new file mode 100644 index 00000000..23cdd65d --- /dev/null +++ b/contracts/mvx-game-sc/wasm/src/lib.rs @@ -0,0 +1,43 @@ +// Code generated by the multiversx-sc multi-contract system. DO NOT EDIT. + +//////////////////////////////////////////////////// +////////////////// AUTO-GENERATED ////////////////// +//////////////////////////////////////////////////// + +// Init: 1 +// Endpoints: 15 +// Async Callback (empty): 1 +// Total number of exported functions: 17 + +#![no_std] + +// Configuration that works with rustc < 1.73.0. +// TODO: Recommended rustc version: 1.73.0 or newer. +#![feature(lang_items)] + +multiversx_sc_wasm_adapter::allocator!(); +multiversx_sc_wasm_adapter::panic_handler!(); + +multiversx_sc_wasm_adapter::endpoints! { + mvx_game_sc + ( + init => init + createGame => create_game + joinGame => join_game + claimBackWager => claim_back_wager + getTokenId => token_id + getGameStartFee => game_start_fee + getEnabled => enabled + getLastGameId => last_game_id + getGameSettings => game_settings + getPlayers => players + getGamesPerUser => games_per_user + sendReward => send_reward + enableSC => enable_sc + disableSC => disable_sc + setTokenId => set_token_id + setGameStartFee => set_game_start_fee + ) +} + +multiversx_sc_wasm_adapter::async_callback_empty! {}