Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adds view funcs and parameterized launch tourny configs #237

Merged
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion contracts/game/src/game/constants.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ const PRAGMA_LORDS_KEY: felt252 = 'LORDS/USD'; // felt252 conversion of "LORDS/U
const PRAGMA_PUBLISH_DELAY: u8 = 0;
const PRAGMA_NUM_WORDS: u8 = 1;
const GAME_EXPIRY_DAYS: u8 = 10;
const OBITUARY_EXPIRY_DAYS: u8 = 10;
const OBITUARY_EXPIRY_DAYS: u8 = 1;
const MAX_U64: u64 = 0xffffffffffffffff;
const STARTER_BEAST_ATTACK_DAMAGE: u16 = 10;
const CONTROLLER_DELEGATE_ACCOUNT_INTERFACE_ID: felt252 =
0x406350870d0cf6ca3332d174788fdcfa803e21633b124b746629775b9a294c;
const DAO_CONTRACT_REWARD_ADVENTURER: u8 = 2;
const PG_CONTRACT_REWARD_ADVENTURER: u8 = 3;

mod messages {
const NOT_ENOUGH_GOLD: felt252 = 'Not enough gold';
Expand Down
4 changes: 4 additions & 0 deletions contracts/game/src/game/interfaces.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ trait IGame<TContractState> {
fn get_adventurer_renderer(self: @TContractState, adventurer_id: felt252) -> ContractAddress;
fn get_adventurer_vrf_allowance(self: @TContractState, adventurer_id: felt252) -> u128;
fn get_vrf_premiums_address(self: @TContractState) -> ContractAddress;
fn free_vrf_promotion_active(self: @TContractState) -> bool;
fn is_launch_tournament_active(self: @TContractState) -> bool;
fn get_launch_tournament_winner(self: @TContractState) -> ContractAddress;
fn get_launch_tournament_end_time(self: @TContractState) -> u64;
}

#[starknet::interface]
Expand Down
152 changes: 120 additions & 32 deletions contracts/game/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ mod Game {
TARGET_PRICE_USD_CENTS, VRF_COST_PER_GAME, VRF_MAX_CALLBACK_MAINNET,
VRF_MAX_CALLBACK_TESTNET, PRAGMA_LORDS_KEY, PRAGMA_PUBLISH_DELAY, PRAGMA_NUM_WORDS,
GAME_EXPIRY_DAYS, OBITUARY_EXPIRY_DAYS, MAX_U64,
CONTROLLER_DELEGATE_ACCOUNT_INTERFACE_ID
CONTROLLER_DELEGATE_ACCOUNT_INTERFACE_ID, DAO_CONTRACT_REWARD_ADVENTURER,
PG_CONTRACT_REWARD_ADVENTURER
},
RenderContract::{
IRenderContract, IRenderContractDispatcher, IRenderContractDispatcherTrait
Expand Down Expand Up @@ -151,25 +152,26 @@ mod Game {
_bag: Map::<felt252, Bag>,
_beasts_dispatcher: IBeastsDispatcher,
_cost_to_play: u128,
_dao: ContractAddress,
_default_renderer: ContractAddress,
_eth_dispatcher: IERC20Dispatcher,
_free_vrf_promotion_duration_seconds: u64,
_game_count: felt252,
_genesis_timestamp: u64,
_golden_token_dispatcher: IERC721Dispatcher,
_golden_token_last_use: Map::<u32, u64>,
_launch_tournament_champions_dispatcher: IERC721Dispatcher,
_launch_tournament_claimed_games: Map::<felt252, bool>,
_launch_tournament_collections: Vec<ContractAddress>,
_launch_tournament_games_per_claim: Map::<ContractAddress, u8>,
_launch_tournament_games_per_collection: u16,
_launch_tournament_end_time: u64,
_launch_tournament_duration_seconds: u64,
_launch_tournament_participants: Map::<felt252, ContractAddress>,
_launch_tournament_scores: Map::<ContractAddress, u32>,
_launch_tournament_start_delay_seconds: u64,
_launch_tournament_game_counts: Map::<ContractAddress, u16>,
_leaderboard: Leaderboard,
_payment_token_dispatcher: IERC20Dispatcher,
_oracle_dispatcher: IPragmaABIDispatcher,
_pg_address: ContractAddress,
_previous_free_game_timestamp: Map::<(ContractAddress, u32), u64>,
_terminal_timestamp: u64,
_vrf_dispatcher: IRandomnessDispatcher,
Expand Down Expand Up @@ -239,10 +241,13 @@ mod Game {
/// @param oracle_address: the address of the oracle
/// @param render_contract: the address of the render contract
/// @param qualifying_collections: the qualifying collections for the launch tournament
/// @param launch_tournament_end_timestamp: the timestamp of the launch tournament end
/// @param launch_tournament_duration_seconds: the duration of the launch tournament in seconds
/// @param vrf_payments_address: the address of the VRF payments
/// @param launch_tournament_games_per_collection: the number of games per collection for the
/// launch tournament
/// @param launch_tournament_start_delay_seconds: the delay before the launch tournament claims
/// starts
/// @param free_vrf_promotion_duration_seconds: the duration of the free VRF promotion
#[constructor]
fn constructor(
ref self: ContractState,
Expand All @@ -257,9 +262,11 @@ mod Game {
oracle_address: ContractAddress,
render_contract: ContractAddress,
qualifying_collections: Array<LaunchTournamentCollections>,
launch_tournament_end_timestamp: u64,
launch_tournament_duration_seconds: u64,
vrf_payments_address: ContractAddress,
launch_tournament_games_per_collection: u16
launch_tournament_games_per_collection: u16,
launch_tournament_start_delay_seconds: u64,
free_vrf_promotion_duration_seconds: u64
) {
if payment_token.is_non_zero() {
let payment_dispatcher = IERC20Dispatcher { contract_address: payment_token };
Expand All @@ -278,14 +285,6 @@ mod Game {
// @dev the only reason ETH should be in the contract is to cover VRF costs
}

if dao_address.is_non_zero() {
self._dao.write(dao_address);
}

if pg_address.is_non_zero() {
self._pg_address.write(pg_address);
}

if beasts_address.is_non_zero() {
let beasts_dispatcher = IBeastsDispatcher { contract_address: beasts_address };
self._beasts_dispatcher.write(beasts_dispatcher);
Expand All @@ -309,8 +308,16 @@ mod Game {
self._default_renderer.write(render_contract);
}

if launch_tournament_end_timestamp != 0 {
self._launch_tournament_end_time.write(launch_tournament_end_timestamp);
self._genesis_timestamp.write(get_block_timestamp());

if launch_tournament_duration_seconds != 0 {
self._launch_tournament_duration_seconds.write(launch_tournament_duration_seconds);
}

if launch_tournament_start_delay_seconds != 0 {
self
._launch_tournament_start_delay_seconds
.write(launch_tournament_start_delay_seconds);
}

if launch_tournament_games_per_collection != 0 {
Expand All @@ -334,11 +341,18 @@ mod Game {
self._vrf_premiums_address.write(vrf_payments_address);
}

if free_vrf_promotion_duration_seconds != 0 {
self._free_vrf_promotion_duration_seconds.write(free_vrf_promotion_duration_seconds);
}

// @dev base uri isn't used in the current implementation
self.erc721.initializer("Loot Survivor", "LSVR", "https://token.lootsurvivor.io/");

// initialize launch tournament
_initialize_launch_tournament(ref self, qualifying_collections.span());

// mint genesis adventurers
_mint_genesis_adventurers(ref self, dao_address, pg_address);
}

// ------------------------------------------ //
Expand Down Expand Up @@ -395,11 +409,7 @@ mod Game {
_process_payment_and_distribute_rewards(ref self, client_reward_address);
}

// get current timestamp
let current_timestamp = starknet::get_block_info().unbox().block_timestamp;
// check if timestamp is within launch promotion period
if current_timestamp > self._launch_tournament_end_time.read() {
// pay for vrf
if !_free_vrf_promotion_active(@self) {
_pay_for_vrf(@self);
}
}
Expand Down Expand Up @@ -1260,12 +1270,67 @@ mod Game {
) -> bool {
_free_game_available(self, token_type, token_id)
}
fn free_vrf_promotion_active(self: @ContractState) -> bool {
_free_vrf_promotion_active(self)
}
fn is_launch_tournament_active(self: @ContractState) -> bool {
_is_launch_tournament_active(self)
}
fn get_launch_tournament_winner(self: @ContractState) -> ContractAddress {
_get_launch_tournament_winner(self)
}
fn get_launch_tournament_end_time(self: @ContractState) -> u64 {
_launch_tournament_end_time(self)
}
}

// ------------------------------------------ //
// ------------ Internal Functions ---------- //
// ------------------------------------------ //

fn _mint_genesis_adventurers(
ref self: ContractState, dao_address: ContractAddress, pg_address: ContractAddress
) {
_start_game(
ref self,
ItemId::Wand,
'Genesis Adventurer',
contract_address_const::<0>(),
true,
0,
0,
pg_address
);

_start_game(
ref self,
ItemId::Book,
'Bibliomancer',
contract_address_const::<0>(),
true,
0,
0,
dao_address
);

_start_game(
ref self,
ItemId::ShortSword,
'GLHF',
contract_address_const::<0>(),
true,
0,
0,
pg_address
);
}
fn _free_vrf_promotion_active(self: @ContractState) -> bool {
let current_timestamp = starknet::get_block_info().unbox().block_timestamp;
let genesis_timestamp = self._genesis_timestamp.read();
let free_vrf_promotion_duration_seconds = self._free_vrf_promotion_duration_seconds.read();
current_timestamp <= genesis_timestamp + free_vrf_promotion_duration_seconds
}

fn _enter_launch_tournament(
ref self: ContractState,
weapon: u8,
Expand Down Expand Up @@ -1821,6 +1886,14 @@ mod Game {
/ (response.price * 100000000)
}

fn _get_dao_address(self: @ContractState) -> ContractAddress {
_get_owner(self, DAO_CONTRACT_REWARD_ADVENTURER.into())
}

fn _get_pg_address(self: @ContractState) -> ContractAddress {
_get_owner(self, PG_CONTRACT_REWARD_ADVENTURER.into())
}

/// @title Process Payment and Distribute Rewards
/// @notice Processes the payment and distributes the rewards to the appropriate addresses.
/// @dev This function is called when the payment is processed and the rewards are distributed.
Expand All @@ -1838,7 +1911,7 @@ mod Game {
// send tokens to PG address
// @dev this is expected to be a trivial amount and exists to remove incentive to play
// and die fast
let pg_address = self._pg_address.read();
let pg_address = _get_pg_address(@self);
payment_dispatcher.transfer_from(get_caller_address(), pg_address, cost_to_play.into());
} else {
// if payouts are active, calculate rewards
Expand All @@ -1858,14 +1931,14 @@ mod Game {
}

if rewards.BIBLIO != 0 {
let dao_address = self._dao.read();
let dao_address = _get_dao_address(@self);
payment_dispatcher
.transfer_from(get_caller_address(), dao_address, rewards.BIBLIO.into());
}

// if pg is not zero, transfer rewards
if rewards.PG != 0 {
let pg_address = self._pg_address.read();
let pg_address = _get_pg_address(@self);
payment_dispatcher
.transfer_from(get_caller_address(), pg_address, rewards.PG.into());
}
Expand Down Expand Up @@ -3479,11 +3552,19 @@ mod Game {
fn _assert_is_dead(self: Adventurer) {
assert(self.health == 0, messages::ADVENTURER_IS_ALIVE);
}

fn _is_genesis_adventurer(adventurer_id: felt252) -> bool {
adventurer_id == 1 || adventurer_id == 2 || adventurer_id == 3
}
fn _is_expired(self: @ContractState, adventurer_id: felt252,) -> bool {
let current_time = get_block_timestamp();
let birth_date = _load_adventurer_metadata(self, adventurer_id).birth_date;
let expiry_time = birth_date + (GAME_EXPIRY_DAYS.into() * SECONDS_IN_DAY.into());
current_time > expiry_time
if _is_genesis_adventurer(adventurer_id) {
false
} else {
let current_time = get_block_timestamp();
let birth_date = _load_adventurer_metadata(self, adventurer_id).birth_date;
let expiry_time = birth_date + (GAME_EXPIRY_DAYS.into() * SECONDS_IN_DAY.into());
current_time > expiry_time
}
}
fn _assert_valid_starter_weapon(starting_weapon: u8) {
assert(
Expand Down Expand Up @@ -3550,10 +3631,17 @@ mod Game {
assert(!_is_launch_tournament_active(self), messages::TOURNAMENT_STILL_ACTIVE);
}

fn _launch_tournament_end_time(self: @ContractState) -> u64 {
let genesis_timestamp = self._genesis_timestamp.read();
let start_delay = self._launch_tournament_start_delay_seconds.read();
let duration = self._launch_tournament_duration_seconds.read();
genesis_timestamp + duration + start_delay
}

fn _is_launch_tournament_active(self: @ContractState) -> bool {
let current_timestamp = starknet::get_block_info().unbox().block_timestamp;
let launch_promotion_end_timestamp = self._launch_tournament_end_time.read();
current_timestamp <= launch_promotion_end_timestamp
let launch_tournament_end_time = _launch_tournament_end_time(self);
current_timestamp <= launch_tournament_end_time
}

fn _initialize_launch_tournament(
Expand Down Expand Up @@ -3622,7 +3710,7 @@ mod Game {
poseidon_hash_span(hash_span.span())
}

fn _get_tournament_winner(self: @ContractState) -> ContractAddress {
fn _get_launch_tournament_winner(self: @ContractState) -> ContractAddress {
self._launch_tournament_champions_dispatcher.read().contract_address
}

Expand Down
Loading
Loading