Repository: skalenetwork/skale.py (language: python)

Issue:
Merge beta to develop



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml
new file mode 100644
index 00000000..c5a3c1f8
--- /dev/null
+++ b/.github/workflows/cla.yml
@@ -0,0 +1,38 @@
+name: "cla"
+on:
+  issue_comment:
+    types: [created]
+  pull_request_target:
+    types: [opened, closed, synchronize]
+
+jobs:
+  cla:
+    runs-on: ubuntu-latest
+    steps:
+      - name: "Get Team Members"
+        id: team
+        # github-script, v6.1.0
+        uses: actions/github-script@7a5c598405937d486b0331594b5da2b14db670da
+        with:
+          github-token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
+          result-encoding: string
+          script: |
+            const members = await github.paginate(
+              github.rest.orgs.listMembers,
+              { org: "skalenetwork" },
+            );
+            return members.map(m => m.login).join(",");
+
+      - name: "CLA Assistant"
+        if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
+        # Beta Release, v2.1.3-beta
+        uses: cla-assistant/github-action@ba066dbae3769e2ce93ec8cfc4fdc51b9db628ba
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          PERSONAL_ACCESS_TOKEN : ${{ secrets.PERSONAL_ACCESS_TOKEN }}
+        with:
+          path-to-signatures: 'signatures/version1/cla.json'
+          path-to-document: 'https://skale.network/cla.txt'
+          remote-organization-name: 'skalenetwork'
+          remote-repository-name: cla-sigs
+          allowlist: '${{ steps.team.outputs.result }},*[bot]'
diff --git a/.gitmodules b/.gitmodules
index d54a2086..cbe21c5d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -2,3 +2,6 @@
 	path = helper-scripts
 	url = https://github.com/skalenetwork/helper-scripts.git
 	branch = develop
+[submodule "hardhat-node"]
+	path = hardhat-node
+	url = git@github.com:skalenetwork/hardhat-node.git
diff --git a/CODEOWNERS b/CODEOWNERS
index fac00956..f8254e9d 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -1,2 +1,2 @@
-* @dmitry-tk @kladkogex @badrogger
+* @dmytrotkk @kladkogex @badrogger
 *.md @skalenetwork/docowners
diff --git a/README.md b/README.md
index 95373fd8..f9097911 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
 Python client library used in SKALE network components.
 
 - Python 3.7+ support
-- Compatibility with `web3.py` v5
+- Compatibility with `web3.py` v6
 
 ### Installation
 
diff --git a/hardhat-node b/hardhat-node
new file mode 160000
index 00000000..8a4b03fd
--- /dev/null
+++ b/hardhat-node
@@ -0,0 +1,1 @@
+Subproject commit 8a4b03fd1051960a3e0182280bf4bfdc43129997
diff --git a/helper-scripts b/helper-scripts
index 22428990..356ee771 160000
--- a/helper-scripts
+++ b/helper-scripts
@@ -1,1 +1,1 @@
-Subproject commit 2242899037c120ce43ec87d9b80f2a223c619331
+Subproject commit 356ee771191d6654e9d1f97a0f131ef36481d4d9
diff --git a/scripts/install_python_dependencies.sh b/scripts/install_python_dependencies.sh
index aae78ffe..4fbfc4ed 100644
--- a/scripts/install_python_dependencies.sh
+++ b/scripts/install_python_dependencies.sh
@@ -1,8 +1,8 @@
 #!/usr/bin/env bash
 
-set -e
+set -ea
 
 python -m pip install --upgrade pip
 pip install -e .
 pip install -e .[dev]
-pip install codecov pytest-cov
\ No newline at end of file
+pip install codecov pytest-cov
diff --git a/setup.py b/setup.py
index de0957f5..7892f26e 100644
--- a/setup.py
+++ b/setup.py
@@ -16,7 +16,7 @@
         "click==7.1.2",
         "freezegun==1.2.2",
         "mock==4.0.2",
-        "pytest==5.4.3",
+        "pytest==7.1.3",
         "pytest-cov==2.8.1",
         "Random-Word==1.0.4",
         "twine==4.0.2",
@@ -33,7 +33,7 @@
 
 setup(
     name='skale.py',
-    version='5.8',
+    version='6.2',
     description='SKALE client tools',
     long_description_markdown_filename='README.md',
     author='SKALE Labs',
@@ -41,11 +41,12 @@
     url='https://github.com/skalenetwork/skale.py',
     include_package_data=True,
     install_requires=[
-        "web3==5.31.1",
         "asyncio==3.4.3",
         "pyyaml==6.0",
-        "sgx.py==0.8dev7",
-        "redis==4.3.4"
+        "sgx.py==0.9dev2",
+        "redis==4.4.4",
+        "typing-extensions==4.9.0",
+        "web3==6.13.0"
     ],
 
     python_requires='>=3.7,<4',
diff --git a/skale/contracts/allocator/allocator.py b/skale/contracts/allocator/allocator.py
index 9eb37b56..37f64b1d 100644
--- a/skale/contracts/allocator/allocator.py
+++ b/skale/contracts/allocator/allocator.py
@@ -21,6 +21,7 @@
 from enum import IntEnum
 
 from skale.contracts.base_contract import BaseContract, transaction_method
+from skale.transactions.exceptions import ContractLogicError
 from skale.transactions.result import TxRes
 from skale.utils.helper import format_fields
 
@@ -157,7 +158,7 @@ def get_all_plans(self) -> dict:
                 plan = self.get_plan(i)
                 plan['planId'] = i
                 plans.append(plan)
-            except ValueError:
+            except (ContractLogicError, ValueError):
                 break
         return plans
 
diff --git a/skale/contracts/base_contract.py b/skale/contracts/base_contract.py
index 5d2309b6..e984c1aa 100644
--- a/skale/contracts/base_contract.py
+++ b/skale/contracts/base_contract.py
@@ -25,12 +25,8 @@
 from web3 import Web3
 
 import skale.config as config
-from skale.transactions.result import (
-    TxRes,
-    is_success,
-    is_success_or_not_performed
-)
-from skale.transactions.tools import make_dry_run_call, transaction_from_method
+from skale.transactions.result import TxRes
+from skale.transactions.tools import make_dry_run_call, transaction_from_method, TxStatus
 from skale.utils.web3_utils import (
     DEFAULT_BLOCKS_TO_WAIT,
     get_eth_nonce,
@@ -44,14 +40,6 @@
 logger = logging.getLogger(__name__)
 
 
-def execute_dry_run(skale, method, custom_gas_limit, value=0) -> tuple:
-    dry_run_result = make_dry_run_call(skale, method, custom_gas_limit, value)
-    estimated_gas_limit = None
-    if is_success(dry_run_result):
-        estimated_gas_limit = dry_run_result['payload']
-    return dry_run_result, estimated_gas_limit
-
-
 def transaction_method(transaction):
     @wraps(transaction)
     def wrapper(
@@ -76,27 +64,23 @@ def wrapper(
         **kwargs
     ):
         method = transaction(self, *args, **kwargs)
-        dry_run_result, tx_hash, receipt = None, None, None
 
         nonce = get_eth_nonce(self.skale.web3, self.skale.wallet.address)
 
-        # Make dry_run and estimate gas limit
-        estimated_gas_limit = None
-        if not skip_dry_run and not config.DISABLE_DRY_RUN:
-            dry_run_result, estimated_gas_limit = execute_dry_run(
-                self.skale, method, gas_limit, value
-            )
+        call_result, tx_hash, receipt = None, None, None
+        should_dry_run = not skip_dry_run and not config.DISABLE_DRY_RUN
 
-        gas_limit = gas_limit or estimated_gas_limit or \
-            config.DEFAULT_GAS_LIMIT
+        if should_dry_run:
+            call_result = make_dry_run_call(self.skale, method, gas_limit, value)
+            if call_result.status == TxStatus.SUCCESS:
+                gas_limit = gas_limit or call_result.data['gas']
 
-        gas_price = gas_price or config.DEFAULT_GAS_PRICE_WEI or \
-            self.skale.gas_price
-        # Send transaction
-        should_send_transaction = not dry_run_only and \
-            is_success_or_not_performed(dry_run_result)
+        should_send = not dry_run_only and \
+            (not should_dry_run or call_result.status == TxStatus.SUCCESS)
 
-        if should_send_transaction:
+        if should_send:
+            gas_limit = gas_limit or config.DEFAULT_GAS_LIMIT
+            gas_price = gas_price or config.DEFAULT_GAS_PRICE_WEI or self.skale.gas_price
             tx = transaction_from_method(
                 method=method,
                 gas_limit=gas_limit,
@@ -114,15 +98,16 @@ def wrapper(
                 method=method_name,
                 meta=meta
             )
-            if wait_for:
-                receipt = self.skale.wallet.wait(tx_hash)
-            if confirmation_blocks:
-                wait_for_confirmation_blocks(
-                    self.skale.web3,
-                    confirmation_blocks
-                )
 
-        tx_res = TxRes(dry_run_result, tx_hash, receipt)
+        should_wait = tx_hash is not None and wait_for
+        if should_wait:
+            receipt = self.skale.wallet.wait(tx_hash)
+
+        should_confirm = receipt is not None and confirmation_blocks > 0
+        if should_confirm:
+            wait_for_confirmation_blocks(self.skale.web3, confirmation_blocks)
+
+        tx_res = TxRes(call_result, tx_hash, receipt)
 
         if raise_for_status:
             tx_res.raise_for_status()
@@ -135,7 +120,7 @@ class BaseContract:
     def __init__(self, skale, name, address, abi):
         self.skale = skale
         self.name = name
-        self.address = Web3.toChecksumAddress(address)
+        self.address = Web3.to_checksum_address(address)
         self.contract = skale.web3.eth.contract(address=self.address, abi=abi)
 
     def __getattr__(self, attr):
diff --git a/skale/contracts/manager/delegation/validator_service.py b/skale/contracts/manager/delegation/validator_service.py
index e70ee32d..ffba3305 100644
--- a/skale/contracts/manager/delegation/validator_service.py
+++ b/skale/contracts/manager/delegation/validator_service.py
@@ -195,7 +195,7 @@ def register_validator(self, name: str, description: str, fee_rate: int,
             name, description, fee_rate, min_delegation_amount)
 
     def get_link_node_signature(self, validator_id: int) -> str:
-        unsigned_hash = Web3.soliditySha3(['uint256'], [validator_id])
+        unsigned_hash = Web3.solidity_keccak(['uint256'], [validator_id])
         signed_hash = self.skale.wallet.sign_hash(unsigned_hash.hex())
         return signed_hash.signature.hex()
 
diff --git a/skale/contracts/manager/dkg.py b/skale/contracts/manager/dkg.py
index 771dddfb..47d22c79 100644
--- a/skale/contracts/manager/dkg.py
+++ b/skale/contracts/manager/dkg.py
@@ -40,10 +40,11 @@ class DKG(BaseContract):
     @retry_tx
     @transaction_method
     def broadcast(self, group_index, node_index,
-                  verification_vector, secret_key_contribution):
+                  verification_vector, secret_key_contribution, rotation_id):
         return self.contract.functions.broadcast(group_index, node_index,
                                                  verification_vector,
-                                                 secret_key_contribution)
+                                                 secret_key_contribution,
+                                                 rotation_id)
 
     @retry_tx
     @transaction_method
@@ -153,3 +154,6 @@ def get_complaint_data(self, group_index):
 
     def get_time_of_last_successful_dkg(self, group_index):
         return self.contract.functions.getTimeOfLastSuccessfulDKG(group_index).call()
+
+    def is_node_broadcasted(self, group_index: int, node_id: int) -> bool:
+        return self.contract.functions.isNodeBroadcasted(group_index, node_id).call()
diff --git a/skale/contracts/manager/manager.py b/skale/contracts/manager/manager.py
index 3522844c..e3a844f8 100644
--- a/skale/contracts/manager/manager.py
+++ b/skale/contracts/manager/manager.py
@@ -22,7 +22,7 @@
 import logging
 import socket
 
-from eth_abi import encode_abi
+from eth_abi import encode
 
 from skale.contracts.base_contract import BaseContract, transaction_method
 from skale.utils import helper
@@ -83,7 +83,7 @@ def create_schain(
         if not options:
             options = get_default_schain_options()
 
-        tx_data = encode_abi(
+        tx_data = encode(
             ['(uint,uint8,uint16,string,address,(string,bytes)[])'],
             [(lifetime, type_of_nodes, skale_nonce, name, schain_originator, options.to_tuples())]
         )
diff --git a/skale/contracts/manager/node_rotation.py b/skale/contracts/manager/node_rotation.py
index 0994974e..8e3a9a9f 100644
--- a/skale/contracts/manager/node_rotation.py
+++ b/skale/contracts/manager/node_rotation.py
@@ -109,7 +109,7 @@ def is_finish_ts_reached(self, schain_name) -> bool:
         if not schain_finish_ts:
             schain_finish_ts = 0
 
-        latest_block = self.skale.web3.eth.getBlock('latest')
+        latest_block = self.skale.web3.eth.get_block('latest')
         current_ts = latest_block['timestamp']
 
         logger.info(f'current_ts: {current_ts}, schain_finish_ts: {schain_finish_ts}')
@@ -133,7 +133,7 @@ def get_previous_node(self, schain_name: str, node_id: int) -> int:
         schain_id = self.schains.name_to_id(schain_name)
         try:
             return self.contract.functions.getPreviousNode(schain_id, node_id).call()
-        except ContractLogicError as e:
+        except (ContractLogicError, ValueError) as e:
             if NO_PREVIOUS_NODE_EXCEPTION_TEXT in str(e):
                 return None
             raise e
diff --git a/skale/contracts/manager/nodes.py b/skale/contracts/manager/nodes.py
index 03bfbe7c..86af9360 100644
--- a/skale/contracts/manager/nodes.py
+++ b/skale/contracts/manager/nodes.py
@@ -22,7 +22,7 @@
 from enum import IntEnum
 
 from Crypto.Hash import keccak
-from web3.exceptions import BadFunctionCallOutput
+from web3.exceptions import BadFunctionCallOutput, ContractLogicError
 
 from skale.contracts.base_contract import BaseContract, transaction_method
 from skale.transactions.result import TxRes
@@ -47,7 +47,7 @@ class Nodes(BaseContract):
     def __get_raw(self, node_id):
         try:
             return self.contract.functions.nodes(node_id).call()
-        except (ValueError, BadFunctionCallOutput):
+        except (ContractLogicError, ValueError, BadFunctionCallOutput):
             raise InvalidNodeIdError(node_id)
 
     def __get_raw_w_pk(self, node_id):
@@ -91,7 +91,7 @@ def get_active_node_ips(self):
 
     def name_to_id(self, name):
         keccak_hash = keccak.new(data=name.encode("utf8"), digest_bits=256)
-        return keccak_hash.hexdigest()
+        return keccak_hash.digest()
 
     def is_node_name_available(self, name):
         node_id = self.name_to_id(name)
@@ -108,25 +108,25 @@ def node_name_to_index(self, name):
     def get_node_status(self, node_id):
         try:
             return self.contract.functions.getNodeStatus(node_id).call()
-        except (ValueError, BadFunctionCallOutput):
+        except (ContractLogicError, ValueError, BadFunctionCallOutput):
             raise InvalidNodeIdError(node_id)
 
     def get_node_finish_time(self, node_id):
         try:
             return self.contract.functions.getNodeFinishTime(node_id).call()
-        except (ValueError, BadFunctionCallOutput):
+        except (ContractLogicError, ValueError, BadFunctionCallOutput):
             raise InvalidNodeIdError(node_id)
 
     def __get_node_public_key_raw(self, node_id):
         try:
             return self.contract.functions.getNodePublicKey(node_id).call()
-        except (ValueError, BadFunctionCallOutput):
+        except (ContractLogicError, ValueError, BadFunctionCallOutput):
             raise InvalidNodeIdError(node_id)
 
     def get_node_public_key(self, node_id):
         raw_key = self.__get_node_public_key_raw(node_id)
         key_bytes = raw_key[0] + raw_key[1]
-        return self.skale.web3.toHex(key_bytes)
+        return self.skale.web3.to_hex(key_bytes)
 
     def get_validator_node_indices(self, validator_id: int) -> list:
         """Returns list of node indices to the validator
@@ -136,6 +136,9 @@ def get_validator_node_indices(self, validator_id: int) -> list:
         """
         return self.contract.functions.getValidatorNodeIndexes(validator_id).call()
 
+    def get_last_change_ip_time(self, node_id: int) -> list:
+        return self.contract.functions.getLastChangeIpTime(node_id).call()
+
     @transaction_method
     def set_node_in_maintenance(self, node_id):
         return self.contract.functions.setNodeInMaintenance(node_id)
diff --git a/skale/contracts/manager/schains.py b/skale/contracts/manager/schains.py
index 74e4cb58..e12d18cd 100644
--- a/skale/contracts/manager/schains.py
+++ b/skale/contracts/manager/schains.py
@@ -180,3 +180,6 @@ def get_options(self, schain_id: str) -> SchainOptions:
     def get_options_by_name(self, name: str) -> SchainOptions:
         id_ = self.name_to_id(name)
         return self.get_options(id_)
+
+    def restart_schain_creation(self, name: str) -> TxRes:
+        return self.contract.functions.restartSchainCreation(name)
diff --git a/skale/schain_config/rotation_history.py b/skale/schain_config/rotation_history.py
index a1bb6d30..7ef488fe 100644
--- a/skale/schain_config/rotation_history.py
+++ b/skale/schain_config/rotation_history.py
@@ -32,7 +32,6 @@ def get_previous_schain_groups(
     skale: Skale,
     schain_name: str,
     leaving_node_id=None,
-    include_keys=True
 ) -> dict:
     """
     Returns all previous node groups with public keys and finish timestamps.
@@ -43,12 +42,8 @@ def get_previous_schain_groups(
 
     group_id = skale.schains.name_to_group_id(schain_name)
 
-    previous_public_keys = None
-    current_public_key = None
-
-    if include_keys:
-        previous_public_keys = skale.key_storage.get_all_previous_public_keys(group_id)
-        current_public_key = skale.key_storage.get_common_public_key(group_id)
+    previous_public_keys = skale.key_storage.get_all_previous_public_keys(group_id)
+    current_public_key = skale.key_storage.get_common_public_key(group_id)
 
     rotation = skale.node_rotation.get_rotation_obj(schain_name)
 
@@ -108,7 +103,6 @@ def _add_previous_schain_rotations_state(
     node_groups dictionary
     """
     previous_nodes = {}
-    node_to_finish_ts = {}
 
     for rotation_id in range(rotation.rotation_counter - 1, -1, -1):
         nodes = node_groups[rotation_id + 1]['nodes'].copy()
@@ -117,7 +111,6 @@ def _add_previous_schain_rotations_state(
                 previous_node = skale.node_rotation.get_previous_node(schain_name, node_id)
                 if previous_node is not None:
                     finish_ts = skale.node_rotation.get_schain_finish_ts(previous_node, schain_name)
-                    node_to_finish_ts[previous_node] = finish_ts
                     previous_nodes[node_id] = {
                         'finish_ts': finish_ts,
                         'previous_node_id': previous_node
@@ -128,8 +121,7 @@ def _add_previous_schain_rotations_state(
         public_key = skale.nodes.get_node_public_key(previous_node_id)
 
         current_finish_ts = previous_nodes[new_node_id]['finish_ts']
-        is_next_dkg_failed = new_node_id in node_to_finish_ts and \
-            current_finish_ts + 1 != node_to_finish_ts[new_node_id]
+        next_dkg_is_failed = current_finish_ts + 1 == node_groups[rotation_id + 1]['finish_ts']
 
         nodes[previous_node_id] = RotationNodeData(
             nodes[new_node_id].index,
@@ -138,12 +130,12 @@ def _add_previous_schain_rotations_state(
         )
         del nodes[new_node_id]
 
-        if not is_next_dkg_failed and previous_public_keys:
-            bls_public_key = _pop_previous_bls_public_key(previous_public_keys)
-            node_finish_ts = previous_nodes[new_node_id]['finish_ts']
+        bls_public_key = None
+        if not next_dkg_is_failed:
+            if len(previous_public_keys) > 0:
+                bls_public_key = _pop_previous_bls_public_key(previous_public_keys)
         else:
             bls_public_key = node_groups[rotation_id + 1]['bls_public_key']
-            node_finish_ts = previous_nodes[new_node_id]['finish_ts']
             node_groups[rotation_id + 1]['finish_ts'] = None
             node_groups[rotation_id + 1]['bls_public_key'] = None
 
@@ -155,7 +147,7 @@ def _add_previous_schain_rotations_state(
                 'new_node_id': new_node_id
             },
             'nodes': nodes,
-            'finish_ts': node_finish_ts,
+            'finish_ts': current_finish_ts,
             'bls_public_key': bls_public_key
         }
 
diff --git a/skale/transactions/exceptions.py b/skale/transactions/exceptions.py
index f4f17858..19c8cbd7 100644
--- a/skale/transactions/exceptions.py
+++ b/skale/transactions/exceptions.py
@@ -1,29 +1,79 @@
-from web3.exceptions import SolidityError
+from web3.exceptions import ContractLogicError
 
 
 class TransactionError(Exception):
+    """
+    Base exception for transaction related errors
+    """
     pass
 
 
-class DryRunFailedError(TransactionError):
+class ChainIdError(TransactionError):
+    """
+    Raised when chainId is missing or incorrect
+    """
     pass
 
 
-class InsufficientBalanceError(TransactionError):
+class TransactionNotSignedError(TransactionError):
+    """
+    Raised when transaction wasn't signed
+    """
     pass
 
 
 class TransactionNotSentError(TransactionError):
+    """
+    Raised when transaction wasn't sent
+    """
     pass
 
 
 class TransactionNotMinedError(TimeoutError, TransactionError):
+    """
+    Raised when transaction wasn't included in block within timeout
+    """
     pass
 
 
-class TransactionFailedError(TransactionError):
+class TransactionWaitError(TimeoutError, TransactionError):
+    """
+    Raised when error occurred during waiting for transaction
+    to be included in block
+    """
     pass
 
 
-class RevertError(TransactionError, SolidityError):
+class TransactionLogicError(TransactionError, ContractLogicError):
+    """
+    Raised when transaction executed with error
+    """
+    pass
+
+
+class DryRunFailedError(TransactionLogicError):
+    """
+    Raised when error occurred during dry run call
+    """
+    pass
+
+
+class TransactionFailedError(TransactionLogicError):
+    """
+    Raised when transaction included in the block failed during execution
+    """
+    pass
+
+
+class TransactionRevertError(TransactionFailedError):
+    """
+    Raised when transaction included in the block failed with revert
+    """
+    pass
+
+
+class DryRunRevertError(DryRunFailedError):
+    """
+    Raised when transaction reverted during dry run call
+    """
     pass
diff --git a/skale/transactions/result.py b/skale/transactions/result.py
index 1984e8f4..f5c0251f 100644
--- a/skale/transactions/result.py
+++ b/skale/transactions/result.py
@@ -17,57 +17,53 @@
 #   You should have received a copy of the GNU Affero General Public License
 #   along with SKALE.py.  If not, see <https://www.gnu.org/licenses/>.
 
+import enum
+from typing import NamedTuple
+
 from skale.transactions.exceptions import (
     DryRunFailedError,
-    RevertError,
+    DryRunRevertError,
     TransactionFailedError
 )
 
-SUCCESS_STATUS = 1
-
-
-def is_success(result: dict) -> bool:
-    return result.get('status') == SUCCESS_STATUS
 
+class TxStatus(int, enum.Enum):
+    FAILED = 0
+    SUCCESS = 1
 
-def is_success_or_not_performed(result: dict) -> bool:
-    return result is None or is_success(result)
 
-
-def is_revert_error(result: dict) -> bool:
-    return result and result.get('error', None) and 'reverted' in result['error'].lower()
+class TxCallResult(NamedTuple):
+    status: TxStatus
+    error: str
+    message: str
+    data: dict
 
 
 class TxRes:
-    def __init__(self, dry_run_result=None, tx_hash=None, receipt=None):
-        self.dry_run_result = dry_run_result
+    def __init__(self, tx_call_result=None, tx_hash=None, receipt=None, revert=None):
+        self.tx_call_result = tx_call_result
         self.tx_hash = tx_hash
         self.receipt = receipt
+        self.attempts = 0
 
     def __str__(self) -> str:
         return (
-            f'TxRes hash: {self.tx_hash}, dry_run_result {self.dry_run_result}, '
+            f'TxRes hash: {self.tx_hash}, tx_call_result {self.tx_call_result}, '
             f'receipt {self.receipt}'
         )
 
     def __repr__(self) -> str:
         return (
-            f'TxRes hash: {self.tx_hash}, dry_run_result {self.dry_run_result}, '
+            f'TxRes hash: {self.tx_hash}, tx_call_result {self.tx_call_result}, '
             f'receipt {self.receipt}'
         )
 
-    def dry_run_failed(self) -> bool:
-        return not is_success_or_not_performed(self.dry_run_result)
-
-    def tx_failed(self) -> bool:
-        return not is_success_or_not_performed(self.receipt)
-
     def raise_for_status(self) -> None:
-        if self.dry_run_failed():
-            if is_revert_error(self.dry_run_result):
-                raise RevertError(self.dry_run_result['error'])
-            raise DryRunFailedError(f'Dry run check failed. '
-                                    f'See result {self.dry_run_result}')
-        if self.tx_failed():
-            raise TransactionFailedError(f'Transaction failed. '
-                                         f'See receipt {self.receipt}')
+        if self.receipt is not None:
+            if self.receipt['status'] == TxStatus.FAILED:
+                raise TransactionFailedError(self.receipt)
+        elif self.tx_call_result is not None and self.tx_call_result.status == TxStatus.FAILED:
+            if self.tx_call_result.error == 'revert':
+                raise DryRunRevertError(self.tx_call_result.message)
+            else:
+                raise DryRunFailedError(self.tx_call_result.message)
diff --git a/skale/transactions/tools.py b/skale/transactions/tools.py
index 8b3d5800..f0451933 100644
--- a/skale/transactions/tools.py
+++ b/skale/transactions/tools.py
@@ -23,13 +23,13 @@
 from typing import Dict, Optional
 
 from web3 import Web3
+from web3.exceptions import ContractLogicError, Web3Exception
 from web3._utils.transactions import get_block_gas_limit
 
 import skale.config as config
 from skale.transactions.exceptions import TransactionError
-from skale.transactions.result import TxRes
+from skale.transactions.result import TxCallResult, TxRes, TxStatus
 from skale.utils.web3_utils import get_eth_nonce
-from skale.wallets.redis_wallet import RedisAdapterError
 
 
 logger = logging.getLogger(__name__)
@@ -38,7 +38,7 @@
 DEFAULT_ETH_SEND_GAS_LIMIT = 22000
 
 
-def make_dry_run_call(skale, method, gas_limit=None, value=0) -> dict:
+def make_dry_run_call(skale, method, gas_limit=None, value=0) -> TxCallResult:
     opts = {
         'from': skale.wallet.address,
         'value': value
@@ -49,6 +49,7 @@ def make_dry_run_call(skale, method, gas_limit=None, value=0) -> dict:
         f'wallet: {skale.wallet.__class__.__name__}, '
         f'value: {value}, '
     )
+    estimated_gas = 0
 
     try:
         if gas_limit:
@@ -58,11 +59,15 @@ def make_dry_run_call(skale, method, gas_limit=None, value=0) -> dict:
         else:
             estimated_gas = estimate_gas(skale.web3, method, opts)
         logger.info(f'Estimated gas for {method.fn_name}: {estimated_gas}')
-    except Exception as err:
-        logger.error('Dry run for method failed with error', exc_info=err)
-        return {'status': 0, 'error': str(err)}
+    except ContractLogicError as e:
+        return TxCallResult(status=TxStatus.FAILED,
+                            error='revert', message=e.message, data=e.data)
+    except (Web3Exception, ValueError) as e:
+        logger.exception('Dry run for %s failed', method)
+        return TxCallResult(status=TxStatus.FAILED, error='exception', message=str(e), data={})
 
-    return {'status': 1, 'payload': estimated_gas}
+    return TxCallResult(status=TxStatus.SUCCESS, error='',
+                        message='success', data={'gas': estimated_gas})
 
 
 def estimate_gas(web3, method, opts):
@@ -71,7 +76,7 @@ def estimate_gas(web3, method, opts):
     except AttributeError:
         block_gas_limit = get_block_gas_limit(web3)
 
-    estimated_gas = method.estimateGas(
+    estimated_gas = method.estimate_gas(
         opts,
         block_identifier='latest'
     )
@@ -87,7 +92,7 @@ def estimate_gas(web3, method, opts):
 
 def build_tx_dict(method, *args, **kwargs):
     base_fields = compose_base_fields(*args, **kwargs)
-    return method.buildTransaction(base_fields)
+    return method.build_transaction(base_fields)
 
 
 def compose_base_fields(
@@ -168,29 +173,43 @@ def wrapper(*args, **kwargs):
 
 def run_tx_with_retry(transaction, *args, max_retries=3,
                       retry_timeout=-1,
+                      raise_for_status=True,
                       **kwargs) -> TxRes:
-    success = False
     attempt = 0
     tx_res = None
     exp_timeout = 1
-    while not success and attempt < max_retries:
+    error = None
+    while attempt < max_retries:
         try:
-            tx_res = transaction(*args, **kwargs)
+            tx_res = transaction(
+                *args,
+                raise_for_status=raise_for_status,
+                **kwargs
+            )
             tx_res.raise_for_status()
-        except (RedisAdapterError, TransactionError) as err:
-            logger.error(f'Tx attempt {attempt}/{max_retries} failed',
-                         exc_info=err)
+        except TransactionError as e:
+            error = e
+            logger.exception('Tx attempt %d/%d failed', attempt + 1, max_retries)
+
             timeout = exp_timeout if retry_timeout < 0 else exp_timeout
             time.sleep(timeout)
             exp_timeout *= 2
         else:
-            success = True
+            error = None
+            break
         attempt += 1
-    if success:
-        logger.info(f'Tx {transaction.__name__} completed '
-                    f'after {attempt}/{max_retries} retries')
+    if error is None:
+        logger.info(
+            'Tx %s completed after %d/%d retries',
+            transaction.__name__, attempt + 1, max_retries
+        )
     else:
         logger.error(
-            f'Tx {transaction.__name__} failed after '
-            f'{max_retries} retries')
+            'Tx %s failed after %d retries',
+            transaction.__name__, max_retries
+        )
+        if raise_for_status:
+            raise error
+    if tx_res is not None:
+        tx_res.attempts = attempt
     return tx_res
diff --git a/skale/utils/account_tools.py b/skale/utils/account_tools.py
index 9c6605e7..cb438fe1 100644
--- a/skale/utils/account_tools.py
+++ b/skale/utils/account_tools.py
@@ -57,7 +57,7 @@ def send_tokens(
         f'{receiver_address}'
     )
 
-    wei_amount = skale.web3.toWei(amount, 'ether')
+    wei_amount = skale.web3.to_wei(amount, 'ether')
     return skale.token.transfer(
         receiver_address,
         wei_amount,
@@ -83,7 +83,7 @@ def send_eth(
         f'Sending {amount} ETH from {wallet.address} => '
         f'{receiver_address}'
     )
-    wei_amount = web3.toWei(amount, 'ether')
+    wei_amount = web3.to_wei(amount, 'ether')
     gas_price = gas_price or default_gas_price(web3)
     tx = compose_eth_transfer_tx(
         web3=web3,
@@ -111,12 +111,12 @@ def send_eth(
 
 
 def account_eth_balance_wei(web3, address):
-    return web3.eth.getBalance(address)
+    return web3.eth.get_balance(address)
 
 
 def check_ether_balance(web3, address):
     balance_wei = account_eth_balance_wei(web3, address)
-    balance = web3.fromWei(balance_wei, 'ether')
+    balance = web3.from_wei(balance_wei, 'ether')
 
     logger.info(f'{address} balance: {balance} ETH')
     return balance
@@ -124,7 +124,7 @@ def check_ether_balance(web3, address):
 
 def check_skale_balance(skale, address):
     balance_wei = skale.token.get_balance(address)
-    balance = skale.web3.fromWei(balance_wei, 'ether')
+    balance = skale.web3.from_wei(balance_wei, 'ether')
     logger.info(f'{address} balance: {balance} SKALE')
     return balance
 
diff --git a/skale/utils/contracts_provision/fake_multisig_contract.py b/skale/utils/contracts_provision/fake_multisig_contract.py
index 7c849806..915e0f99 100644
--- a/skale/utils/contracts_provision/fake_multisig_contract.py
+++ b/skale/utils/contracts_provision/fake_multisig_contract.py
@@ -84,6 +84,7 @@ def deploy_fake_multisig_contract(web3, wallet):
     tx = transaction_from_method(
         constructor,
         nonce=get_eth_nonce(web3, wallet.address),
+        gas_price=3 * 10 ** 9,
         gas_limit=FAKE_MULTISIG_CONSTRUCTOR_GAS
     )
     tx_hash = wallet.sign_and_send(tx)
diff --git a/skale/utils/contracts_provision/main.py b/skale/utils/contracts_provision/main.py
index 01b665ea..38542390 100644
--- a/skale/utils/contracts_provision/main.py
+++ b/skale/utils/contracts_provision/main.py
@@ -17,6 +17,7 @@
 #   You should have received a copy of the GNU Affero General Public License
 #   along with SKALE.py.  If not, see <https://www.gnu.org/licenses/>.
 
+from web3 import Web3
 
 from skale.contracts.manager.nodes import NodeStatus
 from skale.transactions.result import TxRes
@@ -41,14 +42,29 @@
 )
 
 
+DEFAULT_MINING_INTERVAL = 1000
 TEST_SRW_FUND_VALUE = 3000000000000000000
 
 
-def _skip_evm_time(web3, seconds) -> int:
-    """For test purposes only, works only with ganache node"""
-    res = web3.provider.make_request("evm_increaseTime", [seconds])
+def _skip_evm_time(web3: Web3, seconds: int, mine: bool = True) -> int:
+    """For test purposes only, works only with hardhat node"""
+    res = web3.provider.make_request('evm_increaseTime', [seconds])
     web3.provider.make_request("evm_mine", [])
-    return res['result']
+    return int(res['result'])
+
+
+def set_automining(web3: Web3, value: bool) -> int:
+    res = web3.provider.make_request('evm_setAutomine', [value])
+    return int(res['result'])
+
+
+def set_mining_interval(web3: Web3, ms: int) -> int:
+    res = web3.provider.make_request('evm_setIntervalMining', [ms])
+    return int(res['result'])
+
+
+def set_default_mining_interval(web3) -> int:
+    return set_mining_interval(web3, DEFAULT_MINING_INTERVAL)
 
 
 def add_test_permissions(skale):
diff --git a/skale/utils/exceptions.py b/skale/utils/exceptions.py
index 3ebd6098..a59912ae 100644
--- a/skale/utils/exceptions.py
+++ b/skale/utils/exceptions.py
@@ -46,7 +46,3 @@ class InvalidNodeIdError(Exception):
     def __init__(self, node_id):
         message = f'Node with ID = {node_id} doesn\'t exist!'
         super().__init__(message)
-
-
-class ChainIdError(ValueError):
-    """Raised when chainId is missing or incorrect"""
diff --git a/skale/utils/web3_utils.py b/skale/utils/web3_utils.py
index cda32c8c..eae748ea 100644
--- a/skale/utils/web3_utils.py
+++ b/skale/utils/web3_utils.py
@@ -71,6 +71,10 @@ class EthClientOutdatedError(Exception):
     pass
 
 
+class BlockWaitTimeoutError(Exception):
+    pass
+
+
 def get_last_known_block_number(state_path: str) -> int:
     if not os.path.isfile(state_path):
         return 0
@@ -98,7 +102,7 @@ def make_client_checking_middleware(allowed_ts_diff: int,
                                     state_path: str = None):
     def eth_client_checking_middleware(make_request, web3):
         def middleware(method, params):
-            if method in ('eth_blockNumber', 'eth_getBlockByNumber'):
+            if method in ('eth_block_number', 'eth_getBlockByNumber'):
                 response = make_request(method, params)
             else:
                 latest_block = web3.eth.get_block('latest')
@@ -178,7 +182,7 @@ def wait_for_receipt_by_blocks(
 ):
     blocks_to_wait = blocks_to_wait or DEFAULT_BLOCKS_TO_WAIT
     timeout = timeout or MAX_WAITING_TIME
-    previous_block = web3.eth.blockNumber
+    previous_block = web3.eth.block_number
     current_block = previous_block
     wait_start_time = time.time()
     while time.time() - wait_start_time < timeout and \
@@ -189,7 +193,7 @@ def wait_for_receipt_by_blocks(
             receipt = None
         if receipt is not None:
             return receipt
-        current_block = web3.eth.blockNumber
+        current_block = web3.eth.block_number
         time.sleep(3)
     raise TransactionNotMinedError(
         f'Transaction with hash: {tx} not found in {blocks_to_wait} blocks.'
@@ -227,7 +231,7 @@ def wait_for_confirmation_blocks(
     timeout=MAX_WAITING_TIME,
     request_timeout=5
 ):
-    current_block = start_block = web3.eth.blockNumber
+    current_block = start_block = web3.eth.block_number
     logger.info(
         f'Current block number is {current_block}, '
         f'waiting for {blocks_to_wait} confimration blocks to be mined'
@@ -235,19 +239,19 @@ def wait_for_confirmation_blocks(
     wait_start_time = time.time()
     while time.time() - wait_start_time < timeout and \
             current_block <= start_block + blocks_to_wait:
-        current_block = web3.eth.blockNumber
+        current_block = web3.eth.block_number
         time.sleep(request_timeout)
 
 
 def private_key_to_public(pr):
-    pr_bytes = Web3.toBytes(hexstr=pr)
+    pr_bytes = Web3.to_bytes(hexstr=pr)
     pk = keys.PrivateKey(pr_bytes)
     return pk.public_key
 
 
 def public_key_to_address(pk):
     hash = Web3.keccak(hexstr=str(pk))
-    return Web3.toHex(hash[-20:])
+    return Web3.to_hex(hash[-20:])
 
 
 def private_key_to_address(pr):
@@ -256,7 +260,7 @@ def private_key_to_address(pr):
 
 
 def to_checksum_address(address):
-    return Web3.toChecksumAddress(address)
+    return Web3.to_checksum_address(address)
 
 
 def wallet_to_public_key(wallet):
diff --git a/skale/wallets/__init__.py b/skale/wallets/__init__.py
index a3b2cc4f..a5d7b685 100644
--- a/skale/wallets/__init__.py
+++ b/skale/wallets/__init__.py
@@ -3,6 +3,5 @@
 from skale.wallets.common import BaseWallet
 from skale.wallets.ledger_wallet import LedgerWallet
 from skale.wallets.redis_wallet import RedisWalletAdapter
-from skale.wallets.rpc_wallet import RPCWallet
 from skale.wallets.sgx_wallet import SgxWallet
 from skale.wallets.web3_wallet import Web3Wallet
diff --git a/skale/wallets/common.py b/skale/wallets/common.py
index 3a601f87..bb97ee8c 100644
--- a/skale/wallets/common.py
+++ b/skale/wallets/common.py
@@ -20,16 +20,23 @@
 from abc import ABC, abstractmethod
 from typing import Dict, Optional
 
-from skale.utils.exceptions import ChainIdError
+from skale.transactions.exceptions import ChainIdError
 
 
 def ensure_chain_id(tx_dict, web3):
     if not tx_dict.get('chainId'):
-        tx_dict['chainId'] = web3.eth.chainId
+        tx_dict['chainId'] = web3.eth.chain_id
     if not tx_dict.get('chainId'):
         raise ChainIdError('chainId must be in tx_dict (see EIP-155)')
 
 
+class MessageNotSignedError(Exception):
+    """
+    Raised when signing message failed
+    """
+    pass
+
+
 class BaseWallet(ABC):
     @abstractmethod
     def sign(self, tx):
diff --git a/skale/wallets/ledger_wallet.py b/skale/wallets/ledger_wallet.py
index ddec695c..6d2638e0 100644
--- a/skale/wallets/ledger_wallet.py
+++ b/skale/wallets/ledger_wallet.py
@@ -29,8 +29,10 @@
 
 from eth_utils.crypto import keccak
 from rlp import encode
+from web3.exceptions import Web3Exception
 
 import skale.config as config
+from skale.transactions.exceptions import TransactionNotSentError, TransactionNotSignedError
 from skale.utils.web3_utils import (
     get_eth_nonce,
     public_key_to_address,
@@ -157,14 +159,16 @@ def exchange_sign_payload_by_chunks(self, payload):
 
     def sign(self, tx_dict):
         ensure_chain_id(tx_dict, self._web3)
-        if config.ENV == 'dev':  # fix for big chainId in ganache
-            tx_dict['chainId'] = None
         if tx_dict.get('nonce') is None:
-            tx_dict['nonce'] = self._web3.eth.getTransactionCount(self.address)
+            tx_dict['nonce'] = self._web3.eth.get_transaction_count(self.address)
+
         tx = tx_from_dict(tx_dict)
-        payload = self.make_payload(tx)
-        exchange_result = self.exchange_sign_payload_by_chunks(payload)
-        return LedgerWallet.parse_sign_result(tx, exchange_result)
+        try:
+            payload = self.make_payload(tx)
+            exchange_result = self.exchange_sign_payload_by_chunks(payload)
+            return LedgerWallet.parse_sign_result(tx, exchange_result)
+        except Exception as e:
+            raise TransactionNotSignedError(e)
 
     def sign_and_send(
         self,
@@ -175,9 +179,12 @@ def sign_and_send(
         meta: Optional[Dict] = None
     ) -> str:
         signed_tx = self.sign(tx)
-        return self._web3.eth.sendRawTransaction(
-            signed_tx.rawTransaction
-        ).hex()
+        try:
+            return self._web3.eth.send_raw_transaction(
+                signed_tx.rawTransaction
+            ).hex()
+        except (ValueError, Web3Exception) as e:
+            raise TransactionNotSentError(e)
 
     def sign_hash(self, unsigned_hash: str):
         raise NotImplementedError(
@@ -220,13 +227,13 @@ def wait(self, tx_hash: str, blocks_to_wait=None, timeout=None):
 def hardware_sign_and_send(web3, method, gas_amount, wallet) -> str:
     address_from = wallet['address']
     eth_nonce = get_eth_nonce(web3, address_from)
-    tx_dict = method.buildTransaction({
+    tx_dict = method.build_transaction({
         'gas': gas_amount,
         'nonce': eth_nonce
     })
     signed_txn = wallet.sign(tx_dict)
-    tx = web3.eth.sendRawTransaction(signed_txn.rawTransaction).hex()
+    tx = web3.eth.send_raw_transaction(signed_txn.rawTransaction).hex()
     logger.info(
-        f'{method.__class__.__name__} - transaction_hash: {web3.toHex(tx)}'
+        f'{method.__class__.__name__} - transaction_hash: {web3.to_hex(tx)}'
     )
     return tx
diff --git a/skale/wallets/redis_wallet.py b/skale/wallets/redis_wallet.py
index 150b2664..2d68b71f 100644
--- a/skale/wallets/redis_wallet.py
+++ b/skale/wallets/redis_wallet.py
@@ -22,37 +22,53 @@
 import logging
 import os
 import time
+from enum import Enum
 from typing import Dict, Optional, Tuple
 
 from redis import Redis
 
 import skale.config as config
+from skale.transactions.exceptions import (
+    TransactionError,
+    TransactionNotMinedError,
+    TransactionNotSentError,
+    TransactionWaitError
+)
 from skale.utils.web3_utils import get_receipt, MAX_WAITING_TIME
 from skale.wallets import BaseWallet
 
 logger = logging.getLogger(__name__)
 
 
-class RedisAdapterError(Exception):
+class RedisWalletError(Exception):
     pass
 
 
-class DroppedError(RedisAdapterError):
+class RedisWalletDroppedError(RedisWalletError, TransactionNotMinedError):
     pass
 
 
-class EmptyStatusError(RedisAdapterError):
+class RedisWalletEmptyStatusError(RedisWalletError, TransactionError):
     pass
 
 
-class AdapterSendError(RedisAdapterError):
+class RedisWalletNotSentError(RedisWalletError, TransactionNotSentError):
     pass
 
 
-class AdapterWaitError(RedisAdapterError):
+class RedisWalletWaitError(RedisWalletError, TransactionWaitError):
     pass
 
 
+class TxRecordStatus(str, Enum):
+    DROPPED = 'DROPPED'
+    SUCCESS = 'SUCCESS'
+    FAILED = 'FAILED'
+
+    def __str__(self) -> str:
+        return str.__str__(self)
+
+
 class RedisWalletAdapter(BaseWallet):
     ID_SIZE = 16
 
@@ -150,7 +166,7 @@ def sign_and_send(
             return self._to_id(raw_id)
         except Exception as err:
             logger.exception(f'Sending {tx} with redis wallet errored')
-            raise AdapterSendError(err)
+            raise RedisWalletNotSentError(err)
 
     def get_status(self, tx_id: str) -> str:
         return self.get_record(tx_id)['status']
@@ -166,23 +182,28 @@ def wait(
         timeout: int = MAX_WAITING_TIME
     ) -> Dict:
         start_ts = time.time()
-        status = None
-
-        while time.time() - start_ts < timeout:
+        status, result = None, None
+        while status not in [
+            TxRecordStatus.DROPPED,
+            TxRecordStatus.SUCCESS,
+            TxRecordStatus.FAILED
+        ] and time.time() - start_ts < timeout:
             try:
-                status = self.get_status(tx_id)
-                if status == 'DROPPED':
-                    break
-                if status in ('SUCCESS', 'FAILED'):
-                    r = self.get_record(tx_id)
-                    return get_receipt(self.wallet._web3, r['tx_hash'])
-            except Exception as err:
-                logger.exception(f'Waiting for tx {tx_id} errored')
-                raise AdapterWaitError(err)
+                record = self.get_record(tx_id)
+                if record is not None:
+                    status = record.get('status')
+                    if status in (TxRecordStatus.SUCCESS, TxRecordStatus.FAILED):
+                        result = get_receipt(self.wallet._web3, record['tx_hash'])
+            except Exception as e:
+                logger.exception('Waiting for tx %s errored', tx_id)
+                raise RedisWalletWaitError(e)
+
+        if result:
+            return result
 
         if status is None:
-            raise EmptyStatusError('Tx status is None')
-        if status == 'DROPPED':
-            raise DroppedError('Tx was dropped after max retries')
+            raise RedisWalletEmptyStatusError(f'Tx status is {status}')
+        elif status == TxRecordStatus.DROPPED:
+            raise RedisWalletDroppedError('Tx was dropped after max retries')
         else:
-            raise AdapterWaitError(f'Tx finished with status {status}')
+            raise RedisWalletWaitError(f'Tx finished with status {status}')
diff --git a/skale/wallets/rpc_wallet.py b/skale/wallets/rpc_wallet.py
deleted file mode 100644
index 5def77cc..00000000
--- a/skale/wallets/rpc_wallet.py
+++ /dev/null
@@ -1,99 +0,0 @@
-#   -*- coding: utf-8 -*-
-#
-#   This file is part of SKALE.py
-#
-#   Copyright (C) 2019-Present SKALE Labs
-#
-#   SKALE.py is free software: you can redistribute it and/or modify
-#   it under the terms of the GNU Affero General Public License as published by
-#   the Free Software Foundation, either version 3 of the License, or
-#   (at your option) any later version.
-#
-#   SKALE.py is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU Affero General Public License for more details.
-#
-#   You should have received a copy of the GNU Affero General Public License
-#   along with SKALE.py.  If not, see <https://www.gnu.org/licenses/>.
-
-import functools
-import json
-import time
-import logging
-import urllib
-
-import requests
-
-from skale.utils.exceptions import RPCWalletError
-from skale.wallets.sgx_wallet import SgxWallet
-
-
-logger = logging.getLogger(__name__)
-
-
-ATTEMPTS = 100
-TIMEOUTS = [2 ** p for p in range(ATTEMPTS)]
-
-
-def rpc_request(func):
-    @functools.wraps(func)
-    def wrapper(self, route, *args, **kwargs):
-        data, error, response = None, None, None
-        for i, timeout in enumerate(TIMEOUTS):
-            logger.info(f'Sending wallet rpc {route} request. Attempt {i}')
-            try:
-                response = func(self, route, *args, **kwargs).json()
-                data, error = response.get('data'), response.get('error')
-            except Exception as err:
-                error = 'RPC request failed'
-                logger.error(error, exc_info=err)
-
-            if isinstance(error, str) and \
-                error.startswith('Dry run failed') or \
-                    not error or not self._retry_if_failed:
-                break
-
-            logger.info(f'Sleeping {timeout}s ...')
-            time.sleep(timeout)
-
-        if error is not None:
-            raise RPCWalletError(error)
-        logger.info(f'Rpc wallet {route} request returned {data}')
-        return data
-    return wrapper
-
-
-class RPCWallet(SgxWallet):
-    def __init__(self, url, sgx_endpoint, web3, key_name=None,
-                 path_to_cert=None, retry_if_failed=False) -> None:
-        super().__init__(sgx_endpoint=sgx_endpoint,
-                         web3=web3, key_name=key_name,
-                         path_to_cert=path_to_cert)
-        self._url = url
-        self._retry_if_failed = retry_if_failed
-
-    @classmethod
-    def _construct_url(cls, host, url):
-        return urllib.parse.urljoin(host, url)
-
-    @rpc_request
-    def _post(self, route, data):
-        request_url = self._construct_url(self._url, route)
-        return requests.post(request_url, json=data)
-
-    @rpc_request
-    def _get(self, route, data=None):
-        request_url = self._construct_url(self._url, route)
-        return requests.get(request_url, data=data)
-
-    @classmethod
-    def _compose_tx_data(cls, tx_dict):
-        return {
-            'transaction_dict': json.dumps(tx_dict)
-        }
-
-    def sign_and_send(self, tx_dict):
-        data = self._post('/sign-and-send',
-                          self._compose_tx_data(tx_dict))
-        return data['transaction_hash']
diff --git a/skale/wallets/sgx_wallet.py b/skale/wallets/sgx_wallet.py
index 6ffa6318..c2053bce 100644
--- a/skale/wallets/sgx_wallet.py
+++ b/skale/wallets/sgx_wallet.py
@@ -22,10 +22,12 @@
 
 from sgx import SgxClient
 from web3 import Web3
+from web3.exceptions import Web3Exception
 
 import skale.config as config
+from skale.transactions.exceptions import TransactionNotSentError, TransactionNotSignedError
 from skale.utils.web3_utils import get_eth_nonce, wait_for_receipt_by_blocks
-from skale.wallets.common import BaseWallet, ensure_chain_id
+from skale.wallets.common import BaseWallet, ensure_chain_id, MessageNotSignedError
 
 
 logger = logging.getLogger(__name__)
@@ -45,7 +47,10 @@ def sign(self, tx_dict):
         if tx_dict.get('nonce') is None:
             tx_dict['nonce'] = get_eth_nonce(self._web3, self._address)
         ensure_chain_id(tx_dict, self._web3)
-        return self.sgx_client.sign(tx_dict, self.key_name)
+        try:
+            return self.sgx_client.sign(tx_dict, self.key_name)
+        except Exception as e:
+            raise TransactionNotSignedError(e)
 
     def sign_and_send(
         self,
@@ -56,9 +61,12 @@ def sign_and_send(
         meta: Optional[Dict] = None
     ) -> str:
         signed_tx = self.sign(tx_dict)
-        return self._web3.eth.sendRawTransaction(
-            signed_tx.rawTransaction
-        ).hex()
+        try:
+            return self._web3.eth.send_raw_transaction(
+                signed_tx.rawTransaction
+            ).hex()
+        except (ValueError, Web3Exception) as e:
+            raise TransactionNotSentError(e)
 
     def sign_hash(self, unsigned_hash: str):
         if unsigned_hash.startswith('0x'):
@@ -69,11 +77,14 @@ def sign_hash(self, unsigned_hash: str):
         normalized_hash = header + body
         hash_to_sign = Web3.keccak(hexstr='0x' + normalized_hash.hex())
         chain_id = None
-        return self.sgx_client.sign_hash(
-            hash_to_sign,
-            self._key_name,
-            chain_id
-        )
+        try:
+            return self.sgx_client.sign_hash(
+                hash_to_sign,
+                self._key_name,
+                chain_id
+            )
+        except Exception as e:
+            raise MessageNotSignedError(e)
 
     @property
     def address(self):
diff --git a/skale/wallets/web3_wallet.py b/skale/wallets/web3_wallet.py
index 5c6f2fc4..64b9faf5 100644
--- a/skale/wallets/web3_wallet.py
+++ b/skale/wallets/web3_wallet.py
@@ -21,21 +21,26 @@
 from eth_keys import keys
 from web3 import Web3
 from eth_account import messages
+from web3.exceptions import Web3Exception
 
 import skale.config as config
+from skale.transactions.exceptions import (
+    TransactionNotSignedError,
+    TransactionNotSentError
+)
 from skale.utils.web3_utils import get_eth_nonce, wait_for_receipt_by_blocks
-from skale.wallets.common import BaseWallet, ensure_chain_id
+from skale.wallets.common import BaseWallet, ensure_chain_id, MessageNotSignedError
 
 
 def private_key_to_public(pr):
-    pr_bytes = Web3.toBytes(hexstr=pr)
+    pr_bytes = Web3.to_bytes(hexstr=pr)
     pk = keys.PrivateKey(pr_bytes)
     return pk.public_key
 
 
 def public_key_to_address(pk):
     hash = Web3.keccak(hexstr=str(pk))
-    return to_checksum_address(Web3.toHex(hash[-20:]))
+    return to_checksum_address(Web3.to_hex(hash[-20:]))
 
 
 def private_key_to_address(pr):
@@ -44,7 +49,7 @@ def private_key_to_address(pr):
 
 
 def to_checksum_address(address):
-    return Web3.toChecksumAddress(address)
+    return Web3.to_checksum_address(address)
 
 
 def generate_wallet(web3):
@@ -65,17 +70,23 @@ def sign(self, tx_dict):
         if not tx_dict.get('nonce'):
             tx_dict['nonce'] = get_eth_nonce(self._web3, self._address)
         ensure_chain_id(tx_dict, self._web3)
-        return self._web3.eth.account.sign_transaction(
-            tx_dict,
-            private_key=self._private_key
-        )
+        try:
+            return self._web3.eth.account.sign_transaction(
+                tx_dict,
+                private_key=self._private_key
+            )
+        except (TypeError, ValueError, Web3Exception) as e:
+            raise TransactionNotSignedError(e)
 
     def sign_hash(self, unsigned_hash: str):
-        unsigned_message = messages.encode_defunct(hexstr=unsigned_hash)
-        return self._web3.eth.account.sign_message(
-            unsigned_message,
-            private_key=self._private_key
-        )
+        try:
+            unsigned_message = messages.encode_defunct(hexstr=unsigned_hash)
+            return self._web3.eth.account.sign_message(
+                unsigned_message,
+                private_key=self._private_key
+            )
+        except (TypeError, ValueError, Web3Exception) as e:
+            raise MessageNotSignedError(e)
 
     def sign_and_send(
         self,
@@ -86,9 +97,12 @@ def sign_and_send(
         meta: Optional[Dict] = None
     ) -> str:
         signed_tx = self.sign(tx_dict)
-        return self._web3.eth.sendRawTransaction(
-            signed_tx.rawTransaction
-        ).hex()
+        try:
+            return self._web3.eth.send_raw_transaction(
+                signed_tx.rawTransaction
+            ).hex()
+        except (ValueError, Web3Exception) as e:
+            raise TransactionNotSentError(e)
 
     @property
     def address(self):


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 0942a1ba..d999019b 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -3,15 +3,15 @@ on: [push, pull_request]
 
 jobs:
   test_manager:
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-20.04
     strategy:
       matrix:
-        python-version: [3.7]
+        python-version: [3.11]
     env:
       ETH_PRIVATE_KEY: ${{ secrets.ETH_PRIVATE_KEY }}
       ENDPOINT: ${{ secrets.ENDPOINT }}
       CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
-      MANAGER_TAG: "1.9.3-custom-release-history.1.0"
+      MANAGER_TAG: "1.10.0-v1.10.0.0"
     steps:
     - uses: actions/checkout@v2
       with:
@@ -20,27 +20,49 @@ jobs:
       uses: actions/setup-python@v1
       with:
         python-version: ${{ matrix.python-version }}
-    - name: Install host dependencies
-      run: bash ./scripts/install_host_dependencies.sh
+
     - name: Install python dependencies
       run: bash ./scripts/install_python_dependencies.sh
+
     - name: Lint with flake8
       run: flake8 .
-    - name: Deploy manager contracts
+
+    - name: Launch hardhat node
+      working-directory: hardhat-node
+      run: |
+        docker-compose up -d && sleep 20 
+
+    - name: Deploy manager
       run: |
         bash ./helper-scripts/deploy_test_manager.sh
+        docker rmi -f skalenetwork/skale-manager:${{ env.MANAGER_TAG }}
+
+    - name: Show stats before tests
+      if: always()
+      run: | 
+        sudo lsblk -f
+        sudo free -h
+
     - name: Run tests
       run: |
         bash ./scripts/run_manager_tests.sh
     - name: Codecov
       run: |
         codecov -t $CODECOV_TOKEN
+
+    - name: Show stats after tests
+      if: always()
+      run: | 
+        sudo lsblk -f
+        sudo free -h
+
   test_allocator:
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-20.04
     strategy:
       matrix:
-        python-version: [3.7]
+        python-version: [3.11]
     env:
+      ENDPOINT: ${{ secrets.ENDPOINT }}
       ETH_PRIVATE_KEY: ${{ secrets.ETH_PRIVATE_KEY }}
       MANAGER_TAG: "1.9.0-develop.20"
       ALLOCATOR_TAG: "2.2.2-develop.0"
@@ -48,17 +70,39 @@ jobs:
     - uses: actions/checkout@v2
       with:
         submodules: true
+
     - name: Set up Python ${{ matrix.python-version }}
       uses: actions/setup-python@v1
       with:
         python-version: ${{ matrix.python-version }}
+
     - name: Install host dependencies
       run: bash ./scripts/install_host_dependencies.sh
+
     - name: Install python dependencies
       run: bash ./scripts/install_python_dependencies.sh
+
+    - name: Launch hardhat node
+      working-directory: hardhat-node
+      run: |
+        docker-compose up -d && sleep 20 
+
+    - name: Deploy manager contracts
+      run: |
+        bash ./helper-scripts/deploy_test_manager.sh
+        docker rmi -f skalenetwork/skale-manager:${{ env.MANAGER_TAG }}
+
     - name: Deploy allocator contracts
       run: |
-        bash ./helper-scripts/deploy_test_allocator.sh 
+        bash ./helper-scripts/deploy_test_allocator.sh
+        docker rmi -f skalenetwork/skale-allocator:${{ env.ALLOCATOR_TAG }}
+
     - name: Run tests
       run: |
         bash ./scripts/run_allocator_tests.sh
+
+    - name: Show stats after tests
+      if: always()
+      run: | 
+        sudo lsblk -f
+        sudo free -h
diff --git a/tests/conftest.py b/tests/conftest.py
index e639b034..488a1b3d 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -17,6 +17,11 @@
     link_nodes_to_validator,
     setup_validator
 )
+from skale.utils.contracts_provision.main import (
+    set_automining,
+    set_default_mining_interval,
+    set_mining_interval
+)
 from skale.utils.contracts_provision.fake_multisig_contract import (
     deploy_fake_multisig_contract
 )
@@ -117,9 +122,22 @@ def empty_account():
 def failed_skale(skale):
     tmp_wait, tmp_sign_and_send = skale.wallet.wait, skale.wallet.sign_and_send
     skale.wallet.sign_and_send = mock.Mock(return_value='0x000000000')
-    skale.wallet.wait = mock.Mock(return_value={'status': 0})
+    skale.wallet.wait = mock.Mock(return_value={'status': 0, 'error': 'Test error'})
     try:
         yield skale
     finally:
         skale.wallet.sign_and_send = tmp_sign_and_send
         skale.wallet.wait = tmp_wait
+
+
+@pytest.fixture
+def block_in_seconds(skale):
+    # Mine block every three seconds without automine
+    # Makes web3.py throw exception in a same way as for geth
+    try:
+        set_automining(skale.web3, False)
+        set_mining_interval(skale.web3, 3)
+        yield
+    finally:
+        set_automining(skale.web3, True)
+        set_default_mining_interval(skale.web3)
diff --git a/tests/main_test.py b/tests/main_test.py
index 37d54320..bf269f62 100644
--- a/tests/main_test.py
+++ b/tests/main_test.py
@@ -11,6 +11,7 @@
 from tests.constants import TEST_CONTRACT_NAME, ENDPOINT, TEST_ABI_FILEPATH, ETH_PRIVATE_KEY
 from skale.utils.contracts_provision.main import _skip_evm_time
 
+ALLOWED_SKIP_TIME_GAP = 10
 DEFAULT_CONTRACTS_NUMBER = 1
 
 
@@ -27,7 +28,7 @@ def test_lib_init():
         assert issubclass(type(lib_contract), BaseContract)
         assert lib_contract.address is not None
         assert int(lib_contract.address, 16) != 0
-        assert web3.eth.getCode(lib_contract.address)
+        assert web3.eth.get_code(lib_contract.address)
         assert skale.web3.provider._request_kwargs == {'timeout': 20}
 
     isinstance(skale.web3.provider, HTTPProvider)
@@ -77,8 +78,9 @@ def test_get_attr(skale):
     assert isinstance(skale_py_nodes_contract, Nodes)
 
 
+@pytest.mark.skip('Fragile')
 def test_skip_evm_time(skale):
     seconds = 10
-    old_time = _skip_evm_time(skale.web3, 0)
-    new_time = _skip_evm_time(skale.web3, seconds)
-    assert new_time == old_time + seconds
+    old_time = _skip_evm_time(skale.web3, 0, mine=False)
+    new_time = _skip_evm_time(skale.web3, seconds, mine=False)
+    assert new_time - (old_time + seconds) < ALLOWED_SKIP_TIME_GAP
diff --git a/tests/manager/base_contract_test.py b/tests/manager/base_contract_test.py
index e3d8acfb..5c3aeb8a 100644
--- a/tests/manager/base_contract_test.py
+++ b/tests/manager/base_contract_test.py
@@ -4,6 +4,8 @@
 from unittest import mock
 import pytest
 import skale.config as config
+from skale.transactions.exceptions import TransactionNotSentError
+from skale.transactions.result import TxStatus
 from skale.transactions.tools import estimate_gas
 from skale.utils.account_tools import generate_account
 from skale.utils.contracts_provision.utils import generate_random_schain_data
@@ -19,14 +21,14 @@
 def test_dry_run(skale):
     account = generate_account(skale.web3)
     address_to = account['address']
-    address_from = Web3.toChecksumAddress(skale.wallet.address)
-    address_to = Web3.toChecksumAddress(address_to)
+    address_from = Web3.to_checksum_address(skale.wallet.address)
+    address_to = Web3.to_checksum_address(address_to)
     balance_from_before = skale.token.get_balance(address_from)
     balance_to_before = skale.token.get_balance(address_to)
     amount = 10 * ETH_IN_WEI
     tx_res = skale.token.transfer(address_to, amount, dry_run_only=True)
-    assert isinstance(tx_res.dry_run_result['payload'], int)
-    assert tx_res.dry_run_result['status'] == 1
+    assert isinstance(tx_res.tx_call_result.data['gas'], int)
+    assert tx_res.tx_call_result.status == TxStatus.SUCCESS
     tx_res.raise_for_status()
 
     balance_from_after = skale.token.get_balance(address_from)
@@ -53,7 +55,7 @@ def test_disable_dry_run_env(skale, disable_dry_run_env):
     address_to = account['address']
     amount = 10 * ETH_IN_WEI
     with mock.patch(
-        'skale.contracts.base_contract.execute_dry_run'
+        'skale.contracts.base_contract.make_dry_run_call'
     ) as dry_run_mock:
         skale.token.transfer(address_to, amount)
         dry_run_mock.assert_not_called()
@@ -62,8 +64,8 @@ def test_disable_dry_run_env(skale, disable_dry_run_env):
 def test_skip_dry_run(skale):
     account = generate_account(skale.web3)
     address_to = account['address']
-    address_from = Web3.toChecksumAddress(skale.wallet.address)
-    address_to = Web3.toChecksumAddress(address_to)
+    address_from = Web3.to_checksum_address(skale.wallet.address)
+    address_to = Web3.to_checksum_address(address_to)
     balance_from_before = skale.token.get_balance(address_from)
     balance_to_before = skale.token.get_balance(address_to)
     amount = 10 * ETH_IN_WEI
@@ -75,7 +77,7 @@ def test_skip_dry_run(skale):
     )
     assert tx_res.tx_hash is not None, tx_res
     assert tx_res.receipt is not None
-    assert tx_res.dry_run_result is None
+    assert tx_res.tx_call_result is None
     balance_from_after = skale.token.get_balance(address_from)
     assert balance_from_after == balance_from_before - amount
     balance_to_after = skale.token.get_balance(address_to)
@@ -86,8 +88,8 @@ def test_wait_for_false(skale):
     ETH_IN_WEI = 10 ** 18
     account = generate_account(skale.web3)
     address_to = account['address']
-    address_from = Web3.toChecksumAddress(skale.wallet.address)
-    address_to = Web3.toChecksumAddress(address_to)
+    address_from = Web3.to_checksum_address(skale.wallet.address)
+    address_to = Web3.to_checksum_address(address_to)
     balance_from_before = skale.token.get_balance(address_from)
     balance_to_before = skale.token.get_balance(address_to)
     amount = 10 * ETH_IN_WEI
@@ -95,8 +97,8 @@ def test_wait_for_false(skale):
     tx_res = skale.token.transfer(address_to, amount, wait_for=False)
     assert tx_res.tx_hash is not None
     assert tx_res.receipt is None
-    assert isinstance(tx_res.dry_run_result['payload'], int)
-    assert tx_res.dry_run_result['status'] == 1
+    assert isinstance(tx_res.tx_call_result.data['gas'], int)
+    assert tx_res.tx_call_result.status == TxStatus.SUCCESS
 
     tx_res.receipt = wait_for_receipt_by_blocks(skale.web3, tx_res.tx_hash)
     tx_res.raise_for_status()
@@ -112,7 +114,7 @@ def test_tx_res_dry_run(skale):
     token_amount = 10
     tx_res = skale.token.transfer(
         account['address'], token_amount, dry_run_only=True)
-    assert tx_res.dry_run_result is not None
+    assert tx_res.tx_call_result is not None
     assert tx_res.tx_hash is None
     assert tx_res.receipt is None
     tx_res.raise_for_status()
@@ -144,7 +146,7 @@ def test_tx_res_with_insufficient_funds(skale):
     account = generate_account(skale.web3)
     token_amount = 9
     huge_gas_price = 10 ** 22
-    with pytest.raises(ValueError):
+    with pytest.raises(TransactionNotSentError):
         skale.token.transfer(
             account['address'],
             token_amount,
@@ -156,16 +158,16 @@ def test_confirmation_blocks(skale):
     account = generate_account(skale.web3)
     token_amount = 10
     confirmation_blocks = 0  # todo: enable mining on ganache
-    start_block = skale.web3.eth.blockNumber
+    start_block = skale.web3.eth.block_number
     skale.token.transfer(account['address'], token_amount, confirmation_blocks=confirmation_blocks)
-    assert skale.web3.eth.blockNumber >= start_block + confirmation_blocks
+    assert skale.web3.eth.block_number >= start_block + confirmation_blocks
 
 
 def test_block_limit_estimate_gas(skale):
     account = generate_account(skale.web3)
     token_amount = 10
     max_gas = 200000000
-    with mock.patch.object(skale.token.contract.functions.transfer, 'estimateGas',
+    with mock.patch.object(skale.token.contract.functions.transfer, 'estimate_gas',
                            new=mock.Mock(return_value=max_gas)):
         method = skale.token.contract.functions.transfer(account['address'], token_amount)
         res = estimate_gas(skale.web3, method, {'from': skale.wallet.address})
diff --git a/tests/manager/constants_test.py b/tests/manager/constants_test.py
index e2de8047..4f804026 100644
--- a/tests/manager/constants_test.py
+++ b/tests/manager/constants_test.py
@@ -3,7 +3,7 @@
 
 
 from tests.constants import NEW_REWARD_PERIOD, NEW_DELTA_PERIOD
-from skale.transactions.result import RevertError
+from skale.transactions.result import DryRunRevertError
 
 
 def test_get_set_periods(skale):
@@ -42,7 +42,7 @@ def test_get_set_latency(skale):
 def test_get_set_launch_timestamp(skale):
     launch_ts = skale.constants_holder.get_launch_timestamp()
     assert isinstance(launch_ts, int)
-    with pytest.raises(RevertError):
+    with pytest.raises(DryRunRevertError):
         skale.constants_holder.set_launch_timestamp(launch_ts, wait_for=True)
 
 
diff --git a/tests/manager/delegation/delegation_controller_test.py b/tests/manager/delegation/delegation_controller_test.py
index 35885723..e8ec4249 100644
--- a/tests/manager/delegation/delegation_controller_test.py
+++ b/tests/manager/delegation/delegation_controller_test.py
@@ -1,17 +1,22 @@
 """ Tests for contracts/delegation/delegation_controller.py """
 
-from datetime import date
-
 import pytest
 
-from skale.utils.contracts_provision.utils import generate_random_name
 from skale.contracts.manager.delegation.delegation_controller import FIELDS
-from skale.transactions.result import RevertError
+from skale.transactions.exceptions import ContractLogicError
+from skale.transactions.result import DryRunRevertError
 from skale.utils.contracts_provision.main import _skip_evm_time
+from skale.utils.contracts_provision.utils import generate_random_name
 
-from tests.constants import (NOT_EXISTING_ID, D_DELEGATION_INFO, D_VALIDATOR_ID,
-                             D_DELEGATION_AMOUNT, D_DELEGATION_PERIOD, DELEGATION_STRUCT_LEN,
-                             MONTH_IN_SECONDS)
+from tests.constants import (
+    NOT_EXISTING_ID,
+    D_DELEGATION_INFO,
+    D_VALIDATOR_ID,
+    D_DELEGATION_AMOUNT,
+    D_DELEGATION_PERIOD,
+    DELEGATION_STRUCT_LEN,
+    MONTH_IN_SECONDS
+)
 
 
 def _delegate_and_activate(skale, validator_id=D_VALIDATOR_ID):
@@ -29,7 +34,7 @@ def _delegate_and_activate(skale, validator_id=D_VALIDATOR_ID):
         delegations[-1]['id'],
         wait_for=True
     )
-    _skip_evm_time(skale.web3, MONTH_IN_SECONDS)
+    _skip_evm_time(skale.web3, MONTH_IN_SECONDS, mine=False)
 
 
 def _get_number_of_delegations(skale, validator_id=D_VALIDATOR_ID):
@@ -37,7 +42,7 @@ def _get_number_of_delegations(skale, validator_id=D_VALIDATOR_ID):
 
 
 def test_get_raw_not_exist(skale):
-    with pytest.raises(ValueError):
+    with pytest.raises((ContractLogicError, ValueError)):
         skale.delegation_controller._DelegationController__raw_get_delegation(
             NOT_EXISTING_ID)
 
@@ -91,10 +96,10 @@ def test_delegate(skale, validator):
     assert delegated_now_after == delegated_now_before + D_DELEGATION_AMOUNT
     assert delegated_amount_after == delegated_amount_before + D_DELEGATION_AMOUNT
 
-    month = date.fromtimestamp(skale.web3.eth.get_block('latest')['timestamp']).month
+    month = skale.time_helpers_with_debug.get_current_month()
     res = skale.delegation_controller.get_delegated_to_validator(
         validator_id,
-        month * 100
+        month
     )
     assert isinstance(res, int)
 
@@ -199,7 +204,7 @@ def test_request_undelegate(skale, validator):
     )
 
     # Transaction failed if delegation period is in progress
-    with pytest.raises(RevertError):
+    with pytest.raises(DryRunRevertError):
         tx_res = skale.delegation_controller.request_undelegation(
             delegation_id,
             wait_for=True,
diff --git a/tests/manager/delegation/validator_service_test.py b/tests/manager/delegation/validator_service_test.py
index 462fcc9e..29e7fb9f 100644
--- a/tests/manager/delegation/validator_service_test.py
+++ b/tests/manager/delegation/validator_service_test.py
@@ -4,7 +4,7 @@
 import pytest
 
 from skale.contracts.manager.delegation.validator_service import FIELDS
-from skale.transactions.result import RevertError
+from skale.transactions.result import DryRunRevertError
 from skale.utils.account_tools import send_eth
 from skale.wallets.web3_wallet import generate_wallet
 from skale.utils.contracts_provision.main import _skip_evm_time, enable_validator
@@ -208,7 +208,7 @@ def test_is_accepting_new_requests(skale, validator):
 
 
 def test_register_existing_validator(skale):
-    with pytest.raises(RevertError):
+    with pytest.raises(DryRunRevertError):
         skale.validator_service.register_validator(
             name=D_VALIDATOR_NAME,
             description=D_VALIDATOR_DESC,
@@ -319,7 +319,7 @@ def test_request_confirm_new_address(skale):
         validator = skale.validator_service.get(validator_id)
         assert validator['requested_address'] == '0x0000000000000000000000000000000000000000'
 
-        with pytest.raises(RevertError):
+        with pytest.raises(DryRunRevertError):
             skale.validator_service.request_for_new_address(
                 new_validator_address=main_wallet.address,
                 wait_for=True
@@ -393,6 +393,7 @@ def test_set_validator_description(skale):
 
 
 def test_revert_reason(skale):
+    no_validator_revert = "VM Exception while processing transaction: reverted with reason string 'Validator with such address already exists'"  # noqa
     try:
         skale.validator_service.register_validator(
             name=D_VALIDATOR_NAME,
@@ -401,8 +402,8 @@ def test_revert_reason(skale):
             min_delegation_amount=D_VALIDATOR_MIN_DEL,
             wait_for=True
         )
-    except RevertError as err:
-        assert str(err) == 'execution reverted: VM Exception while processing transaction: revert Validator with such address already exists'  # noqa
+    except DryRunRevertError as e:
+        assert no_validator_revert in e.message
 
 
 def test_get_use_whitelist(skale):
diff --git a/tests/manager/dkg_test.py b/tests/manager/dkg_test.py
index b3222496..5bdcc18e 100644
--- a/tests/manager/dkg_test.py
+++ b/tests/manager/dkg_test.py
@@ -5,68 +5,80 @@
 
 from skale.contracts.manager.dkg import G2Point, KeyShare
 
-
-def test_broadcast(skale):
-    nonce = skale.web3.eth.getTransactionCount(skale.wallet.address)
-    contract_address = skale.dkg.address
-    chain_id = skale.web3.eth.chainId
-    gas_limit = 8000000
-    expected_txn = {
-        'value': 0, 'gasPrice': skale.web3.eth.gasPrice * 2, 'chainId': chain_id,
-        'gas': gas_limit, 'nonce': nonce,
-        'type': 1,
-        'to': contract_address,
-        'data': (
-            '0x7d93019b653632396661363539386437333237363866376337323662346236323132383500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001f925c203a30ec6cad5a263db3efab7ed4c1fd74c8688167e10a5a22e15ab5018d8553df0ac54ea105a3d21845e5660bc3d4e7c82e7af1daa3baad393b15214673131310000000000000000000000000000000000000000000000000000000000'  # noqa
-        )
-    }
-    group_index = b'e629fa6598d732768f7c726b4b621285'
-    node_index = 0
-
-    verification_vector = [G2Point(1, 2, 3, 4).tuple for i in range(0, 3)]
-    secret_key_contribution = [KeyShare(skale.wallet.public_key, b'111').tuple]
-
-    exp = skale.web3.eth.account.signTransaction(
-        expected_txn, skale.wallet._private_key).rawTransaction
-    with mock.patch.object(skale.dkg.contract.functions.broadcast, 'call',
-                           new=Mock(return_value=[])):
-        with mock.patch.object(web3.eth.Eth, 'sendRawTransaction') as send_tx_mock:
-            send_tx_mock.return_value = b'hexstring'
-            skale.dkg.broadcast(group_index, node_index, verification_vector,
-                                secret_key_contribution,
-                                gas_limit=gas_limit,
-                                wait_for=False)
-            send_tx_mock.assert_called_with(HexBytes(exp))
+SCHAIN_NAME = 'pointed-asellus-australis'
+PUBLIC_KEY = '0xfcb3765bdb954ab0672fce731583ad8a94cf05fe63c147f881f8feea18e072d4cad3ec142a65de66a1d50e4fc34a7841c5488ccb55d02cf86013208c17517d64'   # noqa
+
+
+# def test_broadcast(skale):
+#     nonce = skale.web3.eth.get_transaction_count(skale.wallet.address)
+#     contract_address = skale.dkg.address
+#     chain_id = skale.web3.eth.chain_id
+#     gas_limit = 8000000
+#     expected_txn = {
+#         'value': 0, 'gasPrice': skale.web3.eth.gas_price * 2, 'chainId': chain_id,
+#         'gas': gas_limit, 'nonce': nonce,
+#         'type': 1,
+#         'to': contract_address,
+#         'data': (
+#             '0x7d93019be332bac19e758fe13db6129827da76846b8c6d26f1e70385d3f0afc0299e3db900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001fcb3765bdb954ab0672fce731583ad8a94cf05fe63c147f881f8feea18e072d4cad3ec142a65de66a1d50e4fc34a7841c5488ccb55d02cf86013208c17517d64e332bac19e758fe13db6129827da76846b8c6d26f1e70385d3f0afc0299e3db90000000000000000000000000000000000000000000000000000000000000000'  # noqa
+#         )
+#     }
+#     group_index = skale.schains.name_to_id(SCHAIN_NAME)
+#     share = group_index  # not an invariant, only a mock
+#     node_index = 0
+
+#     verification_vector = [G2Point(1, 2, 3, 4).tuple for i in range(0, 3)]
+#     secret_key_contribution = [KeyShare(PUBLIC_KEY, share).tuple]
+#     rotation_id = 0
+
+#     exp = skale.web3.eth.account.sign_transaction(
+#         expected_txn, skale.wallet._private_key).rawTransaction
+#     with mock.patch.object(skale.dkg.contract.functions.broadcast, 'call',
+#                            new=Mock(return_value=[])):
+#         with mock.patch.object(web3.eth.Eth, 'send_raw_transaction') as send_tx_mock:
+#             send_tx_mock.return_value = b'hexstring'
+#             skale.dkg.broadcast(
+#                 group_index,
+#                 node_index,
+#                 verification_vector,
+#                 secret_key_contribution,
+#                 rotation_id,
+#                 gas_limit=gas_limit,
+#                 wait_for=False
+#             )
+#             print(send_tx_mock.call_args)
+#             send_tx_mock.assert_called_with(HexBytes(exp))
 
 
 def test_response(skale):
-    nonce = skale.web3.eth.getTransactionCount(skale.wallet.address)
+    nonce = skale.web3.eth.get_transaction_count(skale.wallet.address)
     contract_address = skale.dkg.address
-    chain_id = skale.web3.eth.chainId
+    chain_id = skale.web3.eth.chain_id
     gas_limit = 11000000
     expected_txn = {
-        'value': 0, 'gasPrice': skale.web3.eth.gasPrice * 2, 'chainId': chain_id,
+        'value': 0, 'gasPrice': skale.web3.eth.gas_price * 2, 'chainId': chain_id,
         'gas': gas_limit, 'nonce': nonce,
         'type': 1,
         'to': contract_address,
         'data': (
-            '0x587e22fee629fa6598d732768f7c726b4b62128500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001f925c203a30ec6cad5a263db3efab7ed4c1fd74c8688167e10a5a22e15ab5018d8553df0ac54ea105a3d21845e5660bc3d4e7c82e7af1daa3baad393b15214673131310000000000000000000000000000000000000000000000000000000000'  # noqa
+            '0x587e22fee332bac19e758fe13db6129827da76846b8c6d26f1e70385d3f0afc0299e3db9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001fcb3765bdb954ab0672fce731583ad8a94cf05fe63c147f881f8feea18e072d4cad3ec142a65de66a1d50e4fc34a7841c5488ccb55d02cf86013208c17517d64e332bac19e758fe13db6129827da76846b8c6d26f1e70385d3f0afc0299e3db9'  # noqa
         )
     }
-    group_index = 'e629fa6598d732768f7c726b4b621285'
     from_node_index = 0
+    group_index = skale.schains.name_to_id(SCHAIN_NAME)
+    share = group_index  # not an invariant, only a mock
     secret_number = 1
     multiplied_share = G2Point(1, 2, 3, 4).tuple
     verification_vector = [G2Point(1, 2, 3, 4).tuple for i in range(0, 3)]
     verification_vector_mult = [G2Point(1, 2, 3, 4).tuple for i in range(0, 3)]
-    secret_key_contribution = [KeyShare(skale.wallet.public_key, b'111').tuple]
+    secret_key_contribution = [KeyShare(PUBLIC_KEY, share).tuple]
 
-    exp = skale.web3.eth.account.signTransaction(
+    exp = skale.web3.eth.account.sign_transaction(
         expected_txn, skale.wallet._private_key).rawTransaction
 
     with mock.patch.object(skale.dkg.contract.functions.preResponse, 'call',
                            new=Mock(return_value=[])):
-        with mock.patch.object(web3.eth.Eth, 'sendRawTransaction') as send_tx_mock:
+        with mock.patch.object(web3.eth.Eth, 'send_raw_transaction') as send_tx_mock:
             send_tx_mock.return_value = b'hexstring'
             skale.dkg.pre_response(
                 group_index=group_index,
@@ -80,20 +92,20 @@ def test_response(skale):
             send_tx_mock.assert_called_with(HexBytes(exp))
 
     expected_txn = {
-        'value': 0, 'gasPrice': skale.web3.eth.gasPrice * 2, 'chainId': chain_id,
+        'value': 0, 'gasPrice': skale.web3.eth.gas_price * 2, 'chainId': chain_id,
         'gas': gas_limit, 'nonce': nonce,
         'to': contract_address,
         'type': 1,
         'data': (
-            '0x6ef89763e629fa6598d732768f7c726b4b62128500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004'  # noqa
+'0x6ef89763e332bac19e758fe13db6129827da76846b8c6d26f1e70385d3f0afc0299e3db9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004'  # noqa
         )
     }
-    exp = skale.web3.eth.account.signTransaction(
+    exp = skale.web3.eth.account.sign_transaction(
         expected_txn, skale.wallet._private_key).rawTransaction
 
     with mock.patch.object(skale.dkg.contract.functions.response, 'call',
                            new=Mock(return_value=[])):
-        with mock.patch.object(web3.eth.Eth, 'sendRawTransaction') as send_tx_mock:
+        with mock.patch.object(web3.eth.Eth, 'send_raw_transaction') as send_tx_mock:
             send_tx_mock.return_value = b'hexstring'
             skale.dkg.response(
                 group_index=group_index,
@@ -107,28 +119,28 @@ def test_response(skale):
 
 
 def test_alright(skale):
-    nonce = skale.web3.eth.getTransactionCount(skale.wallet.address)
+    nonce = skale.web3.eth.get_transaction_count(skale.wallet.address)
     contract_address = skale.dkg.address
-    chain_id = skale.web3.eth.chainId
+    chain_id = skale.web3.eth.chain_id
     gas_limit = 10000000
     expected_txn = {
-        'value': 0, 'gasPrice': skale.web3.eth.gasPrice * 2, 'chainId': chain_id,
+        'value': 0, 'gasPrice': skale.web3.eth.gas_price * 2, 'chainId': chain_id,
         'gas': gas_limit, 'nonce': nonce,
         'type': 1,
         'to': contract_address,
         'data': (
-            '0xb9799682e629fa6598d732768f7c726b4b621285000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'  # noqa
+'0xb9799682e332bac19e758fe13db6129827da76846b8c6d26f1e70385d3f0afc0299e3db90000000000000000000000000000000000000000000000000000000000000000'  # noqa
         )
     }
-    group_index = 'e629fa6598d732768f7c726b4b621285'
+    group_index = skale.schains.name_to_id(SCHAIN_NAME)
     from_node_index = 0
 
-    exp = skale.web3.eth.account.signTransaction(
+    exp = skale.web3.eth.account.sign_transaction(
         expected_txn, skale.wallet._private_key).rawTransaction
 
     with mock.patch.object(skale.dkg.contract.functions.alright,
                            'call', new=Mock(return_value=[])):
-        with mock.patch.object(web3.eth.Eth, 'sendRawTransaction') as send_tx_mock:
+        with mock.patch.object(web3.eth.Eth, 'send_raw_transaction') as send_tx_mock:
             send_tx_mock.return_value = b'hexstring'
             skale.dkg.alright(group_index, from_node_index,
                               wait_for=False,
@@ -137,28 +149,28 @@ def test_alright(skale):
 
 
 def test_complaint(skale):
-    nonce = skale.web3.eth.getTransactionCount(skale.wallet.address)
+    nonce = skale.web3.eth.get_transaction_count(skale.wallet.address)
     contract_address = skale.dkg.address
-    chain_id = skale.web3.eth.chainId
+    chain_id = skale.web3.eth.chain_id
     gas_limit = 8000000
     expected_txn = {
-        'value': 0, 'gasPrice': skale.web3.eth.gasPrice * 2, 'chainId': chain_id,
+        'value': 0, 'gasPrice': skale.web3.eth.gas_price * 2, 'chainId': chain_id,
         'gas': gas_limit, 'nonce': nonce,
         'to': contract_address,
         'type': 1,
         'data': (
-            '0xd76c2c4fe629fa6598d732768f7c726b4b6212850000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'  # noqa
+'0xd76c2c4fe332bac19e758fe13db6129827da76846b8c6d26f1e70385d3f0afc0299e3db900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'  # noqa
         )
     }
-    group_index = 'e629fa6598d732768f7c726b4b621285'
+    group_index = skale.schains.name_to_id(SCHAIN_NAME)
     from_node_index = 0
     to_node_index = 0
 
-    exp = skale.web3.eth.account.signTransaction(
+    exp = skale.web3.eth.account.sign_transaction(
         expected_txn, skale.wallet._private_key).rawTransaction
     with mock.patch.object(skale.dkg.contract.functions.complaint,
                            'call', new=Mock(return_value=[])):
-        with mock.patch.object(web3.eth.Eth, 'sendRawTransaction') as send_tx_mock:
+        with mock.patch.object(web3.eth.Eth, 'send_raw_transaction') as send_tx_mock:
             send_tx_mock.return_value = b'hexstring'
             skale.dkg.complaint(group_index, from_node_index, to_node_index,
                                 wait_for=False,
@@ -167,104 +179,103 @@ def test_complaint(skale):
 
 
 def test_complaint_bad_data(skale):
-    nonce = skale.web3.eth.getTransactionCount(skale.wallet.address)
+    nonce = skale.web3.eth.get_transaction_count(skale.wallet.address)
     contract_address = skale.dkg.address
-    chain_id = skale.web3.eth.chainId
+    chain_id = skale.web3.eth.chain_id
     gas_limit = 8000000
     expected_txn = {
-        'value': 0, 'gasPrice': skale.web3.eth.gasPrice * 2, 'chainId': chain_id,
+        'value': 0, 'gasPrice': skale.web3.eth.gas_price * 2, 'chainId': chain_id,
         'gas': gas_limit, 'nonce': nonce,
         'to': contract_address,
         'type': 1,
         'data': (
-            '0xd76c2c4fe629fa6598d732768f7c726b4b6212850000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'  # noqa
+'0xd76c2c4fe332bac19e758fe13db6129827da76846b8c6d26f1e70385d3f0afc0299e3db900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'  # noqa
         )
     }
-    group_index = 'e629fa6598d732768f7c726b4b621285'
+    group_index = skale.schains.name_to_id(SCHAIN_NAME)
     from_node_index = 0
     to_node_index = 0
 
-    exp = skale.web3.eth.account.signTransaction(
+    exp = skale.web3.eth.account.sign_transaction(
         expected_txn, skale.wallet._private_key).rawTransaction
     with mock.patch.object(skale.dkg.contract.functions.complaintBadData,
                            'call', new=Mock(return_value=[])):
-        with mock.patch.object(web3.eth.Eth, 'sendRawTransaction') as send_tx_mock:
+        with mock.patch.object(web3.eth.Eth, 'send_raw_transaction') as send_tx_mock:
             send_tx_mock.return_value = b'hexstring'
             skale.dkg.complaint(group_index, from_node_index, to_node_index,
                                 wait_for=False,
-                                skip_dry_run=True,
                                 gas_limit=gas_limit)
             send_tx_mock.assert_called_with(HexBytes(exp))
 
 
 def test_is_last_dkg_successful(skale, schain):
-    group_index = skale.web3.sha3(text=schain)
+    group_index = skale.web3.keccak(text=schain)
     assert not skale.dkg.is_last_dkg_successful(group_index)
 
 
 def test_channel_opened(skale, schain):
-    group_index = skale.web3.sha3(text=schain)
+    group_index = skale.web3.keccak(text=schain)
     assert skale.dkg.is_channel_opened(group_index)
 
 
 def test_broadcast_possible(skale, nodes, schain, node_wallets):
-    group_index = skale.web3.sha3(text=schain)
+    group_index = skale.web3.keccak(text=schain)
     node_id, *_ = nodes
     wallet, *_ = node_wallets
     assert skale.dkg.is_broadcast_possible(group_index, node_id, wallet.address)
 
 
 def test_alright_possible(skale, nodes, schain, node_wallets):
-    group_index = skale.web3.sha3(text=schain)
+    group_index = skale.web3.keccak(text=schain)
     node_id, *_ = nodes
     wallet, *_ = node_wallets
     assert not skale.dkg.is_alright_possible(group_index, node_id, wallet.address)
 
 
 def test_pre_response_possible(skale, nodes, schain, node_wallets):
-    group_index = skale.web3.sha3(text=schain)
+    group_index = skale.web3.keccak(text=schain)
     node_id, *_ = nodes
     wallet, *_ = node_wallets
     assert not skale.dkg.is_pre_response_possible(group_index, node_id, wallet.address)
 
 
 def test_response_possible(skale, nodes, schain, node_wallets):
-    group_index = skale.web3.sha3(text=schain)
+    group_index = skale.web3.keccak(text=schain)
     node_id, *_ = nodes
     wallet, *_ = node_wallets
     assert not skale.dkg.is_response_possible(group_index, node_id, wallet.address)
 
 
 def test_everyone_broadcasted(skale, schain):
-    group_index = skale.web3.sha3(text=schain)
+    group_index = skale.web3.keccak(text=schain)
     assert not skale.dkg.is_everyone_broadcasted(group_index, skale.wallet.address)
 
 
 def test_number_of_completed(skale, schain):
-    group_index = skale.web3.sha3(text=schain)
+    group_index = skale.web3.keccak(text=schain)
     assert skale.dkg.get_number_of_completed(group_index) == 0
 
 
 def test_channel_started_time(skale, schain):
-    group_index = skale.web3.sha3(text=schain)
+    group_index = skale.web3.keccak(text=schain)
     assert skale.dkg.get_channel_started_time(group_index) != 0
 
 
 def test_complaint_started_time(skale, schain):
-    group_index = skale.web3.sha3(text=schain)
+    group_index = skale.web3.keccak(text=schain)
     assert skale.dkg.get_complaint_started_time(group_index) == 0
 
 
 def test_alright_started_time(skale, schain):
-    group_index = skale.web3.sha3(text=schain)
+    group_index = skale.web3.keccak(text=schain)
     assert skale.dkg.get_alright_started_time(group_index) == 0
 
 
-def test_complaint_data(skale, schain):
-    group_index = skale.web3.sha3(text=schain)
+def test_get_complaint_data(skale, schain):
+    group_index = skale.web3.keccak(text=schain)
     assert skale.dkg.get_complaint_data(group_index) != [0, 0]
 
 
 def test_time_of_last_successful_dkg(skale, schain):
-    group_index = skale.web3.sha3(text=schain)
+    group_index = skale.web3.keccak(text=schain)
     assert skale.dkg.get_time_of_last_successful_dkg(group_index) == 0
diff --git a/tests/manager/key_storage_test.py b/tests/manager/key_storage_test.py
index 9e36a79d..e903a877 100644
--- a/tests/manager/key_storage_test.py
+++ b/tests/manager/key_storage_test.py
@@ -2,7 +2,7 @@
 
 
 def test_get_previous_groups_public_key(skale):
-    group_id = skale.web3.sha3(text=DEFAULT_SCHAIN_NAME)
+    group_id = skale.web3.keccak(text=DEFAULT_SCHAIN_NAME)
     public_key = skale.key_storage.get_previous_public_key(group_id)
     assert isinstance(public_key, tuple)
     assert len(public_key) == 2
@@ -12,7 +12,7 @@ def test_get_previous_groups_public_key(skale):
 
 def test_get_all_previous_groups_public_keys(skale):
     # TODO: Improve test
-    group_id = skale.web3.sha3(text=DEFAULT_SCHAIN_NAME)
+    group_id = skale.web3.keccak(text=DEFAULT_SCHAIN_NAME)
     keys = skale.key_storage.get_all_previous_public_keys(group_id)
     assert keys == []
 
diff --git a/tests/manager/manager_test.py b/tests/manager/manager_test.py
index 326345f2..2c7349e9 100644
--- a/tests/manager/manager_test.py
+++ b/tests/manager/manager_test.py
@@ -9,7 +9,7 @@
 from unittest.mock import Mock
 
 from skale.wallets.web3_wallet import generate_wallet
-from skale.transactions.result import TransactionFailedError
+from skale.transactions.result import DryRunRevertError, TransactionFailedError
 
 from skale.utils.contracts_provision.main import (
     generate_random_node_data, generate_random_schain_data
@@ -21,9 +21,9 @@
 
 def test_get_bounty(skale):
     node_id = 0
-    nonce = skale.web3.eth.getTransactionCount(skale.wallet.address)
+    nonce = skale.web3.eth.get_transaction_count(skale.wallet.address)
     contract_address = skale.manager.address
-    chain_id = skale.web3.eth.chainId
+    chain_id = skale.web3.eth.chain_id
     expected_txn = {
         'value': 0, 'gasPrice': skale.gas_price, 'chainId': chain_id,
         'gas': TEST_GAS_LIMIT, 'nonce': nonce,
@@ -34,11 +34,11 @@ def test_get_bounty(skale):
             '00000000000000000000'
         )
     }
-    exp = skale.web3.eth.account.signTransaction(
+    exp = skale.web3.eth.account.sign_transaction(
         expected_txn, skale.wallet._private_key).rawTransaction
     with mock.patch.object(skale.manager.contract.functions.getBounty, 'call',
                            new=Mock(return_value=[])):
-        with mock.patch.object(web3.eth.Eth, 'sendRawTransaction') as send_tx_mock:
+        with mock.patch.object(web3.eth.Eth, 'send_raw_transaction') as send_tx_mock:
             send_tx_mock.return_value = b'hexstring'
             skale.manager.get_bounty(node_id, wait_for=False, gas_limit=TEST_GAS_LIMIT)
             send_tx_mock.assert_called_with(HexBytes(exp))
@@ -144,6 +144,7 @@ def test_create_node_status_0(failed_skale):
         name,
         domain_name=DEFAULT_DOMAIN_NAME,
         wait_for=True,
+        skip_dry_run=True,
         raise_for_status=False
     )
     assert tx_res.receipt['status'] == 0
@@ -159,10 +160,11 @@ def test_node_exit_with_no_schains(skale, nodes):
     assert skale.nodes.get_node_status(node_id) == 2
 
 
-def test_failed_node_exit(skale):
+def test_failed_node_exit(skale, block_in_seconds):
+    # block_in_seconds fixuture to return transaction revert in a same way as geth does
     not_existed_node_id = 1
-    with pytest.raises(TransactionFailedError):
-        skale.manager.node_exit(not_existed_node_id, skip_dry_run=True,
+    with pytest.raises(DryRunRevertError):
+        skale.manager.node_exit(not_existed_node_id,
                                 wait_for=True, gas_limit=TEST_GAS_LIMIT)
 
 
diff --git a/tests/manager/node_rotation_test.py b/tests/manager/node_rotation_test.py
index e6325990..9aaa6c61 100644
--- a/tests/manager/node_rotation_test.py
+++ b/tests/manager/node_rotation_test.py
@@ -73,10 +73,8 @@ def four_node_schain(skale, validator):
 
 
 def test_is_rotation_active(skale, four_node_schain):
-    # cleanup_nodes_schains(skale)
     nodes, skale_instances, name = four_node_schain
-    add_test4_schain_type(skale)
-    group_index = skale.web3.sha3(text=name)
+    group_index = skale.web3.keccak(text=name)
 
     run_dkg(nodes, skale_instances, group_index)
 
@@ -102,13 +100,13 @@ def test_is_rotation_active(skale, four_node_schain):
     nodes[exiting_node_index] = new_nodes[0]
     skale_instances[exiting_node_index] = new_skale_instances[0]
 
-    run_dkg(nodes, skale_instances, group_index, skip_time=False)
+    run_dkg(nodes, skale_instances, group_index, skip_time=False, rotation_id=1)
 
     assert skale.node_rotation.is_new_node_found(name)
     assert skale.node_rotation.is_rotation_in_progress(name)
     assert skale.node_rotation.is_rotation_active(name)
 
-    _skip_evm_time(skale_instances[0].web3, TEST_ROTATION_DELAY)
+    _skip_evm_time(skale.web3, TEST_ROTATION_DELAY)
 
     assert skale.node_rotation.is_new_node_found(name)
     assert not skale.node_rotation.is_rotation_in_progress(name)
diff --git a/tests/manager/nodes_test.py b/tests/manager/nodes_test.py
index ac1cbdde..d8989288 100644
--- a/tests/manager/nodes_test.py
+++ b/tests/manager/nodes_test.py
@@ -24,7 +24,7 @@ def test_get_raw_not_exist(skale):
 
 
 def public_key_from_private(key):
-    pr_bytes = Web3.toBytes(hexstr=key)
+    pr_bytes = Web3.to_bytes(hexstr=key)
     return keys.PrivateKey(pr_bytes)
 
 
@@ -179,3 +179,12 @@ def test_change_ip(skale, nodes):
     data = skale.nodes.get(node_id)
     assert data['ip'] == old_ip
     assert data['publicIP'] == old_ip
+
+
+def test_get_last_change_ip_time(skale, nodes):
+    node_id = skale.nodes.node_name_to_index(DEFAULT_NODE_NAME)
+    new_ip = Helper.ip_to_bytes(generate_random_ip())
+    tx = skale.nodes.change_ip(node_id, new_ip, new_ip, wait_for=True, confirmation_blocks=5)
+    change_timestamp = skale.nodes.get_last_change_ip_time(node_id)
+    block = skale.web3.eth.get_block(tx.receipt.blockNumber)
+    assert change_timestamp == block.timestamp
diff --git a/tests/manager/schains_internal_test.py b/tests/manager/schains_internal_test.py
index 5debf67a..1abc952d 100644
--- a/tests/manager/schains_internal_test.py
+++ b/tests/manager/schains_internal_test.py
@@ -14,7 +14,7 @@ def test_get_raw(skale):
 
 
 def test_get_raw_not_exist(skale):
-    not_exist_schain_id = b'unused_hash'
+    not_exist_schain_id = skale.schains.name_to_id('unused_hash')
     schain_arr = skale.schains_internal.get_raw(not_exist_schain_id)
     assert schain_arr == EMPTY_SCHAIN_ARR
 
diff --git a/tests/manager/schains_test.py b/tests/manager/schains_test.py
index 48c742f7..4b2dd78a 100644
--- a/tests/manager/schains_test.py
+++ b/tests/manager/schains_test.py
@@ -256,3 +256,8 @@ def test_get_options(skale, nodes):
     finally:
         if name:
             skale.manager.delete_schain(name)
+
+
+def test_restart_schain_creation(skale, nodes, schain):
+    name = schain
+    skale.schains.restart_schain_creation(name)
diff --git a/tests/manager/sync_manager_test.py b/tests/manager/sync_manager_test.py
index 910bd5b5..f386717b 100644
--- a/tests/manager/sync_manager_test.py
+++ b/tests/manager/sync_manager_test.py
@@ -1,12 +1,15 @@
+from web3.exceptions import ContractLogicError
+
+from skale.transactions.exceptions import DryRunRevertError
+
 import pytest
-from web3.exceptions import SolidityError
 
 START_IP = '0.0.0.1'
 END_IP = '255.255.255.254'
 
 
 @pytest.fixture
-def sync_manager_powers(skale):
+def sync_manager_permissions(skale):
     skale.sync_manager.grant_sync_manager_role(skale.wallet.address)
 
 
@@ -20,7 +23,7 @@ def ip_range(skale):
         skale.sync_manager.remove_ip_range(name)
 
 
-def test_add_get_remove_ip_range(skale, sync_manager_powers, ip_range):
+def test_add_get_remove_ip_range(skale, sync_manager_permissions, ip_range, block_in_seconds):
     r = skale.sync_manager.get_ip_range_by_name(ip_range)
     assert r.start_ip == START_IP
     assert r.end_ip == END_IP
@@ -30,27 +33,28 @@ def test_add_get_remove_ip_range(skale, sync_manager_powers, ip_range):
     assert r.end_ip == END_IP
 
 
-def test_add_bad_ip_range(skale, sync_manager_powers):
-    with pytest.raises(SolidityError):
+def test_add_bad_ip_range(skale, sync_manager_permissions, block_in_seconds):
+    with pytest.raises(DryRunRevertError):
         skale.sync_manager.add_ip_range('brange', '0.0.0.0', '1.1.1.1')
 
-    with pytest.raises(SolidityError):
+    with pytest.raises(DryRunRevertError):
         skale.sync_manager.add_ip_range('brange', '2.2.2.2', '1.1.1.1')
 
     with pytest.raises(OSError):
         skale.sync_manager.add_ip_range('brange', '1.1.1.1', '256.256.256.256')
 
 
-def test_remove_range_bad_params(skale, sync_manager_powers):
-    with pytest.raises(SolidityError):
+def test_remove_range_bad_params(skale, sync_manager_permissions, block_in_seconds):
+    with pytest.raises(DryRunRevertError):
         skale.sync_manager.remove_ip_range('phantom')
 
 
-def test_get_range_bad_params(skale, sync_manager_powers):
+def test_get_range_bad_params(skale, sync_manager_permissions, block_in_seconds):
     num = skale.sync_manager.get_ip_ranges_number()
-    with pytest.raises(SolidityError):
+    # TODO: Make dry run handle revert that has empty reason properly
+    with pytest.raises(ContractLogicError):
         r = skale.sync_manager.get_ip_range_by_index(num)
-    with pytest.raises(SolidityError):
+    with pytest.raises(ContractLogicError):
         r = skale.sync_manager.get_ip_range_by_index(0)
     r = skale.sync_manager.get_ip_range_by_name('phantom')
     assert r.start_ip == '0.0.0.0' and r.end_ip == '0.0.0.0'
diff --git a/tests/rotation_history/rotation_history_test.py b/tests/rotation_history/rotation_history_test.py
index 7c6fa88f..a3c57725 100644
--- a/tests/rotation_history/rotation_history_test.py
+++ b/tests/rotation_history/rotation_history_test.py
@@ -21,7 +21,8 @@
 
 
 def test_get_previous_node_no_node(skale):
-    assert skale.node_rotation.get_previous_node(DEFAULT_SCHAIN_NAME, 0) is None
+    assert skale.node_rotation.get_previous_node(
+        DEFAULT_SCHAIN_NAME, 0) is None
 
 
 @pytest.fixture
@@ -41,15 +42,15 @@ def four_node_schain(skale, validator):
 
 def test_rotation_history(skale, four_node_schain):
     nodes, skale_instances, name = four_node_schain
-    group_index = skale.web3.sha3(text=name)
+    group_index = skale.web3.keccak(text=name)
 
-    run_dkg(nodes, skale_instances, group_index)
+    run_dkg(nodes, skale_instances, group_index, rotation_id=0)
 
     group_ids_0 = skale.schains_internal.get_node_ids_for_schain(name)
 
     exiting_node_index = 1
     exiting_node_id = nodes[exiting_node_index]['node_id']
-    rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index)
+    rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index, rotation_id=1)
 
     previous_node_id = skale.node_rotation.get_previous_node(
         name,
@@ -61,7 +62,7 @@ def test_rotation_history(skale, four_node_schain):
 
     exiting_node_index = 1
     exiting_node_id = nodes[exiting_node_index]['node_id']
-    rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index)
+    rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index, rotation_id=2)
 
     previous_node_id = skale.node_rotation.get_previous_node(
         name,
@@ -73,7 +74,7 @@ def test_rotation_history(skale, four_node_schain):
 
     exiting_node_index = 2
     exiting_node_id = nodes[exiting_node_index]['node_id']
-    rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index)
+    rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index, rotation_id=3)
 
     previous_node_id = skale.node_rotation.get_previous_node(
         name,
@@ -85,7 +86,7 @@ def test_rotation_history(skale, four_node_schain):
 
     exiting_node_index = 3
     exiting_node_id = nodes[exiting_node_index]['node_id']
-    rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index)
+    rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index, rotation_id=4)
 
     previous_node_id = skale.node_rotation.get_previous_node(
         name,
@@ -97,7 +98,7 @@ def test_rotation_history(skale, four_node_schain):
 
     exiting_node_index = 1
     exiting_node_id = nodes[exiting_node_index]['node_id']
-    rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index)
+    rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index, rotation_id=5)
 
     previous_node_id = skale.node_rotation.get_previous_node(
         name,
@@ -129,14 +130,14 @@ def test_rotation_history_no_rotations(skale, four_node_schain):
 
 def test_rotation_history_single_rotation(skale, four_node_schain):
     nodes, skale_instances, name = four_node_schain
-    group_index = skale.web3.sha3(text=name)
+    group_index = skale.web3.keccak(text=name)
 
-    run_dkg(nodes, skale_instances, group_index)
+    run_dkg(nodes, skale_instances, group_index, rotation_id=0)
 
     group_ids_0 = skale.schains_internal.get_node_ids_for_schain(name)
 
     exiting_node_index = 1
-    rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index)
+    rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index, rotation_id=1)
 
     group_ids_1 = skale.schains_internal.get_node_ids_for_schain(name)
 
@@ -147,28 +148,39 @@ def test_rotation_history_single_rotation(skale, four_node_schain):
     assert set(node_groups[1]['nodes'].keys()) == set(group_ids_1)
 
 
-def test_rotation_history_failed_dkg(skale, four_node_schain):
+@pytest.mark.parametrize(
+    'first_node_index_to_exit,failed_node_index,second_node_index_to_exit',
+    [(1, 2, 1), (1, 2, 3), (2, 2, 2)]
+)
+def test_rotation_history_failed_dkg(
+    skale,
+    four_node_schain,
+    first_node_index_to_exit,
+    failed_node_index,
+    second_node_index_to_exit
+):
     nodes, skale_instances, name = four_node_schain
-    group_index = skale.web3.sha3(text=name)
+    group_index = skale.web3.keccak(text=name)
+    assert not skale.dkg.is_node_broadcasted(group_index, nodes[0]['node_id'])
 
-    run_dkg(nodes, skale_instances, group_index)
+    run_dkg(nodes, skale_instances, group_index, rotation_id=0)
+    assert skale.dkg.is_node_broadcasted(group_index, nodes[0]['node_id'])
 
     group_ids_0 = skale.schains_internal.get_node_ids_for_schain(name)
 
-    exiting_node_index = 1
-    rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index, do_dkg=False)
+    rotate_node(skale, group_index, nodes, skale_instances,
+                first_node_index_to_exit, do_dkg=False, rotation_id=1)
 
     group_ids_1 = skale.schains_internal.get_node_ids_for_schain(name)
 
-    failed_node_index = 2
     failed_node_id = nodes[failed_node_index]['node_id']
-    fail_dkg(skale, nodes, skale_instances, group_index, failed_node_index)
+    fail_dkg(skale, nodes, skale_instances, group_index, failed_node_index, rotation_id=1)
 
     group_ids_2 = skale.schains_internal.get_node_ids_for_schain(name)
 
-    exiting_node_index = 1
+    exiting_node_index = second_node_index_to_exit
     exiting_node_id = nodes[exiting_node_index]['node_id']
-    rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index)
+    rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index, rotation_id=3)
 
     previous_node_id = skale.node_rotation.get_previous_node(
         name,
@@ -205,54 +217,45 @@ def test_rotation_history_failed_dkg(skale, four_node_schain):
 
 def test_get_new_nodes_list(skale, four_node_schain):
     nodes, skale_instances, name = four_node_schain
-    group_index = skale.web3.sha3(text=name)
+    group_index = skale.web3.keccak(text=name)
 
-    run_dkg(nodes, skale_instances, group_index)
+    run_dkg(nodes, skale_instances, group_index, rotation_id=0)
 
     exiting_node_index = 1  # in group
-    exiting_node_g_id = nodes[exiting_node_index]['node_id']  # global id
-    rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index, do_dkg=False)
+    rotate_node(skale, group_index, nodes, skale_instances,
+                exiting_node_index, do_dkg=False, rotation_id=1)
 
     failed_node_index = 2
-    failed_node_g_id = nodes[failed_node_index]['node_id']
     second_failed_node_index = 3
-    second_failed_node_g_id = nodes[second_failed_node_index]['node_id']
     test_new_node_ids = fail_dkg(
         skale=skale,
         nodes=nodes,
         skale_instances=skale_instances,
         group_index=group_index,
         failed_node_index=failed_node_index,
-        second_failed_node_index=second_failed_node_index
+        second_failed_node_index=second_failed_node_index,
+        rotation_id=1
     )
 
     rotation = skale.node_rotation.get_rotation_obj(name)
     node_groups = get_previous_schain_groups(
         skale=skale,
         schain_name=name,
-        leaving_node_id=rotation.leaving_node_id,
-        include_keys=False
+        leaving_node_id=rotation.leaving_node_id
     )
     new_nodes = get_new_nodes_list(skale, name, node_groups)
 
     assert len(new_nodes) == 3
     assert all(x in new_nodes for x in test_new_node_ids)
 
-    # Temorary fix for "The schain does not exist" problem
-    # Bad nodes should be removed before chain is deleted
-    remove_node(skale, exiting_node_g_id)
-    remove_node(skale, failed_node_g_id)
-    remove_node(skale, second_failed_node_g_id)
-
     exiting_node_index = 3
-    rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index)
+    rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index, rotation_id=4)
 
     rotation = skale.node_rotation.get_rotation_obj(name)
     node_groups = get_previous_schain_groups(
         skale=skale,
         schain_name=name,
-        leaving_node_id=rotation.leaving_node_id,
-        include_keys=False
+        leaving_node_id=rotation.leaving_node_id
     )
     new_nodes = get_new_nodes_list(skale, name, node_groups)
 
diff --git a/tests/rotation_history/utils.py b/tests/rotation_history/utils.py
index f84aaf53..c017a8fb 100644
--- a/tests/rotation_history/utils.py
+++ b/tests/rotation_history/utils.py
@@ -106,14 +106,15 @@ def init_skale_from_wallet(wallet) -> Skale:
     return Skale(ENDPOINT, TEST_ABI_FILEPATH, wallet)
 
 
-def send_broadcasts(nodes, skale_instances, group_index, skip_node_index=None):
+def send_broadcasts(nodes, skale_instances, group_index, skip_node_index=None, rotation_id=0):
     for i, node in enumerate(nodes):
         if i != skip_node_index:
             skale_instances[i].dkg.broadcast(
                 group_index,
                 node['node_id'],
                 TEST_DKG_DATA['test_verification_vectors'][i],
-                TEST_DKG_DATA['test_encrypted_secret_key_contributions'][i]
+                TEST_DKG_DATA['test_encrypted_secret_key_contributions'][i],
+                rotation_id
             )
         else:
             print(f'Skipping broadcast from node {node["node_id"]}')
@@ -134,14 +135,15 @@ def send_complaint(nodes, skale_instances, group_index, failed_node_index):
             skale_instance.dkg.complaint(group_index, nodes[i]['node_id'], failed_node_id)
 
 
-def rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index, do_dkg=True):
+def rotate_node(skale, group_index, nodes, skale_instances, exiting_node_index, do_dkg=True,
+                rotation_id=0):
     new_nodes, new_skale_instances = set_up_nodes(skale, 1)
     skale.nodes.init_exit(nodes[exiting_node_index]['node_id'])
     skale_instances[exiting_node_index].manager.node_exit(nodes[exiting_node_index]['node_id'])
     nodes[exiting_node_index] = new_nodes[0]
     skale_instances[exiting_node_index] = new_skale_instances[0]
     if do_dkg:
-        run_dkg(nodes, skale_instances, group_index)
+        run_dkg(nodes, skale_instances, group_index, rotation_id=rotation_id)
     return nodes, skale_instances
 
 
@@ -151,14 +153,15 @@ def fail_dkg(
     skale_instances,
     group_index,
     failed_node_index,
-    second_failed_node_index=None
+    second_failed_node_index=None,
+    rotation_id=0
 ) -> list:
     logger.info('Failing first DKG...')
     new_node_ids = []
     new_nodes, new_skale_instances = set_up_nodes(skale, 1)
     new_node_ids.append(new_nodes[0]['node_id'])
 
-    send_broadcasts(nodes, skale_instances, group_index, failed_node_index)
+    send_broadcasts(nodes, skale_instances, group_index, failed_node_index, rotation_id=rotation_id)
     _skip_evm_time(skale_instances[0].web3, skale.constants_holder.get_dkg_timeout())
     send_complaint(nodes, skale_instances, group_index, failed_node_index)
 
@@ -170,20 +173,22 @@ def fail_dkg(
         new_nodes, new_skale_instances = set_up_nodes(skale, 1)
         new_node_ids.append(new_nodes[0]['node_id'])
 
-        send_broadcasts(nodes, skale_instances, group_index, second_failed_node_index)
+        send_broadcasts(nodes, skale_instances, group_index, second_failed_node_index,
+                        rotation_id=rotation_id + 1)
         _skip_evm_time(skale_instances[0].web3, skale.constants_holder.get_dkg_timeout())
         send_complaint(nodes, skale_instances, group_index, second_failed_node_index)
 
         nodes[second_failed_node_index] = new_nodes[0]
         skale_instances[second_failed_node_index] = new_skale_instances[0]
 
-    run_dkg(nodes, skale_instances, group_index)
+    run_dkg(nodes, skale_instances, group_index, rotation_id=rotation_id + 1 +
+            (0 if second_failed_node_index is None else 1))
     return new_node_ids
 
 
-def run_dkg(nodes, skale_instances, group_index, skip_time=True):
+def run_dkg(nodes, skale_instances, group_index, skip_time=True, rotation_id=0):
     logger.info('Running DKG procedure...')
-    send_broadcasts(nodes, skale_instances, group_index)
+    send_broadcasts(nodes, skale_instances, group_index, rotation_id=rotation_id)
     send_alrights(nodes, skale_instances, group_index)
     if skip_time:
         _skip_evm_time(skale_instances[0].web3, TEST_ROTATION_DELAY)
diff --git a/tests/transaction_tools_test.py b/tests/transaction_tools_test.py
index 2c34cb09..bf142117 100644
--- a/tests/transaction_tools_test.py
+++ b/tests/transaction_tools_test.py
@@ -8,16 +8,18 @@
 )
 from skale import Skale
 from skale.transactions.tools import (
-    run_tx_with_retry,
+    get_block_gas_limit,
     estimate_gas,
-    get_block_gas_limit
+    TxCallResult,
+    TxStatus,
+    run_tx_with_retry
 )
 from skale.utils.account_tools import generate_account
 from skale.utils.web3_utils import init_web3
 from skale.wallets import Web3Wallet
 from skale.wallets.web3_wallet import generate_wallet
 
-from tests.constants import ENDPOINT, TEST_ABI_FILEPATH, TEST_GAS_LIMIT
+from tests.constants import ENDPOINT, TEST_ABI_FILEPATH
 from tests.constants import (
     D_VALIDATOR_NAME, D_VALIDATOR_DESC,
     D_VALIDATOR_FEE, D_VALIDATOR_MIN_DEL,
@@ -30,7 +32,6 @@ def generate_new_skale():
     web3 = init_web3(ENDPOINT)
     account = generate_account(web3)
     wallet = Web3Wallet(account['private_key'], web3)
-    wallet.sign_and_send = mock.Mock()
     wallet.wait = mock.Mock()
     return Skale(ENDPOINT, TEST_ABI_FILEPATH, wallet)
 
@@ -38,8 +39,8 @@ def generate_new_skale():
 def test_run_tx_with_retry(skale):
     account = generate_account(skale.web3)
     address_to = account['address']
-    address_from = Web3.toChecksumAddress(skale.wallet.address)
-    address_to = Web3.toChecksumAddress(address_to)
+    address_from = Web3.to_checksum_address(skale.wallet.address)
+    address_to = Web3.to_checksum_address(address_to)
     balance_from_before = skale.token.get_balance(address_from)
     balance_to_before = skale.token.get_balance(address_to)
 
@@ -58,10 +59,12 @@ def test_run_tx_with_retry(skale):
 
 def test_run_tx_with_retry_dry_run_failed(skale):
     dry_run_call_mock = mock.Mock(
-        return_value={
-            'status': 0,
-            'error': 'Dry run failed'
-        }
+        return_value=TxCallResult(
+            status=TxStatus.FAILED,
+            error='revert',
+            message='Dry run test failure',
+            data={}
+        )
     )
     account = generate_account(skale.web3)
     token_amount = 10 * ETH_IN_WEI
@@ -102,21 +105,15 @@ def test_run_tx_with_retry_tx_failed(failed_skale):
 def test_run_tx_with_retry_insufficient_balance(skale):
     sender_skale = generate_new_skale()
     token_amount = 10 * ETH_IN_WEI
-    skale.token.transfer(sender_skale.wallet.address, token_amount + 1,
-                         skip_dry_run=True,
-                         wait_for=True,
-                         gas_limit=TEST_GAS_LIMIT)
     retries_number = 5
-    sender_skale.wallet.wait = mock.Mock()
-    run_tx_with_retry(
+    tx_res = run_tx_with_retry(
         sender_skale.token.transfer,
-        skale.wallet.address, token_amount, wait_for=True,
+        skale.wallet.address, token_amount,
         raise_for_status=False,
         max_retries=retries_number,
     )
 
-    assert sender_skale.wallet.sign_and_send.call_count == retries_number
-    assert sender_skale.wallet.wait.call_count == retries_number
+    assert tx_res.attempts == retries_number
 
 
 def test_estimate_gas(skale):
@@ -140,7 +137,7 @@ def test_estimate_gas(skale):
     assert isinstance(estimated_gas, int)
     assert estimated_gas != block_gas_limit
 
-    with mock.patch.object(method, 'estimateGas', return_value=10000000000):
+    with mock.patch.object(method, 'estimate_gas', return_value=10000000000):
         estimated_gas = estimate_gas(skale.web3, method, opts)
 
     assert estimated_gas == block_gas_limit
@@ -150,8 +147,8 @@ def test_estimate_gas(skale):
 def test_tx_fee_options(skale):
     account = generate_account(skale.web3)
     address_to = account['address']
-    address_from = Web3.toChecksumAddress(skale.wallet.address)
-    address_to = Web3.toChecksumAddress(address_to)
+    address_from = Web3.to_checksum_address(skale.wallet.address)
+    address_to = Web3.to_checksum_address(address_to)
     balance_from_before = skale.token.get_balance(address_from)
     balance_to_before = skale.token.get_balance(address_to)
     token_amount = 10 * ETH_IN_WEI
@@ -176,5 +173,5 @@ def test_tx_fee_options(skale):
         account['address'],
         token_amount,
         max_fee_per_gas=max_fee,
-        max_priority_fee_per_gas=max_fee * 2
+        max_priority_fee_per_gas=int(max_fee / 2)
     )
diff --git a/tests/utils/account_tools_test.py b/tests/utils/account_tools_test.py
index c8aab080..a4b9be1b 100644
--- a/tests/utils/account_tools_test.py
+++ b/tests/utils/account_tools_test.py
@@ -24,7 +24,7 @@ def test_send_tokens(skale, empty_account):
     receiver_balance_after = skale.token.get_balance(empty_account.address)
     sender_balance_after = skale.token.get_balance(skale.wallet.address)
 
-    token_transfer_value_wei = skale.web3.toWei(TOKEN_TRANSFER_VALUE, 'ether')
+    token_transfer_value_wei = skale.web3.to_wei(TOKEN_TRANSFER_VALUE, 'ether')
 
     assert receiver_balance_after == token_transfer_value_wei
     assert sender_balance_after == sender_balance - token_transfer_value_wei
@@ -52,9 +52,9 @@ def test_send_eth(skale, empty_account):
         sender_balance - ETH_TRANSFER_VALUE
 
 
-def test_send_eth_with_gas_price(skale, empty_account):
+def test_send_eth_with_gas_price(skale, empty_account, block_in_seconds):
     def get_signed_tx_with_custom_gas_price(gas_price):
-        wei_amount = skale.web3.toWei(ETH_TRANSFER_VALUE, 'ether')
+        wei_amount = skale.web3.to_wei(ETH_TRANSFER_VALUE, 'ether')
         return skale.wallet.sign({
             'to': empty_account.address,
             'value': wei_amount,
@@ -64,7 +64,7 @@ def get_signed_tx_with_custom_gas_price(gas_price):
         })
 
     # Send tx with small gas price
-    small_gas_price = 1
+    small_gas_price = 6
     with pytest.raises(TransactionNotMinedError):
         send_eth(
             skale.web3,
@@ -89,7 +89,7 @@ def get_signed_tx_with_custom_gas_price(gas_price):
         assert receipt['effectiveGasPrice'] == custom_default_gas_price
 
     # Send ether with default avg gas price
-    avg_gas_price = skale.web3.eth.gasPrice * GAS_PRICE_COEFFICIENT
+    avg_gas_price = skale.web3.eth.gas_price * GAS_PRICE_COEFFICIENT
     receipt = send_eth(
         skale.web3, skale.wallet, empty_account.address,
         ETH_TRANSFER_VALUE, wait_for=True)
@@ -118,7 +118,7 @@ def test_generate_accounts(skale):
     token_balance_test = check_skale_balance(skale, test_address)
     token_balance = skale.token.get_balance(test_address)
 
-    token_transfer_value_wei = skale.web3.toWei(TOKEN_TRANSFER_VALUE, 'ether')
+    token_transfer_value_wei = skale.web3.to_wei(TOKEN_TRANSFER_VALUE, 'ether')
 
     assert TOKEN_TRANSFER_VALUE == token_balance_test
     assert eth_balance == ETH_TRANSFER_VALUE
diff --git a/tests/utils/web3_utils_test.py b/tests/utils/web3_utils_test.py
index 441c844d..220149fe 100644
--- a/tests/utils/web3_utils_test.py
+++ b/tests/utils/web3_utils_test.py
@@ -55,13 +55,13 @@ def test_get_save_last_known_block_number(last_block_file):
 def test_call_with_last_block_file(skale_block_file, last_block_file):
     skale = skale_block_file
     state_path = last_block_file
-    current_block = skale.web3.eth.blockNumber
+    current_block = skale.web3.eth.block_number
     needed_block = current_block
 
     save_last_known_block_number(state_path, needed_block)
     skale_block_file.validator_service.ls()
 
-    current_block = skale.web3.eth.blockNumber
+    current_block = skale.web3.eth.block_number
     needed_block = current_block + 10
     save_last_known_block_number(state_path, needed_block)
     with pytest.raises(EthClientOutdatedError):
@@ -76,7 +76,8 @@ def test_call_with_outdated_client(skale):
     dt = datetime.utcfromtimestamp(current_ts + allowed_diff)
     with freeze_time(dt):
         skale.validator_service.ls()
-    dt = datetime.utcfromtimestamp(current_ts + allowed_diff + 7)
+    print(current_ts, allowed_diff)
+    dt = datetime.utcfromtimestamp(current_ts + allowed_diff + 5)
     with freeze_time(dt):
         with pytest.raises(EthClientOutdatedError):
             skale.validator_service.ls()
@@ -85,7 +86,7 @@ def test_call_with_outdated_client(skale):
 def test_transaction_with_last_block_file(last_block_file, skale_block_file):
     skale = skale_block_file
     state_path = last_block_file
-    current_block = skale.web3.eth.blockNumber
+    current_block = skale.web3.eth.block_number
     needed_block = current_block
     save_last_known_block_number(state_path, needed_block)
 
@@ -93,7 +94,7 @@ def test_transaction_with_last_block_file(last_block_file, skale_block_file):
     skale.constants_holder.set_rotation_delay(new_rotation_delay,
                                               wait_for=True)
 
-    current_block = skale.web3.eth.blockNumber
+    current_block = skale.web3.eth.block_number
     last_block = current_block + 100
     save_last_known_block_number(state_path, last_block)
     new_rotation_delay = 101
diff --git a/tests/wallets/common_test.py b/tests/wallets/common_test.py
index 62ca243c..688d617d 100644
--- a/tests/wallets/common_test.py
+++ b/tests/wallets/common_test.py
@@ -4,7 +4,7 @@
 from skale.wallets import Web3Wallet
 from skale.wallets.common import ensure_chain_id
 
-from skale.utils.exceptions import ChainIdError
+from skale.transactions.exceptions import ChainIdError
 from skale.utils.web3_utils import init_web3
 from tests.constants import ENDPOINT, ETH_PRIVATE_KEY
 
@@ -23,12 +23,12 @@ def test_ensure_chain_id(skale):
     tx_dict = get_tx_dict()
     ensure_chain_id(tx_dict, skale.web3)
     assert isinstance(tx_dict['chainId'], int)
-    assert tx_dict['chainId'] == skale.web3.eth.chainId
+    assert tx_dict['chainId'] == skale.web3.eth.chain_id
 
 
 def test_ensure_chain_id_fail(skale):
     tx_dict = get_tx_dict()
-    with mock.patch.object(web3.eth.Eth, 'chainId', new=None):
+    with mock.patch.object(web3.eth.Eth, 'chain_id', new=None):
         with pytest.raises(ChainIdError):
             ensure_chain_id(tx_dict, skale.web3)
 
diff --git a/tests/wallets/ledger_test.py b/tests/wallets/ledger_test.py
index 1d9e2f51..f10315e6 100644
--- a/tests/wallets/ledger_test.py
+++ b/tests/wallets/ledger_test.py
@@ -1,5 +1,7 @@
+import pytest
 from unittest import mock
 
+from skale.transactions.exceptions import TransactionNotSentError
 from skale.utils.web3_utils import init_web3
 from skale.wallets.ledger_wallet import LedgerWallet
 
@@ -36,3 +38,16 @@ def test_hardware_sign_and_send():
             'data': b'\x9b\xd9\xbb\xc6\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95qY\xc4i\xfc;\xba\xa8\xe3\x9e\xe0\xa3$\xc28\x8a\xd6Q\xe5\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r\xe0\xb6\xb3\xa7d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa8\xc0\x04/Rglamorous-kitalpha\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'  # noqa
         }
         wallet.sign(tx_dict)
+
+        tx_dict = {
+            'to': '0x1057dc7277a319927D3eB43e05680B75a00eb5f4',
+            'value': 9,
+            'gas': 200000,
+            'gasPrice': 1,
+            'nonce': 1,
+            'chainId': 2132,
+            'data': b'\x9b\xd9\xbb\xc6\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95qY\xc4i\xfc;\xba\xa8\xe3\x9e\xe0\xa3$\xc28\x8a\xd6Q\xe5\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r\xe0\xb6\xb3\xa7d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa8\xc0\x04/Rglamorous-kitalpha\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'  # noqa
+        }
+        # No balance on this account, should fail
+        with pytest.raises(TransactionNotSentError):
+            wallet.sign_and_send(tx_dict)
diff --git a/tests/wallets/redis_adapter_test.py b/tests/wallets/redis_adapter_test.py
index 030818e7..4d032a13 100644
--- a/tests/wallets/redis_adapter_test.py
+++ b/tests/wallets/redis_adapter_test.py
@@ -5,10 +5,10 @@
 from freezegun import freeze_time
 
 from skale.wallets.redis_wallet import (
-    AdapterSendError,
-    AdapterWaitError,
-    DroppedError,
-    EmptyStatusError,
+    RedisWalletNotSentError,
+    RedisWalletWaitError,
+    RedisWalletDroppedError,
+    RedisWalletEmptyStatusError,
     RedisWalletAdapter
 )
 
@@ -68,29 +68,28 @@ def test_sign_and_send(rdp):
     assert tx_id.startswith('tx-') and len(tx_id) == 19
 
     rdp.rs.pipeline = mock.Mock(side_effect=RedisTestError('rtest'))
-    with pytest.raises(AdapterSendError):
+    with pytest.raises(RedisWalletNotSentError):
         tx_id = rdp.sign_and_send(tx, multiplier=2, priority=5)
 
 
-def test_wait(rdp):
+def test_rdp_wait(rdp):
     tx_id = 'tx-tttttttttttttttt'
-    rdp.get_status = mock.Mock(return_value=None)
+    rdp.get_record = mock.Mock(return_value=None)
     with in_time(3):
-        with pytest.raises(EmptyStatusError):
+        with pytest.raises(RedisWalletEmptyStatusError):
             rdp.wait(tx_id, timeout=2)
 
-    rdp.get_status = mock.Mock(return_value='DROPPED')
+    rdp.get_record = mock.Mock(return_value={'tx_hash': 'test', 'status': 'DROPPED'})
     with in_time(2):
-        with pytest.raises(DroppedError):
+        with pytest.raises(RedisWalletDroppedError):
             rdp.wait(tx_id, timeout=100)
 
-    rdp.get_status = mock.Mock(side_effect=RedisTestError('test'))
+    rdp.get_record = mock.Mock(side_effect=RedisTestError('test'))
     with in_time(2):
-        with pytest.raises(AdapterWaitError):
+        with pytest.raises(RedisWalletWaitError):
             rdp.wait(tx_id, timeout=100)
 
-    rdp.get_status = mock.Mock(return_value='SUCCESS')
-    rdp.get_record = mock.Mock(return_value={'tx_hash': 'test'})
+    rdp.get_record = mock.Mock(return_value={'tx_hash': 'test', 'status': 'SUCCESS'})
     fake_receipt = {'test': 'test'}
     with mock.patch(
         'skale.wallets.redis_wallet.get_receipt',
diff --git a/tests/wallets/rpc_test.py b/tests/wallets/rpc_test.py
deleted file mode 100644
index 8c566820..00000000
--- a/tests/wallets/rpc_test.py
+++ /dev/null
@@ -1,161 +0,0 @@
-""" SKALE RPCWallet test """
-
-
-from http import HTTPStatus
-
-import pytest
-from unittest import mock
-
-from hexbytes import HexBytes
-from skale.wallets import RPCWallet
-from skale.utils.exceptions import RPCWalletError
-
-from tests.constants import (
-    ENDPOINT, EMPTY_HEX_STR, ETH_PRIVATE_KEY,
-    NOT_EXISTING_RPC_WALLET_URL, TEST_SGX_ENDPOINT, TEST_RPC_WALLET_URL
-)
-from tests.helper import response_mock, request_mock
-from tests.wallets.utils import SgxClient
-from skale.utils.web3_utils import (
-    init_web3,
-    private_key_to_address, private_key_to_public,
-    to_checksum_address
-)
-
-
-TX_DICT = {
-    'to': '0x1057dc7277a319927D3eB43e05680B75a00eb5f4',
-    'value': 9,
-    'gas': 200000,
-    'gasPrice': 1,
-    'nonce': 7,
-    'chainId': None,
-    'data': '0x0'
-}
-
-EMPTY_ETH_ACCOUNT = '0x0000000000000000000000000000000000000000'
-TEST_MAX_RETRIES = 3
-
-
-@pytest.fixture
-def web3():
-    return init_web3(ENDPOINT)
-
-
-@pytest.fixture
-@mock.patch('skale.wallets.sgx_wallet.SgxClient', new=SgxClient)
-def wallet(web3):
-    return RPCWallet(TEST_RPC_WALLET_URL, TEST_SGX_ENDPOINT, web3,
-                     retry_if_failed=True)
-
-
-@mock.patch('skale.wallets.sgx_wallet.SgxClient', new=SgxClient)
-def test_rpc_not_available(web3):
-    wallet = RPCWallet(NOT_EXISTING_RPC_WALLET_URL, TEST_SGX_ENDPOINT, web3)
-    with pytest.raises(RPCWalletError):
-        wallet.sign_and_send({})
-
-
-def test_rpc_sign_and_send(wallet):
-    res_mock = response_mock(HTTPStatus.OK,
-                             {'data': {'transaction_hash': EMPTY_HEX_STR},
-                              'error': None})
-    with mock.patch('requests.post', new=request_mock(res_mock)):
-        tx_hash = wallet.sign_and_send(TX_DICT)
-        assert tx_hash == EMPTY_HEX_STR
-
-
-def test_rpc_sign_and_send_fails(wallet):
-    cnt = 0
-
-    def post_mock(*args, **kwargs):
-        nonlocal cnt
-        response_mock = mock.Mock()
-        if cnt < TEST_MAX_RETRIES:
-            rv = {'data': None, 'error': object()}
-            cnt += 1
-        else:
-            rv = {'data': 'test', 'error': ''}
-
-        response_mock.json = mock.Mock(return_value=rv)
-        return response_mock
-
-    with mock.patch('requests.post', post_mock):
-        with pytest.raises(RPCWalletError):
-            wallet.sign_and_send(TX_DICT)
-
-        assert cnt == TEST_MAX_RETRIES
-
-
-@mock.patch('skale.wallets.sgx_wallet.SgxClient', new=SgxClient)
-def test_rpc_sign_and_send_sgx_unreachable_no_retries(web3):
-    res_mock = response_mock(HTTPStatus.BAD_REQUEST,
-                             {'data': None,
-                              'error': 'Sgx server is unreachable'})
-    wallet = RPCWallet(NOT_EXISTING_RPC_WALLET_URL, TEST_SGX_ENDPOINT, web3)
-    with mock.patch('requests.post', new=request_mock(res_mock)):
-        with pytest.raises(RPCWalletError):
-            wallet.sign_and_send(TX_DICT)
-            assert res_mock.call_count == 1
-
-
-def test_rpc_sign_and_send_sgx_unreachable(wallet):
-    cnt = 0
-
-    def post_mock(*args, **kwargs):
-        nonlocal cnt
-        response_mock = mock.Mock()
-        if cnt < TEST_MAX_RETRIES:
-            rv = {'data': None, 'error': 'Sgx server is unreachable'}
-            cnt += 1
-        else:
-            rv = {'data': 'test', 'error': ''}
-
-        response_mock.json = mock.Mock(return_value=rv)
-        return response_mock
-
-    with mock.patch('requests.post', post_mock):
-        with pytest.raises(RPCWalletError):
-            wallet.sign_and_send(TX_DICT)
-
-        assert cnt == TEST_MAX_RETRIES
-
-
-def test_rpc_sign_hash(wallet):
-    unsigned_hash = '0x31323331'
-    signed_message = wallet.sign_hash(unsigned_hash)
-    assert signed_message.signature == HexBytes('0x6161616161613131313131')
-
-
-def test_sign_and_send_dry_run(wallet):
-    cnt = 0
-
-    def post_mock(*args, **kwargs):
-        nonlocal cnt
-        response_mock = mock.Mock()
-        if cnt < TEST_MAX_RETRIES:
-            rv = {'data': None, 'error': 'Dry run failed: {"Test"}'}
-            cnt += 1
-        else:
-            rv = {'data': 'test', 'error': ''}
-
-        response_mock.json = mock.Mock(return_value=rv)
-        return response_mock
-
-    with mock.patch('requests.post', post_mock):
-        with pytest.raises(RPCWalletError):
-            wallet.sign_and_send(TX_DICT)
-
-        assert cnt == 1
-
-
-def test_rpc_address(wallet):
-    address = to_checksum_address(
-        private_key_to_address(ETH_PRIVATE_KEY)
-    )
-    assert wallet.address == address
-
-
-def test_rpc_public_key(wallet):
-    pk = private_key_to_public(ETH_PRIVATE_KEY)
-    assert wallet.public_key == pk
diff --git a/tests/wallets/sgx_test.py b/tests/wallets/sgx_test.py
index 8200a87d..b1fe7132 100644
--- a/tests/wallets/sgx_test.py
+++ b/tests/wallets/sgx_test.py
@@ -1,7 +1,8 @@
 from unittest import mock
 import pytest
 from hexbytes import HexBytes
-from skale.wallets import SgxWallet
+from skale.wallets.sgx_wallet import (SgxWallet, TransactionNotSentError,
+                                      TransactionNotSignedError, MessageNotSignedError)
 from skale.utils.web3_utils import (
     init_web3,
     private_key_to_address,
@@ -10,7 +11,7 @@
 )
 
 from tests.constants import ENDPOINT, ETH_PRIVATE_KEY, TEST_SGX_ENDPOINT
-from tests.wallets.utils import SgxClient
+from tests.wallets.utils import BadSgxClient, SgxClient
 
 ADDRESS = to_checksum_address(
     private_key_to_address(ETH_PRIVATE_KEY)
@@ -43,8 +44,8 @@ def test_sgx_sign(wallet):
 
 def test_sgx_sign_and_send_without_nonce(wallet):
     send_tx_mock = mock.Mock()
-    wallet._web3.eth.sendRawTransaction = send_tx_mock
-    wallet._web3.eth.getTransactionCount = mock.Mock(return_value=0)
+    wallet._web3.eth.send_raw_transaction = send_tx_mock
+    wallet._web3.eth.get_transaction_count = mock.Mock(return_value=0)
     tx_dict = {
         'to': '0x1057dc7277a31',
         'value': 9,
@@ -88,3 +89,43 @@ def test_sgx_key_init(web3):
     assert wallet.key_name == 'TEST_KEY'
     assert wallet.address == ADDRESS
     assert wallet.public_key == pk
+
+
+@mock.patch('skale.wallets.sgx_wallet.SgxClient', new=SgxClient)
+def test_not_sent_error(web3):
+    wallet = SgxWallet(TEST_SGX_ENDPOINT, web3, 'TEST_KEY')
+    tx_dict = {
+        'to': '0x1057dc7277a319927D3eB43e05680B75a00eb5f4',
+        'value': 9,
+        'gas': 200000,
+        'gasPrice': 1,
+        'nonce': 1,  # nonce too low
+        'chainId': None,
+        'data': b'\x9b\xd9\xbb\xc6\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95qY\xc4i\xfc;\xba\xa8\xe3\x9e\xe0\xa3$\xc28\x8a\xd6Q\xe5\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r\xe0\xb6\xb3\xa7d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa8\xc0\x04/Rglamorous-kitalpha\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'  # noqa
+    }
+
+    with pytest.raises(TransactionNotSentError):
+        wallet.sign_and_send(tx_dict)
+
+
+@mock.patch('skale.wallets.sgx_wallet.SgxClient', new=BadSgxClient)
+def test_sign_error(web3):
+    wallet = SgxWallet(TEST_SGX_ENDPOINT, web3, 'TEST_KEY')
+    tx_dict = {
+        'to': '0x1057dc7277a319927D3eB43e05680B75a00eb5f4',
+        'value': 9,
+        'gas': 200000,
+        'gasPrice': 1,
+        'nonce': 7,
+        'chainId': None,
+        'data': b'\x9b\xd9\xbb\xc6\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95qY\xc4i\xfc;\xba\xa8\xe3\x9e\xe0\xa3$\xc28\x8a\xd6Q\xe5\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r\xe0\xb6\xb3\xa7d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa8\xc0\x04/Rglamorous-kitalpha\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'  # noqa
+    }
+    with pytest.raises(TransactionNotSignedError):
+        wallet.sign(tx_dict)
+
+
+@mock.patch('skale.wallets.sgx_wallet.SgxClient', new=BadSgxClient)
+def test_sign_hash_error(web3):
+    wallet = SgxWallet(TEST_SGX_ENDPOINT, web3, 'TEST_KEY')
+    with pytest.raises(MessageNotSignedError):
+        wallet.sign_hash('0x')
diff --git a/tests/wallets/utils.py b/tests/wallets/utils.py
index 4a9c322f..1b84d229 100644
--- a/tests/wallets/utils.py
+++ b/tests/wallets/utils.py
@@ -49,3 +49,28 @@ def sign_hash(self, message, key_name, chain_id):
             v=27,
             signature=HexBytes('0x6161616161613131313131')
         )
+
+
+class BadSgxClient:
+    def __init__(self, endpoint, path_to_cert=None):
+        pass
+
+    def generate_key(self):
+        return Account(
+            name='NEK:aaabbb',
+            address=ADDRESS,
+            public_key=PUBLIC_KEY
+        )
+
+    def get_account(self, key_name):
+        return Account(
+            name='NEK:aaabbb',
+            address=ADDRESS,
+            public_key=PUBLIC_KEY
+        )
+
+    def sign(self, transaction_dict, key_name):
+        raise ValueError('Test Error')
+
+    def sign_hash(self, message, key_name, chain_id):
+        raise ValueError('Test error')