@@ -36,9 +36,9 @@ def _fail(msg: str):
3636def test_factory_registers_six_families ():
3737 print ("\n [1] Factory registration" )
3838 fams = list_adapters ()
39- expected = {"jsonrpc" , "rest" , "tendermint" , "bitcoin_jsonrpc" , "substrate" , "ogmios" }
39+ expected = {"jsonrpc" , "rest" , "tendermint" , "bitcoin_jsonrpc" , "substrate" , "ogmios" , "tron" }
4040 assert set (fams ) == expected , f"expected { expected } , got { fams } "
41- _ok (f"6 families registered: { sorted (fams )} " )
41+ _ok (f"7 families registered: { sorted (fams )} " )
4242
4343
4444# ─────────────────────────────────────────────────────────────────────────────
@@ -310,6 +310,89 @@ def test_evm_compat_5chains_standard_enum():
310310 _ok (f"{ chain } : { len (pf )} formats all standard" )
311311
312312
313+ # ─────────────────────────────────────────────────────────────────────────────
314+ # Test 10: TronAdapter — dual-protocol shapes
315+ # ─────────────────────────────────────────────────────────────────────────────
316+ def test_tron_adapter_shapes ():
317+ print ("\n [10] TronAdapter: HTTP /wallet/* + JSON-RPC /jsonrpc subset" )
318+ import base64
319+ a = get_adapter ("tron" )
320+ assert a .protocol_family == "tron" , f"expected 'tron', got { a .protocol_family !r} "
321+
322+ BASE = "http://localhost:8545"
323+ ADDR = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" # base58 tron address
324+
325+ # 10a: /wallet/getnowblock → empty body
326+ t = a .build_vegeta_target ("/wallet/getnowblock" , ADDR , BASE , "no_params" )
327+ assert t ["method" ] == "POST"
328+ assert t ["url" ] == "http://localhost:8545/wallet/getnowblock" , f"bad url: { t ['url' ]} "
329+ body = json .loads (base64 .b64decode (t ["body" ]))
330+ assert body == {}, f"expected empty body, got { body } "
331+ _ok (f"/wallet/getnowblock → POST { t ['url' ]} body={{}}" )
332+
333+ # 10b: /wallet/getaccount → {address, visible}
334+ t = a .build_vegeta_target ("/wallet/getaccount" , ADDR , BASE , "body_address_visible" )
335+ body = json .loads (base64 .b64decode (t ["body" ]))
336+ assert body == {"address" : ADDR , "visible" : True }, f"bad body: { body } "
337+ _ok (f"/wallet/getaccount → body={{address: { ADDR [:10 ]} ..., visible: True}}" )
338+
339+ # 10c: /wallet/gettransactionbyid → {value: txid_no_0x}
340+ txid = "0xabc123" + "0" * 58
341+ t = a .build_vegeta_target ("/wallet/gettransactionbyid" , txid , BASE , "body_value_txid_nopfx" )
342+ body = json .loads (base64 .b64decode (t ["body" ]))
343+ assert body ["value" ] == "abc123" + "0" * 58 , f"expected stripped 0x: { body } "
344+ _ok (f"/wallet/gettransactionbyid → body.value 0x-stripped" )
345+
346+ # 10d: /wallet/triggerconstantcontract → 5-field body
347+ t = a .build_vegeta_target (
348+ "/wallet/triggerconstantcontract" , ADDR , BASE ,
349+ "body_owner_contract_selector_parameter" ,
350+ )
351+ body = json .loads (base64 .b64decode (t ["body" ]))
352+ assert body ["function_selector" ] == "balanceOf(address)" , f"bad selector: { body .get ('function_selector' )} "
353+ assert body ["owner_address" ] == ADDR
354+ assert len (body ["parameter" ]) == 64 , f"parameter must be 32-byte hex, got len={ len (body ['parameter' ])} "
355+ _ok (f"/wallet/triggerconstantcontract → 5-field body with balanceOf selector" )
356+
357+ # 10e: JSON-RPC subset routes to /jsonrpc path
358+ t = a .build_vegeta_target ("eth_blockNumber" , ADDR , BASE , "no_params" )
359+ assert t ["url" ] == "http://localhost:8545/jsonrpc" , f"jsonrpc path mismatch: { t ['url' ]} "
360+ body = json .loads (base64 .b64decode (t ["body" ]))
361+ assert body ["method" ] == "eth_blockNumber"
362+ assert body ["params" ] == []
363+ _ok (f"eth_blockNumber → POST /jsonrpc with JSON-RPC envelope" )
364+
365+ # 10f: parse_block_height — Tron getnowblock response
366+ sample = json .dumps ({
367+ "blockID" : "0" * 64 ,
368+ "block_header" : {"raw_data" : {"number" : 60100000 , "timestamp" : 1735200000000 }},
369+ })
370+ h = a .parse_block_height (sample )
371+ assert h == 60100000 , f"expected 60100000, got { h } "
372+ _ok (f"parse_block_height Tron envelope → 60100000" )
373+
374+ # 10g: parse_block_height — JSON-RPC fallback
375+ rpc_sample = json .dumps ({"jsonrpc" : "2.0" , "id" : 1 , "result" : "0x3947ea0" })
376+ h = a .parse_block_height (rpc_sample )
377+ assert h == 0x3947ea0 , f"expected { 0x3947ea0 } , got { h } "
378+ _ok (f"parse_block_height JSON-RPC fallback → { 0x3947ea0 } " )
379+
380+ # 10h: health_check_request shape
381+ hc = a .health_check_request (BASE )
382+ assert hc ["method" ] == "POST"
383+ assert hc ["url" ] == BASE + "/wallet/getnowblock"
384+ assert hc ["body" ] == "{}"
385+ assert hc ["parse_jq" ] == ".block_header.raw_data.number"
386+ _ok (f"health_check → POST /wallet/getnowblock + parse_jq" )
387+
388+ # 10i: unknown method shape → raises
389+ try :
390+ a .build_vegeta_target ("foo_bar" , ADDR , BASE , "" )
391+ _fail ("expected ValueError for unknown method" )
392+ except ValueError as e :
393+ _ok (f"unknown method raises ValueError: { str (e )[:60 ]} " )
394+
395+
313396# ─────────────────────────────────────────────────────────────────────────────
314397# Main
315398# ─────────────────────────────────────────────────────────────────────────────
@@ -324,6 +407,7 @@ def main():
324407 test_rest_requires_env_and_path_map ,
325408 test_jsonrpc_s3a_new_formats ,
326409 test_evm_compat_5chains_standard_enum ,
410+ test_tron_adapter_shapes ,
327411 ]
328412 print (f"Running { len (tests )} test groups for chain_adapters" )
329413 for t in tests :
0 commit comments