Ton

Форк
0
199 строк · 6.7 Кб
1
;; Wallet smart contract with plugins
2

3
#include "stdlib.fc";
4

5
(slice, int) dict_get?(cell dict, int key_len, slice index) asm(index dict key_len) "DICTGET" "NULLSWAPIFNOT";
6
(cell, int) dict_add_builder?(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTADDB";
7
(cell, int) dict_delete?(cell dict, int key_len, slice index) asm(index dict key_len) "DICTDEL";
8

9
() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure {
10
  var cs = in_msg_cell.begin_parse();
11
  var flags = cs~load_uint(4);  ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
12
  if (flags & 1) {
13
    ;; ignore all bounced messages
14
    return ();
15
  }
16
  if (in_msg.slice_bits() < 32) {
17
    ;; ignore simple transfers
18
    return ();
19
  }
20
  int op = in_msg~load_uint(32);
21
  if (op != 0x706c7567) & (op != 0x64737472) { ;; "plug" & "dstr"
22
    ;; ignore all messages not related to plugins
23
    return ();
24
  }
25
  slice s_addr = cs~load_msg_addr();
26
  (int wc, int addr_hash) = parse_std_addr(s_addr);
27
  slice wc_n_address = begin_cell().store_int(wc, 8).store_uint(addr_hash, 256).end_cell().begin_parse();
28
  var ds = get_data().begin_parse().skip_bits(32 + 32 + 256);
29
  var plugins = ds~load_dict();
30
  var (_, success?) = plugins.dict_get?(8 + 256, wc_n_address);
31
  if ~(success?) {
32
    ;; it may be a transfer
33
    return ();
34
  }
35
  int query_id = in_msg~load_uint(64);
36
  var msg = begin_cell();
37
  if (op == 0x706c7567) { ;; request funds
38

39
    (int r_toncoins, cell r_extra) = (in_msg~load_grams(), in_msg~load_dict());
40

41
    [int my_balance, _] = get_balance();
42
    throw_unless(80, my_balance - msg_value >= r_toncoins);
43

44
    msg = msg.store_uint(0x18, 6)
45
             .store_slice(s_addr)
46
             .store_grams(r_toncoins)
47
             .store_dict(r_extra)
48
             .store_uint(0, 4 + 4 + 64 + 32 + 1 + 1)
49
             .store_uint(0x706c7567 | 0x80000000, 32)
50
             .store_uint(query_id, 64);
51
    send_raw_message(msg.end_cell(), 64);
52

53
  }
54

55
  if (op == 0x64737472) { ;; remove plugin by its request
56

57
    plugins~dict_delete?(8 + 256, wc_n_address);
58
    var ds = get_data().begin_parse().first_bits(32 + 32 + 256);
59
    set_data(begin_cell().store_slice(ds).store_dict(plugins).end_cell());
60
    ;; return coins only if bounce expected
61
    if (flags & 2) {
62
      msg = msg.store_uint(0x18, 6)
63
               .store_slice(s_addr)
64
               .store_grams(0)
65
               .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
66
               .store_uint(0x64737472 | 0x80000000, 32)
67
               .store_uint(query_id, 64);
68
      send_raw_message(msg.end_cell(), 64);
69
    }
70
  }
71
}
72

73
() recv_external(slice in_msg) impure {
74
  var signature = in_msg~load_bits(512);
75
  var cs = in_msg;
76
  var (subwallet_id, valid_until, msg_seqno) = (cs~load_uint(32), cs~load_uint(32), cs~load_uint(32));
77
  throw_if(36, valid_until <= now());
78
  var ds = get_data().begin_parse();
79
  var (stored_seqno, stored_subwallet, public_key, plugins) = (ds~load_uint(32), ds~load_uint(32), ds~load_uint(256), ds~load_dict());
80
  ds.end_parse();
81
  throw_unless(33, msg_seqno == stored_seqno);
82
  throw_unless(34, subwallet_id == stored_subwallet);
83
  throw_unless(35, check_signature(slice_hash(in_msg), signature, public_key));
84
  accept_message();
85
  set_data(begin_cell()
86
    .store_uint(stored_seqno + 1, 32)
87
    .store_uint(stored_subwallet, 32)
88
    .store_uint(public_key, 256)
89
    .store_dict(plugins)
90
    .end_cell());
91
  commit();
92
  cs~touch();
93
  int op = cs~load_uint(8);
94

95
  if (op == 0) { ;; simple send
96
    while (cs.slice_refs()) {
97
      var mode = cs~load_uint(8);
98
      send_raw_message(cs~load_ref(), mode);
99
    }
100
    return (); ;; have already saved the storage
101
  }
102

103
  if (op == 1) { ;; deploy and install plugin
104
    int plugin_workchain = cs~load_int(8);
105
    int plugin_balance = cs~load_grams();
106
    (cell state_init, cell body) = (cs~load_ref(), cs~load_ref());
107
    int plugin_address = cell_hash(state_init);
108
    slice wc_n_address = begin_cell().store_int(plugin_workchain, 8).store_uint(plugin_address, 256).end_cell().begin_parse();
109
    var msg = begin_cell()
110
      .store_uint(0x18, 6)
111
      .store_uint(4, 3).store_slice(wc_n_address)
112
      .store_grams(plugin_balance)
113
      .store_uint(4 + 2 + 1, 1 + 4 + 4 + 64 + 32 + 1 + 1 + 1)
114
      .store_ref(state_init)
115
      .store_ref(body);
116
    send_raw_message(msg.end_cell(), 3);
117
    (plugins, int success?) = plugins.dict_add_builder?(8 + 256, wc_n_address, begin_cell());
118
    throw_unless(39, success?);
119
  }
120

121
  if (op == 2) { ;; install plugin
122
    slice wc_n_address = cs~load_bits(8 + 256);
123
    int amount = cs~load_grams();
124
    int query_id = cs~load_uint(64);
125

126
    (plugins, int success?) = plugins.dict_add_builder?(8 + 256, wc_n_address, begin_cell());
127
    throw_unless(39, success?);
128

129
    builder msg = begin_cell()
130
      .store_uint(0x18, 6)
131
      .store_uint(4, 3).store_slice(wc_n_address)
132
      .store_grams(amount)
133
      .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
134
      .store_uint(0x6e6f7465, 32) ;; op
135
      .store_uint(query_id, 64);
136
    send_raw_message(msg.end_cell(), 3);
137
  }
138

139
  if (op == 3) { ;; remove plugin
140
    slice wc_n_address = cs~load_bits(8 + 256);
141
    int amount = cs~load_grams();
142
    int query_id = cs~load_uint(64);
143

144
    (plugins, int success?) = plugins.dict_delete?(8 + 256, wc_n_address);
145
    throw_unless(39, success?);
146

147
    builder msg = begin_cell()
148
      .store_uint(0x18, 6)
149
      .store_uint(4, 3).store_slice(wc_n_address)
150
      .store_grams(amount)
151
      .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
152
      .store_uint(0x64737472, 32) ;; op
153
      .store_uint(query_id, 64);
154
    send_raw_message(msg.end_cell(), 3);
155
  }
156

157
  set_data(begin_cell()
158
    .store_uint(stored_seqno + 1, 32)
159
    .store_uint(stored_subwallet, 32)
160
    .store_uint(public_key, 256)
161
    .store_dict(plugins)
162
    .end_cell());
163
}
164

165
;; Get methods
166

167
int seqno() method_id {
168
  return get_data().begin_parse().preload_uint(32);
169
}
170

171
int get_subwallet_id() method_id {
172
  return get_data().begin_parse().skip_bits(32).preload_uint(32);
173
}
174

175
int get_public_key() method_id {
176
  var cs = get_data().begin_parse().skip_bits(64);
177
  return cs.preload_uint(256);
178
}
179

180
int is_plugin_installed(int wc, int addr_hash) method_id {
181
  var ds = get_data().begin_parse().skip_bits(32 + 32 + 256);
182
  var plugins = ds~load_dict();
183
  var (_, success?) = plugins.dict_get?(8 + 256, begin_cell().store_int(wc, 8).store_uint(addr_hash, 256).end_cell().begin_parse());
184
  return success?;
185
}
186

187
tuple get_plugin_list() method_id {
188
  var list = null();
189
  var ds = get_data().begin_parse().skip_bits(32 + 32 + 256);
190
  var plugins = ds~load_dict();
191
  do {
192
    var (wc_n_address, _, f) = plugins~dict::delete_get_min(8 + 256);
193
    if (f) {
194
      (int wc, int addr) = (wc_n_address~load_int(8), wc_n_address~load_uint(256));
195
      list = cons(pair(wc, addr), list);
196
    }
197
  } until (~ f);
198
  return list;
199
}
200

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

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

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

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