For the sake of brevity, we skip the app_id key in lock_state, which enables the lock state to provide the exclusivity option to the lock consuming dApps. We will add this detail later.
subtracts lock_amount from balance and adds it to lock_balance.
leaves the end_time the same or increases it to msg_endTime it if msg_endTime is greater.
The following set of rules prevent double spending and allow us to have a simple, secure and low cost implementation.
The jetton-wallet contract
can not undo a locking operation.
can unlock the full lock_balance ONLY after end_time.
can add more locks to the lock state provided that end_time can stay the same or increase.
Lock Code in Alice's DAOL jetton-wallet contract:
// Replace // with ;; for commenting lines in Func code editor.
```func
() lock_tokens (slice in_msg_body, slice sender_address, int msg_value, int fwd_fee) impure {
//;; NOTE we can not allow fails in action phase since in that case there will be
//;; no bounce. Thus check and throw in computation phase.
(int balance, int lock_balance, int endtime, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) = load_data();
int query_id = in_msg_body~load_uint(64);
int lock_amount = in_msg_body~load_coins();
int msg_endtime = in_msg_body~load_uint(64);
slice response_address = in_msg_body~load_msg_addr();
//;; ignore custom payload
//;; slice custom_payload = in_msg_body~load_dict();
//;; instead of using custom_payload we preferred to introduce lock_balance and endtime
//;; state variables explicitly to describe behaviour easily.
//;; in the TEP proposal version the lock state includes app_id for exclusivity option.
//;; The locking consumer dapps that demand exclusivity will check app_id
int newBalance = balance - lock_amount;
//;; locking cannot exceed balance
//;; if user tries to lock more than balance
//;; we do not reject but cap the lock at balance
if (newBalance < 0){
lock_amount = balance;
balance = 0;
} else {
balance = newBalance;
lock_balance += lock_amount;
}
//;; user can only increase endtime (prevention against double spend)
if (msg_endtime > endtime) {endtime = msg_endtime;}
throw_unless(705, equal_slices(owner_address, sender_address));
//;; throw_unless(706, balance >= 0);
throw_unless(707, msg_value > fwd_fee + 2 * gas_consumption);
var msg_body = begin_cell()
.store_uint(op::lock_notification(), 32)
.store_uint(query_id, 64)
.store_coins(lock_amount)
.store_uint(endtime, 64)
.store_slice(owner_address)
.store_slice(response_address)
.end_cell();
var msg = begin_cell()
.store_uint(0x18, 6)
.store_slice(jetton_master_address)
.store_coins(0)
.store_uint(1, 1 + 4 + 4 + 64 + 32 + 1 + 1)
.store_ref(msg_body);
send_raw_message(msg.end_cell(), 64);
save_data(balance, lock_balance, endtime, owner_address, jetton_master_address, jetton_wallet_code);
}
```