Skip to content

Commit 49ff586

Browse files
authored
Feat/update next game (#26)
* half testing * stable version, not fully tested * update_next_game * optimizer v16 * add transfer nft message and reply * remove migrate * remove migrate msg fields * end restart button on homepage
1 parent 185487f commit 49ff586

File tree

13 files changed

+379
-69
lines changed

13 files changed

+379
-69
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,5 @@ jobs:
3636
-v "$(pwd)":/code \
3737
--mount type=volume,source="$(basename "$(pwd)")_cache",target=/target \
3838
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
39-
cosmwasm/workspace-optimizer:0.15.0 \
39+
cosmwasm/workspace-optimizer:0.16.0 \
4040
/code

contracts/prudent-pots/src/contract.rs

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ use cosmwasm_std::{
66
use cw2::set_contract_version;
77

88
use crate::error::ContractError;
9-
use crate::execute::{allocate_tokens, game_end, reallocate_tokens, update_config};
9+
use crate::execute::{
10+
allocate_tokens, game_end, reallocate_tokens, update_config, update_next_game,
11+
};
1012
use crate::helpers::game_end::prepare_next_game;
1113
use crate::helpers::validate::{validate_funds, validate_pot_initial_amount};
1214
use crate::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg, ReplyMsg};
@@ -16,8 +18,8 @@ use crate::query::{
1618
query_raffle, query_raffle_denom_split, query_raffle_winner, query_reallocation_fee_pool,
1719
query_winning_pots,
1820
};
19-
use crate::reply::game_end_reply;
20-
use crate::state::{GameConfig, GAME_CONFIG, OLD_GAME_CONFIG, REALLOCATION_FEE_POOL};
21+
use crate::reply::transfer_nft_reply;
22+
use crate::state::{GAME_CONFIG, REALLOCATION_FEE_POOL};
2123

2224
// version info for migration info
2325
const CONTRACT_NAME: &str = "crates.io:prudent-pots";
@@ -93,13 +95,25 @@ pub fn execute(
9395
raffle_cw721_token_addr,
9496
next_game_start,
9597
),
98+
ExecuteMsg::UpdateNextGame {
99+
raffle_cw721_token_id,
100+
raffle_cw721_token_addr,
101+
next_game_start,
102+
} => update_next_game(
103+
deps,
104+
env,
105+
info,
106+
raffle_cw721_token_id,
107+
raffle_cw721_token_addr,
108+
next_game_start,
109+
),
96110
}
97111
}
98112

99113
#[cfg_attr(not(feature = "library"), entry_point)]
100114
pub fn reply(_deps: DepsMut, _env: Env, msg: Reply) -> Result<Response, ContractError> {
101115
match msg.id.into() {
102-
ReplyMsg::GameEnd {} => game_end_reply(msg.result),
116+
ReplyMsg::TransferNft {} => transfer_nft_reply(msg.result),
103117
_ => Err(ContractError::UnknownReply {}),
104118
}
105119
}
@@ -128,31 +142,6 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult<Binary> {
128142
}
129143

130144
#[cfg_attr(not(feature = "library"), entry_point)]
131-
pub fn migrate(deps: DepsMut, _env: Env, msg: MigrateMsg) -> Result<Response, ContractError> {
132-
// load the old game config
133-
let old_game_config = OLD_GAME_CONFIG.load(deps.storage)?;
134-
135-
// Save new GameConfig at game_config_v2 storage key
136-
GAME_CONFIG.save(
137-
deps.storage,
138-
&GameConfig {
139-
fee: old_game_config.fee,
140-
fee_reallocation: old_game_config.fee_reallocation,
141-
fee_address: old_game_config.fee_address,
142-
game_denom: old_game_config.game_denom,
143-
game_cw721_addrs: old_game_config.game_cw721_addrs,
144-
game_duration: old_game_config.game_duration,
145-
game_duration_epoch: msg.game_duration_epoch, // this is from migrateMsg
146-
game_extend: old_game_config.game_extend,
147-
game_end_threshold: old_game_config.game_end_threshold,
148-
min_pot_initial_allocation: old_game_config.min_pot_initial_allocation,
149-
decay_factor: msg.decay_factor, // this is from migrateMsg
150-
reallocations_limit: old_game_config.reallocations_limit,
151-
},
152-
)?;
153-
154-
// remove the old game config
155-
OLD_GAME_CONFIG.remove(deps.storage);
156-
145+
pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
157146
Ok(Response::new().add_attribute("migrate", "successful"))
158147
}

contracts/prudent-pots/src/execute.rs

Lines changed: 106 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use std::str::FromStr;
22

33
use cosmwasm_std::{
4-
attr, BankMsg, CosmosMsg, Decimal, DepsMut, Env, MessageInfo, Response, Uint128,
4+
attr, to_json_binary, BankMsg, CosmosMsg, Decimal, DepsMut, Env, MessageInfo, Response, SubMsg,
5+
Uint128, WasmMsg,
56
};
67

78
use crate::{
@@ -20,8 +21,8 @@ use crate::{
2021
validate_is_contract_admin_game_end, validate_pot_limit_not_exceeded,
2122
},
2223
},
23-
msg::UpdateGameConfig,
24-
state::{GAME_CONFIG, GAME_STATE, PLAYER_ALLOCATIONS, REALLOCATION_FEE_POOL},
24+
msg::{ReplyMsg, UpdateGameConfig},
25+
state::{GAME_CONFIG, GAME_STATE, PLAYER_ALLOCATIONS, RAFFLE, REALLOCATION_FEE_POOL},
2526
ContractError,
2627
};
2728

@@ -311,3 +312,105 @@ pub fn game_end(
311312
.add_attributes(process_raffle_winner_resp.attributes) // this contains the raffle event attributes including the treasury denom fee split, which is not included above
312313
.add_attribute("total_outgoing_tokens", total_outgoing_tokens)) // this is the total of distribution + raffle + treasury
313314
}
315+
316+
pub fn update_next_game(
317+
deps: DepsMut,
318+
env: Env,
319+
info: MessageInfo,
320+
new_raffle_cw721_id: Option<String>,
321+
new_raffle_cw721_addr: Option<String>,
322+
next_game_start: Option<u64>,
323+
) -> Result<Response, ContractError> {
324+
validate_is_contract_admin(&deps.querier, &env, &info.sender)?;
325+
326+
let mut submsgs: Vec<SubMsg> = vec![];
327+
let mut response_attributes = vec![];
328+
329+
// Handle start time update
330+
if let Some(start_time) = next_game_start {
331+
// If next_game_start is passed, it should be in the future
332+
if start_time <= env.block.time.seconds() {
333+
return Err(ContractError::InvalidNextGameStart {});
334+
}
335+
336+
let game_duration = GAME_CONFIG.load(deps.storage)?.game_duration;
337+
GAME_STATE.update(deps.storage, |mut game_state| -> Result<_, ContractError> {
338+
game_state.start_time = start_time;
339+
game_state.end_time = start_time + game_duration;
340+
Ok(game_state)
341+
})?;
342+
343+
response_attributes.push(attr("next_game_start", start_time.to_string()));
344+
}
345+
346+
// Handle raffle NFT update, if a raffle_id is passed we assume we want to set an NFT for the next round's raffle
347+
if let Some(raffle_id) = &new_raffle_cw721_id {
348+
// Ensure both or neither options are provided or throw an error
349+
if new_raffle_cw721_id.is_some() != new_raffle_cw721_addr.is_some() {
350+
return Err(ContractError::InvalidRaffleNft {});
351+
}
352+
353+
// Update the raffle CW721 token ID and address, only if there is no one yet
354+
RAFFLE.update(deps.storage, |mut raffle| -> Result<_, ContractError> {
355+
if raffle.cw721_token_id.is_none() {
356+
raffle.cw721_token_id = Some(raffle_id.clone());
357+
raffle.cw721_addr = new_raffle_cw721_addr.clone();
358+
} else {
359+
// Otherwise throw
360+
return Err(ContractError::InvalidRaffleNft {});
361+
}
362+
Ok(raffle)
363+
})?;
364+
365+
// Transfer the NFT
366+
let transfer_nft_msg = SubMsg::reply_always(
367+
WasmMsg::Execute {
368+
contract_addr: new_raffle_cw721_addr.clone().unwrap(),
369+
msg: to_json_binary(&cw721::Cw721ExecuteMsg::TransferNft {
370+
recipient: env.contract.address.to_string(),
371+
token_id: raffle_id.to_string(),
372+
})?,
373+
funds: vec![],
374+
},
375+
ReplyMsg::TransferNft as u64,
376+
);
377+
submsgs.push(transfer_nft_msg);
378+
response_attributes.extend(vec![
379+
attr("raffle_cw721_addr", new_raffle_cw721_addr.unwrap()),
380+
attr("raffle_cw721_id", raffle_id),
381+
]);
382+
}
383+
384+
// Handle raffle funds update, validate_funds to obtain current sent funds
385+
let game_denom = GAME_CONFIG.load(deps.storage)?.game_denom;
386+
let total_amount = validate_funds(&info.funds, &game_denom).unwrap_or_default();
387+
if !total_amount.is_zero() {
388+
// Update the denom amount for the next raffle incrementing any previous value
389+
RAFFLE.update(deps.storage, |mut raffle| -> Result<_, ContractError> {
390+
raffle.denom_amount += total_amount;
391+
Ok(raffle)
392+
})?;
393+
response_attributes.push(attr("raffle_denom_amount", total_amount.to_string()));
394+
// this is only the new amount sent
395+
}
396+
397+
// Throw an error if we did nothing in the previous workflow, this method is meant to be executed for a reason
398+
if response_attributes.is_empty() {
399+
return Err(ContractError::InvalidInput {});
400+
}
401+
402+
// Create response with dynamic attributes based on the current execution
403+
let mut response = Response::new()
404+
.add_attributes(vec![
405+
attr("method", "execute"),
406+
attr("action", "update_next_game"),
407+
])
408+
.add_attributes(response_attributes);
409+
410+
// If submsgs is not empty, append the message to transfer the NFT
411+
if !submsgs.is_empty() {
412+
response = response.add_submessages(submsgs);
413+
}
414+
415+
Ok(response)
416+
}

contracts/prudent-pots/src/helpers/game_end.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,8 @@ pub fn process_raffle_winner(
190190
// TODO_FUTURE: Early return here if there is no raffle
191191
// if raffle.nft_id && addr is none and denom_prize is_zero() return all default values.
192192

193-
let mut msgs = Vec::new();
194-
let mut submsgs = Vec::new();
193+
let mut msgs = vec![];
194+
let mut submsgs = vec![];
195195
let mut raffle_response_attributes = vec![];
196196

197197
// this is common for yes_raffle and no_raffle scenarios
@@ -213,12 +213,11 @@ pub fn process_raffle_winner(
213213
})?,
214214
funds: vec![],
215215
},
216-
ReplyMsg::GameEnd as u64,
216+
ReplyMsg::TransferNft as u64,
217217
);
218218
submsgs.push(transfer_nft_msg);
219219
// Append attributes
220220
raffle_response_attributes.extend(vec![
221-
attr("raffle_winner", recipient.to_string()),
222221
attr("raffle_outgoing_nft_addr", cw721_addr),
223222
attr("raffle_outgoing_nft_id", token_id),
224223
]);
@@ -233,10 +232,10 @@ pub fn process_raffle_winner(
233232
msgs.push(send_msg);
234233
}
235234
// Append attributes
236-
raffle_response_attributes.extend(vec![attr(
237-
"raffle_outgoing_tokens_winner",
238-
prize_to_distribute,
239-
)]);
235+
raffle_response_attributes.extend(vec![
236+
attr("raffle_winner", recipient.to_string()),
237+
attr("raffle_outgoing_tokens_winner", prize_to_distribute),
238+
]);
240239

241240
if !prize_to_treasury.is_zero() {
242241
let send_msg = CosmosMsg::Bank(BankMsg::Send {
@@ -289,7 +288,7 @@ pub fn process_raffle_winner(
289288
})?,
290289
funds: vec![],
291290
},
292-
ReplyMsg::GameEnd as u64,
291+
ReplyMsg::TransferNft as u64,
293292
);
294293
submsgs.push(transfer_nft_msg);
295294
}

contracts/prudent-pots/src/msg.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,19 @@ pub enum ExecuteMsg {
4343
raffle_cw721_token_addr: Option<String>,
4444
next_game_start: Option<u64>,
4545
},
46+
UpdateNextGame {
47+
raffle_cw721_token_id: Option<String>,
48+
raffle_cw721_token_addr: Option<String>,
49+
next_game_start: Option<u64>,
50+
},
4651
}
4752

4853
/// Reply
4954
5055
#[derive(FromPrimitive, IntoPrimitive)]
5156
#[repr(u64)]
5257
pub enum ReplyMsg {
53-
GameEnd = 1,
58+
TransferNft = 1,
5459
#[default]
5560
Unknown,
5661
}
@@ -154,7 +159,4 @@ pub struct RaffleDenomSplitResponse {
154159
}
155160

156161
#[cw_serde]
157-
pub struct MigrateMsg {
158-
pub game_duration_epoch: u64,
159-
pub decay_factor: Decimal,
160-
}
162+
pub struct MigrateMsg {}

contracts/prudent-pots/src/reply.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ use cosmwasm_std::{attr, Response, SubMsgResult};
33
use crate::ContractError;
44

55
// This reply function is called by reply_always. This should only do nothing, or throw an error, foreach NFT send during game_end workflow to the raflle winner.
6-
pub fn game_end_reply(msg: SubMsgResult) -> Result<Response, ContractError> {
6+
pub fn transfer_nft_reply(msg: SubMsgResult) -> Result<Response, ContractError> {
77
match msg.into() {
88
Ok(_data) => Ok(Response::new().add_attributes(vec![
99
attr("method", "reply"),
10-
attr("action", "game_end_reply"),
10+
attr("action", "transfer_nft_reply"),
1111
])),
1212
_ => Err(ContractError::Cw721TokenNotReceived {}),
1313
}

contracts/prudent-pots/src/state.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ pub struct FirstBidder {
6666
pub time: u64,
6767
}
6868

69-
pub const OLD_GAME_CONFIG: Item<OldGameConfig> = Item::new("game_config");
7069
pub const GAME_CONFIG: Item<GameConfig> = Item::new("game_config_v2");
7170
pub const GAME_STATE: Item<GameState> = Item::new("game_state");
7271
pub const POT_STATES: Map<u8, TokenAllocation> = Map::new("pot_states");

contracts/prudent-pots/src/tests/integration/fixtures.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,15 +142,16 @@ pub fn default_with_balances(
142142
mint_nfts(&mut app, &cw721_addr, 1, 10, Addr::unchecked(ADMIN_ADDRESS));
143143

144144
// ApproveAll as admin to operator pp
145-
let _ = app.execute_contract(
145+
app.execute_contract(
146146
Addr::unchecked(ADMIN_ADDRESS),
147147
cw721_addr.clone(),
148148
&cw721::Cw721ExecuteMsg::ApproveAll {
149149
operator: pp_addr.to_string(),
150150
expires: None,
151151
},
152152
&vec![],
153-
);
153+
)
154+
.unwrap();
154155

155156
// Update config to extend game duration
156157
update_config(

contracts/prudent-pots/src/tests/integration/helpers.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,26 @@ pub fn game_end(
7272
)
7373
}
7474

75+
pub fn update_next_game(
76+
app: &mut App,
77+
pp_addr: &Addr,
78+
info: &MessageInfo,
79+
raffle_cw721_token_id: Option<String>,
80+
raffle_cw721_token_addr: Option<String>,
81+
next_game_start: Option<u64>,
82+
) -> Result<AppResponse, AnyError> {
83+
app.execute_contract(
84+
info.sender.clone(),
85+
pp_addr.clone(),
86+
&ExecuteMsg::UpdateNextGame {
87+
raffle_cw721_token_id,
88+
raffle_cw721_token_addr,
89+
next_game_start,
90+
},
91+
&info.funds,
92+
)
93+
}
94+
7595
// CW721
7696

7797
pub fn mint_nfts(app: &mut App, cw721_addr: &Addr, start_id: u64, count: u64, to_addr: Addr) {

contracts/prudent-pots/src/tests/integration/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ mod helpers;
55
mod instantiate;
66
mod reallocate_tokens;
77
mod update_config;
8+
mod update_next_game;

0 commit comments

Comments
 (0)