Repository: ethereum/eth-account

Issue:
Expose TypedTransactions Publicly 
Currently TypedTransaction classes live under _utils. We want to expose those for general use. This should :tm: just involve moving them and changing the import path as needed.

Discussion:

Patch:
diff --git a/MANIFEST.in b/MANIFEST.in
index 724e6ea..f4e9c3c 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,6 +1,6 @@
 include LICENSE
 include README.md
-include eth_account/_utils/typed_transactions/blob_transactions/kzg_trusted_setup.txt
+include eth_account/typed_transactions/blob_transactions/kzg_trusted_setup.txt
 
 recursive-include scripts *
 recursive-include tests *
diff --git a/docs/conf.py b/docs/conf.py
index 15870c1..1f6b19c 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -83,6 +83,7 @@ exclude_patterns = [
     "_build",
     "modules.rst",
     "eth_account.internal.rst",
+    "eth_account.typed_transactions.blob_transactions.rst",
 ]
 
 # The reST default role (used for this markup: `text`) to use for all
diff --git a/docs/eth_account.typed_transactions.blob_transactions.rst b/docs/eth_account.typed_transactions.blob_transactions.rst
new file mode 100644
index 0000000..e0e84cc
--- /dev/null
+++ b/docs/eth_account.typed_transactions.blob_transactions.rst
@@ -0,0 +1,21 @@
+eth\_account.typed\_transactions.blob\_transactions package
+===========================================================
+
+Submodules
+----------
+
+eth\_account.typed\_transactions.blob\_transactions.blob\_transaction module
+----------------------------------------------------------------------------
+
+.. automodule:: eth_account.typed_transactions.blob_transactions.blob_transaction
+   :members:
+   :undoc-members:
+   :show-inheritance:
+
+Module contents
+---------------
+
+.. automodule:: eth_account.typed_transactions.blob_transactions
+   :members:
+   :undoc-members:
+   :show-inheritance:
diff --git a/docs/eth_account.typed_transactions.rst b/docs/eth_account.typed_transactions.rst
new file mode 100644
index 0000000..8896c87
--- /dev/null
+++ b/docs/eth_account.typed_transactions.rst
@@ -0,0 +1,34 @@
+Typed Transactions
+==================
+
+Typed Transaction Base
+----------------------
+
+.. automodule:: eth_account.typed_transactions.typed_transaction
+   :members:
+   :undoc-members:
+   :show-inheritance:
+
+Access List Transaction
+-----------------------
+
+.. automodule:: eth_account.typed_transactions.access_list_transaction
+   :members:
+   :undoc-members:
+   :show-inheritance:
+
+Dynamic Fee Transaction
+-----------------------
+
+.. automodule:: eth_account.typed_transactions.dynamic_fee_transaction
+   :members:
+   :undoc-members:
+   :show-inheritance:
+
+Blob Transaction
+----------------
+
+.. automodule:: eth_account.typed_transactions.blob_transactions.blob_transaction
+   :members:
+   :undoc-members:
+   :show-inheritance:
diff --git a/docs/index.rst b/docs/index.rst
index 57dbbf6..2ff040f 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -11,6 +11,7 @@ Contents
 
     eth_account
     eth_account.signers
+    eth_account.typed_transactions
     release_notes
 
 
diff --git a/eth_account/_utils/legacy_transactions.py b/eth_account/_utils/legacy_transactions.py
index c8dee86..cc835b3 100644
--- a/eth_account/_utils/legacy_transactions.py
+++ b/eth_account/_utils/legacy_transactions.py
@@ -23,12 +23,13 @@ from rlp.sedes import (
     binary,
 )
 
+from eth_account.typed_transactions import (
+    TypedTransaction,
+)
+
 from .transaction_utils import (
     set_transaction_type_if_needed,
 )
-from .typed_transactions import (
-    TypedTransaction,
-)
 from .validation import (
     LEGACY_TRANSACTION_FORMATTERS,
     LEGACY_TRANSACTION_VALID_VALUES,
diff --git a/eth_account/_utils/signing.py b/eth_account/_utils/signing.py
index c6c988b..081a834 100644
--- a/eth_account/_utils/signing.py
+++ b/eth_account/_utils/signing.py
@@ -14,7 +14,7 @@ from eth_account._utils.legacy_transactions import (
     serializable_unsigned_transaction_from_dict,
     strip_signature,
 )
-from eth_account._utils.typed_transactions import (
+from eth_account.typed_transactions import (
     TypedTransaction,
 )
 
diff --git a/eth_account/account.py b/eth_account/account.py
index b34652a..330521b 100644
--- a/eth_account/account.py
+++ b/eth_account/account.py
@@ -56,9 +56,6 @@ from eth_account._utils.signing import (
     to_standard_signature_bytes,
     to_standard_v,
 )
-from eth_account._utils.typed_transactions import (
-    TypedTransaction,
-)
 from eth_account.datastructures import (
     SignedMessage,
     SignedTransaction,
@@ -77,6 +74,9 @@ from eth_account.messages import (
 from eth_account.signers.local import (
     LocalAccount,
 )
+from eth_account.typed_transactions import (
+    TypedTransaction,
+)
 
 VRS = TypeVar("VRS", bytes, HexStr, int)
 
diff --git a/eth_account/_utils/typed_transactions/__init__.py b/eth_account/typed_transactions/__init__.py
similarity index 100%
rename from eth_account/_utils/typed_transactions/__init__.py
rename to eth_account/typed_transactions/__init__.py
diff --git a/eth_account/_utils/typed_transactions/access_list_transaction.py b/eth_account/typed_transactions/access_list_transaction.py
similarity index 94%
rename from eth_account/_utils/typed_transactions/access_list_transaction.py
rename to eth_account/typed_transactions/access_list_transaction.py
index d157865..7e4166d 100644
--- a/eth_account/_utils/typed_transactions/access_list_transaction.py
+++ b/eth_account/typed_transactions/access_list_transaction.py
@@ -34,15 +34,16 @@ from rlp.sedes import (
     binary,
 )
 
-from ..transaction_utils import (
+from eth_account._utils.transaction_utils import (
     transaction_rlp_to_rpc_structure,
     transaction_rpc_to_rlp_structure,
 )
-from ..validation import (
+from eth_account._utils.validation import (
     LEGACY_TRANSACTION_VALID_VALUES,
     is_int_or_prefixed_hexstr,
     is_rpc_structured_access_list,
 )
+
 from .base import (
     TYPED_TRANSACTION_FORMATTERS,
     _TypedTransactionImplementation,
@@ -174,7 +175,7 @@ class AccessListTransaction(_TypedTransactionImplementation):
 
     @classmethod
     def from_bytes(cls, encoded_transaction: HexBytes) -> "AccessListTransaction":
-        """Builds an AccesslistTransaction from a signed encoded transaction."""
+        """Builds an AccessListTransaction from a signed encoded transaction."""
         if not isinstance(encoded_transaction, HexBytes):
             raise TypeError(f"expected Hexbytes, got type: {type(encoded_transaction)}")
         if not (
@@ -204,8 +205,8 @@ class AccessListTransaction(_TypedTransactionImplementation):
         """
         Hashes this AccessListTransaction to prepare it for signing.
         As per the EIP-2930 specifications, the signature is a secp256k1 signature over
-        keccak256(0x01 || rlp([chainId, nonce, gasPrice, gasLimit, to, value, data, accessList])).  # noqa E501
-        Here, we compute the keccak256(...) hash.
+        ``keccak256(0x01 || rlp([chainId, nonce, gasPrice, gasLimit,
+        to, value, data, accessList])).``
         """
         # Remove signature fields.
         transaction_without_signature_fields = dissoc(self.dictionary, "v", "r", "s")
@@ -227,9 +228,11 @@ class AccessListTransaction(_TypedTransactionImplementation):
         """
         Returns this transaction's payload as bytes.
 
-        Here, the TransactionPayload = rlp([chainId,
-        nonce, gasPrice, gasLimit, to, value, data, accessList,
-        signatureYParity, signatureR, signatureS])
+        Here, the transaction payload is:
+
+            TransactionPayload = rlp([chainId,
+            nonce, gasPrice, gasLimit, to, value, data, accessList,
+            signatureYParity, signatureR, signatureS])
         """
         if not all(k in self.dictionary for k in "vrs"):
             raise ValueError("attempting to encode an unsigned transaction")
diff --git a/eth_account/_utils/typed_transactions/base.py b/eth_account/typed_transactions/base.py
similarity index 100%
rename from eth_account/_utils/typed_transactions/base.py
rename to eth_account/typed_transactions/base.py
diff --git a/eth_account/_utils/typed_transactions/blob_transactions/__init__.py b/eth_account/typed_transactions/blob_transactions/__init__.py
similarity index 100%
rename from eth_account/_utils/typed_transactions/blob_transactions/__init__.py
rename to eth_account/typed_transactions/blob_transactions/__init__.py
diff --git a/eth_account/_utils/typed_transactions/blob_transactions/blob_transaction.py b/eth_account/typed_transactions/blob_transactions/blob_transaction.py
similarity index 95%
rename from eth_account/_utils/typed_transactions/blob_transactions/blob_transaction.py
rename to eth_account/typed_transactions/blob_transactions/blob_transaction.py
index 9954d7a..aa8124b 100644
--- a/eth_account/_utils/typed_transactions/blob_transactions/blob_transaction.py
+++ b/eth_account/typed_transactions/blob_transactions/blob_transaction.py
@@ -40,21 +40,21 @@ from eth_account._utils.transaction_utils import (
     transaction_rlp_to_rpc_structure,
     transaction_rpc_to_rlp_structure,
 )
-from eth_account._utils.typed_transactions.access_list_transaction import (
+from eth_account._utils.validation import (
+    LEGACY_TRANSACTION_VALID_VALUES,
+    is_int_or_prefixed_hexstr,
+    is_rpc_structured_access_list,
+    is_sequence_of_bytes_or_hexstr,
+)
+from eth_account.typed_transactions.access_list_transaction import (
     access_list_sede_type,
 )
-from eth_account._utils.typed_transactions.base import (
+from eth_account.typed_transactions.base import (
     TYPED_TRANSACTION_FORMATTERS,
     Blob,
     BlobPooledTransactionData,
     _TypedTransactionImplementation,
 )
-from eth_account._utils.validation import (
-    LEGACY_TRANSACTION_VALID_VALUES,
-    is_int_or_prefixed_hexstr,
-    is_rpc_structured_access_list,
-    is_sequence_of_bytes_or_hexstr,
-)
 
 
 class BlobTransaction(_TypedTransactionImplementation):
@@ -288,13 +288,11 @@ class BlobTransaction(_TypedTransactionImplementation):
 
     def hash(self) -> bytes:
         """
-        Hashes the BlobTransaction to prepare it for signing.
+        Keccak256 hash of the BlobTransaction to prepare it for signing.
         As per the EIP-4844 specifications, the signature is a secp256k1 signature over
-        keccak256(0x03 || rlp([chainId, nonce, maxPriorityFeePerGas,
+        ``keccak256(0x03 || rlp([chainId, nonce, maxPriorityFeePerGas,
         maxFeePerGas, gasLimit, to, value, data, accessList, maxFeePerBlobGas,
-        blobVersionedHashes])).
-
-        Here, we compute the keccak256(...) hash.
+        blobVersionedHashes]))``.
         """
         # Remove signature fields.
         transaction_without_signature_fields = dissoc(self.dictionary, "v", "r", "s")
@@ -332,10 +330,13 @@ class BlobTransaction(_TypedTransactionImplementation):
         """
         Returns this transaction's payload as bytes.
 
-        Here, the TransactionPayload = rlp([chainId,
-        nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, to, value, data,
-        accessList, maxFeePerBlobGas, blobVersionedHashes, signatureYParity, signatureR,
-        signatureS])
+        Here, the transaction payload is:
+
+            TransactionPayload = rlp([chainId,
+            nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, to, value, data,
+            accessList, maxFeePerBlobGas, blobVersionedHashes, signatureYParity,
+            signatureR, signatureS])
+
         """
         if not all(k in self.dictionary for k in "vrs"):
             raise ValueError("attempting to encode an unsigned transaction")
diff --git a/eth_account/_utils/typed_transactions/blob_transactions/kzg_trusted_setup.txt b/eth_account/typed_transactions/blob_transactions/kzg_trusted_setup.txt
similarity index 100%
rename from eth_account/_utils/typed_transactions/blob_transactions/kzg_trusted_setup.txt
rename to eth_account/typed_transactions/blob_transactions/kzg_trusted_setup.txt
diff --git a/eth_account/_utils/typed_transactions/dynamic_fee_transaction.py b/eth_account/typed_transactions/dynamic_fee_transaction.py
similarity index 94%
rename from eth_account/_utils/typed_transactions/dynamic_fee_transaction.py
rename to eth_account/typed_transactions/dynamic_fee_transaction.py
index e61d5bc..83be9ca 100644
--- a/eth_account/_utils/typed_transactions/dynamic_fee_transaction.py
+++ b/eth_account/typed_transactions/dynamic_fee_transaction.py
@@ -31,15 +31,16 @@ from rlp.sedes import (
     binary,
 )
 
-from ..transaction_utils import (
+from eth_account._utils.transaction_utils import (
     transaction_rlp_to_rpc_structure,
     transaction_rpc_to_rlp_structure,
 )
-from ..validation import (
+from eth_account._utils.validation import (
     LEGACY_TRANSACTION_VALID_VALUES,
     is_int_or_prefixed_hexstr,
     is_rpc_structured_access_list,
 )
+
 from .access_list_transaction import (
     access_list_sede_type,
 )
@@ -195,9 +196,8 @@ class DynamicFeeTransaction(_TypedTransactionImplementation):
         """
         Hashes this DynamicFeeTransaction to prepare it for signing.
         As per the EIP-1559 specifications, the signature is a secp256k1 signature over
-        keccak256(0x02 || rlp([chainId, nonce, maxPriorityFeePerGas,
-        maxFeePerGas, gasLimit, to, value, data, accessList])).
-        Here, we compute the keccak256(...) hash.
+        ``keccak256(0x02 || rlp([chainId, nonce, maxPriorityFeePerGas,
+        maxFeePerGas, gasLimit, to, value, data, accessList]))``
         """
         # Remove signature fields.
         transaction_without_signature_fields = dissoc(self.dictionary, "v", "r", "s")
@@ -219,9 +219,11 @@ class DynamicFeeTransaction(_TypedTransactionImplementation):
         """
         Returns this transaction's payload as bytes.
 
-        Here, the TransactionPayload = rlp([chainId,
-        nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, to, value, data,
-        accessList, signatureYParity, signatureR, signatureS])
+        Here, the transaction payload is:
+
+            TransactionPayload = rlp([chainId,
+            nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, to, value, data,
+            accessList, signatureYParity, signatureR, signatureS])
         """
         if not all(k in self.dictionary for k in "vrs"):
             raise ValueError("attempting to encode an unsigned transaction")
diff --git a/eth_account/_utils/typed_transactions/typed_transaction.py b/eth_account/typed_transactions/typed_transaction.py
similarity index 98%
rename from eth_account/_utils/typed_transactions/typed_transaction.py
rename to eth_account/typed_transactions/typed_transaction.py
index 93b5a77..ba4074d 100644
--- a/eth_account/_utils/typed_transactions/typed_transaction.py
+++ b/eth_account/typed_transactions/typed_transaction.py
@@ -18,13 +18,14 @@ from hexbytes import (
     HexBytes,
 )
 
-from ..transaction_utils import (
+from eth_account._utils.transaction_utils import (
     normalize_transaction_dict,
     set_transaction_type_if_needed,
 )
-from ..validation import (
+from eth_account._utils.validation import (
     is_int_or_prefixed_hexstr,
 )
+
 from .access_list_transaction import (
     AccessListTransaction,
 )
@@ -44,9 +45,11 @@ class TypedTransaction:
     """
     Represents a Typed Transaction as per EIP-2718.
     The currently supported Transaction Types are:
+
      * EIP-2930's AccessListTransaction
      * EIP-1559's DynamicFeeTransaction
      * EIP-4844's BlobTransaction
+
     """
 
     def __init__(
diff --git a/newsfragments/276.feature.rst b/newsfragments/276.feature.rst
new file mode 100644
index 0000000..f36f0ed
--- /dev/null
+++ b/newsfragments/276.feature.rst
@@ -0,0 +1,1 @@
+Expose TypedTransactions for public use


Test patch:
diff --git a/tests/core/test_blob_transactions.py b/tests/core/test_blob_transactions.py
index 83cb21b..4d9a669 100644
--- a/tests/core/test_blob_transactions.py
+++ b/tests/core/test_blob_transactions.py
@@ -15,7 +15,7 @@ from toolz import (
 from eth_account import (
     Account,
 )
-from eth_account._utils.typed_transactions import (
+from eth_account.typed_transactions import (
     BlobTransaction,
 )
 
diff --git a/tests/core/test_typed_transactions.py b/tests/core/test_typed_transactions.py
index 21f3bef..911ac77 100644
--- a/tests/core/test_typed_transactions.py
+++ b/tests/core/test_typed_transactions.py
@@ -4,7 +4,7 @@ from hexbytes import (
     HexBytes,
 )
 
-from eth_account._utils.typed_transactions import (
+from eth_account.typed_transactions import (
     AccessListTransaction,
     BlobTransaction,
     DynamicFeeTransaction,