Sample SCORE
Before showing the usage of PythonSDK in Jupyter Notebook, we will require a SCORE to be interacted with. For this documentation we chose one of the SCORE having highest number of transactions in ICON blockchain ie Dice SCORE of ICONbet.
Some changes have been made to the actual SCORE to make it easier for demonstration purpose. You can access the project folder from Github.

Dice SCORE

The following is the code snippet for the dice SCORE:-
1
from iconservice import *
2
3
TAG = "DICE"
4
UPPER_LIMIT = 99
5
LOWER_LIMIT = 0
6
MAIN_BET_MULTIPLIER = 98.5
7
SIDE_BET_MULTIPLIER = 95
8
BET_MIN = 1000000000000000
9
SIDE_BET_TYPES = ["digits_match", "icon_logo1", "icon_logo2"]
10
SIDE_BET_MULTIPLIERS = {"digits_match": 9.5, "icon_logo1": 5, "icon_logo2": 95}
11
BET_LIMIT_RATIOS_SIDE_BET = {"digits_match": 1140, "icon_logo1": 540, "icon_logo2": 12548}
12
MINIMUM_TREASURY = 250
13
14
class Dice(IconScoreBase):
15
_GAME_ON = "game_on"
16
17
def __init__(self, db: IconScoreDatabase) -> None:
18
super().__init__(db)
19
self._game_on = VarDB(self._GAME_ON, db, value_type=bool)
20
21
@eventlog(indexed=2)
22
def BetSource(self, _from: Address, timestamp: int):
23
pass
24
25
@eventlog(indexed=3)
26
def PayoutAmount(self, payout: int, main_bet_payout: int, side_bet_payout: int):
27
pass
28
29
@eventlog(indexed=3)
30
def BetResult(self, spin: str, winningNumber: int, payout: int):
31
pass
32
33
@eventlog(indexed=2)
34
def FundTransfer(self, recipient: Address, amount: int, note: str):
35
pass
36
37
def on_install(self) -> None:
38
super().on_install()
39
self._game_on.set(False)
40
41
def on_update(self) -> None:
42
super().on_update()
43
44
45
@external
46
def toggle_game_status(self) -> None:
47
48
if self.msg.sender != self.owner:
49
revert('Only the owner can call the toggle_game_status method')
50
self._game_on.set(not self._game_on.get() )
51
52
53
@external(readonly=True)
54
def get_game_status(self) -> bool:
55
return self._game_on.get()
56
57
def get_random(self, user_seed: str = '') -> float:
58
seed = (str(bytes.hex(self.tx.hash)) + str(self.now()) + user_seed)
59
spin = (int.from_bytes(sha3_256(seed.encode()), "big") % 100000) / 100000.0
60
return spin
61
62
@payable
63
@external
64
def call_bet(self, upper: int, lower: int, user_seed: str = '', side_bet_amount: int = 0,
65
side_bet_type: str = '') -> None:
66
return self.__bet(upper, lower, user_seed, side_bet_amount, side_bet_type)
67
68
def __bet(self, upper: int, lower: int, user_seed: str, side_bet_amount: int, side_bet_type: str) -> None:
69
side_bet_win = False
70
side_bet_set = False
71
side_bet_payout = 0
72
self.BetSource(self.tx.origin, self.tx.timestamp)
73
74
#condition checks
75
if not self._game_on.get():
76
revert(f'Game not active yet.')
77
78
if not (0 <= upper <= 99 and 0 <= lower <= 99):
79
revert(f'Invalid bet. Choose a number between 0 to 99')
80
if not (0 <= upper - lower <= 95):
81
revert(f'Invalid gap. Choose upper and lower values such that gap is between 0 to 95')
82
if (side_bet_type == '' and side_bet_amount != 0) or (side_bet_type != '' and side_bet_amount == 0):
83
revert(f'should set both side bet type as well as side bet amount')
84
if side_bet_amount < 0:
85
revert(f'Bet amount cannot be negative')
86
if side_bet_type != '' and side_bet_amount != 0:
87
side_bet_set = True
88
if side_bet_type not in SIDE_BET_TYPES:
89
revert(f'Invalid side bet type.')
90
side_bet_limit = MINIMUM_TREASURY // BET_LIMIT_RATIOS_SIDE_BET[side_bet_type]
91
if side_bet_amount < BET_MIN or side_bet_amount > side_bet_limit:
92
revert(f'Betting amount {side_bet_amount} out of range ({BET_MIN} ,{side_bet_limit}).')
93
side_bet_payout = int(SIDE_BET_MULTIPLIERS[side_bet_type] * 100) * side_bet_amount // 100
94
95
96
main_bet_amount = self.msg.value - side_bet_amount
97
gap = (upper - lower) + 1
98
if main_bet_amount == 0:
99
Logger.debug(f'No main bet amount provided', TAG)
100
revert(f'No main bet amount provided')
101
102
main_bet_limit = (MINIMUM_TREASURY * 1.5 * gap) // (68134 - 681.34 * gap)
103
if main_bet_amount < BET_MIN or main_bet_amount > main_bet_limit:
104
revert(f'Main Bet amount {main_bet_amount} out of range {BET_MIN},{main_bet_limit} ')
105
main_bet_payout = int(MAIN_BET_MULTIPLIER * 100) * main_bet_amount // (100 * gap)
106
payout = side_bet_payout + main_bet_payout
107
if self.icx.get_balance(self.address) < payout:
108
revert('Not enough in treasury to make the play.')
109
spin = self.get_random(user_seed)
110
winningNumber = int(spin * 100)
111
if lower <= winningNumber <= upper:
112
main_bet_win = True
113
else:
114
main_bet_win = False
115
if side_bet_set:
116
side_bet_win = self.check_side_bet_win(side_bet_type, winningNumber)
117
if not side_bet_win:
118
side_bet_payout = 0
119
main_bet_payout = main_bet_payout * main_bet_win
120
payout = main_bet_payout + side_bet_payout
121
self.BetResult(str(spin), winningNumber, payout)
122
self.PayoutAmount(payout, main_bet_payout, side_bet_payout)
123
if main_bet_win or side_bet_win:
124
try:
125
self.icx.transfer(self.msg.sender,payout)
126
except BaseException as e:
127
revert('Network problem. Winnings not sent. Returning funds.')
128
129
# check for bet limits and side limits
130
def check_side_bet_win(self, side_bet_type: str, winning_number: int) -> bool:
131
if side_bet_type == SIDE_BET_TYPES[0]: # digits_match
132
return winning_number % 11 == 0
133
if side_bet_type == SIDE_BET_TYPES[1]: # for icon logo1 ie for numbers having 1 zero in it
134
return str(0) in str(winning_number) or winning_number in range(1, 10)
135
if side_bet_type == SIDE_BET_TYPES[2]: # for icon logo2 ie for 0
136
return winning_number == 0
137
138
@payable
139
def fallback(self):
140
if self.msg.sender != self.owner:
141
revert("Treasury can only be filled by the SCORE owner")
Copied!
Copy link
Contents
Dice SCORE