-
Notifications
You must be signed in to change notification settings - Fork 791
/
Copy pathtransactionFactory.ts
141 lines (135 loc) · 4.95 KB
/
transactionFactory.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import { fetchFromProvider, getProvider } from '@ethereumjs/util'
import { createFeeMarket1559Tx, createFeeMarket1559TxFromRLP } from './1559/constructors.js'
import { createAccessList2930Tx, createAccessList2930TxFromRLP } from './2930/constructors.js'
import { createBlob4844Tx, createBlob4844TxFromRLP } from './4844/constructors.js'
import { createEOACode7702Tx, createEOACode7702TxFromRLP } from './7702/constructors.js'
import {
createLegacyTx,
createLegacyTxFromBytesArray,
createLegacyTxFromRLP,
} from './legacy/constructors.js'
import {
TransactionType,
isAccessList2930TxData,
isBlob4844TxData,
isEOACode7702TxData,
isFeeMarket1559TxData,
isLegacyTxData,
} from './types.js'
import { normalizeTxParams } from './util.js'
import type { Transaction, TxData, TxOptions, TypedTxData } from './types.js'
import type { EthersProvider } from '@ethereumjs/util'
/**
* Create a transaction from a `txData` object
*
* @param txData - The transaction data. The `type` field will determine which transaction type is returned (if undefined, creates a legacy transaction)
* @param txOptions - Options to pass on to the constructor of the transaction
*/
export function createTx<T extends TransactionType>(
txData: TypedTxData,
txOptions: TxOptions = {},
): Transaction[T] {
if (!('type' in txData) || txData.type === undefined) {
// Assume legacy transaction
return createLegacyTx(txData, txOptions) as Transaction[T]
} else {
if (isLegacyTxData(txData)) {
return createLegacyTx(txData, txOptions) as Transaction[T]
} else if (isAccessList2930TxData(txData)) {
return createAccessList2930Tx(txData, txOptions) as Transaction[T]
} else if (isFeeMarket1559TxData(txData)) {
return createFeeMarket1559Tx(txData, txOptions) as Transaction[T]
} else if (isBlob4844TxData(txData)) {
return createBlob4844Tx(txData, txOptions) as Transaction[T]
} else if (isEOACode7702TxData(txData)) {
return createEOACode7702Tx(txData, txOptions) as Transaction[T]
} else {
throw new Error(`Tx instantiation with type ${(txData as TypedTxData)?.type} not supported`)
}
}
}
/**
* This method tries to decode serialized data.
*
* @param data - The data Uint8Array
* @param txOptions - The transaction options
*/
export function createTxFromRLP<T extends TransactionType>(
data: Uint8Array,
txOptions: TxOptions = {},
): Transaction[T] {
if (data[0] <= 0x7f) {
// Determine the type.
switch (data[0]) {
case TransactionType.AccessListEIP2930:
return createAccessList2930TxFromRLP(data, txOptions) as Transaction[T]
case TransactionType.FeeMarketEIP1559:
return createFeeMarket1559TxFromRLP(data, txOptions) as Transaction[T]
case TransactionType.BlobEIP4844:
return createBlob4844TxFromRLP(data, txOptions) as Transaction[T]
case TransactionType.EOACodeEIP7702:
return createEOACode7702TxFromRLP(data, txOptions) as Transaction[T]
default:
throw new Error(`TypedTransaction with ID ${data[0]} unknown`)
}
} else {
return createLegacyTxFromRLP(data, txOptions) as Transaction[T]
}
}
/**
* When decoding a BlockBody, in the transactions field, a field is either:
* A Uint8Array (a TypedTransaction - encoded as TransactionType || rlp(TransactionPayload))
* A Uint8Array[] (Legacy Transaction)
* This method returns the right transaction.
*
* @param data - A Uint8Array or Uint8Array[]
* @param txOptions - The transaction options
*/
export function createTxFromBlockBodyData(
data: Uint8Array | Uint8Array[],
txOptions: TxOptions = {},
) {
if (data instanceof Uint8Array) {
return createTxFromRLP(data, txOptions)
} else if (Array.isArray(data)) {
// It is a legacy transaction
return createLegacyTxFromBytesArray(data, txOptions)
} else {
throw new Error('Cannot decode transaction: unknown type input')
}
}
/**
* Method to decode data retrieved from RPC, such as `eth_getTransactionByHash`
* Note that this normalizes some of the parameters
* @param txData The RPC-encoded data
* @param txOptions The transaction options
* @returns
*/
export async function createTxFromRPC<T extends TransactionType>(
txData: TxData[T],
txOptions: TxOptions = {},
): Promise<Transaction[T]> {
return createTx(normalizeTxParams(txData), txOptions)
}
/**
* Method to retrieve a transaction from the provider
* @param provider - a url string for a JSON-RPC provider or an Ethers JSONRPCProvider object
* @param txHash - Transaction hash
* @param txOptions - The transaction options
* @returns the transaction specified by `txHash`
*/
export async function createTxFromJSONRPCProvider(
provider: string | EthersProvider,
txHash: string,
txOptions?: TxOptions,
) {
const prov = getProvider(provider)
const txData = await fetchFromProvider(prov, {
method: 'eth_getTransactionByHash',
params: [txHash],
})
if (txData === null) {
throw new Error('No data returned from provider')
}
return createTxFromRPC(txData, txOptions)
}