@@ -511,5 +511,55 @@ describe('Sui Transfer Builder', () => {
511511 should . exist ( epochVal ) ;
512512 Number ( epochVal ) . should . equal ( 324 ) ;
513513 } ) ;
514+
515+ it ( 'should round-trip a self-pay transfer with ValidDuring expiration via fromBytes' , async function ( ) {
516+ // Verifies the full 6-field ValidDuringExpiration BCS schema:
517+ // minEpoch/maxEpoch as Option<u64>, minTimestamp/maxTimestamp as Option<u64> (None),
518+ // chain as 32-byte Base58 ObjectDigest, nonce as u32.
519+ // Uses a real mainnet genesis checkpoint digest (32 bytes, Base58).
520+ const GENESIS_CHAIN_ID = 'GAFpCCcRCxTdFfUEMbQbkLBaZy2RNiGAfvFBhMNpq2kT' ;
521+ const FUNDS_IN_ADDRESS_BALANCE = '5000000000' ;
522+ const gasDataNoPayment = {
523+ ...testData . gasDataWithoutGasPayment ,
524+ payment : [ ] ,
525+ } ;
526+
527+ const txBuilder = factory . getTransferBuilder ( ) ;
528+ txBuilder . type ( SuiTransactionType . Transfer ) ;
529+ txBuilder . sender ( testData . sender . address ) ;
530+ txBuilder . send ( testData . recipients ) ;
531+ txBuilder . gasData ( gasDataNoPayment ) ;
532+ txBuilder . fundsInAddressBalance ( FUNDS_IN_ADDRESS_BALANCE ) ;
533+ txBuilder . expiration ( {
534+ ValidDuring : {
535+ minEpoch : { Some : 500 } ,
536+ maxEpoch : { Some : 501 } ,
537+ minTimestamp : { None : null } ,
538+ maxTimestamp : { None : null } ,
539+ chain : GENESIS_CHAIN_ID ,
540+ nonce : 0xdeadbeef ,
541+ } ,
542+ } ) ;
543+
544+ const tx = await txBuilder . build ( ) ;
545+ const rawTx = tx . toBroadcastFormat ( ) ;
546+ should . equal ( utils . isValidRawTransaction ( rawTx ) , true ) ;
547+
548+ // fromBytes must not throw — ValidDuring fields must survive deserialization
549+ const rebuilder = factory . from ( rawTx ) ;
550+ rebuilder . addSignature ( { pub : testData . sender . publicKey } , Buffer . from ( testData . sender . signatureHex ) ) ;
551+ const rebuiltTx = await rebuilder . build ( ) ;
552+
553+ // BCS round-trip: serialized bytes must be identical
554+ rebuiltTx . toBroadcastFormat ( ) . should . equal ( rawTx ) ;
555+
556+ // All ValidDuring fields must survive the round-trip
557+ const expiration = ( rebuiltTx . toJson ( ) . expiration as any ) ?. ValidDuring ;
558+ should . exist ( expiration ) ;
559+ Number ( expiration . minEpoch ?. Some ?? expiration . minEpoch ) . should . equal ( 500 ) ;
560+ Number ( expiration . maxEpoch ?. Some ?? expiration . maxEpoch ) . should . equal ( 501 ) ;
561+ expiration . chain . should . equal ( GENESIS_CHAIN_ID ) ;
562+ Number ( expiration . nonce ) . should . equal ( 0xdeadbeef ) ;
563+ } ) ;
514564 } ) ;
515565} ) ;
0 commit comments