diff --git a/.gitignore b/.gitignore
index 305350c..828b11c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
 node_modules
-
+package-lock.json
 #Hardhat files
 cache
 artifacts
@@ -13,4 +13,6 @@ contract-deployed.env
 ganache/
 
 # secrets
-/secrets.json
\ No newline at end of file
+/secrets.json
+accounts.json
+deployed.json
\ No newline at end of file
diff --git a/contracts/Bytes.sol b/contracts/Bytes.sol
new file mode 100644
index 0000000..d6258dd
--- /dev/null
+++ b/contracts/Bytes.sol
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+
+pragma solidity ^0.8.0;
+
+library Bytes {
+    function shiftAndReverseBits8(uint8 val, uint8 offset)
+        internal
+        pure
+        returns (uint256 ret)
+    {
+        uint16 effectLen = offset < 248 ? 8 : 256 - offset;
+        for (uint16 i = 0; i < effectLen; i++) {
+            if (val & 1 == 1) {
+                ret += (1 << (255 - i - offset));
+            }
+            val >>= 1;
+        }
+    }
+
+    function shiftAndReverseBits16(uint16 val, uint8 offset)
+        internal
+        pure
+        returns (uint256 ret)
+    {
+        uint16 effectLen = offset < 240 ? 16 : 256 - offset;
+        for (uint16 i = 0; i < effectLen; i++) {
+            if (val & 1 == 1) {
+                ret += (1 << (255 - i - offset));
+            }
+            val >>= 1;
+        }
+    }
+
+    function shiftAndReverseBits32(uint32 val, uint8 offset)
+        internal
+        pure
+        returns (uint256 ret)
+    {
+        uint16 effectLen = offset < 224 ? 32 : 256 - offset;
+        for (uint16 i = 0; i < effectLen; i++) {
+            if (val & 1 == 1) {
+                ret += (1 << (255 - i - offset));
+            }
+            val >>= 1;
+        }
+    }
+
+    function shiftAndReverseBits64(uint64 val, uint8 offset)
+        internal
+        pure
+        returns (uint256 ret)
+    {
+        uint16 effectLen = offset < 192 ? 64 : 256 - offset;
+        for (uint16 i = 0; i < effectLen; i++) {
+            if (val & 1 == 1) {
+                ret += (1 << (255 - i - offset));
+            }
+            val >>= 1;
+        }
+    }
+
+    function shiftAndReverseBits128(uint128 val, uint8 offset)
+        internal
+        pure
+        returns (uint256 ret)
+    {
+        uint16 effectLen = offset < 128 ? 128 : 256 - offset;
+        for (uint16 i = 0; i < effectLen; i++) {
+            if (val & 1 == 1) {
+                ret += (1 << (255 - i - offset));
+            }
+            val >>= 1;
+        }
+    }
+
+    function shiftAndReverseBits(uint256 val, uint8 offset)
+        internal
+        pure
+        returns (uint256 ret)
+    {
+        for (uint16 i = 0; i < 256 - offset; i++) {
+            if (val & 1 == 1) {
+                ret += (1 << (255 - i - offset));
+            }
+            val >>= 1;
+        }
+    }
+
+    //see https://ethereum.stackexchange.com/questions/83626/how-to-reverse-byte-order-in-uint256-or-bytes32
+    function swapBytes(uint256 input) internal pure returns (uint256 v) {
+        v = input;
+
+        // swap bytes
+        v =
+            ((v &
+                0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >>
+                8) |
+            ((v &
+                0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) <<
+                8);
+
+        // swap 2-byte long pairs
+        v =
+            ((v &
+                0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >>
+                16) |
+            ((v &
+                0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) <<
+                16);
+
+        // swap 4-byte long pairs
+        v =
+            ((v &
+                0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >>
+                32) |
+            ((v &
+                0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) <<
+                32);
+
+        // swap 8-byte long pairs
+        v =
+            ((v &
+                0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >>
+                64) |
+            ((v &
+                0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) <<
+                64);
+
+        // swap 16-byte long pairs
+        v = (v >> 128) | (v << 128);
+    }
+
+    // See comment at the top of this file for explanation of how this function works.
+    // NOTE: theoretically possible overflow of (_start + 0x2)
+    function bytesToUInt16(bytes memory _bytes, uint256 _start)
+        internal
+        pure
+        returns (uint16 r)
+    {
+        uint256 offset = _start + 0x2;
+        require(_bytes.length >= offset, "T");
+        assembly {
+            r := mload(add(_bytes, offset))
+        }
+    }
+
+    // NOTE: theoretically possible overflow of (_offset + 2)
+    function readUInt16(bytes memory _data, uint256 _offset)
+        internal
+        pure
+        returns (uint256 newOffset, uint16 r)
+    {
+        newOffset = _offset + 2;
+        r = bytesToUInt16(_data, _offset);
+    }
+}
diff --git a/contracts/FluiDex.sol b/contracts/FluiDex.sol
index c8f8907..7c1df55 100644
--- a/contracts/FluiDex.sol
+++ b/contracts/FluiDex.sol
@@ -5,17 +5,25 @@ pragma solidity ^0.8.0;
 import "@openzeppelin/contracts/access/AccessControl.sol";
 import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
 import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
+import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
 import "@openzeppelin/contracts/access/Ownable.sol";
 import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
 import "hardhat/console.sol"; // for debugging
 
 import "./IFluiDex.sol";
 import "./IVerifier.sol";
+import "./Storage.sol";
 
 /**
  * @title FluiDexDemo
  */
-contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard {
+contract FluiDexDemo is
+    AccessControl,
+    IFluiDex,
+    Ownable,
+    ReentrancyGuard,
+    Storage
+{
     using SafeERC20 for IERC20;
 
     bytes32 public constant PLUGIN_ADMIN_ROLE = keccak256("PLUGIN_ADMIN_ROLE");
@@ -37,6 +45,7 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard {
 
     uint16 public tokenNum;
     mapping(uint16 => address) public tokenIdToAddr;
+    mapping(uint16 => uint8) public tokenScales;
     mapping(address => uint16) public tokenAddrToId;
 
     uint16 public userNum;
@@ -51,6 +60,9 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard {
         _setRoleAdmin(DELEGATE_ROLE, DEFAULT_ADMIN_ROLE);
         grantRole(PLUGIN_ADMIN_ROLE, msg.sender);
         grantRole(DELEGATE_ROLE, msg.sender);
+
+        //TODO: define defaut scale of ETH: eth (10^18 wei) with prec 6 so we get
+        tokenScales[0] = 12;
     }
 
     /**
@@ -68,9 +80,10 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard {
     /**
      * @notice request to add a new ERC20 token
      * @param tokenAddr the ERC20 token address
+     * @param prec specify the precise inside fluidex
      * @return the new ERC20 token tokenId
      */
-    function addToken(address tokenAddr)
+    function addToken(address tokenAddr, uint8 prec)
         external
         override
         nonReentrant
@@ -85,6 +98,9 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard {
         tokenIdToAddr[tokenId] = tokenAddr;
         tokenAddrToId[tokenAddr] = tokenId;
 
+        uint8 tokenDecimal = IERC20Metadata(tokenAddr).decimals();
+        require(tokenDecimal >= prec, "prec can not exceed token's decimal");
+        tokenScales[tokenId] = tokenDecimal - prec;
         return tokenId;
     }
 
@@ -96,25 +112,61 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard {
         payable
         override
         onlyRole(DELEGATE_ROLE)
-    {}
+        returns (uint128 realAmount)
+    {
+        uint16 accountId = userBjjPubkeyToUserId[to];
+        require(accountId != 0, "non-existed user");
+        realAmount = Operations.scaleTokenValueToAmount(
+            msg.value,
+            tokenScales[0]
+        );
+
+        Operations.Deposit memory op = Operations.Deposit({
+            accountId: accountId,
+            tokenId: 0,
+            amount: realAmount
+        });
+
+        addPriorityRequest(
+            Operations.OpType.Deposit,
+            Operations.writeDepositPubdataForPriorityQueue(op)
+        );
+    }
 
     /**
      * @param amount the deposit amount.
      */
-    function depositERC20(IERC20 token, uint256 amount)
+    function depositERC20(
+        IERC20 token,
+        bytes32 to,
+        uint256 amount
+    )
         external
         override
         nonReentrant
         tokenExist(token)
         onlyRole(DELEGATE_ROLE)
-        returns (uint16 tokenId, uint256 realAmount)
+        returns (uint16 tokenId, uint128 realAmount)
     {
         tokenId = tokenAddrToId[address(token)];
 
-        uint256 balanceBeforeDeposit = token.balanceOf(address(this));
-        token.safeTransferFrom(msg.sender, address(this), amount);
-        uint256 balanceAfterDeposit = token.balanceOf(address(this));
-        realAmount = balanceAfterDeposit - balanceBeforeDeposit;
+        uint16 accountId = userBjjPubkeyToUserId[to];
+        require(accountId != 0, "non-existed user");
+        realAmount = Operations.scaleTokenValueToAmount(
+            amount,
+            tokenScales[tokenId]
+        );
+
+        Operations.Deposit memory op = Operations.Deposit({
+            accountId: accountId,
+            tokenId: tokenId,
+            amount: realAmount
+        });
+
+        addPriorityRequest(
+            Operations.OpType.Deposit,
+            Operations.writeDepositPubdataForPriorityQueue(op)
+        );
     }
 
     /**
@@ -138,6 +190,16 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard {
             bjjPubkey: bjjPubkey
         });
         userBjjPubkeyToUserId[bjjPubkey] = userId;
+
+        Operations.Registry memory op = Operations.Registry({
+            accountId: userId,
+            l2key: bjjPubkey
+        });
+
+        addPriorityRequest(
+            Operations.OpType.Registry,
+            Operations.writeRegistryPubdataForPriorityQueue(op)
+        );
     }
 
     function getBlockStateByBlockId(uint256 _block_id)
@@ -150,17 +212,137 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard {
     }
 
     /**
-     * @notice request to submit a new l2 block
-     * @param _block_id the l2 block id
+     * @notice to verify the validity of a sole block
      * @param _public_inputs the public inputs of this block
      * @param _serialized_proof the serialized proof of this block
+     * @param _public_data the serialized tx data inside this block (data availability)
+     * @return true if the block was accepted
+     */
+    function verifyBlock(
+        uint256[] calldata _public_inputs,
+        uint256[] calldata _serialized_proof,
+        bytes calldata _public_data,
+        bytes calldata _priority_op_index
+    ) public view returns (uint64) {
+        // _public_inputs[2]/[3] is the low/high 128bit of sha256 hash of _public_data respectively
+        require(_public_inputs.length >= 4, "invalid public input fields");
+
+        bytes32 h = sha256(_public_data);
+
+        //console.logBytes(_public_data);
+        //console.logBytes32(h);
+
+        uint256 h_lo = 0;
+        for (uint256 i = 0; i < 16; i++) {
+            uint256 tmp = uint256(uint8(h[i + 16])) << (120 - 8 * i);
+            h_lo = h_lo + tmp;
+        }
+        uint256 h_hi = 0;
+        for (uint256 i = 0; i < 16; i++) {
+            uint256 tmp = uint256(uint8(h[i])) << (120 - 8 * i);
+            h_hi = h_hi + tmp;
+        }
+
+        require(
+            _public_inputs[2] == h_hi && _public_inputs[3] == h_lo,
+            "tx data invalid"
+        );
+
+        uint64 next_priority_op = firstPriorityRequestId;
+        if (_priority_op_index.length != 0) {
+            (bool pass, uint64 nextIndex) = verifyPriorityOp(
+                _public_data,
+                _priority_op_index
+            );
+            /*            console.log(
+                "start from %d, stop in index %d, current %d",
+                firstPriorityRequestId,
+                nextIndex,
+                totalOpenPriorityRequests
+            );*/
+            require(pass, "handling priority ops incorrect");
+            next_priority_op = nextIndex;
+        }
+
+        require(
+            verifier.verify_serialized_proof(_public_inputs, _serialized_proof),
+            "proof is invalid"
+        );
+        return next_priority_op;
+    }
+
+    /**
+     * @notice request to submit a new l2 block, same parameters with verifySubmitting
      * @return true if the block was accepted
      */
     function submitBlock(
         uint256 _block_id,
-        uint256[] memory _public_inputs,
-        uint256[] memory _serialized_proof
+        uint256[] calldata _public_inputs,
+        uint256[] calldata _serialized_proof,
+        bytes calldata _public_data,
+        bytes calldata _priority_op_index
     ) external override returns (bool) {
+        require(_public_inputs.length >= 2);
+        if (_block_id == 0) {
+            assert(_public_inputs[0] == GENESIS_ROOT);
+        } else {
+            assert(_public_inputs[0] == state_roots[_block_id - 1]);
+        }
+
+        if (_serialized_proof.length != 0) {
+            uint64 nextIndex = verifyBlock(
+                _public_inputs,
+                _serialized_proof,
+                _public_data,
+                _priority_op_index
+            );
+
+            //forward priority op
+            assert(
+                totalOpenPriorityRequests >= nextIndex - firstPriorityRequestId
+            );
+            totalOpenPriorityRequests -= nextIndex - firstPriorityRequestId;
+            firstPriorityRequestId = nextIndex;
+
+            if (_block_id > 0) {
+                require(
+                    block_states[_block_id - 1] == BlockState.Verified,
+                    "Previous block must be verified"
+                );
+            }
+            require(
+                block_states[_block_id] != BlockState.Verified,
+                "Block must not be submitted twice"
+            );
+            block_states[_block_id] = BlockState.Verified;
+        } else {
+            // mark a block as Committed directly, because we may
+            // temporarily run out of proving resource.
+            // note: Committing a block without a rollback/revert mechanism should
+            // only happen in demo version!
+            if (_block_id > 0) {
+                assert(block_states[_block_id - 1] != BlockState.Empty);
+            }
+            assert(block_states[_block_id] == BlockState.Empty);
+            block_states[_block_id] = BlockState.Committed;
+        }
+
+        state_roots[_block_id] = _public_inputs[1];
+        return true;
+    }
+
+    /**
+     * @notice request to submit a new l2 block
+     * @param _block_id the l2 block id
+     * @param _public_inputs the public inputs of this block
+     * @param _serialized_proof the serialized proof of this block
+     * @return true if the block was accepted
+     */
+    function submitBlockLegacy(
+        uint256 _block_id,
+        uint256[] calldata _public_inputs,
+        uint256[] calldata _serialized_proof
+    ) external returns (bool) {
         // _public_inputs[0] is previous_state_root
         // _public_inputs[1] is new_state_root
         require(_public_inputs.length >= 2);
diff --git a/contracts/FluiDexDelegate.sol b/contracts/FluiDexDelegate.sol
index 955d09e..ab2346f 100644
--- a/contracts/FluiDexDelegate.sol
+++ b/contracts/FluiDexDelegate.sol
@@ -47,15 +47,16 @@ contract FluiDexDelegate is
     /**
      * @notice request to add a new ERC20 token
      * @param tokenAddr the ERC20 token address
+     * @param prec specify the precise inside fluidex
      * @return tokenId the new ERC20 token tokenId
      */
-    function addToken(address tokenAddr)
+    function addToken(address tokenAddr, uint8 prec)
         external
         override
         onlyRole(TOKEN_ADMIN_ROLE)
         returns (uint16 tokenId)
     {
-        tokenId = target.addToken(tokenAddr);
+        tokenId = target.addToken(tokenAddr, prec);
         emit NewToken(msg.sender, tokenAddr, tokenId);
     }
 
@@ -80,18 +81,15 @@ contract FluiDexDelegate is
         IERC20 token,
         bytes32 to,
         uint256 amount
-    ) external override {
+    ) external override orCreateUser(msg.sender, to) {
         uint256 balanceBeforeDeposit = token.balanceOf(address(this));
         token.safeTransferFrom(msg.sender, address(this), amount);
         uint256 balanceAfterDeposit = token.balanceOf(address(this));
         uint256 realAmount = balanceAfterDeposit - balanceBeforeDeposit;
         token.safeIncreaseAllowance(address(target), realAmount);
 
-        (uint16 tokenId, uint256 finalAmount) = target.depositERC20(
-            token,
-            realAmount
-        );
-        emit Deposit(tokenId, to, finalAmount);
+        (uint16 tokenId, ) = target.depositERC20(token, to, realAmount);
+        emit Deposit(tokenId, to, realAmount);
     }
 
     /**
@@ -103,10 +101,19 @@ contract FluiDexDelegate is
      */
     function submitBlock(
         uint256 _block_id,
-        uint256[] memory _public_inputs,
-        uint256[] memory _serialized_proof
+        uint256[] calldata _public_inputs,
+        uint256[] calldata _serialized_proof,
+        bytes calldata _public_data,
+        bytes calldata _priority_op_index
     ) external override returns (bool) {
-        return target.submitBlock(_block_id, _public_inputs, _serialized_proof);
+        return
+            target.submitBlock(
+                _block_id,
+                _public_inputs,
+                _serialized_proof,
+                _public_data,
+                _priority_op_index
+            );
     }
 
     /**
diff --git a/contracts/IFluiDex.sol b/contracts/IFluiDex.sol
index 96f1826..7c3c763 100644
--- a/contracts/IFluiDex.sol
+++ b/contracts/IFluiDex.sol
@@ -19,21 +19,27 @@ interface IFluiDex {
     /**
      * @notice request to add a new ERC20 token
      * @param tokenAddr the ERC20 token address
+     * @param prec specify the precise inside fluidex
      * @return the new ERC20 token tokenId
      */
-    function addToken(address tokenAddr) external returns (uint16);
+    function addToken(address tokenAddr, uint8 prec) external returns (uint16);
 
     /**
      * @param to the L2 address (bjjPubkey) of the deposit target.
      */
-    function depositETH(bytes32 to) external payable;
+    function depositETH(bytes32 to)
+        external
+        payable
+        returns (uint128 realAmount);
 
     /**
      * @param amount the deposit amount.
      */
-    function depositERC20(IERC20 token, uint256 amount)
-        external
-        returns (uint16 tokenId, uint256 realAmount);
+    function depositERC20(
+        IERC20 token,
+        bytes32 to,
+        uint256 amount
+    ) external returns (uint16 tokenId, uint128 realAmount);
 
     function getBlockStateByBlockId(uint256 _block_id)
         external
@@ -44,12 +50,16 @@ interface IFluiDex {
      * @param _block_id the l2 block id
      * @param _public_inputs the public inputs of this block
      * @param _serialized_proof the serialized proof of this block
+     * @param _public_data the serialized tx data inside this block (data availability)
+     * @param _priority_op_index the positions of priority op in public data
      * @return true if the block was accepted
      */
     function submitBlock(
         uint256 _block_id,
-        uint256[] memory _public_inputs,
-        uint256[] memory _serialized_proof
+        uint256[] calldata _public_inputs,
+        uint256[] calldata _serialized_proof,
+        bytes calldata _public_data,
+        bytes calldata _priority_op_index
     ) external returns (bool);
 
     /**
diff --git a/contracts/IFluiDexDelegate.sol b/contracts/IFluiDexDelegate.sol
index 23605f5..df5be32 100644
--- a/contracts/IFluiDexDelegate.sol
+++ b/contracts/IFluiDexDelegate.sol
@@ -8,9 +8,10 @@ interface IFluiDexDelegate {
     /**
      * @notice request to add a new ERC20 token
      * @param tokenAddr the ERC20 token address
+     * @param prec specify the precise inside fluidex
      * @return the new ERC20 token tokenId
      */
-    function addToken(address tokenAddr) external returns (uint16);
+    function addToken(address tokenAddr, uint8 prec) external returns (uint16);
 
     /**
      * @param to the L2 address (bjjPubkey) of the deposit target.
@@ -32,11 +33,15 @@ interface IFluiDexDelegate {
      * @param _block_id the l2 block id
      * @param _public_inputs the public inputs of this block
      * @param _serialized_proof the serialized proof of this block
+     * @param _public_data the serialized tx data inside this block (data availability)
+     * @param _priority_op_index the positions of priority op in public data
      * @return true if the block was accepted
      */
     function submitBlock(
         uint256 _block_id,
-        uint256[] memory _public_inputs,
-        uint256[] memory _serialized_proof
+        uint256[] calldata _public_inputs,
+        uint256[] calldata _serialized_proof,
+        bytes calldata _public_data,
+        bytes calldata _priority_op_index
     ) external returns (bool);
 }
diff --git a/contracts/Operations.sol b/contracts/Operations.sol
new file mode 100644
index 0000000..0356974
--- /dev/null
+++ b/contracts/Operations.sol
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+
+pragma solidity ^0.8.0;
+pragma experimental ABIEncoderV2;
+
+import "./Bytes.sol";
+import "./Utils.sol";
+import "hardhat/console.sol"; //for debugging
+
+/// @title Fluidex operations tools
+library Operations {
+    /// @notice Config parameters, generated from circuit parameters
+    uint8 constant BALANCE_BITS = 3;
+    uint8 constant ACCOUNT_BITS = 5;
+    uint8 constant ORDER_BITS = 3;
+    uint256 constant TX_PUBDATA_BYTES = 33;
+
+    /// @dev Expected average period of block creation
+    uint256 internal constant BLOCK_PERIOD = 15 seconds;
+
+    /// @dev Expiration delta for priority request to be satisfied (in seconds)
+    /// @dev NOTE: Priority expiration should be > (EXPECT_VERIFICATION_IN * BLOCK_PERIOD)
+    /// @dev otherwise incorrect block with priority op could not be reverted.
+    uint256 internal constant PRIORITY_EXPIRATION_PERIOD = 7 days;
+
+    /// @dev Expiration delta for priority request to be satisfied (in ETH blocks)
+    uint256 internal constant PRIORITY_EXPIRATION =
+        PRIORITY_EXPIRATION_PERIOD / BLOCK_PERIOD;
+
+    /// @notice Fluidex circuit operation type
+    enum OpType {
+        Deposit,
+        Registry
+    }
+
+    function hashPubData(bytes calldata _public_data, uint256 pos)
+        internal
+        pure
+        returns (bytes20)
+    {
+        uint256 start = pos * TX_PUBDATA_BYTES;
+
+        return
+            Utils.hashBytesToBytes20(
+                _public_data[start:start + TX_PUBDATA_BYTES]
+            );
+    }
+
+    // Registry L2key pubdata
+    struct Registry {
+        uint32 accountId;
+        bytes32 l2key;
+    }
+
+    // Deposit pubdata
+    struct Deposit {
+        uint32 accountId;
+        uint16 tokenId;
+        uint128 amount;
+    }
+
+    function scaleTokenValueToAmount(uint256 value, uint8 scale)
+        internal
+        pure
+        returns (uint128)
+    {
+        //require(scale > 0, "Known token must has a scaling");
+        //notice scale can be zero if the decimal just equal to the prec used inside fluidex
+        return uint128(value / (10**scale));
+    }
+
+    function hashOpDataFromBuf(bytes memory buf)
+        internal
+        pure
+        returns (bytes20)
+    {
+        bytes memory truncatedBuf = new bytes(TX_PUBDATA_BYTES);
+        for (uint256 i = 0; i < TX_PUBDATA_BYTES; i++) {
+            truncatedBuf[i] = buf[i];
+        }
+
+        return Utils.hashBytesToBytes20(truncatedBuf);
+    }
+
+    /// Serialize registry pubdata
+    function writeRegistryPubdataForPriorityQueue(Registry memory op)
+        internal
+        pure
+        returns (bytes20)
+    {
+        uint256 encoded_1 = 0;
+        uint8 offset = 0;
+        encoded_1 += Bytes.shiftAndReverseBits8(uint8(1), offset); //100 in bits
+        offset += 3;
+        encoded_1 += Bytes.shiftAndReverseBits32(op.accountId, offset);
+        offset += ACCOUNT_BITS;
+        uint8 sign = op.l2key[31] & 0x80 != 0 ? 1 : 0;
+        encoded_1 += Bytes.shiftAndReverseBits8(sign, offset);
+        offset += 1;
+        uint256 ay = uint256(op.l2key);
+        ay -= (uint8(op.l2key[31]) - uint8(op.l2key[31] & 0x7f));
+        //notice babyjub consider the read bytes as LITTLE-endian integer
+        ay = Bytes.swapBytes(ay);
+        encoded_1 += Bytes.shiftAndReverseBits(ay, offset);
+        //calc the resident of bits in ay
+        ay >>= (256 - offset);
+        uint256 encoded_2 = Bytes.shiftAndReverseBits(ay, 0);
+
+        return hashOpDataFromBuf(abi.encodePacked(encoded_1, encoded_2));
+    }
+
+    /// Serialize deposit pubdata
+    function writeDepositPubdataForPriorityQueue(Deposit memory op)
+        internal
+        pure
+        returns (bytes20)
+    {
+        uint256 encoded_1 = 0;
+        uint8 offset = 0;
+        encoded_1 += Bytes.shiftAndReverseBits8(uint8(0), offset); //000 in bits
+        offset += 3;
+        encoded_1 += Bytes.shiftAndReverseBits32(op.accountId, offset);
+        offset += ACCOUNT_BITS;
+        //according to the encoding scheme we need to encode account id twice
+        encoded_1 += Bytes.shiftAndReverseBits32(op.accountId, offset);
+        offset += ACCOUNT_BITS;
+        encoded_1 += Bytes.shiftAndReverseBits16(op.tokenId, offset);
+        offset += BALANCE_BITS;
+        assert(offset <= 128);
+
+        encoded_1 += Bytes.shiftAndReverseBits128(op.amount, offset);
+
+        return hashOpDataFromBuf(abi.encodePacked(encoded_1, uint256(0)));
+    }
+}
diff --git a/contracts/Storage.sol b/contracts/Storage.sol
new file mode 100644
index 0000000..8281dda
--- /dev/null
+++ b/contracts/Storage.sol
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+
+pragma solidity ^0.8.0;
+
+import "./Operations.sol";
+
+/// @title Fluidex storage contract
+contract Storage {
+    /// @notice First open priority request id
+    uint64 public firstPriorityRequestId;
+
+    /// @notice Total number of requests
+    uint64 public totalOpenPriorityRequests;
+
+    /// @notice Priority Operation container
+    /// @member hashedPubData Hashed priority operation public data
+    /// @member expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)
+    /// @member opType Priority operation type
+    struct PriorityOperation {
+        bytes20 hashedPubData;
+        uint64 expirationBlock;
+        Operations.OpType opType;
+    }
+
+    /// @dev Priority Requests mapping (request id - operation)
+    /// @dev Contains op type, pubdata and expiration block of unsatisfied requests.
+    /// @dev Numbers are in order of requests receiving
+    mapping(uint64 => PriorityOperation) internal priorityRequests;
+
+    /// @notice Check if priorityOp in queue has expired
+    function checkPriorityOpExpiration() public view returns (bool) {
+        if (totalOpenPriorityRequests == 0) return false;
+
+        return
+            priorityRequests[firstPriorityRequestId].expirationBlock <
+            block.number;
+    }
+
+    /// @notice Verify priorityOp inside the calling public data match the priority queue
+    /// @dev Calculates expiration block for request, store this request and emit NewPriorityRequest event
+    /// @param _public_data Calling public_data
+    /// @param _op_indexs indexs specify which op should be checked
+    function verifyPriorityOp(
+        bytes calldata _public_data,
+        bytes calldata _op_indexs
+    ) public view returns (bool _ret, uint64 _priorityRequestId) {
+        //_op_indexs is uint16 being encode packed
+        assert(_op_indexs.length % 2 == 0);
+        assert(_public_data.length % Operations.TX_PUBDATA_BYTES == 0);
+
+        require(
+            !checkPriorityOpExpiration() ||
+                //last chance: we put all effort on priority ops when they have expired
+                _op_indexs.length / 2 == totalOpenPriorityRequests ||
+                _public_data.length / Operations.TX_PUBDATA_BYTES ==
+                _op_indexs.length / 2,
+            "priority op must be handled before expiration"
+        );
+
+        _priorityRequestId = firstPriorityRequestId;
+
+        for (uint256 i = 0; i < _op_indexs.length; i += 2) {
+            //TODO: with compiler later than 0.8.10 we can use slice
+            //uint pos = uint16(bytes2(_op_indexs[i:i+2]));
+            uint256 pos = uint256(uint8(_op_indexs[i])) *
+                256 +
+                uint256(uint8(_op_indexs[i + 1]));
+            assert(pos < _public_data.length);
+            bytes20 hashedPubdata = priorityRequests[_priorityRequestId]
+            .hashedPubData;
+            if (Operations.hashPubData(_public_data, pos) != hashedPubdata) {
+                return (false, _priorityRequestId);
+            }
+            _priorityRequestId++;
+        }
+
+        _ret = true;
+    }
+
+    /// @notice Saves priority request in storage
+    /// @dev Calculates expiration block for request, store this request and emit NewPriorityRequest event
+    /// @param _opType Rollup operation type
+    /// @param _hashedPubData Hashed Operation pubdata
+    function addPriorityRequest(
+        Operations.OpType _opType,
+        bytes20 _hashedPubData
+    ) internal {
+        // Expiration block is: current block number + priority expiration delta
+        uint64 expirationBlock = uint64(
+            block.number + Operations.PRIORITY_EXPIRATION
+        );
+
+        uint64 nextPriorityRequestId = firstPriorityRequestId +
+            totalOpenPriorityRequests;
+
+        priorityRequests[nextPriorityRequestId] = PriorityOperation({
+            hashedPubData: _hashedPubData,
+            expirationBlock: expirationBlock,
+            opType: _opType
+        });
+
+        totalOpenPriorityRequests++;
+    }
+}
diff --git a/contracts/TestLibs.sol b/contracts/TestLibs.sol
new file mode 100644
index 0000000..87ea3dd
--- /dev/null
+++ b/contracts/TestLibs.sol
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+
+pragma solidity ^0.8.0;
+
+import "./Operations.sol";
+
+/// @title Unittest contract for libraries
+contract TestLibs {
+    function testBitsOp8(uint8 val, uint8 offset)
+        public
+        pure
+        returns (uint256)
+    {
+        return Bytes.shiftAndReverseBits8(val, offset);
+    }
+
+    function testBitsOp32(uint32 val, uint8 offset)
+        public
+        pure
+        returns (uint256)
+    {
+        return Bytes.shiftAndReverseBits32(val, offset);
+    }
+
+    function testBitsOp256(uint256 val, uint8 offset)
+        public
+        pure
+        returns (uint256)
+    {
+        return Bytes.shiftAndReverseBits(val, offset);
+    }
+
+    function testWriteRegistryPubdata(uint32 accId, bytes32 l2key)
+        public
+        pure
+        returns (bytes20)
+    {
+        Operations.Registry memory op = Operations.Registry({
+            accountId: accId,
+            l2key: l2key
+        });
+
+        return Operations.writeRegistryPubdataForPriorityQueue(op);
+    }
+
+    function testWriteDepositPubdata(
+        uint32 accId,
+        uint16 tokenId,
+        uint128 amount
+    ) public pure returns (bytes20) {
+        Operations.Deposit memory op = Operations.Deposit({
+            accountId: accId,
+            tokenId: tokenId,
+            amount: amount
+        });
+
+        return Operations.writeDepositPubdataForPriorityQueue(op);
+    }
+}
diff --git a/contracts/Utils.sol b/contracts/Utils.sol
new file mode 100644
index 0000000..500671d
--- /dev/null
+++ b/contracts/Utils.sol
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+
+pragma solidity ^0.8.0;
+
+library Utils {
+    function hashBytesToBytes20(bytes memory _bytes)
+        internal
+        pure
+        returns (bytes20)
+    {
+        return bytes20(uint160(uint256(keccak256(_bytes))));
+    }
+}
diff --git a/package.json b/package.json
index c27de65..5c83278 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
     "ethers": "^5.0.24",
     "fluidex.js": "git+https://github.com/fluidex/fluidex.js.git#b9224719013c224445fe8ec06f6a05e800b4469e",
     "hardhat": "^2.0.6",
+    "mocha": "^9.1.3",
     "prettier": "^2.2.1",
     "prettier-plugin-solidity": "^1.0.0-beta.2",
     "ts-node": "^10.2.1",
diff --git a/scripts/deploy.ts b/scripts/deploy.ts
index 75398ee..e50ca21 100644
--- a/scripts/deploy.ts
+++ b/scripts/deploy.ts
@@ -7,6 +7,7 @@ import { getTestAccount } from "./accounts";
 const loadAccounts = () => Array.from(botsIds).map((user_id) => Account.fromMnemonic(getTestAccount(user_id).mnemonic));
 const botsIds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19];
 const accounts = loadAccounts();
+const outputPath = process.env.DEPLOY_DIR || '/tmp/'
 
 interface Token {
   symbol: string,
@@ -17,7 +18,7 @@ async function main() {
   await run('compile');
 
   let tokens: Token[];
-  const raw = fs.readFileSync('/tmp/tokens.json', 'utf-8');
+  const raw = fs.readFileSync(`${outputPath}tokens.json`, 'utf-8');
   tokens = JSON.parse(raw);
 
   let deployed: Record<string, string | number> = {};
@@ -36,14 +37,15 @@ async function main() {
   console.log("FluiDex deployed to:", fluiDex.address);
   deployed['FluiDexDemo'] = fluiDex.address;
 
-  const registerUser = fluiDex.functions.registerUser;
+  // const registerUser = fluiDex.functions.registerUser;
   const accountsDump = new Array();
   for(const [idx, account] of accounts.entries()) {
-    await registerUser(account.ethAddr, account.bjjPubKey);
-    accountsDump.push({ id: idx, pubkey: account.bjjPubKey });
+    // await registerUser(account.ethAddr, account.bjjPubKey);
+    // for provided to the "offline" mode of ethlistener, id should start from 1
+    accountsDump.push({ id: idx + 1, pubkey: account.bjjPubKey });
     console.log(`register user ${account.bjjPubKey}`);
   }
-  fs.writeFileSync('/tmp/accounts.json', JSON.stringify(accountsDump));
+  fs.writeFileSync(`${outputPath}accounts.json`, JSON.stringify(accountsDump));
 
   const fluiDexDelegateFactory = await ethers.getContractFactory("FluiDexDelegate");
   const fluiDexDelegate = await fluiDexDelegateFactory.deploy(fluiDex.address);
@@ -53,7 +55,7 @@ async function main() {
   deployed['FluiDexDelegate'] = fluiDexDelegate.address;
   const tx = await ethers.provider.getTransaction(fluiDexDelegate.deployTransaction.hash);
   deployed['baseBlock'] = tx.blockNumber!!;
-  fs.writeFileSync('/tmp/deployed.json', JSON.stringify(deployed));
+  fs.writeFileSync(`${outputPath}deployed.json`, JSON.stringify(deployed));
 
   const DELEGATE_ROLE = await fluiDex.callStatic.DELEGATE_ROLE();
   await fluiDex.functions.grantRole(DELEGATE_ROLE, fluiDexDelegate.address);
@@ -61,12 +63,14 @@ async function main() {
 
   const addToken = fluiDexDelegate.functions.addToken;
   for (const {symbol, address} of Array.from(tokens)) {
-    await addToken(address);
-    console.log(`add ${symbol} token at`, address);
+    //the prec is consistend with pre-defined assets
+    let prec = 6;
+    await addToken(address, 6);
+    console.log(`add ${symbol} token (prec ${prec}) at`, address);
   }
 
   // skip verify on localhost
-  if (hre.network.name !== "geth") {
+  if (hre.network.name == "goerli") {
     try {
       await run('verify', {
         address: verifier.address,
diff --git a/scripts/deposit.ts b/scripts/deposit.ts
new file mode 100644
index 0000000..2816a8b
--- /dev/null
+++ b/scripts/deposit.ts
@@ -0,0 +1,87 @@
+import * as fs from 'fs';
+import { Account } from "fluidex.js";
+import { ethers } from "hardhat";
+//import * as hre from "hardhat";
+import { getTestAccount } from "./accounts";
+import { assert } from 'chai';
+
+const loadAccounts = () => Array.from(botsIds).map((user_id) => Account.fromMnemonic(getTestAccount(user_id).mnemonic));
+const botsIds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19];
+const accounts = loadAccounts();
+
+interface Token {
+  symbol: string,
+  address: string,
+}
+
+const Erc20Abi = [
+    // Read-Only Functions
+    "function balanceOf(address owner) view returns (uint256)",
+    "function allowance(address owner, address spender) view returns (uint256)",
+    "function decimals() view returns (uint8)",
+    "function symbol() view returns (string)",
+
+    // Authenticated Functions
+    "function transfer(address to, uint amount) returns (bool)",
+    "function approve(address spender, uint amount) returns (bool)",
+
+    // Events
+    "event Transfer(address indexed from, address indexed to, uint amount)"
+];
+
+let tokens: Token[];
+const raw = fs.readFileSync('tokens.json', 'utf-8');
+tokens = JSON.parse(raw);
+
+async function deploy_account(userId: number, account: Account) {
+
+  let acc_wallet = ethers.Wallet.fromMnemonic(getTestAccount(userId).mnemonic);
+  let acc_address = await acc_wallet.getAddress();
+  assert(account.ethAddr == acc_address, "same account");
+  let acc_l2 = account.bjjPubKey;
+
+  acc_wallet = acc_wallet.connect(ethers.provider);
+  let ethBalance = await acc_wallet.getBalance();
+  console.log("eth balance of ", acc_address, ethBalance.toString());
+  assert(account.ethAddr == acc_address, "same account");
+
+  const delegateAddress = process.env.CONTRACT_ADDR;
+  console.log("delegate contract at:", delegateAddress);
+  const contract = await ethers.getContractAt("FluiDexDelegate", delegateAddress as string, acc_wallet);  
+
+  for (const {symbol, address} of Array.from(tokens)) {
+    //suppose all symbol use prec as 6
+    let depositAmount = symbol == 'USDT' ? BigInt('500000000000') : BigInt('10000000');
+    console.log(`Find ${symbol} at`, address);
+  
+    let erc20 = new ethers.Contract(address, Erc20Abi, acc_wallet);
+    let ercBalance = await erc20.functions.balanceOf(acc_address);
+    console.log(`${acc_address}'s balance of ${symbol}`, ercBalance.toString());
+
+    let allowedBalanced = await erc20.functions.allowance(acc_address, delegateAddress);
+    if (allowedBalanced < depositAmount){
+        console.log(`no enough allowed balance: expected ${depositAmount} but only ${allowedBalanced}`),
+        await erc20.functions.approve(delegateAddress, depositAmount);
+    }
+    
+    await contract.functions.depositERC20(address, acc_l2, depositAmount);
+  }
+  await contract.functions.depositETH(acc_l2, {value: ethers.utils.parseEther("0.6")} /* overrides */);
+
+}
+
+
+async function main() {
+
+  for(const [idx, account] of accounts.entries()) {
+    await deploy_account(idx + 1, account);
+  }
+
+}
+
+main()
+  .then(() => process.exit(0))
+  .catch(error => {
+    console.error(error);
+    process.exit(1);
+  });
diff --git a/scripts/mine.ts b/scripts/mine.ts
new file mode 100644
index 0000000..b43d62e
--- /dev/null
+++ b/scripts/mine.ts
@@ -0,0 +1,15 @@
+import * as hre from "hardhat";
+
+async function main() {
+
+    await hre.network.provider.send("evm_mine", []);
+
+}
+
+
+main()
+  .then(() => process.exit(0))
+  .catch(error => {
+    console.error(error);
+    process.exit(1);
+  });
diff --git a/test/operations-test.js b/test/operations-test.js
new file mode 100644
index 0000000..bc86c1c
--- /dev/null
+++ b/test/operations-test.js
@@ -0,0 +1,129 @@
+const { expect } = require("chai");
+const { ethers } = require("hardhat");
+
+describe("TestBytes", function () {
+  it("Express input to reversed-bit inside the returning integer", async function () {
+    const TestC = await ethers.getContractFactory("TestLibs");
+    const testC = await TestC.deploy();
+
+    await testC.deployed();
+
+    expect(await testC.testBitsOp8(0, 138)).to.equal(0);
+    expect(await testC.testBitsOp8(1, 0)).to.equal(
+      BigInt(
+        "0x8000000000000000000000000000000000000000000000000000000000000000"
+      )
+    );
+    expect(await testC.testBitsOp8(1, 1)).to.equal(
+      BigInt(
+        "0x4000000000000000000000000000000000000000000000000000000000000000"
+      )
+    );
+    expect(await testC.testBitsOp8(42, 3)).to.equal(
+      BigInt(
+        "0x0A80000000000000000000000000000000000000000000000000000000000000"
+      )
+    );
+    expect(await testC.testBitsOp8(3, 255)).to.equal(1);
+    expect(await testC.testBitsOp32(1, 0)).to.equal(
+      BigInt(
+        "0x8000000000000000000000000000000000000000000000000000000000000000"
+      )
+    );
+    expect(await testC.testBitsOp32(42, 3)).to.equal(
+      BigInt(
+        "0x0A80000000000000000000000000000000000000000000000000000000000000"
+      )
+    );
+    expect(await testC.testBitsOp32(BigInt("0x80000001"), 225)).to.equal(
+      BigInt("0x40000000")
+    );
+    expect(await testC.testBitsOp32(995535, 236)).to.equal(995535);
+    expect(await testC.testBitsOp256(1, 0)).to.equal(
+      BigInt(
+        "0x8000000000000000000000000000000000000000000000000000000000000000"
+      )
+    );
+    expect(await testC.testBitsOp256(1, 128)).to.equal(
+      BigInt("0x80000000000000000000000000000000")
+    );
+    expect(
+      await testC.testBitsOp256(BigInt("0x80000000000000000000000000000000"), 0)
+    ).to.equal(BigInt("0x100000000000000000000000000000000"));
+    expect(
+      await testC.testBitsOp256(BigInt("0x80000000000000000000000000000000"), 1)
+    ).to.equal(BigInt("0x80000000000000000000000000000000"));
+    expect(
+      await testC.testBitsOp256(
+        BigInt("0x80000000000000000000000000000000"),
+        128
+      )
+    ).to.equal(1);
+    expect(
+      await testC.testBitsOp256(
+        BigInt("0x80000000000000000000000000000000"),
+        129
+      )
+    ).to.equal(0);
+  });
+});
+
+const keccak256To160 = (bytesLike) =>
+  "0x" + ethers.utils.keccak256(bytesLike).slice(26);
+
+describe("TestWriteRegistryOp", function () {
+  it("Encode registry op just like circuit did", async function () {
+    const TestC = await ethers.getContractFactory("TestLibs");
+    const testC = await TestC.deploy();
+
+    await testC.deployed();
+
+    //this cases only work for acc = 4, order = 4 and balance = 3
+    const expectedEncodeOp1 = keccak256To160(
+      "0x91ba18348a3d7f991abc0eaee50583b0697d1fd451a039d21fa36fe748324fddc4"
+    );
+    const expectedEncodeOp2 = keccak256To160(
+      "0x8997ad724ddb0f85f255bf087945654549ed416e131cf8719f21bb7b7ff54d7bf4"
+    );
+    const expectedEncodeOp3 = keccak256To160(
+      "0x949c82e7b8eefc3ce0ef812304c79cba948014945150117fda5f1c0c33873099b8"
+    );
+
+    expect(
+      await testC.testWriteRegistryPubdata(
+        1,
+        "0x5d182c51bcfe99583d7075a7a0c10d96bef82b8a059c4bf8c5f6e7124cf2bba3"
+      )
+    ).to.equal(expectedEncodeOp1);
+    expect(
+      await testC.testWriteRegistryPubdata(
+        2,
+        "0xe9b54eb2dbf0a14faafd109ea2a6a292b78276c8381f8ef984dddefeafb2deaf"
+      )
+    ).to.equal(expectedEncodeOp2);
+    expect(
+      await testC.testWriteRegistryPubdata(
+        5,
+        "0x3941e71d773f3c07f781c420e3395d290128298a0a88fe5bfa3830cce10c991d"
+      )
+    ).to.equal(expectedEncodeOp3);
+  });
+});
+
+describe("TestWriteDepositOp", function () {
+  it("Encode deposit op just like circuit did", async function () {
+    const TestC = await ethers.getContractFactory("TestLibs");
+    const testC = await TestC.deploy();
+
+    await testC.deployed();
+
+    //this cases only work for acc = 4, order = 4 and balance = 3
+    const expectedEncodeOp1 = keccak256To160(
+      "0x111000452958b80000000000000000000000000000000000000000000000000000"
+    );
+
+    expect(
+      await testC.testWriteDepositPubdata(1, 1, BigInt("500000000000"))
+    ).to.equal(expectedEncodeOp1);
+  });
+});
diff --git a/yarn.lock b/yarn.lock
index 77dcd30..7fd2802 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1169,6 +1169,11 @@
     "@types/bn.js" "*"
     "@types/underscore" "*"
 
+"@ungap/promise-all-settled@1.1.2":
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44"
+  integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==
+
 "@yarnpkg/lockfile@^1.1.0":
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31"
@@ -1286,7 +1291,7 @@ ansi-colors@3.2.3:
   resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813"
   integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==
 
-ansi-colors@^4.1.1:
+ansi-colors@4.1.1, ansi-colors@^4.1.1:
   version "4.1.1"
   resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
   integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
@@ -1335,7 +1340,7 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1:
   dependencies:
     color-convert "^1.9.0"
 
-ansi-styles@^4.0.0:
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
   version "4.3.0"
   resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
   integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
@@ -1367,6 +1372,11 @@ argparse@^1.0.7:
   dependencies:
     sprintf-js "~1.0.2"
 
+argparse@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
+  integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
+
 arr-diff@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
@@ -2390,6 +2400,11 @@ camelcase@^5.0.0:
   resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
   integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
 
+camelcase@^6.0.0:
+  version "6.3.0"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
+  integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
+
 caniuse-lite@^1.0.30000844:
   version "1.0.30001240"
   resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001240.tgz#ec15d125b590602c8731545c5351ff054ad2d52f"
@@ -2440,6 +2455,14 @@ chalk@^2.4.1, chalk@^2.4.2:
     escape-string-regexp "^1.0.5"
     supports-color "^5.3.0"
 
+chalk@^4.1.0:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+  integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
+  dependencies:
+    ansi-styles "^4.1.0"
+    supports-color "^7.1.0"
+
 check-error@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
@@ -2467,7 +2490,7 @@ chokidar@3.3.0:
   optionalDependencies:
     fsevents "~2.1.1"
 
-chokidar@^3.4.0:
+chokidar@3.5.2, chokidar@^3.4.0:
   version "3.5.2"
   resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75"
   integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==
@@ -2588,6 +2611,15 @@ cliui@^6.0.0:
     strip-ansi "^6.0.0"
     wrap-ansi "^6.2.0"
 
+cliui@^7.0.2:
+  version "7.0.4"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
+  integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
+  dependencies:
+    string-width "^4.2.0"
+    strip-ansi "^6.0.0"
+    wrap-ansi "^7.0.0"
+
 clone-response@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
@@ -2875,6 +2907,13 @@ debug@4, debug@^4.1.1:
   dependencies:
     ms "2.1.2"
 
+debug@4.3.2:
+  version "4.3.2"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
+  integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
+  dependencies:
+    ms "2.1.2"
+
 debug@^3.1.0:
   version "3.2.7"
   resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
@@ -2887,6 +2926,11 @@ decamelize@^1.1.1, decamelize@^1.2.0:
   resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
   integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
 
+decamelize@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837"
+  integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==
+
 decode-uri-component@^0.2.0:
   version "0.2.0"
   resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
@@ -3015,6 +3059,11 @@ diff@3.5.0:
   resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
   integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
 
+diff@5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b"
+  integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==
+
 diff@^4.0.1:
   version "4.0.2"
   resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
@@ -3222,6 +3271,11 @@ es6-symbol@^3.1.1, es6-symbol@~3.1.3:
     d "^1.0.1"
     ext "^1.1.2"
 
+escalade@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
+  integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
+
 escape-html@~1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
@@ -3232,7 +3286,7 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1
   resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
   integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
 
-escape-string-regexp@^4.0.0:
+escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
   integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
@@ -4009,6 +4063,14 @@ find-up@3.0.0, find-up@^3.0.0:
   dependencies:
     locate-path "^3.0.0"
 
+find-up@5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
+  integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
+  dependencies:
+    locate-path "^6.0.0"
+    path-exists "^4.0.0"
+
 find-up@^1.0.0:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
@@ -4054,6 +4116,11 @@ flat@^4.1.0:
   dependencies:
     is-buffer "~2.0.3"
 
+flat@^5.0.2:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
+  integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
+
 flow-stoplight@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/flow-stoplight/-/flow-stoplight-1.0.0.tgz#4a292c5bcff8b39fa6cc0cb1a853d86f27eeff7b"
@@ -4245,7 +4312,7 @@ get-caller-file@^1.0.1:
   resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
   integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
 
-get-caller-file@^2.0.1:
+get-caller-file@^2.0.1, get-caller-file@^2.0.5:
   version "2.0.5"
   resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
   integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
@@ -4314,7 +4381,7 @@ glob@7.1.3:
     once "^1.3.0"
     path-is-absolute "^1.0.0"
 
-glob@^7.1.2, glob@^7.1.3, glob@~7.1.6:
+glob@7.1.7, glob@^7.1.2, glob@^7.1.3, glob@~7.1.6:
   version "7.1.7"
   resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
   integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==
@@ -4469,6 +4536,11 @@ has-flag@^3.0.0:
   resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
   integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
 
+has-flag@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+  integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+
 has-symbol-support-x@^1.4.1:
   version "1.4.2"
   resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455"
@@ -4914,6 +4986,11 @@ is-plain-obj@^1.1.0:
   resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
   integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
 
+is-plain-obj@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
+  integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
+
 is-plain-object@^2.0.3, is-plain-object@^2.0.4:
   version "2.0.4"
   resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
@@ -4963,6 +5040,11 @@ is-typedarray@^1.0.0, is-typedarray@~1.0.0:
   resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
   integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
 
+is-unicode-supported@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
+  integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
+
 is-url@^1.2.4:
   version "1.2.4"
   resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52"
@@ -5063,6 +5145,13 @@ js-yaml@3.13.1:
     argparse "^1.0.7"
     esprima "^4.0.0"
 
+js-yaml@4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
+  integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
+  dependencies:
+    argparse "^2.0.1"
+
 jsbn@~0.1.0:
   version "0.1.1"
   resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
@@ -5454,6 +5543,13 @@ locate-path@^5.0.0:
   dependencies:
     p-locate "^4.1.0"
 
+locate-path@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
+  integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
+  dependencies:
+    p-locate "^5.0.0"
+
 lodash.assign@^4.0.3, lodash.assign@^4.0.6:
   version "4.2.0"
   resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
@@ -5476,6 +5572,14 @@ log-symbols@3.0.0:
   dependencies:
     chalk "^2.4.2"
 
+log-symbols@4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
+  integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==
+  dependencies:
+    chalk "^4.1.0"
+    is-unicode-supported "^0.1.0"
+
 looper@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/looper/-/looper-2.0.0.tgz#66cd0c774af3d4fedac53794f742db56da8f09ec"
@@ -5833,6 +5937,36 @@ mocha@^7.1.2:
     yargs-parser "13.1.2"
     yargs-unparser "1.6.0"
 
+mocha@^9.1.3:
+  version "9.1.3"
+  resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.1.3.tgz#8a623be6b323810493d8c8f6f7667440fa469fdb"
+  integrity sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw==
+  dependencies:
+    "@ungap/promise-all-settled" "1.1.2"
+    ansi-colors "4.1.1"
+    browser-stdout "1.3.1"
+    chokidar "3.5.2"
+    debug "4.3.2"
+    diff "5.0.0"
+    escape-string-regexp "4.0.0"
+    find-up "5.0.0"
+    glob "7.1.7"
+    growl "1.10.5"
+    he "1.2.0"
+    js-yaml "4.1.0"
+    log-symbols "4.1.0"
+    minimatch "3.0.4"
+    ms "2.1.3"
+    nanoid "3.1.25"
+    serialize-javascript "6.0.0"
+    strip-json-comments "3.1.1"
+    supports-color "8.1.1"
+    which "2.0.2"
+    workerpool "6.1.5"
+    yargs "16.2.0"
+    yargs-parser "20.2.4"
+    yargs-unparser "2.0.0"
+
 mock-fs@^4.1.0:
   version "4.14.0"
   resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18"
@@ -5853,7 +5987,7 @@ ms@2.1.2:
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
   integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
 
-ms@^2.1.1:
+ms@2.1.3, ms@^2.1.1:
   version "2.1.3"
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
   integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
@@ -5913,6 +6047,11 @@ nanoassert@^1.0.0:
   resolved "https://registry.yarnpkg.com/nanoassert/-/nanoassert-1.1.0.tgz#4f3152e09540fde28c76f44b19bbcd1d5a42478d"
   integrity sha1-TzFS4JVA/eKMdvRLGbvNHVpCR40=
 
+nanoid@3.1.25:
+  version "3.1.25"
+  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152"
+  integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==
+
 nanomatch@^1.2.9:
   version "1.2.13"
   resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
@@ -6189,6 +6328,13 @@ p-limit@^2.0.0, p-limit@^2.2.0:
   dependencies:
     p-try "^2.0.0"
 
+p-limit@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
+  integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
+  dependencies:
+    yocto-queue "^0.1.0"
+
 p-locate@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
@@ -6210,6 +6356,13 @@ p-locate@^4.1.0:
   dependencies:
     p-limit "^2.2.0"
 
+p-locate@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
+  integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
+  dependencies:
+    p-limit "^3.0.2"
+
 p-timeout@^1.1.1:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386"
@@ -7016,6 +7169,13 @@ send@0.17.1:
     range-parser "~1.2.1"
     statuses "~1.5.0"
 
+serialize-javascript@6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8"
+  integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==
+  dependencies:
+    randombytes "^2.1.0"
+
 serve-static@1.14.1:
   version "1.14.1"
   resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
@@ -7477,6 +7637,11 @@ strip-json-comments@2.0.1:
   resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
   integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
 
+strip-json-comments@3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
+  integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
+
 supports-color@6.0.0:
   version "6.0.0"
   resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a"
@@ -7484,6 +7649,13 @@ supports-color@6.0.0:
   dependencies:
     has-flag "^3.0.0"
 
+supports-color@8.1.1:
+  version "8.1.1"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
+  integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
+  dependencies:
+    has-flag "^4.0.0"
+
 supports-color@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
@@ -7496,6 +7668,13 @@ supports-color@^5.3.0:
   dependencies:
     has-flag "^3.0.0"
 
+supports-color@^7.1.0:
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+  integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
+  dependencies:
+    has-flag "^4.0.0"
+
 swarm-js@^0.1.40:
   version "0.1.40"
   resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.40.tgz#b1bc7b6dcc76061f6c772203e004c11997e06b99"
@@ -8391,6 +8570,13 @@ which@1.3.1, which@^1.2.9:
   dependencies:
     isexe "^2.0.0"
 
+which@2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+  integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
+  dependencies:
+    isexe "^2.0.0"
+
 wide-align@1.1.3:
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
@@ -8408,6 +8594,11 @@ worker-threads@^1.0.0:
   resolved "https://registry.yarnpkg.com/worker-threads/-/worker-threads-1.0.0.tgz#2b49ea7c9692ba737d9148f2c9b2be65e14e3470"
   integrity sha512-vK6Hhvph8oLxocEJIlc3YfGAZhm210uGzjZsXSu+JYLAQ/s/w4Tqgl60JrdH58hW8NSGP4m3bp8a92qPXgX05w==
 
+workerpool@6.1.5:
+  version "6.1.5"
+  resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.5.tgz#0f7cf076b6215fd7e1da903ff6f22ddd1886b581"
+  integrity sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==
+
 wrap-ansi@^2.0.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
@@ -8434,6 +8625,15 @@ wrap-ansi@^6.2.0:
     string-width "^4.1.0"
     strip-ansi "^6.0.0"
 
+wrap-ansi@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+  integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+  dependencies:
+    ansi-styles "^4.0.0"
+    string-width "^4.1.0"
+    strip-ansi "^6.0.0"
+
 wrappy@1:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
@@ -8524,6 +8724,11 @@ y18n@^4.0.0:
   resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"
   integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==
 
+y18n@^5.0.5:
+  version "5.0.8"
+  resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
+  integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
+
 yaeti@^0.0.6:
   version "0.0.6"
   resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577"
@@ -8547,6 +8752,11 @@ yargs-parser@13.1.2, yargs-parser@^13.1.2:
     camelcase "^5.0.0"
     decamelize "^1.2.0"
 
+yargs-parser@20.2.4:
+  version "20.2.4"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"
+  integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==
+
 yargs-parser@^18.1.2:
   version "18.1.3"
   resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0"
@@ -8563,6 +8773,11 @@ yargs-parser@^2.4.1:
     camelcase "^3.0.0"
     lodash.assign "^4.0.6"
 
+yargs-parser@^20.2.2:
+  version "20.2.9"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
+  integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
+
 yargs-unparser@1.6.0:
   version "1.6.0"
   resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f"
@@ -8572,6 +8787,16 @@ yargs-unparser@1.6.0:
     lodash "^4.17.15"
     yargs "^13.3.0"
 
+yargs-unparser@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb"
+  integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==
+  dependencies:
+    camelcase "^6.0.0"
+    decamelize "^4.0.0"
+    flat "^5.0.2"
+    is-plain-obj "^2.1.0"
+
 yargs@13.3.2, yargs@^13.3.0:
   version "13.3.2"
   resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd"
@@ -8588,6 +8813,19 @@ yargs@13.3.2, yargs@^13.3.0:
     y18n "^4.0.0"
     yargs-parser "^13.1.2"
 
+yargs@16.2.0:
+  version "16.2.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
+  integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
+  dependencies:
+    cliui "^7.0.2"
+    escalade "^3.1.1"
+    get-caller-file "^2.0.5"
+    require-directory "^2.1.1"
+    string-width "^4.2.0"
+    y18n "^5.0.5"
+    yargs-parser "^20.2.2"
+
 yargs@^15.3.1:
   version "15.4.1"
   resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
@@ -8629,3 +8867,8 @@ yn@3.1.1:
   version "3.1.1"
   resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
   integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
+
+yocto-queue@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
+  integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==