-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlib.rs
140 lines (123 loc) · 4.99 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#![cfg_attr(not(feature = "std"), no_std, no_main)]
/// This contract demonstrates a safe approach to handling randomness in smart contracts using an external oracle.
/// It simulates a simple casino-like game where users can place bets and potentially win rewards.
///
/// The provided code is for educational purposes only and should not be used in production.
///
/// Key Features:
///
/// - Integration with a Randomness Oracle: Relies on an external oracle (DIA Oracle in this example) to provide
/// unpredictable randomness, ensuring fairness.
/// - Two-Phase Betting:
/// - register_bet: User registers a bet and pays a fee.
/// - resolve_bet: User resolves the bet based on the oracle's randomness to determine win/loss and receive rewards.
///
/// Contract Structure:
///
/// Storage:
/// bets: Mapping that stores bet details (bet id, round, user).
/// oracle: Contract reference to the DIA Oracle.
///
/// Functionality:
///
/// - get_random(key: u64) -> Option<Vec<u8>>: Fetches randomness for a given round from the oracle.
/// - register_bet() -> Result<(), Error>: Registers a new bet, assigning a future round number, and charging a fee.
/// - resolve_bet(bet_id: BetId) -> Result<(), Error>: Resolves a bet based on the oracle's randomness,
/// distributing rewards if applicable.
///
/// - get_id() -> BetId: Generates a unique bet identifier.
/// - pay_fee(user: User) -> Result<(), Error>: Handles fee payment.
/// - is_victorious(randomness: Vec<u8>) -> bool: Determines if the bet is a win based on randomness.
/// - pay_reward(user: User) -> Result<(), Error>: Pays out rewards to the user.
#[ink::contract]
mod casino {
use dia_oracle_randomness_getter::RandomOracleGetter;
use ink::contract_ref;
use ink::prelude::vec::Vec;
use ink::storage::Mapping;
#[derive(Eq, PartialEq, Debug, scale::Encode, scale::Decode)]
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
pub enum Error {
FailedTransfer,
BetResolutionTooEarly,
Custom(Vec<u8>),
}
/// Example helper types
pub type BetId = u128;
pub type Round = u64;
pub type User = AccountId;
pub type BetDetails = (Round, User);
#[ink(storage)]
pub struct Casino {
bets: Mapping<BetId, BetDetails>,
// reference to the oracle contract
oracle: contract_ref!(RandomOracleGetter),
}
impl Casino {
#[ink(constructor)]
pub fn new(oracle_address: AccountId) -> Self {
Self {
bets: Mapping::default(),
oracle: oracle_address.into(),
}
}
/// Gets a random value from an oracle.
#[ink(message)]
pub fn get_random(&self, key: u64) -> Option<Vec<u8>> {
self.oracle.get_random_value_for_round(key)
}
/// A user will call the message to place a bet
#[ink(message)]
pub fn register_bet(&mut self) -> Result<(), Error> {
let user = self.env().caller();
// The player pays the fee to the Casino for playing.
self.pay_fee(user)?;
let bet_id = self.get_id(); // get a fresh BetId
let current_round = self.oracle.get_latest_round();
let round = current_round + 2; // we need to make sure this is a round in the future;
let details = (round, user);
self.bets.insert(bet_id, &details);
Ok(())
}
/// Depending on the randomness, provided by the oracle, determines if a user is victorious and pays
/// them up in that case.
///
/// The user needs to wait a couple of blocks after registering a bet before calling this message.
#[ink(message)]
pub fn resolve_bet(&mut self, bet_id: BetId) -> Result<(), Error> {
let user = self.env().caller();
let round = self.bets.get(bet_id).unwrap().0;
let randomness = self.oracle.get_random_value_for_round(round);
// Based on `randomness` determine if the bet was won or lost. Pay out rewards to the user, etc.
match randomness {
Some(randomness) => {
if self.is_victorious(randomness) {
self.pay_reward(user)?;
}
},
None => {
// After registering bet, user would need to wait a couple of blocks for randomness
return Err(Error::BetResolutionTooEarly);
}
}
self.bets.remove(bet_id);
Ok(())
}
fn get_id(&self) -> BetId {
// implement id generation
42
}
fn pay_fee(&self, user: User) -> Result<(), Error> {
// implement fee payment
Ok(())
}
fn is_victorious(&self, randomness: Vec<u8>) -> bool {
// implement victory logics
true
}
fn pay_reward(&self, user: User) -> Result<(), Error> {
//implement reward payment
Ok(())
}
}
}