Repository: 0xSpaceShard/starknet-devnet (language: python)

Issue:
Update JSON-RPC schema to v0.3.0
https://github.com/starkware-libs/starknet-specs/blob/v0.3.0-rc1/api/starknet_api_openrpc.json

Should resolve #401 (and close #412 ?)
RPC schema felt validation
**Describe the bug (observed vs expected behavior)**

For the RPC schema validation of the latest `devnet` version the regular expression used for validating `felt` fields seems to be too strict. It necessitates that the corresponding values conform to the `0x0{digits}` format, while for the earlier versions and for `testnet` the `0x{digits}` format is accepted.

For the payload:
```
{
    "jsonrpc": "2.0",
    "method": "starknet_getClass",
    "params": {
        "block_id": "latest",
        "class_hash": "0x25ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918"
    },
    "id": 0
}
```
- `testnet` replies with a successful response
- `devnet 0.4.4` replies with the expected `UNDECLARED_CLASS` error
- `devnet 0.4.5` replies with the unexpected `"Got invalid value for parameter: \"'0x25ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918' does not match '^0x0[a-fA-F0-9]{1,63}$'\""` error message

**Not reproducible on alpha-goerli**

- [x] This issue is only present on Devnet and cannot be reproduced on alpha-goerli (check the box if true).

**Devnet version**

- I am using Devnet version: 0.4.5
- [x] This happens with a dockerized Devnet (check the box if true).
- This does not appear on the following Devnet version: 0.4.4

Update felt schema to be less strict

## Usage related changes

Update the schema used to validate felts to the most recent version
included in starknet-specs.
This schema is less strict, and allows felts that are not zero-padded.

Fix #401

## Development related changes

No changes

## Checklist:

- [x] Applied formatting - `./scripts/format.sh`
- [x] No linter errors - `./scripts/lint.sh`
- [x] Performed code self-review
- [x] Rebased to the last commit of the target branch (or merged it into my branch)
- [x] Documented the changes
- [x] Linked the issues which this PR resolves
- [ ] Updated the tests
- [ ] All tests are passing - `./scripts/test.sh`



Discussion / hints:

I'm also hitting this bug by requesting the transaction receipt of the seed accounts deploy transactions.
@fracek just proposed another updated regex with a simple `?`, see corresponding PR
I believe the devnet should stick with the "official" regexp from starknet's rpc-spec repo. This change will probably soon be released, and my understanding is that regexp used there was deliberate (as the leading 0 does not change the value - `0x0123` == `0x123`).

I'd rather the devnet complies to the rpc spec (especially that it is supposed to validate payloads/responses against it) than introduce some other regexp that technically works, but is only specific to it. This can lead to all kinds of problems in the future.

It probably means some additional work is necessary on the devnet part to make it work (I guess changing/removing `rpc_felt`s or checking felt values and converting them by removing leading 0 if needed). It shouldn't be too complicated though.
> I believe the devnet should stick with the "official" regexp from starknet's rpc-spec repo. This change will probably soon be released, and my understanding is that regexp used there was deliberate (as the leading 0 does not change the value - `0x0123` == `0x123`).
> 
> I'd rather the devnet complies to the rpc spec (especially that it is supposed to validate payloads/responses against it) than introduce some other regexp that technically works, but is only specific to it. This can lead to all kinds of problems in the future.
> 
> It probably means some additional work is necessary on the devnet part to make it work (I guess changing/removing `rpc_felt`s or checking felt values and converting them by removing leading 0 if needed). It shouldn't be too complicated though.

I don't really have an opinion, I don't understand why people care so much about a leading `0` which doesn't really make any sense to me (is it to have a 32 long bytes string? though felt is not a bytes32), but what I'm sure about is that it makes the current devnet not working with starknet-rs
Does it help if `starknet-devnet` is started with `--disable-rpc-request-validation` or `--disable-rpc-response-validation`?

EDIT: Yes, running Devnet with:
```sh
starknet-devnet --disable-rpc-request-validation
```

resolves the issue and can be used at least as a temporary solution.
Looks like the response validation doesn't like the regex I added (copied from starknet-specs) and returns an error for every request.

```json
{
	"error": {
		"code": -32603,
		"message": "Devnet tried to return invalid value: \"Unevaluated properties are not allowed ('block_hash', 'block_number', 'new_root', 'parent_hash', 'sequencer_address', 'status', 'timestamp', 'transactions' were unexpected)\""
	},
	"id": 0,
	"jsonrpc": "2.0"
}
```
I can see the regex used was based on the [recent change in spec](https://github.com/starkware-libs/starknet-specs/blob/master/api/starknet_api_openrpc.json#L1030), however, it looks like it might be missing some parentheses. `^0x(0|[a-fA-F1-9]{1}[a-fA-F0-9]{0,62})` checks for `0x followed by 0 or the rest`, the intent was probably for it to be `^0x(0|[a-fA-F1-9]{1})([a-fA-F0-9]{0,62})$` so it checks for `0x followed by 0|[a-fA-F1-9]{1} followed by [a-fA-F0-9]{0,62}`.

I'm unsure if the regex should maybe be `^0x0?[a-fA-F0-9]{1,63}$` so the leading zero is only optional and doesn't affect the count of significant digits.
@penovicp see my correponding PR https://github.com/Shard-Labs/starknet-devnet/pull/413 with the `?` which seems to me the most easy and straighforward change
@ClementWalter @penovicp
~~Doesn't `^0x0?[a-fA-F0-9]{1,63}$` then allow 64 digits after `0x`? Should that be considered legal?~~

EDIT: Sorry, that's how it's supposed to be, I had a wrong number in my head
Personally I'm leaning towards penovicp's idea implement in Clement's #413
Agree! Let's keep it simple! 
As pointed out [here](https://github.com/Shard-Labs/starknet-devnet/issues/401#issuecomment-1448121152), we should reopen this PR and close #413.

@fracek Would you know how to resolve the issue arising with this PR?
The error originates when validating the response of calling `starknet_getBlockWithTxs` on the genesis block. I haven't investigated too much why it happens.
@mikiw Can you take a look
> The error originates when validating the response of calling `starknet_getBlockWithTxs` on the genesis block. I haven't investigated too much why it happens.

I'll take a look now.
```
============================================ short test summary info =============================================
FAILED test/rpc/test_rpc_blocks.py::test_get_block_with_tx_hashes[hash] - KeyError: 'result'
FAILED test/rpc/test_rpc_blocks.py::test_get_block_with_tx_hashes[number] - KeyError: 'result'
FAILED test/rpc/test_rpc_blocks.py::test_get_block_with_tx_hashes[tag] - KeyError: 'result'
FAILED test/rpc/test_rpc_blocks.py::test_get_block_with_tx_hashes[tag_pending] - KeyError: 'result'
FAILED test/rpc/test_rpc_blocks.py::test_get_block_with_tx_hashes_raises_on_incorrect_block_id[block_id1] - assert {'code': -326...]{0,62})$\'"'} == {'code': 24, ...ck not found'}
FAILED test/rpc/test_rpc_blocks.py::test_get_block_with_txs[hash] - KeyError: 'result'
FAILED test/rpc/test_rpc_blocks.py::test_get_block_with_txs[number] - KeyError: 'result'
FAILED test/rpc/test_rpc_blocks.py::test_get_block_with_txs[tag] - KeyError: 'result'
FAILED test/rpc/test_rpc_blocks.py::test_get_block_with_txs[tag_pending] - KeyError: 'result'
FAILED test/rpc/test_rpc_blocks.py::test_get_block_with_txs_raises_on_incorrect_block_id[block_id1] - assert {'code': -326...]{0,62})$\'"'} == {'code': 24, ...ck not found'}
FAILED test/rpc/test_rpc_blocks.py::test_get_block_transaction_count[hash] - KeyError: 'result'
FAILED test/rpc/test_rpc_blocks.py::test_get_block_transaction_count_raises_on_incorrect_block_id[block_id1] - assert {'code': -326...]{0,62})$\'"'} == {'code': 24, ...ck not found'}
==================================== 12 failed, 7 passed in 136.81s (0:02:16) ====================================
```

I got these test results. Checking how to fix it.

In tests we use dummy data like `0x1` I advise disabling validation in those tests to avoid many changes from `0x1` to `0x000000000000000000000000000000000000000000000000000000000000001`. So validation tests will only be in `test_rpc_schema.py`.
I made a 2fecdd96304bd3a90b2f2fe28a2a2c6f7fa3e478 commit with some test fixes and now just 3 tests are failing in this test file.
Actually, I reverted that, seems that fix can be made only by modifying the rpc_felt wrapper.
Actually, I tried that but only one test was fixed. This was my change:
![image](https://user-images.githubusercontent.com/5063930/222135108-138f2c2f-e1a9-466c-85bd-83f70a2da117.png)

```
    if value == 0:
        return f"{0:#0{65}x}"
    return f"{value:#0{65}x}"
```

Any ideas?

Fix patch:
diff --git a/page/docs/guide/json-rpc-api.md b/page/docs/guide/json-rpc-api.md
index 0c4718820..d4bea2956 100644
--- a/page/docs/guide/json-rpc-api.md
+++ b/page/docs/guide/json-rpc-api.md
@@ -4,7 +4,7 @@ sidebar_position: 3
 
 # JSON-RPC API
 
-Devnet also supports JSON-RPC API v0.2.1: [specifications](https://github.com/starkware-libs/starknet-specs/releases/tag/v0.2.1) . It can be reached under `/rpc`. For an example:
+Devnet also supports JSON-RPC API v0.3.0-rc1: [specifications](https://github.com/starkware-libs/starknet-specs/releases/tag/v0.3.0-rc1) . It can be reached under `/rpc`. For an example:
 
 Requests to rpc and devnet responses are automatically validated against JSON schema in runtime.
 In case of problems, this validations can be disabled by `--disable-rpc-request-validation` and
diff --git a/starknet_devnet/blueprints/rpc/classes.py b/starknet_devnet/blueprints/rpc/classes.py
index 5dc4c8c8f..8b18d0c8b 100644
--- a/starknet_devnet/blueprints/rpc/classes.py
+++ b/starknet_devnet/blueprints/rpc/classes.py
@@ -1,14 +1,10 @@
 """
 RPC classes endpoints
 """
-
-from starkware.starknet.services.api.contract_class.contract_class import (
-    DeprecatedCompiledClass,
-)
 from starkware.starkware_utils.error_handling import StarkException
 
 from starknet_devnet.blueprints.rpc.schema import validate_schema
-from starknet_devnet.blueprints.rpc.structures.payloads import rpc_contract_class
+from starknet_devnet.blueprints.rpc.structures.payloads import contract_class_from_dict
 from starknet_devnet.blueprints.rpc.structures.types import (
     Address,
     BlockId,
@@ -34,9 +30,7 @@ async def get_class(block_id: BlockId, class_hash: Felt) -> dict:
     except StarknetDevnetException as ex:
         raise RpcError.from_spec_name("CLASS_HASH_NOT_FOUND") from ex
 
-    # only works with cairo 0 classes
-    loaded_class = DeprecatedCompiledClass.load(result_dict)
-    return rpc_contract_class(loaded_class)
+    return contract_class_from_dict(result_dict)
 
 
 @validate_schema("getClassHashAt")
@@ -67,8 +61,7 @@ async def get_class_at(block_id: BlockId, contract_address: Address) -> dict:
         result_dict = await state.starknet_wrapper.get_class_by_address(
             int(contract_address, 16), block_id
         )
-        contract_class = DeprecatedCompiledClass.load(result_dict)
     except StarkException as ex:
         raise RpcError.from_spec_name("CONTRACT_NOT_FOUND") from ex
 
-    return rpc_contract_class(contract_class)
+    return contract_class_from_dict(result_dict)
diff --git a/starknet_devnet/blueprints/rpc/misc.py b/starknet_devnet/blueprints/rpc/misc.py
index 3ebd50308..75e70cfd9 100644
--- a/starknet_devnet/blueprints/rpc/misc.py
+++ b/starknet_devnet/blueprints/rpc/misc.py
@@ -41,11 +41,20 @@ def check_address(address, event):
     return event.from_address == int(address, 0)
 
 
-def check_keys(keys, event):
+def _check_keys(keys: List[List[Felt]], event):
     """
     Check keys.
+
+    Check every key in an event against related list of accepted values.
+    n-th array in keys (keys[n]) lists all possible values of n-th key in an
+    event (event.keys[n]). Empty list of accepted_keys, means that all keys
+    should be accepted.
     """
-    return bool(set(event.keys) & set(keys))
+    for event_key, accepted_keys in zip(event.keys, keys):
+        if len(accepted_keys) > 0 and event_key not in accepted_keys:
+            return False
+
+    return True
 
 
 def _get_events_from_block(block: StarknetBlock, address, keys):
@@ -56,7 +65,7 @@ def _get_events_from_block(block: StarknetBlock, address, keys):
     for receipt, event in [
         (r, e) for r in block.transaction_receipts for e in r.events
     ]:
-        if check_keys(keys, event) and check_address(address, event):
+        if _check_keys(keys, event) and check_address(address, event):
             _event: EmittedEvent = {
                 "from_address": rpc_felt(event.from_address),
                 "keys": [rpc_felt(e) for e in event.keys],
@@ -139,7 +148,11 @@ async def get_events(
         ) from ex
 
     address = filter.get("address")
-    keys = [int(k, 0) for k in filter.get("keys")]
+
+    if filter.get("keys") is not None:
+        keys = [[int(key, 0) for key in keys] for keys in filter.get("keys")]
+    else:
+        keys = []
     # Optional parameter
     continuation_token = int(filter.get("continuation_token", "0"))
 
diff --git a/starknet_devnet/blueprints/rpc/rpc_spec.py b/starknet_devnet/blueprints/rpc/rpc_spec.py
index c73a6b781..ce9acd110 100644
--- a/starknet_devnet/blueprints/rpc/rpc_spec.py
+++ b/starknet_devnet/blueprints/rpc/rpc_spec.py
@@ -1,13 +1,12 @@
 # pylint: disable=too-many-lines, missing-module-docstring
-# NOTE: This is modified version of 0.2.1 spec
-# Some usages of "oneOf" has been replaced by "anyOf"
-# and one method has been fixed
+# NOTE: This is modified version of 0.3.0-rc1 spec
+# All usages of "oneOf" have been replaced by "anyOf"
 RPC_SPECIFICATION = r"""
 {
     "openrpc": "1.0.0-rc1",
     "info": {
-        "version": "0.45.0",
-        "title": "Starknet Node API",
+        "version": "0.50.0",
+        "title": "StarkNet Node API",
         "license": {}
     },
     "servers": [],
@@ -95,7 +94,14 @@
                 "name": "result",
                 "description": "The information about the state update of the requested block",
                 "schema": {
-                    "$ref": "#/components/schemas/STATE_UPDATE"
+                    "anyOf": [
+                        {
+                            "$ref": "#/components/schemas/STATE_UPDATE"
+                        },
+                        {
+                            "$ref": "#/components/schemas/PENDING_STATE_UPDATE"
+                        }
+                    ]
                 }
             },
             "errors": [
@@ -267,7 +273,14 @@
                 "name": "result",
                 "description": "The contract class, if found",
                 "schema": {
-                    "$ref": "#/components/schemas/CONTRACT_CLASS"
+                    "anyOf": [
+                        {
+                            "$ref": "#/components/schemas/DEPRECATED_CONTRACT_CLASS"
+                        },
+                        {
+                            "$ref": "#/components/schemas/CONTRACT_CLASS"
+                        }
+                    ]
                 }
             },
             "errors": [
@@ -341,7 +354,14 @@
                 "name": "result",
                 "description": "The contract class",
                 "schema": {
-                    "$ref": "#/components/schemas/CONTRACT_CLASS"
+                    "anyOf": [
+                        {
+                            "$ref": "#/components/schemas/DEPRECATED_CONTRACT_CLASS"
+                        },
+                        {
+                            "$ref": "#/components/schemas/CONTRACT_CLASS"
+                        }
+                    ]
                 }
             },
             "errors": [
@@ -384,7 +404,7 @@
         },
         {
             "name": "starknet_call",
-            "summary": "call a starknet function without creating a Starknet transaction",
+            "summary": "call a starknet function without creating a StarkNet transaction",
             "description": "Calls a function in a contract and returns the return value.  Using this call will not create a transaction; hence, will not change the state",
             "params": [
                 {
@@ -435,14 +455,18 @@
         },
         {
             "name": "starknet_estimateFee",
-            "summary": "estimate the fee for a given Starknet transaction",
-            "description": "estimates the resources required by a transaction relative to a given state",
+            "summary": "estimate the fee for of StarkNet transactions",
+            "description": "estimates the resources required by transactions when applyed on a given state",
             "params": [
                 {
                     "name": "request",
                     "summary": "The transaction to estimate",
                     "schema": {
-                        "$ref": "#/components/schemas/BROADCASTED_TXN"
+                        "type": "array",
+                        "description": "a sequence of transactions to estimate, running each transaction on the state resulting from applying all the previous ones",
+                        "items": {
+                            "$ref": "#/components/schemas/BROADCASTED_TXN"
+                        }
                     },
                     "required": true
                 },
@@ -457,9 +481,13 @@
             ],
             "result": {
                 "name": "result",
-                "description": "the fee estimation",
+                "description": "the fee estimations",
                 "schema": {
-                    "$ref": "#/components/schemas/FEE_ESTIMATE"
+                    "type": "array",
+                    "description": "a sequence of fee estimatione where the i'th estimate corresponds to the i'th transaction",
+                    "items": {
+                        "$ref": "#/components/schemas/FEE_ESTIMATE"
+                    }
                 }
             },
             "errors": [
@@ -524,7 +552,7 @@
         },
         {
             "name": "starknet_chainId",
-            "summary": "Return the currently configured Starknet chain id",
+            "summary": "Return the currently configured StarkNet chain id",
             "params": [],
             "result": {
                 "name": "result",
@@ -558,7 +586,7 @@
                 "summary": "The state of the synchronization, or false if the node is not synchronizing",
                 "description": "The status of the node, if it is currently synchronizing state. FALSE otherwise",
                 "schema": {
-                    "oneOf": [
+                    "anyOf": [
                         {
                             "type": "boolean",
                             "description": "only legal value is FALSE here"
@@ -595,23 +623,7 @@
                 "name": "events",
                 "description": "All the event objects matching the filter",
                 "schema": {
-                    "type": "object",
-                    "properties": {
-                        "events": {
-                            "type": "array",
-                            "title": "Matching Events",
-                            "items": {
-                                "$ref": "#/components/schemas/EMITTED_EVENT"
-                            }
-                        },
-                        "continuation_token": {
-                            "description": "a pointer to the last element of the delivered page, use this token in a subsequent query to obtain the next page",
-                            "type": "string"
-                        }
-                    },
-                    "required": [
-                        "events"
-                    ]
+                    "$ref": "#/components/schemas/EVENTS_CHUNK"
                 }
             },
             "errors": [
@@ -623,6 +635,9 @@
                 },
                 {
                     "$ref": "#/components/errors/BLOCK_NOT_FOUND"
+                },
+                {
+                    "$ref": "#/components/errors/TOO_MANY_KEYS_IN_FILTER"
                 }
             ]
         },
@@ -667,11 +682,30 @@
     "components": {
         "contentDescriptors": {},
         "schemas": {
+            "EVENTS_CHUNK": {
+                "type": "object",
+                "properties": {
+                    "events": {
+                        "type": "array",
+                        "title": "Matching Events",
+                        "items": {
+                            "$ref": "#/components/schemas/EMITTED_EVENT"
+                        }
+                    },
+                    "continuation_token": {
+                        "description": "Use this token in a subsequent query to obtain the next page. Should not appear if there are no more pages.",
+                        "type": "string"
+                    }
+                },
+                "required": [
+                    "events"
+                ]
+            },
             "RESULT_PAGE_REQUEST": {
                 "type": "object",
                 "properties": {
                     "continuation_token": {
-                        "description": "a pointer to the last element of the delivered page, use this token in a subsequent query to obtain the next page",
+                        "description": "The token returned from the previous query. If no token is provided the first page is returned.",
                         "type": "string"
                     },
                     "chunk_size": {
@@ -707,12 +741,17 @@
                                 "title": "The transaction that emitted the event",
                                 "$ref": "#/components/schemas/TXN_HASH"
                             }
-                        }
+                        },
+                        "required": [
+                            "block_hash",
+                            "block_number",
+                            "transaction_hash"
+                        ]
                     }
                 ]
             },
             "EVENT": {
-                "title": "A Starknet event",
+                "title": "A StarkNet event",
                 "allOf": [
                     {
                         "type": "object",
@@ -720,7 +759,10 @@
                             "from_address": {
                                 "$ref": "#/components/schemas/ADDRESS"
                             }
-                        }
+                        },
+                        "required": [
+                            "from_address"
+                        ]
                     },
                     {
                         "$ref": "#/components/schemas/EVENT_CONTENT"
@@ -744,7 +786,11 @@
                             "$ref": "#/components/schemas/FELT"
                         }
                     }
-                }
+                },
+                "required": [
+                    "keys",
+                    "data"
+                ]
             },
             "EVENT_FILTER": {
                 "title": "An event filter/query",
@@ -767,15 +813,25 @@
                         "description": "The values used to filter the events",
                         "type": "array",
                         "items": {
-                            "title": "event key value",
-                            "$ref": "#/components/schemas/FELT"
+                            "title": "Possible values, per key",
+                            "description": "Per key (by position), designate the possible values to be matched for events to be returned. Empty array designates 'any' value",
+                            "type": "array",
+                            "items": {
+                                "$ref": "#/components/schemas/FELT"
+                            }
                         }
                     }
-                }
+                },
+                "required": [
+                    "from_block",
+                    "to_block",
+                    "address",
+                    "keys"
+                ]
             },
             "BLOCK_ID": {
                 "title": "Block hash, number or tag",
-                "oneOf": [
+                "anyOf": [
                     {
                         "type": "object",
                         "properties": {
@@ -783,7 +839,9 @@
                                 "$ref": "#/components/schemas/BLOCK_HASH"
                             }
                         },
-                        "required": ["block_hash"]
+                        "required": [
+                            "block_hash"
+                        ]
                     },
                     {
                         "type": "object",
@@ -792,7 +850,9 @@
                                 "$ref": "#/components/schemas/BLOCK_NUMBER"
                             }
                         },
-                        "required": ["block_number"]
+                        "required": [
+                            "block_number"
+                        ]
                     },
                     {
                         "$ref": "#/components/schemas/BLOCK_TAG"
@@ -835,7 +895,15 @@
                         "description": "The number (height) of the estimated highest block to be synchronized",
                         "$ref": "#/components/schemas/NUM_AS_HEX"
                     }
-                }
+                },
+                "required": [
+                    "starting_block_hash",
+                    "starting_block_num",
+                    "current_block_hash",
+                    "current_block_num",
+                    "highest_block_hash",
+                    "highest_block_num"
+                ]
             },
             "NUM_AS_HEX": {
                 "title": "An integer number in hex format (0x...)",
@@ -844,20 +912,37 @@
             },
             "CHAIN_ID": {
                 "title": "chainId",
-                "description": "Starknet chain id, given in hex representation.",
+                "description": "StarkNet chain id, given in hex representation.",
                 "type": "string",
                 "pattern": "^0x[a-fA-F0-9]+$"
             },
             "STATE_UPDATE": {
                 "type": "object",
-                "properties": {
-                    "block_hash": {
-                        "$ref": "#/components/schemas/BLOCK_HASH"
-                    },
-                    "new_root": {
-                        "description": "The new global state root",
-                        "$ref": "#/components/schemas/FELT"
+                "allOf": [
+                    {
+                        "type": "object",
+                        "properties": {
+                            "block_hash": {
+                                "$ref": "#/components/schemas/BLOCK_HASH"
+                            },
+                            "new_root": {
+                                "description": "The new global state root",
+                                "$ref": "#/components/schemas/FELT"
+                            }
+                        },
+                        "required": [
+                            "block_hash",
+                            "new_root"
+                        ]
                     },
+                    {
+                        "$ref": "#/components/schemas/PENDING_STATE_UPDATE"
+                    }
+                ]
+            },
+            "PENDING_STATE_UPDATE": {
+                "type": "object",
+                "properties": {
                     "old_root": {
                         "description": "The previous global state root",
                         "$ref": "#/components/schemas/FELT"
@@ -873,20 +958,54 @@
                                     "$ref": "#/components/schemas/CONTRACT_STORAGE_DIFF_ITEM"
                                 }
                             },
-                            "declared_contract_hashes": {
+                            "deprecated_declared_classes": {
                                 "type": "array",
                                 "items": {
-                                    "description": "The hash of a new contract declared as part of the new state",
+                                    "description": "The hash of the declared class",
                                     "$ref": "#/components/schemas/FELT"
                                 }
                             },
+                            "declared_classes": {
+                                "type": "array",
+                                "items": {
+                                    "description": "The declared class hash and compiled class hash",
+                                    "type": "object",
+                                    "properties": {
+                                        "class_hash": {
+                                            "description": "The hash of the declared class",
+                                            "$ref": "#/components/schemas/FELT"
+                                        },
+                                        "compiled_class_hash": {
+                                            "description": "The Cairo assembly hash corresponding to the declared class",
+                                            "$ref": "#/components/schemas/FELT"
+                                        }
+                                    }
+                                }
+                            },
                             "deployed_contracts": {
                                 "type": "array",
                                 "items": {
-                                    "description": "A new contract deployed as part of the new state",
+                                    "description": "A new contract deployed as part of the state update",
                                     "$ref": "#/components/schemas/DEPLOYED_CONTRACT_ITEM"
                                 }
                             },
+                            "replaced_classes": {
+                                "type": "array",
+                                "items": {
+                                    "description": "The list of contracts whose class was replaced",
+                                    "type": "object",
+                                    "properties": {
+                                        "contract_address": {
+                                            "description": "The address of the contract whose class was replaced",
+                                            "$ref": "#/components/schemas/ADDRESS"
+                                        },
+                                        "class_hash": {
+                                            "description": "The new class hash",
+                                            "$ref": "#/components/schemas/FELT"
+                                        }
+                                    }
+                                }
+                            },
                             "nonces": {
                                 "type": "array",
                                 "items": {
@@ -904,9 +1023,21 @@
                                     }
                                 }
                             }
-                        }
+                        },
+                        "required": [
+                            "storage_diffs",
+                            "deprecated_declared_classes",
+                            "declared_classes",
+                            "replaced_classes",
+                            "deployed_contracts",
+                            "nonces"
+                        ]
                     }
-                }
+                },
+                "required": [
+                    "old_root",
+                    "state_diff"
+                ]
             },
             "ADDRESS": {
                 "$ref": "#/components/schemas/FELT"
@@ -926,15 +1057,14 @@
             },
             "TXN_HASH": {
                 "$ref": "#/components/schemas/FELT",
-                "description": "The transaction hash, as assigned in Starknet",
+                "description": "The transaction hash, as assigned in StarkNet",
                 "title": "A transaction's hash"
             },
             "FELT": {
                 "type": "string",
                 "title": "Field element",
-                "$comment": "A field element, represented as a string of hex digits",
-                "description": "A field element. Represented as up to 63 hex digits and leading 4 bits zeroed.",
-                "pattern": "^0x0[a-fA-F0-9]{1,63}$"
+                "description": "A field element. represented by at most 63 hex digits",
+                "pattern": "^0x(0|[a-fA-F1-9]{1}[a-fA-F0-9]{0,62})$"
             },
             "BLOCK_NUMBER": {
                 "description": "The block's number (its height)",
@@ -955,7 +1085,10 @@
                             "$ref": "#/components/schemas/TXN_HASH"
                         }
                     }
-                }
+                },
+                "required": [
+                    "transactions"
+                ]
             },
             "BLOCK_BODY_WITH_TXS": {
                 "type": "object",
@@ -967,10 +1100,13 @@
                             "$ref": "#/components/schemas/TXN"
                         }
                     }
-                }
+                },
+                "required": [
+                    "transactions"
+                ]
             },
             "BLOCK_HEADER": {
-                "title": "Block header",
+                "type": "object",
                 "properties": {
                     "block_hash": {
                         "$ref": "#/components/schemas/BLOCK_HASH"
@@ -993,10 +1129,18 @@
                         "minimum": 0
                     },
                     "sequencer_address": {
-                        "description": "The Starknet identity of the sequencer submitting this block",
+                        "description": "The StarkNet identity of the sequencer submitting this block",
                         "$ref": "#/components/schemas/FELT"
                     }
-                }
+                },
+                "required": [
+                    "block_hash",
+                    "parent_hash",
+                    "block_number",
+                    "new_root",
+                    "timestamp",
+                    "sequencer_address"
+                ]
             },
             "BLOCK_WITH_TX_HASHES": {
                 "title": "The block object",
@@ -1007,7 +1151,10 @@
                             "status": {
                                 "$ref": "#/components/schemas/BLOCK_STATUS"
                             }
-                        }
+                        },
+                        "required": [
+                            "status"
+                        ]
                     },
                     {
                         "$ref": "#/components/schemas/BLOCK_HEADER"
@@ -1054,7 +1201,7 @@
                                 "minimum": 0
                             },
                             "sequencer_address": {
-                                "description": "The Starknet identity of the sequencer submitting this block",
+                                "description": "The StarkNet identity of the sequencer submitting this block",
                                 "$ref": "#/components/schemas/FELT"
                             },
                             "parent_hash": {
@@ -1080,7 +1227,7 @@
                                 "minimum": 0
                             },
                             "sequencer_address": {
-                                "description": "The Starknet identity of the sequencer submitting this block",
+                                "description": "The StarkNet identity of the sequencer submitting this block",
                                 "$ref": "#/components/schemas/FELT"
                             },
                             "parent_hash": {
@@ -1102,7 +1249,11 @@
                         "description": "The hash of the contract code",
                         "$ref": "#/components/schemas/FELT"
                     }
-                }
+                },
+                "required": [
+                    "address",
+                    "class_hash"
+                ]
             },
             "CONTRACT_STORAGE_DIFF_ITEM": {
                 "type": "object",
@@ -1128,7 +1279,11 @@
                             }
                         }
                     }
-                }
+                },
+                "required": [
+                    "address",
+                    "storage_entries"
+                ]
             },
             "TXN": {
                 "title": "Transaction",
@@ -1147,7 +1302,7 @@
                         "$ref": "#/components/schemas/DEPLOY_TXN"
                     },
                     {
-                        "ref": "#/components/schemas/DEPLOY_ACCOUNT_TXN"
+                        "$ref": "#/components/schemas/DEPLOY_ACCOUNT_TXN"
                     }
                 ]
             },
@@ -1161,9 +1316,6 @@
                     {
                         "$ref": "#/components/schemas/BROADCASTED_DECLARE_TXN"
                     },
-                    {
-                        "$ref": "#/components/schemas/BROADCASTED_DEPLOY_TXN"
-                    },
                     {
                         "$ref": "#/components/schemas/BROADCASTED_DEPLOY_ACCOUNT_TXN"
                     }
@@ -1180,9 +1332,6 @@
                 "type": "object",
                 "description": "common properties of a transaction that is sent to the sequencer (but is not yet in a block)",
                 "properties": {
-                    "type": {
-                        "$ref": "#/components/schemas/TXN_TYPE"
-                    },
                     "max_fee": {
                         "$ref": "#/components/schemas/FELT",
                         "description": "The maximal fee that can be charged for including the transaction"
@@ -1197,7 +1346,13 @@
                     "nonce": {
                         "$ref": "#/components/schemas/FELT"
                     }
-                }
+                },
+                "required": [
+                    "max_fee",
+                    "version",
+                    "signature",
+                    "nonce"
+                ]
             },
             "COMMON_TXN_PROPERTIES": {
                 "allOf": [
@@ -1208,7 +1363,10 @@
                                 "$ref": "#/components/schemas/TXN_HASH",
                                 "description": "The hash identifying the transaction"
                             }
-                        }
+                        },
+                        "required": [
+                            "transaction_hash"
+                        ]
                     },
                     {
                         "$ref": "#/components/schemas/BROADCASTED_TXN_COMMON_PROPERTIES"
@@ -1216,6 +1374,16 @@
                 ]
             },
             "DECLARE_TXN": {
+                "anyOf": [
+                    {
+                        "$ref": "#/components/schemas/DECLARE_TXN_V1"
+                    },
+                    {
+                        "$ref": "#/components/schemas/DECLARE_TXN_V2"
+                    }
+                ]
+            },
+            "DECLARE_TXN_V1": {
                 "title": "Declare Contract Transaction",
                 "allOf": [
                     {
@@ -1224,6 +1392,12 @@
                     {
                         "type": "object",
                         "properties": {
+                            "type": {
+                                "type": "string",
+                                "enum": [
+                                    "DECLARE"
+                                ]
+                            },
                             "class_hash": {
                                 "description": "The hash of the declared class",
                                 "$ref": "#/components/schemas/FELT"
@@ -1232,11 +1406,43 @@
                                 "description": "The address of the account contract sending the declaration transaction",
                                 "$ref": "#/components/schemas/ADDRESS"
                             }
+                        },
+                        "required": [
+                            "type",
+                            "class_hash",
+                            "sender_address"
+                        ]
+                    }
+                ]
+            },
+            "DECLARE_TXN_V2": {
+                "title": "Declare Contract Transaction",
+                "allOf": [
+                    {
+                        "$ref": "#/components/schemas/DECLARE_TXN_V1"
+                    },
+                    {
+                        "type": "object",
+                        "properties": {
+                            "compiled_class_hash": {
+                                "description": "The hash of the Cairo assembly resulting from the Sierra compilation",
+                                "$ref": "#/components/schemas/FELT"
+                            }
                         }
                     }
                 ]
             },
             "BROADCASTED_DECLARE_TXN": {
+                "anyOf": [
+                    {
+                        "$ref": "#/components/schemas/BROADCASTED_DECLARE_TXN_V1"
+                    },
+                    {
+                        "$ref": "#/components/schemas/BROADCASTED_DECLARE_TXN_V2"
+                    }
+                ]
+            },
+            "BROADCASTED_DECLARE_TXN_V1": {
                 "title": "mempool representation of a declare transaction",
                 "allOf": [
                     {
@@ -1247,9 +1453,7 @@
                         "properties": {
                             "contract_class": {
                                 "description": "The class to be declared",
-                                "schema": {
-                                    "$ref": "#/components/schemas/CONTRACT_CLASS"
-                                }
+                                "$ref": "#/components/schemas/DEPRECATED_CONTRACT_CLASS"
                             },
                             "sender_address": {
                                 "description": "The address of the account contract sending the declaration transaction",
@@ -1259,6 +1463,42 @@
                     }
                 ]
             },
+            "BROADCASTED_DECLARE_TXN_V2": {
+                "title": "mempool representation of a declare transaction",
+                "allOf": [
+                    {
+                        "$ref": "#/components/schemas/BROADCASTED_TXN_COMMON_PROPERTIES"
+                    },
+                    {
+                        "type": "object",
+                        "properties": {
+                            "type": {
+                                "type": "string",
+                                "enum": [
+                                    "DECLARE"
+                                ]
+                            },
+                            "contract_class": {
+                                "description": "The class to be declared",
+                                "$ref": "#/components/schemas/CONTRACT_CLASS"
+                            },
+                            "sender_address": {
+                                "description": "The address of the account contract sending the declaration transaction",
+                                "$ref": "#/components/schemas/ADDRESS"
+                            },
+                            "compiled_class_hash": {
+                                "description": "The hash of the Cairo assembly resulting from the Sierra compilation",
+                                "$ref": "#/components/schemas/FELT"
+                            }
+                        },
+                        "required": [
+                            "type",
+                            "contract_class",
+                            "sender_address"
+                        ]
+                    }
+                ]
+            },
             "DEPLOY_ACCOUNT_TXN": {
                 "title": "Deploy Account Transaction",
                 "description": "Deploys an account contract, charges fee from the pre-funded account addresses",
@@ -1285,6 +1525,12 @@
             "DEPLOY_ACCOUNT_TXN_PROPERTIES": {
                 "type": "object",
                 "properties": {
+                    "type": {
+                        "type": "string",
+                        "enum": [
+                            "DEPLOY_ACCOUNT"
+                        ]
+                    },
                     "contract_address_salt": {
                         "description": "The salt for the address of the deployed contract",
                         "$ref": "#/components/schemas/FELT"
@@ -1300,7 +1546,13 @@
                         "description": "The hash of the deployed contract's class",
                         "$ref": "#/components/schemas/FELT"
                     }
-                }
+                },
+                "required": [
+                    "type",
+                    "contract_address_salt",
+                    "constructor_calldata",
+                    "class_hash"
+                ]
             },
             "DEPLOY_TXN": {
                 "title": "Deploy Contract Transaction",
@@ -1317,27 +1569,11 @@
                                 "description": "The hash of the deployed contract's class",
                                 "$ref": "#/components/schemas/FELT"
                             }
-                        }
-                    },
-                    {
-                        "$ref": "#/components/schemas/DEPLOY_TXN_PROPERTIES"
-                    }
-                ]
-            },
-            "BROADCASTED_DEPLOY_TXN": {
-                "title": "mempool representation of a deploy transaction",
-                "description": "The structure of a deploy transaction. Note that this transaction type is deprecated and will no longer be supported in future versions",
-                "allOf": [
-                    {
-                        "type": "object",
-                        "properties": {
-                            "contract_class": {
-                                "description": "The class of the contract that will be deployed",
-                                "schema": {
-                                    "$ref": "#/components/schemas/CONTRACT_CLASS"
-                                }
-                            }
-                        }
+                        },
+                        "required": [
+                            "transaction_hash",
+                            "class_hash"
+                        ]
                     },
                     {
                         "$ref": "#/components/schemas/DEPLOY_TXN_PROPERTIES"
@@ -1352,7 +1588,10 @@
                         "$ref": "#/components/schemas/NUM_AS_HEX"
                     },
                     "type": {
-                        "$ref": "#/components/schemas/TXN_TYPE"
+                        "type": "string",
+                        "enum": [
+                            "DEPLOY"
+                        ]
                     },
                     "contract_address_salt": {
                         "description": "The salt for the address of the deployed contract",
@@ -1365,7 +1604,13 @@
                             "$ref": "#/components/schemas/FELT"
                         }
                     }
-                }
+                },
+                "required": [
+                    "version",
+                    "type",
+                    "contract_address_salt",
+                    "constructor_calldata"
+                ]
             },
             "INVOKE_TXN_V0": {
                 "title": "version 0 invoke transaction",
@@ -1387,7 +1632,11 @@
                             "$ref": "#/components/schemas/FELT"
                         }
                     }
-                }
+                },
+                "required": [
+                    "sender_address",
+                    "calldata"
+                ]
             },
             "INVOKE_TXN": {
                 "title": "Initiate a transaction from an account",
@@ -1396,7 +1645,21 @@
                         "$ref": "#/components/schemas/COMMON_TXN_PROPERTIES"
                     },
                     {
-                        "oneOf": [
+                        "type": "object",
+                        "properties": {
+                            "type": {
+                                "type": "string",
+                                "enum": [
+                                    "INVOKE"
+                                ]
+                            }
+                        },
+                        "required": [
+                            "type"
+                        ]
+                    },
+                    {
+                        "anyOf": [
                             {
                                 "$ref": "#/components/schemas/INVOKE_TXN_V0"
                             },
@@ -1414,7 +1677,21 @@
                         "$ref": "#/components/schemas/BROADCASTED_TXN_COMMON_PROPERTIES"
                     },
                     {
-                        "oneOf": [
+                        "type": "object",
+                        "properties": {
+                            "type": {
+                                "type": "string",
+                                "enum": [
+                                    "INVOKE"
+                                ]
+                            }
+                        },
+                        "required": [
+                            "type"
+                        ]
+                    },
+                    {
+                        "anyOf": [
                             {
                                 "$ref": "#/components/schemas/INVOKE_TXN_V0"
                             },
@@ -1450,7 +1727,13 @@
                                 "description": "The L1->L2 message nonce field of the SN Core L1 contract at the time the transaction was sent",
                                 "$ref": "#/components/schemas/NUM_AS_HEX"
                             }
-                        }
+                        },
+                        "required": [
+                            "transaction_hash",
+                            "version",
+                            "type",
+                            "nonce"
+                        ]
                     },
                     {
                         "$ref": "#/components/schemas/FUNCTION_CALL"
@@ -1478,9 +1761,6 @@
                     "block_number": {
                         "$ref": "#/components/schemas/BLOCK_NUMBER"
                     },
-                    "type": {
-                        "$ref": "#/components/schemas/TXN_TYPE"
-                    },
                     "messages_sent": {
                         "type": "array",
                         "items": {
@@ -1501,22 +1781,80 @@
                     "status",
                     "block_hash",
                     "block_number",
-                    "type",
                     "messages_sent",
                     "events"
                 ]
             },
             "INVOKE_TXN_RECEIPT": {
                 "title": "Invoke Transaction Receipt",
-                "$ref": "#/components/schemas/COMMON_RECEIPT_PROPERTIES"
+                "allOf": [
+                    {
+                        "type": "object",
+                        "properties": {
+                            "type": {
+                                "type": "string",
+                                "enum": [
+                                    "INVOKE"
+                                ]
+                            }
+                        },
+                        "required": [
+                            "type"
+                        ]
+                    },
+                    {
+                        "$ref": "#/components/schemas/COMMON_RECEIPT_PROPERTIES"
+                    }
+                ]
             },
             "DECLARE_TXN_RECEIPT": {
                 "title": "Declare Transaction Receipt",
-                "$ref": "#/components/schemas/COMMON_RECEIPT_PROPERTIES"
+                "allOf": [
+                    {
+                        "type": "object",
+                        "properties": {
+                            "type": {
+                                "type": "string",
+                                "enum": [
+                                    "DECLARE"
+                                ]
+                            }
+                        },
+                        "required": [
+                            "type"
+                        ]
+                    },
+                    {
+                        "$ref": "#/components/schemas/COMMON_RECEIPT_PROPERTIES"
+                    }
+                ]
             },
             "DEPLOY_ACCOUNT_TXN_RECEIPT": {
                 "title": "Deploy Account Transaction Receipt",
-                "$ref": "#/components/schemas/DEPLOY_TXN_RECEIPT"
+                "allOf": [
+                    {
+                        "$ref": "#/components/schemas/COMMON_RECEIPT_PROPERTIES"
+                    },
+                    {
+                        "type": "object",
+                        "properties": {
+                            "type": {
+                                "type": "string",
+                                "enum": [
+                                    "DEPLOY_ACCOUNT"
+                                ]
+                            },
+                            "contract_address": {
+                                "description": "The address of the deployed contract",
+                                "$ref": "#/components/schemas/FELT"
+                            }
+                        },
+                        "required": [
+                            "type",
+                            "contract_address"
+                        ]
+                    }
+                ]
             },
             "DEPLOY_TXN_RECEIPT": {
                 "title": "Deploy Transaction Receipt",
@@ -1527,17 +1865,45 @@
                     {
                         "type": "object",
                         "properties": {
+                            "type": {
+                                "type": "string",
+                                "enum": [
+                                    "DEPLOY"
+                                ]
+                            },
                             "contract_address": {
                                 "description": "The address of the deployed contract",
                                 "$ref": "#/components/schemas/FELT"
                             }
-                        }
+                        },
+                        "required": [
+                            "type",
+                            "contract_address"
+                        ]
                     }
                 ]
             },
             "L1_HANDLER_TXN_RECEIPT": {
                 "title": "receipt for l1 handler transaction",
-                "$ref": "#/components/schemas/COMMON_RECEIPT_PROPERTIES"
+                "allOf": [
+                    {
+                        "type": "object",
+                        "properties": {
+                            "type": {
+                                "type": "string",
+                                "enum": [
+                                    "L1_HANDLER"
+                                ]
+                            }
+                        },
+                        "required": [
+                            "type"
+                        ]
+                    },
+                    {
+                        "$ref": "#/components/schemas/COMMON_RECEIPT_PROPERTIES"
+                    }
+                ]
             },
             "TXN_RECEIPT": {
                 "anyOf": [
@@ -1639,7 +2005,11 @@
                             "$ref": "#/components/schemas/FELT"
                         }
                     }
-                }
+                },
+                "required": [
+                    "to_address",
+                    "payload"
+                ]
             },
             "TXN_STATUS": {
                 "type": "string",
@@ -1689,10 +2059,63 @@
                             "$ref": "#/components/schemas/FELT"
                         }
                     }
-                }
+                },
+                "required": [
+                    "contract_address",
+                    "entry_point_selector",
+                    "calldata"
+                ]
             },
             "CONTRACT_CLASS": {
-                "title": "The definition of a Starknet contract class",
+                "type": "object",
+                "properties": {
+                    "sierra_program": {
+                        "type": "array",
+                        "description": "The list of Sierra instructions of which the program consists",
+                        "items": {
+                            "$ref": "#/components/schemas/FELT"
+                        }
+                    },
+                    "contract_class_version": {
+                        "type": "string",
+                        "description": "The version of the contract class object. Currently, the Starknet OS supports version 0.1.0"
+                    },
+                    "entry_points_by_type": {
+                        "type": "object",
+                        "properties": {
+                            "CONSTRUCTOR": {
+                                "type": "array",
+                                "items": {
+                                    "$ref": "#/components/schemas/SIERRA_ENTRY_POINT"
+                                }
+                            },
+                            "EXTERNAL": {
+                                "type": "array",
+                                "items": {
+                                    "$ref": "#/components/schemas/SIERRA_ENTRY_POINT"
+                                }
+                            },
+                            "L1_HANDLER": {
+                                "type": "array",
+                                "items": {
+                                    "$ref": "#/components/schemas/SIERRA_ENTRY_POINT"
+                                }
+                            }
+                        }
+                    },
+                    "abi": {
+                        "type": "string",
+                        "descripition": "The class ABI, as supplied by the user declaring the class"
+                    }
+                },
+                "required": [
+                    "sierra_program",
+                    "contract_class_version",
+                    "entry_points_by_type"
+                ]
+            },
+            "DEPRECATED_CONTRACT_CLASS": {
+                "title": "The definition of a StarkNet contract class",
                 "type": "object",
                 "properties": {
                     "program": {
@@ -1704,26 +2127,27 @@
                         "type": "object",
                         "properties": {
                             "CONSTRUCTOR": {
-                                "schema": {
-                                    "$ref": "#/components/schemas/CONTRACT_ENTRY_POINT_LIST"
+                                "type": "array",
+                                "items": {
+                                    "$ref": "#/components/schemas/DEPRECATED_CAIRO_ENTRY_POINT"
                                 }
                             },
                             "EXTERNAL": {
-                                "schema": {
-                                    "$ref": "#/components/schemas/CONTRACT_ENTRY_POINT_LIST"
+                                "type": "array",
+                                "items": {
+                                    "$ref": "#/components/schemas/DEPRECATED_CAIRO_ENTRY_POINT"
                                 }
                             },
                             "L1_HANDLER": {
-                                "schema": {
-                                    "$ref": "#/components/schemas/CONTRACT_ENTRY_POINT_LIST"
+                                "type": "array",
+                                "items": {
+                                    "$ref": "#/components/schemas/DEPRECATED_CAIRO_ENTRY_POINT"
                                 }
                             }
                         }
                     },
                     "abi": {
-                        "schema": {
-                            "$ref": "#/components/schemas/CONTRACT_ABI"
-                        }
+                        "$ref": "#/components/schemas/CONTRACT_ABI"
                     }
                 },
                 "required": [
@@ -1731,26 +2155,29 @@
                     "entry_points_by_type"
                 ]
             },
-            "CONTRACT_ENTRY_POINT_LIST": {
-                "type": "array",
-                "items": {
-                    "$ref": "#/components/schemas/CONTRACT_ENTRY_POINT"
-                }
-            },
-            "CONTRACT_ENTRY_POINT": {
+            "DEPRECATED_CAIRO_ENTRY_POINT": {
                 "type": "object",
                 "properties": {
                     "offset": {
                         "description": "The offset of the entry point in the program",
-                        "schema": {
-                            "$ref": "#/components/schemas/NUM_AS_HEX"
-                        }
+                        "$ref": "#/components/schemas/NUM_AS_HEX"
                     },
                     "selector": {
                         "description": "A unique identifier of the entry point (function) in the program",
-                        "schema": {
-                            "$ref": "#/components/schemas/FELT"
-                        }
+                        "$ref": "#/components/schemas/FELT"
+                    }
+                }
+            },
+            "SIERRA_ENTRY_POINT": {
+                "type": "object",
+                "properties": {
+                    "selector": {
+                        "description": "A unique identifier of the entry point (function) in the program",
+                        "$ref": "#/components/schemas/FELT"
+                    },
+                    "function_idx": {
+                        "description": "The index of the function in the program",
+                        "type": "integer"
                     }
                 }
             },
@@ -1761,8 +2188,7 @@
                 }
             },
             "CONTRACT_ABI_ENTRY": {
-                "type": "object",
-                "oneOf": [
+                "anyOf": [
                     {
                         "$ref": "#/components/schemas/FUNCTION_ABI_ENTRY"
                     },
@@ -1795,11 +2221,10 @@
                 ]
             },
             "STRUCT_ABI_ENTRY": {
+                "type": "object",
                 "properties": {
                     "type": {
-                        "schema": {
-                            "$ref": "#/components/schemas/STRUCT_ABI_TYPE"
-                        }
+                        "$ref": "#/components/schemas/STRUCT_ABI_TYPE"
                     },
                     "name": {
                         "description": "The struct name",
@@ -1818,7 +2243,6 @@
                 }
             },
             "STRUCT_MEMBER": {
-                "type": "object",
                 "allOf": [
                     {
                         "$ref": "#/components/schemas/TYPED_PARAMETER"
@@ -1838,9 +2262,7 @@
                 "type": "object",
                 "properties": {
                     "type": {
-                        "schema": {
-                            "$ref": "#/components/schemas/EVENT_ABI_TYPE"
-                        }
+                        "$ref": "#/components/schemas/EVENT_ABI_TYPE"
                     },
                     "name": {
                         "description": "The event name",
@@ -1864,9 +2286,7 @@
                 "type": "object",
                 "properties": {
                     "type": {
-                        "schema": {
-                            "$ref": "#/components/schemas/FUNCTION_ABI_TYPE"
-                        }
+                        "$ref": "#/components/schemas/FUNCTION_ABI_TYPE"
                     },
                     "name": {
                         "description": "The function name",
@@ -1904,21 +2324,15 @@
                 "properties": {
                     "gas_consumed": {
                         "description": "The Ethereum gas cost of the transaction (see https://docs.starknet.io/docs/Fees/fee-mechanism for more info)",
-                        "schema": {
-                            "$ref": "#/components/schemas/NUM_AS_HEX"
-                        }
+                        "$ref": "#/components/schemas/NUM_AS_HEX"
                     },
                     "gas_price": {
                         "description": "The gas price (in gwei) that was used in the cost estimation",
-                        "schema": {
-                            "$ref": "#/components/schemas/NUM_AS_HEX"
-                        }
+                        "$ref": "#/components/schemas/NUM_AS_HEX"
                     },
                     "overall_fee": {
                         "description": "The estimated fee for the transaction (in gwei), product of gas_consumed and gas_price",
-                        "schema": {
-                            "$ref": "#/components/schemas/NUM_AS_HEX"
-                        }
+                        "$ref": "#/components/schemas/NUM_AS_HEX"
                     }
                 }
             }
@@ -1968,6 +2382,10 @@
                 "code": 33,
                 "message": "The supplied continuation token is invalid or unknown"
             },
+            "TOO_MANY_KEYS_IN_FILTER": {
+                "code": 34,
+                "message": "Too many keys provided in a filter"
+            },
             "CONTRACT_ERROR": {
                 "code": 40,
                 "message": "Contract error"
diff --git a/starknet_devnet/blueprints/rpc/rpc_spec_write.py b/starknet_devnet/blueprints/rpc/rpc_spec_write.py
index be77b23b4..4f33ab554 100644
--- a/starknet_devnet/blueprints/rpc/rpc_spec_write.py
+++ b/starknet_devnet/blueprints/rpc/rpc_spec_write.py
@@ -4,7 +4,7 @@
     "openrpc": "1.0.0-rc1",
     "info": {
         "version": "0.4.0",
-        "title": "Starknet Node Write API",
+        "title": "StarkNet Node Write API",
         "license": {}
     },
     "servers": [],
@@ -33,8 +33,7 @@
                             "$ref": "#/components/schemas/TXN_HASH"
                         }
                     }
-                },
-                "required": ["transaction_hash"]
+                }
             },
             "errors": []
         },
@@ -44,6 +43,7 @@
             "params": [
                 {
                     "name": "declare_transaction",
+                    "required": true,
                     "schema": {
                         "$ref": "#/components/schemas/BROADCASTED_DECLARE_TXN"
                     }
@@ -64,43 +64,6 @@
                             "$ref": "#/components/schemas/FELT"
                         }
                     }
-                },
-                "required": ["transaction_hash", "class_hash"]
-            },
-            "errors": [
-                {
-                    "$ref": "#/components/errors/INVALID_CONTRACT_CLASS"
-                }
-            ]
-        },
-        {
-            "name": "starknet_addDeployTransaction",
-            "summary": "Submit a new deploy contract transaction",
-            "params": [
-                {
-                    "name": "deploy_transaction",
-                    "description": "The deploy transaction",
-                    "schema": {
-                        "$ref": "#/components/schemas/BROADCASTED_DEPLOY_TXN"
-                    }
-                }
-            ],
-            "result": {
-                "name": "result",
-                "description": "The result of the transaction submission",
-                "schema": {
-                    "type": "object",
-                    "properties": {
-                        "transaction_hash": {
-                            "title": "The hash of the deploy transaction",
-                            "$ref": "#/components/schemas/TXN_HASH"
-                        },
-                        "contract_address": {
-                            "title": "The address of the new contract",
-                            "$ref": "#/components/schemas/FELT"
-                        }
-                    },
-                    "required": ["transaction_hash", "contract_address"]
                 }
             },
             "errors": [
@@ -116,6 +79,7 @@
                 {
                     "name": "deploy_account_transaction",
                     "description": "The deploy account transaction",
+                    "required": true,
                     "schema": {
                         "$ref": "#/components/schemas/BROADCASTED_DEPLOY_ACCOUNT_TXN"
                     }
@@ -135,8 +99,7 @@
                             "title": "The address of the new contract",
                             "$ref": "#/components/schemas/FELT"
                         }
-                    },
-                    "required": ["transaction_hash", "contract_address"]
+                    }
                 }
             },
             "errors": [
@@ -172,9 +135,6 @@
             "BROADCASTED_DECLARE_TXN": {
                 "$ref": "./api/starknet_api_openrpc.json#/components/schemas/BROADCASTED_DECLARE_TXN"
             },
-            "BROADCASTED_DEPLOY_TXN": {
-                "$ref": "./api/starknet_api_openrpc.json#/components/schemas/BROADCASTED_DEPLOY_TXN"
-            },
             "BROADCASTED_DEPLOY_ACCOUNT_TXN": {
                 "$ref": "./api/starknet_api_openrpc.json#/components/schemas/BROADCASTED_DEPLOY_ACCOUNT_TXN"
             },
diff --git a/starknet_devnet/blueprints/rpc/schema.py b/starknet_devnet/blueprints/rpc/schema.py
index 93bf1f79b..1893a1c35 100644
--- a/starknet_devnet/blueprints/rpc/schema.py
+++ b/starknet_devnet/blueprints/rpc/schema.py
@@ -26,15 +26,6 @@ def _load_schemas() -> Tuple[Dict[str, Any], Dict[str, Any]]:
 
     methods = {**_extract_methods(specs_json), **_extract_methods(write_specs_json)}
 
-    for schema in schemas.values():
-        # Newer version of the RPC (above 0.45.0) has properly defined `required` fields.
-        # Once we start targeting them, this can be removed.
-        #
-        # NOTE: This does not add `required` to all schemas that should have it, i.e. it fails to add `required`
-        # to nested objects. This causes validation to be incomplete in these cases.
-        if "required" not in schema and "properties" in schema:
-            schema["required"] = list(schema["properties"].keys())
-
     return methods, schemas
 
 
@@ -199,6 +190,16 @@ def __str__(self):
         return f"""Devnet tried to return invalid value: \"{self.validation_error.message}\""""
 
 
+@lru_cache
+def felt_pattern_from_schema() -> str:
+    """
+    Load regex pattern of felt from rpc schema.
+    """
+    _, schemas = _load_schemas()
+
+    return schemas["FELT"]["pattern"]
+
+
 def validate_schema(method_name: str):
     """
     Decorator ensuring that call to rpc method and its response are valid
diff --git a/starknet_devnet/blueprints/rpc/structures/payloads.py b/starknet_devnet/blueprints/rpc/structures/payloads.py
index cd411b5fd..9b440d3e0 100644
--- a/starknet_devnet/blueprints/rpc/structures/payloads.py
+++ b/starknet_devnet/blueprints/rpc/structures/payloads.py
@@ -4,13 +4,20 @@
 
 from __future__ import annotations
 
-from typing import Callable, List, Optional, Union
+from test.shared import (
+    DEPRECATED_RPC_DECLARE_TX_VERSION,
+    SUPPORTED_RPC_DECLARE_TX_VERSION,
+)
+from typing import Callable, Dict, List, Optional, Union
 
 from marshmallow.exceptions import MarshmallowError
 from starkware.starknet.definitions.general_config import StarknetGeneralConfig
 from starkware.starknet.public.abi import AbiEntryType
 from starkware.starknet.services.api.contract_class.contract_class import (
+    ContractClass,
+    ContractEntryPoint,
     DeprecatedCompiledClass,
+    EntryPointType,
 )
 from starkware.starknet.services.api.feeder_gateway.request_objects import CallFunction
 from starkware.starknet.services.api.feeder_gateway.response_objects import (
@@ -26,6 +33,7 @@
     TransactionType,
 )
 from starkware.starknet.services.api.gateway.transaction import (
+    Declare,
     DeployAccount,
     DeprecatedDeclare,
     InvokeFunction,
@@ -139,21 +147,22 @@ class RpcBroadcastedInvokeTxnV1(RpcBroadcastedTxnCommon):
 RpcBroadcastedInvokeTxn = Union[RpcBroadcastedInvokeTxnV0, RpcBroadcastedInvokeTxnV1]
 
 
-class RpcBroadcastedDeclareTxn(RpcBroadcastedTxnCommon):
-    """TypedDict for RpcBroadcastedDeclareTxn"""
+class RpcBroadcastedDeclareTxnV1(RpcBroadcastedTxnCommon):
+    """TypedDict for RpcBroadcastDeclareTxnV1"""
 
-    contract_class: RpcContractClass
+    contract_class: RpcDeprecatedContractClass
     sender_address: Address
 
 
-class RpcBroadcastedDeployTxn(TypedDict):
-    """TypedDict for RpcBroadcastedDeployTxn"""
+class RpcBroadcastedDeclareTxnV2(RpcBroadcastedTxnCommon):
+    """TypedDict for RpcBroadcastedDeclareTxnV2"""
 
     contract_class: RpcContractClass
-    version: NumAsHex
-    type: RpcTxnType
-    contract_address_salt: Felt
-    constructor_calldata: List[Felt]
+    sender_address: Address
+    compiled_class_hash: Felt
+
+
+RpcBroadcastedDeclareTxn = Union[RpcBroadcastedDeclareTxnV1, RpcBroadcastedDeclareTxnV2]
 
 
 class RpcBroadcastedDeployAccountTxn(RpcBroadcastedTxnCommon):
@@ -166,7 +175,6 @@ class RpcBroadcastedDeployAccountTxn(RpcBroadcastedTxnCommon):
 
 # rpc transaction's representation when it's sent to the sequencer (but not yet in a block)
 RpcBroadcastedTxn = Union[
-    RpcBroadcastedDeployTxn,
     RpcBroadcastedDeclareTxn,
     RpcBroadcastedInvokeTxn,
     RpcBroadcastedDeployAccountTxn,
@@ -385,15 +393,20 @@ class RpcFeeEstimate(TypedDict):
     overall_fee: NumAsHex
 
 
-def rpc_fee_estimate(fee_estimate: FeeEstimationInfo) -> dict:
+def rpc_fee_estimate(fee_estimates: List[FeeEstimationInfo]) -> list:
     """
     Convert gateway estimate_fee response to rpc_fee_estimate
     """
-    result: RpcFeeEstimate = {
-        "gas_consumed": hex(fee_estimate.gas_usage),
-        "gas_price": hex(fee_estimate.gas_price),
-        "overall_fee": hex(fee_estimate.overall_fee),
-    }
+
+    result = [
+        {
+            "gas_consumed": hex(fee_estimate.gas_usage),
+            "gas_price": hex(fee_estimate.gas_price),
+            "overall_fee": hex(fee_estimate.overall_fee),
+        }
+        for fee_estimate in fee_estimates
+    ]
+
     return result
 
 
@@ -430,9 +443,11 @@ def make_invoke_function(invoke_transaction: RpcBroadcastedInvokeTxn) -> InvokeF
     return invoke_function
 
 
-def make_declare(declare_transaction: RpcBroadcastedDeclareTxn) -> DeprecatedDeclare:
+def make_declare_v1(
+    declare_transaction: RpcBroadcastedDeclareTxnV1,
+) -> DeprecatedDeclare:
     """
-    Convert RpcBroadcastedDeclareTxn to DeprecatedDeclare
+    Convert RpcBroadcastedDeclareTxnV1 to DeprecatedDeclare
     """
     contract_class = declare_transaction["contract_class"]
     if "abi" not in contract_class:
@@ -456,6 +471,43 @@ def make_declare(declare_transaction: RpcBroadcastedDeclareTxn) -> DeprecatedDec
     return declare_tx
 
 
+def make_declare_v2(declare_transaction: RpcBroadcastedDeclareTxnV2) -> Declare:
+    """Convert RpcBroadcastedDeclareTxnV2 to Declare"""
+    nonce = declare_transaction.get("nonce")
+
+    contract_class = declare_transaction["contract_class"]
+
+    if "abi" not in contract_class:
+        contract_class["abi"] = ""
+
+    contract_class = ContractClass.load(contract_class)
+
+    return Declare(
+        contract_class=contract_class,
+        compiled_class_hash=int(declare_transaction["compiled_class_hash"], 16),
+        sender_address=int(declare_transaction["sender_address"], 16),
+        nonce=int(nonce, 16) if nonce is not None else 0,
+        version=int(declare_transaction["version"], 16),
+        max_fee=int(declare_transaction["max_fee"], 16),
+        signature=[int(sig, 16) for sig in declare_transaction["signature"]],
+    )
+
+
+def make_declare(
+    declare_transaction: RpcBroadcastedDeclareTxn,
+) -> Union[Declare, DeprecatedDeclare]:
+    """Convert RpcBroadcastedDeclareTxn to Declare or DeprecatedDeclare"""
+    if int(declare_transaction["version"], 0) == SUPPORTED_RPC_DECLARE_TX_VERSION:
+        return make_declare_v2(declare_transaction)
+    if int(declare_transaction["version"], 0) == DEPRECATED_RPC_DECLARE_TX_VERSION:
+        return make_declare_v1(declare_transaction)
+
+    raise RpcError(
+        code=-1,
+        message=f"Declare transaction version {declare_transaction['version']} is not supported by devnet",
+    )
+
+
 def make_deploy_account(
     deploy_account_transaction: RpcBroadcastedDeployAccountTxn,
 ) -> DeployAccount:
@@ -478,19 +530,34 @@ def make_deploy_account(
     return deploy_account_tx
 
 
-class EntryPoint(TypedDict):
-    """TypedDict for rpc contract class entry point"""
+class DeprecatedEntryPoint(TypedDict):
+    """TypedDict for deprecated rpc contract class entry point"""
 
     offset: NumAsHex
     selector: Felt
 
 
+class DeprecatedEntryPoints(TypedDict):
+    """TypedDict for deprecated rpc contract class entry points"""
+
+    CONSTRUCTOR: List[DeprecatedEntryPoint]
+    EXTERNAL: List[DeprecatedEntryPoint]
+    L1_HANDLER: List[DeprecatedEntryPoint]
+
+
+class SierraEntryPoint(TypedDict):
+    """TypedDict for sierra entry point"""
+
+    selector: Felt
+    function_idx: int
+
+
 class EntryPoints(TypedDict):
     """TypedDict for rpc contract class entry points"""
 
-    CONSTRUCTOR: List[EntryPoint]
-    EXTERNAL: List[EntryPoint]
-    L1_HANDLER: List[EntryPoint]
+    CONSTRUCTOR: List[SierraEntryPoint]
+    EXTERNAL: List[SierraEntryPoint]
+    L1_HANDLER: List[SierraEntryPoint]
 
 
 FunctionAbiType = Literal["function", "l1_handler"]
@@ -595,17 +662,30 @@ def rpc_abi_entry(abi_entry: AbiEntryType) -> AbiEntry:
     return function_map[abi_entry["type"]](abi_entry)
 
 
+class RpcDeprecatedContractClass(TypedDict):
+    """
+    TypedDict for deprecated rpc contract class
+    """
+
+    program: str
+    entry_points_by_type: DeprecatedEntryPoints
+    abi: Optional[List[AbiEntry]]
+
+
 class RpcContractClass(TypedDict):
     """
     TypedDict for rpc contract class
     """
 
-    program: str
+    sierra_program: List[Felt]
+    contract_class_version: str
     entry_points_by_type: EntryPoints
-    abi: Optional[List[AbiEntry]]
+    abi: Optional[str]
 
 
-def rpc_contract_class(contract_class: DeprecatedCompiledClass) -> RpcContractClass:
+def rpc_deprecated_contract_class(
+    contract_class: DeprecatedCompiledClass,
+) -> RpcDeprecatedContractClass:
     """
     Convert gateway contract class to rpc contract class
     """
@@ -614,15 +694,15 @@ def program() -> str:
         _program = contract_class.program.Schema().dump(contract_class.program)
         return compress_program(_program)
 
-    def entry_points_by_type() -> EntryPoints:
-        _entry_points: EntryPoints = {
+    def entry_points_by_type() -> DeprecatedEntryPoints:
+        _entry_points: DeprecatedEntryPoints = {
             "CONSTRUCTOR": [],
             "EXTERNAL": [],
             "L1_HANDLER": [],
         }
         for typ, entry_points in contract_class.entry_points_by_type.items():
             for entry_point in entry_points:
-                _entry_point: EntryPoint = {
+                _entry_point: DeprecatedEntryPoint = {
                     "selector": rpc_felt(entry_point.selector),
                     "offset": hex(entry_point.offset),
                 }
@@ -634,7 +714,7 @@ def abi() -> Optional[List[AbiEntry]]:
             return None
         return [rpc_abi_entry(abi_entry_type) for abi_entry_type in contract_class.abi]
 
-    _contract_class: RpcContractClass = {
+    _contract_class: RpcDeprecatedContractClass = {
         "program": program(),
         "entry_points_by_type": entry_points_by_type(),
         "abi": abi(),
@@ -642,6 +722,61 @@ def abi() -> Optional[List[AbiEntry]]:
     return _contract_class
 
 
+def rpc_contract_class(contract_class: ContractClass) -> RpcContractClass:
+    """
+    Convert gateway contract class v1 to rpc contract class v1
+    """
+
+    def program() -> List[Felt]:
+        return list(map(rpc_felt, contract_class.sierra_program))
+
+    def entry_points_by_type() -> EntryPoints:
+        def map_entry_point(entry_point: ContractEntryPoint) -> SierraEntryPoint:
+            return SierraEntryPoint(
+                selector=rpc_felt(entry_point.selector),
+                function_idx=entry_point.function_idx,
+            )
+
+        def get_entry_points_of_type(
+            entry_point_type: EntryPointType,
+        ) -> List[SierraEntryPoint]:
+            return list(
+                map(
+                    map_entry_point,
+                    contract_class.entry_points_by_type[entry_point_type],
+                )
+            )
+
+        _entry_points: EntryPoints = {
+            "CONSTRUCTOR": get_entry_points_of_type(EntryPointType.CONSTRUCTOR),
+            "EXTERNAL": get_entry_points_of_type(EntryPointType.EXTERNAL),
+            "L1_HANDLER": get_entry_points_of_type(EntryPointType.L1_HANDLER),
+        }
+
+        return _entry_points
+
+    _contract_class: RpcContractClass = {
+        "sierra_program": program(),
+        "entry_points_by_type": entry_points_by_type(),
+        "abi": contract_class.abi,
+        "contract_class_version": contract_class.contract_class_version,
+    }
+
+    return _contract_class
+
+
+def contract_class_from_dict(
+    contract_class_dict: Dict,
+) -> Union[RpcContractClass, RpcDeprecatedContractClass]:
+    """Convert contract class dict to RpcContractClass or RpcDeprecatedContractClass"""
+    if "sierra_program" in contract_class_dict.keys():
+        loaded_class = ContractClass.load(contract_class_dict)
+        return rpc_contract_class(loaded_class)
+
+    loaded_class = DeprecatedCompiledClass.load(contract_class_dict)
+    return rpc_deprecated_contract_class(loaded_class)
+
+
 class RpcStorageEntry(TypedDict):
     """TypedDict for rpc storage entry"""
 
@@ -670,25 +805,48 @@ class RpcNonceDiff(TypedDict):
     nonce: Felt
 
 
+class RpcDeclaredClass(TypedDict):
+    """TypedDict for rpc declared class"""
+
+    class_hash: Felt
+    compiled_class_hash: Felt
+
+
+class RpcReplacedClass(TypedDict):
+    """TypedDict for contract which class was replaced"""
+
+    contract_address: Felt
+    class_hash: Felt
+
+
 class RpcStateDiff(TypedDict):
     """TypedDict for rpc state diff"""
 
     storage_diffs: List[RpcStorageDiff]
-    declared_contract_hashes: List[Felt]
+    deprecated_declared_classes: List[Felt]
+    declared_classes: List[RpcDeclaredClass]
     deployed_contracts: List[RpcDeployedContractDiff]
+    replaced_classes: List[RpcReplacedClass]
     nonces: List[RpcNonceDiff]
 
 
-class RpcStateUpdate(TypedDict):
+class RpcPendingStateUpdate(TypedDict):
+    """TypedDict for pending rpc state update"""
+
+    old_root: Felt
+    state_diff: RpcStateDiff
+
+
+class RpcStateUpdate(RpcPendingStateUpdate):
     """TypedDict for rpc state update"""
 
     block_hash: BlockHash
     new_root: Felt
-    old_root: Felt
-    state_diff: RpcStateDiff
 
 
-def rpc_state_update(state_update: BlockStateUpdate) -> RpcStateUpdate:
+def rpc_state_update(
+    state_update: BlockStateUpdate,
+) -> Union[RpcStateUpdate, RpcPendingStateUpdate]:
     """
     Convert gateway state update to rpc state update
     """
@@ -709,12 +867,18 @@ def storage_diffs() -> List[RpcStorageDiff]:
             _storage_diffs.append(_diff)
         return _storage_diffs
 
-    def declared_contract_hashes() -> List[Felt]:
+    def deprecated_declared_classes() -> List[Felt]:
         return [
             rpc_felt(contract)
             for contract in state_update.state_diff.old_declared_contracts
-        ] + [
-            rpc_felt(class_hash_pair.compiled_class_hash)
+        ]
+
+    def declared_classes() -> List[RpcDeclaredClass]:
+        return [
+            RpcDeclaredClass(
+                class_hash=rpc_felt(class_hash_pair.class_hash),
+                compiled_class_hash=rpc_felt(class_hash_pair.compiled_class_hash),
+            )
             for class_hash_pair in state_update.state_diff.declared_classes
         ]
 
@@ -728,21 +892,41 @@ def deployed_contracts() -> List[RpcDeployedContractDiff]:
             _contracts.append(diff)
         return _contracts
 
+    def replaced_classes() -> List[RpcReplacedClass]:
+        return [
+            RpcReplacedClass(
+                contract_address=rpc_felt(replaced_class.address),
+                class_hash=rpc_felt(replaced_class.class_hash),
+            )
+            for replaced_class in state_update.state_diff.replaced_classes
+        ]
+
     def nonces() -> List[RpcNonceDiff]:
         return [
             RpcNonceDiff(contract_address=rpc_felt(address), nonce=rpc_felt(nonce))
             for address, nonce in state_update.state_diff.nonces.items()
         ]
 
+    state_diff: RpcStateDiff = {
+        "storage_diffs": storage_diffs(),
+        "deprecated_declared_classes": deprecated_declared_classes(),
+        "declared_classes": declared_classes(),
+        "deployed_contracts": deployed_contracts(),
+        "replaced_classes": replaced_classes(),
+        "nonces": nonces(),
+    }
+
+    if state_update.block_hash is None or state_update.block_hash == 0:
+        pending_rpc_state: RpcPendingStateUpdate = {
+            "old_root": rpc_root(state_update.old_root.hex()),
+            "state_diff": state_diff,
+        }
+        return pending_rpc_state
+
     rpc_state: RpcStateUpdate = {
         "block_hash": rpc_felt(state_update.block_hash),
         "new_root": rpc_root(state_update.new_root.hex()),
         "old_root": rpc_root(state_update.old_root.hex()),
-        "state_diff": {
-            "storage_diffs": storage_diffs(),
-            "declared_contract_hashes": declared_contract_hashes(),
-            "deployed_contracts": deployed_contracts(),
-            "nonces": nonces(),
-        },
+        "state_diff": state_diff,
     }
     return rpc_state
diff --git a/starknet_devnet/blueprints/rpc/structures/responses.py b/starknet_devnet/blueprints/rpc/structures/responses.py
index 78bdf27c0..3a08b76bf 100644
--- a/starknet_devnet/blueprints/rpc/structures/responses.py
+++ b/starknet_devnet/blueprints/rpc/structures/responses.py
@@ -36,13 +36,6 @@ class RpcDeclareTransactionResult(TypedDict):
     class_hash: Felt
 
 
-class RpcDeployTransactionResult(TypedDict):
-    """TypedDict for rpc deploy transaction result"""
-
-    transaction_hash: TxnHash
-    contract_address: Felt
-
-
 class RpcDeployAccountTransactionResult(TypedDict):
     """TypedDict for rpc deploy account transaction result"""
 
diff --git a/starknet_devnet/blueprints/rpc/structures/types.py b/starknet_devnet/blueprints/rpc/structures/types.py
index e72e6b1ad..f5667453b 100644
--- a/starknet_devnet/blueprints/rpc/structures/types.py
+++ b/starknet_devnet/blueprints/rpc/structures/types.py
@@ -12,6 +12,7 @@
 from typing_extensions import Literal, TypedDict
 
 from ..rpc_spec import RPC_SPECIFICATION
+from ..rpc_spec_write import RPC_SPECIFICATION_WRITE
 
 Felt = str
 
@@ -110,7 +111,19 @@ class PredefinedRpcErrorCode(Enum):
     INTERNAL_ERROR = -32603
 
 
-RPC_ERRORS = json.loads(RPC_SPECIFICATION)["components"]["errors"]
+def _combine_rpc_errors():
+    """
+    Merge write api errors with main api errors.
+
+    All references from write api will be shadowed by errors from main api.
+    """
+    rpc_errors = json.loads(RPC_SPECIFICATION)["components"]["errors"]
+    rpc_write_errors = json.loads(RPC_SPECIFICATION_WRITE)["components"]["errors"]
+
+    return rpc_write_errors | rpc_errors
+
+
+RPC_ERRORS = _combine_rpc_errors()
 
 GATEWAY_TO_RPC_ERROR = {
     StarknetErrorCode.BLOCK_NOT_FOUND: RPC_ERRORS["BLOCK_NOT_FOUND"],
diff --git a/starknet_devnet/blueprints/rpc/transactions.py b/starknet_devnet/blueprints/rpc/transactions.py
index b114f45d2..bb70b34ac 100644
--- a/starknet_devnet/blueprints/rpc/transactions.py
+++ b/starknet_devnet/blueprints/rpc/transactions.py
@@ -32,10 +32,10 @@
 from starknet_devnet.blueprints.rpc.structures.types import BlockId, RpcError, TxnHash
 from starknet_devnet.blueprints.rpc.utils import (
     assert_block_id_is_valid,
-    gateway_felt,
     get_block_by_block_id,
     rpc_felt,
 )
+from starknet_devnet.constants import LEGACY_TX_VERSION
 from starknet_devnet.state import state
 from starknet_devnet.util import StarknetDevnetException
 
@@ -121,10 +121,11 @@ async def add_declare_transaction(
     """
     Submit a new class declaration transaction
     """
-    declare_transaction = make_declare(declare_transaction)
+    if int(declare_transaction["version"], 0) == LEGACY_TX_VERSION:
+        raise RpcError.from_spec_name("INVALID_CONTRACT_CLASS")
 
     class_hash, transaction_hash = await state.starknet_wrapper.declare(
-        external_tx=declare_transaction
+        external_tx=make_declare(declare_transaction)
     )
     return RpcDeclareTransactionResult(
         transaction_hash=rpc_felt(transaction_hash),
@@ -177,23 +178,21 @@ def make_transaction(txn: RpcBroadcastedTxn) -> AccountTransaction:
 
 
 @validate_schema("estimateFee")
-async def estimate_fee(request: RpcBroadcastedTxn, block_id: BlockId) -> dict:
+async def estimate_fee(request: List[RpcBroadcastedTxn], block_id: BlockId) -> list:
     """
     Estimate the fee for a given Starknet transaction
     """
     await assert_block_id_is_valid(block_id)
-    transaction = make_transaction(request)
+    transactions = list(map(make_transaction, request))
+
     try:
-        _, fee_response = await state.starknet_wrapper.calculate_trace_and_fee(
-            transaction,
+        _, fee_response = await state.starknet_wrapper.calculate_traces_and_fees(
+            transactions,
             skip_validate=False,
             block_id=block_id,
         )
     except StarkException as ex:
-        if "entry_point_selector" in request and (
-            f"Entry point {gateway_felt(request['entry_point_selector'])} not found"
-            in ex.message
-        ):
+        if "Entry point" in ex.message and "not found" in ex.message:
             raise RpcError.from_spec_name("INVALID_MESSAGE_SELECTOR") from ex
         if "While handling calldata" in ex.message:
             raise RpcError.from_spec_name("INVALID_CALL_DATA") from ex
diff --git a/starknet_devnet/blueprints/rpc/utils.py b/starknet_devnet/blueprints/rpc/utils.py
index aaaa2ec50..9db537b6b 100644
--- a/starknet_devnet/blueprints/rpc/utils.py
+++ b/starknet_devnet/blueprints/rpc/utils.py
@@ -75,15 +75,25 @@ async def assert_block_id_is_valid(block_id: BlockId) -> None:
 
 def rpc_felt(value: Union[int, str]) -> Felt:
     """
-    Convert value to 0x0 prefixed felt
+    Convert value to 0x prefixed felt
     The value can be base 10 integer, base 10 string or base 16 string
     """
     if isinstance(value, str):
         value = int(value) if value.isnumeric() else int(value, 16)
 
     if value == 0:
-        return "0x00"
-    return "0x0" + hex(value).lstrip("0x")
+        return "0x0"
+    return hex(value)
+
+
+def rpc_storage_key(value: Union[int, str]) -> Felt:
+    """
+    Convert value to 0x0 prefixed storage key.
+    The value can be base 10 integer, base 10 string or base 16 string
+    """
+    value = rpc_felt(value)
+
+    return "0x0" + value.lstrip("0x")
 
 
 def gateway_felt(value: Union[int, str]) -> str:
@@ -101,7 +111,7 @@ def rpc_root(root: str) -> Felt:
     """
     Convert 0 prefixed root to 0x prefixed root
     """
-    return "0x0" + (root.lstrip("0") or "0")
+    return rpc_felt(root)
 
 
 def rpc_response(message_id: int, content: dict) -> dict:


Test patch:
diff --git a/test/rpc/rpc_utils.py b/test/rpc/rpc_utils.py
index c917acd3f..392412dc4 100644
--- a/test/rpc/rpc_utils.py
+++ b/test/rpc/rpc_utils.py
@@ -17,6 +17,8 @@
 
 import requests
 
+from starknet_devnet.blueprints.rpc.schema import felt_pattern_from_schema
+
 
 class BackgroundDevnetClient:
     """A thin wrapper for requests, to interact with a background devnet instance"""
@@ -115,4 +117,4 @@ def is_felt(value: str) -> bool:
     """
     Check whether value is a Felt
     """
-    return bool(re.match(r"^0x0[a-fA-F0-9]{1,63}$", value))
+    return bool(re.match(felt_pattern_from_schema(), value))
diff --git a/test/rpc/test_data/get_events.py b/test/rpc/test_data/get_events.py
index 6200621c0..9940d628d 100644
--- a/test/rpc/test_data/get_events.py
+++ b/test/rpc/test_data/get_events.py
@@ -26,7 +26,7 @@ def create_get_events_filter(
     from_block: Union[int, str] = 0,
     to_block: Union[int, str] = "latest",
     address: str = rpc_felt(EXPECTED_FEE_TOKEN_ADDRESS),
-    keys: Optional[List[str]] = None,
+    keys: Optional[List[List[str]]] = None,
     chunk_size: int = 10,
     continuation_token: Optional[str] = None
 ) -> dict:
@@ -45,7 +45,8 @@ def create_get_events_filter(
     :return: `filter` param matching the specification.
     """
     if keys is None:
-        keys = [rpc_felt(FEE_CHARGED_EVENT_KEY)]
+        keys = [[FEE_CHARGED_EVENT_KEY]]
+
     filter_body = {
         "from_block": parse_block_delimiter_parameter(from_block),
         "address": address,
@@ -100,8 +101,8 @@ def parse_block_delimiter_parameter(
         create_get_events_filter(
             from_block=INVOKE_1_BLOCK_NUMBER,
             keys=[
-                rpc_felt(FEE_CHARGED_EVENT_KEY),
-                rpc_felt(INCREASE_BALANCE_CALLED_EVENT_KEY),
+                [rpc_felt(FEE_CHARGED_EVENT_KEY)],
+                [rpc_felt(INCREASE_BALANCE_CALLED_EVENT_KEY)],
             ],
         ),
         [
diff --git a/test/rpc/test_rpc_call.py b/test/rpc/test_rpc_call.py
index 1fbea6ef4..fa9b291d2 100644
--- a/test/rpc/test_rpc_call.py
+++ b/test/rpc/test_rpc_call.py
@@ -33,7 +33,7 @@ def test_call(deploy_info, latest_block_id):
     assert "error" not in resp
     result = resp["result"]
 
-    assert result == ["0x045"]
+    assert result == ["0x45"]
 
 
 @pytest.mark.usefixtures("run_devnet_in_background", "deploy_info")
@@ -45,7 +45,7 @@ def test_call_raises_on_incorrect_contract_address():
         "starknet_call",
         params={
             "request": {
-                "contract_address": "0x07b529269b82f3f3ebbb2c463a9e1edaa2c6eea8fa308ff70b30398766a2e20c",
+                "contract_address": "0x7b529269b82f3f3ebbb2c463a9e1edaa2c6eea8fa308ff70b30398766a2e20c",
                 "entry_point_selector": rpc_felt(get_selector_from_name("get_balance")),
                 "calldata": [],
             },
@@ -65,7 +65,7 @@ def test_call_raises_on_both_hash_and_number():
         "starknet_call",
         params={
             "request": {
-                "contract_address": "0x07b529269b82f3f3ebbb2c463a9e1edaa2c6eea8fa308ff70b30398766a2e20c",
+                "contract_address": "0x7b529269b82f3f3ebbb2c463a9e1edaa2c6eea8fa308ff70b30398766a2e20c",
                 "entry_point_selector": rpc_felt(get_selector_from_name("get_balance")),
                 "calldata": [],
             },
@@ -181,7 +181,7 @@ def call_and_assert(block_id: dict):
 
         assert "error" not in resp
         result = resp["result"]
-        assert result == ["0x045"]
+        assert result == ["0x45"]
 
     call_and_assert({"block_number": deployment_block["block_number"]})
     call_and_assert({"block_hash": rpc_felt(deployment_block["block_hash"])})
diff --git a/test/rpc/test_rpc_class.py b/test/rpc/test_rpc_class.py
index 65677f8ef..3f0ea9c26 100644
--- a/test/rpc/test_rpc_class.py
+++ b/test/rpc/test_rpc_class.py
@@ -1,7 +1,18 @@
 """
 Tests RPC contract class
 """
+import json
+from test.account import deploy, send_declare_v2
 from test.rpc.rpc_utils import rpc_call
+from test.shared import (
+    ABI_1_PATH,
+    CONTRACT_1_PATH,
+    PREDEPLOY_ACCOUNT_CLI_ARGS,
+    PREDEPLOYED_ACCOUNT_ADDRESS,
+    PREDEPLOYED_ACCOUNT_PRIVATE_KEY,
+)
+from test.test_declare_v2 import assert_declare_v2_accepted, load_cairo1_contract
+from test.util import assert_tx_status, devnet_in_background
 
 import pytest
 from starkware.starknet.services.api.gateway.transaction_utils import decompress_program
@@ -12,21 +23,21 @@
     "CONSTRUCTOR": [
         {
             "offset": "0x35",
-            "selector": "0x028ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194",
+            "selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194",
         }
     ],
     "EXTERNAL": [
         {
             "offset": "0x54",
-            "selector": "0x0362398bec32bc0ebb411203221a35a0301193a96f317ebe5e40be9f60d15320",
+            "selector": "0x362398bec32bc0ebb411203221a35a0301193a96f317ebe5e40be9f60d15320",
         },
         {
             "offset": "0x76",
-            "selector": "0x039e11d48192e4333233c7eb19d10ad67c362bb28580c604d67884c85da39695",
+            "selector": "0x39e11d48192e4333233c7eb19d10ad67c362bb28580c604d67884c85da39695",
         },
         {
             "offset": "0xa1",
-            "selector": "0x03cd0a5d52a5573221431e4a61c6bdffd7f157bd278be73f332f0b10f12d895b",
+            "selector": "0x3cd0a5d52a5573221431e4a61c6bdffd7f157bd278be73f332f0b10f12d895b",
         },
     ],
     "L1_HANDLER": [],
@@ -76,8 +87,24 @@
 ]
 
 
+def assert_correct_cairo_1_contract(contract_class):
+    """
+    Assert that the provided cairo 1 contract is equal to the expected one.
+    """
+    with open(CONTRACT_1_PATH, mode="r", encoding="utf-8") as expected_contract, open(
+        ABI_1_PATH, mode="r", encoding="utf-8"
+    ) as expected_abi:
+        expected_contract_json = json.loads(expected_contract.read())
+        expected_abi_json = json.loads(expected_abi.read())
+        assert (
+            contract_class["entry_points_by_type"]
+            == expected_contract_json["entry_points_by_type"]
+        )
+        assert contract_class["abi"] == json.dumps(expected_abi_json)
+
+
 @pytest.mark.usefixtures("run_devnet_in_background")
-def test_get_class(class_hash):
+def test_get_deprecated_class(class_hash):
     """
     Test get contract class
     """
@@ -92,6 +119,68 @@ def test_get_class(class_hash):
     assert contract_class["abi"] == EXPECTED_ABI
 
 
+@devnet_in_background(*PREDEPLOY_ACCOUNT_CLI_ARGS)
+def test_get_class():
+    """
+    Test get contract class V1
+    """
+    contract_class, _, compiled_class_hash = load_cairo1_contract()
+
+    declare_response = send_declare_v2(
+        contract_class=contract_class,
+        compiled_class_hash=compiled_class_hash,
+        sender_address=PREDEPLOYED_ACCOUNT_ADDRESS,
+        sender_key=PREDEPLOYED_ACCOUNT_PRIVATE_KEY,
+    )
+    assert_declare_v2_accepted(declare_response)
+    class_hash = declare_response.json()["class_hash"]
+
+    resp = rpc_call(
+        "starknet_getClass", params={"block_id": "latest", "class_hash": class_hash}
+    )
+
+    contract_class = resp["result"]
+    assert_correct_cairo_1_contract(contract_class)
+
+
+@devnet_in_background(*PREDEPLOY_ACCOUNT_CLI_ARGS)
+def test_get_class_at():
+    """
+    Test get contract class V1
+    """
+    contract_class, _, compiled_class_hash = load_cairo1_contract()
+
+    declare_response = send_declare_v2(
+        contract_class=contract_class,
+        compiled_class_hash=compiled_class_hash,
+        sender_address=PREDEPLOYED_ACCOUNT_ADDRESS,
+        sender_key=PREDEPLOYED_ACCOUNT_PRIVATE_KEY,
+    )
+    assert_declare_v2_accepted(declare_response)
+    class_hash = declare_response.json()["class_hash"]
+
+    # deploy
+    initial_balance = 10
+    deploy_info = deploy(
+        class_hash=class_hash,
+        account_address=PREDEPLOYED_ACCOUNT_ADDRESS,
+        private_key=PREDEPLOYED_ACCOUNT_PRIVATE_KEY,
+        inputs=[str(initial_balance)],
+        max_fee=int(1e18),
+    )
+    assert_tx_status(
+        tx_hash=deploy_info["tx_hash"], expected_tx_status="ACCEPTED_ON_L2"
+    )
+
+    resp = rpc_call(
+        "starknet_getClassAt",
+        params={"block_id": "latest", "contract_address": deploy_info["address"]},
+    )
+
+    contract_class = resp["result"]
+    assert_correct_cairo_1_contract(contract_class)
+
+
 @pytest.mark.usefixtures("run_devnet_in_background")
 def test_get_class_hash_at(deploy_info, class_hash):
     """
@@ -110,7 +199,7 @@ def test_get_class_hash_at(deploy_info, class_hash):
 
 
 @pytest.mark.usefixtures("run_devnet_in_background")
-def test_get_class_at(deploy_info):
+def test_get_deprecated_class_at(deploy_info):
     """
     Test get contract class at given contract address
     """
diff --git a/test/rpc/test_rpc_estimate_fee.py b/test/rpc/test_rpc_estimate_fee.py
index 552bcc4a9..4dc9161b7 100644
--- a/test/rpc/test_rpc_estimate_fee.py
+++ b/test/rpc/test_rpc_estimate_fee.py
@@ -4,19 +4,24 @@
 
 from __future__ import annotations
 
+import copy
 from test.account import _get_signature, get_nonce
 from test.rpc.rpc_utils import rpc_call_background_devnet
 from test.rpc.test_rpc_transactions import pad_zero_entry_points
 from test.shared import (
+    DEPRECATED_RPC_DECLARE_TX_VERSION,
     PREDEPLOY_ACCOUNT_CLI_ARGS,
     PREDEPLOYED_ACCOUNT_ADDRESS,
     PREDEPLOYED_ACCOUNT_PRIVATE_KEY,
+    SUPPORTED_RPC_DECLARE_TX_VERSION,
     SUPPORTED_RPC_TX_VERSION,
 )
 from test.test_account import deploy_empty_contract
+from test.test_declare_v2 import load_cairo1_contract
 
 import pytest
 from starkware.starknet.core.os.transaction_hash.transaction_hash import (
+    calculate_declare_transaction_hash,
     calculate_deprecated_declare_transaction_hash,
 )
 from starkware.starknet.definitions.general_config import StarknetChainId
@@ -24,17 +29,16 @@
 from starkware.starknet.services.api.contract_class.contract_class import (
     DeprecatedCompiledClass,
 )
-from starkware.starknet.services.api.gateway.transaction import (
-    DEFAULT_DECLARE_SENDER_ADDRESS,
-)
 from starkware.starknet.services.api.gateway.transaction_utils import decompress_program
 
 from starknet_devnet.account_util import get_execute_args
 from starknet_devnet.blueprints.rpc.structures.payloads import (
-    RpcBroadcastedDeclareTxn,
+    RpcBroadcastedDeclareTxnV1,
+    RpcBroadcastedDeclareTxnV2,
     RpcBroadcastedInvokeTxnV0,
     RpcBroadcastedInvokeTxnV1,
-    RpcContractClass,
+    RpcDeprecatedContractClass,
+    rpc_contract_class,
 )
 from starknet_devnet.blueprints.rpc.utils import rpc_felt
 from starknet_devnet.constants import DEFAULT_GAS_PRICE, LEGACY_RPC_TX_VERSION
@@ -42,13 +46,13 @@
 
 def common_estimate_response(response):
     """Expected response from RPC estimate_fee request"""
-    result = response["result"]
-    gas_price: int = int(result["gas_price"], 16)
-    overall_fee: int = int(result["overall_fee"], 16)
-    gas_consumed: int = int(result["gas_consumed"], 16)
+    for estimate in response["result"]:
+        gas_price: int = int(estimate["gas_price"], 16)
+        overall_fee: int = int(estimate["overall_fee"], 16)
+        gas_consumed: int = int(estimate["gas_consumed"], 16)
 
-    assert gas_price == DEFAULT_GAS_PRICE
-    assert overall_fee == gas_consumed * gas_price
+        assert gas_price == DEFAULT_GAS_PRICE
+        assert overall_fee == gas_consumed * gas_price
 
 
 def get_predeployed_acc_execute_args(calls):
@@ -76,15 +80,15 @@ def test_estimate_happy_path_v0():
     txn: RpcBroadcastedInvokeTxnV0 = {
         "contract_address": contract_address,
         "entry_point_selector": rpc_felt(get_selector_from_name("sum_point_array")),
-        "calldata": ["0x02", "0x01", "0x02", "0x03", "0x04"],
+        "calldata": ["0x2", "0x1", "0x2", "0x3", "0x4"],
         "max_fee": rpc_felt(0),
         "version": hex(LEGACY_RPC_TX_VERSION),
         "signature": [],
         "type": "INVOKE",
-        "nonce": "0x00",  # According to RPC specs it seems that nonce should be passed even with tx v0
+        "nonce": "0x0",  # According to RPC specs it seems that nonce should be passed even with tx v0
     }
     response = rpc_call_background_devnet(
-        "starknet_estimateFee", {"request": txn, "block_id": "latest"}
+        "starknet_estimateFee", {"request": [txn], "block_id": "latest"}
     )
 
     common_estimate_response(response)
@@ -114,84 +118,147 @@ def test_estimate_happy_path():
     )
 
     response = rpc_call_background_devnet(
-        "starknet_estimateFee", {"request": invoke_transaction, "block_id": "latest"}
+        "starknet_estimateFee", {"request": [invoke_transaction], "block_id": "latest"}
     )
 
     common_estimate_response(response)
 
 
 @pytest.mark.usefixtures("run_devnet_in_background")
-def test_estimate_fee_declare_v0(declare_content):
+@pytest.mark.parametrize(
+    "run_devnet_in_background",
+    [["--gas-price", str(DEFAULT_GAS_PRICE), *PREDEPLOY_ACCOUNT_CLI_ARGS]],
+    indirect=True,
+)
+def test_estimate_fee_declare_v1(declare_content):
     """Test estimate_fee with declare transaction"""
     contract_class = declare_content["contract_class"]
     pad_zero_entry_points(contract_class["entry_points_by_type"])
 
-    rpc_contract_class = RpcContractClass(
+    _rpc_contract_class = RpcDeprecatedContractClass(
         program=contract_class["program"],
-        entry_points_by_type=contract_class["entry_points_by_type"],
+        entry_points_by_type=copy.deepcopy(contract_class["entry_points_by_type"]),
         abi=contract_class["abi"],
     )
 
-    declare_transaction = RpcBroadcastedDeclareTxn(
+    contract_class["program"] = decompress_program(contract_class["program"])
+    contract_class = DeprecatedCompiledClass.load(contract_class)
+
+    nonce = get_nonce(PREDEPLOYED_ACCOUNT_ADDRESS)
+    tx_hash = calculate_deprecated_declare_transaction_hash(
+        contract_class=contract_class,
+        chain_id=StarknetChainId.TESTNET.value,
+        sender_address=int(PREDEPLOYED_ACCOUNT_ADDRESS, 16),
+        max_fee=0,
+        nonce=nonce,
+        version=DEPRECATED_RPC_DECLARE_TX_VERSION,
+    )
+    signature = _get_signature(tx_hash, PREDEPLOYED_ACCOUNT_PRIVATE_KEY)
+
+    declare_transaction = RpcBroadcastedDeclareTxnV1(
         type=declare_content["type"],
-        max_fee=rpc_felt(declare_content["max_fee"]),
-        version=hex(LEGACY_RPC_TX_VERSION),
-        signature=[],
-        nonce=rpc_felt(0),
-        contract_class=rpc_contract_class,
-        sender_address=rpc_felt(DEFAULT_DECLARE_SENDER_ADDRESS),
+        max_fee=rpc_felt(0),
+        version=hex(DEPRECATED_RPC_DECLARE_TX_VERSION),
+        signature=[rpc_felt(sig) for sig in signature],
+        nonce=rpc_felt(nonce),
+        contract_class=_rpc_contract_class,
+        sender_address=rpc_felt(PREDEPLOYED_ACCOUNT_ADDRESS),
     )
 
     response = rpc_call_background_devnet(
-        "starknet_estimateFee", {"request": declare_transaction, "block_id": "latest"}
+        "starknet_estimateFee", {"request": [declare_transaction], "block_id": "latest"}
     )
 
     common_estimate_response(response)
 
 
-@pytest.mark.usefixtures("run_devnet_in_background")
-@pytest.mark.parametrize(
-    "run_devnet_in_background",
-    [["--gas-price", str(DEFAULT_GAS_PRICE), *PREDEPLOY_ACCOUNT_CLI_ARGS]],
-    indirect=True,
-)
-def test_estimate_fee_declare(declare_content):
-    """Test estimate_fee with declare transaction"""
-    contract_class = declare_content["contract_class"]
-    pad_zero_entry_points(contract_class["entry_points_by_type"])
+@pytest.mark.usefixtures("devnet_with_account")
+def test_estimate_fee_declare_v2():
+    """
+    Test estimating fee for v2 declare transaction.
+    """
+    contract_class, _, compiled_class_hash = load_cairo1_contract()
 
-    rpc_contract_class = RpcContractClass(
-        program=contract_class["program"],
-        entry_points_by_type=contract_class["entry_points_by_type"],
-        abi=contract_class["abi"],
+    nonce = get_nonce(PREDEPLOYED_ACCOUNT_ADDRESS)
+
+    tx_hash = calculate_declare_transaction_hash(
+        contract_class=contract_class,
+        compiled_class_hash=compiled_class_hash,
+        chain_id=StarknetChainId.TESTNET.value,
+        sender_address=int(PREDEPLOYED_ACCOUNT_ADDRESS, 16),
+        max_fee=0,
+        version=SUPPORTED_RPC_DECLARE_TX_VERSION,
+        nonce=nonce,
     )
 
-    contract_class["program"] = decompress_program(contract_class["program"])
-    contract_class = DeprecatedCompiledClass.load(contract_class)
+    signature = _get_signature(tx_hash, PREDEPLOYED_ACCOUNT_PRIVATE_KEY)
 
+    declare_transaction = RpcBroadcastedDeclareTxnV2(
+        contract_class=rpc_contract_class(contract_class),
+        sender_address=PREDEPLOYED_ACCOUNT_ADDRESS,
+        compiled_class_hash=rpc_felt(compiled_class_hash),
+        type="DECLARE",
+        version=rpc_felt(SUPPORTED_RPC_DECLARE_TX_VERSION),
+        nonce=rpc_felt(nonce),
+        max_fee=rpc_felt(0),
+        signature=list(map(rpc_felt, signature)),
+    )
+
+    response = rpc_call_background_devnet(
+        "starknet_estimateFee", {"request": [declare_transaction], "block_id": "latest"}
+    )
+
+    common_estimate_response(response)
+
+
+@pytest.mark.usefixtures("devnet_with_account")
+def test_estimate_multiple_transactions():
+    """Estimate fees for multiple transactions"""
+    contract_address = deploy_empty_contract()["address"]
+
+    calls = [(contract_address, "sum_point_array", [2, 10, 20, 30, 40])]
+    signature, execute_calldata = get_predeployed_acc_execute_args(calls)
     nonce = get_nonce(PREDEPLOYED_ACCOUNT_ADDRESS)
-    tx_hash = calculate_deprecated_declare_transaction_hash(
+
+    invoke_transaction = RpcBroadcastedInvokeTxnV1(
+        type="INVOKE",
+        max_fee=rpc_felt(0),
+        version=hex(DEPRECATED_RPC_DECLARE_TX_VERSION),
+        signature=[rpc_felt(sig) for sig in signature],
+        nonce=rpc_felt(nonce),
+        sender_address=rpc_felt(PREDEPLOYED_ACCOUNT_ADDRESS),
+        calldata=[rpc_felt(data) for data in execute_calldata],
+    )
+
+    contract_class, _, compiled_class_hash = load_cairo1_contract()
+    nonce += 1
+
+    tx_hash = calculate_declare_transaction_hash(
         contract_class=contract_class,
+        compiled_class_hash=compiled_class_hash,
         chain_id=StarknetChainId.TESTNET.value,
         sender_address=int(PREDEPLOYED_ACCOUNT_ADDRESS, 16),
         max_fee=0,
+        version=SUPPORTED_RPC_DECLARE_TX_VERSION,
         nonce=nonce,
-        version=SUPPORTED_RPC_TX_VERSION,
     )
+
     signature = _get_signature(tx_hash, PREDEPLOYED_ACCOUNT_PRIVATE_KEY)
 
-    declare_transaction = RpcBroadcastedDeclareTxn(
-        type=declare_content["type"],
-        max_fee=rpc_felt(declare_content["max_fee"]),
-        version=hex(SUPPORTED_RPC_TX_VERSION),
-        signature=[rpc_felt(sig) for sig in signature],
+    declare_transaction = RpcBroadcastedDeclareTxnV2(
+        contract_class=rpc_contract_class(contract_class),
+        sender_address=PREDEPLOYED_ACCOUNT_ADDRESS,
+        compiled_class_hash=rpc_felt(compiled_class_hash),
+        type="DECLARE",
+        version=rpc_felt(SUPPORTED_RPC_DECLARE_TX_VERSION),
         nonce=rpc_felt(nonce),
-        contract_class=rpc_contract_class,
-        sender_address=rpc_felt(PREDEPLOYED_ACCOUNT_ADDRESS),
+        max_fee=rpc_felt(0),
+        signature=list(map(rpc_felt, signature)),
     )
 
     response = rpc_call_background_devnet(
-        "starknet_estimateFee", {"request": declare_transaction, "block_id": "latest"}
+        "starknet_estimateFee",
+        {"request": [invoke_transaction, declare_transaction], "block_id": "latest"},
     )
 
     common_estimate_response(response)
@@ -220,7 +287,7 @@ def test_estimate_fee_with_invalid_call_data():
         calldata=[rpc_felt(data) for data in execute_calldata],
     )
     ex = rpc_call_background_devnet(
-        "starknet_estimateFee", {"request": invoke_transaction, "block_id": "latest"}
+        "starknet_estimateFee", {"request": [invoke_transaction], "block_id": "latest"}
     )
 
     assert ex["error"] == {"code": 22, "message": "Invalid call data"}
@@ -235,17 +302,17 @@ def test_estimate_fee_with_invalid_call_data():
 def test_estimate_fee_with_invalid_contract_address():
     """Call estimate fee with invalid data on body"""
     txn: RpcBroadcastedInvokeTxnV0 = {
-        "contract_address": "0x01",
+        "contract_address": "0x1",
         "entry_point_selector": rpc_felt(get_selector_from_name("sum_point_array")),
-        "calldata": ["0x02", "0x01", "0x02", "0x03", "0x04"],
+        "calldata": ["0x2", "0x1", "0x2", "0x3", "0x4"],
         "max_fee": rpc_felt(0),
         "version": hex(LEGACY_RPC_TX_VERSION),
         "signature": [],
         "type": "INVOKE",
-        "nonce": "0x00",
+        "nonce": "0x0",
     }
     ex = rpc_call_background_devnet(
-        "starknet_estimateFee", {"request": txn, "block_id": "latest"}
+        "starknet_estimateFee", {"request": [txn], "block_id": "latest"}
     )
 
     assert ex["error"] == {"code": 20, "message": "Contract not found"}
@@ -258,16 +325,16 @@ def test_estimate_fee_with_invalid_message_selector():
 
     txn: RpcBroadcastedInvokeTxnV0 = {
         "contract_address": contract_address,
-        "entry_point_selector": "0x01",
-        "calldata": ["0x02", "0x01", "0x02", "0x03", "0x04"],
+        "entry_point_selector": "0x1",
+        "calldata": ["0x2", "0x1", "0x2", "0x3", "0x4"],
         "max_fee": rpc_felt(0),
         "version": hex(LEGACY_RPC_TX_VERSION),
         "signature": [],
         "type": "INVOKE",
-        "nonce": "0x00",
+        "nonce": "0x0",
     }
     ex = rpc_call_background_devnet(
-        "starknet_estimateFee", {"request": txn, "block_id": "latest"}
+        "starknet_estimateFee", {"request": [txn], "block_id": "latest"}
     )
 
     assert ex["error"] == {"code": 21, "message": "Invalid message selector"}
diff --git a/test/rpc/test_rpc_misc.py b/test/rpc/test_rpc_misc.py
index 06d989e6e..bd34c0a31 100644
--- a/test/rpc/test_rpc_misc.py
+++ b/test/rpc/test_rpc_misc.py
@@ -4,7 +4,12 @@
 
 from __future__ import annotations
 
-from test.account import declare, declare_and_deploy_with_chargeable, invoke
+from test.account import (
+    declare,
+    declare_and_deploy_with_chargeable,
+    invoke,
+    send_declare_v2,
+)
 from test.rpc.rpc_utils import deploy_and_invoke_storage_contract, rpc_call
 from test.rpc.test_data.get_events import GET_EVENTS_TEST_DATA, create_get_events_filter
 from test.shared import (
@@ -18,6 +23,7 @@
     PREDEPLOYED_ACCOUNT_PRIVATE_KEY,
 )
 from test.test_account import deploy_empty_contract
+from test.test_declare_v2 import load_cairo1_contract
 from test.test_state_update import get_class_hash_at_path
 from test.util import (
     assert_get_events_response,
@@ -27,6 +33,7 @@
 )
 
 import pytest
+from starkware.starknet.business_logic.transaction.objects import compute_class_hash
 from starkware.starknet.public.abi import get_storage_var_address
 
 from starknet_devnet.blueprints.rpc.structures.types import PredefinedRpcErrorCode
@@ -65,7 +72,8 @@ def test_get_state_update():
 
     resp = rpc_call("starknet_getStateUpdate", params={"block_id": "latest"})
     diff_after_declare = resp["result"]["state_diff"]
-    assert diff_after_declare["declared_contract_hashes"] == [
+
+    assert diff_after_declare["deprecated_declared_classes"] == [
         rpc_felt(contract_class_hash)
     ]
 
@@ -79,6 +87,7 @@ def test_get_state_update():
     deployer_address = deployer_deploy_info["address"]
 
     resp = rpc_call("starknet_getStateUpdate", params={"block_id": "latest"})
+
     diff_after_deploy = resp["result"]["state_diff"]
 
     deployer_diff = diff_after_deploy["deployed_contracts"][0]
@@ -90,7 +99,52 @@ def test_get_state_update():
     # deployed_contract_diff["address"] is a random value
 
     # deployer expected to be declared one block earier, so nothing new declared
-    assert diff_after_deploy["declared_contract_hashes"] == []
+    assert diff_after_deploy["deprecated_declared_classes"] == []
+
+
+@pytest.mark.usefixtures("devnet_with_account")
+def test_get_state_update_declare_v2():
+    """Test if declared classes with new declare v2 succesfully registered"""
+
+    contract_class, _, compiled_class_hash = load_cairo1_contract()
+
+    send_declare_v2(
+        contract_class=contract_class,
+        compiled_class_hash=compiled_class_hash,
+        sender_address=PREDEPLOYED_ACCOUNT_ADDRESS,
+        sender_key=PREDEPLOYED_ACCOUNT_PRIVATE_KEY,
+    )
+
+    resp = rpc_call("starknet_getStateUpdate", params={"block_id": "latest"})
+
+    declared_class = resp["result"]["state_diff"]["declared_classes"][0]
+    computed_class_hash = compute_class_hash(contract_class)
+
+    assert declared_class["class_hash"] == rpc_felt(computed_class_hash)
+    assert declared_class["compiled_class_hash"] == rpc_felt(compiled_class_hash)
+
+
+@pytest.mark.usefixtures("devnet_with_account")
+def test_get_pending_state_update():
+    """
+    Test if getStateUpdate returns correct update for a pending state.
+    """
+    resp = rpc_call("starknet_getStateUpdate", params={"block_id": "pending"})
+    pending_state_update = resp["result"]
+    keys = pending_state_update.keys()
+
+    assert set(keys) == set(["old_root", "state_diff"])
+
+    state_diff = pending_state_update["state_diff"]
+
+    assert state_diff == {
+        "declared_classes": [],
+        "deployed_contracts": [],
+        "deprecated_declared_classes": [],
+        "nonces": [],
+        "replaced_classes": [],
+        "storage_diffs": [],
+    }
 
 
 @pytest.mark.usefixtures("devnet_with_account")
@@ -286,7 +340,7 @@ def test_get_nonce():
         method="starknet_getNonce",
         params={"block_id": "latest", "contract_address": rpc_felt(account_address)},
     )
-    assert initial_resp["result"] == "0x00"
+    assert initial_resp["result"] == "0x0"
 
     deployment_info = deploy_empty_contract()
 
@@ -301,7 +355,7 @@ def test_get_nonce():
         method="starknet_getNonce",
         params={"block_id": "latest", "contract_address": rpc_felt(account_address)},
     )
-    assert final_resp["result"] == "0x01"
+    assert final_resp["result"] == "0x1"
 
 
 @pytest.mark.usefixtures("devnet_with_account")
diff --git a/test/rpc/test_rpc_schema.py b/test/rpc/test_rpc_schema.py
index 214184aff..b3528de22 100644
--- a/test/rpc/test_rpc_schema.py
+++ b/test/rpc/test_rpc_schema.py
@@ -8,7 +8,10 @@
 import pytest
 from starkware.starknet.public.abi import get_selector_from_name
 
-from starknet_devnet.blueprints.rpc.schema import _assert_valid_rpc_request
+from starknet_devnet.blueprints.rpc.schema import (
+    _assert_valid_rpc_request,
+    felt_pattern_from_schema,
+)
 from starknet_devnet.blueprints.rpc.structures.types import PredefinedRpcErrorCode
 from starknet_devnet.blueprints.rpc.utils import rpc_felt
 
@@ -30,14 +33,14 @@ def _assert_call_does_not_raise_predefined_error(error_code: int):
     (
         {
             "request": {
-                "contract_address": "0x01",
+                "contract_address": "0x1",
                 "entry_point_selector": rpc_felt(get_selector_from_name("get_balance")),
                 "calldata": [],
             },
         },
         {
             "request": {
-                "contract_address": "0x01",
+                "contract_address": "0x1",
                 "entry_point_selector": rpc_felt(get_selector_from_name("get_balance")),
                 "calldata": [],
             },
@@ -45,7 +48,7 @@ def _assert_call_does_not_raise_predefined_error(error_code: int):
         },
         {
             "request": {
-                "contract_address": "0x01",
+                "contract_address": "0x1",
                 "entry_point_selector": rpc_felt(get_selector_from_name("get_balance")),
                 "calldata": [],
             },
@@ -64,7 +67,7 @@ def _assert_call_does_not_raise_predefined_error(error_code: int):
         },
         {
             "request": {
-                "contract_address": "0x01",
+                "contract_address": "0x1",
                 "entry_point_selector": rpc_felt(get_selector_from_name("get_balance")),
                 "calldata": "0x1234",
             },
@@ -80,8 +83,8 @@ def _assert_call_does_not_raise_predefined_error(error_code: int):
         },
         {
             "request": {
-                "contract_address": "0x01",
-                "entry_point_selector": ["0x01", "0x02"],
+                "contract_address": "0x1",
+                "entry_point_selector": ["0x1", "0x2"],
                 "calldata": [],
             },
             "block_id": "latest",
@@ -106,7 +109,7 @@ def test_schema_raises_on_invalid_kwargs(params):
     (
         [
             {
-                "contract_address": "0x01",
+                "contract_address": "0x1",
                 "entry_point_selector": rpc_felt(get_selector_from_name("get_balance")),
                 "calldata": [],
             }
@@ -116,7 +119,7 @@ def test_schema_raises_on_invalid_kwargs(params):
         ],
         [
             {
-                "contract_address": "0x01",
+                "contract_address": "0x1",
                 "entry_point_selector": rpc_felt(get_selector_from_name("get_balance")),
                 "calldata": [],
             },
@@ -124,7 +127,7 @@ def test_schema_raises_on_invalid_kwargs(params):
         ],
         [
             {
-                "contract_address": "0x01",
+                "contract_address": "0x1",
                 "entry_point_selector": rpc_felt(get_selector_from_name("get_balance")),
                 "calldata": [],
             },
@@ -140,7 +143,7 @@ def test_schema_raises_on_invalid_kwargs(params):
         ],
         [
             {
-                "contract_address": "0x01",
+                "contract_address": "0x1",
                 "entry_point_selector": rpc_felt(get_selector_from_name("get_balance")),
                 "calldata": "0x1234",
             },
@@ -156,8 +159,8 @@ def test_schema_raises_on_invalid_kwargs(params):
         ],
         [
             {
-                "contract_address": "0x01",
-                "entry_point_selector": ["0x01", "0x02"],
+                "contract_address": "0x1",
+                "entry_point_selector": ["0x1", "0x2"],
                 "calldata": [],
             },
             "latest",
@@ -165,8 +168,8 @@ def test_schema_raises_on_invalid_kwargs(params):
         [
             "latest",
             {
-                "contract_address": "0x01",
-                "entry_point_selector": "0x01",
+                "contract_address": "0x1",
+                "entry_point_selector": "0x1",
                 "calldata": [],
             },
         ],
@@ -213,7 +216,7 @@ def test_schema_does_not_raise_on_disabled_request_validation():
     (
         {
             "request": {
-                "contract_address": "0x01",
+                "contract_address": "0x1",
                 "entry_point_selector": rpc_felt(get_selector_from_name("get_balance")),
                 "calldata": [],
             },
@@ -222,22 +225,22 @@ def test_schema_does_not_raise_on_disabled_request_validation():
         {
             "block_id": "latest",
             "request": {
-                "contract_address": "0x01",
+                "contract_address": "0x1",
                 "entry_point_selector": rpc_felt(get_selector_from_name("get_balance")),
                 "calldata": [],
             },
         },
         {
             "request": {
-                "contract_address": "0x01",
+                "contract_address": "0x1",
                 "entry_point_selector": rpc_felt(get_selector_from_name("get_balance")),
                 "calldata": [],
             },
-            "block_id": {"block_hash": "0x00"},
+            "block_id": {"block_hash": "0x0"},
         },
         {
             "request": {
-                "contract_address": "0x01",
+                "contract_address": "0x1",
                 "entry_point_selector": rpc_felt(get_selector_from_name("get_balance")),
                 "calldata": [],
             },
@@ -270,7 +273,7 @@ def test_schema_does_not_raise_on_correct_args():
         "starknet_call",
         params=[
             {
-                "contract_address": "0x01",
+                "contract_address": "0x1",
                 "entry_point_selector": rpc_felt(get_selector_from_name("get_balance")),
                 "calldata": [],
             },
@@ -333,3 +336,12 @@ def test_schema_with_optional_values():
 
         params = {"key": "0x01"}
         _assert_valid_rpc_request(**params, method_name="starknet_method")
+
+
+def test_felt_pattern_from_schema():
+    """
+    Test getting the felt pattern from the rpc spec.
+    """
+    pattern = felt_pattern_from_schema()
+
+    assert pattern != ""
diff --git a/test/rpc/test_rpc_storage.py b/test/rpc/test_rpc_storage.py
index 7c6206d77..68ff8a5bf 100644
--- a/test/rpc/test_rpc_storage.py
+++ b/test/rpc/test_rpc_storage.py
@@ -6,7 +6,7 @@
 import pytest
 from starkware.starknet.public.abi import get_storage_var_address
 
-from starknet_devnet.blueprints.rpc.utils import rpc_felt
+from starknet_devnet.blueprints.rpc.utils import rpc_felt, rpc_storage_key
 
 
 @pytest.mark.usefixtures("run_devnet_in_background")
@@ -22,13 +22,13 @@ def test_get_storage_at(deploy_info):
         "starknet_getStorageAt",
         params={
             "contract_address": rpc_felt(contract_address),
-            "key": rpc_felt(key),
+            "key": rpc_storage_key(key),
             "block_id": block_id,
         },
     )
     storage = resp["result"]
 
-    assert storage == "0x045"
+    assert storage == "0x45"
 
 
 @pytest.mark.usefixtures("run_devnet_in_background")
@@ -44,14 +44,14 @@ def get_storage(block_id):
             "starknet_getStorageAt",
             params={
                 "contract_address": rpc_felt(contract_address),
-                "key": rpc_felt(key),
+                "key": rpc_storage_key(key),
                 "block_id": block_id,
             },
         )
         return resp["result"]
 
-    assert get_storage({"block_number": 0}) == "0x00"
-    assert get_storage({"block_hash": "0x00"}) == "0x00"
+    assert get_storage({"block_number": 0}) == "0x0"
+    assert get_storage({"block_hash": "0x0"}) == "0x0"
 
 
 @pytest.mark.usefixtures("run_devnet_in_background", "deploy_info")
@@ -65,8 +65,8 @@ def test_get_storage_at_raises_on_incorrect_contract():
     ex = rpc_call(
         "starknet_getStorageAt",
         params={
-            "contract_address": "0x00",
-            "key": rpc_felt(key),
+            "contract_address": "0x0",
+            "key": rpc_storage_key(key),
             "block_id": block_id,
         },
     )
@@ -75,7 +75,7 @@ def test_get_storage_at_raises_on_incorrect_contract():
 
 
 # internal workings of get_storage_at would have to be changed for this to work properly
-# since currently it will (correctly) return 0x00 for any incorrect key
+# since currently it will (correctly) return 0x0 for any incorrect key
 # and it should throw exception with code=23 and message="Invalid storage key"
 @pytest.mark.usefixtures("run_devnet_in_background")
 def test_get_storage_at_raises_on_incorrect_key(deploy_info):
@@ -93,7 +93,7 @@ def test_get_storage_at_raises_on_incorrect_key(deploy_info):
         },
     )
 
-    assert response["result"] == "0x00"
+    assert response["result"] == "0x0"
 
 
 @pytest.mark.usefixtures("run_devnet_in_background")
@@ -109,7 +109,7 @@ def test_get_storage_at_raises_on_incorrect_block_id(deploy_info):
         "starknet_getStorageAt",
         params={
             "contract_address": rpc_felt(contract_address),
-            "key": rpc_felt(key),
+            "key": rpc_storage_key(key),
             "block_id": {"block_number": 99999},
         },
     )
diff --git a/test/rpc/test_rpc_transactions.py b/test/rpc/test_rpc_transactions.py
index 9731a7d90..98d33d7ba 100644
--- a/test/rpc/test_rpc_transactions.py
+++ b/test/rpc/test_rpc_transactions.py
@@ -21,18 +21,22 @@
 from test.shared import (
     ABI_PATH,
     CONTRACT_PATH,
+    DEPRECATED_RPC_DECLARE_TX_VERSION,
     EXPECTED_UDC_ADDRESS,
     INCORRECT_GENESIS_BLOCK_HASH,
     PREDEPLOYED_ACCOUNT_ADDRESS,
     PREDEPLOYED_ACCOUNT_PRIVATE_KEY,
     STARKNET_CLI_ACCOUNT_ABI_PATH,
+    SUPPORTED_RPC_DECLARE_TX_VERSION,
     SUPPORTED_RPC_TX_VERSION,
 )
+from test.test_declare_v2 import load_cairo1_contract
 from test.util import assert_tx_status, call, load_contract_class, mint, send_tx
 from typing import List
 
 import pytest
 from starkware.starknet.core.os.transaction_hash.transaction_hash import (
+    calculate_declare_transaction_hash,
     calculate_deprecated_declare_transaction_hash,
 )
 from starkware.starknet.definitions.general_config import (
@@ -49,25 +53,27 @@
 
 from starknet_devnet.account_util import get_execute_args
 from starknet_devnet.blueprints.rpc.structures.payloads import (
-    EntryPoints,
-    RpcBroadcastedDeclareTxn,
+    DeprecatedEntryPoints,
+    RpcBroadcastedDeclareTxnV1,
+    RpcBroadcastedDeclareTxnV2,
     RpcBroadcastedInvokeTxnV0,
     RpcBroadcastedInvokeTxnV1,
-    RpcContractClass,
+    RpcDeprecatedContractClass,
+    rpc_contract_class,
 )
 from starknet_devnet.blueprints.rpc.structures.types import Signature, rpc_txn_type
 from starknet_devnet.blueprints.rpc.utils import rpc_felt
 from starknet_devnet.constants import LEGACY_RPC_TX_VERSION
 
 
-def pad_zero_entry_points(entry_points: EntryPoints) -> None:
+def pad_zero_entry_points(entry_points: DeprecatedEntryPoints) -> None:
     """
     Pad zero every selector in entry points in contract_class
     """
 
     def pad_selector(entry_point):
         return {
-            "offset": entry_point["offset"],
+            "offset": rpc_felt(entry_point["offset"]),
             "selector": rpc_felt(entry_point["selector"]),
         }
 
@@ -209,7 +215,7 @@ def test_get_transaction_by_hash_raises_on_incorrect_hash():
     """
     Get transaction by incorrect hash
     """
-    ex = rpc_call("starknet_getTransactionByHash", params={"transaction_hash": "0x00"})
+    ex = rpc_call("starknet_getTransactionByHash", params={"transaction_hash": "0x0"})
 
     assert ex["error"] == {"code": 25, "message": "Transaction hash not found"}
 
@@ -505,7 +511,7 @@ def test_add_invoke_transaction_v0():
         max_fee=rpc_felt(0),
         version=hex(LEGACY_RPC_TX_VERSION),
         signature=[],
-        nonce="0x00",
+        nonce="0x0",
         contract_address=rpc_felt(contract_address),
         entry_point_selector=rpc_felt(get_selector_from_name("increase_balance")),
         calldata=[rpc_felt(amount1), rpc_felt(amount2)],
@@ -536,19 +542,19 @@ def test_add_declare_transaction_on_incorrect_contract(declare_content):
     contract_class = declare_content["contract_class"]
     pad_zero_entry_points(contract_class["entry_points_by_type"])
 
-    rpc_contract_class = RpcContractClass(
+    contract_class = RpcDeprecatedContractClass(
         program="",
         entry_points_by_type=contract_class["entry_points_by_type"],
         abi=contract_class["abi"],
     )
 
-    declare_transaction = RpcBroadcastedDeclareTxn(
+    declare_transaction = RpcBroadcastedDeclareTxnV1(
         type=declare_content["type"],
         max_fee=rpc_felt(declare_content["max_fee"]),
-        version=hex(SUPPORTED_RPC_TX_VERSION),
+        version=hex(DEPRECATED_RPC_DECLARE_TX_VERSION),
         signature=[rpc_felt(sig) for sig in declare_content["signature"]],
         nonce=rpc_felt(declare_content["nonce"]),
-        contract_class=rpc_contract_class,
+        contract_class=contract_class,
         sender_address=rpc_felt(declare_content["sender_address"]),
     )
 
@@ -560,12 +566,56 @@ def test_add_declare_transaction_on_incorrect_contract(declare_content):
     assert ex["error"] == {"code": 50, "message": "Invalid contract class"}
 
 
+@pytest.mark.usefixtures("devnet_with_account")
+def test_add_declare_transaction_v2():
+    """Add declare transaction v2"""
+    contract_class, _, compiled_class_hash = load_cairo1_contract()
+
+    max_fee = int(4e16)
+    nonce = get_nonce(PREDEPLOYED_ACCOUNT_ADDRESS)
+
+    tx_hash = calculate_declare_transaction_hash(
+        contract_class=contract_class,
+        compiled_class_hash=compiled_class_hash,
+        chain_id=StarknetChainId.TESTNET.value,
+        sender_address=int(PREDEPLOYED_ACCOUNT_ADDRESS, 16),
+        max_fee=max_fee,
+        version=SUPPORTED_RPC_DECLARE_TX_VERSION,
+        nonce=nonce,
+    )
+
+    signature = _get_signature(tx_hash, PREDEPLOYED_ACCOUNT_PRIVATE_KEY)
+
+    declare_transaction = RpcBroadcastedDeclareTxnV2(
+        contract_class=rpc_contract_class(contract_class),
+        sender_address=PREDEPLOYED_ACCOUNT_ADDRESS,
+        compiled_class_hash=rpc_felt(compiled_class_hash),
+        type="DECLARE",
+        version=rpc_felt(SUPPORTED_RPC_DECLARE_TX_VERSION),
+        nonce=rpc_felt(nonce),
+        max_fee=rpc_felt(max_fee),
+        signature=list(map(rpc_felt, signature)),
+    )
+
+    resp = rpc_call(
+        "starknet_addDeclareTransaction",
+        params={"declare_transaction": declare_transaction},
+    )
+
+    receipt = resp["result"]
+
+    assert set(receipt.keys()) == set(["transaction_hash", "class_hash"])
+    assert is_felt(receipt["transaction_hash"])
+    assert is_felt(receipt["class_hash"])
+
+
 def _add_declare_transaction():
     contract_class = load_contract_class(CONTRACT_PATH)
     contract_class_dump = contract_class.dump()
 
     pad_zero_entry_points(contract_class_dump["entry_points_by_type"])
-    rpc_contract_class = RpcContractClass(
+
+    _rpc_contract_class = RpcDeprecatedContractClass(
         program=compress_program(contract_class_dump["program"]),
         entry_points_by_type=contract_class_dump["entry_points_by_type"],
         abi=contract_class_dump["abi"],
@@ -583,13 +633,13 @@ def _add_declare_transaction():
     )
     signature = _get_signature(tx_hash, PREDEPLOYED_ACCOUNT_PRIVATE_KEY)
 
-    declare_transaction = RpcBroadcastedDeclareTxn(
+    declare_transaction = RpcBroadcastedDeclareTxnV1(
         type="DECLARE",
         max_fee=rpc_felt(max_fee),
-        version=hex(SUPPORTED_RPC_TX_VERSION),
+        version=hex(DEPRECATED_RPC_DECLARE_TX_VERSION),
         signature=[rpc_felt(sig) for sig in signature],
         nonce=rpc_felt(nonce),
-        contract_class=rpc_contract_class,
+        contract_class=_rpc_contract_class,
         sender_address=rpc_felt(PREDEPLOYED_ACCOUNT_ADDRESS),
     )
 
@@ -601,7 +651,7 @@ def _add_declare_transaction():
 
 
 @pytest.mark.usefixtures("devnet_with_account")
-def test_add_declare_transaction():
+def test_add_declare_transaction_v1():
     """Add declare transaction"""
     receipt = _add_declare_transaction()
 
@@ -612,38 +662,35 @@ def test_add_declare_transaction():
 
 
 @pytest.mark.usefixtures("run_devnet_in_background")
-def test_add_declare_transaction_v0(declare_content):
+def test_add_declare_transaction_v0_fails(declare_content):
     """
-    Add declare transaction with tx v0
+    Adding declare transaction with tx v0 should fail
     """
     contract_class = declare_content["contract_class"]
     pad_zero_entry_points(contract_class["entry_points_by_type"])
 
-    rpc_contract_class = RpcContractClass(
+    contract_class = RpcDeprecatedContractClass(
         program=contract_class["program"],
         entry_points_by_type=contract_class["entry_points_by_type"],
         abi=contract_class["abi"],
     )
 
-    declare_transaction = RpcBroadcastedDeclareTxn(
+    declare_transaction = RpcBroadcastedDeclareTxnV1(
         type=declare_content["type"],
         max_fee=rpc_felt(declare_content["max_fee"]),
         version=hex(LEGACY_RPC_TX_VERSION),
         signature=[],
         nonce=rpc_felt(0),
-        contract_class=rpc_contract_class,
+        contract_class=contract_class,
         sender_address=rpc_felt(1),
     )
 
-    resp = rpc_call(
+    ex = rpc_call(
         "starknet_addDeclareTransaction",
         params={"declare_transaction": declare_transaction},
     )
-    receipt = resp["result"]
 
-    assert set(receipt.keys()) == set(["transaction_hash", "class_hash"])
-    assert is_felt(receipt["transaction_hash"])
-    assert is_felt(receipt["class_hash"])
+    assert ex["error"] == {"code": 50, "message": "Invalid contract class"}
 
 
 @pytest.mark.usefixtures("devnet_with_account")
diff --git a/test/shared.py b/test/shared.py
index 073041fee..bc1df89ab 100644
--- a/test/shared.py
+++ b/test/shared.py
@@ -54,6 +54,9 @@
 SUPPORTED_TX_VERSION = 1
 SUPPORTED_RPC_TX_VERSION = 1
 
+SUPPORTED_RPC_DECLARE_TX_VERSION = 2
+DEPRECATED_RPC_DECLARE_TX_VERSION = 1
+
 PREDEPLOY_ACCOUNT_CLI_ARGS = ("--seed", "42", "--accounts", "1")
 PREDEPLOYED_ACCOUNT_ADDRESS = (
     "0x347be35996a21f6bf0623e75dbce52baba918ad5ae8d83b6f416045ab22961a"
diff --git a/test/util.py b/test/util.py
index c4d073962..3b74eb8f3 100644
--- a/test/util.py
+++ b/test/util.py
@@ -45,6 +45,13 @@ def run_devnet_in_background(*args, stderr=None, stdout=None, env=None):
     if "--accounts" not in args:
         args = [*args, "--accounts", "1"]
 
+    if (
+        "--cairo-compiler-manifest" not in args
+        and os.getenv("CAIRO_1_COMPILER_MANIFEST") is not None
+    ):
+        manifest = os.getenv("CAIRO_1_COMPILER_MANIFEST")
+        args = [*args, "--cairo-compiler-manifest", manifest]
+
     port = args[args.index("--port") + 1] if "--port" in args else PORT
 
     command = [