@@ -470,5 +470,46 @@ describe('Sui Transfer Builder', () => {
470470 const rawTx = tx . toBroadcastFormat ( ) ;
471471 should . equal ( utils . isValidRawTransaction ( rawTx ) , true ) ;
472472 } ) ;
473+
474+ it ( 'should round-trip a self-pay transfer with Epoch expiration via fromBytes' , async function ( ) {
475+ // Regression test for the BigInt round-trip bug:
476+ // BCS.U64 deserializes u64 as BigInt, but the previous superstruct schema used integer()
477+ // which rejected BigInt, causing fromBytes() to throw a StructError at "expiration".
478+ // StringEncodedBigint now accepts string | number | bigint, fixing the round-trip.
479+ const gasDataNoPayment = {
480+ ...testData . gasDataWithoutGasPayment ,
481+ payment : [ ] ,
482+ } ;
483+
484+ const txBuilder = factory . getTransferBuilder ( ) ;
485+ txBuilder . type ( SuiTransactionType . Transfer ) ;
486+ txBuilder . sender ( testData . sender . address ) ;
487+ txBuilder . send ( testData . recipients ) ;
488+ txBuilder . gasData ( gasDataNoPayment ) ;
489+ txBuilder . fundsInAddressBalance ( FUNDS_IN_ADDRESS_BALANCE ) ;
490+ txBuilder . expiration ( { Epoch : 324 } ) ; // number input
491+
492+ const tx = await txBuilder . build ( ) ;
493+ const rawTx = tx . toBroadcastFormat ( ) ;
494+ should . equal ( utils . isValidRawTransaction ( rawTx ) , true ) ;
495+
496+ // fromBytes must not throw StructError — this was the failing case before the fix
497+ should . doesNotThrow ( ( ) => {
498+ const rebuilder = factory . from ( rawTx ) ;
499+ should . exist ( rebuilder ) ;
500+ } ) ;
501+
502+ // Full round-trip: rebuilt tx must serialize identically
503+ const rebuilder = factory . from ( rawTx ) ;
504+ rebuilder . addSignature ( { pub : testData . sender . publicKey } , Buffer . from ( testData . sender . signatureHex ) ) ;
505+ const rebuiltTx = await rebuilder . build ( ) ;
506+ rebuiltTx . toBroadcastFormat ( ) . should . equal ( rawTx ) ;
507+
508+ // Epoch value must survive the round-trip regardless of BigInt/number representation
509+ const rebuiltJson = rebuiltTx . toJson ( ) ;
510+ const epochVal = ( rebuiltJson . expiration as any ) ?. Epoch ;
511+ should . exist ( epochVal ) ;
512+ Number ( epochVal ) . should . equal ( 324 ) ;
513+ } ) ;
473514 } ) ;
474515} ) ;
0 commit comments