forked from starknet-edu/starknet-cairo-101
-
Notifications
You must be signed in to change notification settings - Fork 10
/
ex13.cairo
155 lines (130 loc) · 4.45 KB
/
ex13.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
# ######## Ex 13
# Privacy
# The terminology "Zero knowldge" can be confusing. Devs tend to assume things are private on Zk Rollups.
# They are not. They can be; but they are not by default.
# In this exercice, you need to:
# - Use past data from transactions sent to the contract to find a value that is supposed to be "secret"
%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
#
@storage_var
func user_slots_storage(account : felt) -> (user_slots_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
@event
func assign_user_slot_called(account : felt, rank : 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
#
# 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()
# Checking that the user got a slot assigned
let (user_slot) = user_slots_storage.read(sender_address)
with_attr error_message("User slot not assigned. Call assign_user_slot"):
assert_not_zero(user_slot)
end
with_attr error_message("Input value is not the expected secret value"):
# Checking that the value provided by the user is the one we expect
let (value) = values_mapped_secret_storage.read(user_slot)
assert value = expected_value
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
let (user_slot) = user_slots_storage.read(sender_address)
# Emit an event with secret value
assign_user_slot_called.emit(sender_address, user_slot)
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