Skip to content

Commit

Permalink
This quite did not worked out. git good.
Browse files Browse the repository at this point in the history
  • Loading branch information
Skydev0h committed Oct 11, 2023
1 parent 4192634 commit 542b241
Showing 1 changed file with 268 additions and 0 deletions.
268 changes: 268 additions & 0 deletions contracts/failed/wallet_v5_asm_cond_multicheck.fc
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
#pragma version =0.4.4;

#include "imports/stdlib.fc";

;; LDUQ: s - x s' -1 or s 0 --NULLROTRIFNOT--> s - x s' -1 or # s 0
(int, slice, int) try_load_uint32(slice s) asm "32 LDUQ" "NULLROTRIFNOT";

;; LDUQ: s - x s' -1 or s 0 --IFNOTRET--> x s' or RET
(int, slice) load_uint32_or_ret(slice s) impure asm "32 LDUQ" "IFNOTRET";

{-
Equivalent to:
if (flags & 1) {
;; ignore all bounced messages
return ();
}
-}
() return_if_bounce(int flags) impure asm "1 PUSHINT" "AND" "IFRET";
() return_if_not_equal(int a, int b) impure asm "EQUAL" "IFNOTRET";
() return_if_not(int a) impure asm "IFNOTRET";

(int) equals_a_return_if_not_any(int what, int a, int b) impure asm(a what b) "OVER" "EQUAL" "ROTREV" "EQUAL" "TUCK" "OR" "IFNOTRET";

(slice) udict_get_or_return(cell dict, int key_len, int index) impure asm(index dict key_len) "DICTUGET IFNOTRET";

;; Extensible wallet contract v5

;; Compresses 8+256-bit address into 256-bit uint by cutting off one bit from sha256.
;; This allows us to save on wrapping the address in a cell and make plugin requests cheaper.
;; This method also unpacks address hash if you pass packed hash with the original wc.
int pack_address(int wc, int hash) impure asm "SWAP INC XOR"; ;; hash ^ (wc+1)

;; Stores pre-computed list of actions (mostly `action_send_msg`) in the actions register.
() set_actions(cell action_list) impure asm "c5 POP";

{-
Equivalent to:
ifnot (cs.preload_uint(1)) {
set_actions(cs.preload_ref());
return ();
}
-}
() set_actions_if_simple(slice cs) impure asm "DUP" "1 PLDU" "IFNOTJMP:<{ PLDREF c5 POP }>" "DROP";

;; Dispatches already authenticated request.
() dispatch_complex_request_inline(int stored_seqno, slice cs, slice immutable_tail, int stored_subwallet, int public_key) impure inline {
var extensions = null();

;; Recurse into extended actions until we reach standard actions
while (cs~load_uint(1)) {
int op = cs~load_uint(32);

;; Raw set_data
if (op == 0x1ff8ea0b) {
set_data(cs~load_ref());
}

;; Add/remove extensions
if ((op == 0x1c40db9f) | (op == 0x5eaef4a4)) {
(int wc, int hash) = parse_std_addr(cs~load_msg_addr());
int packed_addr = pack_address(wc, hash);

ifnot (immutable_tail.null?()) {
;; immutable_tail = immutable_tail.skip_bits(80 + 256);
extensions = immutable_tail.skip_bits(80 + 256).preload_dict();
;; ds.end_parse() NO MORE guarantees that there is no more data in immutable_tail
;; immutable_tail~skip_bits(immutable_tail.slice_bits()); ;; more resiliency in case of extraneous data
immutable_tail = null();
}

;; Add extension
if (op == 0x1c40db9f) {
(extensions, int success?) = extensions.udict_add_builder?(256, packed_addr, begin_cell().store_int(wc,8));
throw_unless(39, success?);
}
;; Remove extension
if (op == 0x5eaef4a4) {
(extensions, int success?) = extensions.udict_delete?(256, packed_addr);
throw_unless(40, success?);
}

set_data(begin_cell()
.store_uint(stored_seqno, 32)
.store_uint(stored_subwallet, 80)
.store_uint(public_key, 256)
.store_dict(extensions)
.end_cell());
}

;; Other actions are no-op
;; FIXME: is it costlier to check for unsupported actions and throw?
cs = cs.preload_ref().begin_parse();
}
;; At this point we are at `action_list_basic$0 {n:#} actions:^(OutList n) = ActionList n 0;`
;; Simply set the C5 register with all pre-computed actions:
set_actions(cs.preload_ref());
return ();
}

() dispatch_complex_request_iref(int stored_seqno, slice cs, slice immutable_tail, int stored_subwallet, int public_key) impure inline_ref {
dispatch_complex_request_inline(stored_seqno, cs, immutable_tail, stored_subwallet, public_key);
}

() dispatch_request(int public_key, slice cs, slice immutable_tail, int stored_subwallet, int stored_seqno) impure inline {
{-
ifnot (cs.preload_uint(1)) {
set_actions(cs.preload_ref());
return ();
}
-}
set_actions_if_simple(cs);
;; <<<<<<<<<<---------- CONTEST TEST CUTOFF POINT ---------->>>>>>>>>>
;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;; ------------------------------------------ INLINING BOUNDARY ------------------------------------------
dispatch_complex_request_iref(stored_seqno, cs, immutable_tail, stored_subwallet, public_key);
}

() dispatch_extension_request(slice cs, var dummy) impure inline {
{-
ifnot (cs.preload_uint(1)) {
set_actions(cs.preload_ref());
return ();
}
-}
set_actions_if_simple(cs);
dummy~impure_touch(); ;; DROP merged to 2DROP!
;; <<<<<<<<<<---------- CONTEST TEST CUTOFF POINT ---------->>>>>>>>>>
var ds = get_data().begin_parse();
var stored_seqno = ds~load_uint(32);
var immutable_tail = ds; ;; stored_subwallet ~ public_key ~ extensions
var stored_subwallet = ds~load_uint(80);
var public_key = ds.preload_uint(256);
;; Note: If after modifications code becomes so large it undesirably splits to cells,
;; replace with dispatch_complex_request_iref. This won't affect test cases but will affect GGC slightly.
dispatch_complex_request_inline(stored_seqno, cs, immutable_tail, stored_subwallet, public_key);
}

;; Verifies signed request, prevents replays and proceeds with `dispatch_request`.
() process_signed_request(slice body, int stored_seqno, slice immutable_tail, int stored_subwallet, int public_key) impure inline {
var signature = body~load_bits(512);
throw_unless(35, check_signature(slice_hash(body), signature, public_key));

var cs = body;
var (subwallet_id, valid_until, msg_seqno) = (cs~load_uint(80), cs~load_uint(32), cs~load_uint(32));

throw_unless(34, subwallet_id == stored_subwallet);
throw_unless(33, msg_seqno == stored_seqno);
throw_if(36, valid_until <= now());

accept_message();

;; Store and commit the seqno increment to prevent replays even if the subsequent requests fail.
stored_seqno = stored_seqno + 1;
set_data(begin_cell()
.store_uint(stored_seqno, 32)
.store_slice(immutable_tail) ;; stored_subwallet ~ public_key ~ extensions
.end_cell());

commit();

dispatch_request(public_key, cs, immutable_tail, stored_subwallet, stored_seqno);
}

() recv_external(slice body) impure {
int auth_kind = body~load_uint(32);
return_if_not_equal(auth_kind, 0x7369676E); ;; "sign"
;; if (auth_kind == 0x7369676E) { ;; "sign"
var ds = get_data().begin_parse();
var stored_seqno = ds~load_uint(32);
var immutable_tail = ds; ;; stored_subwallet ~ public_key ~ extensions
var stored_subwallet = ds~load_uint(80);
var public_key = ds.preload_uint(256);
process_signed_request(body, stored_seqno, immutable_tail, stored_subwallet, public_key);
return();
;; }
}

() recv_internal(int msg_value, cell full_msg, slice body) impure {
var full_msg_slice = full_msg.begin_parse();
var flags = full_msg_slice~load_uint(4); ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool src:MsgAddressInt ...
{-
if (flags & 1) {
;; ignore all bounced messages
return ();
}
-}
;; return_if_bounce(3); <- as a test (since there are no bounce tests) - this works (breaks tests)!
return_if_bounce(flags);
{-
(int auth_kind, body, int success) = body.try_load_uint32(); ;; why there is no such stuff built in compiler?
ifnot (success) {
;; ignore simple transfers
return ();
}
-}
(int auth_kind, body) = body.load_uint32_or_ret(); ;; Now that's some hot garbage!

;; We accept two kinds of authenticated messages:
;; - 0x6578746E "extn" authenticated by extension
;; - 0x7369676E "sign" authenticated by signature

int is_extn = equals_a_return_if_not_any(auth_kind, 0x6578746E, 0x7369676E); ;; "extn" "sign"

if (is_extn) {

var ds = get_data().begin_parse();
;; It is not required to read this data here, maybe ext is doing simple transfer where those are not needed
var extensions = ds.skip_bits(32 + 80 + 256).preload_dict();

;; Authenticate extension by its address.
int packed_sender_addr = pack_address(parse_std_addr(full_msg_slice~load_msg_addr())); ;; no PLDMSGADDR exists
;; var (_, success?) = extensions.udict_get?(256, packed_sender_addr);
{-
ifnot (success?) {
;; Note that some random contract may have deposited funds with this prefix,
;; so we accept the funds silently instead of throwing an error (wallet v4 does the same).
return ();
}
-}
;; return_if_not(success?);
var dummy = extensions.udict_get_or_return(256, packed_sender_addr);
;; dummy is for black magic optimization. will drop it later with 2drop
dispatch_extension_request(body, dummy); ;; Special route for external address authenticated request
return ();

}

;; return_if_not_equal(auth_kind, 0x7369676E); ;; "sign"

;; if (auth_kind == 0x7369676E) { ;; "sign"

var ds = get_data().begin_parse();
var stored_seqno = ds~load_uint(32);
var immutable_tail = ds; ;; keep immutable tail for fast commit storage and extensions retrieval if needed
var stored_subwallet = ds~load_uint(80);
var public_key = ds.preload_uint(256);

;; Process the rest of the slice just like the signed request.
process_signed_request(body, stored_seqno, immutable_tail, stored_subwallet, public_key);

return (); ;; Explicit returns escape function faster and const less gas (suddenly!)

;; }

}


;; Get methods

int seqno() method_id {
return get_data().begin_parse().preload_uint(32);
}

int get_wallet_id() method_id {
return get_data().begin_parse().skip_bits(32).preload_uint(80);
}

int get_public_key() method_id {
var cs = get_data().begin_parse().skip_bits(32 + 80);
return cs.preload_uint(256);
}

;; Returns raw dictionary (or null if empty) where keys are packed addresses and the `wc` is stored in leafs.
;; User should unpack the address using the same packing function using `wc` to restore the original address.
cell get_extensions() method_id {
var ds = get_data().begin_parse().skip_bits(32 + 80 + 256);
return ds~load_dict();
}

0 comments on commit 542b241

Please sign in to comment.