2022-09-05 16:57:11 -04:00
"use strict" ;
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
exports . Transaction = void 0 ;
const index _js _1 = require ( "../address/index.js" ) ;
2024-02-02 03:25:03 -05:00
const addresses _js _1 = require ( "../constants/addresses.js" ) ;
2022-09-05 16:57:11 -04:00
const index _js _2 = require ( "../crypto/index.js" ) ;
const index _js _3 = require ( "../utils/index.js" ) ;
const accesslist _js _1 = require ( "./accesslist.js" ) ;
const address _js _1 = require ( "./address.js" ) ;
const BN _0 = BigInt ( 0 ) ;
const BN _2 = BigInt ( 2 ) ;
const BN _27 = BigInt ( 27 ) ;
const BN _28 = BigInt ( 28 ) ;
const BN _35 = BigInt ( 35 ) ;
const BN _MAX _UINT = BigInt ( "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ) ;
function handleAddress ( value ) {
if ( value === "0x" ) {
return null ;
}
return ( 0 , index _js _1 . getAddress ) ( value ) ;
}
function handleAccessList ( value , param ) {
try {
return ( 0 , accesslist _js _1 . accessListify ) ( value ) ;
}
catch ( error ) {
2022-11-30 15:44:23 -05:00
( 0 , index _js _3 . assertArgument ) ( false , error . message , param , value ) ;
2022-09-05 16:57:11 -04:00
}
}
function handleNumber ( _value , param ) {
if ( _value === "0x" ) {
return 0 ;
}
2022-09-15 22:58:45 -04:00
return ( 0 , index _js _3 . getNumber ) ( _value , param ) ;
2022-09-05 16:57:11 -04:00
}
function handleUint ( _value , param ) {
if ( _value === "0x" ) {
return BN _0 ;
}
2022-09-15 22:58:45 -04:00
const value = ( 0 , index _js _3 . getBigInt ) ( _value , param ) ;
2022-11-09 02:57:02 -05:00
( 0 , index _js _3 . assertArgument ) ( value <= BN _MAX _UINT , "value exceeds uint size" , param , value ) ;
2022-09-05 16:57:11 -04:00
return value ;
}
function formatNumber ( _value , name ) {
2022-09-15 22:58:45 -04:00
const value = ( 0 , index _js _3 . getBigInt ) ( _value , "value" ) ;
2022-12-09 18:24:58 -05:00
const result = ( 0 , index _js _3 . toBeArray ) ( value ) ;
2022-11-09 02:57:02 -05:00
( 0 , index _js _3 . assertArgument ) ( result . length <= 32 , ` value too large ` , ` tx. ${ name } ` , value ) ;
2022-09-05 16:57:11 -04:00
return result ;
}
function formatAccessList ( value ) {
return ( 0 , accesslist _js _1 . accessListify ) ( value ) . map ( ( set ) => [ set . address , set . storageKeys ] ) ;
}
2024-02-02 03:25:03 -05:00
function formatHashes ( value , param ) {
( 0 , index _js _3 . assertArgument ) ( Array . isArray ( value ) , ` invalid ${ param } ` , "value" , value ) ;
for ( let i = 0 ; i < value . length ; i ++ ) {
( 0 , index _js _3 . assertArgument ) ( ( 0 , index _js _3 . isHexString ) ( value [ i ] , 32 ) , "invalid ${ param } hash" , ` value[ ${ i } ] ` , value [ i ] ) ;
}
return value ;
}
2022-09-05 16:57:11 -04:00
function _parseLegacy ( data ) {
const fields = ( 0 , index _js _3 . decodeRlp ) ( data ) ;
2022-11-09 02:57:02 -05:00
( 0 , index _js _3 . assertArgument ) ( Array . isArray ( fields ) && ( fields . length === 9 || fields . length === 6 ) , "invalid field count for legacy transaction" , "data" , data ) ;
2022-09-05 16:57:11 -04:00
const tx = {
type : 0 ,
nonce : handleNumber ( fields [ 0 ] , "nonce" ) ,
gasPrice : handleUint ( fields [ 1 ] , "gasPrice" ) ,
gasLimit : handleUint ( fields [ 2 ] , "gasLimit" ) ,
to : handleAddress ( fields [ 3 ] ) ,
value : handleUint ( fields [ 4 ] , "value" ) ,
2022-11-30 15:44:23 -05:00
data : ( 0 , index _js _3 . hexlify ) ( fields [ 5 ] ) ,
2022-09-05 16:57:11 -04:00
chainId : BN _0
} ;
// Legacy unsigned transaction
if ( fields . length === 6 ) {
return tx ;
}
const v = handleUint ( fields [ 6 ] , "v" ) ;
const r = handleUint ( fields [ 7 ] , "r" ) ;
const s = handleUint ( fields [ 8 ] , "s" ) ;
if ( r === BN _0 && s === BN _0 ) {
// EIP-155 unsigned transaction
tx . chainId = v ;
}
else {
// Compute the EIP-155 chain ID (or 0 for legacy)
let chainId = ( v - BN _35 ) / BN _2 ;
if ( chainId < BN _0 ) {
chainId = BN _0 ;
}
tx . chainId = chainId ;
// Signed Legacy Transaction
2022-11-09 02:57:02 -05:00
( 0 , index _js _3 . assertArgument ) ( chainId !== BN _0 || ( v === BN _27 || v === BN _28 ) , "non-canonical legacy v" , "v" , fields [ 6 ] ) ;
2022-09-05 16:57:11 -04:00
tx . signature = index _js _2 . Signature . from ( {
r : ( 0 , index _js _3 . zeroPadValue ) ( fields [ 7 ] , 32 ) ,
s : ( 0 , index _js _3 . zeroPadValue ) ( fields [ 8 ] , 32 ) ,
v
} ) ;
tx . hash = ( 0 , index _js _2 . keccak256 ) ( data ) ;
}
return tx ;
}
function _serializeLegacy ( tx , sig ) {
const fields = [
2024-02-02 03:25:03 -05:00
formatNumber ( tx . nonce , "nonce" ) ,
2024-02-08 20:27:03 -05:00
formatNumber ( tx . gasPrice || 0 , "gasPrice" ) ,
2024-02-02 03:25:03 -05:00
formatNumber ( tx . gasLimit , "gasLimit" ) ,
( tx . to || "0x" ) ,
formatNumber ( tx . value , "value" ) ,
tx . data ,
2022-09-05 16:57:11 -04:00
] ;
let chainId = BN _0 ;
2023-03-20 12:53:37 -04:00
if ( tx . chainId != BN _0 ) {
2022-09-05 16:57:11 -04:00
// A chainId was provided; if non-zero we'll use EIP-155
2022-09-15 22:58:45 -04:00
chainId = ( 0 , index _js _3 . getBigInt ) ( tx . chainId , "tx.chainId" ) ;
2022-09-05 16:57:11 -04:00
// We have a chainId in the tx and an EIP-155 v in the signature,
// make sure they agree with each other
2022-11-09 02:57:02 -05:00
( 0 , index _js _3 . assertArgument ) ( ! sig || sig . networkV == null || sig . legacyChainId === chainId , "tx.chainId/sig.v mismatch" , "sig" , sig ) ;
2022-09-05 16:57:11 -04:00
}
2023-03-20 12:53:37 -04:00
else if ( tx . signature ) {
// No explicit chainId, but EIP-155 have a derived implicit chainId
const legacy = tx . signature . legacyChainId ;
2022-09-05 16:57:11 -04:00
if ( legacy != null ) {
chainId = legacy ;
}
}
// Requesting an unsigned transaction
if ( ! sig ) {
// We have an EIP-155 transaction (chainId was specified and non-zero)
if ( chainId !== BN _0 ) {
2022-12-09 18:24:58 -05:00
fields . push ( ( 0 , index _js _3 . toBeArray ) ( chainId ) ) ;
2022-09-05 16:57:11 -04:00
fields . push ( "0x" ) ;
fields . push ( "0x" ) ;
}
return ( 0 , index _js _3 . encodeRlp ) ( fields ) ;
}
2023-03-20 12:53:37 -04:00
// @TODO: We should probably check that tx.signature, chainId, and sig
// match but that logic could break existing code, so schedule
// this for the next major bump.
// Compute the EIP-155 v
2022-09-05 16:57:11 -04:00
let v = BigInt ( 27 + sig . yParity ) ;
if ( chainId !== BN _0 ) {
v = index _js _2 . Signature . getChainIdV ( chainId , sig . v ) ;
}
else if ( BigInt ( sig . v ) !== v ) {
2022-11-09 02:57:02 -05:00
( 0 , index _js _3 . assertArgument ) ( false , "tx.chainId/sig.v mismatch" , "sig" , sig ) ;
2022-09-05 16:57:11 -04:00
}
2023-03-20 12:53:37 -04:00
// Add the signature
2022-12-09 18:24:58 -05:00
fields . push ( ( 0 , index _js _3 . toBeArray ) ( v ) ) ;
fields . push ( ( 0 , index _js _3 . toBeArray ) ( sig . r ) ) ;
fields . push ( ( 0 , index _js _3 . toBeArray ) ( sig . s ) ) ;
2022-09-05 16:57:11 -04:00
return ( 0 , index _js _3 . encodeRlp ) ( fields ) ;
}
2023-04-25 20:04:48 +09:00
function _parseEipSignature ( tx , fields ) {
2022-09-05 16:57:11 -04:00
let yParity ;
try {
yParity = handleNumber ( fields [ 0 ] , "yParity" ) ;
if ( yParity !== 0 && yParity !== 1 ) {
throw new Error ( "bad yParity" ) ;
}
}
catch ( error ) {
2022-11-09 02:57:02 -05:00
( 0 , index _js _3 . assertArgument ) ( false , "invalid yParity" , "yParity" , fields [ 0 ] ) ;
2022-09-05 16:57:11 -04:00
}
const r = ( 0 , index _js _3 . zeroPadValue ) ( fields [ 1 ] , 32 ) ;
const s = ( 0 , index _js _3 . zeroPadValue ) ( fields [ 2 ] , 32 ) ;
const signature = index _js _2 . Signature . from ( { r , s , yParity } ) ;
tx . signature = signature ;
}
function _parseEip1559 ( data ) {
2022-09-15 22:58:45 -04:00
const fields = ( 0 , index _js _3 . decodeRlp ) ( ( 0 , index _js _3 . getBytes ) ( data ) . slice ( 1 ) ) ;
2022-11-09 02:57:02 -05:00
( 0 , index _js _3 . assertArgument ) ( Array . isArray ( fields ) && ( fields . length === 9 || fields . length === 12 ) , "invalid field count for transaction type: 2" , "data" , ( 0 , index _js _3 . hexlify ) ( data ) ) ;
2022-09-05 16:57:11 -04:00
const tx = {
type : 2 ,
chainId : handleUint ( fields [ 0 ] , "chainId" ) ,
nonce : handleNumber ( fields [ 1 ] , "nonce" ) ,
2024-02-02 03:25:03 -05:00
maxPriorityFeePerGas : handleUint ( fields [ 2 ] , "maxPriorityFeePerGas" ) ,
maxFeePerGas : handleUint ( fields [ 3 ] , "maxFeePerGas" ) ,
2022-09-05 16:57:11 -04:00
gasPrice : null ,
gasLimit : handleUint ( fields [ 4 ] , "gasLimit" ) ,
to : handleAddress ( fields [ 5 ] ) ,
value : handleUint ( fields [ 6 ] , "value" ) ,
2022-11-30 15:44:23 -05:00
data : ( 0 , index _js _3 . hexlify ) ( fields [ 7 ] ) ,
2022-09-05 16:57:11 -04:00
accessList : handleAccessList ( fields [ 8 ] , "accessList" ) ,
} ;
// Unsigned EIP-1559 Transaction
if ( fields . length === 9 ) {
return tx ;
}
tx . hash = ( 0 , index _js _2 . keccak256 ) ( data ) ;
2023-04-25 20:04:48 +09:00
_parseEipSignature ( tx , fields . slice ( 9 ) ) ;
2022-09-05 16:57:11 -04:00
return tx ;
}
function _serializeEip1559 ( tx , sig ) {
const fields = [
2024-02-02 03:25:03 -05:00
formatNumber ( tx . chainId , "chainId" ) ,
formatNumber ( tx . nonce , "nonce" ) ,
2024-02-08 20:27:03 -05:00
formatNumber ( tx . maxPriorityFeePerGas || 0 , "maxPriorityFeePerGas" ) ,
formatNumber ( tx . maxFeePerGas || 0 , "maxFeePerGas" ) ,
2024-02-02 03:25:03 -05:00
formatNumber ( tx . gasLimit , "gasLimit" ) ,
( tx . to || "0x" ) ,
formatNumber ( tx . value , "value" ) ,
tx . data ,
2024-02-08 20:27:03 -05:00
formatAccessList ( tx . accessList || [ ] )
2022-09-05 16:57:11 -04:00
] ;
if ( sig ) {
fields . push ( formatNumber ( sig . yParity , "yParity" ) ) ;
2022-12-09 18:24:58 -05:00
fields . push ( ( 0 , index _js _3 . toBeArray ) ( sig . r ) ) ;
fields . push ( ( 0 , index _js _3 . toBeArray ) ( sig . s ) ) ;
2022-09-05 16:57:11 -04:00
}
return ( 0 , index _js _3 . concat ) ( [ "0x02" , ( 0 , index _js _3 . encodeRlp ) ( fields ) ] ) ;
}
function _parseEip2930 ( data ) {
2022-09-15 22:58:45 -04:00
const fields = ( 0 , index _js _3 . decodeRlp ) ( ( 0 , index _js _3 . getBytes ) ( data ) . slice ( 1 ) ) ;
2022-11-09 02:57:02 -05:00
( 0 , index _js _3 . assertArgument ) ( Array . isArray ( fields ) && ( fields . length === 8 || fields . length === 11 ) , "invalid field count for transaction type: 1" , "data" , ( 0 , index _js _3 . hexlify ) ( data ) ) ;
2022-09-05 16:57:11 -04:00
const tx = {
type : 1 ,
chainId : handleUint ( fields [ 0 ] , "chainId" ) ,
nonce : handleNumber ( fields [ 1 ] , "nonce" ) ,
gasPrice : handleUint ( fields [ 2 ] , "gasPrice" ) ,
gasLimit : handleUint ( fields [ 3 ] , "gasLimit" ) ,
to : handleAddress ( fields [ 4 ] ) ,
value : handleUint ( fields [ 5 ] , "value" ) ,
2022-11-30 15:44:23 -05:00
data : ( 0 , index _js _3 . hexlify ) ( fields [ 6 ] ) ,
2022-09-05 16:57:11 -04:00
accessList : handleAccessList ( fields [ 7 ] , "accessList" )
} ;
// Unsigned EIP-2930 Transaction
if ( fields . length === 8 ) {
return tx ;
}
tx . hash = ( 0 , index _js _2 . keccak256 ) ( data ) ;
2023-04-25 20:04:48 +09:00
_parseEipSignature ( tx , fields . slice ( 8 ) ) ;
2022-09-05 16:57:11 -04:00
return tx ;
}
function _serializeEip2930 ( tx , sig ) {
const fields = [
2024-02-02 03:25:03 -05:00
formatNumber ( tx . chainId , "chainId" ) ,
formatNumber ( tx . nonce , "nonce" ) ,
2024-02-08 20:27:03 -05:00
formatNumber ( tx . gasPrice || 0 , "gasPrice" ) ,
2024-02-02 03:25:03 -05:00
formatNumber ( tx . gasLimit , "gasLimit" ) ,
( tx . to || "0x" ) ,
formatNumber ( tx . value , "value" ) ,
tx . data ,
2024-02-08 20:27:03 -05:00
formatAccessList ( tx . accessList || [ ] )
2022-09-05 16:57:11 -04:00
] ;
if ( sig ) {
fields . push ( formatNumber ( sig . yParity , "recoveryParam" ) ) ;
2022-12-09 18:24:58 -05:00
fields . push ( ( 0 , index _js _3 . toBeArray ) ( sig . r ) ) ;
fields . push ( ( 0 , index _js _3 . toBeArray ) ( sig . s ) ) ;
2022-09-05 16:57:11 -04:00
}
return ( 0 , index _js _3 . concat ) ( [ "0x01" , ( 0 , index _js _3 . encodeRlp ) ( fields ) ] ) ;
}
2024-02-02 03:25:03 -05:00
function _parseEip4844 ( data ) {
const fields = ( 0 , index _js _3 . decodeRlp ) ( ( 0 , index _js _3 . getBytes ) ( data ) . slice ( 1 ) ) ;
( 0 , index _js _3 . assertArgument ) ( Array . isArray ( fields ) && ( fields . length === 11 || fields . length === 14 ) , "invalid field count for transaction type: 3" , "data" , ( 0 , index _js _3 . hexlify ) ( data ) ) ;
const tx = {
type : 3 ,
chainId : handleUint ( fields [ 0 ] , "chainId" ) ,
nonce : handleNumber ( fields [ 1 ] , "nonce" ) ,
maxPriorityFeePerGas : handleUint ( fields [ 2 ] , "maxPriorityFeePerGas" ) ,
maxFeePerGas : handleUint ( fields [ 3 ] , "maxFeePerGas" ) ,
gasPrice : null ,
gasLimit : handleUint ( fields [ 4 ] , "gasLimit" ) ,
to : handleAddress ( fields [ 5 ] ) ,
value : handleUint ( fields [ 6 ] , "value" ) ,
data : ( 0 , index _js _3 . hexlify ) ( fields [ 7 ] ) ,
accessList : handleAccessList ( fields [ 8 ] , "accessList" ) ,
maxFeePerBlobGas : handleUint ( fields [ 9 ] , "maxFeePerBlobGas" ) ,
blobVersionedHashes : fields [ 10 ]
} ;
( 0 , index _js _3 . assertArgument ) ( tx . to != null , "invalid address for transaction type: 3" , "data" , data ) ;
( 0 , index _js _3 . assertArgument ) ( Array . isArray ( tx . blobVersionedHashes ) , "invalid blobVersionedHashes: must be an array" , "data" , data ) ;
for ( let i = 0 ; i < tx . blobVersionedHashes . length ; i ++ ) {
( 0 , index _js _3 . assertArgument ) ( ( 0 , index _js _3 . isHexString ) ( tx . blobVersionedHashes [ i ] , 32 ) , ` invalid blobVersionedHash at index ${ i } : must be length 32 ` , "data" , data ) ;
}
// Unsigned EIP-4844 Transaction
if ( fields . length === 11 ) {
return tx ;
}
tx . hash = ( 0 , index _js _2 . keccak256 ) ( data ) ;
_parseEipSignature ( tx , fields . slice ( 11 ) ) ;
return tx ;
}
function _serializeEip4844 ( tx , sig ) {
const fields = [
formatNumber ( tx . chainId , "chainId" ) ,
formatNumber ( tx . nonce , "nonce" ) ,
2024-02-08 20:27:03 -05:00
formatNumber ( tx . maxPriorityFeePerGas || 0 , "maxPriorityFeePerGas" ) ,
formatNumber ( tx . maxFeePerGas || 0 , "maxFeePerGas" ) ,
2024-02-02 03:25:03 -05:00
formatNumber ( tx . gasLimit , "gasLimit" ) ,
2024-02-08 20:27:03 -05:00
( tx . to || addresses _js _1 . ZeroAddress ) ,
2024-02-02 03:25:03 -05:00
formatNumber ( tx . value , "value" ) ,
tx . data ,
2024-02-08 20:27:03 -05:00
formatAccessList ( tx . accessList || [ ] ) ,
formatNumber ( tx . maxFeePerBlobGas || 0 , "maxFeePerBlobGas" ) ,
formatHashes ( tx . blobVersionedHashes || [ ] , "blobVersionedHashes" )
2024-02-02 03:25:03 -05:00
] ;
if ( sig ) {
fields . push ( formatNumber ( sig . yParity , "yParity" ) ) ;
fields . push ( ( 0 , index _js _3 . toBeArray ) ( sig . r ) ) ;
fields . push ( ( 0 , index _js _3 . toBeArray ) ( sig . s ) ) ;
}
return ( 0 , index _js _3 . concat ) ( [ "0x03" , ( 0 , index _js _3 . encodeRlp ) ( fields ) ] ) ;
}
2022-12-02 21:27:06 -05:00
/ * *
* A * * Transaction * * describes an operation to be executed on
* Ethereum by an Externally Owned Account ( EOA ) . It includes
* who ( the [ [ to ] ] address ) , what ( the [ [ data ] ] ) and how much ( the
* [ [ value ] ] in ether ) the operation should entail .
2022-12-09 18:24:58 -05:00
*
* @ example :
* tx = new Transaction ( )
* //_result:
*
* tx . data = "0x1234" ;
* //_result:
2022-12-02 21:27:06 -05:00
* /
2022-09-05 16:57:11 -04:00
class Transaction {
2022-11-30 15:44:23 -05:00
# type ;
# to ;
# data ;
# nonce ;
# gasLimit ;
# gasPrice ;
# maxPriorityFeePerGas ;
# maxFeePerGas ;
# value ;
# chainId ;
# sig ;
# accessList ;
2024-02-02 03:25:03 -05:00
# maxFeePerBlobGas ;
# blobVersionedHashes ;
2022-12-02 21:27:06 -05:00
/ * *
* The transaction type .
*
* If null , the type will be automatically inferred based on
* explicit properties .
* /
2022-11-30 15:44:23 -05:00
get type ( ) { return this . # type ; }
2022-09-05 16:57:11 -04:00
set type ( value ) {
switch ( value ) {
case null :
2022-11-30 15:44:23 -05:00
this . # type = null ;
2022-09-05 16:57:11 -04:00
break ;
case 0 :
case "legacy" :
2022-11-30 15:44:23 -05:00
this . # type = 0 ;
2022-09-05 16:57:11 -04:00
break ;
case 1 :
case "berlin" :
case "eip-2930" :
2022-11-30 15:44:23 -05:00
this . # type = 1 ;
2022-09-05 16:57:11 -04:00
break ;
case 2 :
case "london" :
case "eip-1559" :
2022-11-30 15:44:23 -05:00
this . # type = 2 ;
2022-09-05 16:57:11 -04:00
break ;
2024-02-02 03:25:03 -05:00
case 3 :
case "cancun" :
case "eip-4844" :
this . # type = 3 ;
break ;
2022-09-05 16:57:11 -04:00
default :
2022-11-30 15:44:23 -05:00
( 0 , index _js _3 . assertArgument ) ( false , "unsupported transaction type" , "type" , value ) ;
2022-09-05 16:57:11 -04:00
}
}
2022-12-02 21:27:06 -05:00
/ * *
* The name of the transaction type .
* /
get typeName ( ) {
switch ( this . type ) {
case 0 : return "legacy" ;
case 1 : return "eip-2930" ;
case 2 : return "eip-1559" ;
2024-02-02 03:25:03 -05:00
case 3 : return "eip-4844" ;
2022-12-02 21:27:06 -05:00
}
return null ;
}
/ * *
* The ` ` to ` ` address for the transaction or ` ` null ` ` if the
* transaction is an ` ` init ` ` transaction .
* /
2024-02-02 03:25:03 -05:00
get to ( ) {
const value = this . # to ;
if ( value == null && this . type === 3 ) {
return addresses _js _1 . ZeroAddress ;
}
return value ;
}
2022-09-05 16:57:11 -04:00
set to ( value ) {
2022-11-30 15:44:23 -05:00
this . # to = ( value == null ) ? null : ( 0 , index _js _1 . getAddress ) ( value ) ;
2022-09-05 16:57:11 -04:00
}
2022-12-02 21:27:06 -05:00
/ * *
* The transaction nonce .
* /
2022-11-30 15:44:23 -05:00
get nonce ( ) { return this . # nonce ; }
set nonce ( value ) { this . # nonce = ( 0 , index _js _3 . getNumber ) ( value , "value" ) ; }
2022-12-02 21:27:06 -05:00
/ * *
* The gas limit .
* /
2022-11-30 15:44:23 -05:00
get gasLimit ( ) { return this . # gasLimit ; }
set gasLimit ( value ) { this . # gasLimit = ( 0 , index _js _3 . getBigInt ) ( value ) ; }
2022-12-02 21:27:06 -05:00
/ * *
* The gas price .
*
* On legacy networks this defines the fee that will be paid . On
* EIP - 1559 networks , this should be ` ` null ` ` .
* /
2022-09-05 16:57:11 -04:00
get gasPrice ( ) {
2022-11-30 15:44:23 -05:00
const value = this . # gasPrice ;
2022-09-05 16:57:11 -04:00
if ( value == null && ( this . type === 0 || this . type === 1 ) ) {
return BN _0 ;
}
return value ;
}
set gasPrice ( value ) {
2022-11-30 15:44:23 -05:00
this . # gasPrice = ( value == null ) ? null : ( 0 , index _js _3 . getBigInt ) ( value , "gasPrice" ) ;
2022-09-05 16:57:11 -04:00
}
2022-12-02 21:27:06 -05:00
/ * *
* The maximum priority fee per unit of gas to pay . On legacy
* networks this should be ` ` null ` ` .
* /
2022-09-05 16:57:11 -04:00
get maxPriorityFeePerGas ( ) {
2022-11-30 15:44:23 -05:00
const value = this . # maxPriorityFeePerGas ;
if ( value == null ) {
2024-02-02 03:25:03 -05:00
if ( this . type === 2 || this . type === 3 ) {
2022-11-30 15:44:23 -05:00
return BN _0 ;
}
return null ;
2022-09-05 16:57:11 -04:00
}
return value ;
}
set maxPriorityFeePerGas ( value ) {
2022-11-30 15:44:23 -05:00
this . # maxPriorityFeePerGas = ( value == null ) ? null : ( 0 , index _js _3 . getBigInt ) ( value , "maxPriorityFeePerGas" ) ;
2022-09-05 16:57:11 -04:00
}
2022-12-02 21:27:06 -05:00
/ * *
* The maximum total fee per unit of gas to pay . On legacy
* networks this should be ` ` null ` ` .
* /
2022-09-05 16:57:11 -04:00
get maxFeePerGas ( ) {
2022-11-30 15:44:23 -05:00
const value = this . # maxFeePerGas ;
if ( value == null ) {
2024-02-02 03:25:03 -05:00
if ( this . type === 2 || this . type === 3 ) {
2022-11-30 15:44:23 -05:00
return BN _0 ;
}
return null ;
2022-09-05 16:57:11 -04:00
}
return value ;
}
set maxFeePerGas ( value ) {
2022-11-30 15:44:23 -05:00
this . # maxFeePerGas = ( value == null ) ? null : ( 0 , index _js _3 . getBigInt ) ( value , "maxFeePerGas" ) ;
2022-09-05 16:57:11 -04:00
}
2022-12-02 21:27:06 -05:00
/ * *
* The transaction data . For ` ` init ` ` transactions this is the
* deployment code .
* /
2022-11-30 15:44:23 -05:00
get data ( ) { return this . # data ; }
set data ( value ) { this . # data = ( 0 , index _js _3 . hexlify ) ( value ) ; }
2022-12-02 21:27:06 -05:00
/ * *
2023-04-25 20:04:48 +09:00
* The amount of ether ( in wei ) to send in this transactions .
2022-12-02 21:27:06 -05:00
* /
2022-11-30 15:44:23 -05:00
get value ( ) { return this . # value ; }
2022-09-05 16:57:11 -04:00
set value ( value ) {
2022-11-30 15:44:23 -05:00
this . # value = ( 0 , index _js _3 . getBigInt ) ( value , "value" ) ;
2022-09-05 16:57:11 -04:00
}
2022-12-02 21:27:06 -05:00
/ * *
* The chain ID this transaction is valid on .
* /
2022-11-30 15:44:23 -05:00
get chainId ( ) { return this . # chainId ; }
set chainId ( value ) { this . # chainId = ( 0 , index _js _3 . getBigInt ) ( value ) ; }
2022-12-02 21:27:06 -05:00
/ * *
* If signed , the signature for this transaction .
* /
2022-11-30 15:44:23 -05:00
get signature ( ) { return this . # sig || null ; }
2022-09-05 16:57:11 -04:00
set signature ( value ) {
2022-11-30 15:44:23 -05:00
this . # sig = ( value == null ) ? null : index _js _2 . Signature . from ( value ) ;
2022-09-05 16:57:11 -04:00
}
2022-12-02 21:27:06 -05:00
/ * *
* The access list .
*
* An access list permits discounted ( but pre - paid ) access to
* bytecode and state variable access within contract execution .
* /
2022-09-05 16:57:11 -04:00
get accessList ( ) {
2022-11-30 15:44:23 -05:00
const value = this . # accessList || null ;
if ( value == null ) {
2024-02-02 03:25:03 -05:00
if ( this . type === 1 || this . type === 2 || this . type === 3 ) {
// @TODO: in v7, this should assign the value or become
// a live object itself, otherwise mutation is inconsistent
2022-11-30 15:44:23 -05:00
return [ ] ;
}
return null ;
2022-09-05 16:57:11 -04:00
}
return value ;
}
set accessList ( value ) {
2022-11-30 15:44:23 -05:00
this . # accessList = ( value == null ) ? null : ( 0 , accesslist _js _1 . accessListify ) ( value ) ;
2022-09-05 16:57:11 -04:00
}
2024-02-02 03:25:03 -05:00
/ * *
* The max fee per blob gas for Cancun transactions .
* /
get maxFeePerBlobGas ( ) {
const value = this . # maxFeePerBlobGas ;
if ( value == null && this . type === 3 ) {
return BN _0 ;
}
return value ;
}
set maxFeePerBlobGas ( value ) {
this . # maxFeePerBlobGas = ( value == null ) ? null : ( 0 , index _js _3 . getBigInt ) ( value , "maxFeePerBlobGas" ) ;
}
/ * *
* The BLOB versioned hashes for Cancun transactions .
* /
get blobVersionedHashes ( ) {
// @TODO: Mutation is inconsistent; if unset, the returned value
// cannot mutate the object, if set it can
let value = this . # blobVersionedHashes ;
if ( value == null && this . type === 3 ) {
return [ ] ;
}
return value ;
}
set blobVersionedHashes ( value ) {
if ( value != null ) {
( 0 , index _js _3 . assertArgument ) ( Array . isArray ( value ) , "blobVersionedHashes must be an Array" , "value" , value ) ;
value = value . slice ( ) ;
for ( let i = 0 ; i < value . length ; i ++ ) {
( 0 , index _js _3 . assertArgument ) ( ( 0 , index _js _3 . isHexString ) ( value [ i ] , 32 ) , "invalid blobVersionedHash" , ` value[ ${ i } ] ` , value [ i ] ) ;
}
}
this . # blobVersionedHashes = value ;
}
2022-12-02 21:27:06 -05:00
/ * *
* Creates a new Transaction with default values .
* /
2022-09-05 16:57:11 -04:00
constructor ( ) {
2022-11-30 15:44:23 -05:00
this . # type = null ;
this . # to = null ;
this . # nonce = 0 ;
2024-02-02 03:25:03 -05:00
this . # gasLimit = BN _0 ;
2022-11-30 15:44:23 -05:00
this . # gasPrice = null ;
this . # maxPriorityFeePerGas = null ;
this . # maxFeePerGas = null ;
this . # data = "0x" ;
2024-02-02 03:25:03 -05:00
this . # value = BN _0 ;
this . # chainId = BN _0 ;
2022-11-30 15:44:23 -05:00
this . # sig = null ;
this . # accessList = null ;
2024-02-02 03:25:03 -05:00
this . # maxFeePerBlobGas = null ;
this . # blobVersionedHashes = null ;
2022-09-05 16:57:11 -04:00
}
2022-12-02 21:27:06 -05:00
/ * *
* The transaction hash , if signed . Otherwise , ` ` null ` ` .
* /
2022-09-05 16:57:11 -04:00
get hash ( ) {
if ( this . signature == null ) {
2022-10-20 05:03:32 -04:00
return null ;
2022-09-05 16:57:11 -04:00
}
return ( 0 , index _js _2 . keccak256 ) ( this . serialized ) ;
}
2022-12-02 21:27:06 -05:00
/ * *
* The pre - image hash of this transaction .
*
* This is the digest that a [ [ Signer ] ] must sign to authorize
* this transaction .
* /
2022-09-05 16:57:11 -04:00
get unsignedHash ( ) {
return ( 0 , index _js _2 . keccak256 ) ( this . unsignedSerialized ) ;
}
2022-12-02 21:27:06 -05:00
/ * *
* The sending address , if signed . Otherwise , ` ` null ` ` .
* /
2022-09-05 16:57:11 -04:00
get from ( ) {
if ( this . signature == null ) {
return null ;
}
2022-10-20 05:03:32 -04:00
return ( 0 , address _js _1 . recoverAddress ) ( this . unsignedHash , this . signature ) ;
2022-09-05 16:57:11 -04:00
}
2022-12-02 21:27:06 -05:00
/ * *
* The public key of the sender , if signed . Otherwise , ` ` null ` ` .
* /
2022-09-05 16:57:11 -04:00
get fromPublicKey ( ) {
if ( this . signature == null ) {
return null ;
}
2022-11-30 15:44:23 -05:00
return index _js _2 . SigningKey . recoverPublicKey ( this . unsignedHash , this . signature ) ;
2022-09-05 16:57:11 -04:00
}
2022-12-02 21:27:06 -05:00
/ * *
* Returns true if signed .
*
* This provides a Type Guard that properties requiring a signed
* transaction are non - null .
* /
2022-09-05 16:57:11 -04:00
isSigned ( ) {
return this . signature != null ;
}
2022-12-02 21:27:06 -05:00
/ * *
* The serialized transaction .
*
* This throws if the transaction is unsigned . For the pre - image ,
* use [ [ unsignedSerialized ] ] .
* /
2022-09-05 16:57:11 -04:00
get serialized ( ) {
2022-11-30 15:44:23 -05:00
( 0 , index _js _3 . assert ) ( this . signature != null , "cannot serialize unsigned transaction; maybe you meant .unsignedSerialized" , "UNSUPPORTED_OPERATION" , { operation : ".serialized" } ) ;
switch ( this . inferType ( ) ) {
2022-09-05 16:57:11 -04:00
case 0 :
return _serializeLegacy ( this , this . signature ) ;
case 1 :
return _serializeEip2930 ( this , this . signature ) ;
case 2 :
return _serializeEip1559 ( this , this . signature ) ;
2024-02-02 03:25:03 -05:00
case 3 :
return _serializeEip4844 ( this , this . signature ) ;
2022-09-05 16:57:11 -04:00
}
2022-11-30 15:44:23 -05:00
( 0 , index _js _3 . assert ) ( false , "unsupported transaction type" , "UNSUPPORTED_OPERATION" , { operation : ".serialized" } ) ;
2022-09-05 16:57:11 -04:00
}
2022-12-02 21:27:06 -05:00
/ * *
* The transaction pre - image .
*
* The hash of this is the digest which needs to be signed to
* authorize this transaction .
* /
2022-09-05 16:57:11 -04:00
get unsignedSerialized ( ) {
2022-11-30 15:44:23 -05:00
switch ( this . inferType ( ) ) {
2022-09-05 16:57:11 -04:00
case 0 :
return _serializeLegacy ( this ) ;
case 1 :
return _serializeEip2930 ( this ) ;
case 2 :
return _serializeEip1559 ( this ) ;
2024-02-02 03:25:03 -05:00
case 3 :
return _serializeEip4844 ( this ) ;
2022-09-05 16:57:11 -04:00
}
2022-11-30 15:44:23 -05:00
( 0 , index _js _3 . assert ) ( false , "unsupported transaction type" , "UNSUPPORTED_OPERATION" , { operation : ".unsignedSerialized" } ) ;
}
/ * *
* Return the most "likely" type ; currently the highest
2022-12-02 21:27:06 -05:00
* supported transaction type .
2022-11-30 15:44:23 -05:00
* /
inferType ( ) {
2024-02-02 03:25:03 -05:00
const types = this . inferTypes ( ) ;
// Prefer London (EIP-1559) over Cancun (BLOb)
if ( types . indexOf ( 2 ) >= 0 ) {
return 2 ;
}
// Return the highest inferred type
return ( types . pop ( ) ) ;
2022-09-05 16:57:11 -04:00
}
2022-12-02 21:27:06 -05:00
/ * *
* Validates the explicit properties and returns a list of compatible
* transaction types .
* /
2022-09-05 16:57:11 -04:00
inferTypes ( ) {
// Checks that there are no conflicting properties set
const hasGasPrice = this . gasPrice != null ;
const hasFee = ( this . maxFeePerGas != null || this . maxPriorityFeePerGas != null ) ;
const hasAccessList = ( this . accessList != null ) ;
2024-02-02 03:25:03 -05:00
const hasBlob = ( this . # maxFeePerBlobGas != null || this . # blobVersionedHashes ) ;
2022-09-05 16:57:11 -04:00
//if (hasGasPrice && hasFee) {
// throw new Error("transaction cannot have gasPrice and maxFeePerGas");
//}
if ( this . maxFeePerGas != null && this . maxPriorityFeePerGas != null ) {
2022-11-30 15:44:23 -05:00
( 0 , index _js _3 . assert ) ( this . maxFeePerGas >= this . maxPriorityFeePerGas , "priorityFee cannot be more than maxFee" , "BAD_DATA" , { value : this } ) ;
2022-09-05 16:57:11 -04:00
}
//if (this.type === 2 && hasGasPrice) {
// throw new Error("eip-1559 transaction cannot have gasPrice");
//}
2022-11-30 15:44:23 -05:00
( 0 , index _js _3 . assert ) ( ! hasFee || ( this . type !== 0 && this . type !== 1 ) , "transaction type cannot have maxFeePerGas or maxPriorityFeePerGas" , "BAD_DATA" , { value : this } ) ;
( 0 , index _js _3 . assert ) ( this . type !== 0 || ! hasAccessList , "legacy transaction cannot have accessList" , "BAD_DATA" , { value : this } ) ;
2022-09-05 16:57:11 -04:00
const types = [ ] ;
// Explicit type
if ( this . type != null ) {
types . push ( this . type ) ;
}
else {
if ( hasFee ) {
types . push ( 2 ) ;
}
else if ( hasGasPrice ) {
types . push ( 1 ) ;
if ( ! hasAccessList ) {
types . push ( 0 ) ;
}
}
else if ( hasAccessList ) {
types . push ( 1 ) ;
types . push ( 2 ) ;
}
2024-02-02 03:25:03 -05:00
else if ( hasBlob && this . to ) {
types . push ( 3 ) ;
}
2022-09-05 16:57:11 -04:00
else {
types . push ( 0 ) ;
types . push ( 1 ) ;
types . push ( 2 ) ;
2024-02-02 03:25:03 -05:00
types . push ( 3 ) ;
2022-09-05 16:57:11 -04:00
}
}
types . sort ( ) ;
return types ;
}
2022-12-02 21:27:06 -05:00
/ * *
* Returns true if this transaction is a legacy transaction ( i . e .
* ` ` type === 0 ` ` ) .
*
* This provides a Type Guard that the related properties are
* non - null .
* /
2022-09-15 22:58:45 -04:00
isLegacy ( ) {
return ( this . type === 0 ) ;
}
2022-12-02 21:27:06 -05:00
/ * *
* Returns true if this transaction is berlin hardform transaction ( i . e .
* ` ` type === 1 ` ` ) .
*
* This provides a Type Guard that the related properties are
* non - null .
* /
2022-09-15 22:58:45 -04:00
isBerlin ( ) {
return ( this . type === 1 ) ;
}
2022-12-02 21:27:06 -05:00
/ * *
* Returns true if this transaction is london hardform transaction ( i . e .
* ` ` type === 2 ` ` ) .
*
* This provides a Type Guard that the related properties are
* non - null .
* /
2022-09-15 22:58:45 -04:00
isLondon ( ) {
return ( this . type === 2 ) ;
}
2024-02-02 03:25:03 -05:00
/ * *
* Returns true if this transaction is an [ [ link - eip - 4844 ] ] BLOB
* transaction .
*
* This provides a Type Guard that the related properties are
* non - null .
* /
isCancun ( ) {
return ( this . type === 3 ) ;
}
2022-12-02 21:27:06 -05:00
/ * *
* Create a copy of this transaciton .
* /
2022-09-05 16:57:11 -04:00
clone ( ) {
return Transaction . from ( this ) ;
}
2022-12-02 21:27:06 -05:00
/ * *
* Return a JSON - friendly object .
* /
2022-10-20 05:03:32 -04:00
toJSON ( ) {
const s = ( v ) => {
if ( v == null ) {
return null ;
}
return v . toString ( ) ;
} ;
return {
type : this . type ,
to : this . to ,
2022-11-30 15:44:23 -05:00
// from: this.from,
2022-10-20 05:03:32 -04:00
data : this . data ,
nonce : this . nonce ,
gasLimit : s ( this . gasLimit ) ,
gasPrice : s ( this . gasPrice ) ,
maxPriorityFeePerGas : s ( this . maxPriorityFeePerGas ) ,
maxFeePerGas : s ( this . maxFeePerGas ) ,
value : s ( this . value ) ,
chainId : s ( this . chainId ) ,
sig : this . signature ? this . signature . toJSON ( ) : null ,
accessList : this . accessList
} ;
}
2022-12-02 21:27:06 -05:00
/ * *
* Create a * * Transaction * * from a serialized transaction or a
* Transaction - like object .
* /
2022-09-05 16:57:11 -04:00
static from ( tx ) {
2022-12-02 21:27:06 -05:00
if ( tx == null ) {
return new Transaction ( ) ;
}
2022-09-05 16:57:11 -04:00
if ( typeof ( tx ) === "string" ) {
2022-09-15 22:58:45 -04:00
const payload = ( 0 , index _js _3 . getBytes ) ( tx ) ;
2022-09-05 16:57:11 -04:00
if ( payload [ 0 ] >= 0x7f ) { // @TODO: > vs >= ??
return Transaction . from ( _parseLegacy ( payload ) ) ;
}
switch ( payload [ 0 ] ) {
case 1 : return Transaction . from ( _parseEip2930 ( payload ) ) ;
case 2 : return Transaction . from ( _parseEip1559 ( payload ) ) ;
2024-02-02 03:25:03 -05:00
case 3 : return Transaction . from ( _parseEip4844 ( payload ) ) ;
2022-09-05 16:57:11 -04:00
}
2022-11-30 15:44:23 -05:00
( 0 , index _js _3 . assert ) ( false , "unsupported transaction type" , "UNSUPPORTED_OPERATION" , { operation : "from" } ) ;
2022-09-05 16:57:11 -04:00
}
const result = new Transaction ( ) ;
if ( tx . type != null ) {
result . type = tx . type ;
}
if ( tx . to != null ) {
result . to = tx . to ;
}
if ( tx . nonce != null ) {
result . nonce = tx . nonce ;
}
if ( tx . gasLimit != null ) {
result . gasLimit = tx . gasLimit ;
}
if ( tx . gasPrice != null ) {
result . gasPrice = tx . gasPrice ;
}
if ( tx . maxPriorityFeePerGas != null ) {
result . maxPriorityFeePerGas = tx . maxPriorityFeePerGas ;
}
if ( tx . maxFeePerGas != null ) {
result . maxFeePerGas = tx . maxFeePerGas ;
}
2024-02-02 03:25:03 -05:00
if ( tx . maxFeePerBlobGas != null ) {
result . maxFeePerBlobGas = tx . maxFeePerBlobGas ;
}
2022-09-05 16:57:11 -04:00
if ( tx . data != null ) {
result . data = tx . data ;
}
if ( tx . value != null ) {
result . value = tx . value ;
}
if ( tx . chainId != null ) {
result . chainId = tx . chainId ;
}
if ( tx . signature != null ) {
result . signature = index _js _2 . Signature . from ( tx . signature ) ;
}
if ( tx . accessList != null ) {
result . accessList = tx . accessList ;
}
2024-02-02 03:25:03 -05:00
if ( tx . blobVersionedHashes != null ) {
result . blobVersionedHashes = tx . blobVersionedHashes ;
}
2022-09-05 16:57:11 -04:00
if ( tx . hash != null ) {
2023-01-17 13:53:49 -05:00
( 0 , index _js _3 . assertArgument ) ( result . isSigned ( ) , "unsigned transaction cannot define hash" , "tx" , tx ) ;
2022-11-30 15:44:23 -05:00
( 0 , index _js _3 . assertArgument ) ( result . hash === tx . hash , "hash mismatch" , "tx" , tx ) ;
2022-09-05 16:57:11 -04:00
}
if ( tx . from != null ) {
2023-01-17 13:53:49 -05:00
( 0 , index _js _3 . assertArgument ) ( result . isSigned ( ) , "unsigned transaction cannot define from" , "tx" , tx ) ;
2022-11-30 15:44:23 -05:00
( 0 , index _js _3 . assertArgument ) ( result . from . toLowerCase ( ) === ( tx . from || "" ) . toLowerCase ( ) , "from mismatch" , "tx" , tx ) ;
2022-09-05 16:57:11 -04:00
}
return result ;
}
}
exports . Transaction = Transaction ;
//# sourceMappingURL=transaction.js.map