Scorum
betting_service.cpp
Go to the documentation of this file.
2 
3 #include <boost/range/algorithm/set_algorithm.hpp>
4 #include <boost/range/algorithm/find_if.hpp>
5 
10 
12 
14 
17 
18 #include <scorum/utils/range/unwrap_ref_wrapper_adaptor.hpp>
19 #include <scorum/utils/algorithm/foreach_mut.hpp>
20 
21 #include <scorum/utils/collect_range_adaptor.hpp>
22 
23 namespace scorum {
24 namespace chain {
25 
27 
30  dba::db_accessor<betting_property_object>& betting_property_dba,
31  dba::db_accessor<matched_bet_object>& matched_bet_dba,
32  dba::db_accessor<pending_bet_object>& pending_bet_dba,
36  : _account_svc(account_svc)
37  , _virt_op_emitter(virt_op_emitter)
38  , _betting_property_dba(betting_property_dba)
39  , _matched_bet_dba(matched_bet_dba)
40  , _pending_bet_dba(pending_bet_dba)
41  , _game_dba(game_dba)
42  , _dprop_dba(dprop_dba)
43  , _uuid_hist_dba(uuid_hist_dba)
44 {
45 }
46 
48 {
49  try
50  {
51  return _betting_property_dba.get().moderator == account_name;
52  }
53  FC_CAPTURE_LOG_AND_RETHROW((account_name))
54 }
55 
57  const asset& stake,
58  odds odds,
59  const wincase_type& wincase,
60  uuid_type game_uuid,
61  uuid_type bet_uuid,
62  pending_bet_kind kind)
63 {
64  const auto& better_acc = _account_svc.get_account(better);
65  FC_ASSERT(better_acc.balance >= stake, "Insufficient funds");
66 
67  _uuid_hist_dba.create([&](bet_uuid_history_object& o) { o.uuid = bet_uuid; });
68 
69  const auto& bet = _pending_bet_dba.create([&](pending_bet_object& o) {
70  o.game_uuid = game_uuid;
71  o.market = create_market(wincase);
72  o.data.uuid = bet_uuid;
73  o.data.stake = stake;
74  o.data.odds = odds;
75  o.data.created = _dprop_dba.get().time;
76  o.data.better = better;
77  o.data.kind = kind;
78  o.data.wincase = wincase;
79  });
80 
81  _dprop_dba.update([&](auto& obj) { obj.betting_stats.pending_bets_volume += stake; });
82 
83  _account_svc.decrease_balance(better_acc, stake);
84 
85  return bet;
86 }
87 
89 {
90  auto matched_bets = _matched_bet_dba.get_range_by<by_game_uuid_market>(game_uuid);
91  FC_ASSERT(matched_bets.empty(), "Cannot cancel game which has associated bets");
92 
93  auto pending_bets = _matched_bet_dba.get_range_by<by_game_uuid_market>(game_uuid);
94  FC_ASSERT(pending_bets.empty(), "Cannot cancel game which has associated bets");
95 
96  const auto& game = _game_dba.get_by<by_uuid>(game_uuid);
97  _game_dba.remove(game);
98 }
99 
101 {
102  cancel_pending_bets(game_uuid);
103  cancel_matched_bets(game_uuid);
104 }
105 
106 void betting_service::cancel_bets(uuid_type game_uuid, fc::time_point_sec created_after)
107 {
108  using namespace dba;
109 
110  auto lower = std::make_tuple(game_uuid, created_after);
111  auto upper = game_uuid;
112  auto matched_bets = _matched_bet_dba.get_range_by<by_game_uuid_created>(lower <= _x, _x <= upper);
113  auto pending_bets = _pending_bet_dba.get_range_by<by_game_uuid_created>(lower <= _x, _x <= upper);
114 
115  cancel_pending_bets(pending_bets);
116 
117  for (const matched_bet_object& matched_bet : matched_bets)
118  {
119  if (matched_bet.bet1_data.created >= created_after)
120  return_bet(matched_bet.bet1_data, game_uuid);
121  else
122  restore_pending_bet(matched_bet.bet1_data, game_uuid);
123 
124  if (matched_bet.bet2_data.created >= created_after)
125  return_bet(matched_bet.bet2_data, game_uuid);
126  else
127  restore_pending_bet(matched_bet.bet2_data, game_uuid);
128  }
129 
130  _matched_bet_dba.remove_all(matched_bets);
131 }
132 
133 void betting_service::cancel_bets(uuid_type game_uuid, const fc::flat_set<market_type>& cancelled_markets)
134 {
135  // clang-format off
136  struct less
137  {
138  bool operator()(const pending_bet_object& b, const market_type& m) const { return b.market < m; }
139  bool operator()(const market_type& m, const pending_bet_object& b) const { return m < b.market; }
140  bool operator()(const matched_bet_object& b, const market_type& m) const { return b.market < m; }
141  bool operator()(const market_type& m, const matched_bet_object& b) const { return m < b.market; }
142  };
143  // clang-format on
144 
145  auto pending_bets = _pending_bet_dba.get_range_by<by_game_uuid_market>(game_uuid);
146 
147  std::vector<std::reference_wrapper<const pending_bet_object>> filtered_pending_bets;
148  boost::set_intersection(pending_bets, cancelled_markets, std::back_inserter(filtered_pending_bets), less{});
149 
150  cancel_pending_bets(utils::unwrap_ref_wrapper(filtered_pending_bets));
151 
152  auto matched_bets = _matched_bet_dba.get_range_by<by_game_uuid_market>(game_uuid);
153 
154  std::vector<std::reference_wrapper<const matched_bet_object>> filtered_matched_bets;
155  boost::set_intersection(matched_bets, cancelled_markets, std::back_inserter(filtered_matched_bets), less{});
156 
157  cancel_matched_bets(utils::unwrap_ref_wrapper(filtered_matched_bets), game_uuid);
158 }
159 
161 {
162  const auto& pending_bet = _pending_bet_dba.get_by<by_id>(id);
163 
164  cancel_pending_bet(pending_bet, pending_bet.game_uuid);
165 }
166 
168 {
169  auto pending_bets = _pending_bet_dba.get_range_by<by_game_uuid_market>(game_uuid);
170 
171  cancel_pending_bets(pending_bets);
172 }
173 
175 {
176  auto pending_bets = _pending_bet_dba.get_range_by<by_game_uuid_kind>(std::make_tuple(game_uuid, kind));
177 
178  cancel_pending_bets(pending_bets);
179 }
180 
181 void betting_service::cancel_pending_bets(utils::bidir_range<const pending_bet_object> bets)
182 {
183  utils::foreach_mut(bets, [&](const pending_bet_object& bet) { //
184  cancel_pending_bet(bet, bet.game_uuid);
185  });
186 }
187 
189 {
190  auto matched_bets = _matched_bet_dba.get_range_by<by_game_uuid_market>(game_uuid);
191 
192  cancel_matched_bets(matched_bets, game_uuid);
193 }
194 
195 void betting_service::cancel_matched_bets(utils::bidir_range<const matched_bet_object> bets, uuid_type game_uuid)
196 {
197  utils::foreach_mut(bets, [&](const matched_bet_object& bet) { //
198  cancel_matched_bet(bet, game_uuid);
199  });
200 }
201 
203 {
204  _account_svc.increase_balance(bet.data.better, bet.data.stake);
205 
206  push_pending_bet_cancelled_op(bet.data, game_uuid);
207 
208  _dprop_dba.update([&](auto& o) { o.betting_stats.pending_bets_volume -= bet.data.stake; });
209 
210  _pending_bet_dba.remove(bet);
211 }
212 
213 void betting_service::cancel_matched_bet(const matched_bet_object& bet, uuid_type game_uuid)
214 {
215  return_bet(bet.bet1_data, game_uuid);
216  return_bet(bet.bet2_data, game_uuid);
217 
218  _matched_bet_dba.remove(bet);
219 }
220 
221 void betting_service::return_bet(const bet_data& bet, uuid_type game_uuid)
222 {
223  _account_svc.increase_balance(bet.better, bet.stake);
224 
225  push_matched_bet_cancelled_op(bet, game_uuid);
226 
227  _dprop_dba.update([&](auto& o) { o.betting_stats.matched_bets_volume -= bet.stake; });
228 }
229 
230 void betting_service::restore_pending_bet(const bet_data& bet, uuid_type game_uuid)
231 {
232  auto is_exists = _pending_bet_dba.is_exists_by<by_uuid>(bet.uuid);
233  if (is_exists)
234  {
235  const auto& pending_bet = _pending_bet_dba.get_by<by_uuid>(bet.uuid);
236  auto old_stake = pending_bet.data.stake;
237 
238  _pending_bet_dba.update(pending_bet, [&](pending_bet_object& o) { o.data.stake += bet.stake; });
239 
240  _virt_op_emitter.push_virtual_operation(
241  bet_updated_operation{ game_uuid, bet.better, bet.uuid, old_stake, pending_bet.data.stake });
242  }
243  else
244  {
245  _pending_bet_dba.create([&](pending_bet_object& o) {
246  o.game_uuid = game_uuid;
247  o.market = create_market(bet.wincase);
248  o.data = bet;
249  });
250 
251  _virt_op_emitter.push_virtual_operation(bet_restored_operation{ game_uuid, bet.better, bet.uuid, bet.stake });
252  }
253 
254  _dprop_dba.update([&](auto& o) {
255  o.betting_stats.pending_bets_volume += bet.stake;
256  o.betting_stats.matched_bets_volume -= bet.stake;
257  });
258 }
259 
260 void betting_service::push_matched_bet_cancelled_op(const bet_data& bet, uuid_type game_uuid)
261 {
262  _virt_op_emitter.push_virtual_operation(
263  bet_cancelled_operation{ game_uuid, bet.better, bet.uuid, bet.stake, bet_kind::matched });
264 }
265 
266 void betting_service::push_pending_bet_cancelled_op(const bet_data& bet, uuid_type game_uuid)
267 {
268  _virt_op_emitter.push_virtual_operation(
269  bet_cancelled_operation{ game_uuid, bet.better, bet.uuid, bet.stake, bet_kind::pending });
270 }
271 }
272 }
void cancel_pending_bets(uuid_type game_uuid) override
const pending_bet_object & create_pending_bet(const account_name_type &better, const protocol::asset &stake, protocol::odds odds, const protocol::wincase_type &wincase, uuid_type game_uuid, uuid_type bet_uuid, pending_bet_kind kind) override
void cancel_matched_bets(uuid_type game_uuid) override
bool is_betting_moderator(const account_name_type &account_name) const override
void cancel_pending_bet(pending_bet_id_type id) override
void cancel_bets(uuid_type game_uuid) override
void cancel_game(uuid_type game_uuid) override
betting_service(account_service_i &, database_virtual_operations_emmiter_i &, dba::db_accessor< betting_property_object > &, dba::db_accessor< matched_bet_object > &, dba::db_accessor< pending_bet_object > &, dba::db_accessor< game_object > &, dba::db_accessor< dynamic_global_property_object > &, dba::db_accessor< bet_uuid_history_object > &)
const param_placeholder _x
market_type create_market(const wincase_type &wincase)
Definition: market.cpp:56
fc::fixed_string_16 account_name_type
Definition: types.hpp:62
fc::static_variant< result_home::yes, result_home::no, result_draw::yes, result_draw::no, result_away::yes, result_away::no, round_home::yes, round_home::no, handicap::over, handicap::under, correct_score_home::yes, correct_score_home::no, correct_score_draw::yes, correct_score_draw::no, correct_score_away::yes, correct_score_away::no, correct_score::yes, correct_score::no, goal_home::yes, goal_home::no, goal_both::yes, goal_both::no, goal_away::yes, goal_away::no, total::over, total::under, total_goals_home::over, total_goals_home::under, total_goals_away::over, total_goals_away::under > wincase_type
Definition: market.hpp:128
fc::static_variant< result_home, result_draw, result_away, round_home, handicap, correct_score_home, correct_score_draw, correct_score_away, correct_score, goal_home, goal_both, goal_away, total, total_goals_home, total_goals_away > market_type
Definition: market.hpp:97
Definition: asset.cpp:15
boost::uuids::uuid uuid_type
Definition: types.hpp:53
virtual const account_object & get_account(const account_name_type &) const =0
virtual void increase_balance(const account_object &account, const asset &amount)=0
virtual void decrease_balance(const account_object &account, const asset &amount)=0
account_name_type better
Definition: bet_objects.hpp:29
virtual void push_virtual_operation(const operation &op)=0