Ton
297 строк · 8.8 Кб
1;;
2;; Low level operations
3;;
4
5() add_member_pending_withdraw(int delta) impure inline {
6ctx_balance_pending_withdraw = ctx_balance_pending_withdraw + delta;
7ctx_member_pending_withdraw = ctx_member_pending_withdraw + delta;
8}
9() set_member_pending_withdraw(int value) impure inline {
10add_member_pending_withdraw(value - ctx_member_pending_withdraw);
11}
12
13() add_member_pending_deposit(int delta) impure inline {
14ctx_member_pending_deposit = ctx_member_pending_deposit + delta;
15ctx_balance_pending_deposits = ctx_balance_pending_deposits + delta;
16}
17() set_member_pending_deposit(int value) impure inline {
18add_member_pending_deposit(value - ctx_member_pending_deposit);
19}
20
21int compose_profit(int a, int b) {
22;; (a + 1) * (b + 1) - 1
23return (((a + params::ppc_precision()) * (b + params::ppc_precision())) / params::ppc_precision()) - params::ppc_precision(); ;; NOTE: Rounded down
24}
25
26int apply_profit(int value, int value_profit, int profit) {
27return ((params::ppc_precision() + profit) * value) / (params::ppc_precision() + value_profit); ;; NOTE: Rounded down
28}
29
30;;
31;; Deposit
32;;
33
34() member_update_balance() impure {
35
36;; Update profit (for non-owner)
37if (ctx_member != owner_id()) {
38if (ctx_profit_per_coin != ctx_member_profit_per_coin) {
39int new_balance = apply_profit(ctx_member_balance, ctx_member_profit_per_coin, ctx_profit_per_coin);
40int delta_balance = new_balance - ctx_member_balance;
41ctx_member_balance = ctx_member_balance + delta_balance;
42ctx_member_profit_per_coin = ctx_profit_per_coin;
43}
44}
45
46;; Update pending withdraw
47if (ctx_member_pending_withdraw_all) {
48if (ctx_member_pending_withdraw != ctx_member_balance) {
49set_member_pending_withdraw(ctx_member_balance);
50}
51} else {
52if (ctx_member_pending_withdraw > ctx_member_balance) {
53set_member_pending_withdraw(ctx_member_balance);
54}
55}
56}
57
58() member_reset_pending_withdraw() impure {
59set_member_pending_withdraw(0);
60ctx_member_pending_withdraw_all = false;
61}
62
63() member_stake_deposit(int value) impure {
64throw_unless(error::invalid_stake_value(), value > 0);
65
66;; Update balances
67member_update_balance();
68
69;; Reset pending withdrawal
70member_reset_pending_withdraw();
71
72;; Add deposit to pending
73;; NOTE: We are not adding directly deposit to member's balance
74;; and we are always confirming acception of deposit to a pool
75;; via sending accept message. This could be done on- and off-chain.
76;; This could be useful to make private nominator pools or black lists.
77;; Anyone always could withdraw their deposits though.
78add_member_pending_deposit(value);
79}
80
81() member_accept_stake() impure {
82
83;; Checks if there are pending deposits
84throw_unless(error::invalid_message(), ctx_member_pending_deposit > 0);
85
86;; Check if not locked
87throw_if(error::invalid_message(), ctx_locked);
88
89;; Recalculate balance
90member_update_balance();
91
92;; Move deposit to member's balance
93var amount = ctx_member_pending_deposit;
94set_member_pending_deposit(0);
95
96
97ctx_member_balance = ctx_member_balance + amount;
98ctx_balance = ctx_balance + amount;
99}
100
101;;
102;; Withdraw
103;;
104
105(int, int) member_stake_withdraw(int value) impure {
106
107;; Check input
108throw_unless(error::invalid_stake_value(), value >= 0);
109
110;; Update balances
111member_update_balance();
112
113;; Reset pending withdrawal: would be overwritten later
114member_reset_pending_withdraw();
115
116;; Pre-flight withdraw check
117throw_unless(error::invalid_stake_value(), value >= 0);
118throw_unless(error::invalid_stake_value(), ctx_member_balance + ctx_member_withdraw + ctx_member_pending_deposit >= value);
119
120;; Check withdraw all
121var withdraw_all = false;
122if (value == 0) {
123withdraw_all = true;
124value = ctx_member_pending_deposit + ctx_member_balance + ctx_member_withdraw;
125}
126
127;; Trying to withdraw immediatelly
128var remaining = value;
129var withdrawed = 0;
130
131;; Try to withdraw from pending deposit
132if ((remaining > 0) & (ctx_member_pending_deposit >= 0)) {
133int delta = min(ctx_member_pending_deposit, remaining);
134add_member_pending_deposit(- delta);
135withdrawed = withdrawed + delta;
136remaining = remaining - delta;
137}
138
139;; Try to withdraw from withdraw balance
140if ((remaining > 0) & ctx_member_withdraw > 0) {
141int delta = min(ctx_member_withdraw, remaining);
142ctx_member_withdraw = ctx_member_withdraw - delta;
143ctx_balance_withdraw = ctx_balance_withdraw - delta;
144withdrawed = withdrawed + delta;
145remaining = remaining - delta;
146}
147
148;; Try to withdraw from balance
149if ((remaining > 0) & (~ ctx_locked) & (ctx_member_balance > 0)) {
150int delta = min(ctx_member_balance, remaining);
151ctx_member_balance = ctx_member_balance - delta;
152ctx_balance = ctx_balance - delta;
153withdrawed = withdrawed + delta;
154remaining = remaining - delta;
155}
156
157;; Add to pending withdrawals
158if (remaining > 0) {
159add_member_pending_withdraw(remaining);
160ctx_member_pending_withdraw_all = withdraw_all;
161}
162
163;; Return withdraw result
164return (withdrawed, remaining == 0);
165}
166
167() member_accept_withdraw() impure {
168
169;; Checks if there are pending withdrawals
170throw_unless(error::invalid_message(), ctx_member_pending_withdraw > 0);
171
172;; Check if not locked
173throw_if(error::invalid_message(), ctx_locked);
174
175;; Recalculate balance
176member_update_balance();
177
178;; Move deposit to member's balance
179var amount = ctx_member_pending_withdraw;
180
181ctx_member_balance = ctx_member_balance - amount;
182ctx_member_withdraw = ctx_member_withdraw + amount;
183ctx_balance = ctx_balance - amount;
184ctx_balance_withdraw = ctx_balance_withdraw + amount;
185ctx_balance_pending_withdraw = ctx_balance_pending_withdraw - amount;
186ctx_member_pending_withdraw = 0;
187ctx_member_pending_withdraw_all = false;
188}
189
190() distribute_profit(int profit) impure {
191
192;; Load extras
193var (enabled, udpates_enabled, min_stake, deposit_fee, withdraw_fee, pool_fee, receipt_price) = ctx_extras;
194
195;; Load owner balances
196load_member(0);
197
198;; Loss
199if (profit < 0) {
200
201;; Stakes
202var owner_stake = ctx_member_balance;
203var nominators_stake = ctx_balance - owner_stake;
204
205;; Distribute loss to everyone
206var cycleProfitPerCoin = profit * params::ppc_precision() / ctx_balance;
207var nominators_profit = (nominators_stake * cycleProfitPerCoin) / params::ppc_precision();
208var owner_profit = profit - nominators_profit;
209
210;; Update balances
211ctx_balance = ctx_balance + profit;
212ctx_member_balance = ctx_member_balance + owner_profit;
213ctx_profit_per_coin = compose_profit(ctx_profit_per_coin, cycleProfitPerCoin);
214
215;; Persist
216store_member();
217
218return ();
219}
220
221;; Profit
222if (profit > 0) {
223
224;; Stakes
225var owner_stake = ctx_member_balance;
226var nominators_stake = ctx_balance - owner_stake;
227
228;; Distribute profit
229var cycleProfitPerCoin = profit * params::ppc_precision() * (100 * 100 - pool_fee) / (ctx_balance * 100 * 100);
230var nominators_profit = (nominators_stake * cycleProfitPerCoin) / params::ppc_precision();
231var owner_profit = profit - nominators_profit;
232
233;; Update balances
234ctx_balance = ctx_balance + profit;
235ctx_member_balance = ctx_member_balance + owner_profit;
236ctx_profit_per_coin = compose_profit(ctx_profit_per_coin, cycleProfitPerCoin);
237
238;; Persist
239store_member();
240
241return ();
242}
243}
244
245;;
246;; Validator
247;;
248
249() on_locked() impure {
250if (~ ctx_locked) {
251
252;; Allow locking only on no pending withdrawals
253throw_unless(error::invalid_message(), ctx_balance_pending_withdraw == 0);
254
255;; Update state
256ctx_locked = true;
257}
258}
259
260() on_unlocked() impure {
261if (ctx_locked) {
262
263;; Update state
264ctx_locked = false;
265}
266}
267
268int available_to_stake() {
269return ctx_balance - ctx_balance_sent;
270}
271
272int owned_balance() {
273return ctx_balance - ctx_balance_sent + ctx_balance_pending_deposits + ctx_balance_withdraw + fees::storage_reserve();
274}
275
276() on_stake_sent(int stake) impure {
277ctx_balance_sent = ctx_balance_sent + stake;
278}
279
280() on_stake_sent_failed(int stake) impure {
281ctx_balance_sent = ctx_balance_sent - stake;
282}
283
284() on_stake_recovered(int stake) impure {
285
286;; Calculate profit
287;; NOTE: ctx_locked is true meaning that ctx_balance
288;; have the same value as was when stake was sent
289;; balances are going to be unlocked after profit distribution
290var profit = stake - ctx_balance_sent;
291
292;; Distribute profit
293distribute_profit(profit);
294
295;; Reset sent amount
296ctx_balance_sent = 0;
297}