Repository: skalenetwork/IMA (language: python)

Issue:
Add function and move to 0.8.16 solidity



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index daf38121a..1b431ed07 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -87,13 +87,62 @@ jobs:
       working-directory: ${{env.working-directory}}
       run: |
         npx hardhat coverage --solcoverjs .solcover.js
-        bash <(curl -s https://codecov.io/bash) -f coverage/lcov.info -t $CODECOV_TOKEN || echo "Codecov did not collect coverage reports"         
+        bash <(curl -s https://codecov.io/bash) -f coverage/lcov.info -t $CODECOV_TOKEN || echo "Codecov did not collect coverage reports"
+
+  test-predeployed:
+    runs-on: ubuntu-latest
+
+    env:
+      working-directory: ./proxy
+
+    steps:
+    - uses: actions/checkout@v2
+
+    - name: Get yarn cache directory path
+      id: yarn-cache-dir-path
+      run: echo "::set-output name=dir::$(yarn cache dir)"
+
+    - uses: actions/cache@v2
+      id: yarn-cache
+      with:
+        path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
+        key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+        restore-keys: |
+          ${{ runner.os }}-yarn-
+
+    - uses: actions/cache@v2
+      with:
+        path: ~/.cache/pip
+        key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
+        restore-keys: |
+          ${{ runner.os }}-pip-
+
+    - name: Install PYTHON
+      uses: actions/setup-python@v2
+      with:
+        python-version: 3.8
+
+    - name: Install NODE JS
+      uses: actions/setup-node@v2
+      with:
+        node-version: 16
+
+    - name: Install project
+      working-directory: ${{env.working-directory}}
+      run: |
+        ../npms/scrypt/get_scrypt_npm.sh
+        yarn install
+        npm run compile
+
+    - name: Install python testing staff
+      working-directory: ${{env.working-directory}}
+      run: pip3 install -r predeployed/test/requirements.txt
 
     - name: Install geth
       run: |
         sudo add-apt-repository -y ppa:ethereum/ethereum
         sudo apt install ethereum
-    
+
     - name: Build predeployed pip package
       working-directory: ${{env.working-directory}}
       env:
@@ -104,6 +153,8 @@ jobs:
 
     - name: Test predeployed pip package
       working-directory: ${{env.working-directory}}
+      env:
+        PYTHONPATH: src
       run: |
         killall -9 node || true # stop any ganache-cli, etc
         killall -9 geth || true # stop any geth, etc
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 1347cef38..775ef86e2 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -84,6 +84,10 @@ jobs:
       run: |
         npx hardhat run migrations/generateManifest.ts
 
+    - name: Install python testing staff
+      working-directory: ${{env.PROXY_DIR}}
+      run: pip3 install -r predeployed/test/requirements.txt
+
     - name: Build predeployed pip package
       working-directory: ${{env.PROXY_DIR}}
       env:
@@ -107,7 +111,7 @@ jobs:
         source scripts/venv/bin/activate
         pip install dist/ima_predeployed-*.whl
         mkdir data
-        scripts/generate_abi.py > data/ima-$VERSION-predeployed-abi.json
+        python scripts/generate_abi.py > data/ima-$VERSION-predeployed-abi.json
 
     - name: Create Release
       id: create_release
diff --git a/README.md b/README.md
index def732ee6..e4be46bb3 100644
--- a/README.md
+++ b/README.md
@@ -44,6 +44,10 @@ A module implementing core IMA functionality.
 
 Data validity verifier module. See [OWASP document](https://www.gitbook.com/download/pdf/book/checkmarx/JS-SCP).
 
+#### SKALE-OBSERVER
+
+[SKALE Network Browser](npms/skale-observer/README.md). Responsible for providing description of all SKALE chains.
+
 #### SKALE-LOG
 
 Console and log file output with rotation.
@@ -65,3 +69,4 @@ Learn more about the SKALE community over on [Discord](https://discord.gg/vvUtWJ
 [![License](https://img.shields.io/github/license/skalenetwork/IMA)](LICENSE)
 All contributions are made under the [GNU Affero General Public License v3](https://www.gnu.org/licenses/agpl-3.0.en.html). See [LICENSE](LICENSE).
 Copyright (C) 2019-Present SKALE Labs.
+[This is a link](src/Test.java)
\ No newline at end of file
diff --git a/VERSION b/VERSION
index 31e5c8434..d0149fef7 100644
--- a/VERSION
+++ b/VERSION
@@ -1,1 +1,1 @@
-1.3.3
+1.3.4
diff --git a/agent/bls.js b/agent/bls.js
index 433f4fcc8..95371c189 100644
--- a/agent/bls.js
+++ b/agent/bls.js
@@ -901,6 +901,17 @@ async function do_sign_messages_impl(
             cc.debug( ", " ) + cc.notice( "sequence ID" ) + cc.debug( " is " ) + cc.attention( sequence_id ) +
             "\n" );
         for( let i = 0; i < jarrNodes.length; ++i ) {
+            cntSuccess = joGatheringTracker.nCountReceived - joGatheringTracker.nCountErrors;
+            if( cntSuccess >= nCountOfBlsPartsToCollect ) {
+                details.write(
+                    strLogPrefix + log.generate_timestamp_string( null, true ) + " " +
+                    cc.debug( "Stop invoking " ) + cc.info( "skale_imaVerifyAndSign" ) +
+                    cc.debug( " for transfer from chain " ) + cc.info( fromChainName ) +
+                    cc.debug( " at #" ) + cc.info( i ) +
+                    cc.debug( " because successfully gathered count is reached " ) + cc.j( cntSuccess ) +
+                    "\n" );
+                break;
+            }
             const joNode = jarrNodes[i];
             const strNodeURL = imaUtils.compose_schain_node_url( joNode );
             const strNodeDescColorized = cc.u( strNodeURL ) + " " +
diff --git a/npms/skale-ima/index.js b/npms/skale-ima/index.js
index 6740ce23f..ba0f56434 100644
--- a/npms/skale-ima/index.js
+++ b/npms/skale-ima/index.js
@@ -5170,10 +5170,27 @@ async function do_transfer(
                     }
                 );
                 //details.write( strLogPrefix + cc.normal( "Logs search result(s): " ) + cc.j( r ) + "\n" );
+                const strChainHashWeAreLookingFor = w3_src.utils.soliditySha3( chain_id_dst );
                 let joValues = "";
+                details.write( strLogPrefix +
+                    cc.debug( "Will review " ) + cc.info( r.length ) +
+                    cc.debug( " found event records(in reverse order, newest to oldest)" ) +
+                    cc.debug( " while looking for hash " ) + cc.info( strChainHashWeAreLookingFor ) +
+                    cc.debug( " of destination chain " ) + cc.info( chain_id_dst ) +
+                    "\n" );
                 for( let i = r.length - 1; i >= 0; i-- ) {
-                    if( r[i].returnValues.dstChainHash == w3_src.utils.soliditySha3( chain_id_dst ) ) {
+                    details.write( strLogPrefix +
+                        cc.debug( "Will review found event record " ) + cc.info( i ) +
+                        cc.debug( " with data " ) + cc.j( r[i] ) +
+                        "\n" );
+                    if( r[i].returnValues.dstChainHash == strChainHashWeAreLookingFor ) {
                         joValues = r[i].returnValues;
+                        joValues.savedBlockNumberForOptimizations = r[i].blockNumber;
+                        details.write( strLogPrefix +
+                            cc.debug( "Found event record " ) + cc.info( i ) + cc.debug( " reviewed and " ) +
+                            cc.success( "accepted for processing, found event values are " ) + cc.j( joValues ) +
+                            cc.success( ", found block number is " ) + cc.info( joValues.savedBlockNumberForOptimizations ) +
+                            "\n" );
                         if( blockNumberNextForecast === 0 )
                             blockNumberNextForecast = w3mod.utils.toHex( r[i].blockNumber );
                         else {
@@ -5185,6 +5202,11 @@ async function do_transfer(
                             }
                         }
                         break;
+                    } else {
+                        details.write( strLogPrefix +
+                            cc.debug( "Found event record " ) + cc.info( i ) + cc.debug( " reviewed and " ) +
+                            cc.warning( "skipped" ) +
+                            "\n" );
                     }
                 }
                 details.write( strLogPrefix + cc.normal( "Next forecasted block number for logs search is " ) + cc.info( blockNumberNextForecast ) + "\n" );
@@ -5297,7 +5319,8 @@ async function do_transfer(
                     destinationContract: joValues.dstContract,
                     to: joValues.to,
                     amount: joValues.amount,
-                    data: joValues.data
+                    data: joValues.data,
+                    savedBlockNumberForOptimizations: joValues.savedBlockNumberForOptimizations
                 };
                 jarrMessages.push( joMessage );
 
@@ -5491,8 +5514,8 @@ async function do_transfer(
                                     10,
                                     jo_message_proxy_node,
                                     "OutgoingMessage",
-                                    0, // nBlockFrom
-                                    "latest", // nBlockTo
+                                    joMessage.savedBlockNumberForOptimizations, // 0, // nBlockFrom
+                                    joMessage.savedBlockNumberForOptimizations, // "latest", // nBlockTo
                                     {
                                         dstChainHash: [ w3_node.utils.soliditySha3( chain_id_dst ) ],
                                         msgCounter: [ idxImaMessage ]
diff --git a/npms/skale-observer/README.md b/npms/skale-observer/README.md
new file mode 100644
index 000000000..19c60cc3a
--- /dev/null
+++ b/npms/skale-observer/README.md
@@ -0,0 +1,179 @@
+# SKALE NETWORK BROWSER
+
+## General Description
+
+**SKALE Network Browser** (**SNB**) or **SKALE Observer** is part of IMA resposible for providing description of all SKALE chains. This is done via set of calls to **SKALE Mananger**.
+
+**SNB** maintains cache of S-Chain descriptions and refreshes all descriptions periodically. These descriptions and needed for S-Chain to S-Chain IMA message transfers when IMA needs to know how to connect to other S-Chain.
+
+First SKALE network scan is performed by **SNB** on IMA startup. Next network description refreshes are performed periodically.
+
+**SNB** works can work in parallel thread to avoid any delay of main IMA's message transfer loop.
+
+## Implementation details
+
+The `SchainsInternal.numberOfSchains` contract call returns number of created S-Chains to load from **SKALE Mananger**. For each of S-Chains we need to get its hash by index what is done `SchainsInternal.schainsAtSystem` contract call. Then contract call to `SchainsInternal.schains` returns basic S-Chain description by hash. Obtained basic S-Chain description does not describe nodes and they must be loaded via set of contract calls. The `SchainsInternal.getNodesInGroup` contract call returns array of node identifiers for all S-Chain nodes. The `Nodes.nodes` contract call returns node description by node id. Returned node description includes IP adderess, domain name and, base port of a node, maintanance state flag. Then call to `SchainsInternal.getSchainIdsForNode` contract call allows to find effective node base port and compute per-protocol ports (`http`, `https`, `ws`, `wss`).
+
+Cache of S-Chain descriptions is result of download process described above. When new S-Chain descriptions are downloaded, they replace old ones. By default this is performed once in an hour.
+
+S-Chain descriptions directly affect on S-Chain to S-Chain transfers because they contain JSON RPC URLs of all `skaled`s of all S-Chains.
+
+**SNB** can be invoked from command line of IMA agent in one of the following ways
+   - The`--browse-skale-network` command line options invokes download entire SKALE network description, all S-Chains, all `skaled` nodes.
+   - The `--browse-connected-schains` command line options invokes download of which are S-Chains conected to S-Chain with name specified in `--id-s-chain` command line parameter.
+
+Example of **SNB** invocation:
+
+```shell
+node agent/main.js --colors --browse-skale-network \
+    --abi-skale-manager=.../sm.json \
+    --abi-main-net=.../mn.json \
+    --abi-s-chain=.../sc.json \
+    --url-main-net=http://127.0.0.1:8545 \
+    --url-s-chain=http://127.0.0.1:15000 \
+    --id-main-net=Mainnet \
+    --id-s-chain=Bob1000 \
+    --cid-main-net=456 \
+    --cid-s-chain=1000 \
+    --key-main-net=... \
+    --key-s-chain=...
+```
+
+Example of downloaded S-Chains description containg 2 S-Chains named `Bob1000` and `Bob1001`, 2 `skaled` nodes each:
+
+```json
+[
+   {
+      "data":{
+         "name":"Bob1000",
+         "owner":"0x7aa5E36AA15E93D10F4F26357C30F052DacDde5F",
+         "indexInOwnerList":"0",
+         "partOfNode":"0",
+         "lifetime":"5",
+         "startDate":"1641992759",
+         "startBlock":"249",
+         "deposit":"100000000000000000000",
+         "index":"0",
+         "generation":"0",
+         "originator":"0x0000000000000000000000000000000000000000",
+         "computed":{
+            "ports":{
+               "httpRpcPort":2264,
+               "httpsRpcPort":2269,
+               "wsRpcPort":2263,
+               "wssRpcPort":2268,
+               "infoHttpRpcPort":2270
+            },
+            "schain_id":"0x975a4814cff8b9fd85b48879dade195028650b0a23f339ca81bd3b1231f72974",
+            "chainId":"0x975a4814cff8b9",
+            "nodes":[
+               {
+                  "id":"0",
+                  "name":"Aldo",
+                  "ip":"127.0.0.1",
+                  "base_port":"2161",
+                  "domain":"test.domain.name.here",
+                  "isMaintenance":false,
+                  "schain_base_port":2161,
+                  "http_endpoint_ip":"http://127.0.0.1:2164",
+                  "https_endpoint_ip":"https://127.0.0.1:2169",
+                  "ws_endpoint_ip":"ws://127.0.0.1:2163",
+                  "wss_endpoint_ip":"wss://127.0.0.1:2168",
+                  "info_http_endpoint_ip":"http://127.0.0.1:2170",
+                  "http_endpoint_domain":"http://test.domain.name.here:2164",
+                  "https_endpoint_domain":"https://test.domain.name.here:2169",
+                  "ws_endpoint_domain":"ws://test.domain.name.here:2163",
+                  "wss_endpoint_domain":"wss://test.domain.name.here:2168",
+                  "info_http_endpoint_domain":"http://test.domain.name.here:2170"
+               },
+               {
+                  "id":"1",
+                  "name":"Bear",
+                  "ip":"127.0.0.2",
+                  "base_port":"2261",
+                  "domain":"test.domain.name.here",
+                  "isMaintenance":false,
+                  "schain_base_port":2261,
+                  "http_endpoint_ip":"http://127.0.0.2:2264",
+                  "https_endpoint_ip":"https://127.0.0.2:2269",
+                  "ws_endpoint_ip":"ws://127.0.0.2:2263",
+                  "wss_endpoint_ip":"wss://127.0.0.2:2268",
+                  "info_http_endpoint_ip":"http://127.0.0.2:2270",
+                  "http_endpoint_domain":"http://test.domain.name.here:2264",
+                  "https_endpoint_domain":"https://test.domain.name.here:2269",
+                  "ws_endpoint_domain":"ws://test.domain.name.here:2263",
+                  "wss_endpoint_domain":"wss://test.domain.name.here:2268",
+                  "info_http_endpoint_domain":"http://test.domain.name.here:2270"
+               }
+            ]
+         }
+      }
+   },
+   {
+      "data":{
+         "name":"Bob1001",
+         "owner":"0x7aa5E36AA15E93D10F4F26357C30F052DacDde5F",
+         "indexInOwnerList":"1",
+         "partOfNode":"0",
+         "lifetime":"5",
+         "startDate":"1641992767",
+         "startBlock":"260",
+         "deposit":"100000000000000000000",
+         "index":"1",
+         "generation":"0",
+         "originator":"0x0000000000000000000000000000000000000000",
+         "computed":{
+            "ports":{
+               "httpRpcPort":2364,
+               "httpsRpcPort":2369,
+               "wsRpcPort":2363,
+               "wssRpcPort":2368,
+               "infoHttpRpcPort":2370
+            },
+            "schain_id":"0xde9b5e1c7bac0a60f917397dfab6ead3f6441acf0399ec81145568874dd829e9",
+            "chainId":"0xde9b5e1c7bac0a",
+            "nodes":[
+               {
+                  "id":"3",
+                  "name":"Seed",
+                  "ip":"127.0.0.4",
+                  "base_port":"2461",
+                  "domain":"test.domain.name.here",
+                  "isMaintenance":false,
+                  "schain_base_port":2461,
+                  "http_endpoint_ip":"http://127.0.0.4:2464",
+                  "https_endpoint_ip":"https://127.0.0.4:2469",
+                  "ws_endpoint_ip":"ws://127.0.0.4:2463",
+                  "wss_endpoint_ip":"wss://127.0.0.4:2468",
+                  "info_http_endpoint_ip":"http://127.0.0.4:2470",
+                  "http_endpoint_domain":"http://test.domain.name.here:2464",
+                  "https_endpoint_domain":"https://test.domain.name.here:2469",
+                  "ws_endpoint_domain":"ws://test.domain.name.here:2463",
+                  "wss_endpoint_domain":"wss://test.domain.name.here:2468",
+                  "info_http_endpoint_domain":"http://test.domain.name.here:2470"
+               },
+               {
+                  "id":"2",
+                  "name":"John",
+                  "ip":"127.0.0.3",
+                  "base_port":"2361",
+                  "domain":"test.domain.name.here",
+                  "isMaintenance":false,
+                  "schain_base_port":2361,
+                  "http_endpoint_ip":"http://127.0.0.3:2364",
+                  "https_endpoint_ip":"https://127.0.0.3:2369",
+                  "ws_endpoint_ip":"ws://127.0.0.3:2363",
+                  "wss_endpoint_ip":"wss://127.0.0.3:2368",
+                  "info_http_endpoint_ip":"http://127.0.0.3:2370",
+                  "http_endpoint_domain":"http://test.domain.name.here:2364",
+                  "https_endpoint_domain":"https://test.domain.name.here:2369",
+                  "ws_endpoint_domain":"ws://test.domain.name.here:2363",
+                  "wss_endpoint_domain":"wss://test.domain.name.here:2368",
+                  "info_http_endpoint_domain":"http://test.domain.name.here:2370"
+               }
+            ]
+         }
+      }
+   }
+]
+```
diff --git a/npms/skale-observer/observer.js b/npms/skale-observer/observer.js
index cfed1d786..d22107216 100644
--- a/npms/skale-observer/observer.js
+++ b/npms/skale-observer/observer.js
@@ -104,7 +104,7 @@ async function load_schain_parts( w3, jo_schain, addressFrom, opts ) {
         };
         if( opts && opts.bStopNeeded )
             return;
-        const schain_ids = await opts.imaState.jo_schains_internal.methods.getSchainIdsForNode( node_id ).call( { from: addressFrom } );
+        const schain_ids = await opts.imaState.jo_schains_internal.methods.getSchainHashesForNode( node_id ).call( { from: addressFrom } );
         node_dict.schain_base_port = get_schain_base_port_on_node( schain_id, schain_ids, node_dict.base_port );
         calc_ports( jo_schain, node_dict.schain_base_port );
         compose_endpoints( jo_schain, node_dict, "ip" );
diff --git a/proxy/.openzeppelin/mainnet.json b/proxy/.openzeppelin/mainnet.json
index ea0fda846..964bddbc9 100644
--- a/proxy/.openzeppelin/mainnet.json
+++ b/proxy/.openzeppelin/mainnet.json
@@ -115,7 +115,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:23"
           },
           {
@@ -312,7 +312,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:23"
           },
           {
@@ -498,7 +498,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:23"
           },
           {
@@ -678,7 +678,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:23"
           },
           {
@@ -864,7 +864,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:23"
           },
           {
@@ -1056,7 +1056,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:23"
           },
           {
@@ -1248,7 +1248,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:23"
           },
           {
@@ -1449,7 +1449,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -1646,7 +1646,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -1832,7 +1832,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -2012,7 +2012,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -2198,7 +2198,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -2390,7 +2390,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -2582,7 +2582,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -2783,7 +2783,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -2980,7 +2980,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -3160,7 +3160,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -3346,7 +3346,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -3538,7 +3538,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -3730,7 +3730,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -3931,7 +3931,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -4128,7 +4128,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -4326,7 +4326,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -4544,7 +4544,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -4730,7 +4730,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -4910,7 +4910,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -5102,7 +5102,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -5300,7 +5300,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -5498,7 +5498,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -5705,7 +5705,7 @@
           {
             "contract": "Initializable",
             "label": "_initialized",
-            "type": "t_bool",
+            "type": "t_uint8",
             "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21"
           },
           {
@@ -7275,4 +7275,4 @@
       }
     }
   }
-}
+}
\ No newline at end of file
diff --git a/proxy/.solhint.json b/proxy/.solhint.json
index 3ebf80d25..c6247f7a6 100644
--- a/proxy/.solhint.json
+++ b/proxy/.solhint.json
@@ -5,7 +5,7 @@
     "mark-callable-contracts": "off",
     "reason-string": "off",
 
-    "compiler-version": ["error","0.8.6"],
+    "compiler-version": ["error","0.8.16"],
     "state-visibility": "error",
     "no-empty-blocks": "error",
     "check-send-result": "error",
diff --git a/proxy/contracts/MessageProxy.sol b/proxy/contracts/MessageProxy.sol
index 6efde8494..36c8ba12a 100644
--- a/proxy/contracts/MessageProxy.sol
+++ b/proxy/contracts/MessageProxy.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
 import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
diff --git a/proxy/contracts/Messages.sol b/proxy/contracts/Messages.sol
index ca685ec73..7429e0709 100644
--- a/proxy/contracts/Messages.sol
+++ b/proxy/contracts/Messages.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 
 /**
diff --git a/proxy/contracts/extensions/ERC721ReferenceMintAndMetadataMainnet.sol b/proxy/contracts/extensions/ERC721ReferenceMintAndMetadataMainnet.sol
index b3d3a25e7..5eff9134e 100644
--- a/proxy/contracts/extensions/ERC721ReferenceMintAndMetadataMainnet.sol
+++ b/proxy/contracts/extensions/ERC721ReferenceMintAndMetadataMainnet.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@skalenetwork/ima-interfaces/extensions/IERC721ReferenceMintAndMetadataMainnet.sol";
 
diff --git a/proxy/contracts/extensions/ERC721ReferenceMintAndMetadataSchain.sol b/proxy/contracts/extensions/ERC721ReferenceMintAndMetadataSchain.sol
index ae1fd91b3..6a085ce28 100644
--- a/proxy/contracts/extensions/ERC721ReferenceMintAndMetadataSchain.sol
+++ b/proxy/contracts/extensions/ERC721ReferenceMintAndMetadataSchain.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@skalenetwork/ima-interfaces/extensions/IERC721ReferenceMintAndMetadataSchain.sol";
 
diff --git a/proxy/contracts/extensions/interfaces/MessageProxyClient.sol b/proxy/contracts/extensions/interfaces/MessageProxyClient.sol
index ba8ebd894..e805248d2 100644
--- a/proxy/contracts/extensions/interfaces/MessageProxyClient.sol
+++ b/proxy/contracts/extensions/interfaces/MessageProxyClient.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "../../MessageProxy.sol";
 
diff --git a/proxy/contracts/extensions/interfaces/MessageReceiver.sol b/proxy/contracts/extensions/interfaces/MessageReceiver.sol
index 86d3dee18..48c5c3474 100644
--- a/proxy/contracts/extensions/interfaces/MessageReceiver.sol
+++ b/proxy/contracts/extensions/interfaces/MessageReceiver.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@skalenetwork/ima-interfaces/IMessageReceiver.sol";
 
diff --git a/proxy/contracts/extensions/interfaces/MessageSender.sol b/proxy/contracts/extensions/interfaces/MessageSender.sol
index 5a5139047..9605e4f3e 100644
--- a/proxy/contracts/extensions/interfaces/MessageSender.sol
+++ b/proxy/contracts/extensions/interfaces/MessageSender.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "./MessageProxyClient.sol";
 
diff --git a/proxy/contracts/mainnet/CommunityPool.sol b/proxy/contracts/mainnet/CommunityPool.sol
index 153337635..1dd726872 100644
--- a/proxy/contracts/mainnet/CommunityPool.sol
+++ b/proxy/contracts/mainnet/CommunityPool.sol
@@ -21,7 +21,7 @@
     along with SKALE Manager.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@skalenetwork/ima-interfaces/mainnet/ICommunityPool.sol";
 import "@skalenetwork/skale-manager-interfaces/IWallets.sol";
@@ -46,7 +46,10 @@ contract CommunityPool is Twin, ICommunityPool {
     // address of user => schainHash => true if unlocked for transferring
     mapping(address => mapping(bytes32 => bool)) public activeUsers;
 
-    uint public minTransactionGas;    
+    uint public minTransactionGas;
+
+    uint public multiplierNumerator;
+    uint public multiplierDivider;
 
     /**
      * @dev Emitted when minimal value in gas for transactions from schain to mainnet was changed 
@@ -56,6 +59,16 @@ contract CommunityPool is Twin, ICommunityPool {
         uint newValue
     );
 
+    /**
+     * @dev Emitted when basefee multiplier was changed 
+     */
+    event MultiplierWasChanged(
+        uint oldMultiplierNumerator,
+        uint oldMultiplierDivider,
+        uint newMultiplierNumerator,
+        uint newMultiplierDivider
+    );
+
     function initialize(
         IContractManager contractManagerOfSkaleManagerValue,
         ILinker linker,
@@ -68,6 +81,8 @@ contract CommunityPool is Twin, ICommunityPool {
         Twin.initialize(contractManagerOfSkaleManagerValue, messageProxyValue);
         _setupRole(LINKER_ROLE, address(linker));
         minTransactionGas = 1e6;
+        multiplierNumerator = 3;
+        multiplierDivider = 2;
     }
 
     /**
@@ -122,6 +137,7 @@ contract CommunityPool is Twin, ICommunityPool {
         returns (bool)
     {
         if (gas > 0) {
+
             IWallets(payable(contractManagerOfSkaleManager.getContract("Wallets"))).refundGasBySchain(
                 schainHash,
                 node,
@@ -199,6 +215,27 @@ contract CommunityPool is Twin, ICommunityPool {
         minTransactionGas = newMinTransactionGas;
     }
 
+    /**
+     * @dev Allows `msg.sender` set the amount of gas that should be 
+     * enough for reimbursing any transaction from schain to mainnet.
+     * 
+     * Requirements:
+     * 
+     * - 'msg.sender` must have sufficient amount of ETH on their gas wallet.
+     */
+    function setMultiplier(uint newMultiplierNumerator, uint newMultiplierDivider) external override {
+        require(hasRole(CONSTANT_SETTER_ROLE, msg.sender), "CONSTANT_SETTER_ROLE is required");
+        require(newMultiplierDivider > 0, "Divider is zero");
+        emit MultiplierWasChanged(
+            multiplierNumerator,
+            multiplierDivider,
+            newMultiplierNumerator,
+            newMultiplierDivider
+        );
+        multiplierNumerator = newMultiplierNumerator;
+        multiplierDivider = newMultiplierDivider;
+    }
+
     /**
      * @dev Returns the amount of ETH on gas wallet for particular user.
      */
@@ -212,10 +249,34 @@ contract CommunityPool is Twin, ICommunityPool {
     function checkUserBalance(bytes32 schainHash, address receiver) external view override returns (bool) {
         return activeUsers[receiver][schainHash] && _balanceIsSufficient(schainHash, receiver, 0);
     }
+
+    /**
+     * @dev Checks whether passed amount is enough to recharge user wallet with current basefee.
+     */
+    function getRecommendedRechargeAmount(
+        bytes32 schainHash,
+        address receiver
+    )
+        external
+        view
+        override
+        returns (uint256)
+    {
+        uint256 currentValue = _multiplyOnAdaptedBaseFee(minTransactionGas);
+        if (currentValue  <= _userWallets[receiver][schainHash]) {
+            return 0;
+        }
+        return currentValue - _userWallets[receiver][schainHash];
+    }
+
     /**
      * @dev Checks whether user wallet was recharged for sufficient amount.
      */
     function _balanceIsSufficient(bytes32 schainHash, address receiver, uint256 delta) private view returns (bool) {
         return delta + _userWallets[receiver][schainHash] >= minTransactionGas * tx.gasprice;
-    } 
+    }
+
+    function _multiplyOnAdaptedBaseFee(uint256 value) private view returns (uint256) {
+        return value * block.basefee * multiplierNumerator / multiplierDivider;
+    }
 }
diff --git a/proxy/contracts/mainnet/DepositBox.sol b/proxy/contracts/mainnet/DepositBox.sol
index 840d165a4..35e091973 100644
--- a/proxy/contracts/mainnet/DepositBox.sol
+++ b/proxy/contracts/mainnet/DepositBox.sol
@@ -20,7 +20,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@skalenetwork/ima-interfaces/mainnet/IDepositBox.sol";
 
diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol
index 8de91f055..2b5a2f49d 100644
--- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol
+++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
 import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
@@ -44,6 +44,8 @@ contract DepositBoxERC1155 is DepositBox, ERC1155ReceiverUpgradeable, IDepositBo
 
 
     // schainHash => address of ERC on Mainnet
+    // Deprecated
+    // slither-disable-next-line unused-state
     mapping(bytes32 => mapping(address => bool)) private _deprecatedSchainToERC1155;
     mapping(bytes32 => mapping(address => mapping(uint256 => uint256))) public transferredAmount;
     mapping(bytes32 => EnumerableSetUpgradeable.AddressSet) private _schainToERC1155;
@@ -59,34 +61,6 @@ contract DepositBoxERC1155 is DepositBox, ERC1155ReceiverUpgradeable, IDepositBo
      */
     event ERC1155TokenReady(address indexed contractOnMainnet, uint256[] ids, uint256[] amounts);
 
-    /**
-     * @dev Allows DEFAULT_ADMIN_ROLE to initialize token mapping
-     * Notice - this function will be executed only once during upgrade
-     * 
-     * Requirements:
-     * 
-     * `msg.sender` should has DEFAULT_ADMIN_ROLE
-     */
-    function initializeAllTokensForSchain(
-        string calldata schainName,
-        address[] calldata tokens
-    )
-        external
-        override
-    {
-        require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Sender is not authorized");
-        bytes32 schainHash = keccak256(abi.encodePacked(schainName));
-        for (uint256 i = 0; i < tokens.length; i++) {
-            if (
-                _deprecatedSchainToERC1155[schainHash][tokens[i]] &&
-                !_schainToERC1155[schainHash].contains(tokens[i])
-            ) {
-                _schainToERC1155[schainHash].add(tokens[i]);
-                delete _deprecatedSchainToERC1155[schainHash][tokens[i]];
-            }
-        }
-    }
-
     /**
      * @dev Allows `msg.sender` to send ERC1155 token from mainnet to schain.
      * 
diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol
index 4d9e5d7b3..4d4c7cbf3 100644
--- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol
+++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol
@@ -19,9 +19,11 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/utils/structs/DoubleEndedQueueUpgradeable.sol";
 import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
 import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
 import "@skalenetwork/ima-interfaces/mainnet/DepositBoxes/IDepositBoxERC20.sol";
@@ -43,15 +45,54 @@ interface IERC20TransferVoid {
  */
 contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 {
     using AddressUpgradeable for address;
+    using DoubleEndedQueueUpgradeable for DoubleEndedQueueUpgradeable.Bytes32Deque;
     using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
 
+    enum DelayedTransferStatus {
+        DELAYED,
+        ARBITRAGE,
+        COMPLETED
+    }
+
+    struct DelayedTransfer {
+        address receiver;
+        bytes32 schainHash;
+        address token;
+        uint256 amount;
+        uint256 untilTimestamp;
+        DelayedTransferStatus status;
+    }
+
+    struct DelayConfig {
+        // token address => value
+        mapping(address => uint256) bigTransferThreshold;
+        EnumerableSetUpgradeable.AddressSet trustedReceivers;
+        uint256 transferDelay;
+        uint256 arbitrageDuration;    
+    }
+
     address private constant _USDT_ADDRESS = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
+    uint256 private constant _QUEUE_PROCESSING_LIMIT = 10;
+
+    bytes32 public constant ARBITER_ROLE = keccak256("ARBITER_ROLE");
 
     // schainHash => address of ERC20 on Mainnet
+    // Deprecated
+    // slither-disable-next-line unused-state
     mapping(bytes32 => mapping(address => bool)) private _deprecatedSchainToERC20;
     mapping(bytes32 => mapping(address => uint256)) public transferredAmount;
     mapping(bytes32 => EnumerableSetUpgradeable.AddressSet) private _schainToERC20;
 
+    // exits delay configuration
+    //   schainHash => delay config
+    mapping(bytes32 => DelayConfig) private _delayConfig;    
+
+    uint256 public delayedTransfersSize;
+    // delayed transfer id => delayed transfer
+    mapping(uint256 => DelayedTransfer) public delayedTransfers;
+    // receiver address => delayed transfers ids queue
+    mapping(address => DoubleEndedQueueUpgradeable.Bytes32Deque) public delayedTransfersByReceiver;    
+
     /**
      * @dev Emitted when token is mapped in DepositBoxERC20.
      */
@@ -63,31 +104,6 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 {
      */
     event ERC20TokenReady(address indexed contractOnMainnet, uint256 amount);
 
-    /**
-     * @dev Allows DEFAULT_ADMIN_ROLE to initialize token mapping
-     * Notice - this function will be executed only once during upgrade
-     * 
-     * Requirements:
-     * 
-     * `msg.sender` should has DEFAULT_ADMIN_ROLE
-     */
-    function initializeAllTokensForSchain(
-        string calldata schainName,
-        address[] calldata tokens
-    )
-        external
-        override
-    {
-        require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Sender is not authorized");
-        bytes32 schainHash = keccak256(abi.encodePacked(schainName));
-        for (uint256 i = 0; i < tokens.length; i++) {
-            if (_deprecatedSchainToERC20[schainHash][tokens[i]] && !_schainToERC20[schainHash].contains(tokens[i])) {
-                _schainToERC20[schainHash].add(tokens[i]);
-                delete _deprecatedSchainToERC20[schainHash][tokens[i]];
-            }
-        }
-    }
-
     /**
      * @dev Allows `msg.sender` to send ERC20 token from mainnet to schain
      * 
@@ -107,9 +123,9 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 {
         external
         override
         rightTransaction(schainName, msg.sender)
-        whenNotKilled(keccak256(abi.encodePacked(schainName)))
+        whenNotKilled(_schainHash(schainName))
     {
-        bytes32 schainHash = keccak256(abi.encodePacked(schainName));
+        bytes32 schainHash = _schainHash(schainName);
         address contractReceiver = schainLinks[schainHash];
         require(contractReceiver != address(0), "Unconnected chain");
         require(
@@ -169,16 +185,16 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 {
         require(message.token.isContract(), "Given address is not a contract");
         require(ERC20Upgradeable(message.token).balanceOf(address(this)) >= message.amount, "Not enough money");
         _removeTransferredAmount(schainHash, message.token, message.amount);
-        if (message.token == _USDT_ADDRESS) {
-            // solhint-disable-next-line no-empty-blocks
-            try IERC20TransferVoid(message.token).transfer(message.receiver, message.amount) {} catch {
-                revert("Transfer was failed");
-            }
+
+        uint256 delay = _delayConfig[schainHash].transferDelay;
+        if (
+            delay > 0
+            && _delayConfig[schainHash].bigTransferThreshold[message.token] <= message.amount
+            && !isReceiverTrusted(schainHash, message.receiver)
+        ) {
+            _createDelayedTransfer(schainHash, message, delay);
         } else {
-            require(
-                ERC20Upgradeable(message.token).transfer(message.receiver, message.amount),
-                "Transfer was failed"
-            );
+            _transfer(message.token, message.receiver, message.amount);
         }
     }
 
@@ -196,7 +212,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 {
         external
         override
         onlySchainOwner(schainName)
-        whenNotKilled(keccak256(abi.encodePacked(schainName)))
+        whenNotKilled(_schainHash(schainName))
     {
         _addERC20ForSchain(schainName, erc20OnMainnet);
     }
@@ -216,9 +232,9 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 {
         external
         override
         onlySchainOwner(schainName)
-        whenKilled(keccak256(abi.encodePacked(schainName)))
+        whenKilled(_schainHash(schainName))
     {
-        bytes32 schainHash = keccak256(abi.encodePacked(schainName));
+        bytes32 schainHash = _schainHash(schainName);
         require(transferredAmount[schainHash][erc20OnMainnet] >= amount, "Incorrect amount");
         _removeTransferredAmount(schainHash, erc20OnMainnet, amount);
         require(
@@ -227,6 +243,189 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 {
         );
     }
 
+    /**
+     * @dev Set a threshold amount of tokens.
+     * If amount of tokens that exits IMA is bigger than the threshold
+     * the transfer is delayed for configurable amount of time
+     * and can be canceled by a voting
+     *
+     * Requirements:
+     * 
+     * - msg.sender should be an owner of schain
+     */
+    function setBigTransferValue(
+        string calldata schainName,
+        address token,
+        uint256 value
+    )
+        external
+        override
+        onlySchainOwner(schainName)
+    {
+        bytes32 schainHash = _schainHash(schainName);
+        _delayConfig[schainHash].bigTransferThreshold[token] = value;   
+    }
+
+    /**
+     * @dev Set a time delay.
+     * If amount of tokens that exits IMA is bigger than a threshold
+     * the transfer is delayed for set amount of time
+     * and can be canceled by a voting
+     *
+     * Requirements:
+     * 
+     * - msg.sender should be an owner of schain
+     */
+    function setBigTransferDelay(
+        string calldata schainName,
+        uint256 delayInSeconds
+    )
+        external
+        override
+        onlySchainOwner(schainName)
+    {
+        bytes32 schainHash = _schainHash(schainName);
+        // need to restrict big delays to avoid overflow
+        require(delayInSeconds < 1e8, "Delay is too big"); // no more then ~ 3 years
+        _delayConfig[schainHash].transferDelay = delayInSeconds;   
+    }
+
+    /**
+     * @dev Set an arbitrage.
+     * After escalation the transfer is locked for provided period of time.
+     *
+     * Requirements:
+     * 
+     * - msg.sender should be an owner of schain
+     */
+    function setArbitrageDuration(
+        string calldata schainName,
+        uint256 delayInSeconds
+    )
+        external
+        override
+        onlySchainOwner(schainName)
+    {
+        bytes32 schainHash = _schainHash(schainName);
+        // need to restrict big delays to avoid overflow
+        require(delayInSeconds < 1e8, "Delay is too big"); // no more then ~ 3 years
+        _delayConfig[schainHash].arbitrageDuration = delayInSeconds;   
+    }
+
+    /**
+     * @dev Add the address to a whitelist of addresses that can do big transfers without delaying
+     * Requirements:
+     * 
+     * - msg.sender should be an owner of schain
+     * - the address must not be in the whitelist
+     */
+    function trustReceiver(
+        string calldata schainName,
+        address receiver
+    )
+        external
+        override
+        onlySchainOwner(schainName)
+    {
+        require(
+            _delayConfig[_schainHash(schainName)].trustedReceivers.add(receiver),
+            "Receiver already is trusted"
+        );        
+    }
+
+    /**
+     * @dev Remove the address from a whitelist of addresses that can do big transfers without delaying
+     * Requirements:
+     * 
+     * - msg.sender should be an owner of schain
+     * - the address must be in the whitelist
+     */
+    function stopTrustingReceiver(
+        string calldata schainName,
+        address receiver
+    )
+        external
+        override
+        onlySchainOwner(schainName)
+    {
+        require(_delayConfig[_schainHash(schainName)].trustedReceivers.remove(receiver), "Receiver is not trusted");
+    }
+
+    /**
+     * @dev Transfers tokens that was locked for delay during exit process.
+     * Must be called by a receiver.
+     */
+    function retrieve() external override {
+        retrieveFor(msg.sender);
+    }
+
+    /**
+     * @dev Initialize arbitrage of a suspicious big transfer
+     *
+     * Requirements:
+     * 
+     * - msg.sender should be an owner of schain or have ARBITER_ROLE role
+     * - transfer must be delayed and arbitrage must not be started
+     */
+    function escalate(uint256 transferId) external override {
+        bytes32 schainHash = delayedTransfers[transferId].schainHash;
+        require(
+            hasRole(ARBITER_ROLE, msg.sender) || isSchainOwner(msg.sender, schainHash),
+            "Not enough permissions to request escalation"
+        );
+        require(delayedTransfers[transferId].status == DelayedTransferStatus.DELAYED, "The transfer has to be delayed");
+        delayedTransfers[transferId].status = DelayedTransferStatus.ARBITRAGE;
+        delayedTransfers[transferId].untilTimestamp = MathUpgradeable.max(
+            delayedTransfers[transferId].untilTimestamp,
+            block.timestamp + _delayConfig[schainHash].arbitrageDuration
+        );
+    }
+
+    /**
+     * @dev Approve a big transfer and immidiately transfer tokens during arbitrage
+     *
+     * Requirements:
+     * 
+     * - msg.sender should be an owner of schain
+     * - arbitrage of the transfer must be started
+     */
+    function validateTransfer(
+        uint transferId
+    )
+        external
+        override
+        onlySchainOwnerByHash(delayedTransfers[transferId].schainHash)
+    {
+        DelayedTransfer storage transfer = delayedTransfers[transferId];
+        require(transfer.status == DelayedTransferStatus.ARBITRAGE, "Arbitrage has to be active");
+        transfer.status = DelayedTransferStatus.COMPLETED;
+        delete transfer.untilTimestamp;
+        _transfer(transfer.token, transfer.receiver, transfer.amount);
+    }
+
+    /**
+     * @dev Reject a big transfer and transfer tokens to SKALE chain owner during arbitrage
+     *
+     * Requirements:
+     * 
+     * - msg.sender should be an owner of schain
+     * - arbitrage of the transfer must be started
+     */
+    function rejectTransfer(
+        uint transferId
+    )
+        external
+        override
+        onlySchainOwnerByHash(delayedTransfers[transferId].schainHash)
+    {
+        DelayedTransfer storage transfer = delayedTransfers[transferId];
+        require(transfer.status == DelayedTransferStatus.ARBITRAGE, "Arbitrage has to be active");
+        transfer.status = DelayedTransferStatus.COMPLETED;
+        delete transfer.untilTimestamp;
+        // msg.sender is schain owner
+        _transfer(transfer.token, msg.sender, transfer.amount);
+    }
+
     /**
      * @dev Returns receiver of message.
      *
@@ -262,7 +461,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 {
         override
         returns (bool)
     {
-        return _schainToERC20[keccak256(abi.encodePacked(schainName))].contains(erc20OnMainnet);
+        return _schainToERC20[_schainHash(schainName)].contains(erc20OnMainnet);
     }
 
     /**
@@ -270,7 +469,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 {
      * or added automatically after sending to schain if whitelist was turned off.
      */
     function getSchainToAllERC20Length(string calldata schainName) external view override returns (uint256) {
-        return _schainToERC20[keccak256(abi.encodePacked(schainName))].length();
+        return _schainToERC20[_schainHash(schainName)].length();
     }
 
     /**
@@ -288,15 +487,143 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 {
         returns (address[] memory tokensInRange)
     {
         require(
-            from < to && to - from <= 10 && to <= _schainToERC20[keccak256(abi.encodePacked(schainName))].length(),
+            from < to && to - from <= 10 && to <= _schainToERC20[_schainHash(schainName)].length(),
             "Range is incorrect"
         );
         tokensInRange = new address[](to - from);
         for (uint256 i = from; i < to; i++) {
-            tokensInRange[i - from] = _schainToERC20[keccak256(abi.encodePacked(schainName))].at(i);
+            tokensInRange[i - from] = _schainToERC20[_schainHash(schainName)].at(i);
+        }
+    }
+
+    /**
+     * @dev Get amount of tokens that are delayed for specified receiver
+     */
+    function getDelayedAmount(address receiver, address token) external view override returns (uint256 value) {
+        uint256 delayedTransfersAmount = delayedTransfersByReceiver[receiver].length();
+        for (uint256 i = 0; i < delayedTransfersAmount; ++i) {
+            DelayedTransfer storage transfer = delayedTransfers[uint256(delayedTransfersByReceiver[receiver].at(i))];
+            DelayedTransferStatus status = transfer.status;
+            if (transfer.token == token) {
+                if (status == DelayedTransferStatus.DELAYED || status == DelayedTransferStatus.ARBITRAGE) {
+                    value += transfer.amount;
+                }
+            }
+        }
+    }
+
+    /**
+     * @dev Get timestamp of next unlock of tokens that are delayed for specified receiver
+     */
+    function getNextUnlockTimestamp(
+        address receiver,
+        address token
+    )
+        external
+        view
+        override
+        returns (uint256 unlockTimestamp)
+    {
+        uint256 delayedTransfersAmount = delayedTransfersByReceiver[receiver].length();
+        unlockTimestamp = type(uint256).max;
+        for (uint256 i = 0; i < delayedTransfersAmount; ++i) {
+            DelayedTransfer storage transfer = delayedTransfers[uint256(delayedTransfersByReceiver[receiver].at(i))];
+            DelayedTransferStatus status = transfer.status;
+            if (transfer.token == token) {
+                if (status != DelayedTransferStatus.COMPLETED) {
+                    unlockTimestamp = MathUpgradeable.min(unlockTimestamp, transfer.untilTimestamp);
+                }
+                if (status == DelayedTransferStatus.DELAYED) {
+                    break;
+                }
+            }
         }
     }
 
+    /**
+     * @dev Get amount of addresses that are added to the whitelist
+     */
+    function getTrustedReceiversAmount(bytes32 schainHash) external view override returns (uint256) {
+        return _delayConfig[schainHash].trustedReceivers.length();
+    }
+
+    /**
+     * @dev Get i-th address of the whitelist
+     */
+    function getTrustedReceiver(string calldata schainName, uint256 index) external view override returns (address) {
+        return _delayConfig[_schainHash(schainName)].trustedReceivers.at(index);
+    }
+
+    /**
+     * @dev Get amount of tokens that are considered as a big transfer
+     */
+    function getBigTransferThreshold(bytes32 schainHash, address token) external view override returns (uint256) {
+        return _delayConfig[schainHash].bigTransferThreshold[token];
+    }
+
+    /**
+     * @dev Get time delay of big transfers
+     */
+    function getTimeDelay(bytes32 schainHash) external view override returns (uint256) {
+        return _delayConfig[schainHash].transferDelay;
+    }
+
+    /**
+     * @dev Get duration of an arbitrage
+     */
+    function getArbitrageDuration(bytes32 schainHash) external view override returns (uint256) {
+        return _delayConfig[schainHash].arbitrageDuration;
+    }
+
+    /**
+     * @dev Retrive tokens that were unlocked after delay for specified receiver
+     */
+    function retrieveFor(address receiver) public override {
+        uint256 transfersAmount = MathUpgradeable.min(
+            delayedTransfersByReceiver[receiver].length(),
+            _QUEUE_PROCESSING_LIMIT
+        );
+
+        uint256 currentIndex = 0;
+        bool retrieved = false;
+        for (uint256 i = 0; i < transfersAmount; ++i) {
+            uint256 transferId = uint256(delayedTransfersByReceiver[receiver].at(currentIndex));
+            DelayedTransfer memory transfer = delayedTransfers[transferId];            
+            ++currentIndex;
+
+            if (transfer.status != DelayedTransferStatus.COMPLETED) {
+                if (block.timestamp < transfer.untilTimestamp) {
+                    // disable detector untill slither fixes false positive
+                    // https://github.com/crytic/slither/issues/778
+                    // slither-disable-next-line incorrect-equality
+                    if (transfer.status == DelayedTransferStatus.DELAYED) {
+                        break;
+                    } else {
+                        // status is ARBITRAGE
+                        continue;
+                    }
+                } else {
+                    // it's time to unlock
+                    if (currentIndex == 1) {
+                        --currentIndex;
+                        _removeOldestDelayedTransfer(receiver);
+                    } else {
+                        delayedTransfers[transferId].status = DelayedTransferStatus.COMPLETED;
+                    }
+                    retrieved = true;
+                    _transfer(transfer.token, transfer.receiver, transfer.amount);
+                }
+            } else {
+                // status is COMPLETED
+                if (currentIndex == 1) {
+                    --currentIndex;
+                    _removeOldestDelayedTransfer(receiver);
+                }
+            }
+        }
+        require(retrieved, "There are no transfers available for retrieving");
+    }
+
     /**
      * @dev Creates a new DepositBoxERC20 contract.
      */
@@ -312,6 +639,15 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 {
         DepositBox.initialize(contractManagerOfSkaleManagerValue, linkerValue, messageProxyValue);
     }
 
+    /**
+     * @dev Check if the receiver is in the delay whitelist
+     */
+    function isReceiverTrusted(bytes32 schainHash, address receiver) public view override returns (bool) {
+        return _delayConfig[schainHash].trustedReceivers.contains(receiver);
+    }
+
+    // private
+
     /**
      * @dev Saves amount of tokens that was transferred to schain.
      */
@@ -345,7 +681,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 {
         private
         returns (bytes memory data)
     {
-        bytes32 schainHash = keccak256(abi.encodePacked(schainName));
+        bytes32 schainHash = _schainHash(schainName);
         ERC20Upgradeable erc20 = ERC20Upgradeable(erc20OnMainnet);
         uint256 totalSupply = erc20.totalSupply();
         require(amount <= totalSupply, "Amount is incorrect");
@@ -381,13 +717,105 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 {
      * - Given address should be contract.
      */
     function _addERC20ForSchain(string calldata schainName, address erc20OnMainnet) private {
-        bytes32 schainHash = keccak256(abi.encodePacked(schainName));
+        bytes32 schainHash = _schainHash(schainName);
         require(erc20OnMainnet.isContract(), "Given address is not a contract");
         require(!_schainToERC20[schainHash].contains(erc20OnMainnet), "ERC20 Token was already added");
         _schainToERC20[schainHash].add(erc20OnMainnet);
         emit ERC20TokenAdded(schainName, erc20OnMainnet);
     }
 
+    /**
+     * @dev Add delayed transfer to receiver specific queue
+     */
+    function _addToDelayedQueue(
+        address receiver,
+        uint256 id,
+        uint256 until
+    )
+        private
+    {
+        _addToDelayedQueueWithPriority(delayedTransfersByReceiver[receiver], id, until, _QUEUE_PROCESSING_LIMIT);
+    }
+
+    /**
+     * @dev Add delayed transfer to receiver specific queue at the position
+     * that maintains order from earlier unlocked to later unlocked.
+     * If the position is located further than depthLimit from the back
+     * the element is added at back - depthLimit index
+     */
+    function _addToDelayedQueueWithPriority(
+        DoubleEndedQueueUpgradeable.Bytes32Deque storage queue, 
+        uint256 id, 
+        uint256 until, 
+        uint256 depthLimit
+    )
+        private
+    {
+        if (depthLimit == 0 || queue.empty()) {
+            queue.pushBack(bytes32(id));
+        } else {
+            if (delayedTransfers[uint256(queue.back())].untilTimestamp <= until) {
+                queue.pushBack(bytes32(id));
+            } else {
+                bytes32 lowPriorityValue = queue.popBack();
+                _addToDelayedQueueWithPriority(queue, id, until, depthLimit - 1);
+                queue.pushBack(lowPriorityValue);
+            }
+        }
+    }
+
+    /**
+     * @dev Transfer ERC20 token or USDT
+     */
+    function _transfer(address token, address receiver, uint256 amount) private {
+        // there is no other reliable way to determine USDT
+        // slither-disable-next-line incorrect-equality
+        if (token == _USDT_ADDRESS) {
+            // solhint-disable-next-line no-empty-blocks
+            try IERC20TransferVoid(token).transfer(receiver, amount) {} catch {
+                revert("Transfer was failed");
+            }
+        } else {
+            require(
+                ERC20Upgradeable(token).transfer(receiver, amount),
+                "Transfer was failed"
+            );
+        }
+    }
+
+    /**
+     * Create instance of DelayedTransfer and initialize all auxiliary fields.
+     */
+    function _createDelayedTransfer(
+        bytes32 schainHash,
+        Messages.TransferErc20Message memory message,
+        uint256 delay
+    )
+        private
+    {
+        uint256 delayId = delayedTransfersSize++;
+        delayedTransfers[delayId] = DelayedTransfer({
+            receiver: message.receiver,
+            schainHash: schainHash,
+            token: message.token,
+            amount: message.amount,
+            untilTimestamp: block.timestamp + delay,
+            status: DelayedTransferStatus.DELAYED
+        });
+        _addToDelayedQueue(message.receiver, delayId, block.timestamp + delay);
+    }
+
+    /**
+     * Remove instance of DelayedTransfer and clean auxiliary fields.
+     */
+    function _removeOldestDelayedTransfer(address receiver) private {
+        uint256 transferId = uint256(delayedTransfersByReceiver[receiver].popFront());
+        // For most cases the loop will have only 1 iteration.
+        // In worst case the amount of iterations is limited by _QUEUE_PROCESSING_LIMIT         
+        // slither-disable-next-line costly-loop
+        delete delayedTransfers[transferId];
+    }
+
     /**
      * @dev Returns total supply of ERC20 token.
      */
diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC721.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC721.sol
index 9fea45a1e..b6674f9ad 100644
--- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC721.sol
+++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC721.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/IERC721MetadataUpgradeable.sol";
 import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
@@ -41,6 +41,8 @@ contract DepositBoxERC721 is DepositBox, IDepositBoxERC721 {
     using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
 
     // schainHash => address of ERC on Mainnet
+    // Deprecated
+    // slither-disable-next-line unused-state
     mapping(bytes32 => mapping(address => bool)) private _deprecatedSchainToERC721;
     mapping(address => mapping(uint256 => bytes32)) public transferredAmount;
     mapping(bytes32 => EnumerableSetUpgradeable.AddressSet) private _schainToERC721;
@@ -56,31 +58,6 @@ contract DepositBoxERC721 is DepositBox, IDepositBoxERC721 {
      */
     event ERC721TokenReady(address indexed contractOnMainnet, uint256 tokenId);
 
-    /**
-     * @dev Allows DEFAULT_ADMIN_ROLE to initialize token mapping
-     * Notice - this function will be executed only once during upgrade
-     * 
-     * Requirements:
-     * 
-     * `msg.sender` should has DEFAULT_ADMIN_ROLE
-     */
-    function initializeAllTokensForSchain(
-        string calldata schainName,
-        address[] calldata tokens
-    )
-        external
-        override
-    {
-        require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Sender is not authorized");
-        bytes32 schainHash = keccak256(abi.encodePacked(schainName));
-        for (uint256 i = 0; i < tokens.length; i++) {
-            if (_deprecatedSchainToERC721[schainHash][tokens[i]] && !_schainToERC721[schainHash].contains(tokens[i])) {
-                _schainToERC721[schainHash].add(tokens[i]);
-                delete _deprecatedSchainToERC721[schainHash][tokens[i]];
-            }
-        }
-    }
-
     /**
      * @dev Allows `msg.sender` to send ERC721 token from mainnet to schain.
      * 
diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC721WithMetadata.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC721WithMetadata.sol
index 926410655..7e2e04770 100644
--- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC721WithMetadata.sol
+++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC721WithMetadata.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/IERC721MetadataUpgradeable.sol";
 import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxEth.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxEth.sol
index 8968c1933..9fa310437 100644
--- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxEth.sol
+++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxEth.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
 import "@skalenetwork/ima-interfaces/mainnet/DepositBoxes/IDepositBoxEth.sol";
diff --git a/proxy/contracts/mainnet/Linker.sol b/proxy/contracts/mainnet/Linker.sol
index 665d5b1a1..25f707d89 100644
--- a/proxy/contracts/mainnet/Linker.sol
+++ b/proxy/contracts/mainnet/Linker.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
 import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
diff --git a/proxy/contracts/mainnet/MessageProxyForMainnet.sol b/proxy/contracts/mainnet/MessageProxyForMainnet.sol
index ec5eac130..56bf1aa04 100644
--- a/proxy/contracts/mainnet/MessageProxyForMainnet.sol
+++ b/proxy/contracts/mainnet/MessageProxyForMainnet.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
 import "@skalenetwork/skale-manager-interfaces/IWallets.sol";
@@ -33,13 +33,6 @@ import "../MessageProxy.sol";
 import "./SkaleManagerClient.sol";
 import "./CommunityPool.sol";
 
-interface IMessageProxyForMainnetInitializeFunction is IMessageProxyForMainnet {
-    function initializeAllRegisteredContracts(
-        bytes32 schainHash,
-        address[] calldata contracts
-    ) external;
-}
-
 
 /**
  * @title Message Proxy for Mainnet
@@ -51,11 +44,17 @@ interface IMessageProxyForMainnetInitializeFunction is IMessageProxyForMainnet {
  * nodes in the chain. Since Ethereum Mainnet has no BLS public key, mainnet
  * messages do not need to be signed.
  */
-contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessageProxyForMainnetInitializeFunction {
+contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessageProxyForMainnet {
 
     using AddressUpgradeable for address;
     using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
 
+    struct Pause {
+        bool paused;
+    }
+
+    bytes32 public constant PAUSABLE_ROLE = keccak256(abi.encodePacked("PAUSABLE_ROLE"));
+
     /**
      * 16 Agents
      * Synchronize time with time.nist.gov
@@ -74,10 +73,17 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro
 
     uint256 public headerMessageGasCost;
     uint256 public messageGasCost;
+
+    // disable detector until slither will fix this issue
+    // https://github.com/crytic/slither/issues/456
+    // slither-disable-next-line uninitialized-state
     mapping(bytes32 => EnumerableSetUpgradeable.AddressSet) private _registryContracts;
     string public version;
     bool public override messageInProgress;
 
+    // schainHash   => Pause structure
+    mapping(bytes32 => Pause) public pauseInfo;
+
     /**
      * @dev Emitted when gas cost for message header was changed.
      */
@@ -104,28 +110,9 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro
         messageInProgress = false;
     }
 
-    /**
-     * @dev Allows DEFAULT_ADMIN_ROLE to initialize registered contracts
-     * Notice - this function will be executed only once during upgrade
-     * 
-     * Requirements:
-     * 
-     * `msg.sender` should have DEFAULT_ADMIN_ROLE
-     */
-    function initializeAllRegisteredContracts(
-        bytes32 schainHash,
-        address[] calldata contracts
-    ) external override {
-        require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Sender is not authorized");
-        for (uint256 i = 0; i < contracts.length; i++) {
-            if (
-                deprecatedRegistryContracts[schainHash][contracts[i]] &&
-                !_registryContracts[schainHash].contains(contracts[i])
-            ) {
-                _registryContracts[schainHash].add(contracts[i]);
-                delete deprecatedRegistryContracts[schainHash][contracts[i]];
-            }
-        }
+    modifier whenNotPaused(bytes32 schainHash) {
+        require(!isPaused(schainHash), "IMA is paused");
+        _;
     }
 
     /**
@@ -215,6 +202,7 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro
         external
         override(IMessageProxy, MessageProxy)
         messageInProgressLocker
+        whenNotPaused(keccak256(abi.encodePacked(fromSchainName)))
     {
         uint256 gasTotal = gasleft();
         bytes32 fromSchainHash = keccak256(abi.encodePacked(fromSchainName));
@@ -290,16 +278,63 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro
         version = newVersion;
     }
 
+    /**
+     * @dev Allows PAUSABLE_ROLE to pause IMA bridge unlimited
+     * or DEFAULT_ADMIN_ROLE to pause for 4 hours
+     * or schain owner to pause unlimited after DEFAULT_ADMIN_ROLE pause it
+     * 
+     * Requirements:
+     * 
+     * - IMA bridge to current schain was not paused
+     * - Sender should be PAUSABLE_ROLE, DEFAULT_ADMIN_ROLE or schain owner
+     */
+    function pause(string calldata schainName) external override {
+        bytes32 schainHash = keccak256(abi.encodePacked(schainName));
+        require(hasRole(PAUSABLE_ROLE, msg.sender), "Incorrect sender");
+        require(!pauseInfo[schainHash].paused, "Already paused");
+        pauseInfo[schainHash].paused = true;
+    }
+
+/**
+     * @dev Allows DEFAULT_ADMIN_ROLE or schain owner to resume IMA bridge 
+     * 
+     * Requirements:
+     * 
+     * - IMA bridge to current schain was paused
+     * - Sender should be DEFAULT_ADMIN_ROLE or schain owner
+     */
+    function resume(string calldata schainName) external override {
+        bytes32 schainHash = keccak256(abi.encodePacked(schainName));
+        require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender) || isSchainOwner(msg.sender, schainHash), "Incorrect sender");
+        require(pauseInfo[schainHash].paused, "Already unpaused");
+        pauseInfo[schainHash].paused = false;
+    }
+
     /**
      * @dev Creates a new MessageProxyForMainnet contract.
      */
     function initialize(IContractManager contractManagerOfSkaleManagerValue) public virtual override initializer {
         SkaleManagerClient.initialize(contractManagerOfSkaleManagerValue);
         MessageProxy.initializeMessageProxy(1e6);
-        headerMessageGasCost = 73800;
+        headerMessageGasCost = 92251;
         messageGasCost = 9000;
     }
 
+    /**
+     * @dev PostOutgoingMessage function with whenNotPaused modifier
+     */
+    function postOutgoingMessage(
+        bytes32 targetChainHash,
+        address targetContract,
+        bytes memory data
+    )
+        public
+        override(IMessageProxy, MessageProxy)
+        whenNotPaused(targetChainHash)
+    {
+        super.postOutgoingMessage(targetChainHash, targetContract, data);
+    }
+
     /**
      * @dev Checks whether chain is currently connected.
      * 
@@ -322,6 +357,13 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro
         return super.isConnectedChain(schainName);
     }
 
+    /**
+     * @dev Returns true if IMA to schain is paused.
+     */
+    function isPaused(bytes32 schainHash) public view override returns (bool) {
+        return pauseInfo[schainHash].paused;
+    }
+
     // private
 
     function _authorizeOutgoingMessageSender(bytes32 targetChainHash) internal view override {
diff --git a/proxy/contracts/mainnet/SkaleManagerClient.sol b/proxy/contracts/mainnet/SkaleManagerClient.sol
index 5c4c0c830..8b07b950d 100644
--- a/proxy/contracts/mainnet/SkaleManagerClient.sol
+++ b/proxy/contracts/mainnet/SkaleManagerClient.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
 import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
@@ -41,7 +41,18 @@ contract SkaleManagerClient is Initializable, AccessControlEnumerableUpgradeable
      */
     modifier onlySchainOwner(string memory schainName) {
         require(
-            isSchainOwner(msg.sender, keccak256(abi.encodePacked(schainName))),
+            isSchainOwner(msg.sender, _schainHash(schainName)),
+            "Sender is not an Schain owner"
+        );
+        _;
+    }
+
+    /**
+     * @dev Modifier for checking whether caller is owner of SKALE chain.
+     */
+    modifier onlySchainOwnerByHash(bytes32 schainHash) {
+        require(
+            isSchainOwner(msg.sender, schainHash),
             "Sender is not an Schain owner"
         );
         _;
@@ -76,4 +87,8 @@ contract SkaleManagerClient is Initializable, AccessControlEnumerableUpgradeable
         address skaleChainsInternal = contractManagerOfSkaleManager.getContract("SchainsInternal");
         return ISchainsInternal(skaleChainsInternal).isNodeAddressesInGroup(schainHash, sender);
     }
+
+    function _schainHash(string memory schainName) internal pure returns (bytes32) {
+        return keccak256(abi.encodePacked(schainName));
+    }
 }
diff --git a/proxy/contracts/mainnet/Twin.sol b/proxy/contracts/mainnet/Twin.sol
index ba9857fa0..45236f4b3 100644
--- a/proxy/contracts/mainnet/Twin.sol
+++ b/proxy/contracts/mainnet/Twin.sol
@@ -21,7 +21,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@skalenetwork/ima-interfaces/mainnet/ITwin.sol";
 
diff --git a/proxy/contracts/schain/CommunityLocker.sol b/proxy/contracts/schain/CommunityLocker.sol
index 58ed57644..b853ed679 100644
--- a/proxy/contracts/schain/CommunityLocker.sol
+++ b/proxy/contracts/schain/CommunityLocker.sol
@@ -21,7 +21,7 @@
     along with SKALE Manager.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
 import "@skalenetwork/ima-interfaces/schain/ICommunityLocker.sol";
diff --git a/proxy/contracts/schain/KeyStorage.sol b/proxy/contracts/schain/KeyStorage.sol
index 55277b907..9440e552d 100644
--- a/proxy/contracts/schain/KeyStorage.sol
+++ b/proxy/contracts/schain/KeyStorage.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
 import "@skalenetwork/ima-interfaces/schain/IKeyStorage.sol";
diff --git a/proxy/contracts/schain/MessageProxyForSchain.sol b/proxy/contracts/schain/MessageProxyForSchain.sol
index bc34bf823..4ce9bad84 100644
--- a/proxy/contracts/schain/MessageProxyForSchain.sol
+++ b/proxy/contracts/schain/MessageProxyForSchain.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
 import "@skalenetwork/ima-interfaces/schain/IMessageProxyForSchain.sol";
@@ -28,13 +28,6 @@ import "@skalenetwork/etherbase-interfaces/IEtherbaseUpgradeable.sol";
 import "../MessageProxy.sol";
 import "./bls/SkaleVerifier.sol";
 
-interface IMessageProxyForSchainInitializeFunction is IMessageProxyForSchain {
-    function initializeAllRegisteredContracts(
-        bytes32 schainHash,
-        address[] calldata contracts
-    ) external;
-}
-
 
 /**
  * @title MessageProxyForSchain
@@ -57,7 +50,7 @@ interface IMessageProxyForSchainInitializeFunction is IMessageProxyForSchain {
  * Call postIncomingMessages function passing (un)signed message array
  * ID of this schain, Chain 0 represents ETH mainnet,
  */
-contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchainInitializeFunction {
+contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain {
     using AddressUpgradeable for address;
     using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
 
@@ -98,6 +91,9 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchainInitialize
     //      schainHash  => tail of unprocessed messages
     mapping(bytes32 => uint) private _idxTail;
 
+    // disable detector until slither will fix this issue
+    // https://github.com/crytic/slither/issues/456
+    // slither-disable-next-line uninitialized-state
     mapping(bytes32 => EnumerableSetUpgradeable.AddressSet) private _registryContracts;
 
     string public version;
@@ -113,30 +109,6 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchainInitialize
         messageInProgress = false;
     }
 
-    /**
-     * @dev Allows DEFAULT_ADMIN_ROLE to initialize registered contracts
-     * Notice - this function will be executed only once during upgrade
-     * 
-     * Requirements:
-     * 
-     * `msg.sender` should have DEFAULT_ADMIN_ROLE
-     */
-    function initializeAllRegisteredContracts(
-        bytes32 chainHash,
-        address[] calldata contracts
-    ) external override {
-        require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Sender is not authorized");
-        for (uint256 i = 0; i < contracts.length; i++) {
-            if (
-                deprecatedRegistryContracts[chainHash][contracts[i]] &&
-                !_registryContracts[chainHash].contains(contracts[i])
-            ) {
-                _registryContracts[chainHash].add(contracts[i]);
-                delete deprecatedRegistryContracts[chainHash][contracts[i]];
-            }
-        }
-    }
-
     /**
      * @dev Allows MessageProxy to register extra contract for being able to transfer messages from custom contracts.
      * 
diff --git a/proxy/contracts/schain/TokenManager.sol b/proxy/contracts/schain/TokenManager.sol
index 0a5a76c82..89c78e515 100644
--- a/proxy/contracts/schain/TokenManager.sol
+++ b/proxy/contracts/schain/TokenManager.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@skalenetwork/ima-interfaces/schain/ITokenManager.sol";
 import "@skalenetwork/ima-interfaces/schain/ICommunityLocker.sol";
diff --git a/proxy/contracts/schain/TokenManagerLinker.sol b/proxy/contracts/schain/TokenManagerLinker.sol
index 563d99c03..ac9501c2a 100644
--- a/proxy/contracts/schain/TokenManagerLinker.sol
+++ b/proxy/contracts/schain/TokenManagerLinker.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
 import "@skalenetwork/ima-interfaces/schain/ITokenManagerLinker.sol";
diff --git a/proxy/contracts/schain/TokenManagers/TokenManagerERC1155.sol b/proxy/contracts/schain/TokenManagers/TokenManagerERC1155.sol
index 394812100..dc463d18b 100644
--- a/proxy/contracts/schain/TokenManagers/TokenManagerERC1155.sol
+++ b/proxy/contracts/schain/TokenManagers/TokenManagerERC1155.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol";
 import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
@@ -31,13 +31,6 @@ import "../TokenManager.sol";
 import "../../thirdparty/ERC1155ReceiverUpgradeableWithoutGap.sol";
 
 
-interface ITokenManagerERC1155InitializeFunction is ITokenManagerERC1155 {
-    function initializeAllClonesERC1155(
-        address[] calldata contracts
-    ) external;
-}
-
-
 /**
  * @title TokenManagerERC1155
  * @dev Runs on SKALE Chains,
@@ -48,7 +41,7 @@ interface ITokenManagerERC1155InitializeFunction is ITokenManagerERC1155 {
 contract TokenManagerERC1155 is
     TokenManager,
     ERC1155ReceiverUpgradeableWithoutGap,
-    ITokenManagerERC1155InitializeFunction
+    ITokenManagerERC1155
 {
     using AddressUpgradeable for address;
     using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
@@ -105,27 +98,6 @@ contract TokenManagerERC1155 is
         uint256[] amounts
     );
 
-    /**
-     * @dev Allows DEFAULT_ADMIN_ROLE to initialize clones ERC1155
-     * Notice - this function will be executed only once during upgrade
-     * 
-     * Requirements:
-     * 
-     * `msg.sender` should have DEFAULT_ADMIN_ROLE
-     */
-    function initializeAllClonesERC1155(address[] calldata contracts) external override {
-        require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Sender is not authorized");
-        for (uint256 i = 0; i < contracts.length; i++) {
-            if (
-                address(deprecatedClonesErc1155[contracts[i]]).isContract() &&
-                !address(clonesErc1155[MAINNET_HASH][contracts[i]]).isContract()
-            ) {
-                clonesErc1155[MAINNET_HASH][contracts[i]] = deprecatedClonesErc1155[contracts[i]];
-                delete deprecatedClonesErc1155[contracts[i]];
-            }
-        }
-    }
-
     /**
      * @dev Move tokens from schain to mainnet.
      * 
diff --git a/proxy/contracts/schain/TokenManagers/TokenManagerERC20.sol b/proxy/contracts/schain/TokenManagers/TokenManagerERC20.sol
index fa9a4463f..6d72b1fdb 100644
--- a/proxy/contracts/schain/TokenManagers/TokenManagerERC20.sol
+++ b/proxy/contracts/schain/TokenManagers/TokenManagerERC20.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
 import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
@@ -30,12 +30,6 @@ import "../../Messages.sol";
 import "../tokens/ERC20OnChain.sol";
 import "../TokenManager.sol";
 
-interface ITokenManagerERC20InitializeFunction is ITokenManagerERC20 {
-    function initializeAllClonesERC20(
-        address[] calldata contracts
-    ) external;
-}
-
 
 /**
  * @title TokenManagerERC20
@@ -44,7 +38,7 @@ interface ITokenManagerERC20InitializeFunction is ITokenManagerERC20 {
  * and creates ERC20 clones.
  * TokenManagerERC20 mints tokens. When a user exits a SKALE chain, it burns them.
  */
-contract TokenManagerERC20 is TokenManager, ITokenManagerERC20InitializeFunction {
+contract TokenManagerERC20 is TokenManager, ITokenManagerERC20 {
     using AddressUpgradeable for address;
     using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
 
@@ -93,27 +87,6 @@ contract TokenManagerERC20 is TokenManager, ITokenManagerERC20InitializeFunction
      */
     event ERC20TokenReady(bytes32 indexed chainHash, address indexed contractOnMainnet, uint256 amount);
 
-    /**
-     * @dev Allows DEFAULT_ADMIN_ROLE to initialize clones ERC20
-     * Notice - this function will be executed only once during upgrade
-     * 
-     * Requirements:
-     * 
-     * `msg.sender` should have DEFAULT_ADMIN_ROLE
-     */
-    function initializeAllClonesERC20(address[] calldata contracts) external override {
-        require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Sender is not authorized");
-        for (uint256 i = 0; i < contracts.length; i++) {
-            if (
-                address(deprecatedClonesErc20[contracts[i]]).isContract() &&
-                !address(clonesErc20[MAINNET_HASH][contracts[i]]).isContract()
-            ) {
-                clonesErc20[MAINNET_HASH][contracts[i]] = deprecatedClonesErc20[contracts[i]];
-                delete deprecatedClonesErc20[contracts[i]];
-            }
-        }
-    }
-
     /**
      * @dev Move tokens from schain to mainnet.
      * 
diff --git a/proxy/contracts/schain/TokenManagers/TokenManagerERC721.sol b/proxy/contracts/schain/TokenManagers/TokenManagerERC721.sol
index eab1aaa0b..3f815e833 100644
--- a/proxy/contracts/schain/TokenManagers/TokenManagerERC721.sol
+++ b/proxy/contracts/schain/TokenManagers/TokenManagerERC721.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
 import "@skalenetwork/ima-interfaces/schain/TokenManagers/ITokenManagerERC721.sol";
@@ -29,13 +29,6 @@ import "../tokens/ERC721OnChain.sol";
 import "../TokenManager.sol";
 
 
-interface ITokenManagerERC721InitializeFunction is ITokenManagerERC721 {
-    function initializeAllClonesERC721(
-        address[] calldata contracts
-    ) external;
-}
-
-
 /**
  * @title TokenManagerERC721
  * @dev Runs on SKALE Chains,
@@ -43,7 +36,7 @@ interface ITokenManagerERC721InitializeFunction is ITokenManagerERC721 {
  * and creates ERC721 clones.
  * TokenManagerERC721 mints tokens. When a user exits a SKALE chain, it burns them.
  */
-contract TokenManagerERC721 is TokenManager, ITokenManagerERC721InitializeFunction {
+contract TokenManagerERC721 is TokenManager, ITokenManagerERC721 {
     using AddressUpgradeable for address;
     using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
 
@@ -93,27 +86,6 @@ contract TokenManagerERC721 is TokenManager, ITokenManagerERC721InitializeFuncti
      */
     event ERC721TokenReady(bytes32 indexed chainHash, address indexed contractOnMainnet, uint256 tokenId);
 
-    /**
-     * @dev Allows DEFAULT_ADMIN_ROLE to initialize clones ERC721
-     * Notice - this function will be executed only once during upgrade
-     * 
-     * Requirements:
-     * 
-     * `msg.sender` should have DEFAULT_ADMIN_ROLE
-     */
-    function initializeAllClonesERC721(address[] calldata contracts) external override {
-        require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Sender is not authorized");
-        for (uint256 i = 0; i < contracts.length; i++) {
-            if (
-                address(deprecatedClonesErc721[contracts[i]]).isContract() &&
-                !address(clonesErc721[MAINNET_HASH][contracts[i]]).isContract()
-            ) {
-                clonesErc721[MAINNET_HASH][contracts[i]] = deprecatedClonesErc721[contracts[i]];
-                delete deprecatedClonesErc721[contracts[i]];
-            }
-        }
-    }
-
     /**
      * @dev Move tokens from schain to mainnet.
      * 
diff --git a/proxy/contracts/schain/TokenManagers/TokenManagerERC721WithMetadata.sol b/proxy/contracts/schain/TokenManagers/TokenManagerERC721WithMetadata.sol
index 22c14e5e0..51807eeef 100644
--- a/proxy/contracts/schain/TokenManagers/TokenManagerERC721WithMetadata.sol
+++ b/proxy/contracts/schain/TokenManagers/TokenManagerERC721WithMetadata.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/IERC721MetadataUpgradeable.sol";
 import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
diff --git a/proxy/contracts/schain/TokenManagers/TokenManagerEth.sol b/proxy/contracts/schain/TokenManagers/TokenManagerEth.sol
index 37a749f8c..28f3aaf03 100644
--- a/proxy/contracts/schain/TokenManagers/TokenManagerEth.sol
+++ b/proxy/contracts/schain/TokenManagers/TokenManagerEth.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@skalenetwork/ima-interfaces/schain/TokenManagers/ITokenManagerEth.sol";
 
diff --git a/proxy/contracts/schain/bls/FieldOperations.sol b/proxy/contracts/schain/bls/FieldOperations.sol
index e5905270a..f2dfc8099 100644
--- a/proxy/contracts/schain/bls/FieldOperations.sol
+++ b/proxy/contracts/schain/bls/FieldOperations.sol
@@ -20,7 +20,7 @@
     along with SKALE Manager.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@skalenetwork/ima-interfaces/schain/bls/IFieldOperations.sol";
 
diff --git a/proxy/contracts/schain/bls/Precompiled.sol b/proxy/contracts/schain/bls/Precompiled.sol
index 236dfdd96..567ee8699 100644
--- a/proxy/contracts/schain/bls/Precompiled.sol
+++ b/proxy/contracts/schain/bls/Precompiled.sol
@@ -19,7 +19,7 @@
     along with SKALE Manager.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 /**
  * @title Precompiled
diff --git a/proxy/contracts/schain/bls/SkaleVerifier.sol b/proxy/contracts/schain/bls/SkaleVerifier.sol
index fdea7a999..3710133ee 100644
--- a/proxy/contracts/schain/bls/SkaleVerifier.sol
+++ b/proxy/contracts/schain/bls/SkaleVerifier.sol
@@ -19,7 +19,7 @@
     along with SKALE Manager.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "./Precompiled.sol";
 import "./FieldOperations.sol";
diff --git a/proxy/contracts/schain/tokens/ERC1155OnChain.sol b/proxy/contracts/schain/tokens/ERC1155OnChain.sol
index 0a0d914af..cb7cd12d1 100644
--- a/proxy/contracts/schain/tokens/ERC1155OnChain.sol
+++ b/proxy/contracts/schain/tokens/ERC1155OnChain.sol
@@ -20,7 +20,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol";
 import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
diff --git a/proxy/contracts/schain/tokens/ERC20OnChain.sol b/proxy/contracts/schain/tokens/ERC20OnChain.sol
index e20ed2a5d..33fb3cec4 100644
--- a/proxy/contracts/schain/tokens/ERC20OnChain.sol
+++ b/proxy/contracts/schain/tokens/ERC20OnChain.sol
@@ -20,7 +20,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
 import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
diff --git a/proxy/contracts/schain/tokens/ERC721OnChain.sol b/proxy/contracts/schain/tokens/ERC721OnChain.sol
index 98a1ec32f..d0c892f0f 100644
--- a/proxy/contracts/schain/tokens/ERC721OnChain.sol
+++ b/proxy/contracts/schain/tokens/ERC721OnChain.sol
@@ -20,7 +20,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol";
 import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol";
diff --git a/proxy/contracts/schain/tokens/EthErc20.sol b/proxy/contracts/schain/tokens/EthErc20.sol
index 6478fe430..96d71a9a2 100644
--- a/proxy/contracts/schain/tokens/EthErc20.sol
+++ b/proxy/contracts/schain/tokens/EthErc20.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
 import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
diff --git a/proxy/contracts/thirdparty/ERC1155ReceiverUpgradeableWithoutGap.sol b/proxy/contracts/thirdparty/ERC1155ReceiverUpgradeableWithoutGap.sol
index abe928e89..4f7c38571 100644
--- a/proxy/contracts/thirdparty/ERC1155ReceiverUpgradeableWithoutGap.sol
+++ b/proxy/contracts/thirdparty/ERC1155ReceiverUpgradeableWithoutGap.sol
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: AGPL-3.0-only
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
 import "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
diff --git a/proxy/hardhat.config.ts b/proxy/hardhat.config.ts
index ad06c7e26..3873aa32a 100644
--- a/proxy/hardhat.config.ts
+++ b/proxy/hardhat.config.ts
@@ -36,7 +36,7 @@ function getGasPrice(gasPrice: string | undefined) {
 const config: HardhatUserConfig = {
   defaultNetwork: "hardhat",
   solidity: {
-    version: '0.8.6',
+    version: '0.8.16',
     settings: {
       optimizer: {
         enabled: true,
diff --git a/proxy/migrations/upgradeMainnet.ts b/proxy/migrations/upgradeMainnet.ts
index a9951d8c3..1cdb09380 100644
--- a/proxy/migrations/upgradeMainnet.ts
+++ b/proxy/migrations/upgradeMainnet.ts
@@ -1,12 +1,83 @@
-import { contracts } from "./deployMainnet";
+import { getManifestAdmin } from "@openzeppelin/hardhat-upgrades/dist/admin";
+import { CommunityPool, MessageProxyForMainnet } from "../typechain";
+import { contracts, getContractKeyInAbiFile } from "./deployMainnet";
+import { encodeTransaction } from "./tools/multiSend";
 import { upgrade } from "./upgrade";
+import chalk from "chalk";
+import { ethers } from "hardhat";
+import hre from "hardhat";
 
 async function main() {
     await upgrade(
         "1.3.2",
         contracts,
         async (safeTransactions, abi) => undefined,
-        async (safeTransactions, abi) => undefined,
+        async (safeTransactions, abi) => {
+            const proxyAdmin = await getManifestAdmin(hre);
+            const owner = await proxyAdmin.owner();
+            const communityPoolName = "CommunityPool";
+            const communityPoolFactory = await ethers.getContractFactory(communityPoolName);
+            const communityPoolAddress = abi[getContractKeyInAbiFile(communityPoolName) + "_address"];
+            let communityPool;
+            if (communityPoolAddress) {
+                communityPool = communityPoolFactory.attach(communityPoolAddress) as CommunityPool;
+                const constantSetterRole = await communityPool.CONSTANT_SETTER_ROLE();
+                const isHasRole = await communityPool.hasRole(constantSetterRole, owner);
+                if (!isHasRole) {
+                    console.log(chalk.yellow("Prepare transaction to grantRole CONSTANT_SETTER_ROLE to " + owner));
+                    safeTransactions.push(encodeTransaction(
+                        0,
+                        communityPoolAddress,
+                        0,
+                        communityPool.interface.encodeFunctionData("grantRole", [constantSetterRole, owner])
+                    ));
+                }
+                console.log(chalk.yellow("Prepare transaction to set multiplier to 3/2"));
+                safeTransactions.push(encodeTransaction(
+                    0,
+                    communityPoolAddress,
+                    0,
+                    communityPool.interface.encodeFunctionData("setMultiplier", [3, 2])
+                ));
+                console.log(chalk.yellow("Prepare transaction to set header message gas cost to 73800"));
+            } else {
+                console.log(chalk.red("CommunityPool was not found!"));
+                console.log(chalk.red("Check your abi!!!"));
+                process.exit(1);
+            }
+
+            const messageProxyForMainnet = (await ethers.getContractFactory("MessageProxyForMainnet"))
+            .attach(abi[getContractKeyInAbiFile("MessageProxyForMainnet") + "_address"]) as MessageProxyForMainnet;
+
+            if (! await messageProxyForMainnet.hasRole(await messageProxyForMainnet.CONSTANT_SETTER_ROLE(), owner)) {
+                console.log(chalk.yellow("Prepare transaction to grantRole CONSTANT_SETTER_ROLE to " + owner));
+                safeTransactions.push(encodeTransaction(
+                    0,
+                    messageProxyForMainnet.address,
+                    0,
+                    messageProxyForMainnet.interface.encodeFunctionData(
+                        "grantRole",
+                        [ await messageProxyForMainnet.CONSTANT_SETTER_ROLE(), owner ]
+                    )
+                ));
+            }
+
+            const newHeaderMessageGasCost = 92251;
+
+            console.log(chalk.yellow(
+                "Prepare transaction to set header message gas cost to",
+                newHeaderMessageGasCost.toString()
+            ));
+            safeTransactions.push(encodeTransaction(
+                0,
+                messageProxyForMainnet.address,
+                0,
+                messageProxyForMainnet.interface.encodeFunctionData(
+                    "setNewHeaderMessageGasCost",
+                    [ newHeaderMessageGasCost ]
+                )
+            ));
+        },
         "proxyMainnet"
     );
 }
diff --git a/proxy/package.json b/proxy/package.json
index dd6b749c2..7763c2dd5 100644
--- a/proxy/package.json
+++ b/proxy/package.json
@@ -4,13 +4,14 @@
     "license": "AGPL-3.0",
     "author": "SKALE Labs and contributors",
     "scripts": {
-        "compile": "npx hardhat clean && npx hardhat compile",
+        "compile": "npx hardhat compile",
+        "cleanCompile": "npx hardhat clean && yarn compile",
         "deploy-to-both-chains": "yarn deploy-to-mainnet && yarn deploy-to-schain",
         "deploy-to-mainnet": "npx hardhat run migrations/deployMainnet.ts --network mainnet",
         "deploy-to-schain": "npx hardhat run migrations/deploySchain.ts --network schain",
         "deploy-skale-manager-components": "npx hardhat run migrations/deploySkaleManagerComponents.ts --network mainnet",
         "lint": "npx solhint \"contracts/**/*.sol\"",
-        "prepare": "yarn compile",
+        "prepare": "yarn cleanCompile",
         "test": "yarn tsc && npx hardhat test",
         "tsc": "tsc --noEmit",
         "tslint": "npx tslint --project .",
@@ -22,10 +23,10 @@
     "dependencies": {
         "@nomiclabs/hardhat-ethers": "^2.0.2",
         "@nomiclabs/hardhat-web3": "^2.0.0",
-        "@openzeppelin/contracts-upgradeable": "^4.3.2",
+        "@openzeppelin/contracts-upgradeable": "^4.7.1",
         "@openzeppelin/hardhat-upgrades": "^1.9.0",
         "@skalenetwork/etherbase-interfaces": "^0.0.1-develop.20",
-        "@skalenetwork/ima-interfaces": "1.0.0-develop.17",
+        "@skalenetwork/ima-interfaces": "1.0.0-develop.20",
         "@skalenetwork/skale-manager-interfaces": "1.0.0-develop.1",
         "axios": "^0.21.4",
         "dotenv": "^10.0.0",
diff --git a/proxy/predeployed/scripts/build_package.sh b/proxy/predeployed/scripts/build_package.sh
index 2003c201d..25cc60b4c 100755
--- a/proxy/predeployed/scripts/build_package.sh
+++ b/proxy/predeployed/scripts/build_package.sh
@@ -1,13 +1,9 @@
 #!/usr/bin/env bash
 
 set -e
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
 
 cd "$(dirname "$0")/.."
 ./scripts/generate_package_version.py > version.txt
-ARTIFACTS_DIR="src/ima_predeployed/artifacts/"
-mkdir -p src/ima_predeployed/artifacts/
-cp -v ../node_modules/@openzeppelin/upgrades-core/artifacts/ProxyAdmin.json $ARTIFACTS_DIR
-cp -v ../node_modules/@openzeppelin/upgrades-core/artifacts/AdminUpgradeabilityProxy.json $ARTIFACTS_DIR
-cp -v ../artifacts/contracts/schain/*/*.json $ARTIFACTS_DIR
-cp -v ../artifacts/contracts/schain/*/*/*.json $ARTIFACTS_DIR
+python3 $SCRIPT_DIR/prepare_artifacts.py
 python3 -m build
diff --git a/proxy/predeployed/scripts/generate_abi.py b/proxy/predeployed/scripts/generate_abi.py
old mode 100755
new mode 100644
diff --git a/proxy/predeployed/scripts/prepare_artifacts.py b/proxy/predeployed/scripts/prepare_artifacts.py
new file mode 100755
index 000000000..584c49d95
--- /dev/null
+++ b/proxy/predeployed/scripts/prepare_artifacts.py
@@ -0,0 +1,34 @@
+from os.path import normpath, join, dirname
+from predeployed_generator.tools import ArtifactsHandler
+
+pkg_name = 'ima_predeployed'
+package_artifacts_path = normpath(join(dirname(__file__), f'../src/{pkg_name}/artifacts'))
+hardhat_contracts_path = normpath(join(dirname(__file__), '../../artifacts/contracts/schain'))
+
+
+def prepare():
+    handler = ArtifactsHandler(hardhat_contracts_path, package_artifacts_path)
+    handler.prepare_artifacts('KeyStorage')
+    handler.prepare_artifacts('MessageProxyForSchain')
+    handler.prepare_artifacts('TokenManager')
+    handler.prepare_artifacts('TokenManagerLinker')
+    handler.prepare_artifacts('CommunityLocker')
+
+    tms_hardhat_path = join(hardhat_contracts_path, 'TokenManagers')
+    tms_handler = ArtifactsHandler(tms_hardhat_path, package_artifacts_path)
+    tms_handler.prepare_artifacts('TokenManagerERC20')
+    tms_handler.prepare_artifacts('TokenManagerERC721')
+    tms_handler.prepare_artifacts('TokenManagerERC721WithMetadata')
+    tms_handler.prepare_artifacts('TokenManagerERC1155')
+    tms_handler.prepare_artifacts('TokenManagerEth')
+
+    tokens_hardhat_path = join(hardhat_contracts_path, 'tokens')
+    tokens_handler = ArtifactsHandler(tokens_hardhat_path, package_artifacts_path)
+    tokens_handler.prepare_artifacts('EthErc20')
+    tokens_handler.prepare_artifacts('ERC20OnChain')
+    tokens_handler.prepare_artifacts('ERC721OnChain')
+    tokens_handler.prepare_artifacts('ERC1155OnChain')
+
+
+if __name__ == '__main__':
+    prepare()
\ No newline at end of file
diff --git a/proxy/predeployed/setup.cfg b/proxy/predeployed/setup.cfg
index 073d09eba..f25ca27aa 100644
--- a/proxy/predeployed/setup.cfg
+++ b/proxy/predeployed/setup.cfg
@@ -19,7 +19,7 @@ packages = find:
 include_package_data = True
 python_requires = >=3.6
 install_requires =
-    web3
+    predeployed-generator >= 1.1.0a0
 
 [options.packages.find]
 where = src
\ No newline at end of file
diff --git a/proxy/predeployed/src/ima_predeployed/artifacts/.gitkeep b/proxy/predeployed/src/ima_predeployed/artifacts/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/proxy/predeployed/src/ima_predeployed/contracts/community_locker.py b/proxy/predeployed/src/ima_predeployed/contracts/community_locker.py
index e6bc02a08..850d40944 100644
--- a/proxy/predeployed/src/ima_predeployed/contracts/community_locker.py
+++ b/proxy/predeployed/src/ima_predeployed/contracts/community_locker.py
@@ -1,10 +1,18 @@
-from ima_predeployed.addresses import MESSAGE_PROXY_FOR_SCHAIN_ADDRESS, TOKEN_MANAGER_LINKER_ADDRESS
-from ima_predeployed.contract_generator import ContractGenerator, next_slot
+from os.path import join, dirname
+from typing import Dict
+
+from predeployed_generator.upgradeable_contract_generator import UpgradeableContractGenerator
+
+from ..addresses import MESSAGE_PROXY_FOR_SCHAIN_ADDRESS, TOKEN_MANAGER_LINKER_ADDRESS
+from predeployed_generator.openzeppelin.access_control_enumerable_generator import (
+    AccessControlEnumerableGenerator
+)
 from web3 import Web3
 
 
-class CommunityLockerGenerator(ContractGenerator):
-    ARTIFACT_FILENAME = "CommunityLocker.json"
+class CommunityLockerGenerator(AccessControlEnumerableGenerator):
+    ARTIFACT_FILENAME = 'CommunityLocker.json'
+    META_FILENAME = 'CommunityLocker.meta.json'
     DEFAULT_ADMIN_ROLE = (0).to_bytes(32, 'big')
     DEFAULT_TIME_LIMIT_SEC = 5 * 60
 
@@ -42,22 +50,41 @@ class CommunityLockerGenerator(ContractGenerator):
     ROLES_SLOT = 101
     ROLE_MEMBERS_SLOT = 151
     MESSAGE_PROXY_SLOT = 201
-    TOKEN_MANAGER_LINKER_SLOT = next_slot(MESSAGE_PROXY_SLOT)
-    COMMUNITY_POOL_SLOT = next_slot(TOKEN_MANAGER_LINKER_SLOT)
-    SCHAIN_HASH_SLOT = next_slot(COMMUNITY_POOL_SLOT)
-    TIME_LIMIT_PER_MESSAGE_SLOT = next_slot(SCHAIN_HASH_SLOT)
-
-    def __init__(self, deployer_address: str, schain_name: str, community_pool_address: str):
-        super().__init__(self.ARTIFACT_FILENAME)
-        self._setup(deployer_address, schain_name, community_pool_address)
-
-    # private
-
-    def _setup(self, deployer_address: str, schain_name: str, community_pool_address) -> None:
-        self._write_uint256(self.INITIALIZED_SLOT, 1)
-        self._setup_role(self.ROLES_SLOT, self.ROLE_MEMBERS_SLOT, self.DEFAULT_ADMIN_ROLE, [deployer_address])
-        self._write_address(self.MESSAGE_PROXY_SLOT, MESSAGE_PROXY_FOR_SCHAIN_ADDRESS)
-        self._write_address(self.TOKEN_MANAGER_LINKER_SLOT, TOKEN_MANAGER_LINKER_ADDRESS)
-        self._write_address(self.COMMUNITY_POOL_SLOT, community_pool_address)
-        self._write_bytes32(self.SCHAIN_HASH_SLOT, Web3.solidityKeccak(['string'], [schain_name]))
-        self._write_uint256(self.TIME_LIMIT_PER_MESSAGE_SLOT, self.DEFAULT_TIME_LIMIT_SEC)
+    TOKEN_MANAGER_LINKER_SLOT = AccessControlEnumerableGenerator.next_slot(MESSAGE_PROXY_SLOT)
+    COMMUNITY_POOL_SLOT = AccessControlEnumerableGenerator.next_slot(TOKEN_MANAGER_LINKER_SLOT)
+    SCHAIN_HASH_SLOT = AccessControlEnumerableGenerator.next_slot(COMMUNITY_POOL_SLOT)
+    TIME_LIMIT_PER_MESSAGE_SLOT = AccessControlEnumerableGenerator.next_slot(SCHAIN_HASH_SLOT)
+
+    def __init__(self):
+        generator = CommunityLockerGenerator.from_hardhat_artifact(
+            join(dirname(__file__), '..', 'artifacts', self.ARTIFACT_FILENAME),
+            join(dirname(__file__), '..', 'artifacts', self.META_FILENAME))
+        super().__init__(bytecode=generator.bytecode, abi=generator.abi, meta=generator.meta)
+
+    @classmethod
+    def generate_storage(cls, **kwargs) -> Dict[str, str]:
+        deployer_address = kwargs['deployer_address']
+        schain_name = kwargs['schain_name']
+        community_pool_address = kwargs['community_pool_address']
+
+        storage: Dict[str, str] = {}
+        roles_slots = cls.RolesSlots(roles=cls.ROLES_SLOT, role_members=cls.ROLE_MEMBERS_SLOT)
+
+        cls._write_uint256(storage, cls.INITIALIZED_SLOT, 1)
+        cls._setup_role(storage, roles_slots, cls.DEFAULT_ADMIN_ROLE, [deployer_address])
+        cls._write_address(storage, cls.MESSAGE_PROXY_SLOT, MESSAGE_PROXY_FOR_SCHAIN_ADDRESS)
+        cls._write_address(storage, cls.TOKEN_MANAGER_LINKER_SLOT, TOKEN_MANAGER_LINKER_ADDRESS)
+        cls._write_address(storage, cls.COMMUNITY_POOL_SLOT, community_pool_address)
+
+        cls._write_bytes32(storage, cls.SCHAIN_HASH_SLOT, Web3.solidityKeccak(['string'], [schain_name]))
+        cls._write_uint256(storage, cls.TIME_LIMIT_PER_MESSAGE_SLOT, cls.DEFAULT_TIME_LIMIT_SEC)
+
+        return storage
+
+
+class UpgradeableCommunityLockerGenerator(UpgradeableContractGenerator):
+    """Generates upgradeable instance of CommunityLockerUpgradeable
+    """
+
+    def __init__(self):
+        super().__init__(implementation_generator=CommunityLockerGenerator())
diff --git a/proxy/predeployed/src/ima_predeployed/contracts/erc1155_on_chain.py b/proxy/predeployed/src/ima_predeployed/contracts/erc1155_on_chain.py
new file mode 100644
index 000000000..ec62a51d9
--- /dev/null
+++ b/proxy/predeployed/src/ima_predeployed/contracts/erc1155_on_chain.py
@@ -0,0 +1,15 @@
+from os.path import join, dirname
+from predeployed_generator.contract_generator import (
+    ContractGenerator
+)
+
+
+class Erc1155OnChainGenerator(ContractGenerator):
+    ARTIFACT_FILENAME = "ERC1155OnChain.json"
+    META_FILENAME = "ERC1155OnChain.meta.json"
+
+    def __init__(self):
+        generator = Erc1155OnChainGenerator.from_hardhat_artifact(
+            join(dirname(__file__), '..', 'artifacts', self.ARTIFACT_FILENAME),
+            join(dirname(__file__), '..', 'artifacts', self.META_FILENAME))
+        super().__init__(bytecode=generator.bytecode, abi=generator.abi, meta=generator.meta)
diff --git a/proxy/predeployed/src/ima_predeployed/contracts/erc20_on_chain.py b/proxy/predeployed/src/ima_predeployed/contracts/erc20_on_chain.py
new file mode 100644
index 000000000..18bc19b5c
--- /dev/null
+++ b/proxy/predeployed/src/ima_predeployed/contracts/erc20_on_chain.py
@@ -0,0 +1,15 @@
+from os.path import join, dirname
+from predeployed_generator.contract_generator import (
+    ContractGenerator
+)
+
+
+class Erc20OnChainGenerator(ContractGenerator):
+    ARTIFACT_FILENAME = "ERC20OnChain.json"
+    META_FILENAME = "ERC20OnChain.meta.json"
+
+    def __init__(self):
+        generator = Erc20OnChainGenerator.from_hardhat_artifact(
+            join(dirname(__file__), '..', 'artifacts', self.ARTIFACT_FILENAME),
+            join(dirname(__file__), '..', 'artifacts', self.META_FILENAME))
+        super().__init__(bytecode=generator.bytecode, abi=generator.abi, meta=generator.meta)
diff --git a/proxy/predeployed/src/ima_predeployed/contracts/erc721_on_chain.py b/proxy/predeployed/src/ima_predeployed/contracts/erc721_on_chain.py
new file mode 100644
index 000000000..050da8fcc
--- /dev/null
+++ b/proxy/predeployed/src/ima_predeployed/contracts/erc721_on_chain.py
@@ -0,0 +1,15 @@
+from os.path import join, dirname
+from predeployed_generator.contract_generator import (
+    ContractGenerator
+)
+
+
+class Erc721OnChainGenerator(ContractGenerator):
+    ARTIFACT_FILENAME = "ERC721OnChain.json"
+    META_FILENAME = "ERC721OnChain.meta.json"
+
+    def __init__(self):
+        generator = Erc721OnChainGenerator.from_hardhat_artifact(
+            join(dirname(__file__), '..', 'artifacts', self.ARTIFACT_FILENAME),
+            join(dirname(__file__), '..', 'artifacts', self.META_FILENAME))
+        super().__init__(bytecode=generator.bytecode, abi=generator.abi, meta=generator.meta)
diff --git a/proxy/predeployed/src/ima_predeployed/contracts/eth_erc20.py b/proxy/predeployed/src/ima_predeployed/contracts/eth_erc20.py
index dd4e446b5..9127825da 100644
--- a/proxy/predeployed/src/ima_predeployed/contracts/eth_erc20.py
+++ b/proxy/predeployed/src/ima_predeployed/contracts/eth_erc20.py
@@ -1,10 +1,18 @@
-from ima_predeployed.addresses import TOKEN_MANAGER_ETH_ADDRESS
-from ima_predeployed.contract_generator import ContractGenerator, next_slot
+from os.path import join, dirname
+from typing import Dict
+
+from predeployed_generator.upgradeable_contract_generator import UpgradeableContractGenerator
+
+from ..addresses import TOKEN_MANAGER_ETH_ADDRESS
+from predeployed_generator.openzeppelin.access_control_enumerable_generator import (
+    AccessControlEnumerableGenerator
+)
 from web3 import Web3
 
 
-class EthErc20Generator(ContractGenerator):
+class EthErc20Generator(AccessControlEnumerableGenerator):
     ARTIFACT_FILENAME = "EthErc20.json"
+    META_FILENAME = "EthErc20.meta.json"
     DEFAULT_ADMIN_ROLE = (0).to_bytes(32, 'big')
     MINTER_ROLE = Web3.solidityKeccak(['string'], ['MINTER_ROLE'])
     BURNER_ROLE = Web3.solidityKeccak(['string'], ['BURNER_ROLE'])
@@ -53,20 +61,36 @@ class EthErc20Generator(ContractGenerator):
     ROLES_SLOT = 101
     ROLE_MEMBERS_SLOT = 151
     NAME_SLOT = 204
-    SYMBOL_SLOT = next_slot(NAME_SLOT)
-    DECIMALS_SLOT = next_slot(SYMBOL_SLOT)
+    SYMBOL_SLOT = AccessControlEnumerableGenerator.next_slot(NAME_SLOT)
+    DECIMALS_SLOT = AccessControlEnumerableGenerator.next_slot(SYMBOL_SLOT)
+
+    def __init__(self):
+        generator = EthErc20Generator.from_hardhat_artifact(
+            join(dirname(__file__), '..', 'artifacts', self.ARTIFACT_FILENAME),
+            join(dirname(__file__), '..', 'artifacts', self.META_FILENAME))
+        super().__init__(bytecode=generator.bytecode, abi=generator.abi, meta=generator.meta)
+
+    @classmethod
+    def generate_storage(cls, **kwargs) -> Dict[str, str]:
+        deployer_address = kwargs['deployer_address']
+
+        storage: Dict[str, str] = {}
+        roles_slots = cls.RolesSlots(roles=cls.ROLES_SLOT, role_members=cls.ROLE_MEMBERS_SLOT)
+
+        cls._write_uint256(storage, cls.INITIALIZED_SLOT, 1)
+        cls._setup_role(storage, roles_slots, cls.DEFAULT_ADMIN_ROLE, [deployer_address])
+        cls._setup_role(storage, roles_slots, cls.MINTER_ROLE, [TOKEN_MANAGER_ETH_ADDRESS])
+        cls._setup_role(storage, roles_slots, cls.BURNER_ROLE, [TOKEN_MANAGER_ETH_ADDRESS])
+        cls._write_string(storage, cls.NAME_SLOT, cls.NAME)
+        cls._write_string(storage, cls.SYMBOL_SLOT, cls.SYMBOL)
+        cls._write_uint256(storage, cls.DECIMALS_SLOT, cls.DECIMALS)
+
+        return storage
 
-    def __init__(self, deployer_address: str):
-        super().__init__(self.ARTIFACT_FILENAME)
-        self._setup(deployer_address)
 
-    # private
+class UpgradeableEthErc20Generator(UpgradeableContractGenerator):
+    """Generates upgradeable instance of EthErc20Upgradeable
+    """
 
-    def _setup(self, deployer_address: str) -> None:
-        self._write_uint256(self.INITIALIZED_SLOT, 1)
-        self._setup_role(self.ROLES_SLOT, self.ROLE_MEMBERS_SLOT, self.DEFAULT_ADMIN_ROLE, [deployer_address])
-        self._setup_role(self.ROLES_SLOT, self.ROLE_MEMBERS_SLOT, self.MINTER_ROLE, [TOKEN_MANAGER_ETH_ADDRESS])
-        self._setup_role(self.ROLES_SLOT, self.ROLE_MEMBERS_SLOT, self.BURNER_ROLE, [TOKEN_MANAGER_ETH_ADDRESS])
-        self._write_string(self.NAME_SLOT, self.NAME)
-        self._write_string(self.SYMBOL_SLOT, self.SYMBOL)
-        self._write_uint256(self.DECIMALS_SLOT, self.DECIMALS)
+    def __init__(self):
+        super().__init__(implementation_generator=EthErc20Generator())
diff --git a/proxy/predeployed/src/ima_predeployed/contracts/key_storage.py b/proxy/predeployed/src/ima_predeployed/contracts/key_storage.py
index b892265c3..d8c5f5d26 100644
--- a/proxy/predeployed/src/ima_predeployed/contracts/key_storage.py
+++ b/proxy/predeployed/src/ima_predeployed/contracts/key_storage.py
@@ -1,8 +1,15 @@
-from ..contract_generator import ContractGenerator
+from os.path import join, dirname
+from typing import Dict
 
+from predeployed_generator.openzeppelin.access_control_enumerable_generator import (
+    AccessControlEnumerableGenerator
+)
+from predeployed_generator.upgradeable_contract_generator import UpgradeableContractGenerator
 
-class KeyStorageGenerator(ContractGenerator):
+
+class KeyStorageGenerator(AccessControlEnumerableGenerator):
     ARTIFACT_FILENAME = "KeyStorage.json"
+    META_FILENAME = "KeyStorage.meta.json"
     DEFAULT_ADMIN_ROLE = (0).to_bytes(32, 'big')
 
     # ---------- storage ----------
@@ -32,12 +39,27 @@ class KeyStorageGenerator(ContractGenerator):
     ROLES_SLOT = 101
     ROLE_MEMBERS_SLOT = 151
 
-    def __init__(self, deployer_address: str):
-        super().__init__(self.ARTIFACT_FILENAME)
-        self._setup(deployer_address)
+    def __init__(self):
+        generator = KeyStorageGenerator.from_hardhat_artifact(
+            join(dirname(__file__), '..', 'artifacts', self.ARTIFACT_FILENAME),
+            join(dirname(__file__), '..', 'artifacts', self.META_FILENAME))
+        super().__init__(bytecode=generator.bytecode, abi=generator.abi, meta=generator.meta)
+
+    @classmethod
+    def generate_storage(cls, **kwargs) -> Dict[str, str]:
+        deployer_address = kwargs['deployer_address']
+        storage: Dict[str, str] = {}
+        roles_slots = cls.RolesSlots(roles=cls.ROLES_SLOT, role_members=cls.ROLE_MEMBERS_SLOT)
+
+        cls._write_uint256(storage, cls.INITIALIZED_SLOT, 1)
+        cls._setup_role(storage, roles_slots, cls.DEFAULT_ADMIN_ROLE, [deployer_address])
+
+        return storage
+
 
-    # private
+class UpgradeableKeyStorageGenerator(UpgradeableContractGenerator):
+    """Generates upgradeable instance of KeyStorageUpgradeable
+    """
 
-    def _setup(self, deployer_address: str) -> None:
-        self._write_uint256(self.INITIALIZED_SLOT, 1)
-        self._setup_role(self.ROLES_SLOT, self.ROLE_MEMBERS_SLOT, self.DEFAULT_ADMIN_ROLE, [deployer_address])
+    def __init__(self):
+        super().__init__(implementation_generator=KeyStorageGenerator())
diff --git a/proxy/predeployed/src/ima_predeployed/contracts/message_proxy_for_schain.py b/proxy/predeployed/src/ima_predeployed/contracts/message_proxy_for_schain.py
index c2b642324..e5ab5a50e 100644
--- a/proxy/predeployed/src/ima_predeployed/contracts/message_proxy_for_schain.py
+++ b/proxy/predeployed/src/ima_predeployed/contracts/message_proxy_for_schain.py
@@ -1,12 +1,21 @@
-from ..contract_generator import ContractGenerator, calculate_mapping_value_slot, calculate_array_value_slot, next_slot
+from os.path import join, dirname
+from typing import Dict
+
+from predeployed_generator.openzeppelin.access_control_enumerable_generator import (
+    AccessControlEnumerableGenerator as Generator
+)
+from predeployed_generator.upgradeable_contract_generator import UpgradeableContractGenerator
+
 from ..addresses import COMMUNITY_LOCKER_ADDRESS, KEY_STORAGE_ADDRESS, TOKEN_MANAGER_ERC1155_ADDRESS, \
     TOKEN_MANAGER_ERC20_ADDRESS, TOKEN_MANAGER_ERC721_ADDRESS, TOKEN_MANAGER_ETH_ADDRESS, \
     TOKEN_MANAGER_ERC721_WITH_METADATA_ADDRESS, TOKEN_MANAGER_LINKER_ADDRESS
 from web3 import Web3
 from pkg_resources import get_distribution
 
-class MessageProxyForSchainGenerator(ContractGenerator):
+
+class MessageProxyForSchainGenerator(Generator):
     ARTIFACT_FILENAME = "MessageProxyForSchain.json"
+    META_FILENAME = "MessageProxyForSchain.meta.json"
     DEFAULT_ADMIN_ROLE = (0).to_bytes(32, 'big')
     CHAIN_CONNECTOR_ROLE = Web3.solidityKeccak(['string'], ['CHAIN_CONNECTOR_ROLE'])
     MAINNET_HASH = Web3.solidityKeccak(['string'], ['Mainnet'])
@@ -51,38 +60,46 @@ class MessageProxyForSchainGenerator(ContractGenerator):
     ROLES_SLOT = 101
     ROLE_MEMBERS_SLOT = 151
     CONNECTED_CHAINS_SLOT = 201
-    DEPRECATED_REGISTRY_CONTRACTS_SLOT = next_slot(CONNECTED_CHAINS_SLOT)
-    GAS_LIMIT_SLOT = next_slot(DEPRECATED_REGISTRY_CONTRACTS_SLOT)
-    KEY_STORAGE_SLOT = next_slot(GAS_LIMIT_SLOT)
-    SCHAIN_HASH_SLOT = next_slot(KEY_STORAGE_SLOT)
-    OUTGOING_MESSAGE_DATA_HASH = next_slot(SCHAIN_HASH_SLOT)
-    IDX_HEAD = next_slot(OUTGOING_MESSAGE_DATA_HASH)
-    IDX_TAIL = next_slot(IDX_HEAD)
-    REGISTRY_CONTRACTS_SLOT = next_slot(IDX_TAIL)
-    VERSION_SLOT = next_slot(REGISTRY_CONTRACTS_SLOT)
+    DEPRECATED_REGISTRY_CONTRACTS_SLOT = Generator.next_slot(CONNECTED_CHAINS_SLOT)
+    GAS_LIMIT_SLOT = Generator.next_slot(DEPRECATED_REGISTRY_CONTRACTS_SLOT)
+    KEY_STORAGE_SLOT = Generator.next_slot(GAS_LIMIT_SLOT)
+    SCHAIN_HASH_SLOT = Generator.next_slot(KEY_STORAGE_SLOT)
+    OUTGOING_MESSAGE_DATA_HASH = Generator.next_slot(SCHAIN_HASH_SLOT)
+    IDX_HEAD = Generator.next_slot(OUTGOING_MESSAGE_DATA_HASH)
+    IDX_TAIL = Generator.next_slot(IDX_HEAD)
+    REGISTRY_CONTRACTS_SLOT = Generator.next_slot(IDX_TAIL)
+    VERSION_SLOT = Generator.next_slot(REGISTRY_CONTRACTS_SLOT)
     
+    def __init__(self):
+        generator = MessageProxyForSchainGenerator.from_hardhat_artifact(
+            join(dirname(__file__), '..', 'artifacts', self.ARTIFACT_FILENAME),
+            join(dirname(__file__), '..', 'artifacts', self.META_FILENAME))
+        super().__init__(bytecode=generator.bytecode, abi=generator.abi, meta=generator.meta)
 
-    def __init__(self, deployer_address: str, schain_name: str):
-        super().__init__(self.ARTIFACT_FILENAME)
-        self._setup(deployer_address, schain_name)
-
-    # private
+    @classmethod
+    def generate_storage(cls, **kwargs) -> Dict[str, str]:
+        deployer_address = kwargs['deployer_address']
+        schain_name = kwargs['schain_name']
+        storage: Dict[str, str] = {}
+        roles_slots = cls.RolesSlots(roles=cls.ROLES_SLOT, role_members=cls.ROLE_MEMBERS_SLOT)
+        
+        cls._write_uint256(storage, cls.INITIALIZED_SLOT, 1)
+        cls._setup_role(storage, roles_slots, cls.DEFAULT_ADMIN_ROLE, [deployer_address])
+        cls._setup_role(storage, roles_slots, cls.CHAIN_CONNECTOR_ROLE,
+                        [TOKEN_MANAGER_LINKER_ADDRESS])
+        cls._write_address(storage, cls.KEY_STORAGE_SLOT, KEY_STORAGE_ADDRESS)
+        cls._write_bytes32(storage, cls.SCHAIN_HASH_SLOT,
+                           Web3.solidityKeccak(['string'], [schain_name]))
 
-    def _setup(self, deployer_address: str, schain_name: str) -> None:
-        self._write_uint256(self.INITIALIZED_SLOT, 1)
-        self._setup_role(self.ROLES_SLOT, self.ROLE_MEMBERS_SLOT, self.DEFAULT_ADMIN_ROLE, [deployer_address])
-        self._setup_role(self.ROLES_SLOT, self.ROLE_MEMBERS_SLOT, self.CHAIN_CONNECTOR_ROLE, [TOKEN_MANAGER_LINKER_ADDRESS])
-        self._write_address(self.KEY_STORAGE_SLOT, KEY_STORAGE_ADDRESS)
-        self._write_bytes32(self.SCHAIN_HASH_SLOT, Web3.solidityKeccak(['string'], [schain_name]))
-
-        connected_chain_info_slot = calculate_mapping_value_slot(
-            self.CONNECTED_CHAINS_SLOT, self.MAINNET_HASH, 'bytes32')
+        connected_chain_info_slot = Generator.calculate_mapping_value_slot(
+            cls.CONNECTED_CHAINS_SLOT, cls.MAINNET_HASH, 'bytes32')
         inited_slot = connected_chain_info_slot + 2
-        self._write_uint256(inited_slot, 1)
-        self._write_uint256(self.GAS_LIMIT_SLOT, self.GAS_LIMIT)
-        self._write_string(self.VERSION_SLOT, get_distribution('ima_predeployed').version)
-        registry_contracts_slot = calculate_mapping_value_slot(
-            self.REGISTRY_CONTRACTS_SLOT, self.ANY_SCHAIN, 'bytes32')
+        cls._write_uint256(storage, inited_slot, 1)
+        cls._write_uint256(storage, cls.GAS_LIMIT_SLOT, cls.GAS_LIMIT)
+        cls._write_string(storage, cls.VERSION_SLOT,
+                          get_distribution('ima_predeployed').version)
+        registry_contracts_slot = Generator.calculate_mapping_value_slot(
+            cls.REGISTRY_CONTRACTS_SLOT, cls.ANY_SCHAIN, 'bytes32')
         allowed_contracts = [
             TOKEN_MANAGER_ETH_ADDRESS,
             TOKEN_MANAGER_ERC20_ADDRESS,
@@ -92,7 +109,23 @@ def _setup(self, deployer_address: str, schain_name: str) -> None:
             COMMUNITY_LOCKER_ADDRESS]
         values_slot = registry_contracts_slot
         indexes_slot = registry_contracts_slot + 1
-        self._write_uint256(values_slot, len(allowed_contracts))
+        cls._write_uint256(storage, values_slot, len(allowed_contracts))
         for i, contract in enumerate(allowed_contracts):
-            self._write_address(calculate_array_value_slot(values_slot, i), contract)
-            self._write_uint256(calculate_mapping_value_slot(indexes_slot, int(contract, 16), 'uint256'), i + 1)
+            cls._write_address(
+                storage,
+                Generator.calculate_array_value_slot(values_slot, i),
+                contract)
+            cls._write_uint256(
+                storage,
+                Generator.calculate_mapping_value_slot(indexes_slot, int(contract, 16), 'uint256'),
+                i + 1)
+            
+        return storage
+
+
+class UpgradeableMessageProxyForSchainGenerator(UpgradeableContractGenerator):
+    """Generates upgradeable instance of MessageProxyForSchainUpgradeable
+    """
+
+    def __init__(self):
+        super().__init__(implementation_generator=MessageProxyForSchainGenerator())
diff --git a/proxy/predeployed/src/ima_predeployed/contracts/token_manager.py b/proxy/predeployed/src/ima_predeployed/contracts/token_manager.py
index 9b869cdee..317e5e05c 100644
--- a/proxy/predeployed/src/ima_predeployed/contracts/token_manager.py
+++ b/proxy/predeployed/src/ima_predeployed/contracts/token_manager.py
@@ -1,11 +1,19 @@
-from ima_predeployed.addresses import MESSAGE_PROXY_FOR_SCHAIN_ADDRESS, TOKEN_MANAGER_LINKER_ADDRESS, \
+from os.path import join, dirname
+from typing import Dict
+
+from predeployed_generator.upgradeable_contract_generator import UpgradeableContractGenerator
+
+from ..addresses import MESSAGE_PROXY_FOR_SCHAIN_ADDRESS, TOKEN_MANAGER_LINKER_ADDRESS, \
     COMMUNITY_LOCKER_ADDRESS
-from ima_predeployed.contract_generator import ContractGenerator, next_slot
+from predeployed_generator.openzeppelin.access_control_enumerable_generator import (
+    AccessControlEnumerableGenerator as Generator
+)
 from web3 import Web3
 
 
-class TokenManagerGenerator(ContractGenerator):
+class TokenManagerGenerator(Generator):
     ARTIFACT_FILENAME = "TokenManager.json"
+    META_FILENAME = "TokenManager.meta.json"
     DEFAULT_ADMIN_ROLE = (0).to_bytes(32, 'big')
     AUTOMATIC_DEPLOY_ROLE = Web3.solidityKeccak(['string'], ['AUTOMATIC_DEPLOY_ROLE'])
     TOKEN_REGISTRAR_ROLE = Web3.solidityKeccak(['string'], ['TOKEN_REGISTRAR_ROLE'])
@@ -43,26 +51,43 @@ class TokenManagerGenerator(ContractGenerator):
     ROLES_SLOT = 101
     ROLE_MEMBERS_SLOT = 151
     MESSAGE_PROXY_SLOT = 201
-    TOKEN_MANAGER_LINKER_SLOT = next_slot(MESSAGE_PROXY_SLOT)
-    COMMUNITY_LOCKER_SLOT = next_slot(TOKEN_MANAGER_LINKER_SLOT)
-    SCHAIN_HASH_SLOT = next_slot(COMMUNITY_LOCKER_SLOT)
-    DEPOSIT_BOX_SLOT = next_slot(SCHAIN_HASH_SLOT)
+    TOKEN_MANAGER_LINKER_SLOT = Generator.next_slot(MESSAGE_PROXY_SLOT)
+    COMMUNITY_LOCKER_SLOT = Generator.next_slot(TOKEN_MANAGER_LINKER_SLOT)
+    SCHAIN_HASH_SLOT = Generator.next_slot(COMMUNITY_LOCKER_SLOT)
+    DEPOSIT_BOX_SLOT = Generator.next_slot(SCHAIN_HASH_SLOT)
     AUTOMATIC_DEPLOY_SLOT = DEPOSIT_BOX_SLOT
-    TOKEN_MANAGERS_SLOT = next_slot(AUTOMATIC_DEPLOY_SLOT)
+    TOKEN_MANAGERS_SLOT = Generator.next_slot(AUTOMATIC_DEPLOY_SLOT)
+
+    def __init__(self):
+        generator = TokenManagerGenerator.from_hardhat_artifact(
+            join(dirname(__file__), '..', 'artifacts', self.ARTIFACT_FILENAME),
+            join(dirname(__file__), '..', 'artifacts', self.META_FILENAME))
+        super().__init__(bytecode=generator.bytecode, abi=generator.abi, meta=generator.meta)
+
+    @classmethod
+    def generate_storage(cls, **kwargs) -> Dict[str, str]:
+        deployer_address = kwargs['deployer_address']
+        schain_name = kwargs['schain_name']
+        deposit_box_address = kwargs['deposit_box_address']
+        storage: Dict[str, str] = {}
+        roles_slots = cls.RolesSlots(roles=cls.ROLES_SLOT, role_members=cls.ROLE_MEMBERS_SLOT)
+        
+        cls._write_uint256(storage, cls.INITIALIZED_SLOT, 1)
+        cls._setup_role(storage, roles_slots, cls.DEFAULT_ADMIN_ROLE, [deployer_address])
+        cls._setup_role(storage, roles_slots, cls.AUTOMATIC_DEPLOY_ROLE, [deployer_address])
+        cls._setup_role(storage, roles_slots, cls.TOKEN_REGISTRAR_ROLE, [deployer_address])
+        cls._write_address(storage, cls.MESSAGE_PROXY_SLOT, MESSAGE_PROXY_FOR_SCHAIN_ADDRESS)
+        cls._write_address(storage, cls.TOKEN_MANAGER_LINKER_SLOT, TOKEN_MANAGER_LINKER_ADDRESS)
+        cls._write_address(storage, cls.COMMUNITY_LOCKER_SLOT, COMMUNITY_LOCKER_ADDRESS)
+        cls._write_bytes32(storage, cls.SCHAIN_HASH_SLOT, Web3.solidityKeccak(['string'], [schain_name]))
+        cls._write_address(storage, cls.DEPOSIT_BOX_SLOT, deposit_box_address)
+        
+        return storage
 
-    def __init__(self, deployer_address: str, deposit_box_address: str, schain_name: str):
-        super().__init__(self.ARTIFACT_FILENAME)
-        self._setup_token_manager(deployer_address, deposit_box_address, schain_name)
 
-    # private
+class UpgradeableTokenManagerGenerator(UpgradeableContractGenerator):
+    """Generates upgradeable instance of TokenManagerUpgradeable
+    """
 
-    def _setup_token_manager(self, deployer_address: str, deposit_box_address: str, schain_name: str) -> None:
-        self._write_uint256(self.INITIALIZED_SLOT, 1)
-        self._setup_role(self.ROLES_SLOT, self.ROLE_MEMBERS_SLOT, self.DEFAULT_ADMIN_ROLE, [deployer_address])
-        self._setup_role(self.ROLES_SLOT, self.ROLE_MEMBERS_SLOT, self.AUTOMATIC_DEPLOY_ROLE, [deployer_address])
-        self._setup_role(self.ROLES_SLOT, self.ROLE_MEMBERS_SLOT, self.TOKEN_REGISTRAR_ROLE, [deployer_address])
-        self._write_address(self.MESSAGE_PROXY_SLOT, MESSAGE_PROXY_FOR_SCHAIN_ADDRESS)
-        self._write_address(self.TOKEN_MANAGER_LINKER_SLOT, TOKEN_MANAGER_LINKER_ADDRESS)
-        self._write_address(self.COMMUNITY_LOCKER_SLOT, COMMUNITY_LOCKER_ADDRESS)
-        self._write_bytes32(self.SCHAIN_HASH_SLOT, Web3.solidityKeccak(['string'], [schain_name]))
-        self._write_address(self.DEPOSIT_BOX_SLOT, deposit_box_address)
+    def __init__(self):
+        super().__init__(implementation_generator=TokenManagerGenerator())
diff --git a/proxy/predeployed/src/ima_predeployed/contracts/token_manager_erc1155.py b/proxy/predeployed/src/ima_predeployed/contracts/token_manager_erc1155.py
index 19e7c43cd..366771a2f 100644
--- a/proxy/predeployed/src/ima_predeployed/contracts/token_manager_erc1155.py
+++ b/proxy/predeployed/src/ima_predeployed/contracts/token_manager_erc1155.py
@@ -1,8 +1,11 @@
-from ima_predeployed.contracts.token_manager import TokenManagerGenerator
+from predeployed_generator.upgradeable_contract_generator import UpgradeableContractGenerator
+
+from .token_manager import TokenManagerGenerator
 
 
 class TokenManagerErc1155Generator(TokenManagerGenerator):
     ARTIFACT_FILENAME = "TokenManagerERC1155.json"
+    META_FILENAME = "TokenManagerERC1155.meta.json"
 
     # ---------- storage ----------
     # --------Initializable--------
@@ -35,5 +38,13 @@ class TokenManagerErc1155Generator(TokenManagerGenerator):
     # ------TokenManagerERC1155------
     # 207:  clonesErc1155
 
-    def __init__(self, deployer_address: str, deposit_box_address: str, schain_name: str):
-        super().__init__(deployer_address, deposit_box_address, schain_name)
+    def __init__(self):
+        super().__init__()
+
+
+class UpgradeableTokenManagerErc1155Generator(UpgradeableContractGenerator):
+    """Generates upgradeable instance of TokenManagerErc1155Upgradeable
+    """
+
+    def __init__(self):
+        super().__init__(implementation_generator=TokenManagerErc1155Generator())
diff --git a/proxy/predeployed/src/ima_predeployed/contracts/token_manager_erc20.py b/proxy/predeployed/src/ima_predeployed/contracts/token_manager_erc20.py
index 6ff7169e5..94a63c2b5 100644
--- a/proxy/predeployed/src/ima_predeployed/contracts/token_manager_erc20.py
+++ b/proxy/predeployed/src/ima_predeployed/contracts/token_manager_erc20.py
@@ -1,8 +1,11 @@
-from ima_predeployed.contracts.token_manager import TokenManagerGenerator
+from predeployed_generator.upgradeable_contract_generator import UpgradeableContractGenerator
+
+from .token_manager import TokenManagerGenerator
 
 
 class TokenManagerErc20Generator(TokenManagerGenerator):
     ARTIFACT_FILENAME = "TokenManagerERC20.json"
+    META_FILENAME = "TokenManagerERC20.meta.json"
 
     # ---------- storage ----------
     # --------Initializable--------
@@ -36,5 +39,13 @@ class TokenManagerErc20Generator(TokenManagerGenerator):
     # 207:  clonesErc20
     # 208:  totalSupplyOnMainnet
 
-    def __init__(self, deployer_address: str, deposit_box_address: str, schain_name: str):
-        super().__init__(deployer_address, deposit_box_address, schain_name)
+    def __init__(self):
+        super().__init__()
+
+
+class UpgradeableTokenManagerErc20Generator(UpgradeableContractGenerator):
+    """Generates upgradeable instance of TokenManagerErc20Upgradeable
+    """
+
+    def __init__(self):
+        super().__init__(implementation_generator=TokenManagerErc20Generator())
diff --git a/proxy/predeployed/src/ima_predeployed/contracts/token_manager_erc721.py b/proxy/predeployed/src/ima_predeployed/contracts/token_manager_erc721.py
index c52ea71d8..6a5d74239 100644
--- a/proxy/predeployed/src/ima_predeployed/contracts/token_manager_erc721.py
+++ b/proxy/predeployed/src/ima_predeployed/contracts/token_manager_erc721.py
@@ -1,8 +1,11 @@
-from ima_predeployed.contracts.token_manager import TokenManagerGenerator
+from predeployed_generator.upgradeable_contract_generator import UpgradeableContractGenerator
+
+from .token_manager import TokenManagerGenerator
 
 
 class TokenManagerErc721Generator(TokenManagerGenerator):
     ARTIFACT_FILENAME = "TokenManagerERC721.json"
+    META_FILENAME = "TokenManagerERC721.meta.json"
 
     # ---------- storage ----------
     # --------Initializable--------
@@ -35,5 +38,13 @@ class TokenManagerErc721Generator(TokenManagerGenerator):
     # ------TokenManagerERC721------
     # 207:  clonesErc721
 
-    def __init__(self, deployer_address: str, deposit_box_address: str, schain_name: str):
-        super().__init__(deployer_address, deposit_box_address, schain_name)
+    def __init__(self):
+        super().__init__()
+
+
+class UpgradeableTokenManagerErc721Generator(UpgradeableContractGenerator):
+    """Generates upgradeable instance of TokenManagerErc721Upgradeable
+    """
+
+    def __init__(self):
+        super().__init__(implementation_generator=TokenManagerErc721Generator())
diff --git a/proxy/predeployed/src/ima_predeployed/contracts/token_manager_erc721_with_metadata.py b/proxy/predeployed/src/ima_predeployed/contracts/token_manager_erc721_with_metadata.py
index 708f29b42..8ffe6758b 100644
--- a/proxy/predeployed/src/ima_predeployed/contracts/token_manager_erc721_with_metadata.py
+++ b/proxy/predeployed/src/ima_predeployed/contracts/token_manager_erc721_with_metadata.py
@@ -1,8 +1,11 @@
-from ima_predeployed.contracts.token_manager import TokenManagerGenerator
+from predeployed_generator.upgradeable_contract_generator import UpgradeableContractGenerator
+
+from .token_manager import TokenManagerGenerator
 
 
 class TokenManagerErc721WithMetadataGenerator(TokenManagerGenerator):
     ARTIFACT_FILENAME = "TokenManagerERC721WithMetadata.json"
+    META_FILENAME = "TokenManagerERC721WithMetadata.meta.json"
 
     # ---------- storage ----------
     # --------Initializable--------
@@ -36,5 +39,13 @@ class TokenManagerErc721WithMetadataGenerator(TokenManagerGenerator):
     # 207:  clonesErc721
     # ------TokenManagerERC721WithMetadata------
 
-    def __init__(self, deployer_address: str, deposit_box_address: str, schain_name: str):
-        super().__init__(deployer_address, deposit_box_address, schain_name)
+    def __init__(self):
+        super().__init__()
+
+
+class UpgradeableTokenManagerErc721WithMetadataGenerator(UpgradeableContractGenerator):
+    """Generates upgradeable instance of TokenManagerErc721WithMetadataUpgradeable
+    """
+
+    def __init__(self):
+        super().__init__(implementation_generator=TokenManagerErc721WithMetadataGenerator())
diff --git a/proxy/predeployed/src/ima_predeployed/contracts/token_manager_eth.py b/proxy/predeployed/src/ima_predeployed/contracts/token_manager_eth.py
index 479930539..7e3442066 100644
--- a/proxy/predeployed/src/ima_predeployed/contracts/token_manager_eth.py
+++ b/proxy/predeployed/src/ima_predeployed/contracts/token_manager_eth.py
@@ -1,10 +1,14 @@
-from ima_predeployed.addresses import ETH_ERC20_ADDRESS
-from ima_predeployed.contract_generator import next_slot
-from ima_predeployed.contracts.token_manager import TokenManagerGenerator
+from typing import Dict
+
+from predeployed_generator.upgradeable_contract_generator import UpgradeableContractGenerator
+
+from ..addresses import ETH_ERC20_ADDRESS
+from .token_manager import TokenManagerGenerator
 
 
 class TokenManagerEthGenerator(TokenManagerGenerator):
     ARTIFACT_FILENAME = "TokenManagerEth.json"
+    META_FILENAME = "TokenManagerEth.meta.json"
 
     # ---------- storage ----------
     # --------Initializable--------
@@ -37,13 +41,21 @@ class TokenManagerEthGenerator(TokenManagerGenerator):
     # -------TokenManagerEth-------
     # 207:  ethErc20
 
-    ETH_ERC_20_SLOT = next_slot(TokenManagerGenerator.TOKEN_MANAGERS_SLOT)
+    ETH_ERC_20_SLOT = TokenManagerGenerator.next_slot(TokenManagerGenerator.TOKEN_MANAGERS_SLOT)
+
+    def __init__(self):
+        super().__init__()
+
+    @classmethod
+    def generate_storage(cls, **kwargs) -> Dict[str, str]:
+        storage = super().generate_storage(**kwargs)
+        cls._write_address(storage, cls.ETH_ERC_20_SLOT, ETH_ERC20_ADDRESS)
+        return storage
 
-    def __init__(self, deployer_address: str, deposit_box_address: str, schain_name: str):
-        super().__init__(deployer_address, deposit_box_address, schain_name)
-        self._setup()
 
-    # private
+class UpgradeableTokenManagerEthGenerator(UpgradeableContractGenerator):
+    """Generates upgradeable instance of TokenManagerEthUpgradeable
+    """
 
-    def _setup(self) -> None:
-        self._write_address(self.ETH_ERC_20_SLOT, ETH_ERC20_ADDRESS)
+    def __init__(self):
+        super().__init__(implementation_generator=TokenManagerEthGenerator())
diff --git a/proxy/predeployed/src/ima_predeployed/contracts/token_manager_linker.py b/proxy/predeployed/src/ima_predeployed/contracts/token_manager_linker.py
index cb7f7aaa2..9f10b54af 100644
--- a/proxy/predeployed/src/ima_predeployed/contracts/token_manager_linker.py
+++ b/proxy/predeployed/src/ima_predeployed/contracts/token_manager_linker.py
@@ -1,12 +1,21 @@
-from ima_predeployed.addresses import MESSAGE_PROXY_FOR_SCHAIN_ADDRESS, TOKEN_MANAGER_ERC20_ADDRESS, \
-    TOKEN_MANAGER_ERC721_ADDRESS, TOKEN_MANAGER_ETH_ADDRESS, TOKEN_MANAGER_ERC1155_ADDRESS, \
-    TOKEN_MANAGER_ERC721_WITH_METADATA_ADDRESS
+from os.path import join, dirname
+from typing import Dict
+
+from predeployed_generator.openzeppelin.access_control_enumerable_generator import (
+    AccessControlEnumerableGenerator as Generator
+)
+from predeployed_generator.upgradeable_contract_generator import UpgradeableContractGenerator
+
+from ..addresses import (
+    MESSAGE_PROXY_FOR_SCHAIN_ADDRESS, TOKEN_MANAGER_ERC20_ADDRESS,
+    TOKEN_MANAGER_ERC721_ADDRESS, TOKEN_MANAGER_ETH_ADDRESS,
+    TOKEN_MANAGER_ERC1155_ADDRESS, TOKEN_MANAGER_ERC721_WITH_METADATA_ADDRESS)
 from web3 import Web3
-from ..contract_generator import ContractGenerator, next_slot
 
 
-class TokenManagerLinkerGenerator(ContractGenerator):
+class TokenManagerLinkerGenerator(Generator):
     ARTIFACT_FILENAME = "TokenManagerLinker.json"
+    META_FILENAME = "TokenManagerLinker.meta.json"
     DEFAULT_ADMIN_ROLE = (0).to_bytes(32, 'big')
     REGISTRAR_ROLE = Web3.solidityKeccak(['string'], ['REGISTRAR_ROLE'])
 
@@ -41,25 +50,41 @@ class TokenManagerLinkerGenerator(ContractGenerator):
     ROLES_SLOT = 101
     ROLE_MEMBERS_SLOT = 151
     MESSAGE_PROXY_SLOT = 201
-    LINKER_ADDRESS_SLOT = next_slot(MESSAGE_PROXY_SLOT)
-    TOKEN_MANAGERS_SLOT = next_slot(LINKER_ADDRESS_SLOT)
+    LINKER_ADDRESS_SLOT = Generator.next_slot(MESSAGE_PROXY_SLOT)
+    TOKEN_MANAGERS_SLOT = Generator.next_slot(LINKER_ADDRESS_SLOT)
 
-    def __init__(self, deployer_address: str, linker_address: str):
-        super().__init__(self.ARTIFACT_FILENAME)
-        self._setup(deployer_address, linker_address)
+    def __init__(self):
+        generator = TokenManagerLinkerGenerator.from_hardhat_artifact(
+            join(dirname(__file__), '..', 'artifacts', self.ARTIFACT_FILENAME),
+            join(dirname(__file__), '..', 'artifacts', self.META_FILENAME))
+        super().__init__(bytecode=generator.bytecode, abi=generator.abi, meta=generator.meta)
 
-    # private
+    @classmethod
+    def generate_storage(cls, **kwargs) -> Dict[str, str]:
+        deployer_address = kwargs['deployer_address']
+        linker_addres = kwargs['linker_address']
+        storage: Dict[str, str] = {}
+        roles_slots = cls.RolesSlots(roles=cls.ROLES_SLOT, role_members=cls.ROLE_MEMBERS_SLOT)
 
-    def _setup(self, deployer_address: str, linker_addres: str) -> None:
-        self._write_uint256(self.INITIALIZED_SLOT, 1)
-        self._setup_role(self.ROLES_SLOT, self.ROLE_MEMBERS_SLOT, self.DEFAULT_ADMIN_ROLE, [deployer_address])
-        self._setup_role(self.ROLES_SLOT, self.ROLE_MEMBERS_SLOT, self.REGISTRAR_ROLE, [deployer_address])
-        self._write_address(self.MESSAGE_PROXY_SLOT, MESSAGE_PROXY_FOR_SCHAIN_ADDRESS)
-        self._write_address(self.LINKER_ADDRESS_SLOT, linker_addres)
-        self._write_addresses_array(
-            self.TOKEN_MANAGERS_SLOT, [
+        cls._write_uint256(storage, cls.INITIALIZED_SLOT, 1)
+        cls._setup_role(storage, roles_slots, cls.DEFAULT_ADMIN_ROLE, [deployer_address])
+        cls._setup_role(storage, roles_slots, cls.REGISTRAR_ROLE, [deployer_address])
+        cls._write_address(storage, cls.MESSAGE_PROXY_SLOT, MESSAGE_PROXY_FOR_SCHAIN_ADDRESS)
+        cls._write_address(storage, cls.LINKER_ADDRESS_SLOT, linker_addres)
+        cls._write_addresses_array(
+            storage,
+            cls.TOKEN_MANAGERS_SLOT, [
                 TOKEN_MANAGER_ETH_ADDRESS,
                 TOKEN_MANAGER_ERC20_ADDRESS,
                 TOKEN_MANAGER_ERC721_ADDRESS,
                 TOKEN_MANAGER_ERC1155_ADDRESS,
                 TOKEN_MANAGER_ERC721_WITH_METADATA_ADDRESS])
+        return storage
+
+
+class UpgradeableTokenManagerLinkerGenerator(UpgradeableContractGenerator):
+    """Generates upgradeable instance of TokenManagerLinkerUpgradeable
+    """
+
+    def __init__(self):
+        super().__init__(implementation_generator=TokenManagerLinkerGenerator())
diff --git a/proxy/predeployed/src/ima_predeployed/generator.py b/proxy/predeployed/src/ima_predeployed/generator.py
index 7fdd60c69..d74f8f360 100644
--- a/proxy/predeployed/src/ima_predeployed/generator.py
+++ b/proxy/predeployed/src/ima_predeployed/generator.py
@@ -1,137 +1,143 @@
 import json
 import os
 
-from ima_predeployed.contracts.eth_erc20 import EthErc20Generator
-from ima_predeployed.contracts.token_manager_erc20 import TokenManagerErc20Generator
-from ima_predeployed.contracts.token_manager_erc721 import TokenManagerErc721Generator
-from ima_predeployed.contracts.token_manager_erc1155 import TokenManagerErc1155Generator
-from ima_predeployed.contracts.token_manager_erc721_with_metadata import TokenManagerErc721WithMetadataGenerator
-from ima_predeployed.contracts.token_manager_eth import TokenManagerEthGenerator
-from ima_predeployed.contracts.token_manager_linker import TokenManagerLinkerGenerator
-from .contracts.community_locker import CommunityLockerGenerator
-from .contract_generator import ContractGenerator
-from .contracts.key_storage import KeyStorageGenerator
-from .upgradeable_contract_generator import UpgradeableContractGenerator
-from .contracts.proxy_admin import ProxyAdminGenerator
-from .contracts.message_proxy_for_schain import MessageProxyForSchainGenerator
-from .addresses import \
-    PROXY_ADMIN_ADDRESS, \
-    MESSAGE_PROXY_FOR_SCHAIN_ADDRESS, \
-    MESSAGE_PROXY_FOR_SCHAIN_IMPLEMENTATION_ADDRESS, KEY_STORAGE_IMPLEMENTATION_ADDRESS, KEY_STORAGE_ADDRESS, \
-    COMMUNITY_LOCKER_IMPLEMENTATION_ADDRESS, COMMUNITY_LOCKER_ADDRESS, \
-    TOKEN_MANAGER_ERC1155_ADDRESS, TOKEN_MANAGER_ERC1155_IMPLEMENTATION_ADDRESS, TOKEN_MANAGER_LINKER_IMPLEMENTATION_ADDRESS, \
-    TOKEN_MANAGER_LINKER_ADDRESS, TOKEN_MANAGER_ETH_IMPLEMENTATION_ADDRESS, TOKEN_MANAGER_ETH_ADDRESS, \
-    TOKEN_MANAGER_ERC20_IMPLEMENTATION_ADDRESS, TOKEN_MANAGER_ERC20_ADDRESS, \
-    TOKEN_MANAGER_ERC721_IMPLEMENTATION_ADDRESS, TOKEN_MANAGER_ERC721_ADDRESS, ETH_ERC20_IMPLEMENTATION_ADDRESS, \
+from predeployed_generator.openzeppelin.proxy_admin_generator import ProxyAdminGenerator
+
+from .contracts.erc1155_on_chain import Erc1155OnChainGenerator
+from .contracts.erc20_on_chain import Erc20OnChainGenerator
+from .contracts.erc721_on_chain import Erc721OnChainGenerator
+from .contracts.eth_erc20 import UpgradeableEthErc20Generator, EthErc20Generator
+from .contracts.token_manager_erc20 import UpgradeableTokenManagerErc20Generator, TokenManagerErc20Generator
+from .contracts.token_manager_erc721 import UpgradeableTokenManagerErc721Generator, TokenManagerErc721Generator
+from .contracts.token_manager_erc1155 import UpgradeableTokenManagerErc1155Generator, TokenManagerErc1155Generator
+from .contracts.token_manager_erc721_with_metadata import (
+    UpgradeableTokenManagerErc721WithMetadataGenerator as UpgradeableTokenManagerErc721WMGenerator,
+    TokenManagerErc721WithMetadataGenerator as TokenManagerErc721WMGenerator
+)
+from .contracts.token_manager_eth import UpgradeableTokenManagerEthGenerator, TokenManagerEthGenerator
+from .contracts.token_manager_linker import UpgradeableTokenManagerLinkerGenerator, TokenManagerLinkerGenerator
+from .contracts.community_locker import UpgradeableCommunityLockerGenerator, CommunityLockerGenerator
+from .contracts.key_storage import UpgradeableKeyStorageGenerator, KeyStorageGenerator
+from .contracts.message_proxy_for_schain import UpgradeableMessageProxyForSchainGenerator, \
+    MessageProxyForSchainGenerator
+from .addresses import (
+    PROXY_ADMIN_ADDRESS, MESSAGE_PROXY_FOR_SCHAIN_ADDRESS,
+    MESSAGE_PROXY_FOR_SCHAIN_IMPLEMENTATION_ADDRESS, KEY_STORAGE_IMPLEMENTATION_ADDRESS,
+    KEY_STORAGE_ADDRESS, COMMUNITY_LOCKER_IMPLEMENTATION_ADDRESS, COMMUNITY_LOCKER_ADDRESS,
+    TOKEN_MANAGER_ERC1155_ADDRESS, TOKEN_MANAGER_ERC1155_IMPLEMENTATION_ADDRESS,
+    TOKEN_MANAGER_LINKER_IMPLEMENTATION_ADDRESS, TOKEN_MANAGER_LINKER_ADDRESS,
+    TOKEN_MANAGER_ETH_IMPLEMENTATION_ADDRESS, TOKEN_MANAGER_ETH_ADDRESS,
+    TOKEN_MANAGER_ERC20_IMPLEMENTATION_ADDRESS, TOKEN_MANAGER_ERC20_ADDRESS,
+    TOKEN_MANAGER_ERC721_IMPLEMENTATION_ADDRESS, TOKEN_MANAGER_ERC721_ADDRESS, ETH_ERC20_IMPLEMENTATION_ADDRESS,
     ETH_ERC20_ADDRESS, TOKEN_MANAGER_ERC721_WITH_METADATA_IMPLEMENTATION_ADDRESS, TOKEN_MANAGER_ERC721_WITH_METADATA_ADDRESS
+)
 
 
 def generate_contracts(
         owner_address: str,
         schain_name: str,
         contracts_on_mainnet: dict) -> dict:
-    proxy_admin = ProxyAdminGenerator(owner_address)
-
-    message_proxy_for_schain_implementation = ContractGenerator(MessageProxyForSchainGenerator.ARTIFACT_FILENAME)
-    message_proxy_for_schain = UpgradeableContractGenerator(
-        MESSAGE_PROXY_FOR_SCHAIN_IMPLEMENTATION_ADDRESS,
-        PROXY_ADMIN_ADDRESS,
-        MessageProxyForSchainGenerator(owner_address, schain_name))
-
-    key_storage_implementation = ContractGenerator(KeyStorageGenerator.ARTIFACT_FILENAME)
-    key_storage = UpgradeableContractGenerator(
-        KEY_STORAGE_IMPLEMENTATION_ADDRESS,
-        PROXY_ADMIN_ADDRESS,
-        KeyStorageGenerator(owner_address))
-
-    community_locker_implementation = ContractGenerator(CommunityLockerGenerator.ARTIFACT_FILENAME)
-    community_locker = UpgradeableContractGenerator(
-        COMMUNITY_LOCKER_IMPLEMENTATION_ADDRESS,
-        PROXY_ADMIN_ADDRESS,
-        CommunityLockerGenerator(owner_address, schain_name, contracts_on_mainnet['community_pool_address'])
+    proxy_admin = ProxyAdminGenerator().generate_allocation(
+        contract_address=PROXY_ADMIN_ADDRESS,
+        owner_address=owner_address
     )
 
-    token_manager_linker_implementation = ContractGenerator(TokenManagerLinkerGenerator.ARTIFACT_FILENAME)
-    token_manager_linker = UpgradeableContractGenerator(
-        TOKEN_MANAGER_LINKER_IMPLEMENTATION_ADDRESS,
-        PROXY_ADMIN_ADDRESS,
-        TokenManagerLinkerGenerator(owner_address, contracts_on_mainnet['linker_address'])
+    message_proxy_for_schain = UpgradeableMessageProxyForSchainGenerator().generate_allocation(
+        proxy_admin_address=PROXY_ADMIN_ADDRESS,
+        contract_address=MESSAGE_PROXY_FOR_SCHAIN_ADDRESS,
+        implementation_address=MESSAGE_PROXY_FOR_SCHAIN_IMPLEMENTATION_ADDRESS,
+        deployer_address=owner_address,
+        schain_name=schain_name
     )
 
-    token_manager_eth_implementation = ContractGenerator(TokenManagerEthGenerator.ARTIFACT_FILENAME)
-    token_manager_eth = UpgradeableContractGenerator(
-        TOKEN_MANAGER_ETH_IMPLEMENTATION_ADDRESS,
-        PROXY_ADMIN_ADDRESS,
-        TokenManagerEthGenerator(owner_address, contracts_on_mainnet['deposit_box_eth_address'], schain_name)
+    key_storage = UpgradeableKeyStorageGenerator().generate_allocation(
+        proxy_admin_address=PROXY_ADMIN_ADDRESS,
+        contract_address=KEY_STORAGE_ADDRESS,
+        implementation_address=KEY_STORAGE_IMPLEMENTATION_ADDRESS,
+        deployer_address=owner_address
     )
 
-    token_manager_erc20_implementation = ContractGenerator(TokenManagerErc20Generator.ARTIFACT_FILENAME)
-    token_manager_erc20 = UpgradeableContractGenerator(
-        TOKEN_MANAGER_ERC20_IMPLEMENTATION_ADDRESS,
-        PROXY_ADMIN_ADDRESS,
-        TokenManagerErc20Generator(owner_address, contracts_on_mainnet['deposit_box_erc20_address'], schain_name)
+    community_locker = UpgradeableCommunityLockerGenerator().generate_allocation(
+        proxy_admin_address=PROXY_ADMIN_ADDRESS,
+        contract_address=COMMUNITY_LOCKER_ADDRESS,
+        implementation_address=COMMUNITY_LOCKER_IMPLEMENTATION_ADDRESS,
+        deployer_address=owner_address,
+        schain_name=schain_name,
+        community_pool_address=contracts_on_mainnet['community_pool_address']
     )
 
-    token_manager_erc721_implementation = ContractGenerator(TokenManagerErc721Generator.ARTIFACT_FILENAME)
-    token_manager_erc721 = UpgradeableContractGenerator(
-        TOKEN_MANAGER_ERC721_IMPLEMENTATION_ADDRESS,
-        PROXY_ADMIN_ADDRESS,
-        TokenManagerErc721Generator(owner_address, contracts_on_mainnet['deposit_box_erc721_address'], schain_name)
+    token_manager_linker = UpgradeableTokenManagerLinkerGenerator().generate_allocation(
+        proxy_admin_address=PROXY_ADMIN_ADDRESS,
+        contract_address=TOKEN_MANAGER_LINKER_ADDRESS,
+        implementation_address=TOKEN_MANAGER_LINKER_IMPLEMENTATION_ADDRESS,
+        deployer_address=owner_address,
+        linker_address=contracts_on_mainnet['linker_address']
     )
 
-    token_manager_erc1155_implementation = ContractGenerator(TokenManagerErc1155Generator.ARTIFACT_FILENAME)
-    token_manager_erc1155 = UpgradeableContractGenerator(
-        TOKEN_MANAGER_ERC1155_IMPLEMENTATION_ADDRESS,
-        PROXY_ADMIN_ADDRESS,
-        TokenManagerErc1155Generator(owner_address, contracts_on_mainnet['deposit_box_erc1155_address'], schain_name)
+    token_manager_eth = UpgradeableTokenManagerEthGenerator().generate_allocation(
+        proxy_admin_address=PROXY_ADMIN_ADDRESS,
+        contract_address=TOKEN_MANAGER_ETH_ADDRESS,
+        implementation_address=TOKEN_MANAGER_ETH_IMPLEMENTATION_ADDRESS,
+        deployer_address=owner_address,
+        schain_name=schain_name,
+        deposit_box_address=contracts_on_mainnet['deposit_box_eth_address']
     )
 
-    token_manager_erc721_with_metadata_implementation = ContractGenerator(TokenManagerErc721WithMetadataGenerator.ARTIFACT_FILENAME)
-    token_manager_erc721_with_metadata = UpgradeableContractGenerator(
-        TOKEN_MANAGER_ERC721_WITH_METADATA_IMPLEMENTATION_ADDRESS,
-        PROXY_ADMIN_ADDRESS,
-        TokenManagerErc721WithMetadataGenerator(owner_address, contracts_on_mainnet['deposit_box_erc721_with_metadata_address'], schain_name)
+    token_manager_erc20 = UpgradeableTokenManagerErc20Generator().generate_allocation(
+        proxy_admin_address=PROXY_ADMIN_ADDRESS,
+        contract_address=TOKEN_MANAGER_ERC20_ADDRESS,
+        implementation_address=TOKEN_MANAGER_ERC20_IMPLEMENTATION_ADDRESS,
+        deployer_address=owner_address,
+        schain_name=schain_name,
+        deposit_box_address=contracts_on_mainnet['deposit_box_erc20_address']
     )
 
-    eth_erc20_implementation = ContractGenerator(EthErc20Generator.ARTIFACT_FILENAME)
-    eth_erc20 = UpgradeableContractGenerator(
-        ETH_ERC20_IMPLEMENTATION_ADDRESS,
-        PROXY_ADMIN_ADDRESS,
-        EthErc20Generator(owner_address)
+    token_manager_erc721 = UpgradeableTokenManagerErc721Generator().generate_allocation(
+        proxy_admin_address=PROXY_ADMIN_ADDRESS,
+        contract_address=TOKEN_MANAGER_ERC721_ADDRESS,
+        implementation_address=TOKEN_MANAGER_ERC721_IMPLEMENTATION_ADDRESS,
+        deployer_address=owner_address,
+        schain_name=schain_name,
+        deposit_box_address=contracts_on_mainnet['deposit_box_erc721_address']
     )
 
-    return {
-        PROXY_ADMIN_ADDRESS: proxy_admin.generate_contract(),
-
-        MESSAGE_PROXY_FOR_SCHAIN_ADDRESS: message_proxy_for_schain.generate_contract(),
-        MESSAGE_PROXY_FOR_SCHAIN_IMPLEMENTATION_ADDRESS: message_proxy_for_schain_implementation.generate_contract(),
-
-        KEY_STORAGE_ADDRESS: key_storage.generate_contract(),
-        KEY_STORAGE_IMPLEMENTATION_ADDRESS: key_storage_implementation.generate_contract(),
-
-        COMMUNITY_LOCKER_ADDRESS: community_locker.generate_contract(),
-        COMMUNITY_LOCKER_IMPLEMENTATION_ADDRESS: community_locker_implementation.generate_contract(),
-
-        TOKEN_MANAGER_LINKER_ADDRESS: token_manager_linker.generate_contract(),
-        TOKEN_MANAGER_LINKER_IMPLEMENTATION_ADDRESS: token_manager_linker_implementation.generate_contract(),
-
-        TOKEN_MANAGER_ETH_ADDRESS: token_manager_eth.generate_contract(),
-        TOKEN_MANAGER_ETH_IMPLEMENTATION_ADDRESS: token_manager_eth_implementation.generate_contract(),
-
-        TOKEN_MANAGER_ERC20_ADDRESS: token_manager_erc20.generate_contract(),
-        TOKEN_MANAGER_ERC20_IMPLEMENTATION_ADDRESS: token_manager_erc20_implementation.generate_contract(),
-
-        TOKEN_MANAGER_ERC721_ADDRESS: token_manager_erc721.generate_contract(),
-        TOKEN_MANAGER_ERC721_IMPLEMENTATION_ADDRESS: token_manager_erc721_implementation.generate_contract(),
+    token_manager_erc1155 = UpgradeableTokenManagerErc1155Generator().generate_allocation(
+        proxy_admin_address=PROXY_ADMIN_ADDRESS,
+        contract_address=TOKEN_MANAGER_ERC1155_ADDRESS,
+        implementation_address=TOKEN_MANAGER_ERC1155_IMPLEMENTATION_ADDRESS,
+        deployer_address=owner_address,
+        schain_name=schain_name,
+        deposit_box_address=contracts_on_mainnet['deposit_box_erc1155_address']
+    )
 
-        TOKEN_MANAGER_ERC1155_ADDRESS: token_manager_erc1155.generate_contract(),
-        TOKEN_MANAGER_ERC1155_IMPLEMENTATION_ADDRESS: token_manager_erc1155_implementation.generate_contract(),
+    token_manager_erc1155_wm = UpgradeableTokenManagerErc721WMGenerator().generate_allocation(
+        proxy_admin_address=PROXY_ADMIN_ADDRESS,
+        contract_address=TOKEN_MANAGER_ERC721_WITH_METADATA_ADDRESS,
+        implementation_address=TOKEN_MANAGER_ERC721_WITH_METADATA_IMPLEMENTATION_ADDRESS,
+        deployer_address=owner_address,
+        schain_name=schain_name,
+        deposit_box_address=contracts_on_mainnet['deposit_box_erc721_with_metadata_address']
+    )
 
-        TOKEN_MANAGER_ERC721_WITH_METADATA_ADDRESS: token_manager_erc721_with_metadata.generate_contract(),
-        TOKEN_MANAGER_ERC721_WITH_METADATA_IMPLEMENTATION_ADDRESS: token_manager_erc721_with_metadata_implementation.generate_contract(),
+    eth_erc20 = UpgradeableEthErc20Generator().generate_allocation(
+        proxy_admin_address=PROXY_ADMIN_ADDRESS,
+        contract_address=ETH_ERC20_ADDRESS,
+        implementation_address=ETH_ERC20_IMPLEMENTATION_ADDRESS,
+        deployer_address=owner_address
+    )
 
-        ETH_ERC20_ADDRESS: eth_erc20.generate_contract(),
-        ETH_ERC20_IMPLEMENTATION_ADDRESS: eth_erc20_implementation.generate_contract()
+    return {
+        **proxy_admin,
+        **message_proxy_for_schain,
+        **key_storage,
+        **community_locker,
+        **token_manager_linker,
+        **token_manager_eth,
+        **token_manager_erc20,
+        **token_manager_erc721,
+        **token_manager_erc1155,
+        **token_manager_erc1155_wm,
+        **eth_erc20
     }
 
 
@@ -147,55 +153,81 @@ def generate_abi() -> dict:
         **generate_abi_key(
             'proxy_admin',
             PROXY_ADMIN_ADDRESS,
-            ContractGenerator(ProxyAdminGenerator.ARTIFACT_FILENAME).abi),
+            ProxyAdminGenerator().get_abi()),
         **generate_abi_key(
             'message_proxy_chain',
             MESSAGE_PROXY_FOR_SCHAIN_ADDRESS,
-            ContractGenerator(MessageProxyForSchainGenerator.ARTIFACT_FILENAME).abi),
+            MessageProxyForSchainGenerator().get_abi()),
         **generate_abi_key(
             'key_storage',
             KEY_STORAGE_ADDRESS,
-            ContractGenerator(KeyStorageGenerator.ARTIFACT_FILENAME).abi),
+            KeyStorageGenerator().get_abi()),
         **generate_abi_key(
             'community_locker',
             COMMUNITY_LOCKER_ADDRESS,
-            ContractGenerator(CommunityLockerGenerator.ARTIFACT_FILENAME).abi),
+            CommunityLockerGenerator().get_abi()),
         **generate_abi_key(
             'token_manager_linker',
             TOKEN_MANAGER_LINKER_ADDRESS,
-            ContractGenerator(TokenManagerLinkerGenerator.ARTIFACT_FILENAME).abi),
+            TokenManagerLinkerGenerator().get_abi()),
         **generate_abi_key(
             'token_manager_eth',
             TOKEN_MANAGER_ETH_ADDRESS,
-            ContractGenerator(TokenManagerEthGenerator.ARTIFACT_FILENAME).abi),
+            TokenManagerEthGenerator().get_abi()),
         **generate_abi_key(
             'token_manager_erc20',
             TOKEN_MANAGER_ERC20_ADDRESS,
-            ContractGenerator(TokenManagerErc20Generator.ARTIFACT_FILENAME).abi),
+            TokenManagerErc20Generator().get_abi()),
         **generate_abi_key(
             'token_manager_erc721',
             TOKEN_MANAGER_ERC721_ADDRESS,
-            ContractGenerator(TokenManagerErc721Generator.ARTIFACT_FILENAME).abi),
+            TokenManagerErc721Generator().get_abi()),
         **generate_abi_key(
             'token_manager_erc1155',
             TOKEN_MANAGER_ERC1155_ADDRESS,
-            ContractGenerator(TokenManagerErc1155Generator.ARTIFACT_FILENAME).abi),
+            TokenManagerErc1155Generator().get_abi()),
         **generate_abi_key(
             'token_manager_erc721_with_metadata',
             TOKEN_MANAGER_ERC721_WITH_METADATA_ADDRESS,
-            ContractGenerator(TokenManagerErc721WithMetadataGenerator.ARTIFACT_FILENAME).abi),
+            TokenManagerErc721WMGenerator().get_abi()),
         **generate_abi_key(
             'eth_erc20',
             ETH_ERC20_ADDRESS,
-            ContractGenerator(EthErc20Generator.ARTIFACT_FILENAME).abi),
+            EthErc20Generator().get_abi()),
         **{
-            'ERC20OnChain_abi': ContractGenerator('ERC20OnChain.json').abi,
-            'ERC721OnChain_abi': ContractGenerator('ERC721OnChain.json').abi,
-            'ERC1155OnChain_abi': ContractGenerator('ERC1155OnChain.json').abi
+            'ERC20OnChain_abi': Erc20OnChainGenerator().get_abi(),
+            'ERC721OnChain_abi': Erc721OnChainGenerator().get_abi(),
+            'ERC1155OnChain_abi': Erc1155OnChainGenerator().get_abi()
         }
     }
 
 
+def generate_meta() -> dict:
+    return {
+        PROXY_ADMIN_ADDRESS: ProxyAdminGenerator().get_meta(),
+        MESSAGE_PROXY_FOR_SCHAIN_ADDRESS: UpgradeableMessageProxyForSchainGenerator().get_meta(),
+        MESSAGE_PROXY_FOR_SCHAIN_IMPLEMENTATION_ADDRESS: MessageProxyForSchainGenerator().get_meta(),
+        KEY_STORAGE_ADDRESS: UpgradeableKeyStorageGenerator().get_meta(),
+        KEY_STORAGE_IMPLEMENTATION_ADDRESS: KeyStorageGenerator().get_meta(),
+        COMMUNITY_LOCKER_ADDRESS: UpgradeableCommunityLockerGenerator().get_meta(),
+        COMMUNITY_LOCKER_IMPLEMENTATION_ADDRESS: CommunityLockerGenerator().get_meta(),
+        TOKEN_MANAGER_LINKER_ADDRESS: UpgradeableTokenManagerLinkerGenerator().get_meta(),
+        TOKEN_MANAGER_LINKER_IMPLEMENTATION_ADDRESS: TokenManagerLinkerGenerator().get_meta(),
+        TOKEN_MANAGER_ETH_ADDRESS: UpgradeableTokenManagerEthGenerator().get_meta(),
+        TOKEN_MANAGER_ETH_IMPLEMENTATION_ADDRESS: TokenManagerEthGenerator().get_meta(),
+        TOKEN_MANAGER_ERC20_ADDRESS: UpgradeableTokenManagerErc20Generator().get_meta(),
+        TOKEN_MANAGER_ERC20_IMPLEMENTATION_ADDRESS: TokenManagerErc20Generator().get_meta(),
+        TOKEN_MANAGER_ERC721_ADDRESS: UpgradeableTokenManagerErc721Generator().get_meta(),
+        TOKEN_MANAGER_ERC721_IMPLEMENTATION_ADDRESS: TokenManagerErc721Generator().get_meta(),
+        TOKEN_MANAGER_ERC1155_ADDRESS: UpgradeableTokenManagerErc1155Generator().get_meta(),
+        TOKEN_MANAGER_ERC1155_IMPLEMENTATION_ADDRESS: TokenManagerErc1155Generator().get_meta(),
+        TOKEN_MANAGER_ERC721_WITH_METADATA_ADDRESS: UpgradeableTokenManagerErc721WMGenerator().get_meta(),
+        TOKEN_MANAGER_ERC721_WITH_METADATA_IMPLEMENTATION_ADDRESS: TokenManagerErc721WMGenerator().get_meta(),
+        ETH_ERC20_ADDRESS: UpgradeableTokenManagerErc20Generator().get_meta(),
+        ETH_ERC20_IMPLEMENTATION_ADDRESS: TokenManagerErc20Generator().get_meta()
+    }
+
+
 def main() -> None:
     contracts_dir = os.path.join(os.path.dirname(__file__), 'artifacts')
     proxy_admin_path = os.path.join(contracts_dir, 'ProxyAdmin.json')    
diff --git a/proxy/scripts/requirements.txt b/proxy/scripts/requirements.txt
index 279067ac0..61cce5d71 100644
--- a/proxy/scripts/requirements.txt
+++ b/proxy/scripts/requirements.txt
@@ -1,1 +1,1 @@
-slither-analyzer==0.8.0
+slither-analyzer==0.8.3
diff --git a/proxy/scripts/updateManifest.py b/proxy/scripts/updateManifest.py
new file mode 100755
index 000000000..aabab63d9
--- /dev/null
+++ b/proxy/scripts/updateManifest.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+'''The script updates manifest file to fix _initialized type after openzeppelin contracts upgrade'''
+
+import sys
+import json
+
+
+def main():
+    manifest_filename = sys.argv[1]
+    with open(manifest_filename) as f:
+        manifest = json.load(f)
+        for impl in manifest['impls'].keys():
+            storage = manifest['impls'][impl]['layout']['storage']
+            for slot in storage:
+                if slot['contract'] == 'Initializable' and slot['label'] == '_initialized' and slot['type'] == 't_bool':
+                    slot['type'] = 't_uint8'
+    with open(manifest_filename, 'w') as f:
+        f.write(json.dumps(manifest, indent=2))
+
+if __name__ == '__main__':
+    main()
\ No newline at end of file
diff --git a/proxy/yarn.lock b/proxy/yarn.lock
index 56b239b1a..c722628ae 100644
--- a/proxy/yarn.lock
+++ b/proxy/yarn.lock
@@ -602,10 +602,10 @@
   dependencies:
     "@types/bignumber.js" "^5.0.0"
 
-"@openzeppelin/contracts-upgradeable@^4.3.2":
-  version "4.3.2"
-  resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.3.2.tgz#92df481362e366c388fc02133cf793029c744cea"
-  integrity sha512-i/pOaOtcqDk4UqsrOv735uYyTbn6dvfiuVu5hstsgV6c4ZKUtu88/31zT2BzkCg+3JfcwOfgg2TtRKVKKZIGkQ==
+"@openzeppelin/contracts-upgradeable@^4.7.1":
+  version "4.7.1"
+  resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.7.1.tgz#f63fc384255d6ac139e0a2561aa207fd7c14183c"
+  integrity sha512-5EFiZld3DYFd8aTL8eeMnhnaWh1/oXLXFNuFMrgF3b1DNPshF3LCyO7VR6lc+gac2URJ0BlVcZoCfkk/3MoEfg==
 
 "@openzeppelin/hardhat-upgrades@^1.9.0":
   version "1.10.0"
@@ -757,10 +757,10 @@
   resolved "https://registry.yarnpkg.com/@skalenetwork/etherbase-interfaces/-/etherbase-interfaces-0.0.1-develop.20.tgz#33f61e18d695fd47063aa39dce4df335d26b9528"
   integrity sha512-j3xnuQtOtjvjAoUMJgSUFxRa9/Egkg1RyA8r6PjcEb33VksE4LWLBy0PNFUFehLZv48595JROTcViGeXXwg5HQ==
 
-"@skalenetwork/ima-interfaces@1.0.0-develop.17":
-  version "1.0.0-develop.17"
-  resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.0.0-develop.17.tgz#e2650b43a056962e62127fe787577db96d9766d3"
-  integrity sha512-x1LEQF4dNklotJNCIRl4wfq9R6N8yeX0ZBe38yiBpKPgIX++R3pBF/gPl6HGK6l5xSp0bOQgzw59fzYdjnZP5A==
+"@skalenetwork/ima-interfaces@1.0.0-develop.20":
+  version "1.0.0-develop.20"
+  resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.0.0-develop.20.tgz#e4ae92f9832c08d289690f080b22363fa8f3a339"
+  integrity sha512-OV6lHSg/UiezfLHM/STawOlu2P0IxAXXVL0LilyunuOAtSg3lLfRRyTJKD3D+JePfhgIc25B8DUxJiRyQg4UIg==
   dependencies:
     "@skalenetwork/skale-manager-interfaces" "^0.1.2"
 


Test patch:
diff --git a/proxy/contracts/test/ConfigReader.sol b/proxy/contracts/test/ConfigReader.sol
index b0e41d46c..24becbf68 100644
--- a/proxy/contracts/test/ConfigReader.sol
+++ b/proxy/contracts/test/ConfigReader.sol
@@ -20,7 +20,7 @@
  */
 
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 
 library ConfigReader {
diff --git a/proxy/contracts/test/EtherbaseMock.sol b/proxy/contracts/test/EtherbaseMock.sol
index c43f37d5f..631b2676b 100644
--- a/proxy/contracts/test/EtherbaseMock.sol
+++ b/proxy/contracts/test/EtherbaseMock.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
 import "@skalenetwork/etherbase-interfaces/IEtherbaseUpgradeable.sol";
diff --git a/proxy/contracts/test/FallbackEthTester.sol b/proxy/contracts/test/FallbackEthTester.sol
index 296b97a27..457028b84 100644
--- a/proxy/contracts/test/FallbackEthTester.sol
+++ b/proxy/contracts/test/FallbackEthTester.sol
@@ -20,7 +20,7 @@
  */
 
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@skalenetwork/ima-interfaces/mainnet/DepositBoxes/IDepositBoxEth.sol";
 import "@skalenetwork/ima-interfaces/mainnet/ICommunityPool.sol";
diff --git a/proxy/contracts/test/KeyStorageMock.sol b/proxy/contracts/test/KeyStorageMock.sol
index c19fb8b1c..c69d86ac1 100644
--- a/proxy/contracts/test/KeyStorageMock.sol
+++ b/proxy/contracts/test/KeyStorageMock.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "../schain/KeyStorage.sol";
 
diff --git a/proxy/contracts/test/Logger.sol b/proxy/contracts/test/Logger.sol
index eb21a2034..cee76bf04 100644
--- a/proxy/contracts/test/Logger.sol
+++ b/proxy/contracts/test/Logger.sol
@@ -20,7 +20,7 @@
  */
 
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 
 library Logger {
diff --git a/proxy/contracts/test/MessageProxyCaller.sol b/proxy/contracts/test/MessageProxyCaller.sol
index debb6fd01..455f533c1 100644
--- a/proxy/contracts/test/MessageProxyCaller.sol
+++ b/proxy/contracts/test/MessageProxyCaller.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "../mainnet/MessageProxyForMainnet.sol";
 import "../schain/MessageProxyForSchain.sol";
diff --git a/proxy/contracts/test/MessageProxyForMainnetTester.sol b/proxy/contracts/test/MessageProxyForMainnetTester.sol
index b29ce0a19..8d1df15af 100644
--- a/proxy/contracts/test/MessageProxyForMainnetTester.sol
+++ b/proxy/contracts/test/MessageProxyForMainnetTester.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "../mainnet/MessageProxyForMainnet.sol";
 
diff --git a/proxy/contracts/test/MessageProxyForSchainTester.sol b/proxy/contracts/test/MessageProxyForSchainTester.sol
index 38590e408..a40c88093 100644
--- a/proxy/contracts/test/MessageProxyForSchainTester.sol
+++ b/proxy/contracts/test/MessageProxyForSchainTester.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "../schain/MessageProxyForSchain.sol";
 
diff --git a/proxy/contracts/test/MessageProxyForSchainWithoutSignature.sol b/proxy/contracts/test/MessageProxyForSchainWithoutSignature.sol
index 8cebc1fea..47e63829b 100644
--- a/proxy/contracts/test/MessageProxyForSchainWithoutSignature.sol
+++ b/proxy/contracts/test/MessageProxyForSchainWithoutSignature.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "./MessageProxyForSchainTester.sol";
 
diff --git a/proxy/contracts/test/MessagesTester.sol b/proxy/contracts/test/MessagesTester.sol
index 3fcd9877e..c42b5969a 100644
--- a/proxy/contracts/test/MessagesTester.sol
+++ b/proxy/contracts/test/MessagesTester.sol
@@ -20,7 +20,7 @@
  */
 
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "../Messages.sol";
 
diff --git a/proxy/contracts/test/PrecompiledMock.sol b/proxy/contracts/test/PrecompiledMock.sol
index d18a96c50..8e41ed601 100644
--- a/proxy/contracts/test/PrecompiledMock.sol
+++ b/proxy/contracts/test/PrecompiledMock.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 
 library PrecompiledMock {
diff --git a/proxy/contracts/test/ReceiverGasLimitMainnetMock.sol b/proxy/contracts/test/ReceiverGasLimitMainnetMock.sol
index eed7d733e..2c451e57f 100644
--- a/proxy/contracts/test/ReceiverGasLimitMainnetMock.sol
+++ b/proxy/contracts/test/ReceiverGasLimitMainnetMock.sol
@@ -20,7 +20,7 @@
  */
 
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@skalenetwork/ima-interfaces/IMessageReceiver.sol";
 
diff --git a/proxy/contracts/test/ReceiverGasLimitSchainMock.sol b/proxy/contracts/test/ReceiverGasLimitSchainMock.sol
index 65b8d6eb4..895ef0735 100644
--- a/proxy/contracts/test/ReceiverGasLimitSchainMock.sol
+++ b/proxy/contracts/test/ReceiverGasLimitSchainMock.sol
@@ -20,7 +20,7 @@
  */
 
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@skalenetwork/ima-interfaces/IMessageReceiver.sol";
 
diff --git a/proxy/contracts/test/ReceiverMock.sol b/proxy/contracts/test/ReceiverMock.sol
index 1c93bf76c..76d42334a 100644
--- a/proxy/contracts/test/ReceiverMock.sol
+++ b/proxy/contracts/test/ReceiverMock.sol
@@ -20,7 +20,7 @@
  */
 
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@skalenetwork/ima-interfaces/IMessageReceiver.sol";
 
diff --git a/proxy/contracts/test/SafeMock.sol b/proxy/contracts/test/SafeMock.sol
index 2f27f476d..f17f4d4f1 100644
--- a/proxy/contracts/test/SafeMock.sol
+++ b/proxy/contracts/test/SafeMock.sol
@@ -19,7 +19,7 @@
     along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
 
@@ -54,7 +54,7 @@ contract SafeMock is OwnableUpgradeable, ISafeMock {
         "EIP712Domain(uint256 chainId,address verifyingContract)"
     );
 
-    constructor() {
+    constructor() initializer {
         OwnableUpgradeable.__Ownable_init();
         multiSend(""); // this is needed to remove slither warning
     }
diff --git a/proxy/contracts/test/SkaleVerifierMock.sol b/proxy/contracts/test/SkaleVerifierMock.sol
index 8fbeb71c5..c652345a1 100644
--- a/proxy/contracts/test/SkaleVerifierMock.sol
+++ b/proxy/contracts/test/SkaleVerifierMock.sol
@@ -20,7 +20,7 @@
  */
 
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "../schain/bls/FieldOperations.sol";
 
diff --git a/proxy/contracts/test/TestCallReceiverContract.sol b/proxy/contracts/test/TestCallReceiverContract.sol
index d8570351e..4183ccee9 100644
--- a/proxy/contracts/test/TestCallReceiverContract.sol
+++ b/proxy/contracts/test/TestCallReceiverContract.sol
@@ -20,7 +20,7 @@
  */
 
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@skalenetwork/ima-interfaces/IMessageReceiver.sol";
 
diff --git a/proxy/contracts/test/TestContractManager.sol b/proxy/contracts/test/TestContractManager.sol
index 48273b421..aca6a39bf 100644
--- a/proxy/contracts/test/TestContractManager.sol
+++ b/proxy/contracts/test/TestContractManager.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
 
diff --git a/proxy/contracts/test/TestNodes.sol b/proxy/contracts/test/TestNodes.sol
index 34f085fe7..8d9ece995 100644
--- a/proxy/contracts/test/TestNodes.sol
+++ b/proxy/contracts/test/TestNodes.sol
@@ -20,7 +20,7 @@
  */
 
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 
 interface INodesTester {
diff --git a/proxy/contracts/test/TestSchains.sol b/proxy/contracts/test/TestSchains.sol
index 25b708c49..4929c7d19 100644
--- a/proxy/contracts/test/TestSchains.sol
+++ b/proxy/contracts/test/TestSchains.sol
@@ -20,7 +20,7 @@
  */
 
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "./TestContractManager.sol";
 import "./KeyStorageMock.sol";
diff --git a/proxy/contracts/test/TestSchainsInternal.sol b/proxy/contracts/test/TestSchainsInternal.sol
index 80960bfa2..3d7bca9fa 100644
--- a/proxy/contracts/test/TestSchainsInternal.sol
+++ b/proxy/contracts/test/TestSchainsInternal.sol
@@ -20,7 +20,7 @@
  */
 
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "./TestContractManager.sol";
 import "./TestNodes.sol";
@@ -108,10 +108,6 @@ contract SchainsInternal is ISchainsInternalTester {
         return schains[schainHash].owner == from;
     }
 
-    function isSchainExist(bytes32) external view override returns (bool) {
-        return true;
-    }
-
     function getSchains() external view override returns (bytes32[] memory) {
         return schainsAtSystem;
     }
@@ -133,4 +129,8 @@ contract SchainsInternal is ISchainsInternalTester {
     {
         return schainsGroups[schainHash];
     }
+
+    function isSchainExist(bytes32) external pure override returns (bool) {
+        return true;
+    }
 }
diff --git a/proxy/contracts/test/TestWallets.sol b/proxy/contracts/test/TestWallets.sol
index 73abc434f..8a3e6a120 100644
--- a/proxy/contracts/test/TestWallets.sol
+++ b/proxy/contracts/test/TestWallets.sol
@@ -19,7 +19,7 @@
  *   along with SKALE IMA.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pragma solidity 0.8.6;
+pragma solidity 0.8.16;
 
 import "./TestSchainsInternal.sol";
 
diff --git a/proxy/predeployed/test/contracts/proxy_admin.py b/proxy/predeployed/test/contracts/proxy_admin.py
deleted file mode 100644
index d7d11c1bc..000000000
--- a/proxy/predeployed/test/contracts/proxy_admin.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from ima_predeployed.addresses import PROXY_ADMIN_ADDRESS
-from tools import w3, load_abi
-
-
-def check_proxy_admin(owner_address):
-    proxy_admin = w3.eth.contract(address=PROXY_ADMIN_ADDRESS, abi=load_abi('ProxyAdmin.json'))
-    if not proxy_admin.functions.owner().call() == owner_address: raise AssertionError
diff --git a/proxy/predeployed/test/prepare_environment.sh b/proxy/predeployed/test/prepare_environment.sh
index 7a19160f0..5d54f89f1 100755
--- a/proxy/predeployed/test/prepare_environment.sh
+++ b/proxy/predeployed/test/prepare_environment.sh
@@ -6,9 +6,9 @@ cd "$(dirname "$0")/.."
 
 python3 -m venv test/venv
 source test/venv/bin/activate
-pip install --force-reinstall dist/ima_predeployed-*.whl
+export PYTHONPATH=src
+pip install -r test/requirements.txt
 BLOCKCHAIN_DIR="/tmp/blockchain/"
-#BLOCKCHAIN_DIR="$(pwd)/blockchain/"
 python test/generate_genesis.py test/base_genesis.json test/config.json > test/genesis.json
 rm -r "$BLOCKCHAIN_DIR" || true
 mkdir "$BLOCKCHAIN_DIR"
diff --git a/proxy/predeployed/test/requirements.txt b/proxy/predeployed/test/requirements.txt
index 329055754..2172ac648 100644
--- a/proxy/predeployed/test/requirements.txt
+++ b/proxy/predeployed/test/requirements.txt
@@ -1,1 +1,1 @@
-web3
\ No newline at end of file
+predeployed-generator>=1.1.0a1
\ No newline at end of file
diff --git a/proxy/predeployed/test/test.py b/proxy/predeployed/test/test.py
index 8703a2c51..1a5136cc3 100644
--- a/proxy/predeployed/test/test.py
+++ b/proxy/predeployed/test/test.py
@@ -1,18 +1,16 @@
-from contracts.admin_upgradeability_proxy import check_admin_upgradeability_proxy
 from contracts.community_locker import check_community_locker
 from contracts.eth_erc20 import check_eth_erc20
 from contracts.key_storage import check_key_storage
 from contracts.message_proxy_for_schain import check_message_proxy_for_schain
-from contracts.proxy_admin import check_proxy_admin
 from contracts.token_manager_erc20 import check_token_manager_erc20
 from contracts.token_manager_erc721 import check_token_manager_erc721
 from contracts.token_manager_erc1155 import check_token_manager_erc1155
 from contracts.token_manager_erc721_with_metadata import check_token_manager_erc721_with_metadata
 from contracts.token_manager_eth import check_token_manager_eth
 from contracts.token_manager_linker import check_token_manager_linker
+from test_generator import check_meta_generator
 import json
 
-
 with open('config.json') as config_file:
     config = json.load(config_file)
     owner_address = config['schain_owner']
@@ -27,8 +25,6 @@
 
 
 def main():
-    check_proxy_admin(owner_address)
-    check_admin_upgradeability_proxy()
     check_message_proxy_for_schain(owner_address, schain_name)
     check_key_storage(owner_address)
     check_community_locker(owner_address, schain_name, community_pool)
@@ -39,6 +35,7 @@ def main():
     check_token_manager_erc1155(owner_address, erc1155_deposit_box, schain_name)
     check_token_manager_erc721_with_metadata(owner_address, erc721_with_metadata_deposit_box, schain_name)
     check_eth_erc20(owner_address)
+    check_meta_generator()
 
     print('All tests pass')
 
diff --git a/proxy/predeployed/test/test.sh b/proxy/predeployed/test/test.sh
index 20ef8008a..1103ed642 100755
--- a/proxy/predeployed/test/test.sh
+++ b/proxy/predeployed/test/test.sh
@@ -23,7 +23,8 @@ GETH_PID=$!
 sleep 3
 
 source venv/bin/activate
-pip install -r requirements.txt
+export PYTHONPATH=../src
+echo $PYTHONPATH
 python test.py
 
 kill $GETH_PID
diff --git a/proxy/predeployed/test/test_generator.py b/proxy/predeployed/test/test_generator.py
new file mode 100644
index 000000000..2f7b64c6e
--- /dev/null
+++ b/proxy/predeployed/test/test_generator.py
@@ -0,0 +1,14 @@
+from ima_predeployed.generator import generate_meta
+from ima_predeployed.addresses import (
+    MESSAGE_PROXY_FOR_SCHAIN_IMPLEMENTATION_ADDRESS,
+    MESSAGE_PROXY_FOR_SCHAIN_ADDRESS, TOKEN_MANAGER_ERC1155_ADDRESS,
+    TOKEN_MANAGER_ERC1155_IMPLEMENTATION_ADDRESS
+)
+
+
+def check_meta_generator():
+    meta = generate_meta()
+    assert meta[MESSAGE_PROXY_FOR_SCHAIN_IMPLEMENTATION_ADDRESS]['name'] == 'MessageProxyForSchain'
+    assert meta[MESSAGE_PROXY_FOR_SCHAIN_ADDRESS]['name'] == 'TransparentUpgradeableProxy'
+    assert meta[TOKEN_MANAGER_ERC1155_IMPLEMENTATION_ADDRESS]['name'] == 'TokenManagerERC1155'
+    assert meta[TOKEN_MANAGER_ERC1155_ADDRESS]['name'] == 'TransparentUpgradeableProxy'
diff --git a/proxy/scripts/test_upgrade.sh b/proxy/scripts/test_upgrade.sh
index 3945fbcc7..fd01cba5f 100644
--- a/proxy/scripts/test_upgrade.sh
+++ b/proxy/scripts/test_upgrade.sh
@@ -37,6 +37,10 @@ cd "$GITHUB_WORKSPACE"
 rm -r --interactive=never "$DEPLOYED_DIR"
 cd proxy
 
+# TODO: remove updateManifest script after upgrade from 1.3.0-stable.0
+./scripts/updateManifest.py ".openzeppelin/unknown-1337.json"
+./scripts/updateManifest.py "data/ima-schain-$DEPLOYED_VERSION-manifest.json"
+
 ABI="data/$ABI_FILENAME_MAINNET" TEST_UPGRADE=true npx hardhat run migrations/upgradeMainnet.ts --network localhost
 
 VERSION="$(git describe --tags | echo "$VERSION_TAG")"
diff --git a/proxy/test/CommunityPool.ts b/proxy/test/CommunityPool.ts
index 6a15a2d26..2a265451f 100644
--- a/proxy/test/CommunityPool.ts
+++ b/proxy/test/CommunityPool.ts
@@ -109,6 +109,27 @@ describe("CommunityPool", () => {
             expect(BigNumber.from(await messageProxy.getOutgoingMessagesCounter(schainName)).toString()).to.be.equal(BigNumber.from(1).toString());
         });
 
+        it("should recharge wallet if user passed enough money with basefee", async () => {
+            const blockNumber = await ethers.provider.getBlockNumber();
+            const baseFeePerGas = (await ethers.provider.getBlock(blockNumber)).baseFeePerGas;
+            const baseFeeCandidate = (baseFeePerGas ? baseFeePerGas : new BigNumber(1, "hex"));
+            const basefee = baseFeeCandidate.toNumber() === 0 ? BigNumber.from(1) : baseFeeCandidate;
+            const amount = minTransactionGas.mul(basefee);
+            //
+            // comment this check until issue https://github.com/NomicFoundation/hardhat/issues/1688 would be fixed
+            //
+            // const amount = await communityPool.getRecommendedRechargeAmount(ethers.utils.id(schainName), user.address));
+            //
+            await communityPool.connect(user).rechargeUserWallet(schainName, user.address, { value: amount.sub(1).toString(), gasPrice: basefee.toNumber()}).should.be.eventually.rejectedWith("Not enough ETH for transaction");
+            await communityPool.connect(user).rechargeUserWallet(schainName, user.address, { value: amount.toString(), gasPrice: basefee.toNumber()});
+            let userBalance = await communityPool.getBalance(user.address, schainName);
+            userBalance.should.be.deep.equal(amount);
+            await communityPool.connect(user).rechargeUserWallet(schainName, user.address, { value: amount.toString(), gasPrice: basefee.toNumber()});
+            userBalance = await communityPool.getBalance(user.address, schainName);
+            userBalance.should.be.deep.equal(amount.mul(2));
+            expect(BigNumber.from(await messageProxy.getOutgoingMessagesCounter(schainName)).toString()).to.be.equal(BigNumber.from(1).toString());
+        });
+
         it("should allow to withdraw money", async () => {
             const amount = minTransactionGas.mul(gasPrice).toNumber();
             await communityPool.connect(user).rechargeUserWallet(schainName, user.address, { value: (amount + 1).toString(), gasPrice });
@@ -232,6 +253,21 @@ describe("CommunityPool", () => {
         expect(BigNumber.from(await communityPool.minTransactionGas()).toString()).to.be.equal(newMinTransactionGas.toString());
     });
 
+    it("should set new multiplier", async () => {
+        const newMultipliermultiplierNumeratorr = BigNumber.from(5);
+        const newMultiplierDivider = BigNumber.from(4);
+        const CONSTANT_SETTER_ROLE  = await communityPool.CONSTANT_SETTER_ROLE();
+        await communityPool.grantRole(CONSTANT_SETTER_ROLE, deployer.address);
+        expect(BigNumber.from(await communityPool.multiplierNumerator()).toString()).to.be.equal(BigNumber.from(3).toString());
+        expect(BigNumber.from(await communityPool.multiplierDivider()).toString()).to.be.equal(BigNumber.from(2).toString());
+        await communityPool.connect(user).setMultiplier(newMultipliermultiplierNumeratorr, newMultiplierDivider)
+            .should.be.eventually.rejectedWith("CONSTANT_SETTER_ROLE is required");
+        await communityPool.setMultiplier(newMultipliermultiplierNumeratorr, 0).should.be.eventually.rejectedWith("Divider is zero");
+        await communityPool.setMultiplier(newMultipliermultiplierNumeratorr, newMultiplierDivider);
+        expect(BigNumber.from(await communityPool.multiplierNumerator()).toString()).to.be.equal(BigNumber.from(newMultipliermultiplierNumeratorr).toString());
+        expect(BigNumber.from(await communityPool.multiplierDivider()).toString()).to.be.equal(BigNumber.from(newMultiplierDivider).toString());
+    });
+
     it("should set rejected when call refundGasByUser not from messageProxy contract", async () => {
         const schainHash = stringValue(web3.utils.soliditySha3("Schain"));
         await communityPool.connect(deployer).refundGasByUser(schainHash, node.address, user.address, 0)
diff --git a/proxy/test/DepositBoxERC20.ts b/proxy/test/DepositBoxERC20.ts
index 67d35b8a4..07b080005 100644
--- a/proxy/test/DepositBoxERC20.ts
+++ b/proxy/test/DepositBoxERC20.ts
@@ -24,7 +24,6 @@
  */
 
 import chaiAsPromised from "chai-as-promised";
-// import chaiAlmost from "chai-almost";
 import {
     ContractManager,
     DepositBoxERC20,
@@ -36,14 +35,12 @@ import {
     ERC20OnChain,
     CommunityPool
 } from "../typechain";
-import { randomString, stringFromHex, stringValue, getPublicKey } from "./utils/helper";
+import { stringFromHex, getPublicKey } from "./utils/helper";
 
 import chai = require("chai");
-import chaiAlmost = require("chai-almost");
 
 chai.should();
 chai.use((chaiAsPromised as any));
-chai.use(chaiAlmost(0.002));
 
 import { deployDepositBoxERC20 } from "./utils/deploy/mainnet/depositBoxERC20";
 import { deployLinker } from "./utils/deploy/mainnet/linker";
@@ -58,12 +55,13 @@ import { deployERC721OnChain } from "./utils/deploy/erc721OnChain";
 import { deployERC1155OnChain } from "./utils/deploy/erc1155OnChain";
 import { deployCommunityPool } from "./utils/deploy/mainnet/communityPool";
 
-import { ethers, web3 } from "hardhat";
+import { ethers } from "hardhat";
 import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/dist/src/signer-with-address";
 import { BigNumber, Wallet } from "ethers";
 
-import { assert, expect } from "chai";
+import { assert, expect, use } from "chai";
 import { createNode } from "./utils/skale-manager-utils/nodes";
+import { currentTime, skipTime } from "./utils/time";
 
 const BlsSignature: [BigNumber, BigNumber] = [
     BigNumber.from("178325537405109593276798394634841698946852714038246117383766698579865918287"),
@@ -73,11 +71,9 @@ const HashA = "30804919429741726545188616007474668515898092414623848790866732560
 const HashB = "15163860114293529009901628456926790077787470245128337652112878212941459329347";
 const Counter = 0;
 
-async function getBalance(address: string) {
-    return parseFloat(web3.utils.fromWei(await web3.eth.getBalance(address)));
-}
 describe("DepositBoxERC20", () => {
     let deployer: SignerWithAddress;
+    let schainOwner: SignerWithAddress;
     let user: SignerWithAddress;
     let user2: SignerWithAddress;
     let richGuy: SignerWithAddress;
@@ -90,9 +86,10 @@ describe("DepositBoxERC20", () => {
     let communityPool: CommunityPool;
     const contractManagerAddress = "0x0000000000000000000000000000000000000000";
     const schainName = "Schain";
+    const schainHash = ethers.utils.solidityKeccak256(["string"], [schainName]);
 
     before(async () => {
-        [deployer, user, user2, richGuy] = await ethers.getSigners();
+        [deployer, schainOwner, user, user2, richGuy] = await ethers.getSigners();
         nodeAddress = Wallet.createRandom().connect(ethers.provider);
         const balanceRichGuy = await richGuy.getBalance();
         await richGuy.sendTransaction({to: nodeAddress.address, value: balanceRichGuy.sub(ethers.utils.parseEther("1"))});
@@ -111,7 +108,7 @@ describe("DepositBoxERC20", () => {
         communityPool = await deployCommunityPool(contractManager, linker, messageProxy);
         await messageProxy.grantRole(await messageProxy.CHAIN_CONNECTOR_ROLE(), linker.address);
         await messageProxy.grantRole(await messageProxy.EXTRA_CONTRACT_REGISTRAR_ROLE(), deployer.address);
-        await initializeSchain(contractManager, schainName, user.address, 1, 1);
+        await initializeSchain(contractManager, schainName, schainOwner.address, 1, 1);
         const nodeCreationParams = {
             port: 1337,
             nonce: 1337,
@@ -144,7 +141,7 @@ describe("DepositBoxERC20", () => {
             it("should rejected with `Whitelist is enabled`", async () => {
                 // preparation
                 const error = "Whitelist is enabled";
-                await depositBoxERC20.connect(user).enableWhitelist(schainName);
+                await depositBoxERC20.connect(schainOwner).enableWhitelist(schainName);
                 await erc20.connect(deployer).mint(user.address, "1000000000");
                 await erc20.connect(deployer).approve(depositBoxERC20.address, "1000000");
                 // set `DepositBox` contract to avoid the `Not allowed` error in LockAndDataForMainnet.sol
@@ -158,8 +155,7 @@ describe("DepositBoxERC20", () => {
             it("should rejected with `DepositBox was not approved for ERC20 token`", async () => {
                 // preparation
                 const error = "DepositBox was not approved for ERC20 token";
-                // await erc20.connect(deployer).mint(user.address, "1000000000");
-                await depositBoxERC20.connect(user).disableWhitelist(schainName);
+                await depositBoxERC20.connect(schainOwner).disableWhitelist(schainName);
                 // set `DepositBox` contract to avoid the `Not allowed` error in LockAndDataForMainnet.sol
                 // execution/expectation
                 await depositBoxERC20
@@ -178,14 +174,13 @@ describe("DepositBoxERC20", () => {
                 await depositBoxERC20
                     .connect(deployer)
                     .depositERC20(schainName, erc20.address, 1).should.be.eventually.rejectedWith("Whitelist is enabled");
-                await depositBoxERC20.connect(user).disableWhitelist(schainName);
+                await depositBoxERC20.connect(schainOwner).disableWhitelist(schainName);
                 await depositBoxERC20
                     .connect(deployer)
                     .depositERC20(schainName, erc20.address, 1);
                 await depositBoxERC20
                     .connect(deployer)
                     .depositERC20(schainName, erc20.address, 1);
-                // console.log("Gas for depositERC20:", res.receipt.gasUsed);
             });
 
             it("should rejected with `Amount is incorrect`", async () => {
@@ -195,7 +190,7 @@ describe("DepositBoxERC20", () => {
                 await erc20.connect(deployer).mint(deployer.address, amount);
                 await erc20.connect(deployer).approve(depositBoxERC20.address, amount + 1);
 
-                await depositBoxERC20.connect(user).disableWhitelist(schainName);
+                await depositBoxERC20.connect(schainOwner).disableWhitelist(schainName);
                 await depositBoxERC20
                     .connect(deployer)
                     .depositERC20(schainName, erc20.address, amount + 1)
@@ -206,24 +201,24 @@ describe("DepositBoxERC20", () => {
         it("should get funds after kill", async () => {
             await erc20.connect(deployer).mint(deployer.address, "1000000000");
             await erc20.connect(deployer).approve(depositBoxERC20.address, "1000000");
-            await depositBoxERC20.connect(user).disableWhitelist(schainName);
+            await depositBoxERC20.connect(schainOwner).disableWhitelist(schainName);
             await depositBoxERC20
                 .connect(deployer)
                 .depositERC20(schainName, erc20.address, 1);
-            await depositBoxERC20.connect(user).getFunds(schainName, erc20.address, user.address, 1).should.be.eventually.rejectedWith("Schain is not killed");
+            await depositBoxERC20.connect(schainOwner).getFunds(schainName, erc20.address, schainOwner.address, 1).should.be.eventually.rejectedWith("Schain is not killed");
             await linker.connect(deployer).kill(schainName);
-            await linker.connect(user).kill(schainName);
-            await depositBoxERC20.connect(user).getFunds(schainName, erc20.address, user.address, 2).should.be.eventually.rejectedWith("Incorrect amount");
-            await depositBoxERC20.connect(user).getFunds(schainName, erc20.address, user.address, 1);
-            expect(BigNumber.from(await erc20.balanceOf(user.address)).toString()).to.equal("1");
+            await linker.connect(schainOwner).kill(schainName);
+            await depositBoxERC20.connect(schainOwner).getFunds(schainName, erc20.address, schainOwner.address, 2).should.be.eventually.rejectedWith("Incorrect amount");
+            await depositBoxERC20.connect(schainOwner).getFunds(schainName, erc20.address, schainOwner.address, 1);
+            expect(BigNumber.from(await erc20.balanceOf(schainOwner.address)).toString()).to.equal("1");
         });
 
         it("should add erc token by schain owner", async () => {
             const fakeERC20Contract = deployer.address;
-            await depositBoxERC20.connect(user).addERC20TokenByOwner(schainName, fakeERC20Contract)
+            await depositBoxERC20.connect(schainOwner).addERC20TokenByOwner(schainName, fakeERC20Contract)
                 .should.be.eventually.rejectedWith("Given address is not a contract");
-            await depositBoxERC20.connect(user).addERC20TokenByOwner(schainName, erc20.address);
-            await depositBoxERC20.connect(user).addERC20TokenByOwner(schainName, erc20.address).should.be.eventually.rejectedWith("ERC20 Token was already added");
+            await depositBoxERC20.connect(schainOwner).addERC20TokenByOwner(schainName, erc20.address);
+            await depositBoxERC20.connect(schainOwner).addERC20TokenByOwner(schainName, erc20.address).should.be.eventually.rejectedWith("ERC20 Token was already added");
             expect(await depositBoxERC20.getSchainToERC20(schainName, erc20.address)).to.be.equal(true);
             expect((await depositBoxERC20.getSchainToAllERC20(schainName, 0, 1))[0]).to.be.equal(erc20.address);
             expect((await depositBoxERC20.getSchainToAllERC20(schainName, 0, 1)).length).to.be.equal(1);
@@ -234,30 +229,22 @@ describe("DepositBoxERC20", () => {
 
         it("should not allow to add token by schain owner if schain killed", async () => {
             await linker.connect(deployer).kill(schainName);
-            await linker.connect(user).kill(schainName);
-            await depositBoxERC20.connect(user).addERC20TokenByOwner(schainName, erc20.address)
+            await linker.connect(schainOwner).kill(schainName);
+            await depositBoxERC20.connect(schainOwner).addERC20TokenByOwner(schainName, erc20.address)
                 .should.be.eventually.rejectedWith("Schain is killed");
         });
     });
 
     describe("tests for `postMessage` function", async () => {
-        // let eRC20ModuleForMainnet: ERC20ModuleForMainnetInstance;
-        // let lockAndDataForMainnetERC20: LockAndDataForMainnetERC20Instance;
         let erc20: ERC20OnChain;
         let erc20Clone: ERC20OnChain;
-        // let eRC721ModuleForMainnet: ERC721ModuleForMainnet;
-        // let lockAndDataForMainnetERC721: LockAndDataForMainnetERC721;
         let eRC721OnChain: ERC721OnChain;
         let eRC1155OnChain: ERC1155OnChain;
         let messages: MessagesTester;
 
         beforeEach(async () => {
-            // eRC20ModuleForMainnet = await deployERC20ModuleForMainnet(lockAndDataForMainnet);
-            // lockAndDataForMainnetERC20 = await deployLockAndDataForMainnetERC20(lockAndDataForMainnet);
             erc20 = await deployERC20OnChain("D2-token", "D2",);
             erc20Clone = await deployERC20OnChain("Token", "T",);
-            // eRC721ModuleForMainnet = await deployERC721ModuleForMainnet(lockAndDataForMainnet);
-            // lockAndDataForMainnetERC721 = await deployLockAndDataForMainnetERC721(lockAndDataForMainnet);
             eRC721OnChain = await deployERC721OnChain("ERC721OnChain", "ERC721");
             eRC1155OnChain = await deployERC1155OnChain("New ERC1155 Token");
             messages = await deployMessages();
@@ -267,7 +254,6 @@ describe("DepositBoxERC20", () => {
             //  preparation
             const ercOnSchain = erc20.address;
             const fakeErc20OnSchain = erc20Clone.address;
-            const schainHash = stringValue(web3.utils.soliditySha3(schainName));
             const amount = 10;
             const to = user.address;
             const senderFromSchain = deployer.address;
@@ -297,7 +283,7 @@ describe("DepositBoxERC20", () => {
                 sender: senderFromSchain
             };
 
-            await initializeSchain(contractManager, schainName, deployer.address, 1, 1);
+            await initializeSchain(contractManager, schainName, schainOwner.address, 1, 1);
             await setCommonPublicKey(contractManager, schainName);
 
             await depositBoxERC20.connect(user).depositERC20(schainName, erc20.address, amount)
@@ -311,7 +297,7 @@ describe("DepositBoxERC20", () => {
                 .connect(user)
                 .rechargeUserWallet(schainName, user.address, { value: wei });
 
-            await depositBoxERC20.disableWhitelist(schainName);
+            await depositBoxERC20.connect(schainOwner).disableWhitelist(schainName);
             await erc20.connect(deployer).mint(user.address, amount * 2);
 
             await depositBoxERC20.connect(user).depositERC20(schainName, erc20.address, amount)
@@ -330,11 +316,11 @@ describe("DepositBoxERC20", () => {
                 assert(false, "No events were emitted");
             }
 
-            const balanceBefore = await getBalance(deployer.address);
+            const balanceBefore = await deployer.getBalance();
             await messageProxy.connect(nodeAddress).postIncomingMessages(schainName, 2, [message], sign);
-            const balance = await getBalance(deployer.address);
-            balance.should.not.be.lessThan(balanceBefore);
-            balance.should.be.almost(balanceBefore);
+            const balance = await deployer.getBalance();
+            balance.should.be.least(balanceBefore);
+            balance.should.be.closeTo(balanceBefore, 10);
 
             await depositBoxERC20.connect(user).depositERC20(schainName, erc20.address, amount);
             await messageProxy.connect(nodeAddress).postIncomingMessages(schainName, 3, [message], sign);
@@ -343,5 +329,327 @@ describe("DepositBoxERC20", () => {
             (await erc20.balanceOf(user.address)).toString().should.be.equal((amount * 2).toString());
 
         });
+
+        describe("When user deposited tokens", async () => {
+            let token: ERC20OnChain;
+            let token2: ERC20OnChain;
+            const amount = 5;
+            const bigAmount = 10;
+            const timeDelay = 24 * 60 * 60;
+            const arbitrageDuration = 30 * 24 * 60 * 60;
+            const ethDeposit = ethers.utils.parseEther("1");
+            const randomSignature = {
+                blsSignature: BlsSignature,
+                counter: Counter,
+                hashA: HashA,
+                hashB: HashB,
+            };
+
+            beforeEach(async () => {
+                token = erc20;
+                token2 = erc20Clone;
+
+                await initializeSchain(contractManager, schainName, schainOwner.address, 1, 1);
+                await setCommonPublicKey(contractManager, schainName);
+
+                await linker.connectSchain(schainName, [deployer.address, deployer.address, deployer.address]);
+
+                await communityPool
+                    .connect(user)
+                    .rechargeUserWallet(schainName, user.address, { value: ethDeposit });
+
+                await depositBoxERC20.connect(schainOwner).disableWhitelist(schainName);
+
+                const depositedAmount = bigAmount * 100;
+                await token.mint(user.address, depositedAmount);
+                await token2.mint(user.address, depositedAmount);
+
+                await token.connect(user).approve(depositBoxERC20.address, depositedAmount);
+                await depositBoxERC20.connect(user).depositERC20(schainName, token.address, depositedAmount);
+
+                await token2.connect(user).approve(depositBoxERC20.address, depositedAmount);
+                await depositBoxERC20.connect(user).depositERC20(schainName, token2.address, depositedAmount);
+
+                await depositBoxERC20.connect(schainOwner).setBigTransferValue(schainName, token.address, bigAmount);
+                await depositBoxERC20.connect(schainOwner).setBigTransferValue(schainName, token2.address, bigAmount);
+                await depositBoxERC20.connect(schainOwner).setBigTransferDelay(schainName, timeDelay);
+                await depositBoxERC20.connect(schainOwner).setArbitrageDuration(schainName, arbitrageDuration);
+
+                await depositBoxERC20.grantRole(await depositBoxERC20.ARBITER_ROLE(), deployer.address);
+            });
+
+            it("should delay a big exit transfer", async () => {
+                const balanceBefore = await token.balanceOf(user.address);
+
+                const message = {
+                    data: await messages.encodeTransferErc20Message(token.address, user.address, bigAmount),
+                    destinationContract: depositBoxERC20.address,
+                    sender: deployer.address
+                };
+
+                await messageProxy.connect(nodeAddress).postIncomingMessages(schainName, 0, [message], randomSignature);
+
+                (await token.balanceOf(user.address)).should.be.equal(balanceBefore);
+
+                await depositBoxERC20.connect(user).retrieve()
+                    .should.be.rejectedWith("There are no transfers available for retrieving");
+
+                (await token.balanceOf(user.address)).should.be.equal(balanceBefore);
+
+                await skipTime(timeDelay);
+
+                await depositBoxERC20.connect(user).retrieve();
+
+                (await token.balanceOf(user.address)).should.be.equal(balanceBefore.add(bigAmount));
+            });
+
+            it("should allow to perform arbitrage", async () => {
+                const smallTransferOfToken1 = {
+                    data: await messages.encodeTransferErc20Message(token.address, user.address, amount),
+                    destinationContract: depositBoxERC20.address,
+                    sender: deployer.address
+                };
+
+                const bigTransferOfToken1 = {
+                    data: await messages.encodeTransferErc20Message(token.address, user.address, bigAmount),
+                    destinationContract: depositBoxERC20.address,
+                    sender: deployer.address
+                };
+
+                const smallTransferOfToken2 = {
+                    data: await messages.encodeTransferErc20Message(token2.address, user.address, amount),
+                    destinationContract: depositBoxERC20.address,
+                    sender: deployer.address
+                };
+
+                const bigTransferOfToken2 = {
+                    data: await messages.encodeTransferErc20Message(token2.address, user.address, bigAmount),
+                    destinationContract: depositBoxERC20.address,
+                    sender: deployer.address
+                };
+
+                const token1BalanceBefore = await token.balanceOf(user.address);
+                const token2BalanceBefore = await token2.balanceOf(user.address);
+
+                await messageProxy.connect(nodeAddress).postIncomingMessages(
+                    schainName,
+                    0,
+                    [
+                        smallTransferOfToken1,
+                        smallTransferOfToken2,
+                        bigTransferOfToken1,
+                        bigTransferOfToken1,
+                        bigTransferOfToken2,
+                        bigTransferOfToken1,
+                        smallTransferOfToken1,
+                        smallTransferOfToken2,
+                        bigTransferOfToken1,
+                    ],
+                    randomSignature
+                );
+
+                (await depositBoxERC20.getDelayedAmount(user.address, token.address))
+                    .should.be.equal(4 * bigAmount);
+                (await depositBoxERC20.getDelayedAmount(user.address, token2.address))
+                    .should.be.equal(bigAmount);
+                (await depositBoxERC20.getNextUnlockTimestamp(user.address, token.address))
+                    .should.be.equal((await currentTime()) + timeDelay);
+                (await depositBoxERC20.getNextUnlockTimestamp(user.address, token2.address))
+                    .should.be.equal((await currentTime()) + timeDelay);
+
+                // 2 small transfers of token 1 and 2 small transfers of token 2 must be processed without delay
+                (await token.balanceOf(user.address)).should.be.equal(token1BalanceBefore.add(2 * amount));
+                (await token2.balanceOf(user.address)).should.be.equal(token2BalanceBefore.add(2 * amount));
+
+                // #0 - big transfer of token 1
+                // #1 - big transfer of token 1
+                // #2 - big transfer of token 2
+                // #3 - big transfer of token 1
+                // #4 - big transfer of token 1
+
+                const suspicionsTransfers = [0, 1, 4];
+
+                for (const suspicionsTransfer of suspicionsTransfers) {
+                    await depositBoxERC20.connect(richGuy).escalate(suspicionsTransfer)
+                        .should.be.rejectedWith("Not enough permissions to request escalation");
+                    await depositBoxERC20.escalate(suspicionsTransfer);
+                    await depositBoxERC20.escalate(suspicionsTransfer)
+                        .should.be.rejectedWith("The transfer has to be delayed");
+                }
+
+                await skipTime(timeDelay);
+
+                // transfer #2 and #3 must be unlocked
+                await depositBoxERC20.retrieveFor(user.address);
+                (await token.balanceOf(user.address))
+                    .should.be.equal(token1BalanceBefore.add(2 * amount + bigAmount));
+                (await token2.balanceOf(user.address))
+                    .should.be.equal(token2BalanceBefore.add(2 * amount + bigAmount));
+
+                await depositBoxERC20.rejectTransfer(suspicionsTransfers[0])
+                    .should.be.rejectedWith("Sender is not an Schain owner");
+
+                await depositBoxERC20.connect(schainOwner).rejectTransfer(suspicionsTransfers[0]);
+                await depositBoxERC20.connect(schainOwner).rejectTransfer(suspicionsTransfers[0])
+                    .should.be.rejectedWith("Arbitrage has to be active");
+                (await token.balanceOf(schainOwner.address))
+                    .should.be.equal(bigAmount);
+
+                await depositBoxERC20.connect(schainOwner).validateTransfer(suspicionsTransfers[1]);
+                await depositBoxERC20.connect(schainOwner).validateTransfer(suspicionsTransfers[1])
+                    .should.be.rejectedWith("Arbitrage has to be active");
+                (await token.balanceOf(user.address))
+                    .should.be.equal(token1BalanceBefore.add(2 * amount + 2 * bigAmount));
+
+                await skipTime(arbitrageDuration);
+                await depositBoxERC20.connect(user).retrieve();
+                (await token.balanceOf(user.address))
+                    .should.be.equal(token1BalanceBefore.add(2 * amount + 3 * bigAmount));
+            });
+
+            it("should not allow to set too big delays", async () => {
+                const tenYears = Math.round(60 * 60 * 24 * 365.25 * 10)
+
+                await depositBoxERC20.setBigTransferDelay(schainName, tenYears)
+                    .should.be.rejectedWith("Sender is not an Schain owner");
+
+                await depositBoxERC20.connect(schainOwner).setBigTransferDelay(schainName, tenYears)
+                    .should.be.rejectedWith("Delay is too big");
+
+                await depositBoxERC20.connect(schainOwner).setArbitrageDuration(schainName, tenYears)
+                    .should.be.rejectedWith("Delay is too big");
+            })
+
+            it("should disable delay for trusted receivers", async () => {
+                const bigTransfer = {
+                    data: await messages.encodeTransferErc20Message(token.address, user.address, bigAmount),
+                    destinationContract: depositBoxERC20.address,
+                    sender: deployer.address
+                };
+
+                await depositBoxERC20.trustReceiver(schainName, user.address)
+                    .should.be.rejectedWith("Sender is not an Schain owner");
+                await depositBoxERC20.connect(schainOwner).trustReceiver(schainName, user.address);
+                await depositBoxERC20.connect(schainOwner).trustReceiver(schainName, user.address)
+                    .should.be.rejectedWith("Receiver already is trusted");
+                (await depositBoxERC20.getTrustedReceiver(schainName, 0))
+                    .should.be.equal(user.address);
+
+                await messageProxy.connect(nodeAddress).postIncomingMessages(
+                    schainName,
+                    0,
+                    [ bigTransfer ],
+                    randomSignature
+                );
+
+                (await token.balanceOf(user.address)).should.be.equal(bigAmount);
+
+                await depositBoxERC20.stopTrustingReceiver(schainName, user.address)
+                    .should.be.rejectedWith("Sender is not an Schain owner")
+                await depositBoxERC20.connect(schainOwner).stopTrustingReceiver(schainName, user.address);
+                await depositBoxERC20.connect(schainOwner).stopTrustingReceiver(schainName, user.address)
+                    .should.be.rejectedWith("Receiver is not trusted");
+
+                await messageProxy.connect(nodeAddress).postIncomingMessages(
+                    schainName,
+                    1,
+                    [ bigTransfer ],
+                    randomSignature
+                );
+
+                (await token.balanceOf(user.address)).should.be.equal(bigAmount);
+                (await depositBoxERC20.getDelayedAmount(user.address, token.address))
+                    .should.be.equal(bigAmount);
+            })
+
+            it("should reduce delay", async () => {
+                const bigTransfer = {
+                    data: await messages.encodeTransferErc20Message(token.address, user.address, bigAmount),
+                    destinationContract: depositBoxERC20.address,
+                    sender: deployer.address
+                };
+
+                await messageProxy.connect(nodeAddress).postIncomingMessages(
+                    schainName,
+                    0,
+                    [ bigTransfer ],
+                    randomSignature
+                );
+
+                (await depositBoxERC20.getNextUnlockTimestamp(user.address, token.address))
+                    .should.be.equal(await currentTime() + timeDelay);
+
+
+                const lowerDelay = Math.round(timeDelay / 2);
+                await depositBoxERC20.connect(schainOwner).setBigTransferDelay(schainName, lowerDelay);
+
+                await messageProxy.connect(nodeAddress).postIncomingMessages(
+                    schainName,
+                    1,
+                    [ bigTransfer ],
+                    randomSignature
+                );
+
+                (await depositBoxERC20.getNextUnlockTimestamp(user.address, token.address))
+                    .should.be.equal(await currentTime() + lowerDelay);
+                (await depositBoxERC20.getDelayedAmount(user.address, token.address))
+                    .should.be.equal(2 * bigAmount);
+            });
+
+            it("should process correctly in non linear order", async () => {
+                const bigTransfer = {
+                    data: await messages.encodeTransferErc20Message(token.address, user.address, bigAmount),
+                    destinationContract: depositBoxERC20.address,
+                    sender: deployer.address
+                };
+
+                await messageProxy.connect(nodeAddress).postIncomingMessages(
+                    schainName,
+                    0,
+                    [
+                        bigTransfer, // #0
+                        bigTransfer  // #1
+                    ],
+                    randomSignature
+                );
+
+                let lockedUntil = await currentTime() + timeDelay;
+
+                await depositBoxERC20.escalate(0);
+
+                (await depositBoxERC20.getNextUnlockTimestamp(user.address, token.address))
+                    .should.be.equal(lockedUntil);
+
+                await skipTime(timeDelay);
+
+                await depositBoxERC20.retrieveFor(user.address);
+
+                (await depositBoxERC20.getDelayedAmount(user.address, token.address))
+                    .should.be.equal(bigAmount);
+
+                await messageProxy.connect(nodeAddress).postIncomingMessages(
+                    schainName,
+                    2,
+                    [
+                        bigTransfer, // #3
+                    ],
+                    randomSignature
+                );
+
+                lockedUntil = await currentTime() + timeDelay;
+                (await depositBoxERC20.getNextUnlockTimestamp(user.address, token.address))
+                    .should.be.equal(lockedUntil);
+                (await depositBoxERC20.getDelayedAmount(user.address, token.address))
+                    .should.be.equal(2 * bigAmount);
+
+                await skipTime(timeDelay);
+                await depositBoxERC20.retrieveFor(user.address);
+
+                (await depositBoxERC20.getDelayedAmount(user.address, token.address))
+                    .should.be.equal(bigAmount);
+                (await token.balanceOf(user.address))
+                    .should.be.equal(2 * bigAmount);
+            });
+        });
     });
 });
\ No newline at end of file
diff --git a/proxy/test/ERC721OnChain.ts b/proxy/test/ERC721OnChain.ts
index 97ad8e1eb..881226b68 100644
--- a/proxy/test/ERC721OnChain.ts
+++ b/proxy/test/ERC721OnChain.ts
@@ -41,7 +41,7 @@ describe("ERC721OnChain", () => {
 
     it("should invoke `burn`", async () => {
         // preparation
-        const error = "ERC721: owner query for nonexistent token";
+        const error = "ERC721: invalid token ID";
         const tokenId = 55;
         // mint to avoid `owner query for nonexistent token` error
         await eRC721OnChain.connect(deployer).mint(deployer.address, tokenId);
@@ -53,7 +53,7 @@ describe("ERC721OnChain", () => {
 
     it("should reject with `ERC721Burnable: caller is not owner nor approved` when invoke `burn`", async () => {
         // preparation
-        const error = "ERC721Burnable: caller is not owner nor approved";
+        const error = "ERC721: caller is not token owner nor approved";
         const tokenId = 55;
         const account = user;
         // mint to avoid `owner query for nonexistent token` error
diff --git a/proxy/test/MessageProxy.ts b/proxy/test/MessageProxy.ts
index 240eb29de..56958e4b4 100644
--- a/proxy/test/MessageProxy.ts
+++ b/proxy/test/MessageProxy.ts
@@ -60,6 +60,7 @@ import { MessageProxyForSchainTester } from "../typechain/MessageProxyForSchainT
 import { deployMessageProxyForSchainTester } from "./utils/deploy/test/messageProxyForSchainTester";
 import { deployCommunityPool } from "./utils/deploy/mainnet/communityPool";
 import { createNode } from "./utils/skale-manager-utils/nodes";
+import { skipTime } from "./utils/time";
 
 chai.should();
 chai.use((chaiAsPromised));
@@ -230,6 +231,89 @@ describe("MessageProxy", () => {
             outgoingMessagesCounter.should.be.deep.equal(BigNumber.from(1));
         });
 
+        it("should pause with a role and unpause", async () => {
+            const contractAddress = messageProxyForMainnet.address;
+            const amount = 4;
+            const bytesData = await messages.encodeTransferEthMessage(user.address, amount);
+            const schainOwner = user;
+
+            await caller
+                .postOutgoingMessageTester(messageProxyForMainnet.address, schainHash, contractAddress, bytesData)
+                .should.be.rejectedWith("Destination chain is not initialized");
+
+            const schainsInternal = (await ethers.getContractFactory("SchainsInternal")).attach(await contractManager.getContract("SchainsInternal")) as SchainsInternal;
+
+
+            await schainsInternal.initializeSchain(schainName, schainOwner.address, 0, 0);
+
+            await messageProxyForMainnet.connect(deployer).addConnectedChain(schainName);
+            await caller
+                .postOutgoingMessageTester(messageProxyForMainnet.address, schainHash, contractAddress, bytesData);
+            let outgoingMessagesCounter = BigNumber.from(
+                await messageProxyForMainnet.getOutgoingMessagesCounter(schainName));
+            outgoingMessagesCounter.should.be.deep.equal(BigNumber.from(1));
+
+            (await messageProxyForMainnet.isPaused(schainHash)).should.be.deep.equal(false);
+
+            let pausedInfo = await messageProxyForMainnet.pauseInfo(schainHash);
+            pausedInfo.should.be.equal(false);
+
+            await messageProxyForMainnet.connect(schainOwner).pause(schainName).should.be.rejectedWith("Incorrect sender");
+            await messageProxyForMainnet.connect(client).pause(schainName).should.be.rejectedWith("Incorrect sender");
+            await messageProxyForMainnet.connect(deployer).pause(schainName).should.be.rejectedWith("Incorrect sender");
+
+            const pauseableRole = await messageProxyForMainnet.PAUSABLE_ROLE();
+
+            await messageProxyForMainnet.connect(deployer).grantRole(pauseableRole, client.address);
+            await messageProxyForMainnet.connect(client).pause(schainName);
+            await messageProxyForMainnet.connect(client).pause(schainName).should.be.rejectedWith("Already paused");
+
+            (await messageProxyForMainnet.isPaused(schainHash)).should.be.deep.equal(true);
+
+            pausedInfo = await messageProxyForMainnet.pauseInfo(schainHash);
+            pausedInfo.should.be.equal(true);
+
+            await caller
+                .postOutgoingMessageTester(messageProxyForMainnet.address, schainHash, contractAddress, bytesData)
+                .should.be.rejectedWith("IMA is paused");
+
+            await messageProxyForMainnet.connect(client).resume(schainName).should.be.rejectedWith("Incorrect sender");
+            await messageProxyForMainnet.connect(schainOwner).resume(schainName);
+            await messageProxyForMainnet.connect(deployer).resume(schainName).should.be.rejectedWith("Already unpaused");
+
+            (await messageProxyForMainnet.isPaused(schainHash)).should.be.deep.equal(false);
+
+            pausedInfo = await messageProxyForMainnet.pauseInfo(schainHash);
+            pausedInfo.should.be.equal(false);
+
+            await caller
+                .postOutgoingMessageTester(messageProxyForMainnet.address, schainHash, contractAddress, bytesData);
+            outgoingMessagesCounter = BigNumber.from(
+                await messageProxyForMainnet.getOutgoingMessagesCounter(schainName));
+            outgoingMessagesCounter.should.be.deep.equal(BigNumber.from(2));
+
+            await messageProxyForMainnet.connect(client).pause(schainName);
+
+            (await messageProxyForMainnet.isPaused(schainHash)).should.be.deep.equal(true);
+
+            pausedInfo = await messageProxyForMainnet.pauseInfo(schainHash);
+            pausedInfo.should.be.equal(true);
+
+            await caller
+                .postOutgoingMessageTester(messageProxyForMainnet.address, schainHash, contractAddress, bytesData)
+                .should.be.rejectedWith("IMA is paused");
+
+            await messageProxyForMainnet.connect(deployer).resume(schainName);
+            await messageProxyForMainnet.connect(schainOwner).resume(schainName).should.be.rejectedWith("Already unpaused");
+
+            await caller
+                .postOutgoingMessageTester(messageProxyForMainnet.address, schainHash, contractAddress, bytesData);
+            outgoingMessagesCounter = BigNumber.from(
+                await messageProxyForMainnet.getOutgoingMessagesCounter(schainName));
+            outgoingMessagesCounter.should.be.deep.equal(BigNumber.from(3));
+
+        });
+
         it("should allow schain owner to send message", async () => {
             const message = "0xd2";
             const schainOwner = user;
@@ -343,6 +427,124 @@ describe("MessageProxy", () => {
             incomingMessagesCounter.should.be.deep.equal(BigNumber.from(4));
         });
 
+        it("should not post incoming messages when IMA bridge is paused", async () => {
+            const startingCounter = 0;
+            await initializeSchain(contractManager, schainName, deployer.address, 1, 1);
+            const nodeCreationParams = {
+                port: 1337,
+                nonce: 1337,
+                ip: "0x12345678",
+                publicIp: "0x12345678",
+                publicKey: getPublicKey(nodeAddress),
+                name: "GasCalculationNode",
+                domainName: "gascalculationnode.com"
+            };
+            await createNode(contractManager, nodeAddress.address, nodeCreationParams);
+            await addNodesToSchain(contractManager, schainName, [0]);
+            await rechargeSchainWallet(contractManager, schainName, deployer.address, "1000000000000000000");
+            await setCommonPublicKey(contractManager, schainName);
+            await messageProxyForMainnet.registerExtraContract(schainName, communityPool.address);
+            await depositBox.addSchainContract(schainName, deployer.address);
+            const minTransactionGas = await communityPool.minTransactionGas();
+            const amountWei = minTransactionGas.mul(gasPrice);
+
+            const message1 = {
+                destinationContract: depositBox.address,
+                sender: deployer.address,
+                data: await messages.encodeTransferEthMessage(client.address, 0),
+            };
+
+            const message2 = {
+                destinationContract: depositBox.address,
+                sender: deployer.address,
+                data: await messages.encodeTransferEthMessage(customer.address, 7),
+            };
+
+            const outgoingMessages = [message1, message2];
+            const sign = {
+                blsSignature: BlsSignature,
+                counter: Counter,
+                hashA: HashA,
+                hashB: HashB,
+            };
+
+            // chain should be inited:
+            await messageProxyForMainnet
+                .connect(nodeAddress)
+                .postIncomingMessages(
+                    schainName,
+                    startingCounter,
+                    outgoingMessages,
+                    sign
+                ).should.be.eventually.rejectedWith("Chain is not initialized");
+
+            await messageProxyForMainnet.connect(deployer).addConnectedChain(schainName);
+
+            await messageProxyForMainnet
+                .connect(nodeAddress)
+                .postIncomingMessages(
+                    schainName,
+                    startingCounter,
+                    Array(11).fill(message1),
+                    sign
+                    ).should.be.eventually.rejectedWith("Too many messages");
+
+            await communityPool.connect(client).rechargeUserWallet(schainName, client.address, {value: amountWei.toString()});
+
+            await messageProxyForMainnet
+                .connect(nodeAddress)
+                .postIncomingMessages(
+                    schainName,
+                    startingCounter,
+                    outgoingMessages,
+                    sign
+                );
+
+            await communityPool.connect(client).rechargeUserWallet(schainName, user.address, {value: amountWei.toString()});
+
+            await messageProxyForMainnet
+                .connect(nodeAddress)
+                .postIncomingMessages(
+                    schainName,
+                    startingCounter + 2,
+                    outgoingMessages,
+                    sign
+                );
+            let incomingMessagesCounter = BigNumber.from(
+                await messageProxyForMainnet.getIncomingMessagesCounter(schainName));
+            incomingMessagesCounter.should.be.deep.equal(BigNumber.from(4));
+
+            const pauseableRole = await messageProxyForMainnet.PAUSABLE_ROLE();
+
+            await messageProxyForMainnet.connect(deployer).grantRole(pauseableRole, client.address);
+
+            await messageProxyForMainnet.connect(client).pause(schainName);
+
+            await messageProxyForMainnet
+                .connect(nodeAddress)
+                .postIncomingMessages(
+                    schainName,
+                    startingCounter + 4,
+                    outgoingMessages,
+                    sign
+                ).should.be.eventually.rejectedWith("IMA is paused");
+
+            await messageProxyForMainnet.connect(deployer).resume(schainName);
+
+            await messageProxyForMainnet
+                .connect(nodeAddress)
+                .postIncomingMessages(
+                    schainName,
+                    startingCounter + 4,
+                    outgoingMessages,
+                    sign
+                );
+
+            incomingMessagesCounter = BigNumber.from(
+                await messageProxyForMainnet.getIncomingMessagesCounter(schainName));
+            incomingMessagesCounter.should.be.deep.equal(BigNumber.from(6));
+        });
+
         it("should not post incoming messages with incorrect address", async () => {
             const startingCounter = 0;
             await initializeSchain(contractManager, schainName, deployer.address, 1, 1);
diff --git a/proxy/test/TokenManagerERC721.ts b/proxy/test/TokenManagerERC721.ts
index d3965db0c..19cc6971e 100644
--- a/proxy/test/TokenManagerERC721.ts
+++ b/proxy/test/TokenManagerERC721.ts
@@ -135,11 +135,11 @@ describe("TokenManagerERC721", () => {
     it("should successfully call exitToMainERC721", async () => {
         // should be "No token clone on schain" if chains were different
         await tokenManagerERC721.connect(user).exitToMainERC721(token.address, tokenId)
-            .should.be.eventually.rejectedWith("ERC721: approved query for nonexistent token");
+            .should.be.eventually.rejectedWith("ERC721: invalid token ID");
 
         await tokenManagerERC721.connect(schainOwner).addERC721TokenByOwner(mainnetName,  token.address, tokenClone.address);
         await tokenManagerERC721.connect(user).exitToMainERC721(token.address, tokenId)
-            .should.be.eventually.rejectedWith("ERC721: approved query for nonexistent token");
+            .should.be.eventually.rejectedWith("ERC721: invalid token ID");
 
         await tokenClone.connect(deployer).mint(user.address, tokenId);
         await tokenManagerERC721.connect(user).exitToMainERC721(token.address, tokenId)
@@ -1159,7 +1159,7 @@ describe("TokenManagerERC721", () => {
             await tokenManagerERC721
                 .connect(user)
                 .exitToMainERC721(erc721OnTargetChain.address, tokenId)
-                .should.be.eventually.rejectedWith("ERC721: approved query for nonexistent token");
+                .should.be.eventually.rejectedWith("ERC721: invalid token ID");
 
         });
 
diff --git a/proxy/test/TokenManagerERC721WithMetadata.ts b/proxy/test/TokenManagerERC721WithMetadata.ts
index e6f73972c..1aea17527 100644
--- a/proxy/test/TokenManagerERC721WithMetadata.ts
+++ b/proxy/test/TokenManagerERC721WithMetadata.ts
@@ -136,11 +136,11 @@ describe("TokenManagerERC721WithMetadata", () => {
     it("should successfully call exitToMainERC721", async () => {
         // should be "No token clone on schain" if chains were different
         await tokenManagerERC721WithMetadata.connect(user).exitToMainERC721(token.address, tokenId)
-            .should.be.eventually.rejectedWith("ERC721: approved query for nonexistent token");
+            .should.be.eventually.rejectedWith("ERC721: invalid token ID");
 
         await tokenManagerERC721WithMetadata.connect(schainOwner).addERC721TokenByOwner(mainnetName,  token.address, tokenClone.address);
         await tokenManagerERC721WithMetadata.connect(user).exitToMainERC721(token.address, tokenId)
-            .should.be.eventually.rejectedWith("ERC721: approved query for nonexistent token");
+            .should.be.eventually.rejectedWith("ERC721: invalid token ID");
 
         await tokenClone.connect(deployer).mint(user.address, tokenId);
         await tokenClone.connect(user).setTokenURI(tokenId, tokenURI);
@@ -1234,7 +1234,7 @@ describe("TokenManagerERC721WithMetadata", () => {
             await tokenManagerERC721WithMetadata
                 .connect(user)
                 .exitToMainERC721(erc721OnTargetChain.address, tokenId)
-                .should.be.eventually.rejectedWith("ERC721: approved query for nonexistent token");
+                .should.be.eventually.rejectedWith("ERC721: invalid token ID");
 
         });
 
diff --git a/proxy/test/utils/deploy/mainnet/communityPool.ts b/proxy/test/utils/deploy/mainnet/communityPool.ts
index b6acbed1f..21fe02723 100644
--- a/proxy/test/utils/deploy/mainnet/communityPool.ts
+++ b/proxy/test/utils/deploy/mainnet/communityPool.ts
@@ -1,4 +1,4 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { ContractManager, MessageProxyForMainnet, Linker, CommunityPool } from "../../../../typechain";
 
 
@@ -8,8 +8,11 @@ export async function deployCommunityPool(
     messageProxy: MessageProxyForMainnet
 ) {
     const factory = await ethers.getContractFactory("CommunityPool");
-    const instance = await factory.deploy() as CommunityPool;
-    await instance["initialize(address,address,address)"](contractManager.address, linker.address, messageProxy.address);
+    const instance = await upgrades.deployProxy(
+        factory,
+        [contractManager.address, linker.address, messageProxy.address],
+        {"initializer": "initialize(address,address,address)"}
+    ) as CommunityPool;
     await linker.registerMainnetContract(instance.address);
     await messageProxy.setCommunityPool(instance.address);
     return instance;
diff --git a/proxy/test/utils/deploy/mainnet/depositBoxERC1155.ts b/proxy/test/utils/deploy/mainnet/depositBoxERC1155.ts
index 466872d76..840ba18fc 100644
--- a/proxy/test/utils/deploy/mainnet/depositBoxERC1155.ts
+++ b/proxy/test/utils/deploy/mainnet/depositBoxERC1155.ts
@@ -1,4 +1,4 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { ContractManager, MessageProxyForMainnet, Linker, DepositBoxERC1155 } from "../../../../typechain";
 
 export async function deployDepositBoxERC1155(
@@ -8,8 +8,11 @@ export async function deployDepositBoxERC1155(
 
 ) {
     const factory = await ethers.getContractFactory("DepositBoxERC1155");
-    const instance = await factory.deploy() as DepositBoxERC1155;
-    await instance["initialize(address,address,address)"](contractManager.address, linker.address, messageProxy.address);
+    const instance = await upgrades.deployProxy(
+        factory,
+        [contractManager.address, linker.address, messageProxy.address],
+        {"initializer": "initialize(address,address,address)"}
+    ) as DepositBoxERC1155;
     await linker.registerMainnetContract(instance.address);
     return instance;
 }
\ No newline at end of file
diff --git a/proxy/test/utils/deploy/mainnet/depositBoxERC20.ts b/proxy/test/utils/deploy/mainnet/depositBoxERC20.ts
index 786191cc2..d8242d76e 100644
--- a/proxy/test/utils/deploy/mainnet/depositBoxERC20.ts
+++ b/proxy/test/utils/deploy/mainnet/depositBoxERC20.ts
@@ -1,4 +1,4 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { ContractManager, MessageProxyForMainnet, Linker, DepositBoxERC20 } from "../../../../typechain";
 
 export async function deployDepositBoxERC20(
@@ -8,8 +8,11 @@ export async function deployDepositBoxERC20(
 
 ) {
     const factory = await ethers.getContractFactory("DepositBoxERC20");
-    const instance = await factory.deploy() as DepositBoxERC20;
-    await instance["initialize(address,address,address)"](contractManager.address, linker.address, messageProxy.address);
+    const instance = await upgrades.deployProxy(
+        factory,
+        [contractManager.address, linker.address, messageProxy.address],
+        {"initializer": "initialize(address,address,address)"}
+    ) as DepositBoxERC20;
     await linker.registerMainnetContract(instance.address);
     return instance;
 }
\ No newline at end of file
diff --git a/proxy/test/utils/deploy/mainnet/depositBoxERC721.ts b/proxy/test/utils/deploy/mainnet/depositBoxERC721.ts
index 9b1831f6f..d88cb6ebe 100644
--- a/proxy/test/utils/deploy/mainnet/depositBoxERC721.ts
+++ b/proxy/test/utils/deploy/mainnet/depositBoxERC721.ts
@@ -1,4 +1,4 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { ContractManager, MessageProxyForMainnet, Linker, DepositBoxERC721 } from "../../../../typechain";
 
 export async function deployDepositBoxERC721(
@@ -8,8 +8,11 @@ export async function deployDepositBoxERC721(
 
 ) {
     const factory = await ethers.getContractFactory("DepositBoxERC721");
-    const instance = await factory.deploy() as DepositBoxERC721;
-    await instance["initialize(address,address,address)"](contractManager.address, linker.address, messageProxy.address);
+    const instance = await upgrades.deployProxy(
+        factory,
+        [contractManager.address, linker.address, messageProxy.address],
+        {"initializer": "initialize(address,address,address)"}
+    ) as DepositBoxERC721;
     await linker.registerMainnetContract(instance.address);
     return instance;
 }
\ No newline at end of file
diff --git a/proxy/test/utils/deploy/mainnet/depositBoxERC721WithMetadata.ts b/proxy/test/utils/deploy/mainnet/depositBoxERC721WithMetadata.ts
index 081704a0d..3e99eae15 100644
--- a/proxy/test/utils/deploy/mainnet/depositBoxERC721WithMetadata.ts
+++ b/proxy/test/utils/deploy/mainnet/depositBoxERC721WithMetadata.ts
@@ -1,4 +1,4 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { ContractManager, MessageProxyForMainnet, Linker, DepositBoxERC721WithMetadata } from "../../../../typechain";
 
 export async function deployDepositBoxERC721WithMetadata(
@@ -8,8 +8,11 @@ export async function deployDepositBoxERC721WithMetadata(
 
 ) {
     const factory = await ethers.getContractFactory("DepositBoxERC721WithMetadata");
-    const instance = await factory.deploy() as DepositBoxERC721WithMetadata;
-    await instance["initialize(address,address,address)"](contractManager.address, linker.address, messageProxy.address);
+    const instance = await upgrades.deployProxy(
+        factory,
+        [contractManager.address, linker.address, messageProxy.address],
+        {"initializer": "initialize(address,address,address)"}
+    ) as DepositBoxERC721WithMetadata;
     await linker.registerMainnetContract(instance.address);
     return instance;
 }
\ No newline at end of file
diff --git a/proxy/test/utils/deploy/mainnet/depositBoxEth.ts b/proxy/test/utils/deploy/mainnet/depositBoxEth.ts
index 2b64a4f29..c203b4e35 100644
--- a/proxy/test/utils/deploy/mainnet/depositBoxEth.ts
+++ b/proxy/test/utils/deploy/mainnet/depositBoxEth.ts
@@ -1,4 +1,4 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { ContractManager, MessageProxyForMainnet, Linker, DepositBoxEth } from "../../../../typechain";
 
 export async function deployDepositBoxEth(
@@ -8,8 +8,11 @@ export async function deployDepositBoxEth(
 
 ) {
     const factory = await ethers.getContractFactory("DepositBoxEth");
-    const instance = await factory.deploy() as DepositBoxEth;
-    await instance["initialize(address,address,address)"](contractManager.address, linker.address, messageProxy.address);
+    const instance = await upgrades.deployProxy(
+        factory,
+        [contractManager.address, linker.address, messageProxy.address],
+        {"initializer": "initialize(address,address,address)"}
+    ) as DepositBoxEth;
     await linker.registerMainnetContract(instance.address);
     return instance;
 }
\ No newline at end of file
diff --git a/proxy/test/utils/deploy/mainnet/linker.ts b/proxy/test/utils/deploy/mainnet/linker.ts
index c76e1f715..4602ff154 100644
--- a/proxy/test/utils/deploy/mainnet/linker.ts
+++ b/proxy/test/utils/deploy/mainnet/linker.ts
@@ -1,4 +1,4 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { MessageProxyForMainnet, Linker, ContractManager, MessageProxyForMainnetTester } from "../../../../typechain";
 
 export async function deployLinker(
@@ -6,8 +6,11 @@ export async function deployLinker(
     messageProxy: MessageProxyForMainnet | MessageProxyForMainnetTester
 ) {
     const factory = await ethers.getContractFactory("Linker");
-    const instance = await factory.deploy() as Linker;
-    await instance["initialize(address,address)"](contractManager.address, messageProxy.address);
+    const instance = await upgrades.deployProxy(
+        factory,
+        [contractManager.address, messageProxy.address],
+        {"initializer": "initialize(address,address)"}
+    ) as Linker;
     await instance.registerMainnetContract(instance.address);
     return instance;
 }
\ No newline at end of file
diff --git a/proxy/test/utils/deploy/mainnet/messageProxyForMainnet.ts b/proxy/test/utils/deploy/mainnet/messageProxyForMainnet.ts
index 00f79b0e8..adbca47fd 100644
--- a/proxy/test/utils/deploy/mainnet/messageProxyForMainnet.ts
+++ b/proxy/test/utils/deploy/mainnet/messageProxyForMainnet.ts
@@ -1,4 +1,4 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { ContractManager, MessageProxyForMainnet } from "../../../../typechain";
 
 const name = "MessageProxyForMainnet";
@@ -10,8 +10,7 @@ export async function deployMessageProxyForMainnet(
     if (await contractManager.getContract(name) !== "0x0000000000000000000000000000000000000000") {
         return factory.attach(await contractManager.getContract(name)) as MessageProxyForMainnet;
     } else {
-        const instance = await factory.deploy() as MessageProxyForMainnet;
-        await instance.initialize(contractManager.address);
+        const instance = await upgrades.deployProxy(factory, [contractManager.address]) as MessageProxyForMainnet;
         await contractManager.setContractsAddress(name, instance.address);
         return instance;
     }
diff --git a/proxy/test/utils/deploy/schain/communityLocker.ts b/proxy/test/utils/deploy/schain/communityLocker.ts
index 6482bd07a..c6b7a4e8d 100644
--- a/proxy/test/utils/deploy/schain/communityLocker.ts
+++ b/proxy/test/utils/deploy/schain/communityLocker.ts
@@ -1,4 +1,4 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { CommunityLocker, MessageProxyForSchain, TokenManagerLinker } from "../../../../typechain";
 
 const name = "CommunityLocker";
@@ -10,7 +10,9 @@ export async function deployCommunityLocker(
     communityPool: string
 ) {
     const factory = await ethers.getContractFactory(name);
-    const instance = await factory.deploy() as CommunityLocker;
-    await instance.initialize(schainName, messageProxyForSchain, tokenManagerLinker.address, communityPool)
+    const instance = await upgrades.deployProxy(
+        factory,
+        [schainName, messageProxyForSchain, tokenManagerLinker.address, communityPool]
+    ) as CommunityLocker;
     return instance;
 }
diff --git a/proxy/test/utils/deploy/schain/ethErc20.ts b/proxy/test/utils/deploy/schain/ethErc20.ts
index 0c09c812d..566f4743a 100644
--- a/proxy/test/utils/deploy/schain/ethErc20.ts
+++ b/proxy/test/utils/deploy/schain/ethErc20.ts
@@ -1,11 +1,10 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { EthErc20, TokenManagerEth } from "../../../../typechain";
 
 export async function deployEthErc20(
     tokenManagerEth: TokenManagerEth
 ) {
     const factory = await ethers.getContractFactory("EthErc20");
-    const instance = await factory.deploy() as EthErc20;
-    await instance.initialize(tokenManagerEth.address);
+    const instance = await upgrades.deployProxy(factory, [tokenManagerEth.address]) as EthErc20;
     return instance;
 }
diff --git a/proxy/test/utils/deploy/schain/messageProxyForSchain.ts b/proxy/test/utils/deploy/schain/messageProxyForSchain.ts
index df077b962..a64829039 100644
--- a/proxy/test/utils/deploy/schain/messageProxyForSchain.ts
+++ b/proxy/test/utils/deploy/schain/messageProxyForSchain.ts
@@ -1,11 +1,13 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { MessageProxyForSchain } from "../../../../typechain";
 
 const name = "MessageProxyForSchain";
 
 export async function deployMessageProxyForSchain(keyStorageAddress: string, schainName: string) {
     const factory = await ethers.getContractFactory(name);
-    const instance = await factory.deploy() as MessageProxyForSchain;
-    await instance.initialize(keyStorageAddress, schainName);
+    const instance = await upgrades.deployProxy(
+        factory,
+        [keyStorageAddress, schainName]
+    ) as MessageProxyForSchain;
     return instance;
 }
\ No newline at end of file
diff --git a/proxy/test/utils/deploy/schain/tokenManagerERC1155.ts b/proxy/test/utils/deploy/schain/tokenManagerERC1155.ts
index 14794c934..1e356d747 100644
--- a/proxy/test/utils/deploy/schain/tokenManagerERC1155.ts
+++ b/proxy/test/utils/deploy/schain/tokenManagerERC1155.ts
@@ -1,4 +1,4 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { TokenManagerERC1155, MessageProxyForSchain, TokenManagerLinker, CommunityLocker } from "../../../../typechain";
 
 const name = "TokenManagerERC1155";
@@ -11,12 +11,15 @@ export async function deployTokenManagerERC1155(
     newDepositBox: string
 ) {
     const factory = await ethers.getContractFactory(name);
-    const instance = await factory.deploy() as TokenManagerERC1155;
-    await instance.initialize(
-        schainName,
-        messageProxyForSchain,
-        tokenManagerLinker.address,
-        communityLocker.address,
-        newDepositBox)
+    const instance = await upgrades.deployProxy(
+        factory,
+        [
+            schainName,
+            messageProxyForSchain,
+            tokenManagerLinker.address,
+            communityLocker.address,
+            newDepositBox
+        ]
+    ) as TokenManagerERC1155;
     return instance;
 }
\ No newline at end of file
diff --git a/proxy/test/utils/deploy/schain/tokenManagerERC20.ts b/proxy/test/utils/deploy/schain/tokenManagerERC20.ts
index 7e22003be..bbf6d3631 100644
--- a/proxy/test/utils/deploy/schain/tokenManagerERC20.ts
+++ b/proxy/test/utils/deploy/schain/tokenManagerERC20.ts
@@ -1,4 +1,4 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { TokenManagerERC20, MessageProxyForSchain, TokenManagerLinker, CommunityLocker } from "../../../../typechain";
 
 const name = "TokenManagerERC20";
@@ -11,13 +11,15 @@ export async function deployTokenManagerERC20(
     newDepositBox: string
 ) {
     const factory = await ethers.getContractFactory(name);
-    const instance = await factory.deploy() as TokenManagerERC20;
-    await instance.initialize(
-        schainName,
-        messageProxyForSchain,
-        tokenManagerLinker.address,
-        communityLocker.address,
-        newDepositBox
-    );
+    const instance = await upgrades.deployProxy(
+        factory,
+        [
+            schainName,
+            messageProxyForSchain,
+            tokenManagerLinker.address,
+            communityLocker.address,
+            newDepositBox
+        ]
+    ) as TokenManagerERC20;
     return instance;
 }
\ No newline at end of file
diff --git a/proxy/test/utils/deploy/schain/tokenManagerERC721.ts b/proxy/test/utils/deploy/schain/tokenManagerERC721.ts
index 47116e828..278128d15 100644
--- a/proxy/test/utils/deploy/schain/tokenManagerERC721.ts
+++ b/proxy/test/utils/deploy/schain/tokenManagerERC721.ts
@@ -1,4 +1,4 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { TokenManagerERC721, MessageProxyForSchain, TokenManagerLinker, CommunityLocker } from "../../../../typechain";
 
 const name = "TokenManagerERC721";
@@ -11,13 +11,15 @@ export async function deployTokenManagerERC721(
     newDepositBox: string
 ) {
     const factory = await ethers.getContractFactory(name);
-    const instance = await factory.deploy() as TokenManagerERC721;
-    await instance.initialize(
-        schainName,
-        messageProxyForSchain,
-        tokenManagerLinker.address,
-        communityLocker.address,
-        newDepositBox
-    );
+    const instance = await upgrades.deployProxy(
+        factory,
+        [
+            schainName,
+            messageProxyForSchain,
+            tokenManagerLinker.address,
+            communityLocker.address,
+            newDepositBox
+        ]
+    ) as TokenManagerERC721;
     return instance;
 }
\ No newline at end of file
diff --git a/proxy/test/utils/deploy/schain/tokenManagerERC721WithMetadata.ts b/proxy/test/utils/deploy/schain/tokenManagerERC721WithMetadata.ts
index d6ae140d2..add9ee256 100644
--- a/proxy/test/utils/deploy/schain/tokenManagerERC721WithMetadata.ts
+++ b/proxy/test/utils/deploy/schain/tokenManagerERC721WithMetadata.ts
@@ -1,4 +1,4 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { TokenManagerERC721WithMetadata, MessageProxyForSchain, TokenManagerLinker, CommunityLocker } from "../../../../typechain";
 
 const name = "TokenManagerERC721WithMetadata";
@@ -11,13 +11,15 @@ export async function deployTokenManagerERC721WithMetadata(
     newDepositBox: string
 ) {
     const factory = await ethers.getContractFactory(name);
-    const instance = await factory.deploy() as TokenManagerERC721WithMetadata;
-    await instance.initialize(
-        schainName,
-        messageProxyForSchain,
-        tokenManagerLinker.address,
-        communityLocker.address,
-        newDepositBox
-    );
+    const instance = await upgrades.deployProxy(
+        factory,
+        [
+            schainName,
+            messageProxyForSchain,
+            tokenManagerLinker.address,
+            communityLocker.address,
+            newDepositBox
+        ]
+    ) as TokenManagerERC721WithMetadata;
     return instance;
 }
\ No newline at end of file
diff --git a/proxy/test/utils/deploy/schain/tokenManagerEth.ts b/proxy/test/utils/deploy/schain/tokenManagerEth.ts
index 8c007eb0f..6249ec31c 100644
--- a/proxy/test/utils/deploy/schain/tokenManagerEth.ts
+++ b/proxy/test/utils/deploy/schain/tokenManagerEth.ts
@@ -1,4 +1,4 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { TokenManagerEth, MessageProxyForSchain, TokenManagerLinker, CommunityLocker } from "../../../../typechain";
 
 const name = "TokenManagerEth";
@@ -12,14 +12,16 @@ export async function deployTokenManagerEth(
     ethErc20Address: string
 ) {
     const factory = await ethers.getContractFactory(name);
-    const instance = await factory.deploy() as TokenManagerEth;
-    await instance.initialize(
-        schainName,
-        messageProxyForSchain,
-        tokenManagerLinker.address,
-        communityLocker.address,
-        newDepositBox,
-        ethErc20Address
-    );
+    const instance = await upgrades.deployProxy(
+        factory,
+        [
+            schainName,
+            messageProxyForSchain,
+            tokenManagerLinker.address,
+            communityLocker.address,
+            newDepositBox,
+            ethErc20Address
+        ]
+    ) as TokenManagerEth;
     return instance;
 }
\ No newline at end of file
diff --git a/proxy/test/utils/deploy/schain/tokenManagerLinker.ts b/proxy/test/utils/deploy/schain/tokenManagerLinker.ts
index 7066a76c7..4d181c11c 100644
--- a/proxy/test/utils/deploy/schain/tokenManagerLinker.ts
+++ b/proxy/test/utils/deploy/schain/tokenManagerLinker.ts
@@ -1,4 +1,4 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { TokenManagerLinker, MessageProxyForSchain, MessageProxyForSchainTester, MessageProxyForSchainWithoutSignature } from "../../../../typechain";
 
 export async function deployTokenManagerLinker(
@@ -6,7 +6,6 @@ export async function deployTokenManagerLinker(
     newLinkerAddress: string
 ) {
     const factory = await ethers.getContractFactory("TokenManagerLinker");
-    const instance = await factory.deploy() as TokenManagerLinker;
-    await instance.initialize(messageProxyForSchain.address, newLinkerAddress);
+    const instance = await upgrades.deployProxy(factory, [messageProxyForSchain.address, newLinkerAddress]) as TokenManagerLinker;
     return instance;
 }
diff --git a/proxy/test/utils/deploy/test/communityPoolTester.ts b/proxy/test/utils/deploy/test/communityPoolTester.ts
index f9f490abd..1fcaf8a00 100644
--- a/proxy/test/utils/deploy/test/communityPoolTester.ts
+++ b/proxy/test/utils/deploy/test/communityPoolTester.ts
@@ -1,4 +1,4 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { ContractManager, MessageProxyForMainnetTester, Linker, CommunityPool } from "../../../../typechain";
 
 
@@ -8,8 +8,11 @@ export async function deployCommunityPoolTester(
     messageProxy: MessageProxyForMainnetTester
 ) {
     const factory = await ethers.getContractFactory("CommunityPool");
-    const instance = await factory.deploy() as CommunityPool;
-    await instance["initialize(address,address,address)"](contractManager.address, linker.address, messageProxy.address);
+    const instance = await upgrades.deployProxy(
+        factory,
+        [contractManager.address, linker.address, messageProxy.address],
+        {"initializer": "initialize(address,address,address)"}
+    ) as CommunityPool;
     await linker.registerMainnetContract(instance.address);
     await messageProxy.setCommunityPool(instance.address);
     return instance;
diff --git a/proxy/test/utils/deploy/test/messageProxyForMainnetTester.ts b/proxy/test/utils/deploy/test/messageProxyForMainnetTester.ts
index 009ab3680..23b864798 100644
--- a/proxy/test/utils/deploy/test/messageProxyForMainnetTester.ts
+++ b/proxy/test/utils/deploy/test/messageProxyForMainnetTester.ts
@@ -1,4 +1,4 @@
-import { ethers } from "hardhat";
+import { ethers, upgrades } from "hardhat";
 import { ContractManager, MessageProxyForMainnetTester } from "../../../../typechain";
 
 const name = "MessageProxyForMainnetTester";
@@ -10,8 +10,10 @@ export async function deployMessageProxyForMainnetTester(
     if (await contractManager.getContract(name) !== "0x0000000000000000000000000000000000000000") {
         return factory.attach(await contractManager.getContract(name)) as MessageProxyForMainnetTester;
     } else {
-        const instance = await factory.deploy() as MessageProxyForMainnetTester;
-        await instance.initialize(contractManager.address);
+        const instance = await upgrades.deployProxy(
+            factory,
+            [contractManager.address]
+        ) as MessageProxyForMainnetTester;
         await contractManager.setContractsAddress(name, instance.address);
         return instance;
     }
diff --git a/test-tokens/contracts/ERC721Custom.sol b/test-tokens/contracts/ERC721Custom.sol
index bf3e11283..243499f93 100644
--- a/test-tokens/contracts/ERC721Custom.sol
+++ b/test-tokens/contracts/ERC721Custom.sol
@@ -74,7 +74,7 @@ contract ERC721Custom {
     }
 
     function getApproved(uint256 tokenId) public view returns (address) {
-        require(_exists(tokenId), "ERC721: approved query for nonexistent token");
+        require(_exists(tokenId), "ERC721: invalid token ID");
 
         return _tokenApprovals[tokenId];
     }