1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-15 04:32:21 +00:00
ton/crypto/func/auto-tests/legacy_tests/whales-nominators/modules/op-controller.fc

414 lines
10 KiB
Text
Raw Normal View History

;;
;; Stake Sending
;;
() op_controller_stake_send(int value, slice in_msg) impure {
;; Parse message
var stake = in_msg~load_coins();
var validator_pubkey = in_msg~load_uint(256);
var stake_at = in_msg~load_uint(32);
var max_factor = in_msg~load_uint(32);
var adnl_addr = in_msg~load_uint(256);
var signature_ref = in_msg~load_ref();
var signature = signature_ref.begin_parse().preload_bits(512);
in_msg.end_parse();
;; Check message value
throw_unless(error::invalid_message(), value >= fees::stake_fees());
;; Allow only single request to elector
if (proxy_stored_query_id != 0) {
throw(error::invalid_message());
}
;; Allow update only for current stake
if ((proxy_stake_at != 0) & (proxy_stake_at != stake_at)) {
throw(error::invalid_message());
}
;; Check stake value
var availableStake = available_to_stake();
throw_unless(error::invalid_stake_value(), availableStake >= stake);
;; Parameters
var (electedFor, stakeHeldFor) = get_stake_parameters();
;; Lock stakes
on_locked();
;; Update operation state
proxy_stake_at = stake_at;
proxy_stake_until = stake_at + electedFor + stakeHeldFor;
proxy_stake_sent = proxy_stake_sent + stake;
proxy_stored_query_id = ctx_query_id;
proxy_stored_query_op = elector::stake::request();
proxy_stored_query_stake = stake;
;; Update balances
on_stake_sent(stake);
;; Send message to elector
send_std_message(
ctx_proxy,
stake + coins::1(),
send_mode::separate_gas(),
elector::stake::request(),
proxy_stored_query_id,
begin_cell()
.store_uint(validator_pubkey, 256)
.store_uint(stake_at, 32)
.store_uint(max_factor, 32)
.store_uint(adnl_addr, 256)
.store_ref(signature_ref)
);
;; Persist
store_validator_data();
store_base_data();
}
() op_elector_stake_response(int value, slice in_msg) impure {
;; Check response
if (ctx_query_id != proxy_stored_query_id) {
;; How to handle invalid? How it is possible?
return ();
}
if (proxy_stored_query_op != elector::stake::request()) {
;; How to handle invalid? How it is possible?
return ();
}
;; Reset active query
proxy_stored_query_id = 0;
proxy_stored_query_op = 0;
proxy_stored_query_stake = 0;
;; Persist
store_validator_data();
store_base_data();
}
() op_elector_stake_response_fail(int value, slice in_msg) impure {
;; Load reason
var reason = in_msg~load_uint(32);
;; Check response
if (ctx_query_id != proxy_stored_query_id) {
;; How to handle invalid? How it is possible?
return ();
}
if (proxy_stored_query_op != elector::stake::request()) {
;; How to handle invalid? How it is possible?
return ();
}
;; Update balances
on_stake_sent_failed(proxy_stored_query_stake);
;; Update proxy state
proxy_stake_sent = proxy_stake_sent - proxy_stored_query_stake;
;; Reset stake at since sent stake became zero
if (proxy_stake_sent == 0) {
proxy_stake_at = 0;
proxy_stake_until = 0;
proxy_stake_sent = 0;
on_unlocked();
}
;; Reset query
proxy_stored_query_id = 0;
proxy_stored_query_op = 0;
proxy_stored_query_stake = 0;
;; Persist
store_validator_data();
store_base_data();
}
;;
;; Recover
;;
() op_stake_recover(int value) impure {
;; NOTE: We never block stake recover operation
;; in case of misbehaviour of something anyone always can get
;; coins from elector after lockup period is up
;; Allow request only if stake is exited lockup period
if ((proxy_stake_until != 0) & (now() < proxy_stake_until)) {
throw(error::invalid_message());
}
;; Double check that validation session and lockup was lifted
if ((proxy_stake_until != 0) & (proxy_stake_at != 0)) {
throw_unless(error::invalid_message(), lockup_lift_time(proxy_stake_at, proxy_stake_until) <= now());
}
;; Check value
throw_unless(error::too_low_value(), value >= fees::stake_fees());
;; Send message to elector
send_empty_std_message(
ctx_proxy,
0,
send_mode::carry_remaining_value(),
elector::refund::request(),
proxy_stored_query_id
);
;; Persist
store_validator_data();
store_base_data();
}
() op_elector_recover_response(int value, slice in_msg) impure {
if ((proxy_stake_until != 0) & (now() > proxy_stake_until)) {
;; Reset state: all stake is returned
proxy_stake_sent = 0;
proxy_stake_at = 0;
proxy_stake_until = 0;
;; Reset query too
proxy_stored_query_id = 0;
proxy_stored_query_op = 0;
proxy_stored_query_stake = 0;
;; Handle stake recovered event
;; NOTE: Any stake recovery outside this condition might be just a noise and
;; effect of various race condirtions that doesn't carry any substantianal vakue
on_stake_recovered(value - fees::stake_fees());
;; Reset lock state
;; NOTE: MUST be after on_stake_recovered since it adjusts withdrawals and
;; modifies global balance
on_unlocked();
}
;; Persist
store_validator_data();
store_base_data();
}
;;
;; Withdraw unowned
;;
() op_controller_withdraw_unowned(int value, slice in_msg) impure {
;; Reserve owned
raw_reserve(owned_balance(), 0);
;; Send message to controller
send_empty_std_message(
ctx_controller,
0,
send_mode::carry_remaining_balance(),
op::withdraw_unowned::response(),
ctx_query_id
);
}
;;
;; Process pending
;;
() op_controller_accept_stakes(int value, slice in_msg) impure {
;; Check if enought value
throw_unless(error::invalid_message(), value >= params::pending_op());
;; Check if not locked
throw_if(error::invalid_message(), ctx_locked);
;; Parse message
var members = in_msg~load_dict();
in_msg.end_parse();
;; Process operations
var member = -1;
do {
(member, var cs, var f) = members.udict_get_next?(256, member);
if (f) {
;; Accept member's stake
load_member(member);
member_accept_stake();
store_member();
}
} until (~ f);
;; Persist
store_base_data();
}
() op_controller_accept_withdraws(int value, slice in_msg) impure {
;; Check if enought value
throw_unless(error::invalid_message(), value >= params::pending_op());
;; Check if not locked
throw_if(error::invalid_message(), ctx_locked);
;; Parse message
var members = in_msg~load_dict();
in_msg.end_parse();
;; Process operations
var member = -1;
do {
(member, var cs, var f) = members.udict_get_next?(256, member);
if (f) {
;; Accept member's stake
load_member(member);
member_accept_withdraw();
store_member();
}
} until (~ f);
;; Persist
store_base_data();
}
() op_controller_force_kick(int value, slice in_msg) impure {
;; Check if enought value
throw_unless(error::invalid_message(), value >= params::pending_op());
;; Check if not locked
throw_if(error::invalid_message(), ctx_locked);
;; Parse message
var members = in_msg~load_dict();
in_msg.end_parse();
;; Process operations
var member = -1;
do {
(member, var cs, var f) = members.udict_get_next?(256, member);
if (f) {
;; Reject owner kicking
throw_if(error::invalid_message(), member == owner_id());
;; Kick member from a pool
load_member(member);
;; Withdraw everything
var (withdrawed, all) = member_stake_withdraw(0);
throw_unless(error::invalid_message(), withdrawed > 0);
throw_unless(error::invalid_message(), all);
;; Forced kick
send_empty_std_message(
serialize_work_addr(member),
withdrawed,
send_mode::default(),
op::force_kick::notification(),
ctx_query_id
);
;; Persist membership
store_member();
}
} until (~ f);
;; Persist
store_base_data();
}
;;
;; Top Level
;;
() op_controller(int flags, int value, slice in_msg) impure {
if (flags & 1) {
return ();
}
;; Check value
throw_unless(error::invalid_message(), value >= params::min_op());
;; Parse operation
int op = in_msg~load_uint(32);
int query_id = in_msg~load_uint(64);
int gas_limit = in_msg~load_coins();
set_gas_limit(gas_limit);
ctx_query_id = query_id;
throw_unless(error::invalid_message(), ctx_query_id > 0);
;; Send stake
if (op == op::stake_send()) {
op_controller_stake_send(value, in_msg);
return ();
}
;; Recover stake
if (op == op::stake_recover()) {
op_stake_recover(value);
return ();
}
;; Withdraw unowned
if (op == op::withdraw_unowned()) {
op_controller_withdraw_unowned(value, in_msg);
return ();
}
;; Accept stakes
if (op == op::accept_stakes()) {
op_controller_accept_stakes(value, in_msg);
return ();
}
;; Accept withdraws
if (op == op::accept_withdraws()) {
op_controller_accept_withdraws(value, in_msg);
return ();
}
;; Kick from pool
if (op == op::force_kick()) {
op_controller_force_kick(value, in_msg);
return ();
}
;; Unknown message
throw(error::invalid_message());
}
() op_elector(int flags, int value, slice in_msg) impure {
int op = in_msg~load_uint(32);
int query_id = in_msg~load_uint(64);
ctx_query_id = query_id;
;; Bounced
;; It seems that handling doesn't make sence sicne there are no throws (?)
;; in elector contract
if (flags & 1) {
return ();
}
;; Stake response
if (op == elector::stake::response()) {
op_elector_stake_response(value, in_msg);
return ();
}
if (op == elector::stake::response::fail()) {
op_elector_stake_response_fail(value, in_msg);
return ();
}
;; Refund response
if (op == elector::refund::response()) {
op_elector_recover_response(value, in_msg);
return ();
}
;; Ignore
}