@@ -253,7 +253,7 @@ class TransactionPayload:
253253 SCRIPT : int = 0
254254 MODULE_BUNDLE : int = 1
255255 SCRIPT_FUNCTION : int = 2
256- INNER_PAYLOAD : int = 4
256+ INNER_PAYLOAD : int = 4
257257
258258 variant : int
259259 value : Any
@@ -265,7 +265,7 @@ def __init__(self, payload: Any):
265265 self .variant = TransactionPayload .MODULE_BUNDLE
266266 elif isinstance (payload , EntryFunction ):
267267 self .variant = TransactionPayload .SCRIPT_FUNCTION
268- elif isinstance (payload , OrderlessPayload ):
268+ elif isinstance (payload , OrderlessPayload ):
269269 self .variant = TransactionPayload .INNER_PAYLOAD
270270 else :
271271 raise Exception ("Invalid type" )
@@ -298,6 +298,7 @@ def serialize(self, serializer: Serializer) -> None:
298298 serializer .uleb128 (self .variant )
299299 self .value .serialize (serializer )
300300
301+
301302class ModuleBundle :
302303 def __init__ (self ):
303304 raise NotImplementedError
@@ -479,45 +480,95 @@ def serialize(self, serializer: Serializer) -> None:
479480 serializer .sequence (self .ty_args , Serializer .struct )
480481 serializer .sequence (self .args , Serializer .to_bytes )
481482
483+
482484class OrderlessPayload :
483485 """Orderless transaction payload wrapper"""
484-
485- def __init__ (self , entry_function : EntryFunction , nonce : int ):
486- self .entry_function = entry_function
486+
487+ # OrderlessTransactionPayload variants
488+ ORDERLESS_V1 : int = 0
489+
490+ # Executable variants
491+ EXECUTABLE_SCRIPT : int = 0
492+ EXECUTABLE_ENTRY_FUNCTION : int = 1
493+ EXECUTABLE_EMPTY : int = 2 # For multisig voting without execution
494+
495+ # ExtraConfig variants
496+ EXTRA_CONFIG_V1 : int = 0
497+
498+ def __init__ (
499+ self ,
500+ executable : Optional [Union [Script , EntryFunction ]],
501+ nonce : int ,
502+ multisig_address : Optional [AccountAddress ] = None ,
503+ ):
504+ """
505+ Create an orderless transaction payload.
506+
507+ :param executable: Script or EntryFunction to execute. None for multisig voting.
508+ :param nonce: Unique nonce for replay protection
509+ :param multisig_address: Address of multisig account (required for multisig transactions)
510+ """
511+ if executable is not None and not isinstance (
512+ executable , (Script , EntryFunction )
513+ ):
514+ raise ValueError ("Executable must be either Script or EntryFunction" )
515+
516+ # If no executable, must be multisig voting
517+ if executable is None and multisig_address is None :
518+ raise ValueError ("Either executable or multisig_address must be provided" )
519+
520+ self .executable = executable
487521 self .nonce = nonce
488-
522+ self .multisig_address = multisig_address
523+
489524 def serialize (self , serializer : Serializer ):
490525 """Serialize orderless payload WITHOUT the outer variant (TransactionPayload handles that)"""
491-
526+
492527 # OrderlessTransactionPayload::V1 variant
493- serializer .uleb128 (0 )
494-
495- # Executable::EntryFunction variant
496- serializer .uleb128 (1 )
497-
498- # Serialize the entry function
499- self .entry_function .serialize (serializer )
500-
528+ serializer .uleb128 (OrderlessPayload .ORDERLESS_V1 )
529+
530+ # Executable variant
531+ if self .executable is None :
532+ # Empty executable for multisig voting
533+ serializer .uleb128 (OrderlessPayload .EXECUTABLE_EMPTY )
534+ elif isinstance (self .executable , Script ):
535+ serializer .uleb128 (OrderlessPayload .EXECUTABLE_SCRIPT )
536+ self .executable .serialize (serializer )
537+ elif isinstance (self .executable , EntryFunction ):
538+ serializer .uleb128 (OrderlessPayload .EXECUTABLE_ENTRY_FUNCTION )
539+ self .executable .serialize (serializer )
540+ else :
541+ raise ValueError ("Invalid executable type" )
542+
501543 # ExtraConfig::V1 variant
502- serializer .uleb128 (0 )
503-
504- # Option<MultisigAddress> - None
505- serializer .bool (False )
506-
544+ serializer .uleb128 (OrderlessPayload .EXTRA_CONFIG_V1 )
545+
546+ # Option<MultisigAddress>
547+ if self .multisig_address is not None :
548+ serializer .bool (True ) # Some
549+ self .multisig_address .serialize (serializer )
550+ else :
551+ serializer .bool (False ) # None
552+
507553 # Option<u64> nonce - Some
508554 serializer .bool (True )
509555 serializer .u64 (self .nonce )
510-
556+
511557 def __eq__ (self , other : object ) -> bool :
512558 if not isinstance (other , OrderlessPayload ):
513559 return NotImplemented
514560 return (
515- self .entry_function == other .entry_function
561+ self .executable == other .executable
516562 and self .nonce == other .nonce
563+ and self .multisig_address == other .multisig_address
517564 )
518-
565+
519566 def __str__ (self ):
520- return f"OrderlessPayload(nonce={ self .nonce } , { self .entry_function } )"
567+ multisig_str = (
568+ f", multisig={ self .multisig_address } " if self .multisig_address else ""
569+ )
570+ return f"OrderlessPayload(nonce={ self .nonce } , { self .executable } { multisig_str } )"
571+
521572
522573class ModuleId :
523574 address : AccountAddress
@@ -939,4 +990,4 @@ def test_deserialize_raw_transaction_multi_agent(self):
939990 raw_txn_with_data .serialize (ser )
940991 self .assertEqual (ser .output ().hex (), input_ma )
941992
942- self .assertTrue (isinstance (raw_txn_with_data , MultiAgentRawTransaction ))
993+ self .assertTrue (isinstance (raw_txn_with_data , MultiAgentRawTransaction ))
0 commit comments