diff --git a/contracts/car-races-old/README.md b/contracts/car-races-old/README.md deleted file mode 100644 index aa0787c22..000000000 --- a/contracts/car-races-old/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Car Races - -This project is a competitive environment where strategy-based programs race against each other, aiming to optimize speed, tactics, and resource management on the track. Each program operates autonomously, employing unique strategies to outmaneuver opponents and complete the race as efficiently as possible. - -A detailed description of the project can be found on the [wiki](https://wiki.vara.network/docs/examples/Gaming/racingcars). - -⚙️ **Note**: The project code is developed using the [Sails](https://github.com/gear-tech/sails) framework. - -### 🏗️ Building - -```sh -cargo b -r -p "car-races" -``` - -### ✅ Testing - -```sh -cargo t -r -p "car-races-app" -``` diff --git a/contracts/car-races-old/app/Cargo.toml b/contracts/car-races-old/app/Cargo.toml deleted file mode 100644 index e396c23fb..000000000 --- a/contracts/car-races-old/app/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "car-races-app" -version.workspace = true -edition.workspace = true - -[dependencies] -sails-rs.workspace = true -parity-scale-codec.workspace = true -scale-info.workspace = true -gstd.workspace = true -session-service.workspace = true - -[build-dependencies] -sails-client-gen.workspace = true - -[dev-dependencies] -gtest.workspace = true diff --git a/contracts/car-races-old/app/src/lib.rs b/contracts/car-races-old/app/src/lib.rs deleted file mode 100644 index cf93dab1b..000000000 --- a/contracts/car-races-old/app/src/lib.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![no_std] - -use sails_rs::prelude::*; -pub mod services; -use services::{ - session::{Config, SessionService}, - CarRacesService, InitConfig, -}; - -use session_service::*; - -#[derive(Default)] -pub struct Program; - -#[program] -impl Program { - pub async fn new( - init_config: InitConfig, - session_config: Config, - dns_id_and_name: Option<(ActorId, String)>, - ) -> Self { - CarRacesService::init(init_config, dns_id_and_name).await; - SessionService::init(session_config); - Self - } - - pub fn car_races_service(&self) -> CarRacesService { - CarRacesService::new() - } - - pub fn session(&self) -> SessionService { - SessionService::new() - } -} diff --git a/contracts/car-races-old/app/src/services/error.rs b/contracts/car-races-old/app/src/services/error.rs deleted file mode 100644 index db095e1b5..000000000 --- a/contracts/car-races-old/app/src/services/error.rs +++ /dev/null @@ -1,15 +0,0 @@ -use sails_rs::prelude::*; - -#[derive(Debug, Encode, Decode, TypeInfo, Clone, PartialEq, Eq)] -pub enum Error { - MessageProcessingSuspended, - MustBeTwoStrategies, - NotAdmin, - NoMessagesForApproval, - NoSession, - GameAlreadyStarted, - DurationTooSmall, - NotPlayerTurn, - NotProgram, - UnexpectedState, -} diff --git a/contracts/car-races-old/app/src/services/game.rs b/contracts/car-races-old/app/src/services/game.rs deleted file mode 100644 index 84499fc05..000000000 --- a/contracts/car-races-old/app/src/services/game.rs +++ /dev/null @@ -1,247 +0,0 @@ -use super::{config, Error}; -use sails_rs::{collections::BTreeMap, prelude::*}; - -pub const DEFAULT_SPEED: u32 = 100; - -#[derive(Encode, Decode, TypeInfo, Clone, Debug)] -pub struct Car { - pub position: u32, - pub speed: u32, - pub car_actions: Vec, - pub round_result: Option, -} - -#[derive(Encode, Decode, TypeInfo, Default, PartialEq, Eq, Debug, Clone)] -pub enum GameState { - #[default] - ReadyToStart, - Race, - Stopped, - Finished, - PlayerAction, -} - -#[derive(Encode, Decode, TypeInfo, Default, Clone, Debug)] -pub struct Game { - pub cars: BTreeMap, - pub car_ids: Vec, - pub current_turn: u8, - pub state: GameState, - pub result: Option, - pub current_round: u32, - pub last_time_step: u64, -} - -#[derive(Encode, Decode, TypeInfo, Clone, Debug)] -pub enum GameResult { - Win, - Draw, - Lose, -} - -#[derive(Encode, Decode, TypeInfo, Debug)] -pub enum StrategyAction { - BuyAcceleration, - BuyShell, - Skip, -} - -#[derive(Encode, Decode, TypeInfo, Debug, Clone, PartialEq, Eq)] -pub enum RoundAction { - Accelerated, - SlowedDown, - SlowedDownAndAccelerated, -} - -#[derive(Encode, Decode, TypeInfo)] -pub enum CarAction { - YourTurn(BTreeMap), -} - -#[derive(Debug, Clone, Encode, Decode, TypeInfo)] -pub enum GameError { - NotAdmin, - MustBeTwoStrategies, - GameAlreadyStarted, - NotPlayerTurn, - NotProgram, - MessageProcessingSuspended, -} - -impl Game { - pub async fn process_car_turn(&mut self) -> Result<(), Error> { - let car_id = self.get_current_car_id(); - - let payload_bytes = [ - "CarStrategy".encode(), - "MakeMove".encode(), - self.cars.clone().encode(), - ] - .concat(); - - let bytes = gstd::msg::send_bytes_with_gas_for_reply( - car_id, - payload_bytes, - config().gas_for_round, - 0, - config().gas_for_reply_deposit, - ) - .expect("Error in sending a message") - .await - .expect("Error in receiving reply"); - - if let Ok((_, _, strategy_action)) = - <(String, String, StrategyAction)>::decode(&mut bytes.as_ref()) - { - self.apply_strategy_move(strategy_action); - } else { - // car eliminated from race for wrong payload - self.car_ids.retain(|id| *id != car_id); - } - - let num_of_cars = self.car_ids.len() as u8; - self.current_turn = (self.current_turn + 1) % num_of_cars; - - Ok(()) - } - - pub fn apply_strategy_move(&mut self, strategy_move: StrategyAction) { - match strategy_move { - StrategyAction::BuyAcceleration => { - self.buy_acceleration(); - } - StrategyAction::BuyShell => { - self.buy_shell(); - } - StrategyAction::Skip => {} - } - } - - pub fn buy_acceleration(&mut self) { - let car_id = self.get_current_car_id(); - let car = self.cars.get_mut(&car_id).expect("Get Car: Can't be None"); - car.speed = car.speed.saturating_add(DEFAULT_SPEED); - car.car_actions.push(RoundAction::Accelerated); - } - - pub fn buy_shell(&mut self) { - let car_id = self.get_current_car_id(); - - let shelled_car_id = self.find_car_to_shell(&car_id); - self.cars.entry(shelled_car_id).and_modify(|car| { - let new_speed = car.speed.saturating_sub(DEFAULT_SPEED); - car.speed = new_speed.max(DEFAULT_SPEED); - car.car_actions.push(RoundAction::SlowedDown); - }); - } - - pub fn get_current_car_id(&self) -> ActorId { - self.car_ids[self.current_turn as usize] - } - - pub fn update_positions(&mut self) { - let mut winners = Vec::with_capacity(3); - for (car_id, car) in self.cars.iter_mut() { - car.position = car.position.saturating_add(car.speed * config().time); - if car.position >= config().max_distance { - self.state = GameState::Finished; - winners.push((*car_id, car.position)); - } - - if !car.car_actions.is_empty() { - car.round_result = if car.car_actions.contains(&RoundAction::Accelerated) - && car.car_actions.contains(&RoundAction::SlowedDown) - { - Some(RoundAction::SlowedDownAndAccelerated) - } else if car.car_actions.contains(&RoundAction::Accelerated) { - Some(RoundAction::Accelerated) - } else { - Some(RoundAction::SlowedDown) - }; - car.car_actions = Vec::new(); - } else { - car.round_result = None; - } - } - winners.sort_by(|a, b| b.1.cmp(&a.1)); - if self.state == GameState::Finished { - match winners.len() { - 1 => { - if winners[0].0 == self.car_ids[0] { - self.result = Some(GameResult::Win); - } else { - self.result = Some(GameResult::Lose); - } - } - 2 => { - if winners[0].0 == self.car_ids[0] || winners[1].0 == self.car_ids[0] { - if winners[0].1 == winners[1].1 { - self.result = Some(GameResult::Draw); - } else if winners[0].0 == self.car_ids[0] { - self.result = Some(GameResult::Win); - } else { - self.result = Some(GameResult::Lose); - } - } else { - self.result = Some(GameResult::Lose); - } - } - 3 => { - if winners[0].1 == winners[1].1 && winners[0].1 == winners[2].1 { - self.result = Some(GameResult::Draw); - } else if winners[0].1 == winners[1].1 { - if winners[0].0 == self.car_ids[0] || winners[1].0 == self.car_ids[0] { - self.result = Some(GameResult::Draw); - } else { - self.result = Some(GameResult::Lose); - } - } else if winners[0].0 == self.car_ids[0] { - self.result = Some(GameResult::Win); - } else { - self.result = Some(GameResult::Lose); - } - } - _ => { - unreachable!(); - } - } - } - } - - fn find_car_to_shell(&self, car_id: &ActorId) -> ActorId { - let mut cars_vec: Vec<(ActorId, Car)> = self - .cars - .iter() - .map(|(car_id, car)| (*car_id, car.clone())) - .collect(); - cars_vec.sort_by(|a, b| b.1.position.cmp(&a.1.position)); - - // if the car is the first - // then we slowed the car that is behind it - if cars_vec[0].0 == *car_id { - return cars_vec[1].0; - } - - // if the car is the second or the last - // then we slowed the first car - cars_vec[0].0 - } - - pub fn verify_game_state(&mut self) -> Result<(), Error> { - if self.state != GameState::PlayerAction { - Err(Error::NotPlayerTurn) - } else { - Ok(()) - } - } - - pub fn is_player_action_or_finished(&self) -> bool { - self.state == GameState::PlayerAction || self.state == GameState::Finished - } -} - -#[derive(Debug, Default, Encode, Decode, TypeInfo, Clone)] -pub struct RoundInfo { - pub cars: Vec<(ActorId, u32, Option)>, - pub result: Option, -} diff --git a/contracts/car-races-old/app/src/services/mod.rs b/contracts/car-races-old/app/src/services/mod.rs deleted file mode 100644 index 645fd42e9..000000000 --- a/contracts/car-races-old/app/src/services/mod.rs +++ /dev/null @@ -1,388 +0,0 @@ -#![allow(clippy::new_without_default)] -#![allow(static_mut_refs)] -use collections::HashMap; -use sails_rs::prelude::*; -use session::{ActionsForSession, SessionData, Storage as SessionStorage}; -pub mod error; -pub mod game; -pub mod session; -pub mod utils; -use crate::services::utils::{panic, panicking}; -use error::Error; -use game::*; -pub struct CarRacesService; - -use gstd::{exec, msg}; -static mut DATA: Option = None; -static mut CONFIG: Option = None; - -#[derive(Debug, Default)] -pub struct ContractData { - admins: Vec, - strategy_ids: Vec, - games: HashMap, - messages_allowed: bool, - dns_info: Option<(ActorId, String)>, -} - -#[derive(Debug, Decode, Encode, TypeInfo)] -pub struct InitConfig { - pub config: Config, -} - -#[derive(Debug, Decode, Encode, TypeInfo, Clone)] -pub struct Config { - pub gas_to_remove_game: u64, - pub initial_speed: u32, - pub min_speed: u32, - pub max_speed: u32, - pub gas_for_round: u64, - pub time_interval: u32, - pub max_distance: u32, - pub time: u32, - pub time_for_game_storage: u64, - pub block_duration_ms: u64, - pub gas_for_reply_deposit: u64, -} - -#[derive(Debug, Decode, Encode, TypeInfo)] -pub enum Event { - RoundInfo(RoundInfo), - GameFinished { player: ActorId }, - Killed { inheritor: ActorId }, -} -#[service(events = Event)] -impl CarRacesService { - pub fn allow_messages(&mut self, messages_allowed: bool) { - let msg_src = msg::source(); - assert!(self.data().admins.contains(&msg_src), "Not admin"); - self.data_mut().messages_allowed = messages_allowed; - } - - pub async fn kill(&mut self, inheritor: ActorId) { - let msg_src = msg::source(); - assert!(self.data().admins.contains(&msg_src), "Not admin"); - - if let Some((id, _name)) = &self.data().dns_info { - let request = ["Dns".encode(), "DeleteMe".to_string().encode(), ().encode()].concat(); - - msg::send_bytes_with_gas_for_reply(*id, request, 5_000_000_000, 0, 0) - .expect("Error in sending message") - .await - .expect("Error in `AddNewProgram`"); - } - - self.notify_on(Event::Killed { inheritor }) - .expect("Notification Error"); - exec::exit(inheritor); - } - - pub fn add_strategy_ids(&mut self, car_ids: Vec) { - let msg_src = msg::source(); - assert!(self.data().messages_allowed, "Message processing suspended"); - assert!(self.data().admins.contains(&msg_src), "Not admin"); - assert_eq!(car_ids.len(), 2, "Must be two strategies"); - self.data_mut().strategy_ids = car_ids; - } - - pub fn start_game(&mut self, session_for_account: Option) { - assert!(self.data().messages_allowed, "Message processing suspended"); - let msg_src = msg::source(); - let sessions = SessionStorage::get_session_map(); - let player = get_player( - sessions, - &msg_src, - &session_for_account, - ActionsForSession::StartGame, - ); - let last_time_step = exec::block_timestamp(); - let strategy_ids = self.data().strategy_ids.clone(); - - let game = if let Some(game) = self.data_mut().games.get_mut(&player) { - assert!(game.state == GameState::Finished, "Game already started"); - game.current_round = 0; - game.result = None; - game.last_time_step = last_time_step; - game - } else { - self.data_mut().games.entry(player).or_insert_with(|| Game { - last_time_step, - ..Default::default() - }) - }; - - game.car_ids = vec![player, strategy_ids[0], strategy_ids[1]]; - let initial_state = Car { - position: 0, - speed: config().initial_speed, - car_actions: Vec::new(), - round_result: None, - }; - - game.cars.insert(player, initial_state.clone()); - game.cars.insert(strategy_ids[0], initial_state.clone()); - game.cars.insert(strategy_ids[1], initial_state); - - game.state = GameState::PlayerAction; - } - - pub async fn player_move( - &mut self, - strategy_move: StrategyAction, - session_for_account: Option, - ) { - assert!(self.data().messages_allowed, "Message processing suspended"); - let msg_src = msg::source(); - let sessions = SessionStorage::get_session_map(); - - let player = get_player( - sessions, - &msg_src, - &session_for_account, - ActionsForSession::Move, - ); - let game_instance = self.get_game(&player); - - panicking(game_instance.verify_game_state()); - - game_instance.apply_strategy_move(strategy_move); - - game_instance.state = GameState::Race; - game_instance.last_time_step = exec::block_timestamp(); - - let num_of_cars = game_instance.car_ids.len() as u8; - - game_instance.current_turn = (game_instance.current_turn + 1) % num_of_cars; - - let mut round_info: Option = None; - let mut game_finished = false; - while !game_instance.is_player_action_or_finished() { - panicking(game_instance.process_car_turn().await); - if game_instance.current_turn == 0 { - game_instance.state = GameState::PlayerAction; - game_instance.current_round = game_instance.current_round.saturating_add(1); - - game_instance.update_positions(); - - round_info = Some(create_round_info(game_instance)); - - if game_instance.state == GameState::Finished { - send_msg_to_remove_game_instance(player); - game_finished = true; - } - } - } - - match round_info { - Some(info) => { - self.notify_on(Event::RoundInfo(info)) - .expect("Notification Error"); - if game_finished { - self.notify_on(Event::GameFinished { player: msg_src }) - .expect("Notification Error"); - } - } - None => { - panic(Error::UnexpectedState); - } - } - } - - pub fn remove_game_instance(&mut self, account: ActorId) { - assert_eq!(msg::source(), exec::program_id(), "Not program"); - - let game = self - .data() - .games - .get(&account) - .expect("Unexpected: the game does not exist"); - - if game.state == GameState::Finished { - self.data_mut().games.remove(&account); - }; - } - - pub fn remove_instances(&mut self, player_ids: Option>) { - let msg_src = msg::source(); - assert!(self.data().admins.contains(&msg_src), "Not admin"); - match player_ids { - Some(player_ids) => { - for player_id in player_ids { - self.data_mut().games.remove(&player_id); - } - } - None => { - self.data_mut().games.retain(|_, game| { - (exec::block_timestamp() - game.last_time_step) < config().time_for_game_storage - }); - } - } - } - - pub fn add_admin(&mut self, admin: ActorId) { - let msg_src = msg::source(); - assert!(self.data().admins.contains(&msg_src), "Not admin"); - self.data_mut().admins.push(admin); - } - - pub fn remove_admin(&mut self, admin: ActorId) { - let msg_src = msg::source(); - assert!(self.data().admins.contains(&msg_src), "Not admin"); - self.data_mut().admins.retain(|id| *id != admin); - } - - pub fn update_config(&mut self, config: Config) { - let msg_src = msg::source(); - assert!(self.data().admins.contains(&msg_src), "Not admin"); - - unsafe { - CONFIG = Some(config); - } - } - - pub fn admins(&self) -> Vec { - self.data().admins.clone() - } - - pub fn strategy_ids(&self) -> Vec { - self.data().strategy_ids.clone() - } - - pub fn game(&self, account_id: ActorId) -> Option { - self.data().games.get(&account_id).cloned() - } - - pub fn all_games(&self) -> Vec<(ActorId, Game)> { - self.data().games.clone().into_iter().collect() - } - - pub fn config_state(&self) -> Config { - config().clone() - } - - pub fn messages_allowed(&self) -> bool { - self.data().messages_allowed - } - - fn get_game(&mut self, account: &ActorId) -> &mut Game { - self.data_mut() - .games - .get_mut(account) - .expect("Game does not exist") - } - - pub fn dns_info(&self) -> Option<(ActorId, String)> { - self.data().dns_info.clone() - } -} - -impl CarRacesService { - pub async fn init(config: InitConfig, dns_id_and_name: Option<(ActorId, String)>) { - unsafe { - DATA = Some(ContractData { - admins: vec![msg::source()], - games: HashMap::with_capacity(20_000), - dns_info: dns_id_and_name.clone(), - ..Default::default() - }); - CONFIG = Some(config.config); - } - if let Some((id, name)) = dns_id_and_name { - let request = [ - "Dns".encode(), - "AddNewProgram".to_string().encode(), - (name, exec::program_id()).encode(), - ] - .concat(); - - msg::send_bytes_with_gas_for_reply(id, request, 5_000_000_000, 0, 0) - .expect("Error in sending message") - .await - .expect("Error in `AddNewProgram`"); - } - } - pub fn new() -> Self { - Self - } - - fn data(&self) -> &ContractData { - unsafe { - DATA.as_ref() - .expect("CarRacesService::seed() should be called") - } - } - - fn data_mut(&mut self) -> &mut ContractData { - unsafe { - DATA.as_mut() - .expect("CarRacesService::seed() should be called") - } - } -} - -fn create_round_info(game: &Game) -> RoundInfo { - let mut cars = Vec::new(); - for (car_id, info) in game.cars.clone().iter() { - cars.push((*car_id, info.position, info.round_result.clone())); - } - RoundInfo { - cars, - result: game.result.clone(), - } -} - -fn send_msg_to_remove_game_instance(player: ActorId) { - let payload_bytes = [ - "CarRacesService".encode(), - "RemoveGameInstance".encode(), - player.encode(), - ] - .concat(); - - msg::send_bytes_with_gas_delayed( - exec::program_id(), - payload_bytes, - config().gas_to_remove_game, - 0, - config().time_interval, - ) - .expect("Error in sending message"); -} - -fn get_player( - session_map: &HashMap, - msg_source: &ActorId, - session_for_account: &Option, - actions_for_session: ActionsForSession, -) -> ActorId { - let player = match session_for_account { - Some(account) => { - let session = session_map - .get(account) - .expect("This account has no valid session"); - assert!( - session.expires > exec::block_timestamp(), - "The session has already expired" - ); - assert!( - session.allowed_actions.contains(&actions_for_session), - "This message is not allowed" - ); - assert_eq!( - session.key, *msg_source, - "The account is not approved for this session" - ); - *account - } - None => *msg_source, - }; - player -} - -pub fn config() -> &'static Config { - unsafe { - CONFIG - .as_ref() - .expect("CarRacesService::seed() should be called") - } -} diff --git a/contracts/car-races-old/app/src/services/session.rs b/contracts/car-races-old/app/src/services/session.rs deleted file mode 100644 index 6e3cd7cc4..000000000 --- a/contracts/car-races-old/app/src/services/session.rs +++ /dev/null @@ -1,11 +0,0 @@ -use sails_rs::prelude::*; -use session_service::*; - -#[derive(Debug, Clone, Encode, Decode, TypeInfo, PartialEq, Eq)] -pub enum ActionsForSession { - StartGame, - Move, - Skip, -} - -generate_session_system!(ActionsForSession); diff --git a/contracts/car-races-old/app/src/services/utils.rs b/contracts/car-races-old/app/src/services/utils.rs deleted file mode 100644 index 508bae6f5..000000000 --- a/contracts/car-races-old/app/src/services/utils.rs +++ /dev/null @@ -1,12 +0,0 @@ -use sails_rs::{fmt::Debug, format}; - -pub fn panicking(res: Result) -> T { - match res { - Ok(v) => v, - Err(e) => panic(e), - } -} - -pub fn panic(err: impl Debug) -> ! { - panic!("{}", &format!("{err:?}")) -} diff --git a/contracts/car-races-old/app/tests/test.rs b/contracts/car-races-old/app/tests/test.rs deleted file mode 100644 index 36f4f473a..000000000 --- a/contracts/car-races-old/app/tests/test.rs +++ /dev/null @@ -1,161 +0,0 @@ -use car_races_app::services::{ - game::{Game, GameState, StrategyAction}, - session::Config as SessionConfig, - Config, InitConfig, -}; -use gtest::{Program, System}; -use sails_rs::{prelude::*, ActorId}; -const PATH_TO_STRATEGIES: [&str; 2] = [ - "../../target/wasm32-unknown-unknown/release/car_strategy_1.opt.wasm", - "../../target/wasm32-unknown-unknown/release/car_strategy_2.opt.wasm", -]; - -const PATH_TO_CAR_RACES: &str = "../../target/wasm32-unknown-unknown/release/car_races.opt.wasm"; - -#[test] -fn test_car_races_without_session() { - let system = System::new(); - system.init_logger(); - system.mint_to(10, 100_000_000_000_000); - - // upload strategy 1 - let car_strategy_1 = Program::from_file(&system, PATH_TO_STRATEGIES[0]); - let payload = ["New".encode()].concat(); - let mid = car_strategy_1.send_bytes(10, payload); - let res = system.run_next_block(); - assert!(res.succeed.contains(&mid)); - - // upload strategy 2 - let car_strategy_2 = Program::from_file(&system, PATH_TO_STRATEGIES[1]); - let payload = ["New".encode()].concat(); - let mid = car_strategy_2.send_bytes(10, payload); - let res = system.run_next_block(); - assert!(res.succeed.contains(&mid)); - - // upload car races - let car_races = Program::from_file(&system, PATH_TO_CAR_RACES); - let init_config = InitConfig { - config: Config { - gas_to_remove_game: 20_000_000_000, - initial_speed: 100, - min_speed: 10, - max_speed: 2000, - gas_for_round: 100_000_000_000, - time_interval: 20, - max_distance: 3242, - time: 1, - time_for_game_storage: 200, - block_duration_ms: 3000, - gas_for_reply_deposit: 15_000_000_000, - }, - }; - let session_config = SessionConfig { - gas_to_delete_session: 10_000_000_000, - minimum_session_duration_ms: 180_000, - ms_per_block: 3_000, - }; - - let dns_id_and_name: Option<(ActorId, String)> = None; - let payload = [ - "New".encode(), - (init_config, session_config, dns_id_and_name).encode(), - ] - .concat(); - - let mid = car_races.send_bytes(10, payload); - let res = system.run_next_block(); - assert!(res.succeed.contains(&mid)); - - // allow messages - let payload = [ - "CarRacesService".encode(), - "AllowMessages".encode(), - true.encode(), - ] - .concat(); - let mid = car_races.send_bytes(10, payload); - let res = system.run_next_block(); - assert!(res.succeed.contains(&mid)); - - // add strategy ids - let payload = [ - "CarRacesService".encode(), - "AddStrategyIds".encode(), - vec![car_strategy_1.id(), car_strategy_2.id()].encode(), - ] - .concat(); - let mid = car_races.send_bytes(10, payload); - let res = system.run_next_block(); - assert!(res.succeed.contains(&mid)); - - // start game - let session_for_account: Option = None; - let payload = [ - "CarRacesService".encode(), - "StartGame".encode(), - session_for_account.encode(), - ] - .concat(); - let mid = car_races.send_bytes(10, payload); - let res = system.run_next_block(); - assert!(res.succeed.contains(&mid)); - - let mut game = if let Some(game) = get_game(&system, &car_races, 10.into()) { - game - } else { - std::panic!("Game does not exist") - }; - - while game.state != GameState::Finished { - // make move (always accelerate) - let session_for_account: Option = None; - let payload = [ - "CarRacesService".encode(), - "PlayerMove".encode(), - (StrategyAction::BuyAcceleration, session_for_account).encode(), - ] - .concat(); - - let mid = car_races.send_bytes(10, payload); - let res = system.run_next_block(); - assert!(res.succeed.contains(&mid)); - - game = if let Some(game) = get_game(&system, &car_races, 10.into()) { - game - } else { - std::panic!("Game does not exist") - }; - } - - // try to start game again - let payload = [ - "CarRacesService".encode(), - "StartGame".encode(), - session_for_account.encode(), - ] - .concat(); - let mid = car_races.send_bytes(10, payload); - let res = system.run_next_block(); - assert!(res.succeed.contains(&mid)); -} - -fn get_game(sys: &System, car_races: &Program<'_>, account: ActorId) -> Option { - let payload = [ - "CarRacesService".encode(), - "Game".encode(), - account.encode(), - ] - .concat(); - car_races.send_bytes(10, payload); - let result = sys.run_next_block(); - let log_entry = result - .log() - .iter() - .find(|log_entry| log_entry.destination() == 10.into()) - .expect("Unable to get reply"); - - let reply = <(String, String, Option)>::decode(&mut log_entry.payload()) - .expect("Unable to decode reply"); // Panic if decoding fails - - reply.2 -} diff --git a/contracts/car-races-old/car-1/Cargo.toml b/contracts/car-races-old/car-1/Cargo.toml deleted file mode 100644 index 4425edf56..000000000 --- a/contracts/car-races-old/car-1/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "car-strategy-1" -version = "0.1.0" -edition = "2021" - -[dependencies] -car-strategy-app-1 = { path = "app" } - -[build-dependencies] -car-strategy-app-1 = { path = "app" } -sails-rs.workspace = true -sails-idl-gen.workspace = true -gear-wasm-builder.workspace = true - -[dev-dependencies] -car-strategy-1 = { path = ".", features = ["wasm-binary"] } -sails-rs.workspace = true -tokio.workspace = true - -[features] -wasm-binary = [] diff --git a/contracts/car-races-old/car-1/README.md b/contracts/car-races-old/car-1/README.md deleted file mode 100644 index c0cfd5e7a..000000000 --- a/contracts/car-races-old/car-1/README.md +++ /dev/null @@ -1,9 +0,0 @@ -## The **car-strategy** program - -The program workspace includes the following packages: -- `car-strategy` is the package allowing to build WASM binary for the program and IDL file for it. - The package also includes integration tests for the program in the `tests` sub-folder -- `car-strategy-app` is the package containing business logic for the program represented by the `CarStrategyService` structure. -- `car-strategy-client` is the package containing the client for the program allowing to interact with it from another program, tests, or - off-chain client. - diff --git a/contracts/car-races-old/car-1/app/Cargo.toml b/contracts/car-races-old/car-1/app/Cargo.toml deleted file mode 100644 index 6285243fb..000000000 --- a/contracts/car-races-old/car-1/app/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "car-strategy-app-1" -version = "0.1.0" -edition = "2021" - -[dependencies] -sails-rs.workspace = true -parity-scale-codec.workspace = true -scale-info.workspace = true \ No newline at end of file diff --git a/contracts/car-races-old/car-1/app/src/lib.rs b/contracts/car-races-old/car-1/app/src/lib.rs deleted file mode 100644 index d9f191b33..000000000 --- a/contracts/car-races-old/car-1/app/src/lib.rs +++ /dev/null @@ -1,54 +0,0 @@ -#![no_std] -#![allow(clippy::new_without_default)] - -use sails_rs::{collections::BTreeMap, prelude::*}; -struct CarStrategyService(()); - -#[sails_rs::service] -impl CarStrategyService { - pub fn new() -> Self { - Self(()) - } - - // this car only accelerates - pub fn make_move(&mut self, _cars: BTreeMap) -> StrategyAction { - StrategyAction::BuyAcceleration - } -} - -pub struct CarStrategyProgram(()); - -#[sails_rs::program] -impl CarStrategyProgram { - // Program's constructor - pub fn new() -> Self { - Self(()) - } - - // Exposed service - pub fn car_strategy(&self) -> CarStrategyService { - CarStrategyService::new() - } -} - -#[derive(Encode, Decode, TypeInfo, Clone, Debug)] -pub struct Car { - pub position: u32, - pub speed: u32, - pub car_actions: Vec, - pub round_result: Option, -} - -#[derive(Encode, Decode, TypeInfo, Debug)] -pub enum StrategyAction { - BuyAcceleration, - BuyShell, - Skip, -} - -#[derive(Encode, Decode, TypeInfo, Debug, Clone, PartialEq, Eq)] -pub enum RoundAction { - Accelerated, - SlowedDown, - SlowedDownAndAccelerated, -} diff --git a/contracts/car-races-old/car-1/build.rs b/contracts/car-races-old/car-1/build.rs deleted file mode 100644 index b725efb6a..000000000 --- a/contracts/car-races-old/car-1/build.rs +++ /dev/null @@ -1,24 +0,0 @@ -use std::{ - env, - fs::File, - io::{BufRead, BufReader}, - path::PathBuf, -}; - -fn main() { - gear_wasm_builder::build(); - - if env::var("__GEAR_WASM_BUILDER_NO_BUILD").is_ok() { - return; - } - - let bin_path_file = File::open(".binpath").unwrap(); - let mut bin_path_reader = BufReader::new(bin_path_file); - let mut bin_path = String::new(); - bin_path_reader.read_line(&mut bin_path).unwrap(); - - let mut idl_path = PathBuf::from(bin_path); - idl_path.set_extension("idl"); - sails_idl_gen::generate_idl_to_file::(idl_path) - .unwrap(); -} diff --git a/contracts/car-races-old/car-1/src/lib.rs b/contracts/car-races-old/car-1/src/lib.rs deleted file mode 100644 index 4076eca4e..000000000 --- a/contracts/car-races-old/car-1/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![no_std] - -#[cfg(target_arch = "wasm32")] -pub use car_strategy_app_1::wasm::*; - -#[cfg(feature = "wasm-binary")] -#[cfg(not(target_arch = "wasm32"))] -pub use code::WASM_BINARY_OPT as WASM_BINARY; - -#[cfg(feature = "wasm-binary")] -#[cfg(not(target_arch = "wasm32"))] -mod code { - include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -} diff --git a/contracts/car-races-old/car-2/Cargo.toml b/contracts/car-races-old/car-2/Cargo.toml deleted file mode 100644 index 047b54660..000000000 --- a/contracts/car-races-old/car-2/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "car-strategy-2" -version = "0.1.0" -edition = "2021" - -[dependencies] -car-strategy-app-2 = { path = "app" } - -[build-dependencies] -car-strategy-app-2 = { path = "app" } -sails-rs.workspace = true -sails-idl-gen.workspace = true -gear-wasm-builder.workspace = true - -[dev-dependencies] -car-strategy-2 = { path = ".", features = ["wasm-binary"] } -sails-rs.workspace = true -tokio.workspace = true - -[features] -wasm-binary = [] diff --git a/contracts/car-races-old/car-2/README.md b/contracts/car-races-old/car-2/README.md deleted file mode 100644 index c0cfd5e7a..000000000 --- a/contracts/car-races-old/car-2/README.md +++ /dev/null @@ -1,9 +0,0 @@ -## The **car-strategy** program - -The program workspace includes the following packages: -- `car-strategy` is the package allowing to build WASM binary for the program and IDL file for it. - The package also includes integration tests for the program in the `tests` sub-folder -- `car-strategy-app` is the package containing business logic for the program represented by the `CarStrategyService` structure. -- `car-strategy-client` is the package containing the client for the program allowing to interact with it from another program, tests, or - off-chain client. - diff --git a/contracts/car-races-old/car-2/app/Cargo.toml b/contracts/car-races-old/car-2/app/Cargo.toml deleted file mode 100644 index 7eeeeb4f0..000000000 --- a/contracts/car-races-old/car-2/app/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "car-strategy-app-2" -version = "0.1.0" -edition = "2021" - -[dependencies] -sails-rs.workspace = true -gstd.workspace = true -parity-scale-codec.workspace = true -scale-info.workspace = true \ No newline at end of file diff --git a/contracts/car-races-old/car-2/app/src/lib.rs b/contracts/car-races-old/car-2/app/src/lib.rs deleted file mode 100644 index 8410d595b..000000000 --- a/contracts/car-races-old/car-2/app/src/lib.rs +++ /dev/null @@ -1,71 +0,0 @@ -#![no_std] -#![allow(clippy::new_without_default)] - -use sails_rs::{collections::BTreeMap, prelude::*}; -struct CarStrategyService(()); - -#[sails_rs::service] -impl CarStrategyService { - pub fn new() -> Self { - Self(()) - } - - pub fn make_move(&mut self, _cars: BTreeMap) -> StrategyAction { - let random_choice = get_random_value(10); - match random_choice { - 0..=2 => StrategyAction::BuyAcceleration, - 3..=9 => StrategyAction::BuyShell, - _ => { - unreachable!() - } - } - } -} - -static mut SEED: u8 = 0; - -pub fn get_random_value(range: u8) -> u8 { - let seed = unsafe { SEED }; - unsafe { SEED = SEED.wrapping_add(1) }; - let mut random_input: [u8; 32] = gstd::exec::program_id().into(); - random_input[0] = random_input[0].wrapping_add(seed); - let (random, _) = gstd::exec::random(random_input).expect("Error in getting random number"); - random[0] % range -} - -pub struct CarStrategyProgram(()); - -#[sails_rs::program] -impl CarStrategyProgram { - // Program's constructor - pub fn new() -> Self { - Self(()) - } - - // Exposed service - pub fn car_strategy(&self) -> CarStrategyService { - CarStrategyService::new() - } -} - -#[derive(Encode, Decode, TypeInfo, Clone, Debug)] -pub struct Car { - pub position: u32, - pub speed: u32, - pub car_actions: Vec, - pub round_result: Option, -} - -#[derive(Encode, Decode, TypeInfo, Debug)] -pub enum StrategyAction { - BuyAcceleration, - BuyShell, - Skip, -} - -#[derive(Encode, Decode, TypeInfo, Debug, Clone, PartialEq, Eq)] -pub enum RoundAction { - Accelerated, - SlowedDown, - SlowedDownAndAccelerated, -} diff --git a/contracts/car-races-old/car-2/build.rs b/contracts/car-races-old/car-2/build.rs deleted file mode 100644 index 8b209c368..000000000 --- a/contracts/car-races-old/car-2/build.rs +++ /dev/null @@ -1,24 +0,0 @@ -use std::{ - env, - fs::File, - io::{BufRead, BufReader}, - path::PathBuf, -}; - -fn main() { - gear_wasm_builder::build(); - - if env::var("__GEAR_WASM_BUILDER_NO_BUILD").is_ok() { - return; - } - - let bin_path_file = File::open(".binpath").unwrap(); - let mut bin_path_reader = BufReader::new(bin_path_file); - let mut bin_path = String::new(); - bin_path_reader.read_line(&mut bin_path).unwrap(); - - let mut idl_path = PathBuf::from(bin_path); - idl_path.set_extension("idl"); - sails_idl_gen::generate_idl_to_file::(idl_path) - .unwrap(); -} diff --git a/contracts/car-races-old/car-2/src/lib.rs b/contracts/car-races-old/car-2/src/lib.rs deleted file mode 100644 index 587c8998b..000000000 --- a/contracts/car-races-old/car-2/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![no_std] - -#[cfg(target_arch = "wasm32")] -pub use car_strategy_app_2::wasm::*; - -#[cfg(feature = "wasm-binary")] -#[cfg(not(target_arch = "wasm32"))] -pub use code::WASM_BINARY_OPT as WASM_BINARY; - -#[cfg(feature = "wasm-binary")] -#[cfg(not(target_arch = "wasm32"))] -mod code { - include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -} diff --git a/contracts/car-races-old/car-3/Cargo.toml b/contracts/car-races-old/car-3/Cargo.toml deleted file mode 100644 index 22c46289e..000000000 --- a/contracts/car-races-old/car-3/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "car-strategy-3" -version = "0.1.0" -edition = "2021" - -[dependencies] -car-strategy-app-3 = { path = "app" } - -[build-dependencies] -car-strategy-app-3 = { path = "app" } -sails-rs.workspace = true -sails-idl-gen.workspace = true -gear-wasm-builder.workspace = true - -[dev-dependencies] -car-strategy-3 = { path = ".", features = ["wasm-binary"] } -sails-rs.workspace = true -tokio.workspace = true - -[features] -wasm-binary = [] diff --git a/contracts/car-races-old/car-3/README.md b/contracts/car-races-old/car-3/README.md deleted file mode 100644 index c0cfd5e7a..000000000 --- a/contracts/car-races-old/car-3/README.md +++ /dev/null @@ -1,9 +0,0 @@ -## The **car-strategy** program - -The program workspace includes the following packages: -- `car-strategy` is the package allowing to build WASM binary for the program and IDL file for it. - The package also includes integration tests for the program in the `tests` sub-folder -- `car-strategy-app` is the package containing business logic for the program represented by the `CarStrategyService` structure. -- `car-strategy-client` is the package containing the client for the program allowing to interact with it from another program, tests, or - off-chain client. - diff --git a/contracts/car-races-old/car-3/app/Cargo.toml b/contracts/car-races-old/car-3/app/Cargo.toml deleted file mode 100644 index cccbcb65d..000000000 --- a/contracts/car-races-old/car-3/app/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "car-strategy-app-3" -version = "0.1.0" -edition = "2021" - -[dependencies] -sails-rs.workspace = true -gstd.workspace = true -parity-scale-codec.workspace = true -scale-info.workspace = true \ No newline at end of file diff --git a/contracts/car-races-old/car-3/app/src/lib.rs b/contracts/car-races-old/car-3/app/src/lib.rs deleted file mode 100644 index c00ed3197..000000000 --- a/contracts/car-races-old/car-3/app/src/lib.rs +++ /dev/null @@ -1,80 +0,0 @@ -#![no_std] -#![allow(clippy::new_without_default)] - -use sails_rs::{collections::BTreeMap, prelude::*}; -struct CarStrategyService(()); - -#[sails_rs::service] -impl CarStrategyService { - pub fn new() -> Self { - Self(()) - } - - // this car only accelerates - pub fn make_move(&mut self, cars: BTreeMap) -> StrategyAction { - let my_car_id = gstd::exec::program_id(); - let my_car = cars.get(&my_car_id).expect("Unable to get my car"); - let my_position = my_car.position; - let mut cars_vec: Vec<(ActorId, Car)> = cars - .iter() - .map(|(car_id, car)| (*car_id, car.clone())) - .collect(); - cars_vec.sort_by(|a, b| b.1.position.cmp(&a.1.position)); - // If I'm the first skip - if cars_vec[0].0 == my_car_id { - return StrategyAction::Skip; - } - // if I'm the second - if cars_vec[1].0 == my_car_id { - // if the distance is small, then just buy acceleration - if (cars_vec[0].1.position - my_position) <= 1000 { - return StrategyAction::BuyShell; - } else { - // else buy shells - return StrategyAction::BuyAcceleration; - } - } - // if I'm the third just buy shell - if cars_vec[2].0 == my_car_id { - return StrategyAction::BuyAcceleration; - } - StrategyAction::Skip - } -} - -pub struct CarStrategyProgram(()); - -#[sails_rs::program] -impl CarStrategyProgram { - // Program's constructor - pub fn new() -> Self { - Self(()) - } - - // Exposed service - pub fn car_strategy(&self) -> CarStrategyService { - CarStrategyService::new() - } -} - -#[derive(Encode, Decode, TypeInfo, Clone, Debug)] -pub struct Car { - pub position: u32, - pub speed: u32, - pub car_actions: Vec, - pub round_result: Option, -} - -#[derive(Encode, Decode, TypeInfo, Debug)] -pub enum StrategyAction { - BuyAcceleration, - BuyShell, - Skip, -} - -#[derive(Encode, Decode, TypeInfo, Debug, Clone, PartialEq, Eq)] -pub enum RoundAction { - Accelerated, - SlowedDown, - SlowedDownAndAccelerated, -} diff --git a/contracts/car-races-old/car-3/build.rs b/contracts/car-races-old/car-3/build.rs deleted file mode 100644 index eb45bfef9..000000000 --- a/contracts/car-races-old/car-3/build.rs +++ /dev/null @@ -1,24 +0,0 @@ -use std::{ - env, - fs::File, - io::{BufRead, BufReader}, - path::PathBuf, -}; - -fn main() { - gear_wasm_builder::build(); - - if env::var("__GEAR_WASM_BUILDER_NO_BUILD").is_ok() { - return; - } - - let bin_path_file = File::open(".binpath").unwrap(); - let mut bin_path_reader = BufReader::new(bin_path_file); - let mut bin_path = String::new(); - bin_path_reader.read_line(&mut bin_path).unwrap(); - - let mut idl_path = PathBuf::from(bin_path); - idl_path.set_extension("idl"); - sails_idl_gen::generate_idl_to_file::(idl_path) - .unwrap(); -} diff --git a/contracts/car-races-old/car-3/src/lib.rs b/contracts/car-races-old/car-3/src/lib.rs deleted file mode 100644 index 25867ee6d..000000000 --- a/contracts/car-races-old/car-3/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![no_std] - -#[cfg(target_arch = "wasm32")] -pub use car_strategy_app_3::wasm::*; - -#[cfg(feature = "wasm-binary")] -#[cfg(not(target_arch = "wasm32"))] -pub use code::WASM_BINARY_OPT as WASM_BINARY; - -#[cfg(feature = "wasm-binary")] -#[cfg(not(target_arch = "wasm32"))] -mod code { - include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -} diff --git a/contracts/car-races-old/wasm/Cargo.toml b/contracts/car-races-old/wasm/Cargo.toml deleted file mode 100644 index f9565196d..000000000 --- a/contracts/car-races-old/wasm/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "car-races" -version.workspace = true -edition.workspace = true -license.workspace = true - -[dependencies] -car-races-app = { path = "../app" } -sails-rs.workspace = true - -[build-dependencies] -gear-wasm-builder.workspace = true -sails-idl-gen.workspace = true -sails-client-gen.workspace = true -car-races-app = { path = "../app" } - -[lib] -crate-type = ["rlib"] -name = "car_races" diff --git a/contracts/car-races-old/wasm/build.rs b/contracts/car-races-old/wasm/build.rs deleted file mode 100644 index fb81af1f0..000000000 --- a/contracts/car-races-old/wasm/build.rs +++ /dev/null @@ -1,15 +0,0 @@ -use car_races_app::Program; -use sails_idl_gen::program; -use std::{env, fs::File, path::PathBuf}; - -fn main() { - gear_wasm_builder::build(); - - let manifest_dir_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); - - let idl_file_path = manifest_dir_path.join("car-races.idl"); - - let idl_file = File::create(idl_file_path.clone()).unwrap(); - - program::generate_idl::(idl_file).unwrap(); -} diff --git a/contracts/car-races-old/wasm/car-races.idl b/contracts/car-races-old/wasm/car-races.idl deleted file mode 100644 index db6287ce7..000000000 --- a/contracts/car-races-old/wasm/car-races.idl +++ /dev/null @@ -1,134 +0,0 @@ -type InitConfig = struct { - config: ServicesConfig, -}; - -type ServicesConfig = struct { - gas_to_remove_game: u64, - initial_speed: u32, - min_speed: u32, - max_speed: u32, - gas_for_round: u64, - time_interval: u32, - max_distance: u32, - time: u32, - time_for_game_storage: u64, - block_duration_ms: u64, - gas_for_reply_deposit: u64, -}; - -type SessionConfig = struct { - gas_to_delete_session: u64, - minimum_session_duration_ms: u64, - ms_per_block: u64, -}; - -type StrategyAction = enum { - BuyAcceleration, - BuyShell, - Skip, -}; - -type Game = struct { - cars: map (actor_id, Car), - car_ids: vec actor_id, - current_turn: u8, - state: GameState, - result: opt GameResult, - current_round: u32, - last_time_step: u64, -}; - -type Car = struct { - position: u32, - speed: u32, - car_actions: vec RoundAction, - round_result: opt RoundAction, -}; - -type RoundAction = enum { - Accelerated, - SlowedDown, - SlowedDownAndAccelerated, -}; - -type GameState = enum { - ReadyToStart, - Race, - Stopped, - Finished, - PlayerAction, -}; - -type GameResult = enum { - Win, - Draw, - Lose, -}; - -type RoundInfo = struct { - cars: vec struct { actor_id, u32, opt RoundAction }, - result: opt GameResult, -}; - -type SignatureData = struct { - key: actor_id, - duration: u64, - allowed_actions: vec ActionsForSession, -}; - -type ActionsForSession = enum { - StartGame, - Move, - Skip, -}; - -type SessionData = struct { - key: actor_id, - expires: u64, - allowed_actions: vec ActionsForSession, - expires_at_block: u32, -}; - -constructor { - New : (init_config: InitConfig, session_config: SessionConfig, dns_id_and_name: opt struct { actor_id, str }); -}; - -service CarRacesService { - AddAdmin : (admin: actor_id) -> null; - AddStrategyIds : (car_ids: vec actor_id) -> null; - AllowMessages : (messages_allowed: bool) -> null; - Kill : (inheritor: actor_id) -> null; - PlayerMove : (strategy_move: StrategyAction, session_for_account: opt actor_id) -> null; - RemoveAdmin : (admin: actor_id) -> null; - RemoveGameInstance : (account: actor_id) -> null; - RemoveInstances : (player_ids: opt vec actor_id) -> null; - StartGame : (session_for_account: opt actor_id) -> null; - UpdateConfig : (config: ServicesConfig) -> null; - query Admins : () -> vec actor_id; - query AllGames : () -> vec struct { actor_id, Game }; - query ConfigState : () -> ServicesConfig; - query DnsInfo : () -> opt struct { actor_id, str }; - query Game : (account_id: actor_id) -> opt Game; - query MessagesAllowed : () -> bool; - query StrategyIds : () -> vec actor_id; - - events { - RoundInfo: RoundInfo; - GameFinished: struct { player: actor_id }; - Killed: struct { inheritor: actor_id }; - } -}; - -service Session { - CreateSession : (signature_data: SignatureData, signature: opt vec u8) -> null; - DeleteSessionFromAccount : () -> null; - DeleteSessionFromProgram : (session_for_account: actor_id) -> null; - query SessionForTheAccount : (account: actor_id) -> opt SessionData; - query Sessions : () -> vec struct { actor_id, SessionData }; - - events { - SessionCreated; - SessionDeleted; - } -}; - diff --git a/contracts/car-races-old/wasm/src/lib.rs b/contracts/car-races-old/wasm/src/lib.rs deleted file mode 100644 index 86d18862d..000000000 --- a/contracts/car-races-old/wasm/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![no_std] -include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); - -#[cfg(target_arch = "wasm32")] -pub use car_races_app::wasm::*;