Ton

Форк
0
414 строк · 10.4 Кб
1
;;
2
;; Stake Sending
3
;;
4

5
() op_controller_stake_send(int value, slice in_msg) impure {
6

7
    ;; Parse message
8
    var stake = in_msg~load_coins();
9
    var validator_pubkey = in_msg~load_uint(256);
10
    var stake_at = in_msg~load_uint(32);
11
    var max_factor = in_msg~load_uint(32);
12
    var adnl_addr = in_msg~load_uint(256);
13
    var signature_ref = in_msg~load_ref();
14
    var signature = signature_ref.begin_parse().preload_bits(512);
15
    in_msg.end_parse();
16

17
    ;; Check message value
18
    throw_unless(error::invalid_message(), value >= fees::stake_fees());
19

20
    ;; Allow only single request to elector
21
    if (proxy_stored_query_id != 0) {
22
        throw(error::invalid_message());
23
    }
24

25
    ;; Allow update only for current stake
26
    if ((proxy_stake_at != 0) & (proxy_stake_at != stake_at)) {
27
        throw(error::invalid_message());
28
    }
29

30
    ;; Check stake value
31
    var availableStake = available_to_stake();
32
    throw_unless(error::invalid_stake_value(), availableStake >= stake);
33

34
    ;; Parameters
35
    var (electedFor, stakeHeldFor) = get_stake_parameters();
36

37
    ;; Lock stakes
38
    on_locked();
39
    
40
    ;; Update operation state
41
    proxy_stake_at = stake_at;
42
    proxy_stake_until = stake_at + electedFor + stakeHeldFor;
43
    proxy_stake_sent = proxy_stake_sent + stake;
44
    proxy_stored_query_id = ctx_query_id;
45
    proxy_stored_query_op = elector::stake::request();
46
    proxy_stored_query_stake = stake;
47

48
    ;; Update balances
49
    on_stake_sent(stake);
50

51
    ;; Send message to elector
52
    send_std_message(
53
        ctx_proxy, 
54
        stake + coins::1(), 
55
        send_mode::separate_gas(), 
56
        elector::stake::request(), 
57
        proxy_stored_query_id, 
58
        begin_cell()
59
            .store_uint(validator_pubkey, 256)
60
            .store_uint(stake_at, 32)
61
            .store_uint(max_factor, 32)
62
            .store_uint(adnl_addr, 256)
63
            .store_ref(signature_ref)
64
    );
65

66
    ;; Persist
67
    store_validator_data();
68
    store_base_data();
69
}
70

71
() op_elector_stake_response(int value, slice in_msg) impure {
72

73
    ;; Check response
74
    if (ctx_query_id != proxy_stored_query_id) {
75
        ;; How to handle invalid? How it is possible?
76
        return ();
77
    }
78
    if (proxy_stored_query_op != elector::stake::request()) {
79
        ;; How to handle invalid? How it is possible?
80
        return ();
81
    }
82

83
    ;; Reset active query
84
    proxy_stored_query_id = 0;
85
    proxy_stored_query_op = 0;
86
    proxy_stored_query_stake = 0;
87

88
    ;; Persist
89
    store_validator_data();
90
    store_base_data();
91
}
92

93
() op_elector_stake_response_fail(int value, slice in_msg) impure {
94

95
    ;; Load reason
96
    var reason = in_msg~load_uint(32);
97

98
    ;; Check response
99
    if (ctx_query_id != proxy_stored_query_id) {
100
        ;; How to handle invalid? How it is possible?
101
        return ();
102
    }
103
    if (proxy_stored_query_op != elector::stake::request()) {
104
        ;; How to handle invalid? How it is possible?
105
        return ();
106
    }
107

108
    ;; Update balances
109
    on_stake_sent_failed(proxy_stored_query_stake);
110

111
    ;; Update proxy state
112
    proxy_stake_sent = proxy_stake_sent - proxy_stored_query_stake;
113

114
    ;; Reset stake at since sent stake became zero
115
    if (proxy_stake_sent == 0) {
116
        proxy_stake_at = 0;
117
        proxy_stake_until = 0;
118
        proxy_stake_sent = 0;
119
        on_unlocked();
120
    }
121

122
    ;; Reset query
123
    proxy_stored_query_id = 0;
124
    proxy_stored_query_op = 0;
125
    proxy_stored_query_stake = 0;
126

127
    ;; Persist
128
    store_validator_data();
129
    store_base_data();
130
}
131

132
;;
133
;; Recover
134
;;
135

136
() op_stake_recover(int value) impure {
137

138
    ;; NOTE: We never block stake recover operation
139
    ;;       in case of misbehaviour of something anyone always can get 
140
    ;;       coins from elector after lockup period is up
141

142
    ;; Allow request only if stake is exited lockup period
143
    if ((proxy_stake_until != 0) & (now() < proxy_stake_until)) {
144
        throw(error::invalid_message());
145
    }
146

147
    ;; Double check that validation session and lockup was lifted
148
    if ((proxy_stake_until != 0) & (proxy_stake_at != 0)) {
149
        throw_unless(error::invalid_message(), lockup_lift_time(proxy_stake_at, proxy_stake_until) <= now());
150
    }
151

152
    ;; Check value
153
    throw_unless(error::too_low_value(), value >= fees::stake_fees());
154

155
    ;; Send message to elector
156
    send_empty_std_message(
157
        ctx_proxy, 
158
        0, 
159
        send_mode::carry_remaining_value(),
160
        elector::refund::request(), 
161
        proxy_stored_query_id
162
    );
163

164
    ;; Persist
165
    store_validator_data();
166
    store_base_data();
167
}
168

169
() op_elector_recover_response(int value, slice in_msg) impure {
170

171
    if ((proxy_stake_until != 0) & (now() > proxy_stake_until)) {
172
        
173
        ;; Reset state: all stake is returned
174
        proxy_stake_sent = 0;
175
        proxy_stake_at = 0;
176
        proxy_stake_until = 0;
177

178
        ;; Reset query too
179
        proxy_stored_query_id = 0;
180
        proxy_stored_query_op = 0;
181
        proxy_stored_query_stake = 0;
182

183
        ;; Handle stake recovered event
184
        ;; NOTE: Any stake recovery outside this condition might be just a noise and 
185
        ;;       effect of various race condirtions that doesn't carry any substantianal vakue
186
        on_stake_recovered(value - fees::stake_fees());
187

188
        ;; Reset lock state
189
        ;; NOTE: MUST be after on_stake_recovered since it adjusts withdrawals and 
190
        ;;       modifies global balance
191
        on_unlocked();
192
    }
193

194
    ;; Persist
195
    store_validator_data();
196
    store_base_data();
197
}
198

199
;;
200
;; Withdraw unowned
201
;;
202

203
() op_controller_withdraw_unowned(int value, slice in_msg) impure {
204

205
    ;; Reserve owned
206
    raw_reserve(owned_balance(), 0);
207

208
    ;; Send message to controller
209
    send_empty_std_message(
210
        ctx_controller, 
211
        0, 
212
        send_mode::carry_remaining_balance(), 
213
        op::withdraw_unowned::response(), 
214
        ctx_query_id
215
    );
216
}
217

218
;;
219
;; Process pending
220
;;
221

222
() op_controller_accept_stakes(int value, slice in_msg) impure {
223

224
    ;; Check if enought value
225
    throw_unless(error::invalid_message(), value >= params::pending_op());
226

227
    ;; Check if not locked
228
    throw_if(error::invalid_message(), ctx_locked);
229

230
    ;; Parse message
231
    var members = in_msg~load_dict();
232
    in_msg.end_parse();
233

234
    ;; Process operations
235
    var member = -1;
236
    do {
237
        (member, var cs, var f) = members.udict_get_next?(256, member);
238
        if (f) {
239
            ;; Accept member's stake
240
            load_member(member);
241
            member_accept_stake();
242
            store_member();
243
        }
244
    } until (~ f);
245

246
    ;; Persist
247
    store_base_data();
248
}
249

250
() op_controller_accept_withdraws(int value, slice in_msg) impure {
251

252
    ;; Check if enought value
253
    throw_unless(error::invalid_message(), value >= params::pending_op());
254

255
    ;; Check if not locked
256
    throw_if(error::invalid_message(), ctx_locked);
257

258
    ;; Parse message
259
    var members = in_msg~load_dict();
260
    in_msg.end_parse();
261

262
    ;; Process operations
263
    var member = -1;
264
    do {
265
        (member, var cs, var f) = members.udict_get_next?(256, member);
266
        if (f) {
267
            ;; Accept member's stake
268
            load_member(member);
269
            member_accept_withdraw();
270
            store_member();
271
        }
272
    } until (~ f);
273

274
    ;; Persist
275
    store_base_data();
276
}
277

278
() op_controller_force_kick(int value, slice in_msg) impure {
279

280
    ;; Check if enought value
281
    throw_unless(error::invalid_message(), value >= params::pending_op());
282

283
    ;; Check if not locked
284
    throw_if(error::invalid_message(), ctx_locked);
285

286
    ;; Parse message
287
    var members = in_msg~load_dict();
288
    in_msg.end_parse();
289

290
    ;; Process operations
291
    var member = -1;
292
    do {
293
        (member, var cs, var f) = members.udict_get_next?(256, member);
294
        if (f) {
295

296
            ;; Reject owner kicking 
297
            throw_if(error::invalid_message(), member == owner_id());
298

299
            ;; Kick member from a pool
300
            load_member(member);
301

302
            ;; Withdraw everything
303
            var (withdrawed, all) = member_stake_withdraw(0);
304
            throw_unless(error::invalid_message(), withdrawed > 0);
305
            throw_unless(error::invalid_message(), all);
306

307
            ;; Forced kick
308
            send_empty_std_message(
309
                serialize_work_addr(member),
310
                withdrawed,
311
                send_mode::default(),
312
                op::force_kick::notification(),
313
                ctx_query_id
314
            );
315
            
316
            ;; Persist membership
317
            store_member();
318
        }
319
    } until (~ f);
320

321
    ;; Persist
322
    store_base_data();
323
}
324

325
;;
326
;; Top Level
327
;;
328

329
() op_controller(int flags, int value, slice in_msg) impure {
330
    if (flags & 1) {
331
        return ();
332
    }
333

334
    ;; Check value
335
    throw_unless(error::invalid_message(), value >= params::min_op());
336

337
    ;; Parse operation
338
    int op = in_msg~load_uint(32);
339
    int query_id = in_msg~load_uint(64);
340
    int gas_limit = in_msg~load_coins();
341
    set_gas_limit(gas_limit);
342
    ctx_query_id = query_id;
343
    throw_unless(error::invalid_message(), ctx_query_id > 0);
344

345
    ;; Send stake
346
    if (op == op::stake_send()) {
347
        op_controller_stake_send(value, in_msg);
348
        return ();
349
    }
350

351
    ;; Recover stake
352
    if (op == op::stake_recover()) {
353
        op_stake_recover(value);
354
        return ();
355
    }
356

357
    ;; Withdraw unowned
358
    if (op == op::withdraw_unowned()) {
359
        op_controller_withdraw_unowned(value, in_msg);
360
        return ();
361
    }
362

363
    ;; Accept stakes
364
    if (op == op::accept_stakes()) {
365
        op_controller_accept_stakes(value, in_msg);
366
        return ();
367
    }
368

369
    ;; Accept withdraws
370
    if (op == op::accept_withdraws()) {
371
        op_controller_accept_withdraws(value, in_msg);
372
        return ();
373
    }
374

375
    ;; Kick from pool
376
    if (op == op::force_kick()) {
377
        op_controller_force_kick(value, in_msg);
378
        return ();
379
    }
380

381
    ;; Unknown message
382
    throw(error::invalid_message());
383
}
384

385
() op_elector(int flags, int value, slice in_msg) impure {
386
    int op = in_msg~load_uint(32);
387
    int query_id = in_msg~load_uint(64);
388
    ctx_query_id = query_id;
389

390
    ;; Bounced
391
    ;; It seems that handling doesn't make sence sicne there are no throws (?) 
392
    ;; in elector contract
393
    if (flags & 1) {
394
        return ();
395
    }
396

397
    ;; Stake response
398
    if (op == elector::stake::response()) {
399
        op_elector_stake_response(value, in_msg);
400
        return ();
401
    }
402
    if (op == elector::stake::response::fail()) {
403
        op_elector_stake_response_fail(value, in_msg);
404
        return ();
405
    }
406

407
    ;; Refund response
408
    if (op == elector::refund::response()) {
409
        op_elector_recover_response(value, in_msg);
410
        return ();
411
    }
412

413
    ;; Ignore
414
}

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.