forked from starknet-edu/starknet-cairo-101
-
Notifications
You must be signed in to change notification settings - Fork 10
/
ex05.cairo
183 lines (154 loc) · 5.34 KB
/
ex05.cairo
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# ######## Ex 05
# Public/private variables
# In this exercice, you need to:
# - Use a function to get assigned a private variable
# - Use a function to duplicate this variable in a public variable
# - Use a function to show you know the correct value of the private variable
# - Your points are credited by the contract
%lang starknet
from starkware.cairo.common.cairo_builtins import HashBuiltin
from starkware.cairo.common.math import assert_not_zero
from starkware.starknet.common.syscalls import get_caller_address
from contracts.utils.ex00_base import (
tderc20_address,
has_validated_exercise,
distribute_points,
validate_exercise,
ex_initializer,
)
#
# Declaring storage vars
# Storage vars are by default not visible through the ABI. They are similar to "private" variables in Solidity
#
# You will need to read values in these storage slots. But not all of them have getters!
@storage_var
func user_slots_storage(account : felt) -> (user_slots_storage : felt):
end
@storage_var
func user_values_public_storage(account : felt) -> (user_values_public_storage : felt):
end
@storage_var
func values_mapped_secret_storage(slot : felt) -> (values_mapped_secret_storage : felt):
end
@storage_var
func was_initialized() -> (was_initialized : felt):
end
@storage_var
func next_slot() -> (next_slot : felt):
end
#
# Declaring getters
# Public variables should be declared explicitly with a getter
#
@view
func user_slots{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(
account : felt
) -> (user_slot : felt):
let (user_slot) = user_slots_storage.read(account)
return (user_slot)
end
@view
func user_values{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(
account : felt
) -> (user_value : felt):
let (value) = user_values_public_storage.read(account)
return (value)
end
#
# Constructor
#
@constructor
func constructor{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(
_tderc20_address : felt, _players_registry : felt, _workshop_id : felt, _exercise_id : felt
):
ex_initializer(_tderc20_address, _players_registry, _workshop_id, _exercise_id)
return ()
end
#
# External functions
#
@external
func claim_points{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(
expected_value : felt
):
# Reading caller address
let (sender_address) = get_caller_address()
with_attr error_message("User slot not assigned. Call assign_user_slot"):
# Checking that the user got a slot assigned
let (user_slot) = user_slots_storage.read(sender_address)
assert_not_zero(user_slot)
end
# Checking that the value provided by the user is the one we expect
# Still sneaky.
let (value) = values_mapped_secret_storage.read(user_slot)
with_attr error_message("Input value is not the expected secret value"):
assert value = expected_value + 23
end
# Checking if the user has validated the exercice before
validate_exercise(sender_address)
# Sending points to the address specified as parameter
distribute_points(sender_address, 2)
return ()
end
@external
func assign_user_slot{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}():
# Reading caller address
let (sender_address) = get_caller_address()
let (next_slot_temp) = next_slot.read()
let (next_value) = values_mapped_secret_storage.read(next_slot_temp + 1)
if next_value == 0:
user_slots_storage.write(sender_address, 1)
next_slot.write(0)
else:
user_slots_storage.write(sender_address, next_slot_temp + 1)
next_slot.write(next_slot_temp + 1)
end
return ()
end
@external
func copy_secret_value_to_readable_mapping{
syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr
}():
# Reading caller address
let (sender_address) = get_caller_address()
with_attr error_message("User slot not assigned. Call assign_user_slot"):
# Checking that the user got a slot assigned
let (user_slot) = user_slots_storage.read(sender_address)
assert_not_zero(user_slot)
end
# Reading user secret value
let (secret_value) = values_mapped_secret_storage.read(user_slot)
# Copying the value from non accessible values_mapped_secret_storage to
user_values_public_storage.write(sender_address, secret_value - 23)
return ()
end
#
# External functions - Administration
# Only admins can call these. You don't need to understand them to finish the exercice.
#
@external
func set_random_values{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(
values_len : felt, values : felt*
):
# Check if the random values were already initialized
let (was_initialized_read) = was_initialized.read()
with_attr error_message("random values already initialized"):
assert was_initialized_read = 0
end
# Storing passed values in the store
set_a_random_value(values_len, values)
# Mark that value store was initialized
was_initialized.write(1)
return ()
end
func set_a_random_value{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(
values_len : felt, values : felt*
):
if values_len == 0:
# Start with sum=0.
return ()
end
set_a_random_value(values_len=values_len - 1, values=values + 1)
values_mapped_secret_storage.write(values_len - 1, [values])
return ()
end