forked from Tonnel-Network/core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
stake.fc
168 lines (138 loc) · 7.05 KB
/
stake.fc
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
#include "staking/storage.fc";
#include "jetton/imports/jetton-utils.fc";
#include "jetton/imports/op-codes.fc";
() send_jetton(slice recepient, int amount, slice JETTON_MASTER_ADDRESS, cell JETTON_BYTE_CODE) impure inline {
slice jetton_wallet = calculate_user_jetton_wallet_address(my_address(), JETTON_MASTER_ADDRESS, JETTON_BYTE_CODE);
var msg = begin_cell()
.store_uint(0x18, 6) ;; nobounce - int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool src:MsgAddress -> 011000
.store_slice(jetton_wallet)
.store_coins(const::tx_fee_send_jetton)
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
.store_uint(op::transfer(), 32)
.store_uint(0, 64)
.store_coins(amount)
.store_slice(recepient)
.store_uint(0, 2)
.store_uint(0, 1)
.store_coins(0)
.store_uint(0, 1);
send_raw_message(msg.end_cell(), 1); ;; paying fees, revert on errors
}
() send_ton(slice recepient, int amount) impure inline {
var msg = begin_cell()
.store_uint(0x10, 6)
.store_slice(recepient)
.store_grams(amount)
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
.end_cell();
send_raw_message(msg, 1);
}
() emit_log_simple (int event_id, slice data) impure inline {
var msg = begin_cell()
.store_uint (12, 4) ;; ext_out_msg_info$11 src:MsgAddressInt ()
.store_uint (1, 2)
.store_uint (256, 9)
.store_uint(event_id, 256)
.store_uint(0, 64 + 32 + 2) ;; created_lt, created_at, init:Maybe, body:Either
.store_slice(data)
.end_cell();
send_raw_message(msg, 0);
}
;; recv_internal is the main function of the contract and is called when it receives a message from other contracts
() recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure {
if (in_msg_body.slice_empty?()) { ;; ignore all empty messages
return ();
}
slice cs = in_msg_full.begin_parse();
int flags = cs~load_uint(4);
if (flags & 1) { ;; ignore all bounced messages
return ();
}
slice sender_address = cs~load_msg_addr();
(cell states, cell jetton_info, cell admin_info) = load_data(); ;; here we populate the storage variables
int op = in_msg_body~load_uint(32); ;; by convention, the first 32 bits of incoming message is the op
int query_id = in_msg_body~load_uint(64); ;; also by convention, the next 64 bits contain the "query id", although this is not always the case
if (op == op::transfer_notification()) {
;; should check if jetton is valid
int send_amount = in_msg_body~load_coins(); ;; Jettons send
slice jetton_info_slice = jetton_info.begin_parse();
slice jetton_master_address = jetton_info_slice~load_msg_addr();
cell JETTON_BYTECODE = jetton_info_slice~load_ref();
throw_unless(error::jetton_sender, equal_slices(sender_address, calculate_user_jetton_wallet_address(my_address(), jetton_master_address, JETTON_BYTECODE)));
slice origin_sender = in_msg_body~load_msg_addr(); ;; transfer origin address (not used)
(slice data, int f) = states.udict_get?(256, slice_hash(origin_sender));
int jettonAmount = 0;
int tonAmount = 0;
ifnot(f == 0) {
jettonAmount = data~load_coins();
tonAmount = data~load_coins();
}
states~udict_set(256, slice_hash(origin_sender),
begin_cell().store_coins(jettonAmount + send_amount).store_coins(tonAmount).end_cell().begin_parse());
emit_log_simple(op::stake_TONNEL(), begin_cell().store_coins(send_amount).end_cell().begin_parse());
save_data(states, jetton_info, admin_info);
return ();
}
if(op == op::stake_TON()) {
throw_unless(error::fund, msg_value > const::tx_fee);
int amount_to_stake = msg_value - const::tx_fee;
(slice data, int f) = states.udict_get?(256, slice_hash(sender_address));
int jettonAmount = 0;
int tonAmount = 0;
ifnot(f == 0) {
jettonAmount = data~load_coins();
tonAmount = data~load_coins();
}
states~udict_set(256, slice_hash(sender_address),
begin_cell().store_coins(jettonAmount).store_coins(tonAmount + amount_to_stake).end_cell().begin_parse());
emit_log_simple(op::stake_TON(), begin_cell().store_coins(amount_to_stake).end_cell().begin_parse());
save_data(states, jetton_info, admin_info);
return ();
}
if(op == op::withdraw_TON()) {
int amount_to_withdraw = in_msg_body~load_coins();
(slice data, int f) = states.udict_get?(256, slice_hash(sender_address));
if(f == 0) {
throw(error::not_staked);
}
int jettonAmount = data~load_coins();
int tonAmount = data~load_coins();
throw_unless(error::not_enough, tonAmount >= amount_to_withdraw);
send_ton(sender_address, amount_to_withdraw);
states~udict_set(256, slice_hash(sender_address),
begin_cell().store_coins(jettonAmount).store_coins(tonAmount - amount_to_withdraw).end_cell().begin_parse());
emit_log_simple(op::withdraw_TON(), begin_cell().store_coins(amount_to_withdraw).end_cell().begin_parse());
save_data(states, jetton_info, admin_info);
return ();
}
if (op == op::withdraw_TONNEL()) {
int amount_to_withdraw = in_msg_body~load_coins();
(slice data, int f) = states.udict_get?(256, slice_hash(sender_address));
if(f == 0) {
throw(error::not_staked);
}
int jettonAmount = data~load_coins();
int tonAmount = data~load_coins();
throw_unless(error::not_enough, jettonAmount >= amount_to_withdraw);
slice jetton_info_slice = jetton_info.begin_parse();
slice jetton_master_address = jetton_info_slice~load_msg_addr();
cell JETTON_BYTECODE = jetton_info_slice~load_ref();
send_jetton(sender_address, amount_to_withdraw, jetton_master_address, JETTON_BYTECODE);
states~udict_set(256, slice_hash(sender_address),
begin_cell().store_coins(jettonAmount - amount_to_withdraw).store_coins(tonAmount).end_cell().begin_parse());
emit_log_simple(op::withdraw_TONNEL(), begin_cell().store_coins(amount_to_withdraw).end_cell().begin_parse());
save_data(states, jetton_info, admin_info);
return ();
}
if(op == op::set_TONNEL()){
slice admin_info_slice = admin_info.begin_parse();
slice admin_address = admin_info_slice~load_msg_addr();
throw_unless(error::not_admin, equal_slices(sender_address, admin_address));
slice jetton_master_address = in_msg_body~load_msg_addr();
cell JETTON_BYTECODE = in_msg_body~load_ref();
jetton_info = begin_cell().store_slice(jetton_master_address).store_ref(JETTON_BYTECODE).end_cell();
save_data(states, jetton_info, admin_info);
return ();
}
throw(0xffff); ;; if the message contains an op that is not known to this contract, we throw
}