Skip to main content

Hints

!! SPOILER ALERT !!

This sections contains solutions to previous section's questions.

ExecuteMsg#

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]#[serde(rename_all = "snake_case")]pub enum ExecuteMsg {  Approve {    // release some coins - if quantity is None, release all coins in balance    quantity: Option<Vec<Coin>>,  },  Refund {},  Steal {    destination: String,  },}

Adding Handler#

Add a global constant:

// this will be the bech32-encoded address in final code// we cannot use Addr in const as that is heap allocated... use `Addr::from() laterconst THIEF: &str = "changeme";

Update the match statement in execute:

    match msg {ExecuteMsg::Approve { quantity } => try_approve(deps, env, state, info, quantity),ExecuteMsg::Refund {} => try_refund(deps, env, info, state),ExecuteMsg::Steal { destination } => try_steal(deps, env, info, destination),}

Implement try_steal:

fn try_steal(  deps: DepsMut,  env: Env,  info: MessageInfo,  destination: String,) -> Result<Response, ContractError> {  if info.sender != deps.api.addr_validate(THIEF)? {    return Err(ContractError::Unauthorized {});  }  let destination = deps.api.addr_validate(destination.as_str())?;  let contract_address = env.contract.address;  let amount = deps.querier.query_all_balances(&contract_address)?;  Ok(send_tokens(destination, amount, "approve"))}

Test Steal#

#[test]fn handle_steal() {  let mut deps = mock_dependencies(&[]);
  // initialize the store  let init_amount = coins(1000, "earth");  let msg = init_msg_expire_by_height(1000);  let mut env = mock_env();  env.block.height = 876;  let info = mock_info("creator", &init_amount);  let contract_addr = env.clone().contract.address;  let init_res = instantiate(deps.as_mut(), env, info, msg).unwrap();  assert_eq!(0, init_res.messages.len());
  // balance changed in init  deps.querier.update_balance(&contract_addr, init_amount);
  // not just "anybody" can steal the funds  let msg = ExecuteMsg::Steal {    destination: "anybody".into(),  };  let mut env = mock_env();  env.block.height = 900;
  let info = mock_info("anybody", &[]);  let execute_res = execute(deps.as_mut(), env, info, msg.clone());  match execute_res.unwrap_err() {    ContractError::Unauthorized {} => {}    e => panic!("unexpected error: {:?}", e),  }
  // only the thief can steal the funds  let msg = ExecuteMsg::Steal {    destination: "changeme".to_string(),  };  let mut env = mock_env();  env.block.height = 900;
  let info = mock_info("changeme", &[]);  let execute_res = execute(deps.as_mut(), env, info, msg.clone()).unwrap();  assert_eq!(1, execute_res.messages.len());  let msg = execute_res.messages.get(0).expect("no message");  assert_eq!(    msg,    &CosmosMsg::Bank(BankMsg::Send {      to_address: "changeme".into(),      amount: coins(1000, "earth"),    })  );}