mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-15 04:32:21 +00:00
* Add legacy_tester for existing funC contracts * Add storage-contracts and pragma options
297 lines
No EOL
8.8 KiB
Text
297 lines
No EOL
8.8 KiB
Text
;;
|
|
;; Low level operations
|
|
;;
|
|
|
|
() add_member_pending_withdraw(int delta) impure inline {
|
|
ctx_balance_pending_withdraw = ctx_balance_pending_withdraw + delta;
|
|
ctx_member_pending_withdraw = ctx_member_pending_withdraw + delta;
|
|
}
|
|
() set_member_pending_withdraw(int value) impure inline {
|
|
add_member_pending_withdraw(value - ctx_member_pending_withdraw);
|
|
}
|
|
|
|
() add_member_pending_deposit(int delta) impure inline {
|
|
ctx_member_pending_deposit = ctx_member_pending_deposit + delta;
|
|
ctx_balance_pending_deposits = ctx_balance_pending_deposits + delta;
|
|
}
|
|
() set_member_pending_deposit(int value) impure inline {
|
|
add_member_pending_deposit(value - ctx_member_pending_deposit);
|
|
}
|
|
|
|
int compose_profit(int a, int b) {
|
|
;; (a + 1) * (b + 1) - 1
|
|
return (((a + params::ppc_precision()) * (b + params::ppc_precision())) / params::ppc_precision()) - params::ppc_precision(); ;; NOTE: Rounded down
|
|
}
|
|
|
|
int apply_profit(int value, int value_profit, int profit) {
|
|
return ((params::ppc_precision() + profit) * value) / (params::ppc_precision() + value_profit); ;; NOTE: Rounded down
|
|
}
|
|
|
|
;;
|
|
;; Deposit
|
|
;;
|
|
|
|
() member_update_balance() impure {
|
|
|
|
;; Update profit (for non-owner)
|
|
if (ctx_member != owner_id()) {
|
|
if (ctx_profit_per_coin != ctx_member_profit_per_coin) {
|
|
int new_balance = apply_profit(ctx_member_balance, ctx_member_profit_per_coin, ctx_profit_per_coin);
|
|
int delta_balance = new_balance - ctx_member_balance;
|
|
ctx_member_balance = ctx_member_balance + delta_balance;
|
|
ctx_member_profit_per_coin = ctx_profit_per_coin;
|
|
}
|
|
}
|
|
|
|
;; Update pending withdraw
|
|
if (ctx_member_pending_withdraw_all) {
|
|
if (ctx_member_pending_withdraw != ctx_member_balance) {
|
|
set_member_pending_withdraw(ctx_member_balance);
|
|
}
|
|
} else {
|
|
if (ctx_member_pending_withdraw > ctx_member_balance) {
|
|
set_member_pending_withdraw(ctx_member_balance);
|
|
}
|
|
}
|
|
}
|
|
|
|
() member_reset_pending_withdraw() impure {
|
|
set_member_pending_withdraw(0);
|
|
ctx_member_pending_withdraw_all = false;
|
|
}
|
|
|
|
() member_stake_deposit(int value) impure {
|
|
throw_unless(error::invalid_stake_value(), value > 0);
|
|
|
|
;; Update balances
|
|
member_update_balance();
|
|
|
|
;; Reset pending withdrawal
|
|
member_reset_pending_withdraw();
|
|
|
|
;; Add deposit to pending
|
|
;; NOTE: We are not adding directly deposit to member's balance
|
|
;; and we are always confirming acception of deposit to a pool
|
|
;; via sending accept message. This could be done on- and off-chain.
|
|
;; This could be useful to make private nominator pools or black lists.
|
|
;; Anyone always could withdraw their deposits though.
|
|
add_member_pending_deposit(value);
|
|
}
|
|
|
|
() member_accept_stake() impure {
|
|
|
|
;; Checks if there are pending deposits
|
|
throw_unless(error::invalid_message(), ctx_member_pending_deposit > 0);
|
|
|
|
;; Check if not locked
|
|
throw_if(error::invalid_message(), ctx_locked);
|
|
|
|
;; Recalculate balance
|
|
member_update_balance();
|
|
|
|
;; Move deposit to member's balance
|
|
var amount = ctx_member_pending_deposit;
|
|
set_member_pending_deposit(0);
|
|
|
|
|
|
ctx_member_balance = ctx_member_balance + amount;
|
|
ctx_balance = ctx_balance + amount;
|
|
}
|
|
|
|
;;
|
|
;; Withdraw
|
|
;;
|
|
|
|
(int, int) member_stake_withdraw(int value) impure {
|
|
|
|
;; Check input
|
|
throw_unless(error::invalid_stake_value(), value >= 0);
|
|
|
|
;; Update balances
|
|
member_update_balance();
|
|
|
|
;; Reset pending withdrawal: would be overwritten later
|
|
member_reset_pending_withdraw();
|
|
|
|
;; Pre-flight withdraw check
|
|
throw_unless(error::invalid_stake_value(), value >= 0);
|
|
throw_unless(error::invalid_stake_value(), ctx_member_balance + ctx_member_withdraw + ctx_member_pending_deposit >= value);
|
|
|
|
;; Check withdraw all
|
|
var withdraw_all = false;
|
|
if (value == 0) {
|
|
withdraw_all = true;
|
|
value = ctx_member_pending_deposit + ctx_member_balance + ctx_member_withdraw;
|
|
}
|
|
|
|
;; Trying to withdraw immediatelly
|
|
var remaining = value;
|
|
var withdrawed = 0;
|
|
|
|
;; Try to withdraw from pending deposit
|
|
if ((remaining > 0) & (ctx_member_pending_deposit >= 0)) {
|
|
int delta = min(ctx_member_pending_deposit, remaining);
|
|
add_member_pending_deposit(- delta);
|
|
withdrawed = withdrawed + delta;
|
|
remaining = remaining - delta;
|
|
}
|
|
|
|
;; Try to withdraw from withdraw balance
|
|
if ((remaining > 0) & ctx_member_withdraw > 0) {
|
|
int delta = min(ctx_member_withdraw, remaining);
|
|
ctx_member_withdraw = ctx_member_withdraw - delta;
|
|
ctx_balance_withdraw = ctx_balance_withdraw - delta;
|
|
withdrawed = withdrawed + delta;
|
|
remaining = remaining - delta;
|
|
}
|
|
|
|
;; Try to withdraw from balance
|
|
if ((remaining > 0) & (~ ctx_locked) & (ctx_member_balance > 0)) {
|
|
int delta = min(ctx_member_balance, remaining);
|
|
ctx_member_balance = ctx_member_balance - delta;
|
|
ctx_balance = ctx_balance - delta;
|
|
withdrawed = withdrawed + delta;
|
|
remaining = remaining - delta;
|
|
}
|
|
|
|
;; Add to pending withdrawals
|
|
if (remaining > 0) {
|
|
add_member_pending_withdraw(remaining);
|
|
ctx_member_pending_withdraw_all = withdraw_all;
|
|
}
|
|
|
|
;; Return withdraw result
|
|
return (withdrawed, remaining == 0);
|
|
}
|
|
|
|
() member_accept_withdraw() impure {
|
|
|
|
;; Checks if there are pending withdrawals
|
|
throw_unless(error::invalid_message(), ctx_member_pending_withdraw > 0);
|
|
|
|
;; Check if not locked
|
|
throw_if(error::invalid_message(), ctx_locked);
|
|
|
|
;; Recalculate balance
|
|
member_update_balance();
|
|
|
|
;; Move deposit to member's balance
|
|
var amount = ctx_member_pending_withdraw;
|
|
|
|
ctx_member_balance = ctx_member_balance - amount;
|
|
ctx_member_withdraw = ctx_member_withdraw + amount;
|
|
ctx_balance = ctx_balance - amount;
|
|
ctx_balance_withdraw = ctx_balance_withdraw + amount;
|
|
ctx_balance_pending_withdraw = ctx_balance_pending_withdraw - amount;
|
|
ctx_member_pending_withdraw = 0;
|
|
ctx_member_pending_withdraw_all = false;
|
|
}
|
|
|
|
() distribute_profit(int profit) impure {
|
|
|
|
;; Load extras
|
|
var (enabled, udpates_enabled, min_stake, deposit_fee, withdraw_fee, pool_fee, receipt_price) = ctx_extras;
|
|
|
|
;; Load owner balances
|
|
load_member(0);
|
|
|
|
;; Loss
|
|
if (profit < 0) {
|
|
|
|
;; Stakes
|
|
var owner_stake = ctx_member_balance;
|
|
var nominators_stake = ctx_balance - owner_stake;
|
|
|
|
;; Distribute loss to everyone
|
|
var cycleProfitPerCoin = profit * params::ppc_precision() / ctx_balance;
|
|
var nominators_profit = (nominators_stake * cycleProfitPerCoin) / params::ppc_precision();
|
|
var owner_profit = profit - nominators_profit;
|
|
|
|
;; Update balances
|
|
ctx_balance = ctx_balance + profit;
|
|
ctx_member_balance = ctx_member_balance + owner_profit;
|
|
ctx_profit_per_coin = compose_profit(ctx_profit_per_coin, cycleProfitPerCoin);
|
|
|
|
;; Persist
|
|
store_member();
|
|
|
|
return ();
|
|
}
|
|
|
|
;; Profit
|
|
if (profit > 0) {
|
|
|
|
;; Stakes
|
|
var owner_stake = ctx_member_balance;
|
|
var nominators_stake = ctx_balance - owner_stake;
|
|
|
|
;; Distribute profit
|
|
var cycleProfitPerCoin = profit * params::ppc_precision() * (100 * 100 - pool_fee) / (ctx_balance * 100 * 100);
|
|
var nominators_profit = (nominators_stake * cycleProfitPerCoin) / params::ppc_precision();
|
|
var owner_profit = profit - nominators_profit;
|
|
|
|
;; Update balances
|
|
ctx_balance = ctx_balance + profit;
|
|
ctx_member_balance = ctx_member_balance + owner_profit;
|
|
ctx_profit_per_coin = compose_profit(ctx_profit_per_coin, cycleProfitPerCoin);
|
|
|
|
;; Persist
|
|
store_member();
|
|
|
|
return ();
|
|
}
|
|
}
|
|
|
|
;;
|
|
;; Validator
|
|
;;
|
|
|
|
() on_locked() impure {
|
|
if (~ ctx_locked) {
|
|
|
|
;; Allow locking only on no pending withdrawals
|
|
throw_unless(error::invalid_message(), ctx_balance_pending_withdraw == 0);
|
|
|
|
;; Update state
|
|
ctx_locked = true;
|
|
}
|
|
}
|
|
|
|
() on_unlocked() impure {
|
|
if (ctx_locked) {
|
|
|
|
;; Update state
|
|
ctx_locked = false;
|
|
}
|
|
}
|
|
|
|
int available_to_stake() {
|
|
return ctx_balance - ctx_balance_sent;
|
|
}
|
|
|
|
int owned_balance() {
|
|
return ctx_balance - ctx_balance_sent + ctx_balance_pending_deposits + ctx_balance_withdraw + fees::storage_reserve();
|
|
}
|
|
|
|
() on_stake_sent(int stake) impure {
|
|
ctx_balance_sent = ctx_balance_sent + stake;
|
|
}
|
|
|
|
() on_stake_sent_failed(int stake) impure {
|
|
ctx_balance_sent = ctx_balance_sent - stake;
|
|
}
|
|
|
|
() on_stake_recovered(int stake) impure {
|
|
|
|
;; Calculate profit
|
|
;; NOTE: ctx_locked is true meaning that ctx_balance
|
|
;; have the same value as was when stake was sent
|
|
;; balances are going to be unlocked after profit distribution
|
|
var profit = stake - ctx_balance_sent;
|
|
|
|
;; Distribute profit
|
|
distribute_profit(profit);
|
|
|
|
;; Reset sent amount
|
|
ctx_balance_sent = 0;
|
|
} |