forked from tensojka/cairo-migration-prompt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
preamble.txt
263 lines (240 loc) · 9.2 KB
/
preamble.txt
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
<c0>
with_attr error_message("weird, var > 2"){
assert_nn_le(var, 2);
}
<c0><c1>
assert(var <= 2, 'weird, var > 2');
</c1><c0>
felt
</c0><c1>
felt252
</c1><c0>
func get_vote_counts{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
prop_id: felt
) -> (res: VoteCounts) {
let (yay) = proposal_total_yay.read(prop_id);
let (nay) = proposal_total_nay.read(prop_id);
return (res=VoteCounts(yay=yay, nay=nay));
}
</c0><c1>
fn get_vote_counts(prop_id: felt252) -> (felt252, felt252) {
let yay = proposal_total_yay::read(prop_id);
let nay = proposal_total_nay::read(prop_id);
(yay, nay)
}
</c1><c0>
func get_free_prop_id{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
) -> (freeid: felt) {
return _get_free_prop_id(0);
}
func _get_free_prop_id{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
currid: felt
) -> (freeid: felt) {
let (res) = proposal_vote_ends.read(currid);
if (res == 0) {
return (freeid = currid);
}else{
return _get_free_prop_id(currid + 1);
}
}
</c0><c1>
fn get_free_prop_id() -> felt252 {
_get_free_prop_id(0)
fn _get_free_prop_id(currid: felt252) -> felt252 {
let res = proposal_vote_ends::read(currid);
if res == 0 {
currid
} else {
_get_free_prop_id(currid + 1)
}
}
</c1><c0>
func assert_correct_contract_type{range_check_ptr}(contract_type: ContractType) {
with_attr error_message("wrong contract type, must be 0, 1 or 2"){
assert_nn_le(contract_type, 2); // either 0, 1 or 2
}
return ();
}
func assert_voting_in_progress{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(prop_id: felt){
let (end_block_number) = proposal_vote_ends.read(prop_id);
with_attr error_message("voting not yet started, prop_id not found"){
assert_not_zero(end_block_number);
}
let (curr_block_number) = get_block_number();
with_attr error_message("voting already concluded"){
let block_diff = end_block_number - curr_block_number;
assert_not_zero(block_diff);
assert_nn(block_diff);
}
return ();
}
</c0><c1>
fn assert_correct_contract_type(contract_type: ContractType) {
let contract_type_u: u64 = contract_type.try_into().unwrap();
assert(contract_type_u <= 2_u64, 'invalid contract type')
}
fn assert_voting_in_progress(prop_id: felt252) {
let end_block_number_felt: felt252 = proposal_vote_ends::read(prop_id);
let end_block_number: u64 = end_block_number_felt.try_into().unwrap();
assert(end_block_number != 0_u64, 'prop_id not found');
let current_block_number: u64 = get_block_info().unbox().block_number;
assert(end_block_number > current_block_number, 'voting concluded')
}
</c1><c0>
func vote{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
prop_id: felt,
opinion: felt
) {
// Checks
with_attr error_message("opinion must be either 1 or -1"){
assert_not_zero(opinion);
assert_le(opinion, 1);
assert_le(-1, opinion);
}
let (gov_token_addr) = governance_token_address.read();
let (caller_addr) = get_caller_address();
let (curr_votestatus) = proposal_voted_by.read(prop_id, caller_addr);
with_attr error_message("already voted"){
assert curr_votestatus = 0;
}
let (caller_balance) = IERC20.balanceOf(contract_address=gov_token_addr, account=caller_addr);
with_attr error_message("governance token balance is zero or erroneous"){
assert caller_balance.high = 0;
assert_not_zero(caller_balance.low);
}
assert_voting_in_progress(prop_id);
// Cast vote
proposal_voted_by.write(prop_id, caller_addr, opinion);
if(opinion == -1){
let (curr_votes) = proposal_total_nay.read(prop_id);
let new_votes = curr_votes + caller_balance.low;
assert_nn(new_votes);
proposal_total_nay.write(prop_id, new_votes);
}else{
let (curr_votes) = proposal_total_yay.read(prop_id);
let new_votes = curr_votes + caller_balance.low;
assert_nn(new_votes);
proposal_total_yay.write(prop_id, new_votes);
}
Voted.emit(prop_id, caller_addr, opinion);
return ();
}
</c0><c1>
fn vote(prop_id: felt252, opinion: felt252) {
// Checks
// This is quite awful and a mistake by me, will be fixed down the line.
let MINUS_ONE: felt252 =
3618502788666131213697322783095070105623107215331596699973092056135872020480;
assert(opinion == MINUS_ONE | opinion == 1, 'opinion must be either 1 or -1');
let gov_token_addr = governance_token_address::read();
let caller_addr = get_caller_address();
let curr_vote_status: felt252 = proposal_voted_by::read((prop_id, caller_addr));
assert(curr_vote_status == 0, 'already voted');
let caller_balance_u256: u256 = IERC20Dispatcher {
contract_address: gov_token_addr
}.balanceOf(caller_addr);
assert(caller_balance_u256.high == 0_u128, 'CARM balance > u128');
let caller_balance: u128 = caller_balance_u256.low;
assert(caller_balance != 0_u128, 'CARM balance is zero');
assert_voting_in_progress(prop_id);
// Cast vote
proposal_voted_by::write((prop_id, caller_addr), opinion);
if opinion == MINUS_ONE {
let curr_votes: u128 = proposal_total_nay::read(prop_id).try_into().unwrap();
let new_votes: u128 = curr_votes + caller_balance;
assert(new_votes >= 0_u128, 'new_votes must be non-negative');
proposal_total_nay::write(prop_id, new_votes.into());
} else {
let curr_votes: u128 = proposal_total_nay::read(prop_id).try_into().unwrap();
let new_votes: u128 = curr_votes + caller_balance;
assert(new_votes >= 0_u128, 'new_votes must be non-negative');
proposal_total_yay::write(prop_id, new_votes.into());
}
Governance::Voted(prop_id, caller_addr, opinion);
}
</c1><c0>
func check_proposal_passed_express{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
prop_id: felt
) -> (res: felt) {
alloc_locals;
let (gov_token_addr) = governance_token_address.read();
let (yay_tally) = proposal_total_yay.read(prop_id);
let (total_eligible_votes_from_tokenholders) = IERC20.totalSupply(contract_address=gov_token_addr);
let TWO = Uint256(low = 2, high = 0);
let (intermediate, carry) = uint256_mul(total_eligible_votes_from_tokenholders, TWO);
with_attr error_message("check_proposal_passed_express: overflow"){
assert carry.low = 0;
assert carry.high = 0;
}
let THREE = Uint256(low = 3, high = 0);
let (minimum_for_express, _) = uint256_unsigned_div_rem(intermediate, THREE);
let yay_tally_uint256 = intToUint256(yay_tally);
let (cmp_res) = uint256_lt(minimum_for_express, yay_tally_uint256);
if(cmp_res == 1){
return (res=1);
}
return (res=0);
}
</c0><c1>
fn check_proposal_passed_express(prop_id: felt252) -> u8 {
let gov_token_addr = governance_token_address::read();
let yay_tally_felt: felt252 = proposal_total_yay::read(prop_id);
let yay_tally: u128 = yay_tally_felt.try_into().unwrap();
let total_eligible_votes_from_tokenholders_u256: u256 = IERC20Dispatcher {
contract_address: gov_token_addr
}.totalSupply();
let total_eligible_votes_from_tokenholders: u128 = total_eligible_votes_from_tokenholders_u256.low;
let minimum_for_express: u128 = total_eligible_votes_from_tokenholders * 2_u128 / 3_u128;
// Check if yay_tally >= minimum_for_express
if yay_tally >= minimum_for_express {
1_u8
} else {
0_u8
}
}
</c1><c0>
func add_and_check_bounds{range_check_ptr}(a: felt, b: felt) -> (res: felt) {
let sum = a + b;
assert_nn(sum);
return (res=sum);
}
</c0><c1>
fn add_and_check_bounds(a: felt252, b: felt252) -> felt252 {
let a_u128: u128 = a.try_into().unwrap();
let b_u128: u128 = b.try_into().unwrap();
let sum_u128 = (a_u128 + b_u128).expect('addition overflow');
sum_u128.into()
}
</c1><c0>
func fibonacci{range_check_ptr}(n: felt) -> (fib: felt) {
if (n == 0) {
return (fib=0);
}
if (n == 1) {
return (fib=1);
}
let fib1 = fibonacci(n - 1);
let fib2 = fibonacci(n - 2);
let sum = fib1.fib + fib2.fib;
assert_nn(sum);
return (fib=sum);
}
</c0><c1>
fn fibonacci(n: u64) -> u64 {
if n == 0 {
0
} else if n == 1 {
1
} else {
let n_minus_1 = n - 1;
let n_minus_2 = n - 2;
let fib1 = fibonacci(n_minus_1);
let fib2 = fibonacci(n_minus_2);
let sum = fib1 + fib2;
sum
}
}
</c1>
Above is are examples of code rewritten from c0, a smart contract language inspired by Python, to c1, very different, inspired by Rust.
c1 ( = <c1>) has a few peculiarities you must attend to. Comparison operations are not supported on the felt (c0) = felt252 (c1) data type, you must convert to uint first. As u256 is represented as two separate felts, it's better to use u128 for efficiency. Arithmetic operations are defined only between variables of the same data type, not between say u64 and u128, so conversions are often needed. There are the following unsigned integer data types in c1: u8 u16 u32 u64 u128 u256, they automatically check for overflows.
Now, is everything clear about the syntax differences? Look at the examples above.