Repository: multiversx/mx-sdk-py-cli (language: python)

Issue:
Bump version to v8.0.0



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml
index 4dfa1a4e..38108868 100644
--- a/.github/workflows/build-windows.yml
+++ b/.github/workflows/build-windows.yml
@@ -46,8 +46,7 @@ jobs:
       shell: bash
       run: |
         export PYTHONPATH=.
-        python3 -m unittest discover -s multiversx_sdk_cli/tests
-        pytest .
+        pytest -m "not skip_on_windows" .
     - name: Run CLI tests
       shell: bash
       run: |
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index f04afedb..24757526 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -48,7 +48,6 @@ jobs:
     - name: Run unit tests
       run: |
         export PYTHONPATH=.
-        python3 -m unittest discover -s multiversx_sdk_cli/tests
         pytest .
     - name: Run CLI tests
       run: |
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000..2a4f3afd
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,16 @@
+{
+    "python.testing.pytestArgs": [
+        "multiversx_sdk_cli"
+    ],
+    "python.testing.pytestEnabled": true,
+    "editor.formatOnSave": true,
+    "[python]": {
+        "editor.defaultFormatter": "ms-python.autopep8"
+    },
+    "python.formatting.provider": "autopep8",
+    "editor.codeActionsOnSave": {
+        "source.organizeImports": true
+    },
+    "files.insertFinalNewline": true,
+    "python.languageServer": "Pylance"
+}
diff --git a/CLI.md b/CLI.md
index bc45e7ae..6b7e9c6b 100644
--- a/CLI.md
+++ b/CLI.md
@@ -20,7 +20,7 @@ https://docs.multiversx.com/sdk-and-tools/mxpy.
         
 
 COMMAND GROUPS:
-  {contract,tx,validator,account,ledger,wallet,network,deps,config,hyperblock,localnet,data,staking-provider,dns}
+  {contract,tx,validator,account,ledger,wallet,deps,config,localnet,data,staking-provider,dns}
 
 TOP-LEVEL OPTIONS:
   -h, --help            show this help message and exit
@@ -36,10 +36,8 @@ validator                      Stake, UnStake, UnBond, Unjail and other actions
 account                        Get Account data (nonce, balance) from the Network
 ledger                         Get Ledger App addresses and version
 wallet                         Create wallet, derive secret key from mnemonic, bech32 address helpers etc.
-network                        Get Network parameters, such as number of shards, chain identifier etc.
 deps                           Manage dependencies or multiversx-sdk modules
 config                         Configure multiversx-sdk (default values etc.)
-hyperblock                     Get Hyperblock from the Network
 localnet                       Set up, start and control localnets
 data                           Data manipulation omnitool
 staking-provider               Staking provider omnitool
@@ -118,21 +116,25 @@ usage: mxpy contract build [-h] ...
 
 Build a Smart Contract project using the appropriate buildchain.
 
-positional arguments:
-  project                              🗀 the project directory (default: current directory)
-
 options:
-  -h, --help                           show this help message and exit
-  -r, --recursive                      locate projects recursively
-  --debug                              set debug flag (default: False)
-  --no-optimization                    bypass optimizations (for clang) (default: False)
-  --no-wasm-opt                        do not optimize wasm files after the build (default: False)
-  --cargo-target-dir CARGO_TARGET_DIR  for rust projects, forward the parameter to Cargo
-  --wasm-symbols                       for rust projects, does not strip the symbols from the wasm output. Useful for
-                                       analysing the bytecode. Creates larger wasm files. Avoid in production (default:
-                                       False)
-  --wasm-name WASM_NAME                for rust projects, optionally specify the name of the wasm bytecode output file
-  --wasm-suffix WASM_SUFFIX            for rust projects, optionally specify the suffix of the wasm bytecode output file
+  -h, --help                 show this help message and exit
+  --path PATH                the project directory (default: current directory)
+  --no-wasm-opt              do not optimize wasm files after the build (default: False)
+  --wasm-symbols             for rust projects, does not strip the symbols from the wasm output. Useful for analysing
+                             the bytecode. Creates larger wasm files. Avoid in production (default: False)
+  --wasm-name WASM_NAME      for rust projects, optionally specify the name of the wasm bytecode output file
+  --wasm-suffix WASM_SUFFIX  for rust projects, optionally specify the suffix of the wasm bytecode output file
+  --target-dir TARGET_DIR    for rust projects, forward the parameter to Cargo
+  --wat                      also generate a WAT file when building
+  --mir                      also emit MIR files when building
+  --llvm-ir                  also emit LL (LLVM) files when building
+  --ignore IGNORE            ignore all directories with these names. [default: target]
+  --no-imports               skips extracting the EI imports after building the contracts
+  --no-abi-git-version       skips loading the Git version into the ABI
+  --twiggy-top               generate a twiggy top report after building
+  --twiggy-paths             generate a twiggy paths report after building
+  --twiggy-monos             generate a twiggy monos report after building
+  --twiggy-dominators        generate a twiggy dominators report after building
 
 ```
 ### Contract.Clean
@@ -144,12 +146,9 @@ usage: mxpy contract clean [-h] ...
 
 Clean a Smart Contract project.
 
-positional arguments:
-  project          🗀 the project directory (default: current directory)
-
 options:
-  -h, --help       show this help message and exit
-  -r, --recursive  locate projects recursively
+  -h, --help   show this help message and exit
+  --path PATH  the project directory (default: current directory)
 
 ```
 ### Contract.Deploy
@@ -443,9 +442,6 @@ usage: mxpy contract report [-h] ...
 
 Print a detailed report of the smart contracts.
 
-positional arguments:
-  project                                         🗀 the project directory (default: current directory)
-
 options:
   -h, --help                                      show this help message and exit
   --skip-build                                    skips the step of building of the wasm contracts
@@ -455,10 +451,8 @@ options:
   --output-file OUTPUT_FILE                       if specified, the output is written to a file, otherwise it's written
                                                   to the standard output
   --compare report-1.json [report-2.json ...]     create a comparison from two or more reports
-  --debug                                         set debug flag (default: False)
-  --no-optimization                               bypass optimizations (for clang) (default: False)
+  --path PATH                                     the project directory (default: current directory)
   --no-wasm-opt                                   do not optimize wasm files after the build (default: False)
-  --cargo-target-dir CARGO_TARGET_DIR             for rust projects, forward the parameter to Cargo
   --wasm-symbols                                  for rust projects, does not strip the symbols from the wasm output.
                                                   Useful for analysing the bytecode. Creates larger wasm files. Avoid in
                                                   production (default: False)
@@ -466,6 +460,17 @@ options:
                                                   output file
   --wasm-suffix WASM_SUFFIX                       for rust projects, optionally specify the suffix of the wasm bytecode
                                                   output file
+  --target-dir TARGET_DIR                         for rust projects, forward the parameter to Cargo
+  --wat                                           also generate a WAT file when building
+  --mir                                           also emit MIR files when building
+  --llvm-ir                                       also emit LL (LLVM) files when building
+  --ignore IGNORE                                 ignore all directories with these names. [default: target]
+  --no-imports                                    skips extracting the EI imports after building the contracts
+  --no-abi-git-version                            skips loading the Git version into the ABI
+  --twiggy-top                                    generate a twiggy top report after building
+  --twiggy-paths                                  generate a twiggy paths report after building
+  --twiggy-monos                                  generate a twiggy monos report after building
+  --twiggy-dominators                             generate a twiggy dominators report after building
 
 ```
 ## Group **Transactions**
@@ -617,37 +622,6 @@ options:
   --proxy PROXY              🔗 the URL of the proxy
   --omit-fields OMIT_FIELDS  omit fields in the output payload (default: [])
 
-```
-## Group **Hyperblocks**
-
-
-```
-$ mxpy hyperblock --help
-usage: mxpy hyperblock COMMAND [-h] ...
-
-Get Hyperblock from the Network
-
-COMMANDS:
-  {get}
-
-OPTIONS:
-  -h, --help  show this help message and exit
-
-```
-### Hyperblock.Get
-
-
-```
-$ mxpy hyperblock get --help
-usage: mxpy hyperblock get [-h] ...
-
-Get hyperblock
-
-options:
-  -h, --help     show this help message and exit
-  --proxy PROXY  🔗 the URL of the proxy
-  --key KEY      the hash or the nonce of the hyperblock
-
 ```
 ## Group **Validator**
 
@@ -1020,7 +994,7 @@ usage: mxpy wallet COMMAND [-h] ...
 Create wallet, derive secret key from mnemonic, bech32 address helpers etc.
 
 COMMANDS:
-  {new,convert,bech32,pem-address,pem-address-hex}
+  {new,convert,bech32}
 
 OPTIONS:
   -h, --help            show this help message and exit
@@ -1031,8 +1005,6 @@ COMMANDS summary
 new                            Create a new wallet and print its mnemonic; optionally save as password-protected JSON (recommended) or PEM (not recommended)
 convert                        Convert a wallet from one format to another
 bech32                         Helper for encoding and decoding bech32 addresses
-pem-address                    Get the public address out of a PEM file as bech32
-pem-address-hex                Get the public address out of a PEM file as hex
 
 ```
 ### Wallet.New
@@ -1212,72 +1184,6 @@ options:
   -h, --help               show this help message and exit
   --configfile CONFIGFILE  An optional configuration file describing the localnet
 
-```
-## Group **Network**
-
-
-```
-$ mxpy network --help
-usage: mxpy network COMMAND [-h] ...
-
-Get Network parameters, such as number of shards, chain identifier etc.
-
-COMMANDS:
-  {num-shards,block-nonce,chain}
-
-OPTIONS:
-  -h, --help            show this help message and exit
-
-----------------
-COMMANDS summary
-----------------
-num-shards                     Get the number of shards.
-block-nonce                    Get the latest block nonce, by shard.
-chain                          Get the chain identifier.
-
-```
-### Network.NumShards
-
-
-```
-$ mxpy network num-shards --help
-usage: mxpy network num-shards [-h] ...
-
-Get the number of shards.
-
-options:
-  -h, --help     show this help message and exit
-  --proxy PROXY  🔗 the URL of the proxy
-
-```
-### Network.BlockNonce
-
-
-```
-$ mxpy network block-nonce --help
-usage: mxpy network block-nonce [-h] ...
-
-Get the latest block nonce, by shard.
-
-options:
-  -h, --help     show this help message and exit
-  --proxy PROXY  🔗 the URL of the proxy
-  --shard SHARD  the shard ID (use 4294967295 for metachain)
-
-```
-### Network.Chain
-
-
-```
-$ mxpy network chain --help
-usage: mxpy network chain [-h] ...
-
-Get the chain identifier.
-
-options:
-  -h, --help     show this help message and exit
-  --proxy PROXY  🔗 the URL of the proxy
-
 ```
 ## Group **Dependencies**
 
diff --git a/CLI.md.sh b/CLI.md.sh
index 4017b726..7b686d87 100755
--- a/CLI.md.sh
+++ b/CLI.md.sh
@@ -55,9 +55,6 @@ generate() {
     command "Transactions.Send" "tx send"
     command "Transactions.Get" "tx get"
 
-    group "Hyperblocks" "hyperblock"
-    command "Hyperblock.Get" "hyperblock get"
-
     group "Validator" "validator"
     command "Validator.Stake" "validator stake"
     command "Validator.Unstake" "validator unstake"
@@ -83,11 +80,6 @@ generate() {
     command "Localnet.Start" "localnet start"
     command "Localnet.Clean" "localnet clean"
 
-    group "Network" "network"
-    command "Network.NumShards" "network num-shards"
-    command "Network.BlockNonce" "network block-nonce"
-    command "Network.Chain" "network chain"
-
     group "Dependencies" "deps"
     command "Dependencies.Install" "deps install"
     command "Dependencies.Check" "deps check"
diff --git a/multiversx_sdk_cli/accounts.py b/multiversx_sdk_cli/accounts.py
index 17d2d13f..26037d3c 100644
--- a/multiversx_sdk_cli/accounts.py
+++ b/multiversx_sdk_cli/accounts.py
@@ -2,11 +2,11 @@
 from pathlib import Path
 from typing import Any, Optional, Protocol
 
-from multiversx_sdk_core import MessageV1, bech32
+from multiversx_sdk_core import Address, MessageV1
 from multiversx_sdk_network_providers.accounts import AccountOnNetwork
 from multiversx_sdk_wallet import UserSigner
 
-from multiversx_sdk_cli import constants, errors
+from multiversx_sdk_cli.constants import DEFAULT_HRP
 from multiversx_sdk_cli.interfaces import IAccount, IAddress, ITransaction
 from multiversx_sdk_cli.ledger.config import compare_versions
 from multiversx_sdk_cli.ledger.ledger_app_handler import \
@@ -24,9 +24,17 @@ def get_account(self, address: IAddress) -> AccountOnNetwork:
         ...
 
 
+class EmptyAddress(IAddress):
+    def hex(self) -> str:
+        return ""
+
+    def bech32(self) -> str:
+        return ""
+
+
 class AccountBase(IAccount):
-    def __init__(self, address: Any = None):
-        self.address = Address(address)
+    def __init__(self, address: Any = EmptyAddress()) -> None:
+        self.address = address
         self.nonce: int = 0
 
     def sync_nonce(self, proxy: INetworkProvider):
@@ -47,17 +55,17 @@ def __init__(self,
                  pem_file: Optional[str] = None,
                  pem_index: int = 0,
                  key_file: str = "",
-                 password: str = ""):
+                 password: str = "") -> None:
         super().__init__(address)
 
         if pem_file:
             pem_path = Path(pem_file).expanduser().resolve()
             self.signer = UserSigner.from_pem_file(pem_path, pem_index)
-            self.address = Address(self.signer.get_pubkey().buffer)
+            self.address = Address(self.signer.get_pubkey().buffer, DEFAULT_HRP)
         elif key_file and password:
             key_file_path = Path(key_file).expanduser().resolve()
             self.signer = UserSigner.from_wallet(key_file_path, password)
-            self.address = Address(self.signer.get_pubkey().buffer)
+            self.address = Address(self.signer.get_pubkey().buffer, DEFAULT_HRP)
 
     def sign_transaction(self, transaction: ITransaction) -> str:
         assert self.signer is not None
@@ -73,18 +81,18 @@ def sign_message(self, data: bytes) -> str:
 
 
 class LedgerAccount(Account):
-    def __init__(self, account_index: int = 0, address_index: int = 0):
+    def __init__(self, account_index: int = 0, address_index: int = 0) -> None:
         super().__init__()
         self.account_index = account_index
         self.address_index = address_index
-        self.address = Address(do_get_ledger_address(account_index=account_index, address_index=address_index))
+        self.address = Address.from_bech32(do_get_ledger_address(account_index=account_index, address_index=address_index))
 
     def sign_transaction(self, transaction: ITransaction) -> str:
         ledger_version = do_get_ledger_version()
         should_use_hash_signing = compare_versions(ledger_version, SIGN_USING_HASH_VERSION) >= 0
         if should_use_hash_signing:
-            transaction.set_version(TX_HASH_SIGN_VERSION)
-            transaction.set_options(TX_HASH_SIGN_OPTIONS)
+            transaction.version = TX_HASH_SIGN_VERSION
+            transaction.options = TX_HASH_SIGN_OPTIONS
 
         signature = do_sign_transaction_with_ledger(
             transaction.serialize_for_signing(),
@@ -111,76 +119,3 @@ def sign_message(self, data: bytes) -> str:
 
         logger.debug(f"LedgerAccount.sign_message(): signature = {signature}")
         return signature
-
-
-class Address(IAddress):
-    HRP = "erd"
-    PUBKEY_LENGTH = 32
-    PUBKEY_STRING_LENGTH = PUBKEY_LENGTH * 2  # hex-encoded
-    BECH32_LENGTH = 62
-    _value_hex: str
-
-    def __init__(self, value: Any):
-        self._value_hex = ''
-
-        if not value:
-            return
-
-        # Copy-constructor
-        if isinstance(value, Address):
-            value = value._value_hex
-
-        # We keep a hex-encoded string as the "backing" value
-        if len(value) == Address.PUBKEY_LENGTH:
-            self._value_hex = value.hex()
-        elif len(value) == Address.PUBKEY_STRING_LENGTH:
-            self._value_hex = _as_string(value)
-        elif len(value) == Address.BECH32_LENGTH:
-            self._value_hex = _decode_bech32(value).hex()
-        else:
-            raise errors.BadAddressFormatError(value)
-
-    def hex(self) -> str:
-        self._assert_validity()
-        return self._value_hex
-
-    def bech32(self) -> str:
-        self._assert_validity()
-        pubkey = self.pubkey()
-        b32 = bech32.bech32_encode(self.HRP, bech32.convertbits(pubkey, 8, 5))
-        assert isinstance(b32, str)
-        return b32
-
-    def pubkey(self):
-        self._assert_validity()
-        pubkey = bytes.fromhex(self._value_hex)
-        return pubkey
-
-    def is_contract_address(self):
-        return self.hex().startswith(constants.SC_HEX_PUBKEY_PREFIX)
-
-    def _assert_validity(self):
-        if self._value_hex == '':
-            raise errors.EmptyAddressError()
-
-    def __repr__(self):
-        return self.bech32()
-
-    @classmethod
-    def zero(cls) -> 'Address':
-        return Address("0" * 64)
-
-
-def _as_string(value):
-    if isinstance(value, str):
-        return value
-    return value.decode("utf-8")
-
-
-def _decode_bech32(value):
-    bech32_string = _as_string(value)
-    hrp, value_bytes = bech32.bech32_decode(bech32_string)
-    if hrp != Address.HRP:
-        raise errors.BadAddressFormatError(value)
-    decoded_bytes = bech32.convertbits(value_bytes, 5, 8, False)
-    return bytearray(decoded_bytes)
diff --git a/multiversx_sdk_cli/cli.py b/multiversx_sdk_cli/cli.py
index a4db72d5..ceaa080c 100644
--- a/multiversx_sdk_cli/cli.py
+++ b/multiversx_sdk_cli/cli.py
@@ -4,8 +4,9 @@
 from argparse import ArgumentParser
 from typing import Any, List
 
+from rich.logging import RichHandler
+
 import multiversx_sdk_cli.cli_accounts
-import multiversx_sdk_cli.cli_block
 import multiversx_sdk_cli.cli_config
 import multiversx_sdk_cli.cli_contracts
 import multiversx_sdk_cli.cli_data
@@ -14,7 +15,6 @@
 import multiversx_sdk_cli.cli_dns
 import multiversx_sdk_cli.cli_ledger
 import multiversx_sdk_cli.cli_localnet
-import multiversx_sdk_cli.cli_network
 import multiversx_sdk_cli.cli_transactions
 import multiversx_sdk_cli.cli_validators
 import multiversx_sdk_cli.cli_wallet
@@ -38,16 +38,14 @@ def main(cli_args: List[str] = sys.argv[1:]):
 
 
 def _do_main(cli_args: List[str]):
-    logging.basicConfig(level=logging.INFO)
-
     argv_with_config_args = config.add_config_args(cli_args)
     parser = setup_parser(argv_with_config_args)
     args = parser.parse_args(argv_with_config_args)
 
     if args.verbose:
-        logging.basicConfig(level=logging.DEBUG, force=True)
+        logging.basicConfig(level="DEBUG", force=True, format='%(name)s: %(message)s', handlers=[RichHandler(show_time=False, rich_tracebacks=True)])
     else:
-        logging.basicConfig(level=logging.INFO, force=True)
+        logging.basicConfig(level="INFO", format='%(name)s: %(message)s', handlers=[RichHandler(show_time=False, rich_tracebacks=True)])
 
     if not hasattr(args, "func"):
         parser.print_help()
@@ -87,10 +85,8 @@ def setup_parser(args: List[str]):
     commands.append(multiversx_sdk_cli.cli_accounts.setup_parser(subparsers))
     commands.append(multiversx_sdk_cli.cli_ledger.setup_parser(subparsers))
     commands.append(multiversx_sdk_cli.cli_wallet.setup_parser(args, subparsers))
-    commands.append(multiversx_sdk_cli.cli_network.setup_parser(subparsers))
     commands.append(multiversx_sdk_cli.cli_deps.setup_parser(subparsers))
     commands.append(multiversx_sdk_cli.cli_config.setup_parser(subparsers))
-    commands.append(multiversx_sdk_cli.cli_block.setup_parser(subparsers))
     commands.append(multiversx_sdk_cli.cli_localnet.setup_parser(args, subparsers))
     commands.append(multiversx_sdk_cli.cli_data.setup_parser(subparsers))
     commands.append(multiversx_sdk_cli.cli_delegation.setup_parser(args, subparsers))
diff --git a/multiversx_sdk_cli/cli_accounts.py b/multiversx_sdk_cli/cli_accounts.py
index db0882a1..8970c5d2 100644
--- a/multiversx_sdk_cli/cli_accounts.py
+++ b/multiversx_sdk_cli/cli_accounts.py
@@ -1,11 +1,11 @@
 import logging
 from typing import Any
 
+from multiversx_sdk_core import Address
 from multiversx_sdk_network_providers.proxy_network_provider import \
     ProxyNetworkProvider
 
 from multiversx_sdk_cli import cli_shared, utils
-from multiversx_sdk_cli.accounts import Address
 
 logger = logging.getLogger("cli.accounts")
 
@@ -36,7 +36,7 @@ def get_account(args: Any):
     proxy_url = args.proxy
     address = args.address
     proxy = ProxyNetworkProvider(proxy_url)
-    account = proxy.get_account(Address(address))
+    account = proxy.get_account(Address.from_bech32(address))
 
     if args.balance:
         print(account.balance)
diff --git a/multiversx_sdk_cli/cli_block.py b/multiversx_sdk_cli/cli_block.py
deleted file mode 100644
index 9473c063..00000000
--- a/multiversx_sdk_cli/cli_block.py
+++ /dev/null
@@ -1,31 +0,0 @@
-from typing import Any
-
-from multiversx_sdk_cli import cli_shared, utils
-from multiversx_sdk_network_providers.proxy_network_provider import ProxyNetworkProvider
-
-
-def setup_parser(subparsers: Any) -> Any:
-    parser = cli_shared.add_group_subparser(subparsers, "hyperblock", "Get Hyperblock from the Network")
-    subparsers = parser.add_subparsers()
-
-    sub = cli_shared.add_command_subparser(subparsers, "hyperblock", "get", "Get hyperblock")
-
-    cli_shared.add_proxy_arg(sub)
-    sub.add_argument("--key", required=True, help="the hash or the nonce of the hyperblock")
-
-    sub.set_defaults(func=get_hyperblock)
-
-
-def get_hyperblock(args: Any) -> Any:
-    proxy_url = args.proxy
-    proxy = ProxyNetworkProvider(proxy_url)
-    key =  args.key
-
-    url = f"hyperblock/by-hash/{key}"
-    if str(key).isnumeric():
-        url = f"hyperblock/by-nonce/{key}"
-
-    response = proxy.do_get_generic(url)
-    response = response.get("hyperblock", {})
-
-    utils.dump_out_json(response)
diff --git a/multiversx_sdk_cli/cli_config.py b/multiversx_sdk_cli/cli_config.py
index adce5e4f..5169ff20 100644
--- a/multiversx_sdk_cli/cli_config.py
+++ b/multiversx_sdk_cli/cli_config.py
@@ -1,9 +1,8 @@
-from multiversx_sdk_cli import cli_shared
 import logging
 import sys
 from typing import Any
 
-from multiversx_sdk_cli import config, utils
+from multiversx_sdk_cli import cli_shared, config, utils
 
 logger = logging.getLogger("cli.config")
 
diff --git a/multiversx_sdk_cli/cli_contracts.py b/multiversx_sdk_cli/cli_contracts.py
index 0ce3df11..e36ad61e 100644
--- a/multiversx_sdk_cli/cli_contracts.py
+++ b/multiversx_sdk_cli/cli_contracts.py
@@ -1,13 +1,14 @@
 import logging
 import os
 from pathlib import Path
-from typing import Any, Dict, List
+from typing import Any, List
 
+from multiversx_sdk_core import Address, Transaction
 from multiversx_sdk_network_providers.proxy_network_provider import \
     ProxyNetworkProvider
 
 from multiversx_sdk_cli import cli_shared, errors, projects, utils
-from multiversx_sdk_cli.accounts import Account, Address, LedgerAccount
+from multiversx_sdk_cli.accounts import Account, LedgerAccount
 from multiversx_sdk_cli.cli_output import CLIOutputBuilder
 from multiversx_sdk_cli.cli_password import load_password
 from multiversx_sdk_cli.contract_verification import \
@@ -17,7 +18,6 @@
 from multiversx_sdk_cli.docker import is_docker_installed, run_docker
 from multiversx_sdk_cli.errors import DockerMissingError, NoWalletProvided
 from multiversx_sdk_cli.projects.core import get_project_paths_recursively
-from multiversx_sdk_cli.transactions import Transaction
 
 logger = logging.getLogger("cli.contracts")
 
@@ -40,14 +40,11 @@ def setup_parser(args: List[str], subparsers: Any) -> Any:
 
     sub = cli_shared.add_command_subparser(subparsers, "contract", "build",
                                            "Build a Smart Contract project using the appropriate buildchain.")
-    _add_project_arg(sub)
-    _add_recursive_arg(sub)
-    _add_build_options_args(sub)
+    _add_build_options_sc_meta(sub)
     sub.set_defaults(func=build)
 
     sub = cli_shared.add_command_subparser(subparsers, "contract", "clean", "Clean a Smart Contract project.")
-    _add_project_arg(sub)
-    _add_recursive_arg(sub)
+    sub.add_argument("--path", default=os.getcwd(), help="the project directory (default: current directory)")
     sub.set_defaults(func=clean)
 
     sub = cli_shared.add_command_subparser(subparsers, "contract", "test", "Run scenarios (tests).")
@@ -59,13 +56,12 @@ def setup_parser(args: List[str], subparsers: Any) -> Any:
     sub.set_defaults(func=run_tests)
 
     sub = cli_shared.add_command_subparser(subparsers, "contract", "report", "Print a detailed report of the smart contracts.")
-    _add_project_arg(sub)
     sub.add_argument("--skip-build", action="store_true", default=False, help="skips the step of building of the wasm contracts")
     sub.add_argument("--skip-twiggy", action="store_true", default=False, help="skips the steps of building the debug wasm files and running twiggy")
     sub.add_argument("--output-format", type=str, default="text-markdown", choices=["github-markdown", "text-markdown", "json"], help="report output format (default: %(default)s)")
     sub.add_argument("--output-file", type=Path, help="if specified, the output is written to a file, otherwise it's written to the standard output")
     sub.add_argument("--compare", type=Path, nargs='+', metavar=("report-1.json", "report-2.json"), help="create a comparison from two or more reports")
-    _add_build_options_args(sub)
+    _add_build_options_sc_meta(sub)
     sub.set_defaults(func=do_report)
 
     output_description = CLIOutputBuilder.describe(with_contract=True, with_transaction_on_network=True, with_simulation=True)
@@ -131,12 +127,9 @@ def setup_parser(args: List[str], subparsers: Any) -> Any:
     _add_arguments_arg(sub)
     sub.set_defaults(func=query)
 
-    sub = cli_shared.add_command_subparser(
-        subparsers,
-        "contract",
-        "verify",
-        "Verify the authenticity of the code of a deployed Smart Contract",
-    )
+    sub = cli_shared.add_command_subparser(subparsers, "contract", "verify",
+                                           "Verify the authenticity of the code of a deployed Smart Contract",
+                                           )
 
     sub.add_argument(
         "--packaged-src", required=True, help="JSON file containing the source code of the contract"
@@ -175,6 +168,29 @@ def _add_project_arg(sub: Any):
                      help="🗀 the project directory (default: current directory)")
 
 
+def _add_build_options_sc_meta(sub: Any):
+    sub.add_argument("--path", default=os.getcwd(), help="the project directory (default: current directory)")
+    sub.add_argument("--no-wasm-opt", action="store_true", default=False,
+                     help="do not optimize wasm files after the build (default: %(default)s)")
+    sub.add_argument("--wasm-symbols", action="store_true", default=False,
+                     help="for rust projects, does not strip the symbols from the wasm output. Useful for analysing the bytecode. Creates larger wasm files. Avoid in production (default: %(default)s)")
+    sub.add_argument("--wasm-name", type=str,
+                     help="for rust projects, optionally specify the name of the wasm bytecode output file")
+    sub.add_argument("--wasm-suffix", type=str,
+                     help="for rust projects, optionally specify the suffix of the wasm bytecode output file")
+    sub.add_argument("--target-dir", type=str, help="for rust projects, forward the parameter to Cargo")
+    sub.add_argument("--wat", action="store_true", help="also generate a WAT file when building", default=False)
+    sub.add_argument("--mir", action="store_true", help="also emit MIR files when building", default=False)
+    sub.add_argument("--llvm-ir", action="store_true", help="also emit LL (LLVM) files when building", default=False)
+    sub.add_argument("--ignore", help="ignore all directories with these names. [default: target]")
+    sub.add_argument("--no-imports", action="store_true", default=False, help="skips extracting the EI imports after building the contracts")
+    sub.add_argument("--no-abi-git-version", action="store_true", default=False, help="skips loading the Git version into the ABI")
+    sub.add_argument("--twiggy-top", action="store_true", default=False, help="generate a twiggy top report after building")
+    sub.add_argument("--twiggy-paths", action="store_true", default=False, help="generate a twiggy paths report after building")
+    sub.add_argument("--twiggy-monos", action="store_true", default=False, help="generate a twiggy monos report after building")
+    sub.add_argument("--twiggy-dominators", action="store_true", default=False, help="generate a twiggy dominators report after building")
+
+
 def _add_build_options_args(sub: Any):
     sub.add_argument("--debug", action="store_true", default=False, help="set debug flag (default: %(default)s)")
     sub.add_argument("--no-optimization", action="store_true", default=False,
@@ -246,35 +262,21 @@ def get_project_paths(args: Any) -> List[Path]:
 
 
 def clean(args: Any):
-    project_paths = get_project_paths(args)
-    for project in project_paths:
-        projects.clean_project(project)
+    project_path = args.path
+    projects.clean_project(Path(project_path))
 
 
 def build(args: Any):
-    project_paths = get_project_paths(args)
-    options: Dict[str, Any] = _prepare_build_options(args)
+    project_paths = [Path(args.path)]
+    arg_list = cli_shared.convert_args_object_to_args_list(args)
 
     for project in project_paths:
-        projects.build_project(project, options)
-
-
-def _prepare_build_options(args: Any) -> Dict[str, Any]:
-    return {
-        "debug": args.debug,
-        "optimized": not args.no_optimization,
-        "no-wasm-opt": args.no_wasm_opt,
-        "verbose": args.verbose,
-        "cargo-target-dir": args.cargo_target_dir,
-        "wasm-symbols": args.wasm_symbols,
-        "wasm-name": args.wasm_name,
-        "wasm-suffix": args.wasm_suffix
-    }
+        projects.build_project(project, arg_list)
 
 
 def do_report(args: Any):
-    build_options: Dict[str, Any] = _prepare_build_options(args)
-    projects.do_report(args, build_options)
+    args_dict = args.__dict__
+    projects.do_report(args, args_dict)
 
 
 def run_tests(args: Any):
@@ -301,8 +303,8 @@ def deploy(args: Any):
     tx = contract.deploy(sender, arguments, gas_price, gas_limit, value, args.chain, version, args.guardian, args.options)
     tx = _sign_guarded_tx(args, tx)
 
-    logger.info("Contract address: %s", contract.address)
-    utils.log_explorer_contract_address(args.chain, contract.address)
+    logger.info("Contract address: %s", contract.address.bech32())
+    utils.log_explorer_contract_address(args.chain, contract.address.bech32())
 
     _send_or_simulate(tx, contract, args)
 
@@ -354,21 +356,16 @@ def _prepare_signer(args: Any) -> Account:
 
 
 def _sign_guarded_tx(args: Any, tx: Transaction) -> Transaction:
-    signature = tx.signature
-    tx.signature = ""
-
     try:
         guardian_account = cli_shared.prepare_guardian_account(args)
     except NoWalletProvided:
         guardian_account = None
 
     if guardian_account:
-        tx.guardianSignature = guardian_account.sign_transaction(tx)
+        tx.guardian_signature = bytes.fromhex(guardian_account.sign_transaction(tx))
     elif args.guardian:
         tx = cosign_transaction(tx, args.guardian_service_url, args.guardian_2fa_code)  # type: ignore
 
-    tx.signature = signature
-
     return tx
 
 
@@ -385,7 +382,7 @@ def call(args: Any):
     value = args.value
     version = args.version
 
-    contract = SmartContract(contract_address)
+    contract = SmartContract(Address.from_bech32(contract_address))
     sender = _prepare_sender(args)
     cli_shared.prepare_chain_id_in_args(args)
 
@@ -407,7 +404,7 @@ def upgrade(args: Any):
     version = args.version
 
     contract = _prepare_contract(args)
-    contract.address = Address(contract_address)
+    contract.address = Address.from_bech32(contract_address)
     sender = _prepare_sender(args)
     cli_shared.prepare_chain_id_in_args(args)
 
@@ -424,7 +421,7 @@ def query(args: Any):
     function = args.function
     arguments = args.arguments
 
-    contract = SmartContract(contract_address)
+    contract = SmartContract(address=Address.from_bech32(contract_address))
     result = contract.query(ProxyNetworkProvider(args.proxy), function, arguments)
     utils.dump_out_json(result)
 
@@ -436,7 +433,7 @@ def _send_or_simulate(tx: Transaction, contract: SmartContract, args: Any):
 
 
 def verify(args: Any) -> None:
-    contract = Address(args.contract)
+    contract = Address.from_bech32(args.contract)
     verifier_url = args.verifier_url
 
     packaged_src = Path(args.packaged_src).expanduser().resolve()
@@ -465,7 +462,7 @@ def do_reproducible_build(args: Any):
 
     utils.ensure_folder(output_path)
 
-    options = _prepare_build_options(args)
+    options = args.__dict__
     no_wasm_opt = options.get("no-wasm-opt", True)
 
     if not is_docker_installed():
diff --git a/multiversx_sdk_cli/cli_dns.py b/multiversx_sdk_cli/cli_dns.py
index 44983063..2e915539 100644
--- a/multiversx_sdk_cli/cli_dns.py
+++ b/multiversx_sdk_cli/cli_dns.py
@@ -1,11 +1,16 @@
 from typing import Any, List
+
+from multiversx_sdk_core import Address
+from multiversx_sdk_network_providers.proxy_network_provider import \
+    ProxyNetworkProvider
 from prettytable import PrettyTable
 
 from multiversx_sdk_cli import cli_shared
-from multiversx_sdk_cli.dns import (name_hash, dns_address_for_name, register, resolve, registration_cost,
-                                    validate_name, version, compute_dns_address_for_shard_id)
-from multiversx_sdk_cli.accounts import Address
-from multiversx_sdk_network_providers.proxy_network_provider import ProxyNetworkProvider
+from multiversx_sdk_cli.constants import ADDRESS_ZERO_BECH32
+from multiversx_sdk_cli.dns import (compute_dns_address_for_shard_id,
+                                    dns_address_for_name, name_hash, register,
+                                    registration_cost, resolve, validate_name,
+                                    version)
 
 
 def setup_parser(args: List[str], subparsers: Any) -> Any:
@@ -69,7 +74,7 @@ def _add_name_arg(sub: Any):
 
 def dns_resolve(args: Any):
     addr = resolve(args.name, ProxyNetworkProvider(args.proxy))
-    if addr.hex() != Address.zero().hex():
+    if addr.hex() != Address.from_bech32(ADDRESS_ZERO_BECH32).hex():
         print(addr.bech32())
 
 
diff --git a/multiversx_sdk_cli/cli_network.py b/multiversx_sdk_cli/cli_network.py
deleted file mode 100644
index 08ddc014..00000000
--- a/multiversx_sdk_cli/cli_network.py
+++ /dev/null
@@ -1,52 +0,0 @@
-from multiversx_sdk_network_providers.proxy_network_provider import ProxyNetworkProvider
-from multiversx_sdk_cli import cli_shared
-import logging
-from typing import Any
-
-logger = logging.getLogger("cli.network")
-
-
-def setup_parser(subparsers: Any) -> Any:
-    parser = cli_shared.add_group_subparser(subparsers, "network", "Get Network parameters, such as number of shards, chain identifier etc.")
-    subparsers = parser.add_subparsers()
-
-    sub = cli_shared.add_command_subparser(subparsers, "network", "num-shards", "Get the number of shards.")
-    cli_shared.add_proxy_arg(sub)
-    sub.set_defaults(func=get_num_shards)
-
-    sub = cli_shared.add_command_subparser(subparsers, "network", "block-nonce", "Get the latest block nonce, by shard.")
-    cli_shared.add_proxy_arg(sub)
-    sub.add_argument("--shard", required=True, help="the shard ID (use 4294967295 for metachain)")
-    sub.set_defaults(func=get_last_block_nonce)
-
-    sub = cli_shared.add_command_subparser(subparsers, "network", "chain", "Get the chain identifier.")
-    cli_shared.add_proxy_arg(sub)
-    sub.set_defaults(func=get_chain_id)
-
-    parser.epilog = cli_shared.build_group_epilog(subparsers)
-    return subparsers
-
-
-def get_num_shards(args: Any):
-    proxy_url = args.proxy
-    proxy = ProxyNetworkProvider(proxy_url)
-    num_shards = proxy.get_network_config().num_shards_without_meta
-    print(num_shards)
-    return num_shards
-
-
-def get_last_block_nonce(args: Any):
-    proxy_url = args.proxy
-    shard = args.shard
-    proxy = ProxyNetworkProvider(proxy_url)
-    nonce = proxy.get_network_status(shard).highest_final_nonce
-    print(nonce)
-    return nonce
-
-
-def get_chain_id(args: Any):
-    proxy_url = args.proxy
-    proxy = ProxyNetworkProvider(proxy_url)
-    chain_id = proxy.get_network_config().chain_id
-    print(chain_id)
-    return chain_id
diff --git a/multiversx_sdk_cli/cli_output.py b/multiversx_sdk_cli/cli_output.py
index 94d76d3c..bbdc5e02 100644
--- a/multiversx_sdk_cli/cli_output.py
+++ b/multiversx_sdk_cli/cli_output.py
@@ -1,10 +1,11 @@
-from collections import OrderedDict
 import json
-from typing import Any, Dict, List, Union
 import logging
-from multiversx_sdk_cli import utils
+from collections import OrderedDict
+from typing import Any, Dict, List, Optional, Union
+
+from multiversx_sdk_core import Address
 
-from multiversx_sdk_cli.accounts import Address
+from multiversx_sdk_cli import utils
 from multiversx_sdk_cli.interfaces import ITransaction
 from multiversx_sdk_cli.utils import ISerializable
 
@@ -13,6 +14,7 @@
 
 class CLIOutputBuilder:
     def __init__(self) -> None:
+        self.emitted_transaction_hash: Optional[str] = None
         self.emitted_transaction: Union[ITransaction, None] = None
         self.emitted_transaction_omitted_fields: List[str] = []
         self.contract_address: Union[Address, None] = None
@@ -20,6 +22,10 @@ def __init__(self) -> None:
         self.transaction_on_network_omitted_fields: List[str] = []
         self.simulation_results: Union[ISerializable, None] = None
 
+    def set_emitted_transaction_hash(self, hash: str):
+        self.emitted_transaction_hash = hash
+        return self
+
     def set_emitted_transaction(self, emitted_transaction: ITransaction, omitted_fields: List[str] = []):
         self.emitted_transaction = emitted_transaction
         self.emitted_transaction_omitted_fields = omitted_fields
@@ -46,8 +52,8 @@ def build(self) -> Dict[str, Any]:
 
         if self.emitted_transaction:
             emitted_transaction_dict = self.emitted_transaction.to_dictionary()
-            emitted_transaction_hash = self.emitted_transaction.get_hash() or ""
-            emitted_transaction_data = self.emitted_transaction.get_data() or ""
+            emitted_transaction_hash = self.emitted_transaction_hash or ""
+            emitted_transaction_data = str(self.emitted_transaction.data)
             utils.omit_fields(emitted_transaction_dict, self.emitted_transaction_omitted_fields)
 
             output["emittedTransaction"] = emitted_transaction_dict
diff --git a/multiversx_sdk_cli/cli_password.py b/multiversx_sdk_cli/cli_password.py
index 227e5abf..d7fff56b 100644
--- a/multiversx_sdk_cli/cli_password.py
+++ b/multiversx_sdk_cli/cli_password.py
@@ -1,15 +1,15 @@
-from typing import Any
 from getpass import getpass
+from typing import Any
 
 
-def load_password(args: Any):
+def load_password(args: Any) -> str:
     if args.passfile:
         with open(args.passfile) as pass_file:
             return pass_file.read().strip()
     return getpass("Keyfile's password: ")
 
 
-def load_guardian_password(args: Any):
+def load_guardian_password(args: Any) -> str:
     if args.guardian_passfile:
         with open(args.guardian_passfile) as pass_file:
             return pass_file.read().strip()
diff --git a/multiversx_sdk_cli/cli_shared.py b/multiversx_sdk_cli/cli_shared.py
index a0f655a0..2438695e 100644
--- a/multiversx_sdk_cli/cli_shared.py
+++ b/multiversx_sdk_cli/cli_shared.py
@@ -1,9 +1,11 @@
 import argparse
 import ast
+import copy
 import sys
 from argparse import FileType
-from typing import Any, List, Text, cast
+from typing import Any, Dict, List, Text, cast
 
+from multiversx_sdk_core import Address
 from multiversx_sdk_network_providers.proxy_network_provider import \
     ProxyNetworkProvider
 
@@ -15,9 +17,10 @@
 from multiversx_sdk_cli.constants import (DEFAULT_TX_VERSION,
                                           TRANSACTION_OPTIONS_TX_GUARDED)
 from multiversx_sdk_cli.errors import ArgumentsNotProvidedError
+from multiversx_sdk_cli.interfaces import ITransaction
 from multiversx_sdk_cli.ledger.ledger_functions import do_get_ledger_address
 from multiversx_sdk_cli.simulation import Simulator
-from multiversx_sdk_cli.transactions import Transaction
+from multiversx_sdk_cli.transactions import send_and_wait_for_result
 from multiversx_sdk_cli.ux import show_warning
 
 
@@ -147,7 +150,7 @@ def prepare_account(args: Any):
         account = Account(key_file=args.keyfile, password=password)
     elif args.ledger:
         address = do_get_ledger_address(account_index=args.ledger_account_index, address_index=args.ledger_address_index)
-        account = Account(address=address)
+        account = Account(address=Address.from_bech32(address))
     else:
         raise errors.NoWalletProvided()
 
@@ -162,7 +165,7 @@ def prepare_guardian_account(args: Any):
         account = Account(key_file=args.guardian_keyfile, password=password)
     elif args.guardian_ledger:
         address = do_get_ledger_address(account_index=args.guardian_ledger_account_index, address_index=args.guardian_ledger_address_index)
-        account = Account(address=address)
+        account = Account(Address.from_bech32(address))
     else:
         raise errors.NoWalletProvided()
 
@@ -245,7 +248,7 @@ def check_options_for_guarded_tx(options: int):
         raise errors.BadUsage("Invalid guarded transaction's options. The second least significant bit must be set.")
 
 
-def send_or_simulate(tx: Transaction, args: Any, dump_output: bool = True) -> CLIOutputBuilder:
+def send_or_simulate(tx: ITransaction, args: Any, dump_output: bool = True) -> CLIOutputBuilder:
     proxy = ProxyNetworkProvider(args.proxy)
 
     is_set_wait_result = hasattr(args, "wait_result") and args.wait_result
@@ -262,10 +265,11 @@ def send_or_simulate(tx: Transaction, args: Any, dump_output: bool = True) -> CL
 
     try:
         if send_wait_result:
-            transaction_on_network = tx.send_wait_result(proxy, args.timeout)
+            transaction_on_network = send_and_wait_for_result(tx, proxy, args.timeout)
             output_builder.set_awaited_transaction(transaction_on_network)
         elif send_only:
-            tx.send(proxy)
+            hash = proxy.send_transaction(tx)
+            output_builder.set_emitted_transaction_hash(hash)
         elif simulate:
             simulation = Simulator(proxy).run(tx)
             output_builder.set_simulation_results(simulation)
@@ -288,3 +292,24 @@ def check_if_sign_method_required(args: List[str], checked_method: str) -> bool:
             return False
 
     return True
+
+
+def convert_args_object_to_args_list(args: Any) -> List[str]:
+    arguments = copy.deepcopy(args)
+    args_dict: Dict[str, Any] = arguments.__dict__
+
+    # delete the function key because we don't need to pass it along
+    args_dict.pop("func", None)
+
+    args_list: List[str] = []
+    for key, val in args_dict.items():
+        modified_key = "--" + key.replace("_", "-")
+
+        if isinstance(val, bool) and val:
+            args_list.extend([modified_key])
+            continue
+
+        if val:
+            args_list.extend([modified_key, val])
+
+    return args_list
diff --git a/multiversx_sdk_cli/cli_transactions.py b/multiversx_sdk_cli/cli_transactions.py
index 8678ba2f..90f8cf8e 100644
--- a/multiversx_sdk_cli/cli_transactions.py
+++ b/multiversx_sdk_cli/cli_transactions.py
@@ -8,7 +8,9 @@
 from multiversx_sdk_cli.cli_output import CLIOutputBuilder
 from multiversx_sdk_cli.cosign_transaction import cosign_transaction
 from multiversx_sdk_cli.errors import NoWalletProvided
-from multiversx_sdk_cli.transactions import Transaction, do_prepare_transaction
+from multiversx_sdk_cli.transactions import (compute_relayed_v1_data,
+                                             do_prepare_transaction,
+                                             load_transaction_from_file)
 
 
 def setup_parser(args: List[str], subparsers: Any) -> Any:
@@ -75,7 +77,7 @@ def create_transaction(args: Any):
     tx = do_prepare_transaction(args)
 
     if hasattr(args, "relay") and args.relay:
-        args.outfile.write(tx.serialize_as_inner())
+        args.outfile.write(compute_relayed_v1_data(tx))
         return
 
     cli_shared.send_or_simulate(tx, args)
@@ -84,12 +86,15 @@ def create_transaction(args: Any):
 def send_transaction(args: Any):
     args = utils.as_object(args)
 
-    tx = Transaction.load_from_file(args.infile)
+    tx = load_transaction_from_file(args.infile)
+    output = CLIOutputBuilder()
 
     try:
-        tx.send(ProxyNetworkProvider(args.proxy))
+        proxy = ProxyNetworkProvider(args.proxy)
+        tx_hash = proxy.send_transaction(tx)
+        output.set_emitted_transaction_hash(tx_hash)
     finally:
-        output = CLIOutputBuilder().set_emitted_transaction(tx).build()
+        output = output.set_emitted_transaction(tx).build()
         utils.dump_out_json(output, outfile=args.outfile)
 
 
@@ -98,7 +103,7 @@ def get_transaction(args: Any):
     omit_fields = cli_shared.parse_omit_fields_arg(args)
     proxy = ProxyNetworkProvider(args.proxy)
 
-    transaction = proxy.get_transaction(args.hash)
+    transaction = proxy.get_transaction(args.hash, True)
     output = CLIOutputBuilder().set_transaction_on_network(transaction, omit_fields).build()
     utils.dump_out_json(output)
 
@@ -109,16 +114,12 @@ def sign_transaction(args: Any):
     cli_shared.check_guardian_args(args)
     cli_shared.check_broadcast_args(args)
 
-    tx = Transaction.load_from_file(args.infile)
+    tx = load_transaction_from_file(args.infile)
     if args.guardian:
         cli_shared.check_options_for_guarded_tx(tx.options)
 
-    # clear existing signatures, if any
-    tx.guardianSignature = ""
-    tx.signature = ""
-
     account = cli_shared.prepare_account(args)
-    signature = account.sign_transaction(tx)
+    tx.signature = bytes.fromhex(account.sign_transaction(tx))
 
     try:
         guardian_account = cli_shared.prepare_guardian_account(args)
@@ -126,10 +127,8 @@ def sign_transaction(args: Any):
         guardian_account = None
 
     if guardian_account:
-        tx.guardianSignature = guardian_account.sign_transaction(tx)
+        tx.guardian_signature = bytes.fromhex(guardian_account.sign_transaction(tx))
     elif args.guardian:
         tx = cosign_transaction(tx, args.guardian_service_url, args.guardian_2fa_code)
 
-    tx.signature = signature
-
     cli_shared.send_or_simulate(tx, args)
diff --git a/multiversx_sdk_cli/cli_wallet.py b/multiversx_sdk_cli/cli_wallet.py
index 09d6ca03..523f8159 100644
--- a/multiversx_sdk_cli/cli_wallet.py
+++ b/multiversx_sdk_cli/cli_wallet.py
@@ -5,12 +5,13 @@
 from pathlib import Path
 from typing import Any, List, Optional, Tuple
 
+from multiversx_sdk_core import Address
 from multiversx_sdk_wallet import UserSecretKey, UserWallet
 from multiversx_sdk_wallet.mnemonic import Mnemonic
 from multiversx_sdk_wallet.user_pem import UserPEM
 
 from multiversx_sdk_cli import cli_shared
-from multiversx_sdk_cli.accounts import Account, Address
+from multiversx_sdk_cli.constants import DEFAULT_HRP
 from multiversx_sdk_cli.errors import KnownError
 
 logger = logging.getLogger("cli.wallet")
@@ -43,7 +44,7 @@ def setup_parser(args: List[str], subparsers: Any) -> Any:
     )
     sub.add_argument("--format", choices=WALLET_FORMATS, help="the format of the generated wallet file (default: %(default)s)", default=None)
     sub.add_argument("--outfile", help="the output path and base file name for the generated wallet files (default: %(default)s)", type=str)
-    sub.add_argument("--address-hrp", help=f"the human-readable part of the address, when format is {WALLET_FORMAT_KEYSTORE_SECRET_KEY} or {WALLET_FORMAT_PEM} (default: %(default)s)", type=str, default="erd")
+    sub.add_argument("--address-hrp", help=f"the human-readable part of the address, when format is {WALLET_FORMAT_KEYSTORE_SECRET_KEY} or {WALLET_FORMAT_PEM} (default: %(default)s)", type=str, default=DEFAULT_HRP)
     sub.set_defaults(func=wallet_new)
 
     sub = cli_shared.add_command_subparser(
@@ -57,7 +58,7 @@ def setup_parser(args: List[str], subparsers: Any) -> Any:
     sub.add_argument("--in-format", required=True, choices=WALLET_FORMATS, help="the format of the input file")
     sub.add_argument("--out-format", required=True, choices=WALLET_FORMATS, help="the format of the output file")
     sub.add_argument("--address-index", help=f"the address index, if input format is {WALLET_FORMAT_RAW_MNEMONIC}, {WALLET_FORMAT_KEYSTORE_MNEMONIC} or {WALLET_FORMAT_PEM} (with multiple entries) and the output format is {WALLET_FORMAT_KEYSTORE_SECRET_KEY} or {WALLET_FORMAT_PEM}", type=int, default=0)
-    sub.add_argument("--address-hrp", help=f"the human-readable part of the address, when the output format is {WALLET_FORMAT_KEYSTORE_SECRET_KEY} or {WALLET_FORMAT_PEM} (default: %(default)s)", type=str, default="erd")
+    sub.add_argument("--address-hrp", help=f"the human-readable part of the address, when the output format is {WALLET_FORMAT_KEYSTORE_SECRET_KEY} or {WALLET_FORMAT_PEM} (default: %(default)s)", type=str, default=DEFAULT_HRP)
     sub.set_defaults(func=convert_wallet)
 
     sub = cli_shared.add_command_subparser(
@@ -72,26 +73,6 @@ def setup_parser(args: List[str], subparsers: Any) -> Any:
     group.add_argument("--decode", action="store_true", help="whether to decode")
     sub.set_defaults(func=do_bech32)
 
-    sub = cli_shared.add_command_subparser(
-        subparsers,
-        "wallet",
-        "pem-address",
-        "Get the public address out of a PEM file as bech32"
-    )
-    sub.add_argument("pem", help="path to the PEM file")
-    sub.add_argument("--pem-index", default=0, help="🔑 the index in the PEM file (default: %(default)s)")
-    sub.set_defaults(func=pem_address)
-
-    sub = cli_shared.add_command_subparser(
-        subparsers,
-        "wallet",
-        "pem-address-hex",
-        "Get the public address out of a PEM file as hex"
-    )
-    sub.add_argument("pem", help="path to the PEM file")
-    sub.add_argument("--pem-index", default=0, help="🔑 the index in the PEM file (default: %(default)s)")
-    sub.set_defaults(func=pem_address_hex)
-
     parser.epilog = cli_shared.build_group_epilog(subparsers)
     return subparsers
 
@@ -234,18 +215,13 @@ def _create_wallet_content(
 def do_bech32(args: Any):
     encode = args.encode
     value = args.value
-    address = Address(value)
 
-    result = address.bech32() if encode else address.hex()
+    if encode:
+        address = Address.from_hex(value, DEFAULT_HRP)
+        result = address.bech32()
+    else:
+        address = Address.from_bech32(value)
+        result = address.hex()
+
     print(result)
     return result
-
-
-def pem_address(args: Any):
-    account = Account(pem_file=args.pem, pem_index=args.pem_index)
-    print(account.address)
-
-
-def pem_address_hex(args: Any):
-    account = Account(pem_file=args.pem, pem_index=args.pem_index)
-    print(account.address.hex())
diff --git a/multiversx_sdk_cli/config.py b/multiversx_sdk_cli/config.py
index 2dc532c6..638a22e4 100644
--- a/multiversx_sdk_cli/config.py
+++ b/multiversx_sdk_cli/config.py
@@ -155,9 +155,9 @@ def get_defaults() -> Dict[str, Any]:
         "dependencies.llvm.urlTemplate.linux": "https://ide.elrond.com/vendor-llvm/{TAG}/linux-amd64.tar.gz?t=19feb",
         "dependencies.llvm.urlTemplate.osx": "https://ide.elrond.com/vendor-llvm/{TAG}/darwin-amd64.tar.gz?t=19feb",
         "dependencies.rust.resolution": "SDK",
-        "dependencies.rust.tag": "nightly-2023-04-24",
+        "dependencies.rust.tag": "nightly-2023-05-26",
         "dependencies.golang.resolution": "SDK",
-        "dependencies.golang.tag": "go1.20.5",
+        "dependencies.golang.tag": "go1.20.7",
         "dependencies.golang.urlTemplate.linux": "https://golang.org/dl/{TAG}.linux-amd64.tar.gz",
         "dependencies.golang.urlTemplate.osx": "https://golang.org/dl/{TAG}.darwin-amd64.tar.gz",
         "dependencies.golang.urlTemplate.windows": "https://golang.org/dl/{TAG}.windows-amd64.zip",
diff --git a/multiversx_sdk_cli/constants.py b/multiversx_sdk_cli/constants.py
index ac5f3b20..0e92e53a 100644
--- a/multiversx_sdk_cli/constants.py
+++ b/multiversx_sdk_cli/constants.py
@@ -8,3 +8,6 @@
 ONE_YEAR_IN_SECONDS = 60 * 60 * 24 * 365
 
 DEFAULT_TX_VERSION = 2
+
+DEFAULT_HRP = "erd"
+ADDRESS_ZERO_BECH32 = "erd1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq6gq4hu"
diff --git a/multiversx_sdk_cli/contract_verification.py b/multiversx_sdk_cli/contract_verification.py
index 5599870f..d9b78824 100644
--- a/multiversx_sdk_cli/contract_verification.py
+++ b/multiversx_sdk_cli/contract_verification.py
@@ -3,11 +3,12 @@
 import logging
 import time
 from pathlib import Path
-from typing import Any, Dict, Tuple, Optional
+from typing import Any, Dict, Optional, Tuple
 
 import requests
+from multiversx_sdk_core import Address
 
-from multiversx_sdk_cli.accounts import Account, Address
+from multiversx_sdk_cli.accounts import Account
 from multiversx_sdk_cli.errors import KnownError
 from multiversx_sdk_cli.utils import dump_out_json, read_json_file
 
diff --git a/multiversx_sdk_cli/contracts.py b/multiversx_sdk_cli/contracts.py
index 450e04fc..267d9922 100644
--- a/multiversx_sdk_cli/contracts.py
+++ b/multiversx_sdk_cli/contracts.py
@@ -1,19 +1,19 @@
 import base64
 import logging
-from typing import Any, List, Optional, Tuple, Protocol, Sequence
+from typing import Any, List, Optional, Protocol, Sequence, Tuple
 
-from Cryptodome.Hash import keccak
+from multiversx_sdk_core import Transaction, TransactionPayload
+from multiversx_sdk_core.address import Address, compute_contract_address
+from multiversx_sdk_network_providers.interface import IAddress, IContractQuery
 
 from multiversx_sdk_cli import config, constants, errors
-from multiversx_sdk_cli.accounts import Account, Address
-from multiversx_sdk_cli.transactions import Transaction
+from multiversx_sdk_cli.accounts import Account, EmptyAddress
+from multiversx_sdk_cli.constants import ADDRESS_ZERO_BECH32, DEFAULT_HRP
 from multiversx_sdk_cli.utils import Object
-from multiversx_sdk_network_providers.interface import IContractQuery
 
 logger = logging.getLogger("contracts")
 
 HEX_PREFIX = "0x"
-ERD_BECH32_PREFIX = "erd"
 FALSE_STR_LOWER = "false"
 TRUE_STR_LOWER = "true"
 STR_PREFIX = "str:"
@@ -32,14 +32,14 @@ def __init__(self, as_base64: str, as_hex: str, as_number: Optional[int]):
 
 
 class ContractQuery(IContractQuery):
-    def __init__(self, address: Address, function: str, value: int, arguments: List[bytes], caller: Optional[Address] = None):
+    def __init__(self, address: IAddress, function: str, value: int, arguments: List[bytes], caller: Optional[IAddress] = None):
         self.contract = address
         self.function = function
         self.caller = caller
         self.value = value
         self.encoded_arguments = [item.hex() for item in arguments]
 
-    def get_contract(self) -> Address:
+    def get_contract(self) -> IAddress:
         return self.contract
 
     def get_function(self) -> str:
@@ -48,7 +48,7 @@ def get_function(self) -> str:
     def get_encoded_arguments(self) -> Sequence[str]:
         return self.encoded_arguments
 
-    def get_caller(self) -> Optional[Address]:
+    def get_caller(self) -> Optional[IAddress]:
         return self.caller
 
     def get_value(self) -> int:
@@ -62,54 +62,46 @@ class IContractQueryResponse(Protocol):
 
 
 class SmartContract:
-    def __init__(self, address: Optional[Address] = None, bytecode=None, metadata=None):
-        self.address = Address(address)
+    def __init__(self, address: Optional[IAddress] = EmptyAddress(), bytecode=None, metadata=None):
+        self.address = address
         self.bytecode = bytecode
         self.metadata = metadata or CodeMetadata()
 
     def deploy(self, owner: Account, arguments: List[Any], gas_price: int, gas_limit: int, value: int, chain: str, version: int, guardian: str, options: int) -> Transaction:
         self.owner = owner
-        self.compute_address()
+        self.address = compute_contract_address(self.owner.address, self.owner.nonce, DEFAULT_HRP)
 
         arguments = arguments or []
         gas_price = int(gas_price)
         gas_limit = int(gas_limit)
         value = value or 0
 
-        tx = Transaction()
-        tx.nonce = owner.nonce
-        tx.value = str(value)
-        tx.sender = owner.address.bech32()
-        tx.receiver = Address.zero().bech32()
-        tx.gasPrice = gas_price
-        tx.gasLimit = gas_limit
-        tx.data = self.prepare_deploy_transaction_data(arguments)
-        tx.chainID = chain
-        tx.version = version
-        tx.guardian = guardian
-        tx.options = options
-
-        tx.sign(owner)
+        tx = Transaction(
+            chain_id=chain,
+            sender=owner.address,
+            receiver=Address.from_bech32(ADDRESS_ZERO_BECH32),
+            gas_limit=gas_limit,
+            gas_price=gas_price,
+            nonce=owner.nonce,
+            value=value,
+            data=self.prepare_deploy_transaction_data(arguments),
+            version=version,
+            options=options
+        )
+
+        if guardian:
+            tx.guardian = Address.from_bech32(guardian)
+
+        tx.signature = bytes.fromhex(owner.sign_transaction(tx))
         return tx
 
-    def prepare_deploy_transaction_data(self, arguments: List[Any]):
+    def prepare_deploy_transaction_data(self, arguments: List[Any]) -> TransactionPayload:
         tx_data = f"{self.bytecode}@{constants.VM_TYPE_WASM_VM}@{self.metadata.to_hex()}"
 
         for arg in arguments:
             tx_data += f"@{_prepare_argument(arg)}"
 
-        return tx_data
-
-    def compute_address(self):
-        """
-        8 bytes of zero + 2 bytes for VM type + 20 bytes of hash(owner) + 2 bytes of shard(owner)
-        """
-        owner_bytes = self.owner.address.pubkey()
-        nonce_bytes = self.owner.nonce.to_bytes(8, byteorder="little")
-        bytes_to_hash = owner_bytes + nonce_bytes
-        address = keccak.new(digest_bits=256).update(bytes_to_hash).digest()
-        address = bytes([0] * 8) + bytes([5, 0]) + address[10:30] + owner_bytes[30:]
-        self.address = Address(address)
+        return TransactionPayload.from_str(tx_data)
 
     def execute(self, caller: Account, function: str, arguments: List[str], gas_price: int, gas_limit: int, value: int, chain: str, version: int, guardian: str, options: int) -> Transaction:
         self.caller = caller
@@ -118,30 +110,34 @@ def execute(self, caller: Account, function: str, arguments: List[str], gas_pric
         gas_price = int(gas_price)
         gas_limit = int(gas_limit)
         value = value or 0
-
-        tx = Transaction()
-        tx.nonce = caller.nonce
-        tx.value = str(value)
-        tx.sender = caller.address.bech32()
-        tx.receiver = self.address.bech32()
-        tx.gasPrice = gas_price
-        tx.gasLimit = gas_limit
-        tx.data = self.prepare_execute_transaction_data(function, arguments)
-        tx.chainID = chain
-        tx.version = version
-        tx.guardian = guardian
-        tx.options = options
-
-        tx.sign(caller)
+        receiver = self.address if self.address else EmptyAddress()
+
+        tx = Transaction(
+            chain_id=chain,
+            sender=caller.address,
+            receiver=receiver,
+            gas_limit=gas_limit,
+            gas_price=gas_price,
+            nonce=caller.nonce,
+            value=value,
+            data=self.prepare_execute_transaction_data(function, arguments),
+            version=version,
+            options=options
+        )
+
+        if guardian:
+            tx.guardian = Address.from_bech32(guardian)
+
+        tx.signature = bytes.fromhex(caller.sign_transaction(tx))
         return tx
 
-    def prepare_execute_transaction_data(self, function: str, arguments: List[Any]):
+    def prepare_execute_transaction_data(self, function: str, arguments: List[Any]) -> TransactionPayload:
         tx_data = function
 
         for arg in arguments:
             tx_data += f"@{_prepare_argument(arg)}"
 
-        return tx_data
+        return TransactionPayload.from_str(tx_data)
 
     def upgrade(self, owner: Account, arguments: List[Any], gas_price: int, gas_limit: int, value: int, chain: str, version: int, guardian: str, options: int) -> Transaction:
         self.owner = owner
@@ -150,30 +146,34 @@ def upgrade(self, owner: Account, arguments: List[Any], gas_price: int, gas_limi
         gas_price = int(gas_price or config.DEFAULT_GAS_PRICE)
         gas_limit = int(gas_limit)
         value = value or 0
-
-        tx = Transaction()
-        tx.nonce = owner.nonce
-        tx.value = str(value)
-        tx.sender = owner.address.bech32()
-        tx.receiver = self.address.bech32()
-        tx.gasPrice = gas_price
-        tx.gasLimit = gas_limit
-        tx.data = self.prepare_upgrade_transaction_data(arguments)
-        tx.chainID = chain
-        tx.version = version
-        tx.guardian = guardian
-        tx.options = options
-
-        tx.sign(owner)
+        receiver = self.address if self.address else EmptyAddress()
+
+        tx = Transaction(
+            chain_id=chain,
+            sender=owner.address,
+            receiver=receiver,
+            gas_limit=gas_limit,
+            gas_price=gas_price,
+            nonce=owner.nonce,
+            value=value,
+            data=self.prepare_upgrade_transaction_data(arguments),
+            version=version,
+            options=options
+        )
+
+        if guardian:
+            tx.guardian = Address.from_bech32(guardian)
+
+        tx.signature = bytes.fromhex(owner.sign_transaction(tx))
         return tx
 
-    def prepare_upgrade_transaction_data(self, arguments: List[Any]):
+    def prepare_upgrade_transaction_data(self, arguments: List[Any]) -> TransactionPayload:
         tx_data = f"upgradeContract@{self.bytecode}@{self.metadata.to_hex()}"
 
         for arg in arguments:
             tx_data += f"@{_prepare_argument(arg)}"
 
-        return tx_data
+        return TransactionPayload.from_str(tx_data)
 
     def query(
         self,
@@ -243,8 +243,8 @@ def _to_hex(arg: str):
 
     if arg.isnumeric():
         return _prepare_decimal(arg)
-    elif arg.startswith(ERD_BECH32_PREFIX):
-        addr = Address(arg)
+    elif arg.startswith(DEFAULT_HRP):
+        addr = Address.from_bech32(arg)
         return _prepare_hexadecimal(f"{HEX_PREFIX}{addr.hex()}")
     elif arg.lower() == FALSE_STR_LOWER or arg.lower() == TRUE_STR_LOWER:
         as_str = f"{HEX_PREFIX}01" if arg.lower() == TRUE_STR_LOWER else f"{HEX_PREFIX}00"
diff --git a/multiversx_sdk_cli/cosign_transaction.py b/multiversx_sdk_cli/cosign_transaction.py
index bb715a12..6c5383dc 100644
--- a/multiversx_sdk_cli/cosign_transaction.py
+++ b/multiversx_sdk_cli/cosign_transaction.py
@@ -1,13 +1,9 @@
-import requests
-from typing import Dict, Any, Protocol
-from multiversx_sdk_cli.errors import GuardianServiceError
-
+from typing import Any, Dict
 
-class ITransaction(Protocol):
-    guardianSignature: str
+import requests
 
-    def to_dictionary(self) -> Dict[str, Any]:
-        ...
+from multiversx_sdk_cli.errors import GuardianServiceError
+from multiversx_sdk_cli.interfaces import ITransaction
 
 
 def cosign_transaction(transaction: ITransaction, service_url: str, guardian_code: str) -> ITransaction:
@@ -21,7 +17,7 @@ def cosign_transaction(transaction: ITransaction, service_url: str, guardian_cod
     check_for_guardian_error(response.json())
 
     tx_as_dict = response.json()["data"]["transaction"]
-    transaction.guardianSignature = tx_as_dict["guardianSignature"]
+    transaction.guardian_signature = bytes.fromhex(tx_as_dict["guardianSignature"])
 
     return transaction
 
diff --git a/multiversx_sdk_cli/delegation/staking_provider.py b/multiversx_sdk_cli/delegation/staking_provider.py
index 6d9a393f..61d43d87 100644
--- a/multiversx_sdk_cli/delegation/staking_provider.py
+++ b/multiversx_sdk_cli/delegation/staking_provider.py
@@ -2,7 +2,7 @@
 from pathlib import Path
 from typing import Any
 
-from multiversx_sdk_core import ArbitraryMessage
+from multiversx_sdk_core import Address, ArbitraryMessage
 from multiversx_sdk_wallet.validator_pem import ValidatorPEM
 from multiversx_sdk_wallet.validator_signer import ValidatorSigner
 
@@ -35,7 +35,7 @@ def prepare_args_for_add_nodes(args: Any):
 
     # TODO: Refactor, so that only address is received here.
     if args.using_delegation_manager:
-        account = Account(address=args.delegation_contract)
+        account = Account(address=Address.from_bech32(args.delegation_contract))
     elif args.pem:
         account = Account(pem_file=args.pem)
     elif args.keyfile:
diff --git a/multiversx_sdk_cli/diskcache.py b/multiversx_sdk_cli/diskcache.py
deleted file mode 100644
index b4ecb5f6..00000000
--- a/multiversx_sdk_cli/diskcache.py
+++ /dev/null
@@ -1,51 +0,0 @@
-from pathlib import Path
-import time
-from typing import Any, Callable, Dict, cast
-
-from multiversx_sdk_cli import utils, workstation
-
-
-class DiskCache:
-    def __init__(self, cache_name: str, max_age: int) -> None:
-        self.cache_name = Path(cache_name)
-        self.max_age = max_age
-
-    def get_path(self) -> Path:
-        return workstation.get_tools_folder() / f"{self.cache_name}.json"
-
-    def get_and_cache_item(self, key: str, item_provider: Callable[[], Any]) -> Any:
-        if not self.has_item(key):
-            item = item_provider()
-            self.save_item(key, item)
-        item = self._get_cached_item(key)
-        return item
-
-    def has_item(self, key: str):
-        payload = self.load_payload()
-        item = payload.get(key, None)
-        timestamp = payload.get(f"timestamp:{key}", 0)
-        age = abs(self._now() - timestamp)
-        expired = age > self.max_age
-        return True if item is not None and not expired else False
-
-    def save_item(self, key: str, item: Any):
-        cache = self.load_payload()
-        cache[key] = item
-        cache[f"timestamp:{key}"] = self._now()
-        self.store_payload(cache)
-
-    def _get_cached_item(self, key: str):
-        return self.load_payload().get(key)
-
-    def load_payload(self) -> Dict[str, Any]:
-        path = self.get_path()
-        if path.exists():
-            payload = utils.read_json_file(path)
-            return cast(Dict[str, Any], payload)
-        return dict()
-
-    def store_payload(self, cache: Any):
-        utils.write_json_file(str(self.get_path()), cache)
-
-    def _now(self):
-        return int(time.time())
diff --git a/multiversx_sdk_cli/dns.py b/multiversx_sdk_cli/dns.py
index a9562e9f..47472d99 100644
--- a/multiversx_sdk_cli/dns.py
+++ b/multiversx_sdk_cli/dns.py
@@ -1,11 +1,14 @@
 from typing import Any, List, Protocol
 
 from Cryptodome.Hash import keccak
+from multiversx_sdk_core.address import Address, compute_contract_address
 
 from multiversx_sdk_cli import cli_shared, utils
-from multiversx_sdk_cli.accounts import Account, Address
+from multiversx_sdk_cli.accounts import Account
+from multiversx_sdk_cli.constants import ADDRESS_ZERO_BECH32, DEFAULT_HRP
 from multiversx_sdk_cli.contracts import SmartContract
-from multiversx_sdk_cli.transactions import do_prepare_transaction
+from multiversx_sdk_cli.transactions import (do_prepare_transaction,
+                                             tx_to_dictionary_as_inner)
 
 MaxNumShards = 256
 ShardIdentiferLen = 2
@@ -23,8 +26,8 @@ def resolve(name: str, proxy: INetworkProvider) -> Address:
     contract = SmartContract(dns_address)
     result = contract.query(proxy, "resolve", [name_arg])
     if len(result) == 0:
-        return Address.zero()
-    return Address(result[0].hex)
+        return Address.from_bech32(ADDRESS_ZERO_BECH32)
+    return Address.from_hex(result[0].hex, DEFAULT_HRP)
 
 
 def validate_name(name: str, shard_id: int, proxy: INetworkProvider):
@@ -47,7 +50,7 @@ def register(args: Any):
     tx = do_prepare_transaction(args)
 
     if hasattr(args, "relay") and args.relay:
-        args.outfile.write(tx.serialize_as_inner())
+        args.outfile.write(tx_to_dictionary_as_inner(tx))
         return
 
     cli_shared.send_or_simulate(tx, args)
@@ -87,17 +90,17 @@ def dns_address_for_name(name: str) -> Address:
     return compute_dns_address_for_shard_id(shard_id)
 
 
-def compute_dns_address_for_shard_id(shard_id) -> Address:
+def compute_dns_address_for_shard_id(shard_id: int) -> Address:
     deployer_pubkey_prefix = InitialDNSAddress[:len(InitialDNSAddress) - ShardIdentiferLen]
 
     deployer_pubkey = deployer_pubkey_prefix + bytes([0, shard_id])
-    deployer = Account(address=Address(deployer_pubkey))
+    deployer = Account(address=Address(deployer_pubkey, DEFAULT_HRP))
     deployer.nonce = 0
     # Workaround: In order to compute the address of a contract, one has to create an instance of the class "SmartContract".
     # This might change in the future.
     contract = SmartContract()
     contract.owner = deployer
-    contract.compute_address()
+    contract.address = compute_contract_address(contract.owner.address, contract.owner.nonce, DEFAULT_HRP)
     return contract.address
 
 
diff --git a/multiversx_sdk_cli/downloader.py b/multiversx_sdk_cli/downloader.py
index 5b19d4d3..93dab7c1 100644
--- a/multiversx_sdk_cli/downloader.py
+++ b/multiversx_sdk_cli/downloader.py
@@ -15,8 +15,8 @@
 
 
 def download(url: str, filename: str) -> None:
-    if url is None:
-        raise errors.BadUrlError()
+    if not url:
+        raise errors.BadUrlError("")
 
     logger.info(f"download_url.url: {url}")
     logger.info(f"download_url.filename: {filename}")
@@ -45,7 +45,7 @@ def download(url: str, filename: str) -> None:
     logger.info("Download done.")
 
 
-def _report_download_progress(progress, chunk_number, total_size):
+def _report_download_progress(progress: int, chunk_number: int, total_size: int):
     try:
         num_chunks = int(total_size / CHUNK_SIZE)
         new_progress = int((chunk_number / num_chunks) * 20)
diff --git a/multiversx_sdk_cli/guards.py b/multiversx_sdk_cli/guards.py
index c7a2d01b..c40f02bb 100644
--- a/multiversx_sdk_cli/guards.py
+++ b/multiversx_sdk_cli/guards.py
@@ -1,4 +1,5 @@
 from pathlib import Path
+
 from multiversx_sdk_cli import errors
 
 
@@ -10,17 +11,3 @@ def is_file(input: Path):
 def is_directory(directory: Path):
     if not directory.is_dir():
         raise errors.BadDirectory(str(directory))
-
-
-def is_hex_address(input):
-    is_hex_string(input)
-
-    if len(input) != 64:
-        raise errors.BadInputError(input, "is not a valid hex-encoded address")
-
-
-def is_hex_string(input):
-    try:
-        bytearray.fromhex(input)
-    except Exception:
-        raise errors.BadInputError(input, "is not a valid hex-encoded string")
diff --git a/multiversx_sdk_cli/interfaces.py b/multiversx_sdk_cli/interfaces.py
index 64f7ec72..947433b2 100644
--- a/multiversx_sdk_cli/interfaces.py
+++ b/multiversx_sdk_cli/interfaces.py
@@ -1,46 +1,40 @@
 from typing import Any, Dict, Protocol
 
-from multiversx_sdk_cli.utils import ISerializable
 
-
-class IAddress:
+class IAddress(Protocol):
     def hex(self) -> str:
-        return ""
+        ...
 
     def bech32(self) -> str:
-        return ""
-
-    def pubkey(self) -> bytes:
-        return bytes()
+        ...
 
 
-class ITransaction(ISerializable):
-    def serialize(self) -> bytes:
-        return bytes()
+ITransactionOptions = int
+ITransactionVersion = int
+ISignature = bytes
 
-    def serialize_for_signing(self) -> bytes:
-        return bytes()
 
-    def serialize_as_inner(self) -> str:
-        return ''
+class ITransactionPayload(Protocol):
+    data: bytes
+    def encoded(self) -> str: ...
+    def length(self) -> int: ...
 
-    def to_dictionary(self) -> Dict[str, Any]:
-        return {}
 
-    def to_dictionary_as_inner(self) -> Dict[str, Any]:
-        return {}
+class ITransaction(Protocol):
+    version: ITransactionVersion
+    options: ITransactionOptions
+    signature: ISignature
+    guardian_signature: ISignature
 
-    def set_version(self, version: int):
-        return
-
-    def set_options(self, options: int):
-        return
+    @property
+    def data(self) -> ITransactionPayload:
+        ...
 
-    def get_hash(self) -> str:
-        return ""
+    def serialize_for_signing(self) -> bytes:
+        ...
 
-    def get_data(self) -> str:
-        return ""
+    def to_dictionary(self, with_signature: bool = True) -> Dict[str, Any]:
+        ...
 
 
 class IAccount(Protocol):
diff --git a/multiversx_sdk_cli/localnet/genesis.py b/multiversx_sdk_cli/localnet/genesis.py
index 453adcaa..aea5d9c4 100644
--- a/multiversx_sdk_cli/localnet/genesis.py
+++ b/multiversx_sdk_cli/localnet/genesis.py
@@ -1,4 +1,6 @@
-from multiversx_sdk_cli.accounts import Address
+from multiversx_sdk_core.address import Address, compute_contract_address
+
+from multiversx_sdk_cli.constants import DEFAULT_HRP
 from multiversx_sdk_cli.contracts import SmartContract
 from multiversx_sdk_cli.localnet import wallets
 
@@ -12,7 +14,7 @@ def get_delegation_address() -> Address:
     contract = SmartContract()
     contract.owner = get_owner_of_genesis_contracts()
     contract.owner.nonce = 0
-    contract.compute_address()
+    contract.address = compute_contract_address(contract.owner.address, contract.owner.nonce, DEFAULT_HRP)
     return contract.address
 
 
diff --git a/multiversx_sdk_cli/localnet/genesis_json.py b/multiversx_sdk_cli/localnet/genesis_json.py
index f7348ffb..cf7042c2 100644
--- a/multiversx_sdk_cli/localnet/genesis_json.py
+++ b/multiversx_sdk_cli/localnet/genesis_json.py
@@ -1,6 +1,8 @@
 from typing import Any, Dict, List
 
-from multiversx_sdk_cli.accounts import Account, Address
+from multiversx_sdk_core import Address
+
+from multiversx_sdk_cli.accounts import Account
 from multiversx_sdk_cli.localnet import wallets
 from multiversx_sdk_cli.localnet.config_root import ConfigRoot
 from multiversx_sdk_cli.localnet.genesis import (get_delegation_address,
diff --git a/multiversx_sdk_cli/projects/core.py b/multiversx_sdk_cli/projects/core.py
index 577ef329..a9cffb88 100644
--- a/multiversx_sdk_cli/projects/core.py
+++ b/multiversx_sdk_cli/projects/core.py
@@ -1,6 +1,6 @@
 import logging
 from pathlib import Path
-from typing import Any, Dict, List
+from typing import Any, List
 
 from multiversx_sdk_cli import dependencies, errors, guards, utils
 from multiversx_sdk_cli.projects import shared
@@ -30,15 +30,14 @@ def load_project(directory: Path) -> Project:
         raise errors.NotSupportedProject(str(directory))
 
 
-def build_project(directory: Path, options: Dict[str, Any]):
+def build_project(directory: Path, args: List[str]):
     directory = directory.expanduser()
 
     logger.info("build_project.directory: %s", directory)
-    logger.info("build_project.debug: %s", options['debug'])
 
     guards.is_directory(directory)
     project = load_project(directory)
-    outputs = project.build(options)
+    outputs = project.build(args)
     logger.info("Build ran.")
     for output_wasm_file in outputs:
         logger.info(f"WASM file generated: {output_wasm_file}")
diff --git a/multiversx_sdk_cli/projects/project_base.py b/multiversx_sdk_cli/projects/project_base.py
index 01724225..aadd5ebc 100644
--- a/multiversx_sdk_cli/projects/project_base.py
+++ b/multiversx_sdk_cli/projects/project_base.py
@@ -21,9 +21,9 @@ def __init__(self, directory: Path):
         self.path = directory.expanduser().resolve()
         self.directory = str(self.path)
 
-    def build(self, options: Union[Dict[str, Any], None] = None) -> List[Path]:
+    def build(self, args: List[str], options: Union[Dict[str, Any], None] = None) -> List[Path]:
         migrate_project_config_file(self.path)
-
+        self.forwarded_args = args
         self.options = options or dict()
         self.debug = self.options.get("debug", False)
         self._ensure_dependencies_installed()
@@ -32,9 +32,6 @@ def build(self, options: Union[Dict[str, Any], None] = None) -> List[Path]:
         self._do_after_build_core()
         return contract_paths
 
-    def get_option(self, option_name: str) -> Any:
-        return self.options.get(option_name, None)
-
     def clean(self):
         utils.remove_folder(self.get_output_folder())
 
diff --git a/multiversx_sdk_cli/projects/project_rust.py b/multiversx_sdk_cli/projects/project_rust.py
index a3ea8543..498dae16 100644
--- a/multiversx_sdk_cli/projects/project_rust.py
+++ b/multiversx_sdk_cli/projects/project_rust.py
@@ -1,6 +1,5 @@
 import logging
 import subprocess
-from os import path
 from pathlib import Path
 from typing import Any, Dict, List, Set, cast
 
@@ -17,9 +16,17 @@ def __init__(self, directory: Path):
         self.cargo_file = self.get_cargo_file()
 
     def clean(self):
-        super().clean()
-        utils.remove_folder(path.join(self.directory, "wasm", "target"))
-        utils.remove_folder(path.join(self.directory, "meta", "target"))
+        env = self.get_env()
+
+        args = [
+            "sc-meta",
+            "all",
+            "clean",
+            "--path",
+            self.directory
+        ]
+
+        subprocess.check_call(args, env=env)
 
     def get_cargo_file(self):
         cargo_path = self.path / 'Cargo.toml'
@@ -36,13 +43,7 @@ def perform_build(self):
         if not meta:
             raise errors.NotSupportedProject("The project does not have a meta crate")
 
-        try:
-            # The meta crate handles the build process, ABI generation and
-            # allows contract developers to add extra
-            # preparation steps before building.
-            self.run_meta()
-        except subprocess.CalledProcessError as err:
-            raise errors.BuildError(err.output)
+        self.run_meta()
 
     def prepare_build_wasm_args(self, args: List[str]):
         args.extend([
@@ -53,7 +54,6 @@ def prepare_build_wasm_args(self, args: List[str]):
         ])
 
     def run_meta(self):
-        cwd = self.get_meta_folder()
         env = self.get_env()
 
         with_wasm_opt = not self.options.get("no-wasm-opt")
@@ -62,38 +62,18 @@ def run_meta(self):
             wasm_opt = dependencies.get_module_by_key("wasm-opt")
             env = merge_env(env, wasm_opt.get_env())
 
-        # run the meta executable with the arguments `build --target=...`
         args = [
-            "cargo",
-            "run",
-            "build",
+            "sc-meta",
+            "all",
+            "build"
         ]
 
-        self.prepare_build_wasm_args(args)
-        self.decorate_cargo_args(args)
-
-        return_code = subprocess.check_call(args, env=env, cwd=cwd)
-        if return_code != 0:
-            raise errors.BuildError(f"error code = {return_code}, see output")
+        args.extend(self.forwarded_args)
 
-    def decorate_cargo_args(self, args: List[str]):
-        target_dir: str = self.options.get("cargo-target-dir", "")
-        target_dir = self._ensure_cargo_target_dir(target_dir)
-        no_wasm_opt = self.options.get("no-wasm-opt")
-        wasm_symbols = self.options.get("wasm-symbols")
-        wasm_name = self.options.get("wasm-name")
-        wasm_suffix = self.options.get("wasm-suffix")
-
-        args.extend(["--target-dir", target_dir])
-
-        if no_wasm_opt:
-            args.extend(["--no-wasm-opt"])
-        if wasm_symbols:
-            args.extend(["--wasm-symbols"])
-        if wasm_name:
-            args.extend(["--wasm-name", wasm_name])
-        if wasm_suffix:
-            args.extend(["--wasm-suffix", wasm_suffix])
+        try:
+            subprocess.check_call(args, env=env)
+        except subprocess.CalledProcessError as err:
+            raise errors.BuildError(f"error code = {err.returncode}, see output")
 
     def _ensure_cargo_target_dir(self, target_dir: str):
         default_target_dir = str(workstation.get_tools_folder() / DEFAULT_CARGO_TARGET_DIR_NAME)
@@ -143,14 +123,14 @@ def get_env(self):
         return dependencies.get_module_by_key("rust").get_env()
 
     def build_wasm_with_debug_symbols(self, build_options: Dict[str, Any]):
-        cwd = self.get_meta_folder()
+        cwd = self.path
         env = self.get_env()
-        target_dir: str = build_options.get("cargo-target-dir", "")
+        target_dir: str = build_options.get("target-dir", "")
         target_dir = self._ensure_cargo_target_dir(target_dir)
 
         args = [
-            "cargo",
-            "run",
+            "sc-meta",
+            "all",
             "build",
             "--wasm-symbols",
             "--wasm-suffix", "dbg",
@@ -158,9 +138,10 @@ def build_wasm_with_debug_symbols(self, build_options: Dict[str, Any]):
             "--target-dir", target_dir
         ]
 
-        return_code = subprocess.check_call(args, env=env, cwd=cwd)
-        if return_code != 0:
-            raise errors.BuildError(f"error code = {return_code}, see output")
+        try:
+            subprocess.check_call(args, env=env, cwd=cwd)
+        except subprocess.CalledProcessError as err:
+            raise errors.BuildError(f"error code = {err.returncode}, see output")
 
 
 class CargoFile:
diff --git a/multiversx_sdk_cli/projects/report/do_report.py b/multiversx_sdk_cli/projects/report/do_report.py
index d3c8d1e7..8d5b2fc0 100644
--- a/multiversx_sdk_cli/projects/report/do_report.py
+++ b/multiversx_sdk_cli/projects/report/do_report.py
@@ -1,15 +1,18 @@
+import copy
 import logging
 from pathlib import Path
 from typing import Any, Dict, List
-from multiversx_sdk_cli import utils
 
+from multiversx_sdk_cli import cli_shared, utils
 from multiversx_sdk_cli.projects.core import get_project_paths_recursively
-from multiversx_sdk_cli.projects.report.data.report import Report, merge_list_of_reports
-from multiversx_sdk_cli.projects.report.format.format_options import FormatOptions
-from multiversx_sdk_cli.projects.report.features.features import get_default_report_features
+from multiversx_sdk_cli.projects.report.data.report import (
+    Report, merge_list_of_reports)
+from multiversx_sdk_cli.projects.report.features.features import \
+    get_default_report_features
+from multiversx_sdk_cli.projects.report.format.format_options import \
+    FormatOptions
 from multiversx_sdk_cli.projects.report.report_creator import ReportCreator
 
-
 logger = logging.getLogger("report")
 
 
@@ -22,14 +25,28 @@ def do_report(args: Any, build_options: Any) -> None:
 
 
 def _build_report(args: Any, build_options: Dict[str, Any]) -> None:
-    base_path = Path(args.project)
+    base_path = Path(args.path)
     project_paths = get_project_paths_recursively(base_path)
     options = get_default_report_features()
-    report_creator = ReportCreator(options, skip_build=args.skip_build, skip_twiggy=args.skip_twiggy, build_options=build_options)
+
+    args_copy = _prepare_args_for_build(args)
+    build_args = cli_shared.convert_args_object_to_args_list(args_copy)
+
+    report_creator = ReportCreator(options, skip_build=args.skip_build, skip_twiggy=args.skip_twiggy, build_options=build_options, build_args=build_args)
     report = report_creator.create_report(base_path, project_paths)
     _finalize_report(report, args)
 
 
+def _prepare_args_for_build(args: Any):
+    args_copy = copy.deepcopy(args)
+
+    arguments: Dict[str, Any] = args_copy.__dict__
+    arguments.pop("output_format", None)
+    arguments.pop("output_file", None)
+
+    return args_copy
+
+
 def _compare_reports(args: Any, merge_report_paths: List[Path]) -> None:
     reports = [Report.load_from_file(report_path) for report_path in merge_report_paths]
     final_report = merge_list_of_reports(reports)
diff --git a/multiversx_sdk_cli/projects/report/features/twiggy_paths_check.py b/multiversx_sdk_cli/projects/report/features/twiggy_paths_check.py
index 639ed7fc..4603e597 100644
--- a/multiversx_sdk_cli/projects/report/features/twiggy_paths_check.py
+++ b/multiversx_sdk_cli/projects/report/features/twiggy_paths_check.py
@@ -1,9 +1,10 @@
 import logging
 from pathlib import Path
 
-from multiversx_sdk_cli import dependencies, myprocess, utils
+from multiversx_sdk_cli import config, dependencies, myprocess, utils
 from multiversx_sdk_cli.errors import BadFile
-from multiversx_sdk_cli.projects.report.features.report_option import ReportFeature
+from multiversx_sdk_cli.projects.report.features.report_option import \
+    ReportFeature
 
 logger = logging.getLogger("projects.report.options.twiggy_paths_check")
 
@@ -29,8 +30,11 @@ def requires_twiggy_paths(self):
 def run_twiggy_paths(wasm_path: Path) -> Path:
     rust = dependencies.get_module_by_key("rust")
     debug_wasm_path = _get_debug_wasm_path(wasm_path)
+
+    dependencies.install_module("twiggy")
     twiggy_paths_args = ["twiggy", "paths", str(debug_wasm_path)]
     output = myprocess.run_process(twiggy_paths_args, env=rust.get_env(), cwd=debug_wasm_path.parent, dump_to_stdout=False)
+
     output_path = _get_twiggy_paths_path(wasm_path)
     utils.write_file(output_path, output)
     logger.info(f"Twiggy paths output path: {output_path}")
diff --git a/multiversx_sdk_cli/projects/report/report_creator.py b/multiversx_sdk_cli/projects/report/report_creator.py
index 1d185e7f..11c30c87 100644
--- a/multiversx_sdk_cli/projects/report/report_creator.py
+++ b/multiversx_sdk_cli/projects/report/report_creator.py
@@ -3,27 +3,32 @@
 import operator
 from pathlib import Path
 from typing import Any, Dict, Iterable, List, Tuple
+
 from multiversx_sdk_cli import guards
-from multiversx_sdk_cli.projects.report.data.folder_report import FolderReport
-from multiversx_sdk_cli.projects.report.data.extracted_feature import ExtractedFeature
-from multiversx_sdk_cli.projects.report.data.report import Report
-from multiversx_sdk_cli.projects.report.data.wasm_report import WasmReport
-from multiversx_sdk_cli.projects.report.data.project_report import ProjectReport
 from multiversx_sdk_cli.projects.core import load_project
 from multiversx_sdk_cli.projects.project_base import remove_suffix
 from multiversx_sdk_cli.projects.project_rust import ProjectRust
-
-from multiversx_sdk_cli.projects.report.features.report_option import ReportFeature
-from multiversx_sdk_cli.projects.report.features.twiggy_paths_check import run_twiggy_paths
+from multiversx_sdk_cli.projects.report.data.extracted_feature import \
+    ExtractedFeature
+from multiversx_sdk_cli.projects.report.data.folder_report import FolderReport
+from multiversx_sdk_cli.projects.report.data.project_report import \
+    ProjectReport
+from multiversx_sdk_cli.projects.report.data.report import Report
+from multiversx_sdk_cli.projects.report.data.wasm_report import WasmReport
+from multiversx_sdk_cli.projects.report.features.report_option import \
+    ReportFeature
+from multiversx_sdk_cli.projects.report.features.twiggy_paths_check import \
+    run_twiggy_paths
 
 
 class ReportCreator:
-    def __init__(self, options: List[ReportFeature], skip_build: bool, skip_twiggy: bool, build_options: Dict[str, Any]) -> None:
+    def __init__(self, options: List[ReportFeature], skip_build: bool, skip_twiggy: bool, build_options: Dict[str, Any], build_args: List[str]) -> None:
         self.report_features = options
         self.skip_build = skip_build
         self.skip_twiggy = skip_twiggy
         self.require_twiggy_paths = any(report_feature.requires_twiggy_paths() for report_feature in self.report_features)
         self.build_options = build_options
+        self.build_args = build_args
 
     def create_report(self, base_path: Path, project_paths: List[Path]) -> Report:
         base_path = base_path.resolve()
@@ -47,7 +52,7 @@ def _create_project_report(self, parent_path: Path, project_path: Path) -> Proje
         project = load_project(project_path)
 
         if not self.skip_build:
-            project.build(self.build_options)
+            project.build(self.build_args, self.build_options)
 
         twiggy_requirements_met = False
         should_build_twiggy = self.require_twiggy_paths and not self.skip_twiggy
diff --git a/multiversx_sdk_cli/transactions.py b/multiversx_sdk_cli/transactions.py
index 16675e51..5b8d2a9f 100644
--- a/multiversx_sdk_cli/transactions.py
+++ b/multiversx_sdk_cli/transactions.py
@@ -2,11 +2,12 @@
 import json
 import logging
 import time
-from collections import OrderedDict
-from typing import Any, Dict, List, Optional, Protocol, Sequence, TextIO, Tuple
+from typing import Any, Dict, Optional, Protocol, Sequence, TextIO, Tuple
 
-from multiversx_sdk_cli import config, errors, utils
-from multiversx_sdk_cli.accounts import Account, Address, LedgerAccount
+from multiversx_sdk_core import Address, Transaction, TransactionPayload
+
+from multiversx_sdk_cli import errors
+from multiversx_sdk_cli.accounts import Account, LedgerAccount
 from multiversx_sdk_cli.cli_password import (load_guardian_password,
                                              load_password)
 from multiversx_sdk_cli.cosign_transaction import cosign_transaction
@@ -32,13 +33,13 @@ def send_transaction(self, transaction: ITransaction) -> str:
     def send_transactions(self, transactions: Sequence[ITransaction]) -> Tuple[int, str]:
         ...
 
-    def get_transaction(self, tx_hash: str, with_process_status: Optional[bool]) -> ITransactionOnNetwork:
+    def get_transaction(self, tx_hash: str, with_process_status: Optional[bool] = False) -> ITransactionOnNetwork:
         ...
 
 
-class Transaction(ITransaction):
-    def __init__(self):
-        self.hash: str = ""
+class JSONTransaction:
+    def __init__(self) -> None:
+        self.hash = ""
         self.nonce = 0
         self.value = "0"
         self.receiver = ""
@@ -55,206 +56,6 @@ def __init__(self):
         self.guardian = ""
         self.guardianSignature = ""
 
-    # The data field is base64-encoded. Here, we only support utf-8 "data" at this moment.
-    def data_encoded(self) -> str:
-        return self._field_encoded("data")
-
-    # Useful when loading a tx from a file (when data is already encoded in base64)
-    def data_decoded(self) -> str:
-        return self._field_decoded("data")
-
-    def sender_username_encoded(self) -> str:
-        return self._field_encoded("senderUsername")
-
-    def sender_username_decoded(self) -> str:
-        return self._field_decoded("senderUsername")
-
-    def receiver_username_encoded(self) -> str:
-        return self._field_encoded("receiverUsername")
-
-    def receiver_username_decoded(self) -> str:
-        return self._field_decoded("receiverUsername")
-
-    def _field_encoded(self, field: str) -> str:
-        field_bytes = self.__dict__.get(field, "").encode("utf-8")
-        encoded = base64.b64encode(field_bytes).decode()
-        return encoded
-
-    def _field_decoded(self, field: str) -> str:
-        return base64.b64decode(self.__dict__.get(field, None)).decode()
-
-    def sign(self, account: Account):
-        self.validate()
-        self.signature = account.sign_transaction(self)
-
-    def validate(self) -> None:
-        if self.gasLimit > config.MAX_GAS_LIMIT:
-            raise errors.GasLimitTooLarge(self.gasLimit, config.MAX_GAS_LIMIT)
-
-    def serialize(self) -> bytes:
-        dictionary = self.to_dictionary()
-        serialized = self._dict_to_json(dictionary)
-        return serialized
-
-    def serialize_for_signing(self) -> bytes:
-        return self.serialize()
-
-    def _dict_to_json(self, dictionary: Dict[str, Any]) -> bytes:
-        serialized = json.dumps(dictionary, separators=(',', ':')).encode("utf8")
-        return serialized
-
-    def serialize_as_inner(self) -> str:
-        inner_dictionary = self.to_dictionary_as_inner()
-        serialized = self._dict_to_json(inner_dictionary)
-        serialized_hex = serialized.hex()
-        return f"relayedTx@{serialized_hex}"
-
-    @classmethod
-    def load_from_file(cls, f: TextIO):
-        data_json: bytes = f.read().encode()
-        fields = json.loads(data_json).get("tx") or json.loads(data_json).get("emittedTransaction")
-        instance = cls()
-        instance.__dict__.update(fields)
-        instance.data = instance.data_decoded()
-        instance.senderUsername = instance.sender_username_decoded()
-        instance.receiverUsername = instance.receiver_username_encoded()
-        return instance
-
-    def send(self, proxy: INetworkProvider):
-        if not self.signature:
-            raise errors.TransactionIsNotSigned()
-
-        logger.info(f"Transaction.send: nonce={self.nonce}")
-
-        self.hash = proxy.send_transaction(self)
-        logger.info(f"Hash: {self.hash}")
-        utils.log_explorer_transaction(self.chainID, self.hash)
-        return self.hash
-
-    def send_wait_result(self, proxy: INetworkProvider, timeout: int) -> ITransactionOnNetwork:
-        if not self.signature:
-            raise errors.TransactionIsNotSigned()
-
-        txOnNetwork = self.__send_transaction_and_wait_for_result(proxy, self, timeout)
-        self.hash = txOnNetwork.hash
-        return txOnNetwork
-
-    def __send_transaction_and_wait_for_result(self, proxy: INetworkProvider, payload: Any, num_seconds_timeout: int = 100) -> ITransactionOnNetwork:
-        AWAIT_TRANSACTION_PERIOD = 5
-
-        tx_hash = proxy.send_transaction(payload)
-        num_periods_to_wait = int(num_seconds_timeout / AWAIT_TRANSACTION_PERIOD)
-
-        for _ in range(0, num_periods_to_wait):
-            time.sleep(AWAIT_TRANSACTION_PERIOD)
-
-            tx = proxy.get_transaction(tx_hash, with_process_status=True)
-            if tx.is_completed:
-                return tx
-            else:
-                logger.info("Transaction not yet done.")
-
-        raise errors.KnownError("Took too long to get transaction.")
-
-    def to_dictionary(self) -> Dict[str, Any]:
-        dictionary: Dict[str, Any] = OrderedDict()
-        dictionary["nonce"] = self.nonce
-        dictionary["value"] = self.value
-
-        dictionary["receiver"] = self.receiver
-        dictionary["sender"] = self.sender
-
-        if self.senderUsername:
-            dictionary["senderUsername"] = self.sender_username_encoded()
-        if self.receiverUsername:
-            dictionary["receiverUsername"] = self.receiver_username_encoded()
-
-        dictionary["gasPrice"] = self.gasPrice
-        dictionary["gasLimit"] = self.gasLimit
-
-        if self.data:
-            dictionary["data"] = self.data_encoded()
-
-        dictionary["chainID"] = self.chainID
-
-        if self.version:
-            dictionary["version"] = int(self.version)
-
-        if self.options:
-            dictionary["options"] = int(self.options)
-
-        if self.guardian:
-            dictionary["guardian"] = self.guardian
-
-        if self.signature:
-            dictionary["signature"] = self.signature
-
-        if self.guardianSignature:
-            dictionary["guardianSignature"] = self.guardianSignature
-
-        return dictionary
-
-    # Creates the payload for a "user" / "inner" transaction
-    def to_dictionary_as_inner(self) -> Dict[str, Any]:
-        dictionary = self.to_dictionary()
-        dictionary["receiver"] = base64.b64encode(Address(self.receiver).pubkey()).decode()
-        dictionary["sender"] = base64.b64encode(Address(self.sender).pubkey()).decode()
-        dictionary["chainID"] = base64.b64encode(self.chainID.encode()).decode()
-        dictionary["signature"] = base64.b64encode(bytes(bytearray.fromhex(self.signature))).decode()
-        dictionary["value"] = int(self.value)
-
-        return dictionary
-
-    def wrap_inner(self, inner: ITransaction) -> None:
-        self.data = inner.serialize_as_inner()
-
-    def set_version(self, version: int):
-        self.version = version
-
-    def set_options(self, options: int):
-        self.options = options
-
-    def get_data(self) -> str:
-        return self.data
-
-    def get_hash(self) -> str:
-        return self.hash
-
-
-class BunchOfTransactions:
-    def __init__(self):
-        self.transactions: List[Transaction] = []
-
-    def add_prepared(self, transaction: Transaction):
-        self.transactions.append(transaction)
-
-    def add(self, sender: Account, receiver_address: str, nonce: Any, value: Any, data: str, gas_price: int,
-            gas_limit: int, chain: str, version: int, options: int):
-        tx = Transaction()
-        tx.nonce = int(nonce)
-        tx.value = str(value)
-        tx.receiver = receiver_address
-        tx.sender = sender.address.bech32()
-        tx.gasPrice = gas_price
-        tx.gasLimit = gas_limit
-        tx.data = data
-        tx.chainID = chain
-        tx.version = version
-        tx.options = options
-
-        tx.sign(sender)
-        self.transactions.append(tx)
-
-    def add_tx(self, tx: Transaction):
-        self.transactions.append(tx)
-
-    def send(self, proxy: INetworkProvider):
-        logger.info(f"BunchOfTransactions.send: {len(self.transactions)} transactions")
-        num_sent, hashes = proxy.send_transactions(self.transactions)
-        logger.info(f"Sent: {num_sent}")
-        logger.info(f"TxsHashes: {hashes}")
-        return num_sent, hashes
-
 
 def do_prepare_transaction(args: Any) -> Transaction:
     account = Account()
@@ -266,22 +67,25 @@ def do_prepare_transaction(args: Any) -> Transaction:
         password = load_password(args)
         account = Account(key_file=args.keyfile, password=password)
 
-    tx = Transaction()
-    tx.nonce = int(args.nonce)
-    tx.value = args.value
-    tx.receiver = args.receiver
-    tx.sender = account.address.bech32()
-    tx.senderUsername = getattr(args, "sender_username", "")
-    tx.receiverUsername = getattr(args, "receiver_username", "")
-    tx.gasPrice = int(args.gas_price)
-    tx.gasLimit = int(args.gas_limit)
-    tx.data = args.data
-    tx.chainID = args.chain
-    tx.version = int(args.version)
-    tx.options = int(args.options)
-    tx.guardian = args.guardian
-
-    tx.sign(account)
+    tx = Transaction(
+        chain_id=args.chain,
+        sender=account.address,
+        receiver=Address.from_bech32(args.receiver),
+        gas_limit=int(args.gas_limit),
+        sender_username=getattr(args, "sender_username", ""),
+        receiver_username=getattr(args, "receiver_username", ""),
+        gas_price=int(args.gas_price),
+        data=TransactionPayload.from_str(args.data),
+        nonce=int(args.nonce),
+        value=int(args.value),
+        version=int(args.version),
+        options=int(args.options)
+    )
+
+    if args.guardian:
+        tx.guardian = Address.from_bech32(args.guardian)
+
+    tx.signature = bytes.fromhex(account.sign_transaction(tx))
     tx = sign_tx_by_guardian(args, tx)
 
     return tx
@@ -293,17 +97,11 @@ def sign_tx_by_guardian(args: Any, tx: Transaction) -> Transaction:
     except NoWalletProvided:
         guardian_account = None
 
-    # empty sender signature
-    sender_signature = tx.signature
-    tx.signature = ""
-
     if guardian_account:
-        tx.guardianSignature = guardian_account.sign_transaction(tx)
+        tx.guardian_signature = bytes.fromhex(guardian_account.sign_transaction(tx))
     elif args.guardian:
         tx = cosign_transaction(tx, args.guardian_service_url, args.guardian_2fa_code)  # type: ignore
 
-    tx.signature = sender_signature
-
     return tx
 
 
@@ -316,8 +114,95 @@ def get_guardian_account_from_args(args: Any):
         account = Account(key_file=args.guardian_keyfile, password=password)
     elif args.guardian_ledger:
         address = do_get_ledger_address(account_index=args.guardian_ledger_account_index, address_index=args.guardian_ledger_address_index)
-        account = Account(address=address)
+        account = Account(address=Address.from_bech32(address))
     else:
         raise errors.NoWalletProvided()
 
     return account
+
+
+def send_and_wait_for_result(transaction: ITransaction, proxy: INetworkProvider, timeout: int) -> ITransactionOnNetwork:
+    if not transaction.signature:
+        raise errors.TransactionIsNotSigned()
+
+    txOnNetwork = _send_transaction_and_wait_for_result(proxy, transaction, timeout)
+    return txOnNetwork
+
+
+def _send_transaction_and_wait_for_result(proxy: INetworkProvider, payload: ITransaction, num_seconds_timeout: int = 100) -> ITransactionOnNetwork:
+    AWAIT_TRANSACTION_PERIOD = 5
+
+    tx_hash = proxy.send_transaction(payload)
+    num_periods_to_wait = int(num_seconds_timeout / AWAIT_TRANSACTION_PERIOD)
+
+    for _ in range(0, num_periods_to_wait):
+        time.sleep(AWAIT_TRANSACTION_PERIOD)
+
+        tx = proxy.get_transaction(tx_hash, True)
+        if tx.is_completed:
+            return tx
+        else:
+            logger.info("Transaction not yet done.")
+
+    raise errors.KnownError("Took too long to get transaction.")
+
+
+def tx_to_dictionary_as_inner(tx: Transaction) -> Dict[str, Any]:
+    dictionary = tx.to_dictionary()
+    dictionary["receiver"] = base64.b64encode(bytes.fromhex(tx.receiver.hex())).decode()  # type: ignore
+    dictionary["sender"] = base64.b64encode(bytes.fromhex(tx.sender.hex())).decode()  # type: ignore
+    dictionary["chainID"] = base64.b64encode(tx.chainID.encode()).decode()
+    dictionary["signature"] = base64.b64encode(bytes(bytearray(tx.signature))).decode()
+    dictionary["value"] = tx.value
+
+    return dictionary
+
+
+def _dict_to_json(dictionary: Dict[str, Any]) -> bytes:
+    serialized = json.dumps(dictionary, separators=(',', ':')).encode("utf8")
+    return serialized
+
+
+def compute_relayed_v1_data(tx: Transaction) -> str:
+    inner_dictionary = tx_to_dictionary_as_inner(tx)
+    serialized = _dict_to_json(inner_dictionary)
+    serialized_hex = serialized.hex()
+    return f"relayedTx@{serialized_hex}"
+
+
+def load_transaction_from_file(f: TextIO) -> Transaction:
+    data_json: bytes = f.read().encode()
+    fields = json.loads(data_json).get("tx") or json.loads(data_json).get("emittedTransaction")
+
+    instance = JSONTransaction()
+    instance.__dict__.update(fields)
+
+    loaded_tx = Transaction(
+        chain_id=instance.chainID,
+        sender=Address.from_bech32(instance.sender),
+        receiver=Address.from_bech32(instance.receiver),
+        sender_username=decode_field_value(instance.senderUsername),
+        receiver_username=decode_field_value(instance.receiverUsername),
+        gas_limit=instance.gasLimit,
+        gas_price=instance.gasPrice,
+        value=int(instance.value),
+        data=TransactionPayload.from_encoded_str(instance.data),
+        version=instance.version,
+        options=instance.options,
+        nonce=instance.nonce
+    )
+
+    if instance.guardian:
+        loaded_tx.guardian = Address.from_bech32(instance.guardian)
+
+    if instance.signature:
+        loaded_tx.signature = bytes.fromhex(instance.signature)
+
+    if instance.guardianSignature:
+        loaded_tx.guardian_signature = bytes.fromhex(instance.guardianSignature)
+
+    return loaded_tx
+
+
+def decode_field_value(value: str) -> str:
+    return base64.b64decode(value).decode()
diff --git a/multiversx_sdk_cli/utils.py b/multiversx_sdk_cli/utils.py
index 751aa25b..89ce3e5c 100644
--- a/multiversx_sdk_cli/utils.py
+++ b/multiversx_sdk_cli/utils.py
@@ -239,16 +239,7 @@ def query_latest_release_tag(repo: str) -> str:
     return latest_release_tag
 
 
-# https://code.visualstudio.com/docs/python/debugging
-def breakpoint():
-    import debugpy
-    debugpy.listen(5678)
-    print("Waiting for debugger attach")
-    debugpy.wait_for_client()
-    debugpy.breakpoint()
-
-
-def log_explorer(chain, name, path, details):
+def log_explorer(chain: str, name: str, path: str, details: str):
     networks = {
         "1": ("MultiversX Mainnet Explorer", "https://explorer.multiversx.com"),
         "T": ("MultiversX Testnet Explorer", "https://testnet-explorer.multiversx.com"),
@@ -261,9 +252,9 @@ def log_explorer(chain, name, path, details):
         return
 
 
-def log_explorer_contract_address(chain, address):
+def log_explorer_contract_address(chain: str, address: str):
     log_explorer(chain, "contract address", "accounts", address)
 
 
-def log_explorer_transaction(chain, transaction_hash):
+def log_explorer_transaction(chain: str, transaction_hash: str):
     log_explorer(chain, "transaction", "transactions", transaction_hash)
diff --git a/multiversx_sdk_cli/validators/core.py b/multiversx_sdk_cli/validators/core.py
index aad73a35..bc327ad6 100644
--- a/multiversx_sdk_cli/validators/core.py
+++ b/multiversx_sdk_cli/validators/core.py
@@ -2,12 +2,12 @@
 from pathlib import Path
 from typing import Any, List, Tuple, Union
 
-from multiversx_sdk_core import ArbitraryMessage
+from multiversx_sdk_core import Address, ArbitraryMessage
 from multiversx_sdk_wallet.validator_pem import ValidatorPEM
 from multiversx_sdk_wallet.validator_signer import ValidatorSigner
 
 from multiversx_sdk_cli import utils
-from multiversx_sdk_cli.accounts import Account, Address
+from multiversx_sdk_cli.accounts import Account
 from multiversx_sdk_cli.cli_password import load_password
 from multiversx_sdk_cli.config import (GAS_PER_DATA_BYTE, MIN_GAS_LIMIT,
                                        MetaChainSystemSCsCost)
@@ -34,7 +34,7 @@ def prepare_args_for_stake(args: Any):
         raise BadUsage("cannot initialize node operator")
 
     validators_file_path = Path(args.validators_file)
-    reward_address = Address(args.reward_address) if args.reward_address else None
+    reward_address = Address.from_bech32(args.reward_address) if args.reward_address else None
 
     data, gas_limit = prepare_transaction_data_for_stake(node_operator.address, validators_file_path, reward_address)
     args.data = data
@@ -71,9 +71,9 @@ def prepare_transaction_data_for_stake(node_operator_address: Address, validator
         call_arguments.append(f"0x{reward_address.hex()}")
 
     data = SmartContract().prepare_execute_transaction_data("stake", call_arguments)
-    gas_limit = estimate_system_sc_call(data, MetaChainSystemSCsCost.STAKE, num_of_nodes)
+    gas_limit = estimate_system_sc_call(str(data), MetaChainSystemSCsCost.STAKE, num_of_nodes)
 
-    return data, gas_limit
+    return str(data), gas_limit
 
 
 def prepare_args_for_top_up(args: Any):
@@ -112,7 +112,7 @@ def prepare_args_for_unjail(args: Any):
 
 
 def prepare_args_for_change_reward_address(args: Any):
-    reward_address = Address(args.reward_address)
+    reward_address = Address.from_bech32(args.reward_address)
     args.data = 'changeRewardAddress@' + reward_address.hex()
     args.receiver = VALIDATORS_SMART_CONTRACT_ADDRESS
 
diff --git a/mxpy-up.py b/mxpy-up.py
index 2b09e0ee..8cfacc3e 100644
--- a/mxpy-up.py
+++ b/mxpy-up.py
@@ -20,14 +20,17 @@ def main():
     parser.add_argument("--exact-version", help="the exact version of mxpy to install")
     parser.add_argument("--from-branch", help="use a branch of multiversx/mx-sdk-py-cli")
     parser.add_argument("--not-interactive", action="store_true", default=False)
+    parser.add_argument("--verbose", action="store_true", default=False)
     parser.set_defaults(modify_path=True)
     args = parser.parse_args()
 
     exact_version = args.exact_version
     from_branch = args.from_branch
     interactive = not args.not_interactive
+    verbose = args.verbose
 
-    logging.basicConfig(level=logging.DEBUG)
+    log_level = logging.DEBUG if verbose else logging.INFO
+    logging.basicConfig(level=log_level)
 
     if get_operating_system() == "windows":
         print("""
@@ -45,7 +48,8 @@ def main():
     # In case of a fresh install:
     sdk_path.mkdir(parents=True, exist_ok=True)
     create_venv()
-    install_mxpy(exact_version, from_branch)
+    logger.info("Installing the necessary dependencies...")
+    install_mxpy(exact_version, from_branch, verbose)
 
     run_post_install_checks()
 
@@ -54,7 +58,7 @@ def main():
 
 
 def guard_non_root_user():
-    logger.info("Checking user (should not be root).")
+    logger.debug("Checking user (should not be root).")
 
     operating_system = get_operating_system()
 
@@ -67,8 +71,8 @@ def guard_non_root_user():
 def guard_python_version():
     python_version = (sys.version_info.major, sys.version_info.minor, sys.version_info.micro)
 
-    logger.info("Checking Python version.")
-    logger.info(f"Python version: {format_version(python_version)}")
+    logger.debug("Checking Python version.")
+    logger.debug(f"Python version: {format_version(python_version)}")
     if python_version < MIN_REQUIRED_PYTHON_VERSION:
         raise InstallError(f"You need Python {format_version(MIN_REQUIRED_PYTHON_VERSION)} or later.")
 
@@ -123,13 +127,13 @@ def create_venv():
     venv_folder = get_mxpy_venv_path()
     venv_folder.mkdir(parents=True, exist_ok=True)
 
-    logger.info(f"Creating virtual environment in: {venv_folder}.")
+    logger.debug(f"Creating virtual environment in: {venv_folder}.")
     import venv
     builder = venv.EnvBuilder(with_pip=True, symlinks=True)
     builder.clear_directory(venv_folder)
     builder.create(venv_folder)
 
-    logger.info(f"Virtual environment has been created in: {venv_folder}.")
+    logger.debug(f"Virtual environment has been created in: {venv_folder}.")
 
 
 def require_python_venv_tools():
@@ -138,7 +142,7 @@ def require_python_venv_tools():
     try:
         import ensurepip
         import venv
-        logger.info(f"Packages found: {ensurepip}, {venv}.")
+        logger.debug(f"Packages found: {ensurepip}, {venv}.")
     except ModuleNotFoundError:
         if operating_system == "linux":
             python_venv = f"python{sys.version_info.major}.{sys.version_info.minor}-venv"
@@ -151,8 +155,8 @@ def get_mxpy_venv_path():
     return sdk_path / "mxpy-venv"
 
 
-def install_mxpy(exact_version: str, from_branch: str):
-    logger.info("Installing mxpy in virtual environment...")
+def install_mxpy(exact_version: str, from_branch: str, verbose: bool):
+    logger.debug("Installing mxpy in virtual environment...")
 
     if from_branch:
         package_to_install = f"https://github.com/multiversx/mx-sdk-py-cli/archive/refs/heads/{from_branch}.zip"
@@ -161,22 +165,22 @@ def install_mxpy(exact_version: str, from_branch: str):
 
     venv_path = get_mxpy_venv_path()
 
-    return_code = run_in_venv(["python3", "-m", "pip", "install", "--upgrade", "pip"], venv_path)
+    return_code = run_in_venv(["python3", "-m", "pip", "install", "--upgrade", "pip"], venv_path, verbose)
     if return_code != 0:
         raise InstallError("Could not upgrade pip.")
-    return_code = run_in_venv(["pip3", "install", "--no-cache-dir", package_to_install], venv_path)
+    return_code = run_in_venv(["pip3", "install", "--no-cache-dir", package_to_install], venv_path, verbose)
     if return_code != 0:
         raise InstallError("Could not install mxpy.")
 
-    logger.info("Creating mxpy shortcut...")
+    logger.debug("Creating mxpy shortcut...")
 
     shortcut_path = sdk_path / "mxpy"
 
     try:
         shortcut_path.unlink()
-        logger.info(f"Removed existing shortcut: {shortcut_path}")
+        logger.debug(f"Removed existing shortcut: {shortcut_path}")
     except FileNotFoundError:
-        logger.info(f"Shortcut does not exist yet: {shortcut_path}")
+        logger.debug(f"Shortcut does not exist yet: {shortcut_path}")
         pass
 
     shortcut_content = get_mxpy_shortcut_content()
@@ -202,7 +206,7 @@ def get_mxpy_shortcut_content():
 """
 
 
-def run_in_venv(args: List[str], venv_path: Path):
+def run_in_venv(args: List[str], venv_path: Path, verbose: bool):
     env = os.environ.copy()
 
     if "PYTHONHOME" in env:
@@ -211,16 +215,28 @@ def run_in_venv(args: List[str], venv_path: Path):
     env["PATH"] = str(venv_path / "bin") + ":" + env["PATH"]
     env["VIRTUAL_ENV"] = str(venv_path)
 
-    process = subprocess.Popen(args, env=env)
+    if verbose:
+        process = subprocess.Popen(args, env=env)
+    else:
+        process = subprocess.Popen(args, env=env, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
+
     return process.wait()
 
 
 def run_post_install_checks():
     multiversx_sdk_path = Path("~/multiversx-sdk").expanduser()
 
-    logger.info("Running post-install checks...")
-    print("~/multiversx-sdk exists", "OK" if multiversx_sdk_path.exists() else "NOK")
-    print("~/multiversx-sdk/mxpy shortcut created", "OK" if (multiversx_sdk_path / "mxpy").exists() else "NOK")
+    logger.debug("Running post-install checks...")
+
+    if multiversx_sdk_path.exists():
+        logger.debug("~/multiversx-sdk exists  OK")
+    else:
+        logger.warning("~/multiversx-sdk exists  NOK")
+
+    if (multiversx_sdk_path / "mxpy").exists():
+        logger.debug("~/multiversx-sdk/mxpy shortcut created  OK")
+    else:
+        logger.warning("~/multiversx-sdk/mxpy shortcut created  NOK")
 
 
 def guide_system_path_integration():
@@ -230,14 +246,14 @@ def guide_system_path_integration():
     if operating_system == "windows":
         print(f"""
 ###############################################################################
-On Windows, for the "mxpy" command shortcut to be available, you need to add the directory "{sdk_path}" to the system PATH.
+On Windows, for the "mxpy" command shortcut to be available, you MUST ADD the directory "{sdk_path}" to the system PATH.
 
 You can do this by following these steps:
 
 https://superuser.com/questions/949560/how-do-i-set-system-environment-variables-in-windows-10
 
 ###############################################################################
-Do you understand the above?
+Do you UNDERSTAND the above?
 ###############################################################################
 """)
         confirm_continuation(interactive)
@@ -255,7 +271,7 @@ def guide_system_path_integration():
 
 The "mxpy" command shortcut will not be available until you add the directory "{sdk_path}" to the system PATH.
 ###############################################################################
-Do you understand the above?
+Do you UNDERSTAND the above?
 """)
         confirm_continuation(interactive)
         return
@@ -279,7 +295,7 @@ def guide_system_path_integration():
 The entry (entries) to remove: 
     {old_export_directive}
 ###############################################################################
-Make sure you understand the above before proceeding further.
+Make sure you UNDERSTAND the above before proceeding further.
 ###############################################################################
 """)
         confirm_continuation(interactive)
@@ -290,7 +306,7 @@ def guide_system_path_integration():
 ###############################################################################
 It seems that the path "~/multiversx-sdk" is already configured in shell profile.
 
-To confirm this, check the shell profile (now or after the installer script ends). 
+To confirm this, CHECK the shell profile (now or after the installer script ends). 
 
 Your shell profile files:
 {profile_files_formatted}
@@ -298,7 +314,7 @@ def guide_system_path_integration():
 The entry to check (it should be present): 
     {new_export_directive}.
 ###############################################################################
-Make sure you understand the above before proceeding further.
+Make sure you UNDERSTAND the above before proceeding further.
 ###############################################################################
 """)
         confirm_continuation(interactive)
diff --git a/pyproject.toml b/pyproject.toml
index 838c051e..702b77e9 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
 
 [project]
 name = "multiversx-sdk-cli"
-version = "7.3.0"
+version = "8.0.0"
 authors = [
   { name="MultiversX" },
 ]
diff --git a/requirements.txt b/requirements.txt
index 2ead6633..d9574c6a 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,6 +9,6 @@ semver
 requests-cache
 rich==13.3.4
 
-multiversx-sdk-core>=0.5.0
+multiversx-sdk-core==0.6.0
 multiversx-sdk-network-providers>=0.11.0
 multiversx-sdk-wallet>=0.7.0


Test patch:
diff --git a/multiversx_sdk_cli/tests/test_accounts.py b/multiversx_sdk_cli/tests/test_accounts.py
index 7f1cf80d..e89e20ec 100644
--- a/multiversx_sdk_cli/tests/test_accounts.py
+++ b/multiversx_sdk_cli/tests/test_accounts.py
@@ -2,80 +2,7 @@
 
 import pytest
 
-from multiversx_sdk_cli import errors
-from multiversx_sdk_cli.accounts import Account, Address
-from multiversx_sdk_cli.transactions import Transaction
-
-
-def test_address():
-    address = Address("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz")
-    address_cloned = Address(address)
-    assert "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293" == address.hex()
-    assert "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz" == address.bech32()
-    assert address.hex() == address_cloned.hex()
-    assert address.bech32() == address_cloned.bech32()
-
-    address = Address("fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293")
-    address_cloned = Address(address)
-    assert "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293" == address.hex()
-    assert "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz" == address.bech32()
-    assert address.hex() == address_cloned.hex()
-    assert address.bech32() == address_cloned.bech32()
-
-    with pytest.raises(errors.EmptyAddressError):
-        address = Address("")
-        address.hex()
-
-    with pytest.raises(errors.EmptyAddressError):
-        address = Address("")
-        address.bech32()
-
-    with pytest.raises(errors.BadAddressFormatError):
-        address = Address("bad")
-
-
-def test_sign_transaction():
-    alice_pem = Path(__file__).parent / "testdata" / "alice.pem"
-    alice = Account(pem_file=str(alice_pem))
-
-    # With data
-    transaction = Transaction()
-    transaction.nonce = 0
-    transaction.value = "0"
-    transaction.sender = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"
-    transaction.receiver = "erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr"
-    transaction.gasPrice = 200000000000000
-    transaction.gasLimit = 500000000
-    transaction.data = "foo"
-    transaction.chainID = "chainID"
-    transaction.version = 1
-    transaction.signature = alice.sign_transaction(transaction)
-
-    assert "0e69f27e24aba2f3b7a8842dc7e7c085a0bfb5b29112b258318eed73de9c8809889756f8afaa74c7b3c7ce20a028b68ba90466a249aaf999a1a78dcf7f4eb40c" == transaction.signature
-
-    # Without data
-    transaction = Transaction()
-    transaction.nonce = 0
-    transaction.value = "0"
-    transaction.sender = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"
-    transaction.receiver = "erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr"
-    transaction.gasPrice = 200000000000000
-    transaction.gasLimit = 500000000
-    transaction.data = ""
-    transaction.chainID = "chainID"
-    transaction.version = 1
-    transaction.signature = alice.sign_transaction(transaction)
-
-    assert "83efd1bc35790ecc220b0ed6ddd1fcb44af6653dd74e37b3a49dcc1f002a1b98b6f79779192cca68bdfefd037bc81f4fa606628b751023122191f8c062362805" == transaction.signature
-
-
-def test_sign_message():
-    alice_pem = Path(__file__).parent / "testdata" / "alice.pem"
-    alice = Account(pem_file=str(alice_pem))
-
-    message = b"hello"
-    signature = alice.sign_message(message)
-    assert signature == "561bc58f1dc6b10de208b2d2c22c9a474ea5e8cabb59c3d3ce06bbda21cc46454aa71a85d5a60442bd7784effa2e062fcb8fb421c521f898abf7f5ec165e5d0f"
+from multiversx_sdk_cli.accounts import Account
 
 
 def test_load_account_from_keystore_without_kind():
diff --git a/multiversx_sdk_cli/tests/test_cli_all.sh b/multiversx_sdk_cli/tests/test_cli_all.sh
index 7592168d..28cb34f2 100644
--- a/multiversx_sdk_cli/tests/test_cli_all.sh
+++ b/multiversx_sdk_cli/tests/test_cli_all.sh
@@ -13,7 +13,6 @@ testAll() {
         source ./test_cli_validators.sh && testAll
         source ./test_cli_tx.sh && testAll
         source ./test_cli_config.sh && testAll
-        source ./test_cli_network.sh && testAll
     fi
     popd
 }
diff --git a/multiversx_sdk_cli/tests/test_cli_contracts.py b/multiversx_sdk_cli/tests/test_cli_contracts.py
index 547309d0..774bab25 100644
--- a/multiversx_sdk_cli/tests/test_cli_contracts.py
+++ b/multiversx_sdk_cli/tests/test_cli_contracts.py
@@ -1,9 +1,88 @@
 from pathlib import Path
+from typing import Any
+
+import pytest
+
 from multiversx_sdk_cli.cli import main
 
+parent = Path(__file__).parent
+
+
+def test_contract_new():
+    main([
+        "contract",
+        "new",
+        "--template",
+        "adder",
+        "--directory",
+        f"{parent}/testdata-out/SANDBOX",
+        "adder"
+    ])
+    assert Path.is_dir(parent / "testdata-out" / "SANDBOX" / "adder")
+
+
+def test_contract_new_with_bad_code():
+    # we change the contract code so the build would fail so we can catch the error
+    main([
+        "contract",
+        "new",
+        "--template",
+        "adder",
+        "--directory",
+        f"{parent}/testdata-out/SANDBOX",
+        "adder-bad-src"
+    ])
+
+    assert Path.is_dir(parent / "testdata-out" / "SANDBOX" / "adder-bad-src")
+    replace_variable_with_unknown_variable()
+
+
+def replace_variable_with_unknown_variable():
+    # this is done in order to replace the value added in the adder contract witha unknown variable
+    with open(parent / "testdata-out" / "SANDBOX" / "adder-bad-src" / "src" / "adder.rs", "r") as f:
+        contract_lines = f.readlines()
+
+    for index, line in reversed(list(enumerate(contract_lines))):
+        if "value" in line:
+            contract_lines[index] = line.replace("value", "unknown_variable")
+            break
+
+    with open(parent / "testdata-out" / "SANDBOX" / "adder-bad-src" / "src" / "adder.rs", "w") as f:
+        f.writelines(contract_lines)
+
+
+@pytest.mark.skip_on_windows
+def test_contract_build():
+    main([
+        "contract",
+        "build",
+        "--path",
+        f"{parent}/testdata-out/SANDBOX/adder"
+    ])
+
+    assert Path.is_file(Path(Path(parent) / "testdata-out" / "SANDBOX" / "adder" / "output" / "adder.wasm"))
+
+
+@pytest.mark.skip_on_windows
+def test_bad_contract_build(capsys: Any):
+    ERROR = "Build error: error code = 101, see output."
+
+    main([
+        "contract",
+        "build",
+        "--path",
+        f"{parent}/testdata-out/SANDBOX/adder-bad-src"
+    ])
+
+    out, _ = capsys.readouterr()
+
+    if ERROR in out:
+        assert True
+    else:
+        assert False
+
 
 def test_contract_deploy():
-    parent = Path(__file__).parent
     output_file = parent / "testdata-out" / "deploy.json"
 
     main(
@@ -31,7 +110,6 @@ def test_contract_deploy():
 
 
 def test_contract_upgrade():
-    parent = Path(__file__).parent
     output_file = parent / "testdata-out" / "upgrade.json"
     contract_address = "erd1qqqqqqqqqqqqqpgq5l9jl0j0gnqmm7hn82zaydwux3s5xuwkyq8srt5vsy"
 
@@ -61,7 +139,6 @@ def test_contract_upgrade():
 
 
 def test_contract_call():
-    parent = Path(__file__).parent
     output_file = parent / "testdata-out" / "call.json"
     contract_address = "erd1qqqqqqqqqqqqqpgq5l9jl0j0gnqmm7hn82zaydwux3s5xuwkyq8srt5vsy"
 
diff --git a/multiversx_sdk_cli/tests/test_cli_contracts.sh b/multiversx_sdk_cli/tests/test_cli_contracts.sh
index d4ddc443..174e0b2f 100755
--- a/multiversx_sdk_cli/tests/test_cli_contracts.sh
+++ b/multiversx_sdk_cli/tests/test_cli_contracts.sh
@@ -24,23 +24,23 @@ testBuildContracts() {
     export TARGET_DIR=$(pwd)/${SANDBOX}/TARGET
     mkdir -p ${TARGET_DIR}
 
-    ${CLI} contract build ${SANDBOX}/myadder-rs --cargo-target-dir=${TARGET_DIR} || return 1
+    ${CLI} contract build --path=${SANDBOX}/myadder-rs --target-dir=${TARGET_DIR} || return 1
     assertFileExists ${SANDBOX}/myadder-rs/output/myadder-rs.wasm || return 1
     assertFileExists ${SANDBOX}/myadder-rs/output/myadder-rs.abi.json || return 1
 
-    ${CLI} contract build ${SANDBOX}/myfactorial-rs --cargo-target-dir=${TARGET_DIR} || return 1
+    ${CLI} contract build --path=${SANDBOX}/myfactorial-rs --target-dir=${TARGET_DIR} || return 1
     assertFileExists ${SANDBOX}/myfactorial-rs/output/myfactorial-rs.wasm || return 1
     assertFileExists ${SANDBOX}/myfactorial-rs/output/myfactorial-rs.abi.json || return 1
 
-    ${CLI} contract build ${SANDBOX}/mybubbles-rs --cargo-target-dir=${TARGET_DIR} || return 1
+    ${CLI} contract build --path=${SANDBOX}/mybubbles-rs --target-dir=${TARGET_DIR} || return 1
     assertFileExists ${SANDBOX}/mybubbles-rs/output/mybubbles-rs.wasm || return 1
     assertFileExists ${SANDBOX}/mybubbles-rs/output/mybubbles-rs.abi.json || return 1
 
-    ${CLI} contract build ${SANDBOX}/mylottery-rs --cargo-target-dir=${TARGET_DIR} || return 1
+    ${CLI} contract build --path=${SANDBOX}/mylottery-rs --target-dir=${TARGET_DIR} || return 1
     assertFileExists ${SANDBOX}/mylottery-rs/output/mylottery-rs.wasm || return 1
     assertFileExists ${SANDBOX}/mylottery-rs/output/mylottery-rs.abi.json || return 1
 
-    ${CLI} contract build ${SANDBOX}/myfunding-rs --cargo-target-dir=${TARGET_DIR} || return 1
+    ${CLI} contract build --path=${SANDBOX}/myfunding-rs --target-dir=${TARGET_DIR} || return 1
     assertFileExists ${SANDBOX}/myfunding-rs/output/myfunding-rs.wasm || return 1
     assertFileExists ${SANDBOX}/myfunding-rs/output/myfunding-rs.abi.json || return 1
 }
@@ -56,9 +56,9 @@ testRunScenarios() {
 testWasmName() {
     echo "testWasmName"
    
-    ${CLI} contract clean ${SANDBOX}/myadder-rs
+    ${CLI} contract clean --path ${SANDBOX}/myadder-rs
     assertFileDoesNotExist ${SANDBOX}/myadder-rs/output/myadder-2-rs.wasm || return 1
-    ${CLI} contract build ${SANDBOX}/myadder-rs --cargo-target-dir=${TARGET_DIR} --wasm-name myadder-2-rs || return 1
+    ${CLI} contract build --path=${SANDBOX}/myadder-rs --target-dir=${TARGET_DIR} --wasm-name myadder-2-rs || return 1
     assertFileExists ${SANDBOX}/myadder-rs/output/myadder-2-rs.wasm || return 1
     assertFileExists ${SANDBOX}/myadder-rs/output/myadder-rs.abi.json || return 1
 }
@@ -68,31 +68,31 @@ testCleanContracts() {
 
     assertFileExists ${SANDBOX}/myadder-rs/output/myadder-rs.wasm || return 1
     assertFileExists ${SANDBOX}/myadder-rs/output/myadder-rs.abi.json || return 1
-    ${CLI} contract clean ${SANDBOX}/myadder-rs || return 1
+    ${CLI} contract clean --path ${SANDBOX}/myadder-rs || return 1
     assertFileDoesNotExist ${SANDBOX}/myadder-rs/output/myadder-rs.wasm || return 1
     assertFileDoesNotExist ${SANDBOX}/myadder-rs/output/myadder-rs.abi.json || return 1
 
     assertFileExists ${SANDBOX}/myfactorial-rs/output/myfactorial-rs.wasm || return 1
     assertFileExists ${SANDBOX}/myfactorial-rs/output/myfactorial-rs.abi.json || return 1
-    ${CLI} contract clean ${SANDBOX}/myfactorial-rs || return 1
+    ${CLI} contract clean --path ${SANDBOX}/myfactorial-rs || return 1
     assertFileDoesNotExist ${SANDBOX}/myfactorial-rs/output/myfactorial-rs.wasm || return 1
     assertFileDoesNotExist ${SANDBOX}/myfactorial-rs/output/myfactorial-rs.abi.json || return 1
 
     assertFileExists ${SANDBOX}/mybubbles-rs/output/mybubbles-rs.wasm || return 1
     assertFileExists ${SANDBOX}/mybubbles-rs/output/mybubbles-rs.abi.json || return 1
-    ${CLI} contract clean ${SANDBOX}/mybubbles-rs || return 1
+    ${CLI} contract clean --path ${SANDBOX}/mybubbles-rs || return 1
     assertFileDoesNotExist ${SANDBOX}/mybubbles-rs/output/mybubbles-rs.wasm || return 1
     assertFileDoesNotExist ${SANDBOX}/mybubbles-rs/output/mybubbles-rs.abi.json || return 1
 
     assertFileExists ${SANDBOX}/mylottery-rs/output/mylottery-rs.wasm || return 1
     assertFileExists ${SANDBOX}/mylottery-rs/output/mylottery-rs.abi.json || return 1
-    ${CLI} contract clean ${SANDBOX}/mylottery-rs || return 1
+    ${CLI} contract clean --path ${SANDBOX}/mylottery-rs || return 1
     assertFileDoesNotExist ${SANDBOX}/mylottery-rs/output/mylottery-rs.wasm || return 1
     assertFileDoesNotExist ${SANDBOX}/mylottery-rs/output/mylottery-rs.abi.json || return 1
 
     assertFileExists ${SANDBOX}/myfunding-rs/output/myfunding-rs.wasm || return 1
     assertFileExists ${SANDBOX}/myfunding-rs/output/myfunding-rs.abi.json || return 1
-    ${CLI} contract clean ${SANDBOX}/myfunding-rs || return 1
+    ${CLI} contract clean --path ${SANDBOX}/myfunding-rs || return 1
     assertFileDoesNotExist ${SANDBOX}/myfunding-rs/output/myfunding-rs.wasm || return 1
     assertFileDoesNotExist ${SANDBOX}/myfunding-rs/output/myfunding-rs.abi.json || return 1
 }
diff --git a/multiversx_sdk_cli/tests/test_cli_dns.sh b/multiversx_sdk_cli/tests/test_cli_dns.sh
index 9af261a0..fa3c9340 100644
--- a/multiversx_sdk_cli/tests/test_cli_dns.sh
+++ b/multiversx_sdk_cli/tests/test_cli_dns.sh
@@ -76,32 +76,32 @@ testRegistrationOffline() {
 }
 
 testTransactionsWithUsernamesOffline() {
-    ${CLI} --verbose tx new --pem=${TestUser} --receiver=${TestUser2} \
+    ${CLI} --verbose tx new --pem=${TestUser} --receiver="erd1ssmsc9022udc8pdw7wk3hxw74jr900xg28vwpz3z60gep66fasasl2nkm4" \
         --value="1${DENOMINATION}" --nonce=42 --gas-limit=50000 --gas-price=2000000000 --chain=${CHAIN_ID} \
         --outfile=${SANDBOX}/txA.txt || return 1
     assertFileExists ${SANDBOX}/txA.txt || return 1
 
-    ${CLI} --verbose tx new --pem=${TestUser} --receiver=${TestUser2} --receiver-username="testuser2" \
+    ${CLI} --verbose tx new --pem=${TestUser} --receiver="erd1ssmsc9022udc8pdw7wk3hxw74jr900xg28vwpz3z60gep66fasasl2nkm4" --receiver-username="testuser2" \
         --value="1${DENOMINATION}" --nonce=43 --gas-limit=50000 --gas-price=2000000000 --chain=${CHAIN_ID} \
         --outfile=${SANDBOX}/txB.txt || return 1
     assertFileExists ${SANDBOX}/txB.txt || return 1
 
-    ${CLI} --verbose tx new --pem=${TestUser} --receiver=${TestUser2} --receiver-username="testuser2foo" \
+    ${CLI} --verbose tx new --pem=${TestUser} --receiver="erd1ssmsc9022udc8pdw7wk3hxw74jr900xg28vwpz3z60gep66fasasl2nkm4" --receiver-username="testuser2foo" \
         --value="1${DENOMINATION}" --nonce=44 --gas-limit=50000 --gas-price=2000000000 --chain=${CHAIN_ID} \
         --outfile=${SANDBOX}/txC.txt || return 1
     assertFileExists ${SANDBOX}/txC.txt || return 1
 
-    ${CLI} --verbose tx new --pem=${TestUser} --sender-username="testuser" --receiver=${TestUser2} --receiver-username="testuser2" \
+    ${CLI} --verbose tx new --pem=${TestUser} --sender-username="testuser" --receiver="erd1ssmsc9022udc8pdw7wk3hxw74jr900xg28vwpz3z60gep66fasasl2nkm4" --receiver-username="testuser2" \
         --value="1${DENOMINATION}" --nonce=45 --gas-limit=50000 --gas-price=2000000000 --chain=${CHAIN_ID} \
         --outfile=${SANDBOX}/txD.txt || return 1
     assertFileExists ${SANDBOX}/txD.txt || return 1
 
-    ${CLI} --verbose tx new --pem=${TestUser} --sender-username="testuser" --receiver=${TestUser2} \
+    ${CLI} --verbose tx new --pem=${TestUser} --sender-username="testuser" --receiver="erd1ssmsc9022udc8pdw7wk3hxw74jr900xg28vwpz3z60gep66fasasl2nkm4" \
         --value="1${DENOMINATION}" --nonce=46 --gas-limit=50000 --gas-price=2000000000 --chain=${CHAIN_ID} \
         --outfile=${SANDBOX}/txF.txt || return 1
     assertFileExists ${SANDBOX}/txF.txt || return 1
 
-    ${CLI} --verbose tx new --pem=${TestUser} --sender-username="testuserfoo" --receiver=${TestUser2} \
+    ${CLI} --verbose tx new --pem=${TestUser} --sender-username="testuserfoo" --receiver="erd1ssmsc9022udc8pdw7wk3hxw74jr900xg28vwpz3z60gep66fasasl2nkm4" \
         --value="1${DENOMINATION}" --nonce=47 --gas-limit=50000 --gas-price=2000000000 --chain=${CHAIN_ID} \
         --outfile=${SANDBOX}/txG.txt || return 1
     assertFileExists ${SANDBOX}/txG.txt || return 1
diff --git a/multiversx_sdk_cli/tests/test_cli_network.sh b/multiversx_sdk_cli/tests/test_cli_network.sh
deleted file mode 100644
index 4b16cc41..00000000
--- a/multiversx_sdk_cli/tests/test_cli_network.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-
-source "./shared.sh"
-
-testAll() {
-    echo "network.num-shards"
-    ${CLI} --verbose network num-shards --proxy=${PROXY}
-    echo "network.block-nonce"
-    ${CLI} --verbose network block-nonce --shard=0 --proxy=${PROXY}
-    echo "network.chain"
-    ${CLI} --verbose network chain --proxy=${PROXY}
-}
diff --git a/multiversx_sdk_cli/tests/test_cli_shared.py b/multiversx_sdk_cli/tests/test_cli_shared.py
new file mode 100644
index 00000000..04944866
--- /dev/null
+++ b/multiversx_sdk_cli/tests/test_cli_shared.py
@@ -0,0 +1,50 @@
+from multiversx_sdk_cli.cli_shared import convert_args_object_to_args_list
+
+
+class ContractBuildArgs:
+    def __init__(self) -> None:
+        self.verbose = False
+        self.path = "testadata-out/SANDBOX/myadder-rs"
+        self.no_wasm_opt = False
+        self.wasm_symbols = False
+        self.wasm_name = None
+        self.wasm_suffix = None
+        self.target_dir = None
+        self.wat = False
+        self.mir = False
+        self.llvm_ir = False
+        self.ignore = None
+        self.no_imports = False
+        self.no_abi_git_version = False
+        self.twiggy_top = False
+        self.twiggy_paths = False
+        self.twiggy_monos = False
+        self.twiggy_dominators = False
+        self.func = "should be a func object"
+
+
+def test_args_obj_to_list():
+    contract_build_args = ContractBuildArgs()
+
+    args_list = convert_args_object_to_args_list(contract_build_args)
+
+    assert len(args_list) == 2
+    assert args_list[0] == "--path"
+    assert args_list[1] == contract_build_args.path
+
+    contract_build_args.no_wasm_opt = True
+    args_list = convert_args_object_to_args_list(contract_build_args)
+
+    assert len(args_list) == 3
+    assert args_list[0] == "--path"
+    assert args_list[1] == contract_build_args.path
+    assert args_list[2] == "--no-wasm-opt"
+
+    contract_build_args.ignore = "random_directory"
+    contract_build_args.no_imports = True
+    args_list = convert_args_object_to_args_list(contract_build_args)
+
+    assert len(args_list) == 6
+    assert args_list[3] == "--ignore"
+    assert args_list[4] == contract_build_args.ignore
+    assert args_list[5] == "--no-imports"
diff --git a/multiversx_sdk_cli/tests/test_code_metadata.py b/multiversx_sdk_cli/tests/test_code_metadata.py
index bfe8e127..2cf904a8 100644
--- a/multiversx_sdk_cli/tests/test_code_metadata.py
+++ b/multiversx_sdk_cli/tests/test_code_metadata.py
@@ -1,9 +1,11 @@
 from multiversx_sdk_cli.contracts import CodeMetadata
 
+
 def test_code_metadata_defaults():
     assert CodeMetadata().to_hex() == "0500"
     assert CodeMetadata().to_hex() == CodeMetadata(upgradeable=True, readable=True, payable=False, payable_by_sc=False).to_hex()
 
+
 def test_code_metadata_single_flag():
     assert CodeMetadata(upgradeable=False, readable=False, payable=False, payable_by_sc=False).to_hex() == "0000"
     assert CodeMetadata(upgradeable=True, readable=False, payable=False, payable_by_sc=False).to_hex() == "0100"
@@ -11,6 +13,7 @@ def test_code_metadata_single_flag():
     assert CodeMetadata(upgradeable=False, readable=False, payable=True, payable_by_sc=False).to_hex() == "0002"
     assert CodeMetadata(upgradeable=False, readable=False, payable=False, payable_by_sc=True).to_hex() == "0004"
 
+
 def test_code_metadata_multiple_flags():
     assert CodeMetadata(upgradeable=False, readable=True, payable=False, payable_by_sc=True).to_hex() == "0404"
     assert CodeMetadata(upgradeable=True, readable=True, payable=False, payable_by_sc=False).to_hex() == "0500"
diff --git a/multiversx_sdk_cli/tests/test_contracts.py b/multiversx_sdk_cli/tests/test_contracts.py
index 7f3f4bc7..f7a63b7f 100644
--- a/multiversx_sdk_cli/tests/test_contracts.py
+++ b/multiversx_sdk_cli/tests/test_contracts.py
@@ -1,13 +1,17 @@
 import logging
 from pathlib import Path
-import sys
-import pytest
 
+import pytest
 from Cryptodome.Hash import keccak
-from multiversx_sdk_cli.accounts import Account, Address
-from multiversx_sdk_cli.contracts import SmartContract, _prepare_argument, _interpret_as_number_if_safely
+from multiversx_sdk_core.address import Address, compute_contract_address
+
 from multiversx_sdk_cli import errors
+from multiversx_sdk_cli.accounts import Account
+from multiversx_sdk_cli.constants import DEFAULT_HRP
 from multiversx_sdk_cli.contract_verification import _create_request_signature
+from multiversx_sdk_cli.contracts import (SmartContract,
+                                          _interpret_as_number_if_safely,
+                                          _prepare_argument)
 
 logging.basicConfig(level=logging.INFO)
 
@@ -21,15 +25,16 @@ def test_playground_keccak():
 
 def test_compute_address():
     contract = SmartContract()
-    contract.owner = Account("93ee6143cdc10ce79f15b2a6c2ad38e9b6021c72a1779051f47154fd54cfbd5e")
+    contract.owner = Account(address=Address.from_hex("93ee6143cdc10ce79f15b2a6c2ad38e9b6021c72a1779051f47154fd54cfbd5e", DEFAULT_HRP))
 
     contract.owner.nonce = 0
-    contract.compute_address()
+    contract.address = compute_contract_address(contract.owner.address, contract.owner.nonce, DEFAULT_HRP)
+    assert contract.address
     assert contract.address.hex() == "00000000000000000500bb652200ed1f994200ab6699462cab4b1af7b11ebd5e"
     assert contract.address.bech32() == "erd1qqqqqqqqqqqqqpgqhdjjyq8dr7v5yq9tv6v5vt9tfvd00vg7h40q6779zn"
 
     contract.owner.nonce = 1
-    contract.compute_address()
+    contract.address = compute_contract_address(contract.owner.address, contract.owner.nonce, DEFAULT_HRP)
     assert contract.address.hex() == "000000000000000005006e4f90488e27342f9a46e1809452c85ee7186566bd5e"
     assert contract.address.bech32() == "erd1qqqqqqqqqqqqqpgqde8eqjywyu6zlxjxuxqfg5kgtmn3setxh40qen8egy"
 
@@ -67,8 +72,8 @@ def test_prepare_argument():
 
 
 def test_contract_verification_create_request_signature():
-    account = Account(pem_file=testdata_folder / "walletKey.pem")
-    contract_address = Address("erd1qqqqqqqqqqqqqpgqeyj9g344pqguukajpcfqz9p0rfqgyg4l396qespdck")
+    account = Account(pem_file=str(testdata_folder / "walletKey.pem"))
+    contract_address = Address.from_bech32("erd1qqqqqqqqqqqqqpgqeyj9g344pqguukajpcfqz9p0rfqgyg4l396qespdck")
     request_payload = b"test"
     signature = _create_request_signature(account, contract_address, request_payload)
 
diff --git a/multiversx_sdk_cli/tests/test_ledger.py b/multiversx_sdk_cli/tests/test_ledger.py
index a3e290d8..fff0b272 100644
--- a/multiversx_sdk_cli/tests/test_ledger.py
+++ b/multiversx_sdk_cli/tests/test_ledger.py
@@ -1,19 +1,17 @@
-import unittest
-
 from multiversx_sdk_cli.ledger.config import compare_versions
 from multiversx_sdk_cli.ledger.ledger_app_handler import get_error
 
 
-class LedgerTestCase(unittest.TestCase):
+class TestLedger:
     def test_compare_versions(self):
-        self.assertEqual(compare_versions("v1.0.0", "v1.0.1"), -1)
-        self.assertEqual(compare_versions("v1.0.1", "v1.0.1"), 0)
-        self.assertEqual(compare_versions("v1.0.1", "v1.0.0"), 1)
-        self.assertEqual(compare_versions("v1.0.0.1", "v1.0.0"), 1)
-        self.assertEqual(compare_versions("v1.0.1", "v1.0.1.0.0.4"), -1)
+        assert compare_versions("v1.0.0", "v1.0.1") == -1
+        assert compare_versions("v1.0.1", "v1.0.1") == 0
+        assert compare_versions("v1.0.1", "v1.0.0") == 1
+        assert compare_versions("v1.0.0.1", "v1.0.0") == 1
+        assert compare_versions("v1.0.1", "v1.0.1.0.0.4") == -1
 
     def test_get_error(self):
-        self.assertEqual(get_error(0x6E0C), "invalid fee")
-        self.assertEqual(get_error(0x6E11), "regular signing is deprecated")
-        self.assertEqual(get_error(0x9000), "")
-        self.assertEqual(get_error(0x9999999999), "unknown error code: 0x9999999999")
+        assert get_error(0x6E0C) == "invalid fee"
+        assert get_error(0x6E11) == "regular signing is deprecated"
+        assert get_error(0x9000) == ""
+        assert get_error(0x9999999999) == "unknown error code: 0x9999999999"
diff --git a/multiversx_sdk_cli/tests/test_modules.py b/multiversx_sdk_cli/tests/test_modules.py
index c305a310..22bfa200 100644
--- a/multiversx_sdk_cli/tests/test_modules.py
+++ b/multiversx_sdk_cli/tests/test_modules.py
@@ -1,5 +1,6 @@
-import semver
 import pytest
+import semver
+
 from multiversx_sdk_cli.config import get_latest_semver
 
 
diff --git a/multiversx_sdk_cli/tests/test_playground_proxy.py b/multiversx_sdk_cli/tests/test_playground_proxy.py
index a9098757..3bd999ee 100644
--- a/multiversx_sdk_cli/tests/test_playground_proxy.py
+++ b/multiversx_sdk_cli/tests/test_playground_proxy.py
@@ -1,10 +1,9 @@
-import unittest
-
+import pytest
 import requests
 
 
-class TestPlaygroundProxy(unittest.TestCase):
-    @unittest.skip('manual run only')
+class TestPlaygroundProxy:
+    @pytest.mark.skip('manual run only')
     def test_do_request(self):
         # use a valid proxy address
         url = "http://localhost:8001"
@@ -13,9 +12,9 @@ def test_do_request(self):
         response = requests.get(url + "/address/" + address + "/nonce")
         print("response status code " + str(response.status_code))
         print(response.json())
-        self.assertTrue(self, response is not None)
+        assert response is not None
 
-    @unittest.skip('manual run only')
+    @pytest.mark.skip('manual run only')
     def test_do_request_node_status(self):
         # use a valid proxy address
         url = "http://localhost:8001"
@@ -25,4 +24,4 @@ def test_do_request_node_status(self):
         response = requests.get(f"{url}/network/status/{shard_id}")
         print("response status code " + str(response.status_code))
         print(response.json())
-        self.assertTrue(self, response is not None)
+        assert response is not None
diff --git a/multiversx_sdk_cli/tests/test_proxy.py b/multiversx_sdk_cli/tests/test_proxy.py
index e292939d..cf570768 100644
--- a/multiversx_sdk_cli/tests/test_proxy.py
+++ b/multiversx_sdk_cli/tests/test_proxy.py
@@ -1,3 +1,4 @@
+from multiversx_sdk_core import Address
 from multiversx_sdk_network_providers.proxy_network_provider import \
     ProxyNetworkProvider
 
@@ -22,42 +23,8 @@ def test_get_account():
         assert False
 
 
-def test_get_hyperblock_by_nonce():
-    result = main(
-        [
-            "hyperblock",
-            "get",
-            "--key",
-            "4312144",
-            "--proxy",
-            "https://devnet-api.multiversx.com",
-        ]
-    )
-    if not result:
-        assert True
-    else:
-        assert False
-
-
-def test_get_hyperblock_by_hash():
-    result = main(
-        [
-            "hyperblock",
-            "get",
-            "--key",
-            "756cb9c0a2d16b0fe9027a21c845a4f4eb1f1331630632669c88250128b40440",
-            "--proxy",
-            "https://devnet-api.multiversx.com",
-        ]
-    )
-    if not result:
-        assert True
-    else:
-        assert False
-
-
 def test_sync_nonce():
-    account = Account("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th")
+    account = Account(address=Address.from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"))
     proxy = ProxyNetworkProvider("https://devnet-api.multiversx.com")
     account.sync_nonce(proxy)
 
@@ -82,56 +49,6 @@ def test_query_contract():
         assert False
 
 
-def test_get_num_shards():
-    result = main(
-        [
-            "network",
-            "num-shards",
-            "--proxy",
-            "https://testnet-api.multiversx.com"
-        ]
-    )
-
-    if not result:
-        assert True
-    else:
-        assert False
-
-
-def test_get_last_block_nonce():
-    result = main(
-        [
-            "network",
-            "block-nonce",
-            "--shard",
-            "4294967295",
-            "--proxy",
-            "https://testnet-api.multiversx.com"
-        ]
-    )
-
-    if not result:
-        assert True
-    else:
-        assert False
-
-
-def test_get_chain_id():
-    result = main(
-        [
-            "network",
-            "chain",
-            "--proxy",
-            "https://testnet-api.multiversx.com"
-        ]
-    )
-
-    if not result:
-        assert True
-    else:
-        assert False
-
-
 def test_get_transaction():
     result = main(
         [
diff --git a/multiversx_sdk_cli/tests/test_rust.py b/multiversx_sdk_cli/tests/test_rust.py
index 5bb91c5d..b7266cb3 100644
--- a/multiversx_sdk_cli/tests/test_rust.py
+++ b/multiversx_sdk_cli/tests/test_rust.py
@@ -1,5 +1,4 @@
 import logging
-import unittest
 from pathlib import Path
 
 from multiversx_sdk_cli import utils
@@ -7,8 +6,8 @@
 logging.basicConfig(level=logging.INFO)
 
 
-class ProjectRustTestCase(unittest.TestCase):
-    def setUp(self):
+class TestProjectRust:
+    def test_set_up(self):
         self.testdata = Path(__file__).parent.joinpath("testdata")
         self.testdata_out = Path(__file__).parent.joinpath("testdata-out")
         utils.ensure_folder(self.testdata_out)
diff --git a/multiversx_sdk_cli/tests/test_transactions.py b/multiversx_sdk_cli/tests/test_transactions.py
deleted file mode 100644
index 7396ba0c..00000000
--- a/multiversx_sdk_cli/tests/test_transactions.py
+++ /dev/null
@@ -1,98 +0,0 @@
-import logging
-
-from multiversx_sdk_cli.accounts import Account
-from multiversx_sdk_cli.errors import GasLimitTooLarge
-from multiversx_sdk_cli.tests.utils import MyTestCase
-from multiversx_sdk_cli.transactions import Transaction
-
-logging.basicConfig(level=logging.INFO)
-
-
-class TransactionsTestCase(MyTestCase):
-    def setUp(self):
-        super().setUp()
-        self.alice = Account(pem_file=str(self.devnet_wallets.joinpath("users", "alice.pem")))
-
-    def test_serialize_transaction_payload(self):
-        # With data field
-        transaction = Transaction()
-        transaction.nonce = 0
-        transaction.value = "42"
-        transaction.sender = "alice"
-        transaction.receiver = "bob"
-        transaction.gasPrice = 43
-        transaction.gasLimit = 44
-        transaction.data = "foobar"
-        transaction.chainID = "BoN"
-        transaction.version = 1
-        serialized = transaction.serialize().decode()
-        self.assertEqual("""{"nonce":0,"value":"42","receiver":"bob","sender":"alice","gasPrice":43,"gasLimit":44,"data":"Zm9vYmFy","chainID":"BoN","version":1}""", serialized)
-
-        # Without data field
-        transaction.data = ""
-        serialized = transaction.serialize().decode()
-        self.assertEqual("""{"nonce":0,"value":"42","receiver":"bob","sender":"alice","gasPrice":43,"gasLimit":44,"chainID":"BoN","version":1}""", serialized)
-
-        # With actual addresses
-        transaction = Transaction()
-        transaction.nonce = 0
-        transaction.value = "0"
-        transaction.sender = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"
-        transaction.receiver = "erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr"
-        transaction.gasPrice = 200000000000000
-        transaction.gasLimit = 500000000
-        transaction.data = "foo"
-        transaction.chainID = "BoN"
-        transaction.version = 1
-        serialized = transaction.serialize().decode()
-        self.assertEqual("""{"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"Zm9v","chainID":"BoN","version":1}""", serialized)
-
-    def test_serialize_transaction_with_usernames(self):
-        transaction = Transaction()
-        transaction.nonce = 89
-        transaction.value = "0"
-        transaction.sender = "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"
-        transaction.receiver = "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"
-        transaction.senderUsername = "alice"
-        transaction.receiverUsername = "bob"
-        transaction.gasPrice = 1000000000
-        transaction.gasLimit = 50000
-        transaction.data = ""
-        transaction.chainID = "localnet"
-        transaction.version = 1
-
-        serialized = transaction.serialize().decode()
-        self.assertEqual("""{"nonce":89,"value":"0","receiver":"erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx","sender":"erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th","senderUsername":"YWxpY2U=","receiverUsername":"Ym9i","gasPrice":1000000000,"gasLimit":50000,"chainID":"localnet","version":1}""", serialized)
-
-        transaction.sign(self.alice)
-        self.assertEqual("f872ea6d43b86ba6b22a7f62319a972124fc6dbd6b0743fa6465819a14d7a90100be865affb030bddf7ed86e648236cd20b1d5078e805b5419d43f3c5032b006", transaction.signature)
-
-    def test_serialize_transaction_as_inner(self):
-        transaction = Transaction()
-        transaction.nonce = 0
-        transaction.value = "0"
-        transaction.sender = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"
-        transaction.receiver = "erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr"
-        transaction.gasPrice = 200000000000000
-        transaction.gasLimit = 500000000
-        transaction.data = "foo"
-        transaction.chainID = "BoN"
-        transaction.version = 1
-        transaction.sign(self.alice)
-        serialized = transaction.serialize_as_inner()
-
-        self.assertEqual("relayedTx@7b226e6f6e6365223a302c2276616c7565223a302c227265636569766572223a224f655a47687431437775596d33376655756233615256346d6d73354b48426b4443757132716670354b67343d222c2273656e646572223a222f576b62746568644543614832424235332f7a6f517454634d6f4a323074544744592f5277304d384d704d3d222c226761735072696365223a3230303030303030303030303030302c226761734c696d6974223a3530303030303030302c2264617461223a225a6d3976222c22636861696e4944223a22516d394f222c2276657273696f6e223a312c227369676e6174757265223a224a38433741664278376f594e79746b713542564845367a4f6f7563596a796a4e79375a47484961485139674f3354384a75442f325147507650724f694f58444b5031744274643338596a667a37384f736a624a7743673d3d227d", serialized)
-
-    def test_sign_when_gas_limit_too_large(self):
-        transaction = Transaction()
-        transaction.nonce = 0
-        transaction.value = "0"
-        transaction.sender = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"
-        transaction.receiver = "erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr"
-        transaction.gasPrice = 200000000000000
-        transaction.gasLimit = 1500000000
-        transaction.data = "foo"
-        transaction.chainID = "chainID"
-        transaction.version = 1
-
-        self.assertRaises(GasLimitTooLarge, lambda: transaction.sign(self.alice))
diff --git a/multiversx_sdk_cli/tests/test_validators_core.py b/multiversx_sdk_cli/tests/test_validators_core.py
index 509522f1..bf473af0 100644
--- a/multiversx_sdk_cli/tests/test_validators_core.py
+++ b/multiversx_sdk_cli/tests/test_validators_core.py
@@ -1,14 +1,17 @@
 from pathlib import Path
-from multiversx_sdk_cli.accounts import Address
-from multiversx_sdk_cli.validators.core import prepare_transaction_data_for_stake
+
+from multiversx_sdk_core import Address
+
+from multiversx_sdk_cli.validators.core import \
+    prepare_transaction_data_for_stake
 
 TESTDATA_FOLDER = Path(__file__).parent.joinpath("testdata")
 
 
 def test_prepare_transaction_data_for_stake():
-    node_operator_address = Address("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th")
+    node_operator_address = Address.from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th")
     validators_file_path = TESTDATA_FOLDER / "validators.json"
     data, gas_limit = prepare_transaction_data_for_stake(node_operator_address, validators_file_path, node_operator_address)
-    
+
     assert data == "stake@03@E7BEAA95B3877F47348DF4DD1CB578A4F7CABF7A20BFEEFE5CDD263878FF132B765E04FEF6F40C93512B666C47ED7719B8902F6C922C04247989B7137E837CC81A62E54712471C97A2DDAB75AA9C2F58F813ED4C0FA722BDE0AB718BFF382208@604882237A9845F508AD03877B5AAB90569683EEB51FAFCBBEB87440BA359992B3C0B837A8757C25BE18132549404F88@78689FD4B1E2E434D567FE01E61598A42717D83124308266BD09CCC15D2339DD318C019914B86AC29ADBAE5DD8A02D0307425E9BD85A296E94943708C72F8C670F0B7C50A890A5719088DBD9F1D062CAD9ACFFA06DF834106EEBE1A4257EF00D@EC54A009695AF56C3585EF623387B67B6DF1974B0B3C9138EB64BDE6EB33978AE9851112B20C99BF63588E8E949E4388@7188B234A8BF834F2E6258012AA09A2AB93178FFAB9C789480275F61FE02CD1B9A58DDC63B79A73ABEA9E2B7AC5CAC0B0D4324EFF50ACA2F0EC946B9AE6797511FA3CE461B57E77129CBA8AB3B51147695D4CE889CBE67905F6586B4E4F22491@C6C637DE17DB5F89A2FA1D1D935CB60C0E5E8958D3BFC47F903F774DD97398C8FE22093E113865EE98C3AFDD1DE62694@0139472EFF6886771A982F3083DA5D421F24C29181E63888228DC81CA60D69E1"
     assert gas_limit == 16464500
diff --git a/multiversx_sdk_cli/tests/test_validators_file.py b/multiversx_sdk_cli/tests/test_validators_file.py
index 23e9c5d3..0015a741 100644
--- a/multiversx_sdk_cli/tests/test_validators_file.py
+++ b/multiversx_sdk_cli/tests/test_validators_file.py
@@ -1,22 +1,20 @@
-import unittest
 from pathlib import Path
 
 from multiversx_sdk_cli.validators.validators_file import ValidatorsFile
 
 
-class ValidatorsFileTestCase(unittest.TestCase):
-    def setUp(self) -> None:
-        self.testdata = Path(__file__).parent.joinpath("testdata")
-        self.validators_file_path = self.testdata / "validators.json"
+class ValidatorsFileTestCase:
+    testdata = Path(__file__).parent.joinpath("testdata")
+    validators_file_path = testdata / "validators.json"
 
     def test_read_validators_files_num_of_nodes(self):
         validators_file = ValidatorsFile(self.validators_file_path)
 
         num_of_nodes = validators_file.get_num_of_nodes()
-        self.assertEqual(3, num_of_nodes)
+        assert num_of_nodes == 3
 
     def test_read_validators_files_get_validators_list(self):
         validators_file = ValidatorsFile(self.validators_file_path)
 
         validators_list = validators_file.get_validators_list()
-        self.assertEqual(3, len(validators_list))
+        assert len(validators_list) == 3
diff --git a/multiversx_sdk_cli/tests/utils.py b/multiversx_sdk_cli/tests/utils.py
deleted file mode 100644
index 5e8c6d0b..00000000
--- a/multiversx_sdk_cli/tests/utils.py
+++ /dev/null
@@ -1,40 +0,0 @@
-import unittest
-from pathlib import Path
-
-from multiversx_sdk_cli import projects, utils
-from multiversx_sdk_cli.accounts import Account
-from multiversx_sdk_cli.contracts import SmartContract
-from multiversx_sdk_cli.workstation import get_tools_folder
-
-
-class MyTestCase(unittest.TestCase):
-    def setUp(self):
-        self.testdata = Path(__file__).parent.joinpath("testdata")
-        self.testdata_out = Path(__file__).parent.joinpath("testdata-out")
-        self.devnet_wallets = get_tools_folder() / "testwallets" /"latest"
-
-        utils.ensure_folder(self.testdata_out)
-
-
-class ProjectTestCase(MyTestCase):
-    def setUp(self):
-        super().setUp()
-        self.testdata = Path(__file__).parent.joinpath("testdata")
-        self.alice = Account(
-            "aaaaaaaa112233441122334411223344112233441122334411223344aaaaaaaa")
-        self.bob = Account(
-            "bbbbbbbb112233441122334411223344112233441122334411223344bbbbbbbb")
-        self.carol = Account(
-            "cccccccc112233441122334411223344112233441122334411223344cccccccc")
-        self.david = Account(
-            "dddddddd112233441122334411223344112233441122334411223344dddddddd")
-
-    def build(self, name):
-        project = self.load_project(name)
-        project.build()
-        bytecode = project.get_bytecode()
-        contract = SmartContract(bytecode=bytecode)
-        return project, contract
-
-    def load_project(self, name):
-        return projects.load_project(self.testdata.joinpath(name))
diff --git a/pytest.ini b/pytest.ini
new file mode 100644
index 00000000..81836503
--- /dev/null
+++ b/pytest.ini
@@ -0,0 +1,3 @@
+[pytest]
+markers =
+    skip_on_windows: marks tests as being skiped when running on windows (deselect with '-m "skip_on_windows"')