@@ -101,12 +101,34 @@ async def test_submit_tx_success(self, mock_async_client_class):
101101 "gas" : 100000 ,
102102 "value" : 0 ,
103103 }
104- result = await client .submit_tx (tx , encrypt = False )
104+ result = await client .submit_tx (tx )
105105
106106 # Verify - returns RoflSubmissionResult with hex-encoded CBOR as submission_id
107107 expected = cbor2 .dumps ({"ok" : b"" }).hex ()
108108 self .assertEqual (result .submission_id , expected )
109109 self .assertEqual (result .ok_payload , b"" )
110+ mock_client .sign_submit .assert_awaited_once_with (tx , True )
111+
112+ @patch ("src.clients.rofl.AsyncRoflClient" )
113+ async def test_submit_tx_encrypts_by_default (self , mock_async_client_class ):
114+ """Test that submit_tx encrypts transactions unless explicitly disabled."""
115+ from src .clients .rofl import RoflAppdClient
116+
117+ mock_client = MagicMock ()
118+ mock_client .sign_submit = AsyncMock (return_value = {"ok" : b"" })
119+ mock_async_client_class .return_value = mock_client
120+
121+ client = RoflAppdClient ()
122+ tx : TxParams = {
123+ "to" : "0x0987654321098765432109876543210987654321" ,
124+ "data" : "0xabcdef" ,
125+ "gas" : 100000 ,
126+ "value" : 0 ,
127+ }
128+
129+ await client .submit_tx (tx )
130+
131+ mock_client .sign_submit .assert_awaited_once_with (tx , True )
110132
111133 @patch ("src.clients.rofl.AsyncRoflClient" )
112134 async def test_submit_tx_reverted_raises_error (self , mock_async_client_class ):
@@ -135,13 +157,58 @@ async def test_submit_tx_reverted_raises_error(self, mock_async_client_class):
135157
136158 # Should raise TransactionRevertedError
137159 with self .assertRaises (TransactionRevertedError ) as ctx :
138- await client .submit_tx (tx , encrypt = False )
160+ await client .submit_tx (tx )
139161
140162 error = ctx .exception
141163 self .assertEqual (error .code , 8 )
142164 self .assertEqual (error .module , "evm" )
143165 self .assertIn ("InvalidSignature" , str (error ))
144166
167+ @patch ("src.clients.rofl.AsyncRoflClient" )
168+ async def test_submit_tx_rejects_unallowlisted_plaintext (self , mock_async_client_class ):
169+ """Test that plaintext submission is blocked unless allow-listed."""
170+ from src .clients .rofl import RoflAppdClient
171+
172+ mock_client = MagicMock ()
173+ mock_client .sign_submit = AsyncMock (return_value = {"ok" : b"" })
174+ mock_async_client_class .return_value = mock_client
175+
176+ client = RoflAppdClient ()
177+ tx : TxParams = {
178+ "to" : "0x0987654321098765432109876543210987654321" ,
179+ "data" : "0xabcdef01" ,
180+ "gas" : 100000 ,
181+ "value" : 0 ,
182+ }
183+
184+ with self .assertRaises (ValueError ) as ctx :
185+ await client .submit_tx (tx , encrypt = False )
186+
187+ self .assertIn ("Plaintext ROFL transaction submission is not allowed" , str (ctx .exception ))
188+ mock_client .sign_submit .assert_not_awaited ()
189+
190+ @patch ("src.clients.rofl._PLAINTEXT_TX_SELECTOR_ALLOWLIST" , frozenset ({"abcdef01" }))
191+ @patch ("src.clients.rofl.AsyncRoflClient" )
192+ async def test_submit_tx_allows_allowlisted_plaintext_selector (self , mock_async_client_class ):
193+ """Test that plaintext submission requires a reviewed selector allow-list entry."""
194+ from src .clients .rofl import RoflAppdClient
195+
196+ mock_client = MagicMock ()
197+ mock_client .sign_submit = AsyncMock (return_value = {"ok" : b"" })
198+ mock_async_client_class .return_value = mock_client
199+
200+ client = RoflAppdClient ()
201+ tx : TxParams = {
202+ "to" : "0x0987654321098765432109876543210987654321" ,
203+ "data" : "0xabcdef0100000000" ,
204+ "gas" : 100000 ,
205+ "value" : 0 ,
206+ }
207+
208+ await client .submit_tx (tx , encrypt = False )
209+
210+ mock_client .sign_submit .assert_awaited_once_with (tx , False )
211+
145212 @patch ("src.clients.rofl.AsyncRoflClient" )
146213 async def test_submit_tx_requires_to_and_data (self , mock_async_client_class ):
147214 """Test that submit_tx raises ValueError without 'to' or 'data'."""
0 commit comments