mirror of
https://github.com/danog/toncontest.git
synced 2024-12-03 09:57:57 +01:00
99 lines
2.8 KiB
Plaintext
99 lines
2.8 KiB
Plaintext
|
;; Multisig wallet smart contract
|
||
|
|
||
|
;; Cleanup expired partial orders (& get contract data)
|
||
|
;; needsWrite, seqno, keys, messages
|
||
|
(int, int, cell, cell) collect_garbage() {
|
||
|
var data = get_data().begin_parse();
|
||
|
var (seqno, keys, messages) = (data~load_int(32), data~load_dict(), data~load_dict());
|
||
|
data.end_parse();
|
||
|
|
||
|
var needsWrite = 0;
|
||
|
var hash = -1;
|
||
|
do {
|
||
|
(hash, var cs, var ok) = messages.idict_get_next?(256, hash);
|
||
|
if (ok) {
|
||
|
;; expiry <= now
|
||
|
if (cs~load_uint(32) <= now()) {
|
||
|
messages.idict_delete?(256, hash);
|
||
|
needsWrite = -1;
|
||
|
}
|
||
|
}
|
||
|
} until (~ ok);
|
||
|
|
||
|
return (needsWrite, seqno, keys, messages);
|
||
|
}
|
||
|
|
||
|
() store_db(int seqno, cell keys, cell messages) {
|
||
|
set_data(begin_cell().store_uint(seqno, 32).store_dict(keys).store_dict(messages).end_cell());
|
||
|
}
|
||
|
|
||
|
() recv_internal(slice in_msg) impure {
|
||
|
;; do nothing for internal messages
|
||
|
}
|
||
|
|
||
|
;; multiSigWrapper$0 keys_signatures:(HashmapE 4 ^Signature) message:(WrappedMessage X) = MultiSigWrapper X;
|
||
|
() recv_external(slice in_msg) impure {
|
||
|
;; Check if multiSigWrapper$0 or future unsupported protocol
|
||
|
throw_if(32, in_msg~load_uint(1) != 0);
|
||
|
|
||
|
;; Check if is hme_empty$0 or hme_root$1
|
||
|
;; If empty signature list
|
||
|
throw_if(33, in_msg.preload_uint(1) != 1);
|
||
|
|
||
|
var signatures = in_msg~load_dict();
|
||
|
var cs = in_msg;
|
||
|
|
||
|
;; wrappedMessage$_ expires_at:uint32 seqno:uint32 body:(Either (Message X) ^(Message X)) = WrappedMessage X;
|
||
|
var (expires_at, msg_seqno) = (cs~load_uint(32), cs~load_uint(32));
|
||
|
;; Message expired
|
||
|
throw_if(34, expires_at <= now());
|
||
|
|
||
|
var hash = slice_hash(in_msg);
|
||
|
var (needsWrite, stored_seqno, keys, messages) = collect_garbage();
|
||
|
var storedSignatures = new_dict();
|
||
|
|
||
|
;; If new message, increase seqno
|
||
|
if (stored_seqno == msg_seqno) {
|
||
|
stored_seqno += 1;
|
||
|
needsWrite = -1;
|
||
|
|
||
|
;; If old message
|
||
|
} else {
|
||
|
(var storedMessage, var ok) = messages.idict_get?(256, hash);
|
||
|
;; If old message and doesn't exist in db
|
||
|
ifnot (ok) {
|
||
|
;; Store new garbage-collected db
|
||
|
if (needsWrite) {
|
||
|
store_db(stored_seqno, keys, messages);
|
||
|
}
|
||
|
;; Throw
|
||
|
throw_if(35, -1);
|
||
|
}
|
||
|
;; Skip expiry
|
||
|
storedMessage.skip_bits(32);
|
||
|
;; No seqno: we can't regenerate the hash of a stored message.
|
||
|
;; That's a tradeoff to save grams on storage (and storing the seqno would be pointless anyway,
|
||
|
;; since all integrity checks were already made when the message was first stored)
|
||
|
;;
|
||
|
;; Load signatures
|
||
|
var storedSignatures = storedMessage.load_dict();
|
||
|
}
|
||
|
|
||
|
accept_message();
|
||
|
cs~touch();
|
||
|
|
||
|
while (cs.slice_refs()) {
|
||
|
var mode = cs~load_uint(8);
|
||
|
send_raw_message(cs~load_ref(), mode);
|
||
|
}
|
||
|
|
||
|
cs.end_parse();
|
||
|
;;set_data(begin_cell().store_uint(stored_seqno + 1, 32).store_uint(public_key, 256).end_cell());
|
||
|
}
|
||
|
|
||
|
;; Get methods
|
||
|
|
||
|
int seqno() method_id {
|
||
|
return get_data().begin_parse().preload_uint(32);
|
||
|
}
|