1- /*
2- actions
1+ import " ./constants" ;
32
4- out_list_empty$_ = OutList 0;
5- out_list$_ {n:#} prev:^(OutList n) action:OutAction = OutList (n + 1);
6- action_send_msg#0ec3c86d mode:(## 8) out_msg:^(MessageRelaxed Any) = OutAction;
7-
8- // Extended actions in W5:
9- action_list_basic$_ {n:#} actions:^(OutList n) = ActionList n 0;
10- action_list_extended$_ {m:#} {n:#} action:ExtendedAction prev:^(ActionList n m) = ActionList n (m+1);
11-
12- action_add_ext#02 addr:MsgAddressInt = ExtendedAction;
13- action_delete_ext#03 addr:MsgAddressInt = ExtendedAction;
14- action_set_signature_auth_allowed#04 allowed:(## 1) = ExtendedAction;
15- */
16-
17- message (0x7369676E ) ExternalSignedRequest {
3+ message (0x7369676e ) ExternalSignedRequest {
184 walletId : Int as uint32 ;
195 validUntil : Int as uint32 ;
206 seqno : Int as uint32 ;
@@ -23,11 +9,6 @@ message(0x7369676E) ExternalSignedRequest {
239 data : Slice as remaining ;
2410}
2511
26- // leave as example for discussion
27- // message(0x73696e74) InternalSignedRequest {
28- // data: Slice as remaining;
29- // }
30-
3112message (0x73696e74 ) InternalSignedRequest {
3213 walletId : Int as uint32 ;
3314 validUntil : Int as uint32 ;
@@ -42,89 +23,13 @@ message(0x6578746e) InternalExtensionRequest {
4223 actions : Slice as remaining ;
4324}
4425
45- asm fun countTrailingZeroes (s : Slice ): Int { SDCNTTRAIL0 }
46- struct SliceFlag {
47- data : Slice ;
48- flag : Bool ;
49- }
50- asm extends fun beginParseExotic (self : Cell ): SliceFlag { XCTOS }
51- asm extends mutates fun enforceAndRemoveActionSendMsgPrefix (self : Slice ) { x {0ec3c86d} SDBEGINS }
52- asm fun setC5 (outActions : Cell ) { c5 POP }
53-
54- asm extends mutates fun checkAndRemoveAddExtensionPrefix (self : Slice ): Bool {x {02 } SDBEGINSQ }
55- asm extends mutates fun checkAndRemoveDeleteExtensionPrefix (self : Slice ): Bool {x {03 } SDBEGINSQ }
56- asm extends mutates fun checkAndRemoveSetSignAllowedPrefix (self : Slice ): Bool {x {04 } SDBEGINSQ }
57-
58- // as example
59- asm fun typeCast (asd : InternalSignedRequest ): ExternalSignedRequest {}
60-
6126contract WalletV5 (
6227 isSignatureAllowed : Bool ,
6328 seqno : Int as uint32 ,
6429 walletId : Int as int32 ,
6530 publicKey : Int as uint256 ,
6631 extensions : map <Int as uint256 , Bool >,
6732) {
68- /*
69- actions has the following structure:
70-
71- {
72- outActions: Cell?;
73- hasOtherActions: Bool;
74- actions: Slice as remaining; // tl-b for ext actions
75- }
76- */
77- inline fun processActions (actions : Slice , isExternal : Bool , isExtension : Bool ) {
78- let outActions = actions .loadMaybeRef ();
79- if (outActions != null ) {
80- setC5 (processSendMessages (outActions !! , isExternal ));
81- }
82-
83- if (! actions .loadBool ()) {
84- return ;
85- }
86-
87- while (true ) {
88- // check tag, process action, try to load next ref while we can
89- let isAddExt = actions .checkAndRemoveAddExtensionPrefix ();
90- let isDeleteExt = isAddExt ? false : actions .checkAndRemoveDeleteExtensionPrefix ();
91-
92- if (isAddExt || isDeleteExt ) {
93- let addr = parseStdAddress (actions .loadAddress ().asSlice ());
94- let myAddr = parseStdAddress (myAddress ().asSlice ());
95-
96- throwUnless (145 , addr .workchain == myAddr .workchain ); // force_workchain optimization
97-
98- if (isAddExt ) {
99- // blocked by https://github.com/tact-lang/tact/issues/2842
100- // throwUnless(139, self.extensions.add(addr.address, true));
101- throwIf (139 , self .extensions .exists (addr .address ));
102- self .extensions .set (addr .address , true );
103- } else if (isDeleteExt ) {
104- throwUnless (140 , self .extensions .del (addr .address ));
105- throwIf (144 , self .extensions .isEmpty () && ! self .isSignatureAllowed );
106- }
107- } else if (actions .checkAndRemoveSetSignAllowedPrefix ()) {
108- throwUnless (146 , isExtension );
109- let newSignMode = actions .loadBool ();
110- throwIf (143 , newSignMode == self .isSignatureAllowed );
111- self .isSignatureAllowed = newSignMode ;
112-
113- if (! self .isSignatureAllowed && self .extensions .isEmpty ()) {
114- throw (142 );
115- }
116- } else {
117- throw (141 );
118- }
119-
120- if (actions .refsEmpty ()) {
121- return ;
122- }
123-
124- actions = actions .preloadRef ().beginParse ();
125- }
126- }
127-
12833 receive (msg : InternalExtensionRequest ) {
12934 let myAddr = parseStdAddress (myAddress ().asSlice ());
13035 let addr = parseStdAddress (sender ().asSlice ());
@@ -148,13 +53,13 @@ contract WalletV5(
14853
14954 let isSignatureValid = checkSignature (signedSlice .hash (), signature , self .publicKey );
15055 if (! isSignatureValid ) {
151- return ;
56+ throw ( 0 ) ;
15257 }
15358
154- throwIf (132 , ! self .isSignatureAllowed && self .extensions .isEmpty ());
155- throwUnless (133 , msg .seqno == self .seqno );
156- throwUnless (134 , msg .walletId == self .walletId );
157- throwIf (136 , msg .validUntil <= now ());
59+ throwIf (signatureDisabled , ! self .isSignatureAllowed && self .extensions .isEmpty ());
60+ throwUnless (invalidSeqno , msg .seqno == self .seqno );
61+ throwUnless (invalidWalletId , msg .walletId == self .walletId );
62+ throwIf (expired , msg .validUntil <= now ());
15863
15964 self .seqno += 1 ;
16065 commit ();
@@ -177,10 +82,10 @@ contract WalletV5(
17782 throw (135 );
17883 }
17984
180- throwIf (132 , ! self .isSignatureAllowed && self .extensions .isEmpty ());
181- throwUnless (133 , msg .seqno == self .seqno );
182- throwUnless (134 , msg .walletId == self .walletId );
183- throwIf (136 , msg .validUntil <= now ());
85+ throwIf (signatureDisabled , ! self .isSignatureAllowed && self .extensions .isEmpty ());
86+ throwUnless (invalidSeqno , msg .seqno == self .seqno );
87+ throwUnless (invalidWalletId , msg .walletId == self .walletId );
88+ throwIf (expired , msg .validUntil <= now ());
18489
18590 acceptMessage ();
18691
@@ -192,6 +97,82 @@ contract WalletV5(
19297 self .processActions (signedSlice , true , false );
19398 }
19499
100+ // / Actions has the following structure:
101+ // /
102+ // / ```tact
103+ // / struct Action {
104+ // / outActions: Cell?;
105+ // / hasOtherActions: Bool;
106+ // / actions: Slice as remaining; // tl-b for ext actions
107+ // / }
108+ // / ```
109+ // /
110+ // / TL-B:
111+ // /
112+ // / ```tlb
113+ // / out_list_empty$_ = OutList 0;
114+ // / out_list$_ {n:#} prev:^(OutList n) action:OutAction = OutList (n + 1);
115+ // / action_send_msg#0ec3c86d mode:(## 8) out_msg:^(MessageRelaxed Any) = OutAction;
116+ // /
117+ // / // Extended actions in W5:
118+ // / action_list_basic$_ {n:#} actions:^(OutList n) = ActionList n 0;
119+ // / action_list_extended$_ {m:#} {n:#} action:ExtendedAction prev:^(ActionList n m) = ActionList n (m+1);
120+ // /
121+ // / action_add_ext#02 addr:MsgAddressInt = ExtendedAction;
122+ // / action_delete_ext#03 addr:MsgAddressInt = ExtendedAction;
123+ // / action_set_signature_auth_allowed#04 allowed:(## 1) = ExtendedAction;
124+ // / ```
125+ inline fun processActions (actions : Slice , isExternal : Bool , isExtension : Bool ) {
126+ let outActions = actions .loadMaybeRef ();
127+ if (outActions != null ) {
128+ setC5 (processSendMessages (outActions !! , isExternal ));
129+ }
130+
131+ if (! actions .loadBool ()) {
132+ return ;
133+ }
134+
135+ while (true ) {
136+ // check tag, process action, try to load next ref while we can
137+ let isAddExt = actions .checkAndRemoveAddExtensionPrefix ();
138+ let isDeleteExt = isAddExt ? false : actions .checkAndRemoveDeleteExtensionPrefix ();
139+
140+ if (isAddExt || isDeleteExt ) {
141+ let addr = parseStdAddress (actions .loadAddress ().asSlice ());
142+ let myAddr = parseStdAddress (myAddress ().asSlice ());
143+
144+ throwUnless (extensionWrongWorkchain , addr .workchain == myAddr .workchain ); // force_workchain optimization
145+
146+ if (isAddExt ) {
147+ // blocked by https://github.com/tact-lang/tact/issues/2842
148+ // throwUnless(139, self.extensions.add(addr.address, true));
149+ throwIf (addExtension , self .extensions .exists (addr .address ));
150+ self .extensions .set (addr .address , true );
151+ } else if (isDeleteExt ) {
152+ throwUnless (removeExtension , self .extensions .del (addr .address ));
153+ throwIf (removeLastExtensionWhenSignatureDisabled , self .extensions .isEmpty () && ! self .isSignatureAllowed );
154+ }
155+ } else if (actions .checkAndRemoveSetSignAllowedPrefix ()) {
156+ throwUnless (onlyExtensionCanChangeSignatureMode , isExtension );
157+ let newSignMode = actions .loadBool ();
158+ throwIf (thisSignatureModeAlreadySet , newSignMode == self .isSignatureAllowed );
159+ self .isSignatureAllowed = newSignMode ;
160+
161+ if (! self .isSignatureAllowed && self .extensions .isEmpty ()) {
162+ throw (disableSignatureWhenExtensionsIsEmpty );
163+ }
164+ } else {
165+ throw (unsupportedAction );
166+ }
167+
168+ if (actions .refsEmpty ()) {
169+ return ;
170+ }
171+
172+ actions = actions .preloadRef ().beginParse ();
173+ }
174+ }
175+
195176 get fun seqno (): Int {
196177 return self .seqno ;
197178 }
@@ -216,16 +197,29 @@ inline fun processSendMessages(outActions: Cell, isExternal: Bool): Cell {
216197 while (! cs .empty ()) {
217198 cs .enforceAndRemoveActionSendMsgPrefix ();
218199
219- throwUnless (147 , cs .bits () == 8 );
220- throwUnless (147 , cs .refs () == 2 );
221- throwIf (137 , isExternal && (countTrailingZeroes (cs .preloadBits (7 )) > 0 ));
200+ throwUnless (invalidC5 , cs .bits () == 8 );
201+ throwUnless (invalidC5 , cs .refs () == 2 );
202+ throwIf (externalSendMessageMustHaveIgnoreErrorsSendMode , isExternal && (countTrailingZeroes (cs .preloadBits (7 )) > 0 ));
222203
223204 cs = cs .preloadRef ().beginParseExotic ().data ;
224205 count += 1 ;
225206 }
226207
227- throwUnless (147 , count <= 255 );
228- throwUnless (147 , cs .refs () == 0 );
208+ throwUnless (invalidC5 , count <= 255 );
209+ throwUnless (invalidC5 , cs .refs () == 0 );
229210
230211 return outActions ;
231212}
213+
214+ asm fun countTrailingZeroes (s : Slice ): Int { SDCNTTRAIL0 }
215+ struct SliceFlag {
216+ data : Slice ;
217+ flag : Bool ;
218+ }
219+ asm extends fun beginParseExotic (self : Cell ): SliceFlag { XCTOS }
220+ asm extends mutates fun enforceAndRemoveActionSendMsgPrefix (self : Slice ) { x {0ec3c86d} SDBEGINS }
221+ asm fun setC5 (outActions : Cell ) { c5 POP }
222+
223+ asm extends mutates fun checkAndRemoveAddExtensionPrefix (self : Slice ): Bool { x {02 } SDBEGINSQ }
224+ asm extends mutates fun checkAndRemoveDeleteExtensionPrefix (self : Slice ): Bool { x {03 } SDBEGINSQ }
225+ asm extends mutates fun checkAndRemoveSetSignAllowedPrefix (self : Slice ): Bool { x {04 } SDBEGINSQ }
0 commit comments