@@ -18,21 +18,29 @@ const size::call_data::max = 2048 * 8; ;; 2 Kilobytes of call data
1818const op::internal::donate = 100;
1919const op::internal::deposit = 101;
2020const op::internal::deposit_and_call = 102;
21+ const op::internal::call = 103;
2122
23+ ;; tss ops
2224const op::external::withdraw = 200;
25+ const op::external::increase_seqno = 205;
2326
27+ ;; authority ops
2428const op::authority::set_deposits_enabled = 201;
2529const op::authority::update_tss = 202;
2630const op::authority::update_code = 203;
2731const op::authority::update_authority = 204;
32+ const op::authority::reset_seqno = 206;
2833
2934;; GAS FEES =========================================
30- ;; These constants are empirically determined based on tests
31- ;; and slighly bumped to cover all other non-gas fees (e.g. storage, fwd_fee, etc.)
35+ ;; IMPORTANT: These constants are empirically determined based on tests
36+ ;; and slightly bumped to cover all other non-gas fees (e.g. storage, fwd_fee, etc.)
3237const gas::deposit = 10000;
3338const gas::deposit_and_call = 13000;
39+ const gas::call = 10000;
40+
3441const gas::authority = 20000;
35- const gas::withdraw = 17500;
42+
43+ const gas::external = 17500;
3644
3745;; PARSING =========================================
3846
@@ -146,6 +154,30 @@ const gas::withdraw = 17500;
146154 send_log_message(log);
147155}
148156
157+ ;; handles zeta's onCall method by ensuring call_data size and gas costs are covered;
158+ ;;
159+ ;; NOTE that this operation DOESN'T rebate sent amount if it's bigger than tx fee!
160+ ;; We can consider sending surplus amount back in the future improvements.
161+ ;; For now, send amount that is equal to calculate_gas_fee(op::call)
162+ () handle_call(int amount, slice in_msg_body) impure inline {
163+ load_state();
164+ guard_deposits();
165+
166+ throw_if(error::invalid_evm_recipient, in_msg_body.slice_bits() < size::evm_address);
167+ in_msg_body~load_uint(size::evm_address);
168+
169+ throw_if(error::invalid_call_data, in_msg_body.slice_refs_empty?());
170+ cell call_data = in_msg_body~load_ref();
171+ guard_cell_size(call_data, size::call_data::max, error::invalid_call_data);
172+
173+ int tx_fee = get_gas_fee_workchain(gas::call);
174+ throw_if(error::insufficient_value, amount < tx_fee);
175+
176+ ;; state::total_locked is NOT changed.
177+
178+ mutate_state();
179+ }
180+
149181;; Enables or disables deposits.
150182() handle_set_deposits_enabled(slice sender, slice message) impure inline {
151183 load_state();
@@ -184,6 +216,20 @@ const gas::withdraw = 17500;
184216 mutate_state();
185217}
186218
219+ ;; Resets the seqno to the specified value
220+ ;; handles reset_seqno (uint32 new_seqno)
221+ () handle_reset_seqno(slice sender, slice message) impure inline {
222+ load_state();
223+
224+ guard_authority_sender(sender);
225+
226+ int new_seqno = message~load_uint(size::seqno);
227+
228+ state::seqno = new_seqno;
229+
230+ mutate_state();
231+ }
232+
187233() handle_update_authority(slice sender, slice message) impure inline {
188234 load_state();
189235
@@ -235,6 +281,10 @@ const gas::withdraw = 17500;
235281 return handle_deposit_and_call(msg_value, in_msg_body);
236282 }
237283
284+ if (op == op::internal::call) {
285+ return handle_call(msg_value, in_msg_body);
286+ }
287+
238288 int tx_fee_authority = get_gas_fee_workchain(gas::authority);
239289 throw_if(error::insufficient_value, msg_value < tx_fee_authority);
240290
@@ -250,6 +300,10 @@ const gas::withdraw = 17500;
250300 return handle_update_code(sender, in_msg_body);
251301 }
252302
303+ if (op == op::authority::reset_seqno) {
304+ return handle_reset_seqno(sender, in_msg_body);
305+ }
306+
253307 if (op == op::authority::update_authority) {
254308 return handle_update_authority(sender, in_msg_body);
255309 }
@@ -285,7 +339,7 @@ cell auth::ecdsa::external(slice message, slice expected_evm_address) inline {
285339
286340;; Withdraws assets to the recipient
287341;;
288- ;; handle_withdrawal (MsgAddr recipient, Coins amount, int seqno)
342+ ;; handle_withdrawal (MsgAddr recipient, Coins amount, uint32 seqno)
289343() handle_withdrawal(slice payload) impure inline {
290344 ;; load the body
291345 slice recipient = payload~load_msg_addr();
@@ -300,7 +354,7 @@ cell auth::ecdsa::external(slice message, slice expected_evm_address) inline {
300354 throw_if(error::insufficient_value, amount == 0);
301355 throw_if(error::invalid_seqno, seqno != state::seqno);
302356
303- int tx_fee = get_gas_fee_workchain(gas::withdraw );
357+ int tx_fee = get_gas_fee_workchain(gas::external );
304358
305359 ;; edge-case: make sure gw has enough coins when having low funds
306360 throw_if(error::insufficient_value, state::total_locked < (amount + tx_fee));
@@ -311,14 +365,41 @@ cell auth::ecdsa::external(slice message, slice expected_evm_address) inline {
311365 state::total_locked -= (amount + tx_fee);
312366 state::seqno += 1;
313367
368+ ;; Sent TON and mutate the state
314369 mutate_state();
315370 commit();
316371
317- ;; Sent TON and mutate the state
318372 int send_mode = message::flag::pay_fees_separately;
319373 send_simple_message_non_bounceable(recipient_addr, amount, send_mode);
320374}
321375
376+ ;; Increases seqno by 1 without doing any other operations.
377+ ;; handle_increase_seqno (uint32 failure_reason, uint32 seqno)
378+ () handle_increase_seqno(slice payload) impure inline {
379+ ;; load the body
380+ int increase_reason = payload~load_uint(size::seqno);
381+
382+ ;; note that increase_reason is an arbitrary number defined by the protocol
383+ ;; and is used to identify the reason for the increase (via parsing input message OR debug logs)
384+ ~strdump("increase_reason");
385+ increase_reason~dump();
386+
387+ int seqno = payload~load_uint(size::seqno);
388+
389+ throw_if(error::invalid_seqno, seqno != state::seqno);
390+
391+ int tx_fee = get_gas_fee_workchain(gas::external);
392+ throw_if(error::insufficient_value, state::total_locked < tx_fee);
393+
394+ ;; accept the message, the contract agrees to pay gas fees
395+ accept_message();
396+
397+ state::total_locked -= tx_fee;
398+ state::seqno += 1;
399+
400+ mutate_state();
401+ }
402+
322403;; Entry point for all external messages
323404() recv_external(slice message) impure {
324405 load_state();
@@ -331,6 +412,10 @@ cell auth::ecdsa::external(slice message, slice expected_evm_address) inline {
331412 return handle_withdrawal(payload);
332413 }
333414
415+ if (op == op::external::increase_seqno) {
416+ return handle_increase_seqno(payload);
417+ }
418+
334419 throw(error::unknown_op);
335420}
336421
@@ -353,7 +438,7 @@ cell auth::ecdsa::external(slice message, slice expected_evm_address) inline {
353438 );
354439}
355440
356- ;; get nonce (int32)
441+ ;; get seqno [ nonce] (int32)
357442int seqno() method_id {
358443 load_state();
359444
@@ -370,17 +455,25 @@ int calculate_gas_fee(int op) method_id {
370455 return get_gas_fee_workchain(gas::deposit_and_call);
371456 }
372457
458+ if (op == op::internal::call) {
459+ return get_gas_fee_workchain(gas::call);
460+ }
461+
373462 int is_authority_op = (op == op::authority::set_deposits_enabled)
374463 | (op == op::authority::update_tss)
375464 | (op == op::authority::update_code)
376- | (op == op::authority::update_authority);
465+ | (op == op::authority::update_authority)
466+ | (op == op::authority::reset_seqno);
377467
378468 if (is_authority_op) {
379469 return get_gas_fee_workchain(gas::authority);
380470 }
381471
382- if (op == op::external::withdraw) {
383- return get_gas_fee_workchain(gas::withdraw);
472+ int is_external_op = (op == op::external::withdraw)
473+ | (op == op::external::increase_seqno);
474+
475+ if (is_external_op) {
476+ return get_gas_fee_workchain(gas::external);
384477 }
385478
386479 throw(error::unknown_op);
0 commit comments