@@ -12,14 +12,15 @@ import {
1212 utils as FlareUtils ,
1313 Credential ,
1414 pvmSerial ,
15+ evmSerial ,
1516 UnsignedTx ,
1617 secp256k1 ,
1718 EVMUnsignedTx ,
1819 Address ,
1920} from '@flarenetwork/flarejs' ;
2021import { Buffer } from 'buffer' ;
2122import { createHash } from 'crypto' ;
22- import { DecodedUtxoObj , TransactionExplanation , Tx , TxData } from './iface' ;
23+ import { DecodedUtxoObj , TransactionExplanation , Tx , TxData , ADDRESS_SEPARATOR , FlareTransactionType } from './iface' ;
2324import { KeyPair } from './keyPair' ;
2425import utils from './utils' ;
2526
@@ -288,28 +289,132 @@ export class Transaction extends BaseTransaction {
288289 return { fee : '0' , ...this . _fee } ;
289290 }
290291
292+ /**
293+ * Check if this transaction is for C-chain (EVM transactions)
294+ */
295+ get isTransactionForCChain ( ) : boolean {
296+ const tx = ( this . _flareTransaction as UnsignedTx ) . getTx ( ) ;
297+ const txType = ( tx as { _type ?: string } ) . _type ;
298+ return txType === FlareTransactionType . EvmExportTx || txType === FlareTransactionType . EvmImportTx ;
299+ }
300+
291301 get outputs ( ) : Entry [ ] {
302+ const tx = ( this . _flareTransaction as UnsignedTx ) . getTx ( ) ;
303+
292304 switch ( this . type ) {
305+ case TransactionType . Import :
306+ if ( this . isTransactionForCChain ) {
307+ // C-chain Import: output is to a C-chain address
308+ const importTx = tx as evmSerial . ImportTx ;
309+ return importTx . Outs . map ( ( out ) => ( {
310+ address : '0x' + Buffer . from ( out . address . toBytes ( ) ) . toString ( 'hex' ) ,
311+ value : out . amount . value ( ) . toString ( ) ,
312+ } ) ) ;
313+ } else {
314+ // P-chain Import: outputs are the baseTx.outputs (destination on P-chain)
315+ const pvmImportTx = tx as pvmSerial . ImportTx ;
316+ return pvmImportTx . baseTx . outputs . map ( utils . mapOutputToEntry ( this . _network ) ) ;
317+ }
318+
319+ case TransactionType . Export :
320+ if ( this . isTransactionForCChain ) {
321+ // C-chain Export: exported outputs go to P-chain
322+ const exportTx = tx as evmSerial . ExportTx ;
323+ return exportTx . exportedOutputs . map ( utils . mapOutputToEntry ( this . _network ) ) ;
324+ } else {
325+ // P-chain Export: exported outputs go to C-chain
326+ const pvmExportTx = tx as pvmSerial . ExportTx ;
327+ return pvmExportTx . outs . map ( utils . mapOutputToEntry ( this . _network ) ) ;
328+ }
329+
293330 case TransactionType . AddPermissionlessValidator :
294331 return [
295332 {
296- address : (
297- ( this . _flareTransaction as UnsignedTx ) . getTx ( ) as pvmSerial . AddPermissionlessValidatorTx
298- ) . subnetValidator . validator . nodeId . toString ( ) ,
299- value : (
300- ( this . _flareTransaction as UnsignedTx ) . getTx ( ) as pvmSerial . AddPermissionlessValidatorTx
301- ) . subnetValidator . validator . weight . toJSON ( ) ,
333+ address : ( tx as pvmSerial . AddPermissionlessValidatorTx ) . subnetValidator . validator . nodeId . toString ( ) ,
334+ value : ( tx as pvmSerial . AddPermissionlessValidatorTx ) . subnetValidator . validator . weight . toJSON ( ) ,
302335 } ,
303336 ] ;
337+
304338 default :
305339 return [ ] ;
306340 }
307341 }
308342
309343 get changeOutputs ( ) : Entry [ ] {
310- return (
311- ( this . _flareTransaction as UnsignedTx ) . getTx ( ) as pvmSerial . AddPermissionlessValidatorTx
312- ) . baseTx . outputs . map ( utils . mapOutputToEntry ( this . _network ) ) ;
344+ const tx = ( this . _flareTransaction as UnsignedTx ) . getTx ( ) ;
345+
346+ // C-chain transactions and Import transactions don't have change outputs
347+ if ( this . isTransactionForCChain || this . type === TransactionType . Import ) {
348+ return [ ] ;
349+ }
350+
351+ switch ( this . type ) {
352+ case TransactionType . Export :
353+ // P-chain Export: change outputs are in baseTx.outputs
354+ return ( tx as pvmSerial . ExportTx ) . baseTx . outputs . map ( utils . mapOutputToEntry ( this . _network ) ) ;
355+
356+ case TransactionType . AddPermissionlessValidator :
357+ return ( tx as pvmSerial . AddPermissionlessValidatorTx ) . baseTx . outputs . map ( utils . mapOutputToEntry ( this . _network ) ) ;
358+
359+ default :
360+ return [ ] ;
361+ }
362+ }
363+
364+ get inputs ( ) : Entry [ ] {
365+ const tx = ( this . _flareTransaction as UnsignedTx ) . getTx ( ) ;
366+
367+ switch ( this . type ) {
368+ case TransactionType . Import :
369+ if ( this . isTransactionForCChain ) {
370+ // C-chain Import: inputs come from P-chain (importedInputs)
371+ const importTx = tx as evmSerial . ImportTx ;
372+ return importTx . importedInputs . map ( ( input ) => ( {
373+ id : utils . cb58Encode ( Buffer . from ( input . utxoID . txID . toBytes ( ) ) ) + ':' + input . utxoID . outputIdx . value ( ) ,
374+ address : this . fromAddresses . sort ( ) . join ( ADDRESS_SEPARATOR ) ,
375+ value : input . amount ( ) . toString ( ) ,
376+ } ) ) ;
377+ } else {
378+ // P-chain Import: inputs are ins (imported from C-chain)
379+ const pvmImportTx = tx as pvmSerial . ImportTx ;
380+ return pvmImportTx . ins . map ( ( input ) => ( {
381+ id : utils . cb58Encode ( Buffer . from ( input . utxoID . txID . toBytes ( ) ) ) + ':' + input . utxoID . outputIdx . value ( ) ,
382+ address : this . fromAddresses . sort ( ) . join ( ADDRESS_SEPARATOR ) ,
383+ value : input . amount ( ) . toString ( ) ,
384+ } ) ) ;
385+ }
386+
387+ case TransactionType . Export :
388+ if ( this . isTransactionForCChain ) {
389+ // C-chain Export: inputs are from C-chain (EVM inputs)
390+ const exportTx = tx as evmSerial . ExportTx ;
391+ return exportTx . ins . map ( ( evmInput ) => ( {
392+ address : '0x' + Buffer . from ( evmInput . address . toBytes ( ) ) . toString ( 'hex' ) ,
393+ value : evmInput . amount . value ( ) . toString ( ) ,
394+ nonce : Number ( evmInput . nonce . value ( ) ) ,
395+ } ) ) ;
396+ } else {
397+ // P-chain Export: inputs are from baseTx.inputs
398+ const pvmExportTx = tx as pvmSerial . ExportTx ;
399+ return pvmExportTx . baseTx . inputs . map ( ( input ) => ( {
400+ id : utils . cb58Encode ( Buffer . from ( input . utxoID . txID . toBytes ( ) ) ) + ':' + input . utxoID . outputIdx . value ( ) ,
401+ address : this . fromAddresses . sort ( ) . join ( ADDRESS_SEPARATOR ) ,
402+ value : input . amount ( ) . toString ( ) ,
403+ } ) ) ;
404+ }
405+
406+ case TransactionType . AddPermissionlessValidator :
407+ default :
408+ const baseTx = tx as pvmSerial . AddPermissionlessValidatorTx ;
409+ if ( baseTx . baseTx ?. inputs ) {
410+ return baseTx . baseTx . inputs . map ( ( input ) => ( {
411+ id : utils . cb58Encode ( Buffer . from ( input . utxoID . txID . toBytes ( ) ) ) + ':' + input . utxoID . outputIdx . value ( ) ,
412+ address : this . fromAddresses . sort ( ) . join ( ADDRESS_SEPARATOR ) ,
413+ value : input . amount ( ) . toString ( ) ,
414+ } ) ) ;
415+ }
416+ return [ ] ;
417+ }
313418 }
314419
315420 explainTransaction ( ) : TransactionExplanation {
0 commit comments