diff --git a/src/move/emojicoin_arena/sources/emojicoin_arena.move b/src/move/emojicoin_arena/sources/emojicoin_arena.move index 7cbaba5c0..9a0652843 100644 --- a/src/move/emojicoin_arena/sources/emojicoin_arena.move +++ b/src/move/emojicoin_arena/sources/emojicoin_arena.move @@ -7,6 +7,7 @@ module arena::emojicoin_arena { use aptos_framework::randomness::Self; use aptos_framework::timestamp; use aptos_std::smart_table::{Self, SmartTable}; + use arena::pseudo_randomness; use emojicoin_dot_fun::emojicoin_dot_fun::{ Self, MarketMetadata, @@ -39,9 +40,9 @@ module arena::emojicoin_arena { const MAX_MATCH_AMOUNT: u64 = 100_000_000; struct Melee has copy, drop, store { - /// 1-indexed for conformity with market ID indexing. + /// 1-indexed for conformity with emojicoin market ID indexing. melee_id: u64, - /// Market with lower market ID first. + /// Metadata for market with lower market ID comes first. market_metadatas: vector, available_rewards_in_octas: u64, /// In microseconds. @@ -63,7 +64,7 @@ module arena::emojicoin_arena { /// Map from melee serial ID to the melee. melees_by_id: SmartTable, /// Map from a sorted combination of market IDs (lower ID first) to the melee serial ID. - melees_by_market_combo_sorted_market_ids: SmartTable, u64>, + melee_ids_by_market_ids: SmartTable, u64>, /// Approves transfers from the vault. signer_capability: SignerCapability } @@ -254,8 +255,8 @@ module arena::emojicoin_arena { ) acquires MeleeEscrow, Registry { let exit_once_done = crank_schedule(); - // Return early if type arguments or melee ID is passed incorrectly, but only after cranking - // schedule. + // Return early if type arguments or melee ID are passed incorrectly, but only after + // cranking schedule. let swapper_address = signer::address_of(swapper); if (!exists>(swapper_address)) { return; @@ -422,19 +423,17 @@ module arena::emojicoin_arena { } fun init_module(arena: &signer) { - // Get first melee market addresses, without using randomness APIs. + // Use pseudo-randomness to get market IDs for the first melee, since randomness is not + // supported during `init_module`. let time = timestamp::now_microseconds(); let n_markets = get_n_registered_markets(); - let pseudo_random_market_id_0 = time % n_markets + 1; - let pseudo_random_market_id_1; + let market_id_0 = pseudo_random_market_id(n_markets); + let market_id_1; loop { - pseudo_random_market_id_1 = psuedo_random_u64(time) % n_markets + 1; - if (pseudo_random_market_id_1 != pseudo_random_market_id_0) break; + market_id_1 = pseudo_random_market_id(n_markets); + if (market_id_1 != market_id_0) break; }; - let market_ids = - sort_unique_market_ids( - pseudo_random_market_id_0, pseudo_random_market_id_1 - ); + let market_ids = sort_unique_market_ids(market_id_0, market_id_1); // Initialize first melee. let start_time = @@ -455,19 +454,15 @@ module arena::emojicoin_arena { duration: MELEE_DURATION_HOURS * MICROSECONDS_PER_HOUR } ); - let melees_by_market_combo_sorted_market_ids = smart_table::new(); - melees_by_market_combo_sorted_market_ids.add(market_ids, 1); + let melee_ids_by_market_ids = smart_table::new(); + melee_ids_by_market_ids.add(market_ids, 1); // Store registry resource. let (vault_signer, signer_capability) = account::create_resource_account(arena, REGISTRY_SEED); move_to( arena, - Registry { - melees_by_id, - melees_by_market_combo_sorted_market_ids, - signer_capability - } + Registry { melees_by_id, melee_ids_by_market_ids, signer_capability } ); coin::register(&vault_signer); } @@ -547,9 +542,7 @@ module arena::emojicoin_arena { duration: MELEE_DURATION_HOURS * MICROSECONDS_PER_HOUR } ); - registry_ref_mut.melees_by_market_combo_sorted_market_ids.add( - market_ids, melee_id - ); + registry_ref_mut.melee_ids_by_market_ids.add(market_ids, melee_id); true } else false } @@ -568,24 +561,20 @@ module arena::emojicoin_arena { let n_markets = get_n_registered_markets(); let market_ids; loop { - let random_market_id_0 = random_market_id(n_markets); - let random_market_id_1 = random_market_id(n_markets); - if (random_market_id_0 == random_market_id_1) continue; - market_ids = sort_unique_market_ids(random_market_id_0, random_market_id_1); - if (!Registry[@arena].melees_by_market_combo_sorted_market_ids.contains(market_ids)) { + let market_id_0 = random_market_id(n_markets); + let market_id_1 = random_market_id(n_markets); + if (market_id_0 == market_id_1) continue; + market_ids = sort_unique_market_ids(market_id_0, market_id_1); + if (!Registry[@arena].melee_ids_by_market_ids.contains(market_ids)) break; - } }; market_ids } - /// Psuedo random number generator based on xorshift64 algorithm from Wikipedia. - inline fun psuedo_random_u64(seed: u64): u64 { - seed = seed ^ (seed << 13); - seed = seed ^ (seed >> 7); - seed = seed ^ (seed << 17); - seed + /// Pseudo-random proxy for `random_market_id` for use during `init_module`. + inline fun pseudo_random_market_id(n_markets: u64): u64 { + pseudo_randomness::u64_range(0, n_markets) + 1 } /// Market IDs are 1-indexed. diff --git a/src/move/emojicoin_arena/sources/pseudo_randomness.move b/src/move/emojicoin_arena/sources/pseudo_randomness.move index 28f4e585f..d96d7e141 100644 --- a/src/move/emojicoin_arena/sources/pseudo_randomness.move +++ b/src/move/emojicoin_arena/sources/pseudo_randomness.move @@ -2,10 +2,32 @@ module arena::pseudo_randomness { use aptos_framework::transaction_context; use std::bcs; + use std::vector; + + friend arena::emojicoin_arena; + + /// Pseudo-random proxy for `aptos_framework::randomness::u64_range`. + public(friend) inline fun u64_range(min_incl: u64, max_excl: u64): u64 { + let range = ((max_excl - min_incl) as u256); + let sample = ((u256_integer() % range) as u64); + + min_incl + sample + } /// Pseudo-random proxy for `aptos_framework::randomness::next_32_bytes`. inline fun next_32_bytes(): vector { - bcs::to_bytes(transaction_context::generate_auid_address()) + bcs::to_bytes(&transaction_context::generate_auid_address()) } -} \ No newline at end of file + /// Pseudo-random proxy for `aptos_framework::randomness::u256_integer`. + inline fun u256_integer(): u256 { + let raw = next_32_bytes(); + let i = 0; + let ret: u256 = 0; + while (i < 32) { + ret = ret * 256 + (vector::pop_back(&mut raw) as u256); + i = i + 1; + }; + ret + } +}