浏览代码

EVM/Node: Custom consistency level (#4406)

* eth: Custom consistency Level

* eth: Update TestCustomConsistencyLevel

* Node: Custom consistency level

* Add integration tests

* Move testing stuff

* Node: Code review rework

* Test: Simplify tests

* Doc: Update white paper

* Test: Use a different private key

* Node: Code review rework
bruce-riley 3 月之前
父节点
当前提交
6279a1474e
共有 31 个文件被更改,包括 10049 次插入113 次删除
  1. 6 0
      Tiltfile
  2. 1 1
      devnet/eth-devnet.yaml
  3. 1 1
      devnet/eth-devnet2.yaml
  4. 25 0
      devnet/tests.yaml
  5. 6 0
      ethereum/README.md
  6. 32 0
      ethereum/contracts/custom_consistency_level/CustomConsistencyLevel.sol
  7. 47 0
      ethereum/contracts/custom_consistency_level/TestCustomConsistencyLevel.sol
  8. 24 0
      ethereum/contracts/custom_consistency_level/interfaces/ICustomConsistencyLevel.sol
  9. 23 0
      ethereum/contracts/custom_consistency_level/libraries/ConfigMakers.sol
  10. 34 0
      ethereum/forge-scripts/DeployCustomConsistencyLevel.s.sol
  11. 37 0
      ethereum/forge-test/CustomConsistencyLevel.t.sol
  12. 34 0
      ethereum/forge-test/TestCustomConsistencyLevel.t.sol
  13. 30 0
      ethereum/sh/deployCustomConsistencyLevel.sh
  14. 6 0
      ethereum/sh/devnetInitialization.sh
  15. 4 0
      node/pkg/watchers/evm/chain_config.go
  16. 340 0
      node/pkg/watchers/evm/custom_consistency_level.go
  17. 399 0
      node/pkg/watchers/evm/custom_consistency_level_abi/CustomConsistencyLevel.go
  18. 94 0
      node/pkg/watchers/evm/custom_consistency_level_test.go
  19. 29 0
      node/pkg/watchers/evm/verify_chain_config/verify.go
  20. 161 111
      node/pkg/watchers/evm/watcher.go
  21. 16 0
      node/pkg/watchers/evm/watcher_test.go
  22. 15 0
      scripts/devnet-consts.json
  23. 2 0
      sdk/vaa/structs.go
  24. 307 0
      testing/contract-integrations/custom_consistency_level/__tests__/test_custom_consistency_level.ts
  25. 18 0
      testing/contract-integrations/custom_consistency_level/ci-config.js
  26. 5 0
      testing/contract-integrations/custom_consistency_level/jest.config.js
  27. 8264 0
      testing/contract-integrations/custom_consistency_level/package-lock.json
  28. 33 0
      testing/contract-integrations/custom_consistency_level/package.json
  29. 9 0
      testing/contract-integrations/custom_consistency_level/test_custom_consistency_level.sh
  30. 14 0
      testing/contract-integrations/custom_consistency_level/tsconfig.json
  31. 33 0
      whitepapers/0001_generic_message_passing.md

+ 6 - 0
Tiltfile

@@ -697,6 +697,12 @@ if ci_tests:
         trigger_mode = trigger_mode,
         trigger_mode = trigger_mode,
         resource_deps = ["eth-devnet"],
         resource_deps = ["eth-devnet"],
     )
     )
+    k8s_resource(
+        "custom-consistency-level-ci-tests",
+        labels = ["ci"],
+        trigger_mode = trigger_mode,
+        resource_deps = [], # uses devnet-consts.json, buttesting/contract-integrations/custom_consistency_level/test_custom_consistency_level.sh handles waiting for guardian, not having deps gets the build earlier
+    )
 
 
 if terra_classic:
 if terra_classic:
     docker_build(
     docker_build(

+ 1 - 1
devnet/eth-devnet.yaml

@@ -42,7 +42,7 @@ spec:
             - --mnemonic=myth like bonus scare over problem client lizard pioneer submit female collect
             - --mnemonic=myth like bonus scare over problem client lizard pioneer submit female collect
             - --block-time=1
             - --block-time=1
             - --host=0.0.0.0
             - --host=0.0.0.0
-            - --accounts=14
+            - --accounts=16
             - --chain-id=1337
             - --chain-id=1337
           ports:
           ports:
             - containerPort: 8545
             - containerPort: 8545

+ 1 - 1
devnet/eth-devnet2.yaml

@@ -43,7 +43,7 @@ spec:
             - --mnemonic=myth like bonus scare over problem client lizard pioneer submit female collect
             - --mnemonic=myth like bonus scare over problem client lizard pioneer submit female collect
             - --block-time=1
             - --block-time=1
             - --host=0.0.0.0
             - --host=0.0.0.0
-            - --accounts=14
+            - --accounts=16
             - --chain-id=1397
             - --chain-id=1397
           ports:
           ports:
             - containerPort: 8545
             - containerPort: 8545

+ 25 - 0
devnet/tests.yaml

@@ -123,4 +123,29 @@ spec:
             initialDelaySeconds: 5
             initialDelaySeconds: 5
             periodSeconds: 5
             periodSeconds: 5
 ---
 ---
+kind: Job
+apiVersion: batch/v1
+metadata:
+  name: custom-consistency-level-ci-tests
+spec:
+  backoffLimit: 0
+  template:
+    spec:
+      restartPolicy: Never
+      containers:
+        - name: custom-consistency-level-ci-tests
+          image: sdk-test-image
+          command:
+            - /bin/sh
+            - -c
+            - "bash /app/testing/contract-integrations/custom_consistency_level/test_custom_consistency_level.sh && touch /app/testing/success"
+          readinessProbe:
+            exec:
+              command:
+                - test
+                - -e
+                - "/app/testing/success"
+            initialDelaySeconds: 5
+            periodSeconds: 5
+---
 
 

+ 6 - 0
ethereum/README.md

@@ -51,6 +51,12 @@ ethereum$ MNEMONIC=<redacted> ./sh/deployCoreShutdown.sh
 ethereum$ MNEMONIC=<redacted> ./sh/deployTokenBridgeShutdown.sh
 ethereum$ MNEMONIC=<redacted> ./sh/deployTokenBridgeShutdown.sh
 ```
 ```
 
 
+#### Deploy the Custom Consistency Level contract
+
+```shell
+ethereum$ RPC_URL= MNEMONIC= EVM_CHAIN_ID= ./sh/deployCustomConsistencyLevel.sh
+```
+
 #### Generate Flattened Source
 #### Generate Flattened Source
 
 
 To generated the flattened source files to verify the contracts using the explorer UI
 To generated the flattened source files to verify the contracts using the explorer UI

+ 32 - 0
ethereum/contracts/custom_consistency_level/CustomConsistencyLevel.sol

@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: Apache 2
+pragma solidity ^0.8.0;
+
+import "./interfaces/ICustomConsistencyLevel.sol";
+
+string constant customConsistencyLevelVersion = "CustomConsistencyLevel-0.0.1";
+
+/// @title CustomConsistencyLevel
+/// @author Wormhole Project Contributors.
+/// @notice The CustomConsistencyLevel contract is an immutable contract that tracks custom consistency level configurations per integrator (emitter address).
+contract CustomConsistencyLevel is ICustomConsistencyLevel {
+    string public constant VERSION = customConsistencyLevelVersion;
+
+    mapping(address => bytes32) private _configurations;
+
+    // ==================== External Interface ===============================================
+
+    /// @inheritdoc ICustomConsistencyLevel
+    function configure(
+        bytes32 config
+    ) external override {
+        _configurations[msg.sender] = config;
+        emit ConfigSet(msg.sender, config);
+    }
+
+    /// @inheritdoc ICustomConsistencyLevel
+    function getConfiguration(
+        address emitterAddress
+    ) external view override returns (bytes32) {
+        return _configurations[emitterAddress];
+    }
+}

+ 47 - 0
ethereum/contracts/custom_consistency_level/TestCustomConsistencyLevel.sol

@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: Apache 2
+pragma solidity ^0.8.0;
+
+import "../interfaces/IWormhole.sol";
+import "./interfaces/ICustomConsistencyLevel.sol";
+import "./libraries/ConfigMakers.sol";
+
+string constant testCustomConsistencyLevelVersion = "TestCustomConsistencyLevel-0.0.1";
+
+/// @title TestCustomConsistencyLevel
+/// @author Wormhole Project Contributors.
+/// @notice The TestCustomConsistencyLevel contract can be used to test the custom consistency level functionality.
+contract TestCustomConsistencyLevel {
+    string public constant VERSION = testCustomConsistencyLevelVersion;
+
+    ICustomConsistencyLevel public immutable customConsistencyLevel;
+    IWormhole public immutable wormhole;
+    uint32 public nonce;
+
+    constructor(
+        address _wormhole,
+        address _customConsistencyLevel,
+        uint8 _consistencyLevel,
+        uint16 _blocks
+    ) {
+        wormhole = IWormhole(_wormhole);
+        customConsistencyLevel = ICustomConsistencyLevel(_customConsistencyLevel);
+        ICustomConsistencyLevel(_customConsistencyLevel).configure(
+            ConfigMakers.makeAdditionalBlocksConfig(_consistencyLevel, _blocks)
+        );
+    }
+
+    // ==================== External Interface ===============================================
+
+    function configure(uint8 _consistencyLevel, uint16 _blocks) external {
+        customConsistencyLevel.configure(
+            ConfigMakers.makeAdditionalBlocksConfig(_consistencyLevel, _blocks)
+        );
+    }
+
+    function publishMessage(
+        string memory str
+    ) external payable returns (uint64 sequence) {
+        nonce++;
+        sequence = wormhole.publishMessage(nonce, bytes(str), 203);
+    }
+}

+ 24 - 0
ethereum/contracts/custom_consistency_level/interfaces/ICustomConsistencyLevel.sol

@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: Apache 2
+pragma solidity ^0.8.0;
+
+interface ICustomConsistencyLevel {
+    /// @notice The configuration for an emitter has been set.
+    /// @dev Topic0
+    ///      0xa37f0112e03d41de27266c1680238ff1548c0441ad1e73c82917c000eefdd5ea.
+    /// @param emitterAddress The emitter address for which the config has been set.
+    /// @param config The config data that was set.
+    event ConfigSet(address emitterAddress, bytes32 config);
+
+    /// @notice Sets / updates the configuration for a given emitter address (msg.sender).
+    /// @param config The config used to determine the custom consistency level handling for an emitter.
+    function configure(
+        bytes32 config
+    ) external;
+
+    /// @notice Returns the configuration for a given emitter address.
+    /// @param emitterAddress The emitter address for which the config has been set.
+    /// @return The configuration.
+    function getConfiguration(
+        address emitterAddress
+    ) external returns (bytes32);
+}

+ 23 - 0
ethereum/contracts/custom_consistency_level/libraries/ConfigMakers.sol

@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+import "../../libraries/external/BytesLib.sol";
+
+library ConfigMakers {
+    using BytesLib for bytes;
+
+    uint8 public constant TYPE_ADDITIONAL_BLOCKS = 1;
+
+    /// @notice Encodes an additional blocks custom consistency level configuration.
+    /// @param consistencyLevel The consistency level to wait for.
+    /// @param blocksToWait The number of additional blocks to wait after the consistency level is reached.
+    /// @return bytes The encoded config.
+    function makeAdditionalBlocksConfig(
+        uint8 consistencyLevel,
+        uint16 blocksToWait
+    ) internal pure returns (bytes32) {
+        bytes28 padding;
+        return abi.encodePacked(TYPE_ADDITIONAL_BLOCKS, consistencyLevel, blocksToWait, padding)
+            .toBytes32(0);
+    }
+}

+ 34 - 0
ethereum/forge-scripts/DeployCustomConsistencyLevel.s.sol

@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+import {
+    CustomConsistencyLevel,
+    customConsistencyLevelVersion
+} from "../contracts/custom_consistency_level/CustomConsistencyLevel.sol";
+import "forge-std/Script.sol";
+
+// DeployCustomConsistencyLevel is a forge script to deploy the CustomConsistencyLevel contract. Use ./sh/deployCustomConsistencyLevel.sh to invoke this.
+// e.g. anvil
+// EVM_CHAIN_ID=31337 MNEMONIC=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 ./sh/deployCustomConsistencyLevel.sh
+// e.g. anvil --fork-url https://ethereum-rpc.publicnode.com
+// EVM_CHAIN_ID=1 MNEMONIC=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 ./sh/deployCustomConsistencyLevel.sh
+contract DeployCustomConsistencyLevel is Script {
+    function test() public {} // Exclude this from coverage report.
+
+    function dryRun() public {
+        _deploy();
+    }
+
+    function run() public returns (address deployedAddress) {
+        vm.startBroadcast();
+        (deployedAddress) = _deploy();
+        vm.stopBroadcast();
+    }
+
+    function _deploy() internal returns (address deployedAddress) {
+        bytes32 salt = keccak256(abi.encodePacked(customConsistencyLevelVersion));
+        CustomConsistencyLevel customConsistencyLevel = new CustomConsistencyLevel{salt: salt}();
+
+        return (address(customConsistencyLevel));
+    }
+}

+ 37 - 0
ethereum/forge-test/CustomConsistencyLevel.t.sol

@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+import {Test, console} from "forge-std/Test.sol";
+import {CustomConsistencyLevel} from
+    "../contracts/custom_consistency_level/CustomConsistencyLevel.sol";
+import {ConfigMakers} from "../contracts/custom_consistency_level/libraries/ConfigMakers.sol";
+
+contract CustomConsistencyLevelTest is Test {
+    CustomConsistencyLevel public customConsistencyLevel;
+
+    address public userA = address(0x123);
+    address public userB = address(0x456);
+    address public guardian = address(0x789);
+
+    function setUp() public {
+        customConsistencyLevel = new CustomConsistencyLevel();
+    }
+
+    function test_makeAdditionalBlocksConfig() public {
+        bytes32 expected = 0x01c9002a00000000000000000000000000000000000000000000000000000000;
+        bytes32 result = ConfigMakers.makeAdditionalBlocksConfig(201, 42);
+        assertEq(expected, result);
+    }
+
+    function test_configure() public {
+        vm.startPrank(userA);
+        customConsistencyLevel.configure(ConfigMakers.makeAdditionalBlocksConfig(201, 42));
+
+        vm.startPrank(guardian);
+        assertEq(
+            0x01c9002a00000000000000000000000000000000000000000000000000000000,
+            customConsistencyLevel.getConfiguration(userA)
+        );
+        assertEq(bytes32(0), customConsistencyLevel.getConfiguration(userB));
+    }
+}

+ 34 - 0
ethereum/forge-test/TestCustomConsistencyLevel.t.sol

@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+import {Test, console} from "forge-std/Test.sol";
+import {TestCustomConsistencyLevel} from
+    "../contracts/custom_consistency_level/TestCustomConsistencyLevel.sol";
+import {CustomConsistencyLevel} from
+    "../contracts/custom_consistency_level/CustomConsistencyLevel.sol";
+import {ConfigMakers} from "../contracts/custom_consistency_level/libraries/ConfigMakers.sol";
+
+contract TestCustomConsistencyLevelTest is Test {
+    CustomConsistencyLevel public customConsistencyLevel;
+    TestCustomConsistencyLevel public testCustomConsistencyLevel;
+
+    address public userA = address(0x123);
+    address public userB = address(0x456);
+    address public guardian = address(0x789);
+    address public wormhole = address(0x123456);
+
+    function setUp() public {
+        customConsistencyLevel = new CustomConsistencyLevel();
+        testCustomConsistencyLevel =
+            new TestCustomConsistencyLevel(wormhole, address(customConsistencyLevel), 201, 5);
+    }
+
+    function test_configure() public {
+        vm.startPrank(guardian);
+        assertEq(
+            0x01c9000500000000000000000000000000000000000000000000000000000000,
+            customConsistencyLevel.getConfiguration(address(testCustomConsistencyLevel))
+        );
+        assertEq(bytes32(0), customConsistencyLevel.getConfiguration(userB));
+    }
+}

+ 30 - 0
ethereum/sh/deployCustomConsistencyLevel.sh

@@ -0,0 +1,30 @@
+#!/bin/bash
+
+#
+# This script deploys the CustomConsistencyLevel contract.
+# Usage: RPC_URL= MNEMONIC= EVM_CHAIN_ID= ./sh/deployCustomConsistencyLevel.sh
+#  tilt: ./sh/deployCustomConsistencyLevel.sh
+#  anvil: EVM_CHAIN_ID=31337 MNEMONIC=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 ./sh/deployCustomConsistencyLevel.sh
+
+if [ "${RPC_URL}X" == "X" ]; then
+  RPC_URL=http://localhost:8545
+fi
+
+if [ "${MNEMONIC}X" == "X" ]; then
+  MNEMONIC=0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d
+fi
+
+if [ "${EVM_CHAIN_ID}X" == "X" ]; then
+  EVM_CHAIN_ID=1337
+fi
+
+forge script ./forge-scripts/DeployCustomConsistencyLevel.s.sol:DeployCustomConsistencyLevel \
+	--sig "run()" \
+	--rpc-url "$RPC_URL" \
+	--private-key "$MNEMONIC" \
+	--broadcast ${FORGE_ARGS}
+
+returnInfo=$(cat ./broadcast/DeployCustomConsistencyLevel.s.sol/$EVM_CHAIN_ID/run-latest.json)
+
+DEPLOYED_ADDRESS=$(jq -r '.returns.deployedAddress.value' <<< "$returnInfo")
+echo "Deployed custom consistency level to address: $DEPLOYED_ADDRESS"

+ 6 - 0
ethereum/sh/devnetInitialization.sh

@@ -82,3 +82,9 @@ echo "Registering chains on nft bridge"
 echo "NFT_BRIDGE_REGISTRATION_VAAS: $NFT_BRIDGE_REGISTRATION_VAAS"
 echo "NFT_BRIDGE_REGISTRATION_VAAS: $NFT_BRIDGE_REGISTRATION_VAAS"
 source "./sh/registerChainsNFTBridge.sh"
 source "./sh/registerChainsNFTBridge.sh"
 echo "Done registering chains on nft bridge"
 echo "Done registering chains on nft bridge"
+
+echo "Deploying Custom Consistency Level"
+source ./sh/deployCustomConsistencyLevel.sh
+returnInfo=$(cat ./broadcast/DeployCustomConsistencyLevel.s.sol/$INIT_EVM_CHAIN_ID/run-latest.json)
+CUSTOM_CONSISTENCY_LEVEL=$(jq -r '.returns.deployedAddress.value' <<< "$returnInfo")
+echo "CUSTOM_CONSISTENCY_LEVEL: $CUSTOM_CONSISTENCY_LEVEL"

+ 4 - 0
node/pkg/watchers/evm/chain_config.go

@@ -45,6 +45,10 @@ type (
 		// ContractAddr specifies the Wormhole core contract address for this chain (starting with 0x).
 		// ContractAddr specifies the Wormhole core contract address for this chain (starting with 0x).
 		// SECURITY: This is for documentation and validation only. Allowing it as a default would provide a single point attack vector.
 		// SECURITY: This is for documentation and validation only. Allowing it as a default would provide a single point attack vector.
 		ContractAddr string
 		ContractAddr string
+
+		// CCLContractAddr specifies the address of the custom consistency level contract for this chain (starting with 0x).
+		// SECURITY: This is for documentation and validation only. Allowing it as a default would provide a single point attack vector.
+		CCLContractAddr string
 	}
 	}
 
 
 	// EnvMap defines the config data for a given environment (mainet or testnet).
 	// EnvMap defines the config data for a given environment (mainet or testnet).

+ 340 - 0
node/pkg/watchers/evm/custom_consistency_level.go

@@ -0,0 +1,340 @@
+// The Custom Consistency Level feature allows integrators to specify custom finality handling for their observations.
+// It involves reading the custom configuration from an on chain contract, using the emitter address as a key. If an
+// entry is found, then the specified special handling is performed. Currently, the only supported custom handling is
+// to wait a certain number of blocks after the block containing the message reaches the specified finality
+// (finalized, safe or immediate).
+//
+// To generate the ABI bindings for the CustomConsistencyLevel contract do the following:
+//
+// - Install abigen: go install github.com/ethereum/go-ethereum/cmd/abigen@latest
+// - Copy the ABI definitions from ethereum/build-forge/CustomConsistencyLevel.sol/CustomConsistencyLevel.json (the stuff after `"abi":`) into /tmp/CustomConsistencyLevel.abi.
+// - cd node/pkg/watcher/evm
+// - mkdir custom_consistency_level_abi
+// - abigen --abi /tmp/CustomConsistencyLevel.abi --pkg ccl --out custom_consistency_level_abi/CustomConsistencyLevel.go
+
+package evm
+
+import (
+	"bytes"
+	"context"
+	"encoding/binary"
+	"fmt"
+	"time"
+
+	"github.com/certusone/wormhole/node/pkg/common"
+	"github.com/wormhole-foundation/wormhole/sdk/vaa"
+	"go.uber.org/zap"
+
+	cclAbi "github.com/certusone/wormhole/node/pkg/watchers/evm/custom_consistency_level_abi"
+
+	ethBind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+	ethCommon "github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/ethclient"
+)
+
+// CCLRequestType used to represent the custom handling type.
+type CCLRequestType uint8
+
+const (
+	NothingSpecialType CCLRequestType = iota
+	AdditionalBlocksType
+)
+
+type (
+	// CCLRequest is the standard interface for custom request types.
+	CCLRequest interface {
+		Type() CCLRequestType
+	}
+
+	// NothingSpecial means there is no custom handling enabled for this emitter.
+	NothingSpecial struct {
+	}
+
+	// AdditionalBlocks means this emitter is configured for the additional blocks custom handling.
+	AdditionalBlocks struct {
+		consistencyLevel uint8
+		additionalBlocks uint16
+	}
+)
+
+func (nr *NothingSpecial) Type() CCLRequestType {
+	return NothingSpecialType
+}
+
+func (abr *AdditionalBlocks) Type() CCLRequestType {
+	return AdditionalBlocksType
+}
+
+type CCLMap map[vaa.ChainID]string
+
+var (
+	// cclMainnetMap specifies the custom consistency level contracts for each mainnet chain.
+	cclMainnetMap = CCLMap{}
+
+	// cclTestnetMap specifies the custom consistency level contracts for each testnet chain.
+	cclTestnetMap = CCLMap{}
+
+	// cclDevnetMap specifies the custom consistency level contracts for each devnet chain.
+	cclDevnetMap = CCLMap{
+		vaa.ChainIDEthereum: "0x6A4B4A882F5F0a447078b4Fd0b4B571A82371ec2",
+	}
+
+	// cclEmptyData is used to check for an empty response from the contract, meaning the emitter address is not configured for special handling.
+	cclEmptyData [32]byte
+)
+
+type (
+	// CCLCacheEntry is the data stored in the cache for a given emitter
+	CCLCacheEntry struct {
+		data     [32]byte
+		readTime time.Time
+	}
+
+	// CCLCache is the layout of the cache of config data for emitters
+	CCLCache map[ethCommon.Address]CCLCacheEntry
+)
+
+// CCLCacheTimeoutInterval is the lifetime of a cache entry. After that time, we delete the entry and re-read the config data.
+// TODO: This time is arbitrary. Does it sound okay?
+const CCLCacheTimeoutInterval = time.Minute * 5
+
+// cclEnable enables the custom consistency level feature, if it is configured for this environment / chain.
+func (w *Watcher) cclEnable(ctx context.Context) error {
+	addrStr, err := cclGetContractAddr(w.env, w.chainID)
+	if err != nil {
+		return err
+	}
+
+	if addrStr == "" {
+		// This is not an error. It just means the feature is not enabled for this chain.
+		w.cclEnabled = false
+		return nil
+	}
+
+	w.cclAddr = ethCommon.HexToAddress(addrStr)
+	w.cclLogger.Info("custom consistency level is enabled", zap.Stringer("contractAddr", w.cclAddr))
+
+	// Do a test read on the contract to confirm it exists. This should not return anything, but it shouldn't fail!
+	// We use the free function here so we don't add the zero emitter to the cache.
+	_, err = CCLReadContract(ctx, w.ethConn.Client(), w.cclAddr, ethCommon.Address{})
+	if err != nil {
+		w.cclLogger.Error("failed to do test read on contract, disabling custom consistency level handling", zap.Stringer("contractAddr", w.cclAddr), zap.Error(err))
+		return nil
+	}
+
+	w.cclEnabled = true
+	w.cclCacheLock.Lock()
+	w.cclCache = CCLCache{}
+	w.cclCacheLock.Unlock()
+	return nil
+}
+
+// cclHandleMessage is called for new observations that have the consistency level set to custom handling.
+// It reads the configuration for the emitter and updates the `pendingMessage` object for custom handling.
+func (w *Watcher) cclHandleMessage(parentCtx context.Context, pe *pendingMessage, emitterAddr ethCommon.Address) {
+	if !w.cclEnabled {
+		w.cclLogger.Error("received an observation with custom handling but the feature is not enabled, treating as finalized", zap.String("msgId", pe.message.MessageIDString()))
+		pe.message.ConsistencyLevel = vaa.ConsistencyLevelFinalized
+		return
+	}
+
+	if pe.message.ConsistencyLevel != vaa.ConsistencyLevelCustom {
+		w.cclLogger.Error("cclHandleMessage called with an invalid consistency level, ignoring it!",
+			zap.String("msgId", pe.message.MessageIDString()),
+			zap.Uint8("consistencyLevel", pe.message.ConsistencyLevel),
+		)
+		return
+	}
+
+	r, err := w.cclReadAndParseConfig(parentCtx, emitterAddr)
+	if err != nil {
+		w.cclLogger.Error("failed to look up config for custom handling, treating as finalized", zap.String("msgId", pe.message.MessageIDString()), zap.Error(err))
+		pe.message.ConsistencyLevel = vaa.ConsistencyLevelFinalized
+		return
+	}
+
+	switch req := r.(type) {
+	case *NothingSpecial:
+		w.cclLogger.Info("received an observation with the nothing special specifier, treating as finalized", zap.String("msgId", pe.message.MessageIDString()))
+		pe.message.ConsistencyLevel = vaa.ConsistencyLevelFinalized
+	case *AdditionalBlocks:
+		if req.consistencyLevel != vaa.ConsistencyLevelFinalized && req.consistencyLevel != vaa.ConsistencyLevelSafe && req.consistencyLevel != vaa.ConsistencyLevelPublishImmediately {
+			w.cclLogger.Error("received an observation with an additional blocks specifier but the configured consistency level is invalid, treating as finalized",
+				zap.String("msgId", pe.message.MessageIDString()),
+				zap.Uint8("consistencyLevel", req.consistencyLevel),
+				zap.Uint16("additionalBlocks", req.additionalBlocks),
+			)
+			pe.message.ConsistencyLevel = vaa.ConsistencyLevelFinalized
+			return
+		}
+
+		w.cclLogger.Info("received an observation with an additional blocks specifier",
+			zap.String("msgId", pe.message.MessageIDString()),
+			zap.Uint8("consistencyLevel", req.consistencyLevel),
+			zap.Uint16("additionalBlocks", req.additionalBlocks),
+		)
+		pe.message.ConsistencyLevel = req.consistencyLevel
+		pe.additionalBlocks = uint64(req.additionalBlocks)
+	default:
+		w.cclLogger.Error("invalid custom handling type, treating as finalized", zap.Stringer("emitterAddress", emitterAddr), zap.Uint8("reqType", uint8(req.Type())), zap.Error(err))
+		pe.message.ConsistencyLevel = vaa.ConsistencyLevelFinalized
+	}
+}
+
+// cclReadAndParseConfig reads the configuration for a given emitter and parses it into a request type.
+func (w *Watcher) cclReadAndParseConfig(ctx context.Context, emitterAddr ethCommon.Address) (CCLRequest, error) {
+	data, err := w.cclReadContract(ctx, emitterAddr)
+	if err != nil {
+		return &NothingSpecial{}, err
+	}
+
+	if data == cclEmptyData {
+		return &NothingSpecial{}, nil
+	}
+
+	request, err := cclParseConfig(data)
+	if err != nil {
+		return &NothingSpecial{}, fmt.Errorf("failed to parse contract data: %w", err)
+	}
+
+	return request, err
+}
+
+// cclReadContract calls into the contract to read the configuration for a given emitter.
+func (w *Watcher) cclReadContract(ctx context.Context, emitterAddr ethCommon.Address) ([32]byte, error) {
+	// Before we read the config from the contract, see if we already have it in the cache.
+	data, found := w.cclCacheLookUp(emitterAddr)
+	if found {
+		return data, nil
+	}
+
+	data, err := CCLReadContract(ctx, w.ethConn.Client(), w.cclAddr, emitterAddr)
+	if err != nil {
+		return cclEmptyData, err
+	}
+
+	w.cclCacheUpdate(emitterAddr, data)
+	w.cclLogger.Debug("read contract", zap.Stringer("emitterAddr", emitterAddr))
+	return data, nil
+}
+
+// CCLReadContract calls into the contract to read the configuration for a given emitter.
+// This is a free function so it can be called by the config verification tool.
+func CCLReadContract(ctx context.Context, ethClient *ethclient.Client, cclAddr ethCommon.Address, emitterAddr ethCommon.Address) ([32]byte, error) {
+	timeout, cancel := context.WithTimeout(ctx, 15*time.Second)
+	defer cancel()
+
+	caller, err := cclAbi.NewCclCaller(cclAddr, ethClient)
+	if err != nil {
+		return cclEmptyData, fmt.Errorf("failed to create abi caller: %w", err)
+	}
+
+	data, err := caller.GetConfiguration(&ethBind.CallOpts{Context: timeout}, emitterAddr)
+	if err != nil {
+		return cclEmptyData, err
+	}
+
+	return data, nil
+}
+
+// cclParseConfig parses the configuration data returned by the contract into a request.
+func cclParseConfig(data [32]byte) (CCLRequest, error) {
+	reader := bytes.NewReader(data[:])
+
+	t := CCLRequestType(0)
+	if err := binary.Read(reader, binary.BigEndian, &t); err != nil {
+		return nil, fmt.Errorf("failed to read data type: %w", err)
+	}
+
+	if t == 0x01 {
+		return cclParseAdditionalBlocksConfig(reader)
+	}
+
+	if t == 0x00 {
+		return &NothingSpecial{}, nil
+	}
+
+	return nil, fmt.Errorf("unexpected data type: %d", t)
+}
+
+// cclParseAdditionalBlocksConfig parses the configuration for an additional blocks request.
+// Note that the configuration type (the first byte) has already been read and verified.
+func cclParseAdditionalBlocksConfig(reader *bytes.Reader) (CCLRequest, error) {
+	consistencyLevel := uint8(0)
+	if err := binary.Read(reader, binary.BigEndian, &consistencyLevel); err != nil {
+		return nil, fmt.Errorf("failed to read consistency level: %w", err)
+	}
+
+	blocks := uint16(0)
+	if err := binary.Read(reader, binary.BigEndian, &blocks); err != nil {
+		return nil, fmt.Errorf("failed to read num blocks: %w", err)
+	}
+
+	// The config data is 32 bytes and the AdditionalBlocks request uses the first four, so we should have 28 left.
+	if reader.Len() != 28 {
+		return nil, fmt.Errorf("unexpected remaining unread bytes in buffer, should be 28, are %d", reader.Len())
+	}
+
+	return &AdditionalBlocks{consistencyLevel, blocks}, nil
+}
+
+// cclGetContractAddr returns the contract address for the given environment / chain.
+// If the chain is not configured to use custom consistency level handling, the empty string is returned.
+func cclGetContractAddr(env common.Environment, chainID vaa.ChainID) (string, error) {
+	m, err := cclGetContractAddrMap(env)
+	if err != nil {
+		return "", err
+	}
+
+	addrStr, exists := m[chainID]
+	if !exists {
+		// The entry not existing is not an error. It just means we don't support custom consistency levels on this chain.
+		return "", nil
+	}
+
+	return addrStr, nil
+}
+
+// cclGetContractAddrMap returns the configuration map for the given environment.
+func cclGetContractAddrMap(env common.Environment) (CCLMap, error) {
+	if env == common.MainNet {
+		return cclMainnetMap, nil
+	}
+
+	if env == common.TestNet {
+		return cclTestnetMap, nil
+	}
+
+	if env == common.UnsafeDevNet {
+		return cclDevnetMap, nil
+	}
+
+	return CCLMap{}, ErrInvalidEnv
+}
+
+// cclCacheLookUp looks to see if the configuration for an emitter is currently in our cache.
+// If the entry does not exists, we return "not found". Otherwise, if it is not expired, we return it.
+// If it is expired, we delete it from the cache and return "not found".
+func (w *Watcher) cclCacheLookUp(emitterAddr ethCommon.Address) ([32]byte, bool) {
+	w.cclCacheLock.Lock()
+	defer w.cclCacheLock.Unlock()
+
+	if entry, exists := w.cclCache[emitterAddr]; exists {
+		if time.Since(entry.readTime) < CCLCacheTimeoutInterval {
+			return entry.data, true
+		}
+
+		w.cclLogger.Debug("cache entry has expired", zap.Stringer("emitterAddr", emitterAddr))
+		delete(w.cclCache, emitterAddr)
+	}
+
+	return cclEmptyData, false
+}
+
+// cclCacheUpdate updates the entry in the cache for a given emitter, including the read time.
+func (w *Watcher) cclCacheUpdate(emitterAddr ethCommon.Address, data [32]byte) {
+	w.cclCacheLock.Lock()
+	w.cclCache[emitterAddr] = CCLCacheEntry{data, time.Now()}
+	w.cclCacheLock.Unlock()
+	w.cclLogger.Debug("cache entry added", zap.Stringer("emitterAddr", emitterAddr))
+}

+ 399 - 0
node/pkg/watchers/evm/custom_consistency_level_abi/CustomConsistencyLevel.go

@@ -0,0 +1,399 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package ccl
+
+import (
+	"errors"
+	"math/big"
+	"strings"
+
+	ethereum "github.com/ethereum/go-ethereum"
+	"github.com/ethereum/go-ethereum/accounts/abi"
+	"github.com/ethereum/go-ethereum/accounts/abi/bind"
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/event"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var (
+	_ = errors.New
+	_ = big.NewInt
+	_ = strings.NewReader
+	_ = ethereum.NotFound
+	_ = bind.Bind
+	_ = common.Big1
+	_ = types.BloomLookup
+	_ = event.NewSubscription
+	_ = abi.ConvertType
+)
+
+// CclMetaData contains all meta data concerning the Ccl contract.
+var CclMetaData = &bind.MetaData{
+	ABI: "[{\"type\":\"function\",\"name\":\"VERSION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"configure\",\"inputs\":[{\"name\":\"config\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getConfiguration\",\"inputs\":[{\"name\":\"emitterAddress\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"ConfigSet\",\"inputs\":[{\"name\":\"emitterAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"config\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"}],\"anonymous\":false}]",
+}
+
+// CclABI is the input ABI used to generate the binding from.
+// Deprecated: Use CclMetaData.ABI instead.
+var CclABI = CclMetaData.ABI
+
+// Ccl is an auto generated Go binding around an Ethereum contract.
+type Ccl struct {
+	CclCaller     // Read-only binding to the contract
+	CclTransactor // Write-only binding to the contract
+	CclFilterer   // Log filterer for contract events
+}
+
+// CclCaller is an auto generated read-only Go binding around an Ethereum contract.
+type CclCaller struct {
+	contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// CclTransactor is an auto generated write-only Go binding around an Ethereum contract.
+type CclTransactor struct {
+	contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// CclFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
+type CclFilterer struct {
+	contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// CclSession is an auto generated Go binding around an Ethereum contract,
+// with pre-set call and transact options.
+type CclSession struct {
+	Contract     *Ccl              // Generic contract binding to set the session for
+	CallOpts     bind.CallOpts     // Call options to use throughout this session
+	TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// CclCallerSession is an auto generated read-only Go binding around an Ethereum contract,
+// with pre-set call options.
+type CclCallerSession struct {
+	Contract *CclCaller    // Generic contract caller binding to set the session for
+	CallOpts bind.CallOpts // Call options to use throughout this session
+}
+
+// CclTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
+// with pre-set transact options.
+type CclTransactorSession struct {
+	Contract     *CclTransactor    // Generic contract transactor binding to set the session for
+	TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// CclRaw is an auto generated low-level Go binding around an Ethereum contract.
+type CclRaw struct {
+	Contract *Ccl // Generic contract binding to access the raw methods on
+}
+
+// CclCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
+type CclCallerRaw struct {
+	Contract *CclCaller // Generic read-only contract binding to access the raw methods on
+}
+
+// CclTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
+type CclTransactorRaw struct {
+	Contract *CclTransactor // Generic write-only contract binding to access the raw methods on
+}
+
+// NewCcl creates a new instance of Ccl, bound to a specific deployed contract.
+func NewCcl(address common.Address, backend bind.ContractBackend) (*Ccl, error) {
+	contract, err := bindCcl(address, backend, backend, backend)
+	if err != nil {
+		return nil, err
+	}
+	return &Ccl{CclCaller: CclCaller{contract: contract}, CclTransactor: CclTransactor{contract: contract}, CclFilterer: CclFilterer{contract: contract}}, nil
+}
+
+// NewCclCaller creates a new read-only instance of Ccl, bound to a specific deployed contract.
+func NewCclCaller(address common.Address, caller bind.ContractCaller) (*CclCaller, error) {
+	contract, err := bindCcl(address, caller, nil, nil)
+	if err != nil {
+		return nil, err
+	}
+	return &CclCaller{contract: contract}, nil
+}
+
+// NewCclTransactor creates a new write-only instance of Ccl, bound to a specific deployed contract.
+func NewCclTransactor(address common.Address, transactor bind.ContractTransactor) (*CclTransactor, error) {
+	contract, err := bindCcl(address, nil, transactor, nil)
+	if err != nil {
+		return nil, err
+	}
+	return &CclTransactor{contract: contract}, nil
+}
+
+// NewCclFilterer creates a new log filterer instance of Ccl, bound to a specific deployed contract.
+func NewCclFilterer(address common.Address, filterer bind.ContractFilterer) (*CclFilterer, error) {
+	contract, err := bindCcl(address, nil, nil, filterer)
+	if err != nil {
+		return nil, err
+	}
+	return &CclFilterer{contract: contract}, nil
+}
+
+// bindCcl binds a generic wrapper to an already deployed contract.
+func bindCcl(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+	parsed, err := CclMetaData.GetAbi()
+	if err != nil {
+		return nil, err
+	}
+	return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_Ccl *CclRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+	return _Ccl.Contract.CclCaller.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_Ccl *CclRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+	return _Ccl.Contract.CclTransactor.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_Ccl *CclRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+	return _Ccl.Contract.CclTransactor.contract.Transact(opts, method, params...)
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_Ccl *CclCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+	return _Ccl.Contract.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_Ccl *CclTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+	return _Ccl.Contract.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_Ccl *CclTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+	return _Ccl.Contract.contract.Transact(opts, method, params...)
+}
+
+// VERSION is a free data retrieval call binding the contract method 0xffa1ad74.
+//
+// Solidity: function VERSION() view returns(string)
+func (_Ccl *CclCaller) VERSION(opts *bind.CallOpts) (string, error) {
+	var out []interface{}
+	err := _Ccl.contract.Call(opts, &out, "VERSION")
+
+	if err != nil {
+		return *new(string), err
+	}
+
+	out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+	return out0, err
+
+}
+
+// VERSION is a free data retrieval call binding the contract method 0xffa1ad74.
+//
+// Solidity: function VERSION() view returns(string)
+func (_Ccl *CclSession) VERSION() (string, error) {
+	return _Ccl.Contract.VERSION(&_Ccl.CallOpts)
+}
+
+// VERSION is a free data retrieval call binding the contract method 0xffa1ad74.
+//
+// Solidity: function VERSION() view returns(string)
+func (_Ccl *CclCallerSession) VERSION() (string, error) {
+	return _Ccl.Contract.VERSION(&_Ccl.CallOpts)
+}
+
+// GetConfiguration is a free data retrieval call binding the contract method 0xc44b11f7.
+//
+// Solidity: function getConfiguration(address emitterAddress) view returns(bytes32)
+func (_Ccl *CclCaller) GetConfiguration(opts *bind.CallOpts, emitterAddress common.Address) ([32]byte, error) {
+	var out []interface{}
+	err := _Ccl.contract.Call(opts, &out, "getConfiguration", emitterAddress)
+
+	if err != nil {
+		return *new([32]byte), err
+	}
+
+	out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte)
+
+	return out0, err
+
+}
+
+// GetConfiguration is a free data retrieval call binding the contract method 0xc44b11f7.
+//
+// Solidity: function getConfiguration(address emitterAddress) view returns(bytes32)
+func (_Ccl *CclSession) GetConfiguration(emitterAddress common.Address) ([32]byte, error) {
+	return _Ccl.Contract.GetConfiguration(&_Ccl.CallOpts, emitterAddress)
+}
+
+// GetConfiguration is a free data retrieval call binding the contract method 0xc44b11f7.
+//
+// Solidity: function getConfiguration(address emitterAddress) view returns(bytes32)
+func (_Ccl *CclCallerSession) GetConfiguration(emitterAddress common.Address) ([32]byte, error) {
+	return _Ccl.Contract.GetConfiguration(&_Ccl.CallOpts, emitterAddress)
+}
+
+// Configure is a paid mutator transaction binding the contract method 0xca23addf.
+//
+// Solidity: function configure(bytes32 config) returns()
+func (_Ccl *CclTransactor) Configure(opts *bind.TransactOpts, config [32]byte) (*types.Transaction, error) {
+	return _Ccl.contract.Transact(opts, "configure", config)
+}
+
+// Configure is a paid mutator transaction binding the contract method 0xca23addf.
+//
+// Solidity: function configure(bytes32 config) returns()
+func (_Ccl *CclSession) Configure(config [32]byte) (*types.Transaction, error) {
+	return _Ccl.Contract.Configure(&_Ccl.TransactOpts, config)
+}
+
+// Configure is a paid mutator transaction binding the contract method 0xca23addf.
+//
+// Solidity: function configure(bytes32 config) returns()
+func (_Ccl *CclTransactorSession) Configure(config [32]byte) (*types.Transaction, error) {
+	return _Ccl.Contract.Configure(&_Ccl.TransactOpts, config)
+}
+
+// CclConfigSetIterator is returned from FilterConfigSet and is used to iterate over the raw logs and unpacked data for ConfigSet events raised by the Ccl contract.
+type CclConfigSetIterator struct {
+	Event *CclConfigSet // Event containing the contract specifics and raw log
+
+	contract *bind.BoundContract // Generic contract to use for unpacking event data
+	event    string              // Event name to use for unpacking event data
+
+	logs chan types.Log        // Log channel receiving the found contract events
+	sub  ethereum.Subscription // Subscription for errors, completion and termination
+	done bool                  // Whether the subscription completed delivering logs
+	fail error                 // Occurred error to stop iteration
+}
+
+// Next advances the iterator to the subsequent event, returning whether there
+// are any more events found. In case of a retrieval or parsing error, false is
+// returned and Error() can be queried for the exact failure.
+func (it *CclConfigSetIterator) Next() bool {
+	// If the iterator failed, stop iterating
+	if it.fail != nil {
+		return false
+	}
+	// If the iterator completed, deliver directly whatever's available
+	if it.done {
+		select {
+		case log := <-it.logs:
+			it.Event = new(CclConfigSet)
+			if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
+				it.fail = err
+				return false
+			}
+			it.Event.Raw = log
+			return true
+
+		default:
+			return false
+		}
+	}
+	// Iterator still in progress, wait for either a data or an error event
+	select {
+	case log := <-it.logs:
+		it.Event = new(CclConfigSet)
+		if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
+			it.fail = err
+			return false
+		}
+		it.Event.Raw = log
+		return true
+
+	case err := <-it.sub.Err():
+		it.done = true
+		it.fail = err
+		return it.Next()
+	}
+}
+
+// Error returns any retrieval or parsing error occurred during filtering.
+func (it *CclConfigSetIterator) Error() error {
+	return it.fail
+}
+
+// Close terminates the iteration process, releasing any pending underlying
+// resources.
+func (it *CclConfigSetIterator) Close() error {
+	it.sub.Unsubscribe()
+	return nil
+}
+
+// CclConfigSet represents a ConfigSet event raised by the Ccl contract.
+type CclConfigSet struct {
+	EmitterAddress common.Address
+	Config         [32]byte
+	Raw            types.Log // Blockchain specific contextual infos
+}
+
+// FilterConfigSet is a free log retrieval operation binding the contract event 0xa37f0112e03d41de27266c1680238ff1548c0441ad1e73c82917c000eefdd5ea.
+//
+// Solidity: event ConfigSet(address emitterAddress, bytes32 config)
+func (_Ccl *CclFilterer) FilterConfigSet(opts *bind.FilterOpts) (*CclConfigSetIterator, error) {
+
+	logs, sub, err := _Ccl.contract.FilterLogs(opts, "ConfigSet")
+	if err != nil {
+		return nil, err
+	}
+	return &CclConfigSetIterator{contract: _Ccl.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+// WatchConfigSet is a free log subscription operation binding the contract event 0xa37f0112e03d41de27266c1680238ff1548c0441ad1e73c82917c000eefdd5ea.
+//
+// Solidity: event ConfigSet(address emitterAddress, bytes32 config)
+func (_Ccl *CclFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *CclConfigSet) (event.Subscription, error) {
+
+	logs, sub, err := _Ccl.contract.WatchLogs(opts, "ConfigSet")
+	if err != nil {
+		return nil, err
+	}
+	return event.NewSubscription(func(quit <-chan struct{}) error {
+		defer sub.Unsubscribe()
+		for {
+			select {
+			case log := <-logs:
+				// New log arrived, parse the event and forward to the user
+				event := new(CclConfigSet)
+				if err := _Ccl.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+					return err
+				}
+				event.Raw = log
+
+				select {
+				case sink <- event:
+				case err := <-sub.Err():
+					return err
+				case <-quit:
+					return nil
+				}
+			case err := <-sub.Err():
+				return err
+			case <-quit:
+				return nil
+			}
+		}
+	}), nil
+}
+
+// ParseConfigSet is a log parse operation binding the contract event 0xa37f0112e03d41de27266c1680238ff1548c0441ad1e73c82917c000eefdd5ea.
+//
+// Solidity: event ConfigSet(address emitterAddress, bytes32 config)
+func (_Ccl *CclFilterer) ParseConfigSet(log types.Log) (*CclConfigSet, error) {
+	event := new(CclConfigSet)
+	if err := _Ccl.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+		return nil, err
+	}
+	event.Raw = log
+	return event, nil
+}

+ 94 - 0
node/pkg/watchers/evm/custom_consistency_level_test.go

@@ -0,0 +1,94 @@
+package evm
+
+import (
+	"bytes"
+	"encoding/binary"
+	"encoding/hex"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestCclParseConfigInvalidType(t *testing.T) {
+	buf, err := hex.DecodeString("09c9002a00000000000000000000000000000000000000000000000000000000")
+	require.NoError(t, err)
+	require.Equal(t, 32, len(buf))
+	data := *(*[32]byte)(buf)
+
+	_, err = cclParseConfig(data)
+	assert.ErrorContains(t, err, "unexpected data type: 9")
+}
+
+func TestCclParseConfigAdditionalBlocksSuccess(t *testing.T) {
+	buf, err := hex.DecodeString("01c9002a00000000000000000000000000000000000000000000000000000000")
+	require.NoError(t, err)
+	require.Equal(t, 32, len(buf))
+	data := *(*[32]byte)(buf)
+
+	r, err := cclParseConfig(data)
+	require.NoError(t, err)
+	require.Equal(t, AdditionalBlocksType, r.Type())
+
+	switch req := r.(type) {
+	case *AdditionalBlocks:
+		assert.Equal(t, uint8(201), req.consistencyLevel)
+		assert.Equal(t, uint16(42), req.additionalBlocks)
+	default:
+		panic("unsupported query type")
+	}
+}
+
+func TestCclParseConfigSuccessNothingSpecial(t *testing.T) {
+	buf, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
+	require.NoError(t, err)
+	require.Equal(t, 32, len(buf))
+	data := *(*[32]byte)(buf)
+
+	r, err := cclParseConfig(data)
+	require.NoError(t, err)
+	require.Equal(t, NothingSpecialType, r.Type())
+
+	switch r.(type) {
+	case *NothingSpecial:
+	default:
+		panic("unsupported query type")
+	}
+}
+
+func TestCclParseAdditionalBlocksConfigWrongLength(t *testing.T) {
+	// First verify our test works by reading valid data.
+	err := testCclParseAdditionalBlocksConfig(t, "01c9002a00000000000000000000000000000000000000000000000000000000")
+	require.NoError(t, err)
+
+	// Too short (deleted the last byte).
+	err = testCclParseAdditionalBlocksConfig(t, "01c9002a000000000000000000000000000000000000000000000000000000")
+	assert.ErrorContains(t, err, "unexpected remaining unread bytes in buffer, should be 28, are 27")
+
+	// Too long (added an extra byte).
+	err = testCclParseAdditionalBlocksConfig(t, "01c9002a0000000000000000000000000000000000000000000000000000000000")
+	assert.ErrorContains(t, err, "unexpected remaining unread bytes in buffer, should be 28, are 29")
+
+	// Way too short (part of num blocks is missing).
+	err = testCclParseAdditionalBlocksConfig(t, "01c900")
+	assert.ErrorContains(t, err, "failed to read num blocks")
+
+	// Really too short (consistency level is missing).
+	err = testCclParseAdditionalBlocksConfig(t, "01")
+	assert.ErrorContains(t, err, "failed to read consistency level")
+}
+
+func testCclParseAdditionalBlocksConfig(t *testing.T, str string) error {
+	t.Helper()
+	data, err := hex.DecodeString(str)
+	require.NoError(t, err)
+	reader := bytes.NewReader(data[:])
+
+	// Skip the request type
+	reqType := CCLRequestType(0)
+	require.NoError(t, binary.Read(reader, binary.BigEndian, &reqType))
+	require.Equal(t, AdditionalBlocksType, reqType)
+
+	_, err = cclParseAdditionalBlocksConfig(reader)
+	return err
+}

+ 29 - 0
node/pkg/watchers/evm/verify_chain_config/verify.go

@@ -123,6 +123,16 @@ func verifyForEnv(env common.Environment, chainID vaa.ChainID) {
 					}
 					}
 					fmt.Println("\u2713")
 					fmt.Println("\u2713")
 				}
 				}
+
+				if entry.Entry.CCLContractAddr != "" {
+					fmt.Printf("   Verifying custom consistency level contract address for %v %v ", env, entry.ChainID)
+					err := verifyCCLContractAddr(ctx, entry.Entry.PublicRPC, entry.Entry.CCLContractAddr)
+					if err != nil {
+						fmt.Printf("\u2717\n   ERROR: failed to verify custom consistency level contract for %v %v: %v\n", env, entry.ChainID, err)
+						os.Exit(1)
+					}
+					fmt.Println("\u2713")
+				}
 			}
 			}
 		}
 		}
 	}
 	}
@@ -182,3 +192,22 @@ func verifyContractAddr(ctx context.Context, url string, contractAddr string) er
 
 
 	return nil
 	return nil
 }
 }
+
+func verifyCCLContractAddr(ctx context.Context, url string, contractAddr string) error {
+	timeout, cancel := context.WithTimeout(ctx, 15*time.Second)
+	defer cancel()
+
+	rawClient, err := ethRpc.DialContext(timeout, url)
+	if err != nil {
+		return fmt.Errorf("failed to connect: %w", err)
+	}
+
+	client := ethClient.NewClient(rawClient)
+
+	_, err = evm.CCLReadContract(ctx, client, ethCommon.HexToAddress(contractAddr), ethCommon.Address{})
+	if err != nil {
+		return err
+	}
+
+	return nil
+}

+ 161 - 111
node/pkg/watchers/evm/watcher.go

@@ -148,6 +148,12 @@ type (
 		txVerifierEnabled bool
 		txVerifierEnabled bool
 		// Transfer Verifier instance. If nil, transfer verification is disabled.
 		// Transfer Verifier instance. If nil, transfer verification is disabled.
 		txVerifier txverifier.TransferVerifierInterface
 		txVerifier txverifier.TransferVerifierInterface
+
+		cclEnabled   bool
+		cclLogger    *zap.Logger
+		cclAddr      eth_common.Address
+		cclCache     CCLCache
+		cclCacheLock sync.Mutex
 	}
 	}
 
 
 	pendingKey struct {
 	pendingKey struct {
@@ -158,8 +164,9 @@ type (
 	}
 	}
 
 
 	pendingMessage struct {
 	pendingMessage struct {
-		message *common.MessagePublication
-		height  uint64
+		message          *common.MessagePublication
+		height           uint64
+		additionalBlocks uint64
 	}
 	}
 )
 )
 
 
@@ -242,6 +249,7 @@ func (w *Watcher) Run(parentCtx context.Context) error {
 	logger := supervisor.Logger(parentCtx)
 	logger := supervisor.Logger(parentCtx)
 	w.logger = logger
 	w.logger = logger
 	w.ccqLogger = logger.With(zap.String("component", "ccqevm"))
 	w.ccqLogger = logger.With(zap.String("component", "ccqevm"))
+	w.cclLogger = logger.With(zap.String("component", "cclevm"))
 
 
 	logger.Info("Starting watcher",
 	logger.Info("Starting watcher",
 		zap.String("watcher_name", "evm"),
 		zap.String("watcher_name", "evm"),
@@ -409,6 +417,10 @@ func (w *Watcher) Run(parentCtx context.Context) error {
 		w.ccqStart(ctx, errC)
 		w.ccqStart(ctx, errC)
 	}
 	}
 
 
+	if err := w.cclEnable(ctx); err != nil {
+		return fmt.Errorf("failed to enable custom consistency level: %w", err)
+	}
+
 	common.RunWithScissors(ctx, errC, "evm_fetch_messages", func(ctx context.Context) error {
 	common.RunWithScissors(ctx, errC, "evm_fetch_messages", func(ctx context.Context) error {
 		for {
 		for {
 			select {
 			select {
@@ -481,153 +493,165 @@ func (w *Watcher) Run(parentCtx context.Context) error {
 				readiness.SetReady(w.readinessSync)
 				readiness.SetReady(w.readinessSync)
 
 
 				blockNumberU := ev.Number.Uint64()
 				blockNumberU := ev.Number.Uint64()
-				if ev.Finality == connectors.Latest {
+				var thisConsistencyLevel uint8
+				switch ev.Finality {
+				case connectors.Latest:
+					thisConsistencyLevel = vaa.ConsistencyLevelPublishImmediately
 					atomic.StoreUint64(&w.latestBlockNumber, blockNumberU)
 					atomic.StoreUint64(&w.latestBlockNumber, blockNumberU)
 					currentEthHeight.WithLabelValues(w.networkName).Set(float64(blockNumberU))
 					currentEthHeight.WithLabelValues(w.networkName).Set(float64(blockNumberU))
 					stats.Height = int64(blockNumberU) // #nosec G115 -- This conversion is safe indefinitely
 					stats.Height = int64(blockNumberU) // #nosec G115 -- This conversion is safe indefinitely
-					w.updateNetworkStats(&stats)
 					w.ccqAddLatestBlock(ev)
 					w.ccqAddLatestBlock(ev)
-					continue
-				}
-
-				// The only blocks that get here are safe and finalized.
-
-				if ev.Finality == connectors.Safe {
+				case connectors.Safe:
+					thisConsistencyLevel = vaa.ConsistencyLevelSafe
 					atomic.StoreUint64(&w.latestSafeBlockNumber, blockNumberU)
 					atomic.StoreUint64(&w.latestSafeBlockNumber, blockNumberU)
 					currentEthSafeHeight.WithLabelValues(w.networkName).Set(float64(blockNumberU))
 					currentEthSafeHeight.WithLabelValues(w.networkName).Set(float64(blockNumberU))
 					stats.SafeHeight = int64(blockNumberU) // #nosec G115 -- This conversion is safe indefinitely
 					stats.SafeHeight = int64(blockNumberU) // #nosec G115 -- This conversion is safe indefinitely
-				} else {
+				case connectors.Finalized:
+					thisConsistencyLevel = vaa.ConsistencyLevelFinalized
 					atomic.StoreUint64(&w.latestFinalizedBlockNumber, blockNumberU)
 					atomic.StoreUint64(&w.latestFinalizedBlockNumber, blockNumberU)
 					currentEthFinalizedHeight.WithLabelValues(w.networkName).Set(float64(blockNumberU))
 					currentEthFinalizedHeight.WithLabelValues(w.networkName).Set(float64(blockNumberU))
 					stats.FinalizedHeight = int64(blockNumberU) // #nosec G115 -- This conversion is safe indefinitely
 					stats.FinalizedHeight = int64(blockNumberU) // #nosec G115 -- This conversion is safe indefinitely
+				default:
+					logger.Error("unexpected finality in block", zap.Stringer("finality", ev.Finality), zap.Any("event", ev))
+					errC <- fmt.Errorf("unexpected finality in block: %v", ev.Finality)
+					p2p.DefaultRegistry.AddErrorCount(w.chainID, 1)
+					return nil
 				}
 				}
 				w.updateNetworkStats(&stats)
 				w.updateNetworkStats(&stats)
 
 
 				w.pendingMu.Lock()
 				w.pendingMu.Lock()
 				for key, pLock := range w.pending {
 				for key, pLock := range w.pending {
-					// If this block is safe, only process messages wanting safe.
-					// If it's not safe, only process messages wanting finalized.
-					if (ev.Finality == connectors.Safe) != (pLock.message.ConsistencyLevel == vaa.ConsistencyLevelSafe) {
+					// Don't process the observation if it is waiting on a different consistency level.
+					if !consistencyLevelMatches(thisConsistencyLevel, pLock.message.ConsistencyLevel) {
+						continue
+					}
+
+					// Don't process the observation if we haven't reached the desired block height yet.
+					if pLock.height+pLock.additionalBlocks > blockNumberU {
 						continue
 						continue
 					}
 					}
 
 
 					// Transaction is now ready
 					// Transaction is now ready
-					if pLock.height <= blockNumberU {
-						msm := time.Now()
-						timeout, cancel := context.WithTimeout(ctx, 5*time.Second)
-						tx, err := w.ethConn.TransactionReceipt(timeout, eth_common.BytesToHash(pLock.message.TxID))
-						queryLatency.WithLabelValues(w.networkName, "transaction_receipt").Observe(time.Since(msm).Seconds())
-						cancel()
-
-						// If the node returns an error after waiting expectedConfirmation blocks,
-						// it means the chain reorged and the transaction was orphaned. The
-						// TransactionReceipt call is using the same websocket connection than the
-						// head notifications, so it's guaranteed to be atomic.
-						//
-						// Check multiple possible error cases - the node seems to return a
-						// "not found" error most of the time, but it could conceivably also
-						// return a nil tx or rpc.ErrNoResult.
-						if tx == nil || errors.Is(err, rpc.ErrNoResult) || (err != nil && err.Error() == "not found") {
-							logger.Warn("tx was orphaned",
-								zap.String("msgId", pLock.message.MessageIDString()),
-								zap.String("txHash", pLock.message.TxIDString()),
-								zap.Stringer("blockHash", key.BlockHash),
-								zap.Uint64("target_blockNum", pLock.height),
-								zap.Stringer("current_blockNum", ev.Number),
-								zap.Stringer("finality", ev.Finality),
-								zap.Stringer("current_blockHash", currentHash),
-								zap.Error(err))
-							delete(w.pending, key)
-							ethMessagesOrphaned.WithLabelValues(w.networkName, "not_found").Inc()
-							continue
-						}
+					msm := time.Now()
+					timeout, cancel := context.WithTimeout(ctx, 5*time.Second)
+					tx, err := w.ethConn.TransactionReceipt(timeout, eth_common.BytesToHash(pLock.message.TxID))
+					queryLatency.WithLabelValues(w.networkName, "transaction_receipt").Observe(time.Since(msm).Seconds())
+					cancel()
+
+					// If the node returns an error after waiting expectedConfirmation blocks,
+					// it means the chain reorged and the transaction was orphaned. The
+					// TransactionReceipt call is using the same websocket connection than the
+					// head notifications, so it's guaranteed to be atomic.
+					//
+					// Check multiple possible error cases - the node seems to return a
+					// "not found" error most of the time, but it could conceivably also
+					// return a nil tx or rpc.ErrNoResult.
+					if tx == nil || errors.Is(err, rpc.ErrNoResult) || (err != nil && err.Error() == "not found") {
+						logger.Warn("tx was orphaned",
+							zap.String("msgId", pLock.message.MessageIDString()),
+							zap.String("txHash", pLock.message.TxIDString()),
+							zap.Stringer("blockHash", key.BlockHash),
+							zap.Uint64("observedHeight", pLock.height),
+							zap.Uint64("additionalBlocks", pLock.additionalBlocks),
+							zap.Stringer("current_blockNum", ev.Number),
+							zap.Stringer("finality", ev.Finality),
+							zap.Stringer("current_blockHash", currentHash),
+							zap.Error(err))
+						delete(w.pending, key)
+						ethMessagesOrphaned.WithLabelValues(w.networkName, "not_found").Inc()
+						continue
+					}
 
 
-						// This should never happen - if we got this far, it means that logs were emitted,
-						// which is only possible if the transaction succeeded. We check it anyway just
-						// in case the EVM implementation is buggy.
-						if tx.Status != 1 {
-							logger.Error("transaction receipt with non-success status",
+					// This should never happen - if we got this far, it means that logs were emitted,
+					// which is only possible if the transaction succeeded. We check it anyway just
+					// in case the EVM implementation is buggy.
+					if tx.Status != 1 {
+						logger.Error("transaction receipt with non-success status",
+							zap.String("msgId", pLock.message.MessageIDString()),
+							zap.String("txHash", pLock.message.TxIDString()),
+							zap.Stringer("blockHash", key.BlockHash),
+							zap.Uint64("observedHeight", pLock.height),
+							zap.Uint64("additionalBlocks", pLock.additionalBlocks),
+							zap.Stringer("current_blockNum", ev.Number),
+							zap.Stringer("finality", ev.Finality),
+							zap.Stringer("current_blockHash", currentHash),
+							zap.Error(err))
+						delete(w.pending, key)
+						ethMessagesOrphaned.WithLabelValues(w.networkName, "tx_failed").Inc()
+						continue
+					}
+
+					// Any error other than "not found" is likely transient - we retry next block.
+					if err != nil {
+						if pLock.height+MaxWaitConfirmations <= blockNumberU {
+							// An error from this "transient" case has persisted for more than MaxWaitConfirmations.
+							logger.Info("observation timed out",
 								zap.String("msgId", pLock.message.MessageIDString()),
 								zap.String("msgId", pLock.message.MessageIDString()),
 								zap.String("txHash", pLock.message.TxIDString()),
 								zap.String("txHash", pLock.message.TxIDString()),
 								zap.Stringer("blockHash", key.BlockHash),
 								zap.Stringer("blockHash", key.BlockHash),
-								zap.Uint64("target_blockNum", pLock.height),
+								zap.Uint64("observedHeight", pLock.height),
+								zap.Uint64("additionalBlocks", pLock.additionalBlocks),
 								zap.Stringer("current_blockNum", ev.Number),
 								zap.Stringer("current_blockNum", ev.Number),
 								zap.Stringer("finality", ev.Finality),
 								zap.Stringer("finality", ev.Finality),
 								zap.Stringer("current_blockHash", currentHash),
 								zap.Stringer("current_blockHash", currentHash),
-								zap.Error(err))
+							)
+							ethMessagesOrphaned.WithLabelValues(w.networkName, "timeout").Inc()
 							delete(w.pending, key)
 							delete(w.pending, key)
-							ethMessagesOrphaned.WithLabelValues(w.networkName, "tx_failed").Inc()
-							continue
-						}
-
-						// Any error other than "not found" is likely transient - we retry next block.
-						if err != nil {
-							if pLock.height+MaxWaitConfirmations <= blockNumberU {
-								// An error from this "transient" case has persisted for more than MaxWaitConfirmations.
-								logger.Info("observation timed out",
-									zap.String("msgId", pLock.message.MessageIDString()),
-									zap.String("txHash", pLock.message.TxIDString()),
-									zap.Stringer("blockHash", key.BlockHash),
-									zap.Uint64("target_blockNum", pLock.height),
-									zap.Stringer("current_blockNum", ev.Number),
-									zap.Stringer("finality", ev.Finality),
-									zap.Stringer("current_blockHash", currentHash),
-								)
-								ethMessagesOrphaned.WithLabelValues(w.networkName, "timeout").Inc()
-								delete(w.pending, key)
-							} else {
-								logger.Warn("transaction could not be fetched",
-									zap.String("msgId", pLock.message.MessageIDString()),
-									zap.String("txHash", pLock.message.TxIDString()),
-									zap.Stringer("blockHash", key.BlockHash),
-									zap.Uint64("target_blockNum", pLock.height),
-									zap.Stringer("current_blockNum", ev.Number),
-									zap.Stringer("finality", ev.Finality),
-									zap.Stringer("current_blockHash", currentHash),
-									zap.Error(err))
-							}
-							continue
-						}
-
-						// It's possible for a transaction to be orphaned and then included in a different block
-						// but with the same tx hash. Drop the observation (it will be re-observed and needs to
-						// wait for the full confirmation time again).
-						if tx.BlockHash != key.BlockHash {
-							logger.Info("tx got dropped and mined in a different block; the message should have been reobserved",
+						} else {
+							logger.Warn("transaction could not be fetched",
 								zap.String("msgId", pLock.message.MessageIDString()),
 								zap.String("msgId", pLock.message.MessageIDString()),
 								zap.String("txHash", pLock.message.TxIDString()),
 								zap.String("txHash", pLock.message.TxIDString()),
 								zap.Stringer("blockHash", key.BlockHash),
 								zap.Stringer("blockHash", key.BlockHash),
-								zap.Uint64("target_blockNum", pLock.height),
+								zap.Uint64("observedHeight", pLock.height),
+								zap.Uint64("additionalBlocks", pLock.additionalBlocks),
 								zap.Stringer("current_blockNum", ev.Number),
 								zap.Stringer("current_blockNum", ev.Number),
 								zap.Stringer("finality", ev.Finality),
 								zap.Stringer("finality", ev.Finality),
 								zap.Stringer("current_blockHash", currentHash),
 								zap.Stringer("current_blockHash", currentHash),
-							)
-							delete(w.pending, key)
-							ethMessagesOrphaned.WithLabelValues(w.networkName, "blockhash_mismatch").Inc()
-							continue
+								zap.Error(err))
 						}
 						}
+						continue
+					}
 
 
-						logger.Info("observation confirmed",
+					// It's possible for a transaction to be orphaned and then included in a different block
+					// but with the same tx hash. Drop the observation (it will be re-observed and needs to
+					// wait for the full confirmation time again).
+					if tx.BlockHash != key.BlockHash {
+						logger.Info("tx got dropped and mined in a different block; the message should have been reobserved",
 							zap.String("msgId", pLock.message.MessageIDString()),
 							zap.String("msgId", pLock.message.MessageIDString()),
 							zap.String("txHash", pLock.message.TxIDString()),
 							zap.String("txHash", pLock.message.TxIDString()),
 							zap.Stringer("blockHash", key.BlockHash),
 							zap.Stringer("blockHash", key.BlockHash),
-							zap.Uint64("target_blockNum", pLock.height),
+							zap.Uint64("observedHeight", pLock.height),
+							zap.Uint64("additionalBlocks", pLock.additionalBlocks),
 							zap.Stringer("current_blockNum", ev.Number),
 							zap.Stringer("current_blockNum", ev.Number),
 							zap.Stringer("finality", ev.Finality),
 							zap.Stringer("finality", ev.Finality),
 							zap.Stringer("current_blockHash", currentHash),
 							zap.Stringer("current_blockHash", currentHash),
 						)
 						)
 						delete(w.pending, key)
 						delete(w.pending, key)
+						ethMessagesOrphaned.WithLabelValues(w.networkName, "blockhash_mismatch").Inc()
+						continue
+					}
 
 
-						// Note that `tx` here is actually a receipt
-						txHash := eth_common.Hash(pLock.message.TxID)
-						pubErr := w.verifyAndPublish(pLock.message, ctx, txHash, tx)
-						if pubErr != nil {
-							logger.Error("could not publish message",
-								zap.String("msgId", pLock.message.MessageIDString()),
-								zap.String("txHash", txHash.String()),
-								zap.Error(pubErr),
-							)
-						}
+					logger.Info("observation confirmed",
+						zap.String("msgId", pLock.message.MessageIDString()),
+						zap.String("txHash", pLock.message.TxIDString()),
+						zap.Stringer("blockHash", key.BlockHash),
+						zap.Uint64("observedHeight", pLock.height),
+						zap.Uint64("additionalBlocks", pLock.additionalBlocks),
+						zap.Stringer("current_blockNum", ev.Number),
+						zap.Stringer("finality", ev.Finality),
+						zap.Stringer("current_blockHash", currentHash),
+					)
+					delete(w.pending, key)
+
+					// Note that `tx` here is actually a receipt
+					txHash := eth_common.Hash(pLock.message.TxID)
+					pubErr := w.verifyAndPublish(pLock.message, ctx, txHash, tx)
+					if pubErr != nil {
+						logger.Error("could not publish message",
+							zap.String("msgId", pLock.message.MessageIDString()),
+							zap.String("txHash", txHash.String()),
+							zap.Error(pubErr),
+						)
 					}
 					}
 				}
 				}
 
 
@@ -815,15 +839,29 @@ func (w *Watcher) postMessage(
 		return
 		return
 	}
 	}
 
 
+	pendingEntry := &pendingMessage{
+		message: msg,
+		height:  ev.Raw.BlockNumber,
+	}
+
+	if msg.ConsistencyLevel == vaa.ConsistencyLevelCustom {
+		// Note: This function may modify the contents of pendingEntry.
+		w.cclHandleMessage(parentCtx, pendingEntry, ev.Sender)
+	}
+
 	w.logger.Info("found new message publication transaction",
 	w.logger.Info("found new message publication transaction",
 		zap.String("msgId", msg.MessageIDString()),
 		zap.String("msgId", msg.MessageIDString()),
 		zap.String("txHash", msg.TxIDString()),
 		zap.String("txHash", msg.TxIDString()),
-		zap.Uint64("blockNum", ev.Raw.BlockNumber),
+		zap.Uint64("reportedBlockNum", ev.Raw.BlockNumber),
+		zap.Uint64("latestBlock", atomic.LoadUint64(&w.latestBlockNumber)),
 		zap.Uint64("latestFinalizedBlock", atomic.LoadUint64(&w.latestFinalizedBlockNumber)),
 		zap.Uint64("latestFinalizedBlock", atomic.LoadUint64(&w.latestFinalizedBlockNumber)),
+		zap.Uint64("latestSafeBlock", atomic.LoadUint64(&w.latestSafeBlockNumber)),
 		zap.Stringer("blockHash", ev.Raw.BlockHash),
 		zap.Stringer("blockHash", ev.Raw.BlockHash),
 		zap.Uint64("blockTime", blockTime),
 		zap.Uint64("blockTime", blockTime),
 		zap.Uint32("Nonce", ev.Nonce),
 		zap.Uint32("Nonce", ev.Nonce),
-		zap.Uint8("ConsistencyLevel", ev.ConsistencyLevel),
+		zap.Uint8("OrigConsistencyLevel", ev.ConsistencyLevel),
+		zap.Uint8("ConsistencyLevel", pendingEntry.message.ConsistencyLevel),
+		zap.Uint64("AdditionalBlocks", pendingEntry.additionalBlocks),
 	)
 	)
 
 
 	key := pendingKey{
 	key := pendingKey{
@@ -834,10 +872,7 @@ func (w *Watcher) postMessage(
 	}
 	}
 
 
 	w.pendingMu.Lock()
 	w.pendingMu.Lock()
-	w.pending[key] = &pendingMessage{
-		message: msg,
-		height:  ev.Raw.BlockNumber,
-	}
+	w.pending[key] = pendingEntry
 	w.pendingMu.Unlock()
 	w.pendingMu.Unlock()
 }
 }
 
 
@@ -997,3 +1032,18 @@ func (w *Watcher) createConnector(ctx context.Context, url string) (ethConn conn
 	}
 	}
 	return
 	return
 }
 }
+
+// consistencyLevelMatches returns true if the consistency level of this block "matches" the requested consistency level of an observation.
+// It matches if either the actual values match, or if this block is finalized and the requested value is not immediate (latest) or safe.
+// This extra check is necessary because the requested consistency level is assumed to be finalized unless they specifically ask for immediate or safe.
+func consistencyLevelMatches(thisConsistencyLevel uint8, requestedConsistencyLevel uint8) bool {
+	if thisConsistencyLevel == requestedConsistencyLevel {
+		return true
+	}
+
+	if thisConsistencyLevel != vaa.ConsistencyLevelFinalized {
+		return false
+	}
+
+	return requestedConsistencyLevel != vaa.ConsistencyLevelPublishImmediately && requestedConsistencyLevel != vaa.ConsistencyLevelSafe
+}

+ 16 - 0
node/pkg/watchers/evm/watcher_test.go

@@ -210,3 +210,19 @@ func (m *MockTransferVerifier[E, C]) Addrs() *txverifier.TVAddresses {
 		TokenBridgeAddr: eth_common.BytesToAddress([]byte{0x01}),
 		TokenBridgeAddr: eth_common.BytesToAddress([]byte{0x01}),
 	}
 	}
 }
 }
+
+func TestConsistencyLevelMatches(t *testing.T) {
+	// Success cases.
+	assert.True(t, consistencyLevelMatches(vaa.ConsistencyLevelPublishImmediately, vaa.ConsistencyLevelPublishImmediately))
+	assert.True(t, consistencyLevelMatches(vaa.ConsistencyLevelSafe, vaa.ConsistencyLevelSafe))
+	assert.True(t, consistencyLevelMatches(vaa.ConsistencyLevelFinalized, vaa.ConsistencyLevelFinalized))
+	assert.True(t, consistencyLevelMatches(vaa.ConsistencyLevelFinalized, 0))
+	assert.True(t, consistencyLevelMatches(vaa.ConsistencyLevelFinalized, 42))
+
+	// Failure cases.
+	assert.False(t, consistencyLevelMatches(vaa.ConsistencyLevelPublishImmediately, vaa.ConsistencyLevelSafe))
+	assert.False(t, consistencyLevelMatches(vaa.ConsistencyLevelSafe, vaa.ConsistencyLevelFinalized))
+	assert.False(t, consistencyLevelMatches(vaa.ConsistencyLevelFinalized, vaa.ConsistencyLevelPublishImmediately))
+	assert.False(t, consistencyLevelMatches(vaa.ConsistencyLevelPublishImmediately, 0))
+	assert.False(t, consistencyLevelMatches(vaa.ConsistencyLevelSafe, 0))
+}

+ 15 - 0
scripts/devnet-consts.json

@@ -315,6 +315,21 @@
       "name": "12",
       "name": "12",
       "public": "0xfA2435Eacf10Ca62ae6787ba2fB044f8733Ee843",
       "public": "0xfA2435Eacf10Ca62ae6787ba2fB044f8733Ee843",
       "private": "0x9b9c613a36396172eab2d34d72331c8ca83a358781883a535d2941f66db07b24"
       "private": "0x9b9c613a36396172eab2d34d72331c8ca83a358781883a535d2941f66db07b24"
+    },
+    {
+      "name": "13",
+      "public": "0x64E078A8Aa15A41B85890265648e965De686bAE6",
+      "private": "0x0874049f95d55fb76916262dc70571701b5c4cc5900c0691af75f1a8a52c8268"
+    },
+    {
+      "name": "14",
+      "public": "0x2F560290FEF1B3Ada194b6aA9c40aa71f8e95598",
+      "private": "0x21d7212f3b4e5332fd465877b64926e3532653e2798a11255a46f533852dfe46"
+    },
+    {
+      "name": "15",
+      "public": "0xf408f04F9b7691f7174FA2bb73ad6d45fD5d3CBe",
+      "private": "0x47b65307d0d654fd4f786b908c04af8fface7710fc998b37d219de19c39ee58c"
     }
     }
   ],
   ],
   "devnetGuardians": [
   "devnetGuardians": [

+ 2 - 0
sdk/vaa/structs.go

@@ -104,6 +104,8 @@ type (
 const (
 const (
 	ConsistencyLevelPublishImmediately = uint8(200)
 	ConsistencyLevelPublishImmediately = uint8(200)
 	ConsistencyLevelSafe               = uint8(201)
 	ConsistencyLevelSafe               = uint8(201)
+	ConsistencyLevelFinalized          = uint8(202)
+	ConsistencyLevelCustom             = uint8(203)
 )
 )
 
 
 //nolint:unparam // error is always nil here but the return type is required to satisfy the interface.
 //nolint:unparam // error is always nil here but the return type is required to satisfy the interface.

+ 307 - 0
testing/contract-integrations/custom_consistency_level/__tests__/test_custom_consistency_level.ts

@@ -0,0 +1,307 @@
+import { ethers } from "ethers";
+import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
+import axios from "axios";
+
+import {
+  CHAIN_ID_ETH,
+  CONTRACTS,
+  getEmitterAddressEth,
+  getSignedVAAWithRetry,
+  parseSequenceFromLogEth,
+} from "@certusone/wormhole-sdk";
+
+import * as CustomConsistencyLevel from "../../../../ethereum/build-forge/CustomConsistencyLevel.sol/CustomConsistencyLevel.json";
+import * as TestCustomConsistencyLevel from "../../../../ethereum/build-forge/TestCustomConsistencyLevel.sol/TestCustomConsistencyLevel.json";
+
+const ci = process.env.CI == "true";
+
+const ETH_NODE_URL = ci ? "http://eth-devnet:8545" : "http://localhost:8545";
+
+const ETH_PRIVATE_KEY14 =
+  "0x21d7212f3b4e5332fd465877b64926e3532653e2798a11255a46f533852dfe46";
+
+const GUARDIAN_HOST = ci ? "guardian" : "localhost";
+const GUARDIAN_RPCS = [`http://${GUARDIAN_HOST}:7071`];
+
+const CORE_CONTRACT_ADDR = "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550";
+const CCL_CONTRACT_ADDR = "0x6A4B4A882F5F0a447078b4Fd0b4B571A82371ec2";
+
+// Waiting for safe and finalized can take a while!
+jest.setTimeout(300000);
+
+let ethProvider: ethers.providers.JsonRpcProvider;
+let ethSigner: ethers.Wallet;
+
+let cclContract: ethers.Contract;
+let testContractFactory: ethers.ContractFactory;
+
+const numBlocks = 5;
+
+beforeAll(async () => {
+  // 1. create a signer for Eth
+  ethProvider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
+  ethSigner = new ethers.Wallet(ETH_PRIVATE_KEY14, ethProvider);
+
+  // 1. Connect to the custom consistency contract so we can read the config.
+  cclContract = new ethers.Contract(
+    CCL_CONTRACT_ADDR,
+    CustomConsistencyLevel.abi,
+    ethProvider
+  );
+
+  // Get the contract factory so we can deploy instances of the test contract.
+  testContractFactory = new ethers.ContractFactory(
+    TestCustomConsistencyLevel.abi,
+    TestCustomConsistencyLevel.bytecode,
+    ethSigner
+  );
+});
+
+const deployTestContract = async (
+  consistencyLevel: number,
+  blocks: number
+): Promise<ethers.Contract> => {
+  // Deploy the contract with the specified parameters.
+  const contract = await testContractFactory.deploy(
+    CORE_CONTRACT_ADDR,
+    CCL_CONTRACT_ADDR,
+    consistencyLevel,
+    blocks
+  );
+
+  // Wait for the contract to be deployed and return it.
+  await contract.deployTransaction.wait();
+  return contract;
+};
+
+const setCustomConsistencyLevel = async (
+  contract: ethers.Contract,
+  consistencyLevel: number,
+  blocks: number
+): Promise<void> => {
+  // Call the write function
+  const transaction = await contract.configure(consistencyLevel, blocks);
+
+  // Wait for the transaction to be mined
+  return transaction.wait();
+};
+
+const getCustomConsistencyLevel = async (
+  contractAddr: string
+): Promise<string> => {
+  return cclContract.getConfiguration(contractAddr);
+};
+
+const getBlockNumber = async (tag: string): Promise<number> => {
+  const str: string = (
+    await axios.post(ETH_NODE_URL, {
+      jsonrpc: "2.0",
+      id: 1,
+      method: "eth_getBlockByNumber",
+      params: [tag, false],
+    })
+  ).data?.result?.number;
+  return Number(str);
+};
+
+describe("Custom Consistency Level Tests", () => {
+  test("1. Set and get consistency level", async () => {
+    const testContract = await deployTestContract(200, 42);
+    expect(await getCustomConsistencyLevel(testContract.address)).toEqual(
+      "0x01c8002a00000000000000000000000000000000000000000000000000000000"
+    );
+
+    await setCustomConsistencyLevel(testContract, 200, 7);
+    expect(await getCustomConsistencyLevel(testContract.address)).toEqual(
+      "0x01c8000700000000000000000000000000000000000000000000000000000000"
+    );
+  });
+
+  test("2. Post a message with latest", async () => {
+    // Create an instance of the test contract for latest.
+    const contract = await deployTestContract(200, numBlocks);
+    console.log("Latest: deployed to address ", contract.address);
+
+    // Make sure the config is what we expect.
+    expect(await getCustomConsistencyLevel(contract.address)).toEqual(
+      "0x01c8000500000000000000000000000000000000000000000000000000000000"
+    );
+
+    // Publish a message.
+    const transaction = await contract.publishMessage("Hello, World!");
+
+    // Wait for the transaction to be mined.
+    const receipt = await transaction.wait();
+
+    // Get the block number of the mined transaction.
+    const blockNumber: number = Number(receipt.blockNumber as string);
+
+    // Get the sequence from the logs (needed to fetch the vaa).
+    const sequence = parseSequenceFromLogEth(
+      receipt,
+      CONTRACTS.DEVNET.ethereum.core
+    );
+
+    // Wait for the VAA to be published.
+    await getSignedVAAWithRetry(
+      GUARDIAN_RPCS,
+      CHAIN_ID_ETH,
+      getEmitterAddressEth(contract.address),
+      sequence,
+      {
+        transport: NodeHttpTransport(),
+      }
+    );
+
+    // Make sure the VAA wasn't published early. This won't be exact, but it definitely shouldn't be sooner than expected.
+    const currentBlockNum = await getBlockNumber("latest");
+    console.log(
+      "Latest: original block: ",
+      blockNumber,
+      ", currentBlock: ",
+      currentBlockNum
+    );
+    expect(blockNumber + numBlocks).toBeLessThanOrEqual(currentBlockNum);
+  });
+
+  test("3. Post a message with safe", async () => {
+    // Create an instance of the test contract for safe.
+    const contract = await deployTestContract(201, numBlocks);
+    console.log("Safe: deployed to address ", contract.address);
+
+    // Make sure the config is what we expect.
+    expect(await getCustomConsistencyLevel(contract.address)).toEqual(
+      "0x01c9000500000000000000000000000000000000000000000000000000000000"
+    );
+
+    // Publish a message.
+    const transaction = await contract.publishMessage("Hello, World!");
+
+    // Wait for the transaction to be mined.
+    const receipt = await transaction.wait();
+
+    // Get the block number of the mined transaction.
+    const blockNumber: number = Number(receipt.blockNumber as string);
+
+    // Get the sequence from the logs (needed to fetch the vaa).
+    const sequence = parseSequenceFromLogEth(
+      receipt,
+      CONTRACTS.DEVNET.ethereum.core
+    );
+
+    // Wait for the VAA to be published.
+    await getSignedVAAWithRetry(
+      GUARDIAN_RPCS,
+      CHAIN_ID_ETH,
+      getEmitterAddressEth(contract.address),
+      sequence,
+      {
+        transport: NodeHttpTransport(),
+      }
+    );
+
+    // Make sure the VAA wasn't published early. This won't be exact, but it definitely shouldn't be sooner than expected.
+    const currentSafe = await getBlockNumber("safe");
+    console.log(
+      "Safe: original block: ",
+      blockNumber,
+      ", currentSafe: ",
+      currentSafe
+    );
+    expect(blockNumber + numBlocks).toBeLessThanOrEqual(currentSafe);
+  });
+
+  test("4. Post a message with finalized", async () => {
+    // Create an instance of the test contract for finalized.
+    const contract = await deployTestContract(202, numBlocks);
+    console.log("Finalized: deployed to address ", contract.address);
+
+    // Make sure the config is what we expect.
+    expect(await getCustomConsistencyLevel(contract.address)).toEqual(
+      "0x01ca000500000000000000000000000000000000000000000000000000000000"
+    );
+
+    // Publish a message.
+    const transaction = await contract.publishMessage("Hello, World!");
+
+    // Wait for the transaction to be mined.
+    const receipt = await transaction.wait();
+
+    // Get the block number of the mined transaction.
+    const blockNumber: number = Number(receipt.blockNumber as string);
+
+    // Get the sequence from the logs (needed to fetch the vaa).
+    const sequence = parseSequenceFromLogEth(
+      receipt,
+      CONTRACTS.DEVNET.ethereum.core
+    );
+
+    // Wait for the VAA to be published.
+    await getSignedVAAWithRetry(
+      GUARDIAN_RPCS,
+      CHAIN_ID_ETH,
+      getEmitterAddressEth(contract.address),
+      sequence,
+      {
+        transport: NodeHttpTransport(),
+      }
+    );
+
+    // Make sure the VAA wasn't published early. This won't be exact, but it definitely shouldn't be sooner than expected.
+    const currentFinalized = await getBlockNumber("finalized");
+    console.log(
+      "Finalized: original block: ",
+      blockNumber,
+      ", currentFinalized: ",
+      currentFinalized
+    );
+    expect(blockNumber + numBlocks).toBeLessThanOrEqual(currentFinalized);
+  });
+
+  test("5. Post a message with latest, no additional blocks", async () => {
+    // Create an instance of the test contract for latest.
+    const contract = await deployTestContract(200, 0);
+    console.log("Latest0: deployed to address ", contract.address);
+
+    // Make sure the config is what we expect.
+    expect(await getCustomConsistencyLevel(contract.address)).toEqual(
+      "0x01c8000000000000000000000000000000000000000000000000000000000000"
+    );
+
+    // Publish a message.
+    const transaction = await contract.publishMessage("Hello, World!");
+
+    // Wait for the transaction to be mined.
+    const receipt = await transaction.wait();
+
+    // Get the block number of the mined transaction.
+    const blockNumber: number = Number(receipt.blockNumber as string);
+
+    // Get the sequence from the logs (needed to fetch the vaa).
+    const sequence = parseSequenceFromLogEth(
+      receipt,
+      CONTRACTS.DEVNET.ethereum.core
+    );
+
+    // Wait for the VAA to be published.
+    await getSignedVAAWithRetry(
+      GUARDIAN_RPCS,
+      CHAIN_ID_ETH,
+      getEmitterAddressEth(contract.address),
+      sequence,
+      {
+        transport: NodeHttpTransport(),
+      }
+    );
+
+    // Make sure the VAA wasn't published early. This won't be exact, but it definitely shouldn't be sooner than expected.
+    const currentBlockNum = await getBlockNumber("latest");
+    console.log(
+      "Latest0: original block: ",
+      blockNumber,
+      ", currentBlock: ",
+      currentBlockNum
+    );
+    expect(blockNumber).toBeLessThanOrEqual(currentBlockNum);
+  });
+});

+ 18 - 0
testing/contract-integrations/custom_consistency_level/ci-config.js

@@ -0,0 +1,18 @@
+// process.env.CI = true;
+
+const info = console.info;
+console.info = function (x) {
+  if (x !== "secp256k1 unavailable, reverting to browser version") {
+    info(x);
+  }
+};
+
+const warn = console.warn;
+console.warn = function (x) {
+  if (
+    x !==
+    "bigint: Failed to load bindings, pure JS will be used (try npm run rebuild?)"
+  ) {
+    warn(x);
+  }
+};

+ 5 - 0
testing/contract-integrations/custom_consistency_level/jest.config.js

@@ -0,0 +1,5 @@
+/** @type {import('ts-jest').JestConfigWithTsJest} */
+module.exports = {
+  preset: 'ts-jest',
+  testEnvironment: 'node',
+};

+ 8264 - 0
testing/contract-integrations/custom_consistency_level/package-lock.json

@@ -0,0 +1,8264 @@
+{
+  "name": "@wormhole-foundation/test-custom-consistency-level",
+  "version": "0.0.1",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "@wormhole-foundation/test-custom-consistency-level",
+      "version": "0.0.1",
+      "dependencies": {
+        "@certusone/wormhole-sdk": "0.10.10",
+        "@cosmjs/cosmwasm-stargate": "0.29.5",
+        "@improbable-eng/grpc-web-node-http-transport": "0.15.0",
+        "cosmwasm": "1.1.1",
+        "dotenv": "16.0.3",
+        "elliptic": "^6.6.1",
+        "ethers": "5.7.2",
+        "js-sha3": "0.8.0",
+        "web3-eth-abi": "1.8.1",
+        "yargs": "17.6.2"
+      },
+      "devDependencies": {
+        "@types/elliptic": "6.4.14",
+        "@types/jest": "^29.4.0",
+        "jest": "29.4.1",
+        "ts-jest": "29.0.5",
+        "ts-node": "10.9.1",
+        "typescript": "4.9.4"
+      }
+    },
+    "node_modules/@ampproject/remapping": {
+      "version": "2.2.0",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.1.0",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@apollo/client": {
+      "version": "3.9.5",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@graphql-typed-document-node/core": "^3.1.1",
+        "@wry/caches": "^1.0.0",
+        "@wry/equality": "^0.5.6",
+        "@wry/trie": "^0.5.0",
+        "graphql-tag": "^2.12.6",
+        "hoist-non-react-statics": "^3.3.2",
+        "optimism": "^0.18.0",
+        "prop-types": "^15.7.2",
+        "rehackt": "0.0.5",
+        "response-iterator": "^0.2.6",
+        "symbol-observable": "^4.0.0",
+        "ts-invariant": "^0.10.3",
+        "tslib": "^2.3.0",
+        "zen-observable-ts": "^1.2.5"
+      },
+      "peerDependencies": {
+        "graphql": "^15.0.0 || ^16.0.0",
+        "graphql-ws": "^5.5.5",
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+        "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0",
+        "subscriptions-transport-ws": "^0.9.0 || ^0.11.0"
+      },
+      "peerDependenciesMeta": {
+        "graphql-ws": {
+          "optional": true
+        },
+        "react": {
+          "optional": true
+        },
+        "react-dom": {
+          "optional": true
+        },
+        "subscriptions-transport-ws": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@apollo/client/node_modules/symbol-observable": {
+      "version": "4.0.0",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.18.6",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/highlight": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/compat-data": {
+      "version": "7.20.14",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/core": {
+      "version": "7.20.12",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@ampproject/remapping": "^2.1.0",
+        "@babel/code-frame": "^7.18.6",
+        "@babel/generator": "^7.20.7",
+        "@babel/helper-compilation-targets": "^7.20.7",
+        "@babel/helper-module-transforms": "^7.20.11",
+        "@babel/helpers": "^7.20.7",
+        "@babel/parser": "^7.20.7",
+        "@babel/template": "^7.20.7",
+        "@babel/traverse": "^7.20.12",
+        "@babel/types": "^7.20.7",
+        "convert-source-map": "^1.7.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.2",
+        "json5": "^2.2.2",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/babel"
+      }
+    },
+    "node_modules/@babel/core/node_modules/convert-source-map": {
+      "version": "1.9.0",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@babel/core/node_modules/semver": {
+      "version": "6.3.0",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/generator": {
+      "version": "7.20.14",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.20.7",
+        "@jridgewell/gen-mapping": "^0.3.2",
+        "jsesc": "^2.5.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.2",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/set-array": "^1.0.1",
+        "@jridgewell/sourcemap-codec": "^1.4.10",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets": {
+      "version": "7.20.7",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/compat-data": "^7.20.5",
+        "@babel/helper-validator-option": "^7.18.6",
+        "browserslist": "^4.21.3",
+        "lru-cache": "^5.1.1",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
+      "version": "5.1.1",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "yallist": "^3.0.2"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
+      "version": "6.3.0",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
+      "version": "3.1.1",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/@babel/helper-environment-visitor": {
+      "version": "7.18.9",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-function-name": {
+      "version": "7.19.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/template": "^7.18.10",
+        "@babel/types": "^7.19.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-hoist-variables": {
+      "version": "7.18.6",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-imports": {
+      "version": "7.18.6",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-transforms": {
+      "version": "7.20.11",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-module-imports": "^7.18.6",
+        "@babel/helper-simple-access": "^7.20.2",
+        "@babel/helper-split-export-declaration": "^7.18.6",
+        "@babel/helper-validator-identifier": "^7.19.1",
+        "@babel/template": "^7.20.7",
+        "@babel/traverse": "^7.20.10",
+        "@babel/types": "^7.20.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-plugin-utils": {
+      "version": "7.20.2",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-simple-access": {
+      "version": "7.20.2",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.20.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-split-export-declaration": {
+      "version": "7.18.6",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-string-parser": {
+      "version": "7.19.4",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.19.1",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-option": {
+      "version": "7.18.6",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helpers": {
+      "version": "7.20.13",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/template": "^7.20.7",
+        "@babel/traverse": "^7.20.13",
+        "@babel/types": "^7.20.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/highlight": {
+      "version": "7.18.6",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.18.6",
+        "chalk": "^2.0.0",
+        "js-tokens": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/chalk": {
+      "version": "2.4.2",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/color-convert": {
+      "version": "1.9.3",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/color-name": {
+      "version": "1.1.3",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@babel/highlight/node_modules/has-flag": {
+      "version": "3.0.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/supports-color": {
+      "version": "5.5.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/parser": {
+      "version": "7.20.15",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-async-generators": {
+      "version": "7.8.4",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-bigint": {
+      "version": "7.8.3",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-class-properties": {
+      "version": "7.12.13",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.12.13"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-import-meta": {
+      "version": "7.10.4",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-json-strings": {
+      "version": "7.8.3",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-jsx": {
+      "version": "7.18.6",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-logical-assignment-operators": {
+      "version": "7.10.4",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": {
+      "version": "7.8.3",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-numeric-separator": {
+      "version": "7.10.4",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-object-rest-spread": {
+      "version": "7.8.3",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-optional-catch-binding": {
+      "version": "7.8.3",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-optional-chaining": {
+      "version": "7.8.3",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-top-level-await": {
+      "version": "7.14.5",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.14.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-typescript": {
+      "version": "7.20.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.19.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/runtime": {
+      "version": "7.20.13",
+      "license": "MIT",
+      "dependencies": {
+        "regenerator-runtime": "^0.13.11"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/template": {
+      "version": "7.20.7",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.18.6",
+        "@babel/parser": "^7.20.7",
+        "@babel/types": "^7.20.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/traverse": {
+      "version": "7.20.13",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.18.6",
+        "@babel/generator": "^7.20.7",
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-function-name": "^7.19.0",
+        "@babel/helper-hoist-variables": "^7.18.6",
+        "@babel/helper-split-export-declaration": "^7.18.6",
+        "@babel/parser": "^7.20.13",
+        "@babel/types": "^7.20.7",
+        "debug": "^4.1.0",
+        "globals": "^11.1.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/types": {
+      "version": "7.20.7",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-string-parser": "^7.19.4",
+        "@babel/helper-validator-identifier": "^7.19.1",
+        "to-fast-properties": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@bcoe/v8-coverage": {
+      "version": "0.2.3",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@certusone/wormhole-sdk": {
+      "version": "0.10.10",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@certusone/wormhole-sdk-proto-web": "0.0.7",
+        "@certusone/wormhole-sdk-wasm": "^0.0.1",
+        "@coral-xyz/borsh": "0.2.6",
+        "@mysten/sui.js": "0.32.2",
+        "@project-serum/anchor": "^0.25.0",
+        "@solana/spl-token": "^0.3.5",
+        "@solana/web3.js": "^1.66.2",
+        "@terra-money/terra.js": "3.1.9",
+        "@xpla/xpla.js": "^0.2.1",
+        "algosdk": "^2.4.0",
+        "aptos": "1.5.0",
+        "axios": "^0.24.0",
+        "bech32": "^2.0.0",
+        "binary-parser": "^2.2.1",
+        "bs58": "^4.0.1",
+        "elliptic": "^6.5.4",
+        "js-base64": "^3.6.1",
+        "near-api-js": "^1.0.0"
+      },
+      "optionalDependencies": {
+        "@injectivelabs/networks": "1.10.12",
+        "@injectivelabs/sdk-ts": "1.10.72",
+        "@injectivelabs/utils": "1.10.12"
+      }
+    },
+    "node_modules/@certusone/wormhole-sdk-proto-web": {
+      "version": "0.0.7",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@improbable-eng/grpc-web": "^0.15.0",
+        "protobufjs": "^7.0.0",
+        "rxjs": "^7.5.6"
+      }
+    },
+    "node_modules/@certusone/wormhole-sdk-proto-web/node_modules/long": {
+      "version": "5.2.3",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@certusone/wormhole-sdk-proto-web/node_modules/protobufjs": {
+      "version": "7.2.6",
+      "hasInstallScript": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.2",
+        "@protobufjs/base64": "^1.1.2",
+        "@protobufjs/codegen": "^2.0.4",
+        "@protobufjs/eventemitter": "^1.1.0",
+        "@protobufjs/fetch": "^1.1.0",
+        "@protobufjs/float": "^1.0.2",
+        "@protobufjs/inquire": "^1.1.0",
+        "@protobufjs/path": "^1.1.2",
+        "@protobufjs/pool": "^1.1.0",
+        "@protobufjs/utf8": "^1.1.0",
+        "@types/node": ">=13.7.0",
+        "long": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/@certusone/wormhole-sdk-proto-web/node_modules/rxjs": {
+      "version": "7.8.1",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@certusone/wormhole-sdk-wasm": {
+      "version": "0.0.1",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@types/long": "^4.0.2",
+        "@types/node": "^18.0.3"
+      }
+    },
+    "node_modules/@certusone/wormhole-sdk/node_modules/axios": {
+      "version": "0.24.0",
+      "license": "MIT",
+      "dependencies": {
+        "follow-redirects": "^1.14.4"
+      }
+    },
+    "node_modules/@certusone/wormhole-sdk/node_modules/bech32": {
+      "version": "2.0.0",
+      "license": "MIT"
+    },
+    "node_modules/@classic-terra/terra.proto": {
+      "version": "1.1.0",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@improbable-eng/grpc-web": "^0.14.1",
+        "google-protobuf": "^3.17.3",
+        "long": "^4.0.0",
+        "protobufjs": "~6.11.2"
+      }
+    },
+    "node_modules/@classic-terra/terra.proto/node_modules/@improbable-eng/grpc-web": {
+      "version": "0.14.1",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "browser-headers": "^0.4.1"
+      },
+      "peerDependencies": {
+        "google-protobuf": "^3.14.0"
+      }
+    },
+    "node_modules/@confio/ics23": {
+      "version": "0.6.8",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@noble/hashes": "^1.0.0",
+        "protobufjs": "^6.8.8"
+      }
+    },
+    "node_modules/@coral-xyz/borsh": {
+      "version": "0.2.6",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "bn.js": "^5.1.2",
+        "buffer-layout": "^1.2.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "@solana/web3.js": "^1.2.0"
+      }
+    },
+    "node_modules/@cosmjs/amino": {
+      "version": "0.29.5",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/crypto": "^0.29.5",
+        "@cosmjs/encoding": "^0.29.5",
+        "@cosmjs/math": "^0.29.5",
+        "@cosmjs/utils": "^0.29.5"
+      }
+    },
+    "node_modules/@cosmjs/cli": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/amino": "0.28.13",
+        "@cosmjs/cosmwasm-stargate": "0.28.13",
+        "@cosmjs/crypto": "0.28.13",
+        "@cosmjs/encoding": "0.28.13",
+        "@cosmjs/faucet-client": "0.28.13",
+        "@cosmjs/math": "0.28.13",
+        "@cosmjs/proto-signing": "0.28.13",
+        "@cosmjs/stargate": "0.28.13",
+        "@cosmjs/tendermint-rpc": "0.28.13",
+        "@cosmjs/utils": "0.28.13",
+        "axios": "^0.21.2",
+        "babylon": "^6.18.0",
+        "chalk": "^4",
+        "cosmjs-types": "^0.4.0",
+        "diff": "^4",
+        "recast": "^0.20",
+        "ts-node": "^8",
+        "typescript": "~4.4",
+        "yargs": "^15.3.1"
+      },
+      "bin": {
+        "cosmjs-cli": "bin/cosmjs-cli"
+      }
+    },
+    "node_modules/@cosmjs/cli/node_modules/@cosmjs/amino": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/crypto": "0.28.13",
+        "@cosmjs/encoding": "0.28.13",
+        "@cosmjs/math": "0.28.13",
+        "@cosmjs/utils": "0.28.13"
+      }
+    },
+    "node_modules/@cosmjs/cli/node_modules/@cosmjs/cosmwasm-stargate": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/amino": "0.28.13",
+        "@cosmjs/crypto": "0.28.13",
+        "@cosmjs/encoding": "0.28.13",
+        "@cosmjs/math": "0.28.13",
+        "@cosmjs/proto-signing": "0.28.13",
+        "@cosmjs/stargate": "0.28.13",
+        "@cosmjs/tendermint-rpc": "0.28.13",
+        "@cosmjs/utils": "0.28.13",
+        "cosmjs-types": "^0.4.0",
+        "long": "^4.0.0",
+        "pako": "^2.0.2"
+      }
+    },
+    "node_modules/@cosmjs/cli/node_modules/@cosmjs/crypto": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/encoding": "0.28.13",
+        "@cosmjs/math": "0.28.13",
+        "@cosmjs/utils": "0.28.13",
+        "@noble/hashes": "^1",
+        "bn.js": "^5.2.0",
+        "elliptic": "^6.5.3",
+        "libsodium-wrappers": "^0.7.6"
+      }
+    },
+    "node_modules/@cosmjs/cli/node_modules/@cosmjs/encoding": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "base64-js": "^1.3.0",
+        "bech32": "^1.1.4",
+        "readonly-date": "^1.0.0"
+      }
+    },
+    "node_modules/@cosmjs/cli/node_modules/@cosmjs/json-rpc": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/stream": "0.28.13",
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/@cosmjs/cli/node_modules/@cosmjs/math": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "bn.js": "^5.2.0"
+      }
+    },
+    "node_modules/@cosmjs/cli/node_modules/@cosmjs/proto-signing": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/amino": "0.28.13",
+        "@cosmjs/crypto": "0.28.13",
+        "@cosmjs/encoding": "0.28.13",
+        "@cosmjs/math": "0.28.13",
+        "@cosmjs/utils": "0.28.13",
+        "cosmjs-types": "^0.4.0",
+        "long": "^4.0.0"
+      }
+    },
+    "node_modules/@cosmjs/cli/node_modules/@cosmjs/socket": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/stream": "0.28.13",
+        "isomorphic-ws": "^4.0.1",
+        "ws": "^7",
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/@cosmjs/cli/node_modules/@cosmjs/stargate": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@confio/ics23": "^0.6.8",
+        "@cosmjs/amino": "0.28.13",
+        "@cosmjs/encoding": "0.28.13",
+        "@cosmjs/math": "0.28.13",
+        "@cosmjs/proto-signing": "0.28.13",
+        "@cosmjs/stream": "0.28.13",
+        "@cosmjs/tendermint-rpc": "0.28.13",
+        "@cosmjs/utils": "0.28.13",
+        "cosmjs-types": "^0.4.0",
+        "long": "^4.0.0",
+        "protobufjs": "~6.11.3",
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/@cosmjs/cli/node_modules/@cosmjs/stream": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/@cosmjs/cli/node_modules/@cosmjs/tendermint-rpc": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/crypto": "0.28.13",
+        "@cosmjs/encoding": "0.28.13",
+        "@cosmjs/json-rpc": "0.28.13",
+        "@cosmjs/math": "0.28.13",
+        "@cosmjs/socket": "0.28.13",
+        "@cosmjs/stream": "0.28.13",
+        "@cosmjs/utils": "0.28.13",
+        "axios": "^0.21.2",
+        "readonly-date": "^1.0.0",
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/@cosmjs/cli/node_modules/@cosmjs/utils": {
+      "version": "0.28.13",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@cosmjs/cli/node_modules/cliui": {
+      "version": "6.0.0",
+      "license": "ISC",
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^6.2.0"
+      }
+    },
+    "node_modules/@cosmjs/cli/node_modules/cosmjs-types": {
+      "version": "0.4.1",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "long": "^4.0.0",
+        "protobufjs": "~6.11.2"
+      }
+    },
+    "node_modules/@cosmjs/cli/node_modules/ts-node": {
+      "version": "8.10.2",
+      "license": "MIT",
+      "dependencies": {
+        "arg": "^4.1.0",
+        "diff": "^4.0.1",
+        "make-error": "^1.1.1",
+        "source-map-support": "^0.5.17",
+        "yn": "3.1.1"
+      },
+      "bin": {
+        "ts-node": "dist/bin.js",
+        "ts-node-script": "dist/bin-script.js",
+        "ts-node-transpile-only": "dist/bin-transpile.js",
+        "ts-script": "dist/bin-script-deprecated.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      },
+      "peerDependencies": {
+        "typescript": ">=2.7"
+      }
+    },
+    "node_modules/@cosmjs/cli/node_modules/typescript": {
+      "version": "4.4.4",
+      "license": "Apache-2.0",
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=4.2.0"
+      }
+    },
+    "node_modules/@cosmjs/cli/node_modules/wrap-ansi": {
+      "version": "6.2.0",
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@cosmjs/cli/node_modules/y18n": {
+      "version": "4.0.3",
+      "license": "ISC"
+    },
+    "node_modules/@cosmjs/cli/node_modules/yargs": {
+      "version": "15.4.1",
+      "license": "MIT",
+      "dependencies": {
+        "cliui": "^6.0.0",
+        "decamelize": "^1.2.0",
+        "find-up": "^4.1.0",
+        "get-caller-file": "^2.0.1",
+        "require-directory": "^2.1.1",
+        "require-main-filename": "^2.0.0",
+        "set-blocking": "^2.0.0",
+        "string-width": "^4.2.0",
+        "which-module": "^2.0.0",
+        "y18n": "^4.0.0",
+        "yargs-parser": "^18.1.2"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@cosmjs/cli/node_modules/yargs-parser": {
+      "version": "18.1.3",
+      "license": "ISC",
+      "dependencies": {
+        "camelcase": "^5.0.0",
+        "decamelize": "^1.2.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@cosmjs/cosmwasm-stargate": {
+      "version": "0.29.5",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/amino": "^0.29.5",
+        "@cosmjs/crypto": "^0.29.5",
+        "@cosmjs/encoding": "^0.29.5",
+        "@cosmjs/math": "^0.29.5",
+        "@cosmjs/proto-signing": "^0.29.5",
+        "@cosmjs/stargate": "^0.29.5",
+        "@cosmjs/tendermint-rpc": "^0.29.5",
+        "@cosmjs/utils": "^0.29.5",
+        "cosmjs-types": "^0.5.2",
+        "long": "^4.0.0",
+        "pako": "^2.0.2"
+      }
+    },
+    "node_modules/@cosmjs/crypto": {
+      "version": "0.29.5",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/encoding": "^0.29.5",
+        "@cosmjs/math": "^0.29.5",
+        "@cosmjs/utils": "^0.29.5",
+        "@noble/hashes": "^1",
+        "bn.js": "^5.2.0",
+        "elliptic": "^6.5.4",
+        "libsodium-wrappers": "^0.7.6"
+      }
+    },
+    "node_modules/@cosmjs/encoding": {
+      "version": "0.29.5",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "base64-js": "^1.3.0",
+        "bech32": "^1.1.4",
+        "readonly-date": "^1.0.0"
+      }
+    },
+    "node_modules/@cosmjs/faucet-client": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "axios": "^0.21.2"
+      }
+    },
+    "node_modules/@cosmjs/json-rpc": {
+      "version": "0.29.5",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/stream": "^0.29.5",
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/@cosmjs/ledger-amino": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/amino": "0.28.13",
+        "@cosmjs/crypto": "0.28.13",
+        "@cosmjs/encoding": "0.28.13",
+        "@cosmjs/math": "0.28.13",
+        "@cosmjs/utils": "0.28.13",
+        "ledger-cosmos-js": "^2.1.8",
+        "semver": "^7.3.2"
+      }
+    },
+    "node_modules/@cosmjs/ledger-amino/node_modules/@cosmjs/amino": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/crypto": "0.28.13",
+        "@cosmjs/encoding": "0.28.13",
+        "@cosmjs/math": "0.28.13",
+        "@cosmjs/utils": "0.28.13"
+      }
+    },
+    "node_modules/@cosmjs/ledger-amino/node_modules/@cosmjs/crypto": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/encoding": "0.28.13",
+        "@cosmjs/math": "0.28.13",
+        "@cosmjs/utils": "0.28.13",
+        "@noble/hashes": "^1",
+        "bn.js": "^5.2.0",
+        "elliptic": "^6.5.3",
+        "libsodium-wrappers": "^0.7.6"
+      }
+    },
+    "node_modules/@cosmjs/ledger-amino/node_modules/@cosmjs/encoding": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "base64-js": "^1.3.0",
+        "bech32": "^1.1.4",
+        "readonly-date": "^1.0.0"
+      }
+    },
+    "node_modules/@cosmjs/ledger-amino/node_modules/@cosmjs/math": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "bn.js": "^5.2.0"
+      }
+    },
+    "node_modules/@cosmjs/ledger-amino/node_modules/@cosmjs/utils": {
+      "version": "0.28.13",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@cosmjs/math": {
+      "version": "0.29.5",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "bn.js": "^5.2.0"
+      }
+    },
+    "node_modules/@cosmjs/proto-signing": {
+      "version": "0.29.5",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/amino": "^0.29.5",
+        "@cosmjs/crypto": "^0.29.5",
+        "@cosmjs/encoding": "^0.29.5",
+        "@cosmjs/math": "^0.29.5",
+        "@cosmjs/utils": "^0.29.5",
+        "cosmjs-types": "^0.5.2",
+        "long": "^4.0.0"
+      }
+    },
+    "node_modules/@cosmjs/socket": {
+      "version": "0.29.5",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/stream": "^0.29.5",
+        "isomorphic-ws": "^4.0.1",
+        "ws": "^7",
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/@cosmjs/stargate": {
+      "version": "0.29.5",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@confio/ics23": "^0.6.8",
+        "@cosmjs/amino": "^0.29.5",
+        "@cosmjs/encoding": "^0.29.5",
+        "@cosmjs/math": "^0.29.5",
+        "@cosmjs/proto-signing": "^0.29.5",
+        "@cosmjs/stream": "^0.29.5",
+        "@cosmjs/tendermint-rpc": "^0.29.5",
+        "@cosmjs/utils": "^0.29.5",
+        "cosmjs-types": "^0.5.2",
+        "long": "^4.0.0",
+        "protobufjs": "~6.11.3",
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/@cosmjs/stream": {
+      "version": "0.29.5",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/@cosmjs/tendermint-rpc": {
+      "version": "0.29.5",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/crypto": "^0.29.5",
+        "@cosmjs/encoding": "^0.29.5",
+        "@cosmjs/json-rpc": "^0.29.5",
+        "@cosmjs/math": "^0.29.5",
+        "@cosmjs/socket": "^0.29.5",
+        "@cosmjs/stream": "^0.29.5",
+        "@cosmjs/utils": "^0.29.5",
+        "axios": "^0.21.2",
+        "readonly-date": "^1.0.0",
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/@cosmjs/utils": {
+      "version": "0.29.5",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@cspotcode/source-map-support": {
+      "version": "0.8.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/trace-mapping": "0.3.9"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@ethereumjs/common": {
+      "version": "2.6.5",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "crc-32": "^1.2.0",
+        "ethereumjs-util": "^7.1.5"
+      }
+    },
+    "node_modules/@ethereumjs/tx": {
+      "version": "3.5.2",
+      "license": "MPL-2.0",
+      "optional": true,
+      "dependencies": {
+        "@ethereumjs/common": "^2.6.4",
+        "ethereumjs-util": "^7.1.5"
+      }
+    },
+    "node_modules/@ethersproject/abi": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/address": "^5.7.0",
+        "@ethersproject/bignumber": "^5.7.0",
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/constants": "^5.7.0",
+        "@ethersproject/hash": "^5.7.0",
+        "@ethersproject/keccak256": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0",
+        "@ethersproject/properties": "^5.7.0",
+        "@ethersproject/strings": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/abstract-provider": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/bignumber": "^5.7.0",
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0",
+        "@ethersproject/networks": "^5.7.0",
+        "@ethersproject/properties": "^5.7.0",
+        "@ethersproject/transactions": "^5.7.0",
+        "@ethersproject/web": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/abstract-signer": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/abstract-provider": "^5.7.0",
+        "@ethersproject/bignumber": "^5.7.0",
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0",
+        "@ethersproject/properties": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/address": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/bignumber": "^5.7.0",
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/keccak256": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0",
+        "@ethersproject/rlp": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/base64": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/bytes": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/basex": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/properties": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/bignumber": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0",
+        "bn.js": "^5.2.1"
+      }
+    },
+    "node_modules/@ethersproject/bytes": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/logger": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/constants": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/bignumber": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/contracts": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/abi": "^5.7.0",
+        "@ethersproject/abstract-provider": "^5.7.0",
+        "@ethersproject/abstract-signer": "^5.7.0",
+        "@ethersproject/address": "^5.7.0",
+        "@ethersproject/bignumber": "^5.7.0",
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/constants": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0",
+        "@ethersproject/properties": "^5.7.0",
+        "@ethersproject/transactions": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/hash": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/abstract-signer": "^5.7.0",
+        "@ethersproject/address": "^5.7.0",
+        "@ethersproject/base64": "^5.7.0",
+        "@ethersproject/bignumber": "^5.7.0",
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/keccak256": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0",
+        "@ethersproject/properties": "^5.7.0",
+        "@ethersproject/strings": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/hdnode": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/abstract-signer": "^5.7.0",
+        "@ethersproject/basex": "^5.7.0",
+        "@ethersproject/bignumber": "^5.7.0",
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0",
+        "@ethersproject/pbkdf2": "^5.7.0",
+        "@ethersproject/properties": "^5.7.0",
+        "@ethersproject/sha2": "^5.7.0",
+        "@ethersproject/signing-key": "^5.7.0",
+        "@ethersproject/strings": "^5.7.0",
+        "@ethersproject/transactions": "^5.7.0",
+        "@ethersproject/wordlists": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/json-wallets": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/abstract-signer": "^5.7.0",
+        "@ethersproject/address": "^5.7.0",
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/hdnode": "^5.7.0",
+        "@ethersproject/keccak256": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0",
+        "@ethersproject/pbkdf2": "^5.7.0",
+        "@ethersproject/properties": "^5.7.0",
+        "@ethersproject/random": "^5.7.0",
+        "@ethersproject/strings": "^5.7.0",
+        "@ethersproject/transactions": "^5.7.0",
+        "aes-js": "3.0.0",
+        "scrypt-js": "3.0.1"
+      }
+    },
+    "node_modules/@ethersproject/keccak256": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/bytes": "^5.7.0",
+        "js-sha3": "0.8.0"
+      }
+    },
+    "node_modules/@ethersproject/logger": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/@ethersproject/networks": {
+      "version": "5.7.1",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/logger": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/pbkdf2": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/sha2": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/properties": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/logger": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/providers": {
+      "version": "5.7.2",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/abstract-provider": "^5.7.0",
+        "@ethersproject/abstract-signer": "^5.7.0",
+        "@ethersproject/address": "^5.7.0",
+        "@ethersproject/base64": "^5.7.0",
+        "@ethersproject/basex": "^5.7.0",
+        "@ethersproject/bignumber": "^5.7.0",
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/constants": "^5.7.0",
+        "@ethersproject/hash": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0",
+        "@ethersproject/networks": "^5.7.0",
+        "@ethersproject/properties": "^5.7.0",
+        "@ethersproject/random": "^5.7.0",
+        "@ethersproject/rlp": "^5.7.0",
+        "@ethersproject/sha2": "^5.7.0",
+        "@ethersproject/strings": "^5.7.0",
+        "@ethersproject/transactions": "^5.7.0",
+        "@ethersproject/web": "^5.7.0",
+        "bech32": "1.1.4",
+        "ws": "7.4.6"
+      }
+    },
+    "node_modules/@ethersproject/providers/node_modules/ws": {
+      "version": "7.4.6",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.3.0"
+      },
+      "peerDependencies": {
+        "bufferutil": "^4.0.1",
+        "utf-8-validate": "^5.0.2"
+      },
+      "peerDependenciesMeta": {
+        "bufferutil": {
+          "optional": true
+        },
+        "utf-8-validate": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@ethersproject/random": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/rlp": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/sha2": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0",
+        "hash.js": "1.1.7"
+      }
+    },
+    "node_modules/@ethersproject/signing-key": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0",
+        "@ethersproject/properties": "^5.7.0",
+        "bn.js": "^5.2.1",
+        "elliptic": "6.5.4",
+        "hash.js": "1.1.7"
+      }
+    },
+    "node_modules/@ethersproject/solidity": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/bignumber": "^5.7.0",
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/keccak256": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0",
+        "@ethersproject/sha2": "^5.7.0",
+        "@ethersproject/strings": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/strings": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/constants": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/transactions": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/address": "^5.7.0",
+        "@ethersproject/bignumber": "^5.7.0",
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/constants": "^5.7.0",
+        "@ethersproject/keccak256": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0",
+        "@ethersproject/properties": "^5.7.0",
+        "@ethersproject/rlp": "^5.7.0",
+        "@ethersproject/signing-key": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/units": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/bignumber": "^5.7.0",
+        "@ethersproject/constants": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/wallet": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/abstract-provider": "^5.7.0",
+        "@ethersproject/abstract-signer": "^5.7.0",
+        "@ethersproject/address": "^5.7.0",
+        "@ethersproject/bignumber": "^5.7.0",
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/hash": "^5.7.0",
+        "@ethersproject/hdnode": "^5.7.0",
+        "@ethersproject/json-wallets": "^5.7.0",
+        "@ethersproject/keccak256": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0",
+        "@ethersproject/properties": "^5.7.0",
+        "@ethersproject/random": "^5.7.0",
+        "@ethersproject/signing-key": "^5.7.0",
+        "@ethersproject/transactions": "^5.7.0",
+        "@ethersproject/wordlists": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/web": {
+      "version": "5.7.1",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/base64": "^5.7.0",
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0",
+        "@ethersproject/properties": "^5.7.0",
+        "@ethersproject/strings": "^5.7.0"
+      }
+    },
+    "node_modules/@ethersproject/wordlists": {
+      "version": "5.7.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/bytes": "^5.7.0",
+        "@ethersproject/hash": "^5.7.0",
+        "@ethersproject/logger": "^5.7.0",
+        "@ethersproject/properties": "^5.7.0",
+        "@ethersproject/strings": "^5.7.0"
+      }
+    },
+    "node_modules/@graphql-typed-document-node/core": {
+      "version": "3.2.0",
+      "license": "MIT",
+      "optional": true,
+      "peerDependencies": {
+        "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
+      }
+    },
+    "node_modules/@improbable-eng/grpc-web": {
+      "version": "0.15.0",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "browser-headers": "^0.4.1"
+      },
+      "peerDependencies": {
+        "google-protobuf": "^3.14.0"
+      }
+    },
+    "node_modules/@improbable-eng/grpc-web-node-http-transport": {
+      "version": "0.15.0",
+      "license": "Apache-2.0",
+      "peerDependencies": {
+        "@improbable-eng/grpc-web": ">=0.13.0"
+      }
+    },
+    "node_modules/@injectivelabs/core-proto-ts": {
+      "version": "0.0.14",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@injectivelabs/grpc-web": "^0.0.1",
+        "google-protobuf": "^3.14.0",
+        "protobufjs": "^7.0.0",
+        "rxjs": "^7.4.0"
+      }
+    },
+    "node_modules/@injectivelabs/core-proto-ts/node_modules/long": {
+      "version": "5.2.3",
+      "license": "Apache-2.0",
+      "optional": true
+    },
+    "node_modules/@injectivelabs/core-proto-ts/node_modules/protobufjs": {
+      "version": "7.2.6",
+      "hasInstallScript": true,
+      "license": "BSD-3-Clause",
+      "optional": true,
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.2",
+        "@protobufjs/base64": "^1.1.2",
+        "@protobufjs/codegen": "^2.0.4",
+        "@protobufjs/eventemitter": "^1.1.0",
+        "@protobufjs/fetch": "^1.1.0",
+        "@protobufjs/float": "^1.0.2",
+        "@protobufjs/inquire": "^1.1.0",
+        "@protobufjs/path": "^1.1.2",
+        "@protobufjs/pool": "^1.1.0",
+        "@protobufjs/utf8": "^1.1.0",
+        "@types/node": ">=13.7.0",
+        "long": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/@injectivelabs/core-proto-ts/node_modules/rxjs": {
+      "version": "7.8.1",
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@injectivelabs/exceptions": {
+      "version": "1.14.5",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "@injectivelabs/grpc-web": "^0.0.1",
+        "@injectivelabs/ts-types": "^1.14.5",
+        "http-status-codes": "^2.2.0",
+        "link-module-alias": "^1.2.0",
+        "shx": "^0.3.2"
+      }
+    },
+    "node_modules/@injectivelabs/grpc-web": {
+      "version": "0.0.1",
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "browser-headers": "^0.4.1"
+      },
+      "peerDependencies": {
+        "google-protobuf": "^3.14.0"
+      }
+    },
+    "node_modules/@injectivelabs/grpc-web-node-http-transport": {
+      "version": "0.0.2",
+      "license": "Apache-2.0",
+      "optional": true,
+      "peerDependencies": {
+        "@injectivelabs/grpc-web": ">=0.0.1"
+      }
+    },
+    "node_modules/@injectivelabs/grpc-web-react-native-transport": {
+      "version": "0.0.2",
+      "license": "Apache-2.0",
+      "optional": true,
+      "peerDependencies": {
+        "@injectivelabs/grpc-web": ">=0.0.1"
+      }
+    },
+    "node_modules/@injectivelabs/indexer-proto-ts": {
+      "version": "1.10.8-rc.4",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@injectivelabs/grpc-web": "^0.0.1",
+        "google-protobuf": "^3.14.0",
+        "protobufjs": "^7.0.0",
+        "rxjs": "^7.4.0"
+      }
+    },
+    "node_modules/@injectivelabs/indexer-proto-ts/node_modules/long": {
+      "version": "5.2.3",
+      "license": "Apache-2.0",
+      "optional": true
+    },
+    "node_modules/@injectivelabs/indexer-proto-ts/node_modules/protobufjs": {
+      "version": "7.2.6",
+      "hasInstallScript": true,
+      "license": "BSD-3-Clause",
+      "optional": true,
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.2",
+        "@protobufjs/base64": "^1.1.2",
+        "@protobufjs/codegen": "^2.0.4",
+        "@protobufjs/eventemitter": "^1.1.0",
+        "@protobufjs/fetch": "^1.1.0",
+        "@protobufjs/float": "^1.0.2",
+        "@protobufjs/inquire": "^1.1.0",
+        "@protobufjs/path": "^1.1.2",
+        "@protobufjs/pool": "^1.1.0",
+        "@protobufjs/utf8": "^1.1.0",
+        "@types/node": ">=13.7.0",
+        "long": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/@injectivelabs/indexer-proto-ts/node_modules/rxjs": {
+      "version": "7.8.1",
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@injectivelabs/mito-proto-ts": {
+      "version": "1.0.9",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@injectivelabs/grpc-web": "^0.0.1",
+        "google-protobuf": "^3.14.0",
+        "protobufjs": "^7.0.0",
+        "rxjs": "^7.4.0"
+      }
+    },
+    "node_modules/@injectivelabs/mito-proto-ts/node_modules/long": {
+      "version": "5.2.3",
+      "license": "Apache-2.0",
+      "optional": true
+    },
+    "node_modules/@injectivelabs/mito-proto-ts/node_modules/protobufjs": {
+      "version": "7.2.6",
+      "hasInstallScript": true,
+      "license": "BSD-3-Clause",
+      "optional": true,
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.2",
+        "@protobufjs/base64": "^1.1.2",
+        "@protobufjs/codegen": "^2.0.4",
+        "@protobufjs/eventemitter": "^1.1.0",
+        "@protobufjs/fetch": "^1.1.0",
+        "@protobufjs/float": "^1.0.2",
+        "@protobufjs/inquire": "^1.1.0",
+        "@protobufjs/path": "^1.1.2",
+        "@protobufjs/pool": "^1.1.0",
+        "@protobufjs/utf8": "^1.1.0",
+        "@types/node": ">=13.7.0",
+        "long": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/@injectivelabs/mito-proto-ts/node_modules/rxjs": {
+      "version": "7.8.1",
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@injectivelabs/networks": {
+      "version": "1.10.12",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "@injectivelabs/exceptions": "^1.10.12",
+        "@injectivelabs/ts-types": "^1.10.12",
+        "@injectivelabs/utils": "^1.10.12",
+        "link-module-alias": "^1.2.0",
+        "shx": "^0.3.2"
+      }
+    },
+    "node_modules/@injectivelabs/sdk-ts": {
+      "version": "1.10.72",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "@apollo/client": "^3.5.8",
+        "@cosmjs/amino": "^0.30.1",
+        "@cosmjs/proto-signing": "^0.30.1",
+        "@cosmjs/stargate": "^0.30.1",
+        "@ethersproject/bytes": "^5.7.0",
+        "@injectivelabs/core-proto-ts": "^0.0.14",
+        "@injectivelabs/exceptions": "^1.10.12",
+        "@injectivelabs/grpc-web": "^0.0.1",
+        "@injectivelabs/grpc-web-node-http-transport": "^0.0.2",
+        "@injectivelabs/grpc-web-react-native-transport": "^0.0.2",
+        "@injectivelabs/indexer-proto-ts": "1.10.8-rc.4",
+        "@injectivelabs/mito-proto-ts": "1.0.9",
+        "@injectivelabs/networks": "^1.10.12",
+        "@injectivelabs/test-utils": "^1.10.12",
+        "@injectivelabs/token-metadata": "^1.10.42",
+        "@injectivelabs/ts-types": "^1.10.12",
+        "@injectivelabs/utils": "^1.10.12",
+        "@metamask/eth-sig-util": "^4.0.0",
+        "axios": "^0.27.2",
+        "bech32": "^2.0.0",
+        "bip39": "^3.0.4",
+        "cosmjs-types": "^0.7.1",
+        "eth-crypto": "^2.6.0",
+        "ethereumjs-util": "^7.1.4",
+        "ethers": "^5.7.2",
+        "google-protobuf": "^3.21.0",
+        "graphql": "^16.3.0",
+        "http-status-codes": "^2.2.0",
+        "js-sha3": "^0.8.0",
+        "jscrypto": "^1.0.3",
+        "keccak256": "^1.0.6",
+        "link-module-alias": "^1.2.0",
+        "rxjs": "^7.8.0",
+        "secp256k1": "^4.0.3",
+        "shx": "^0.3.2",
+        "snakecase-keys": "^5.4.1"
+      }
+    },
+    "node_modules/@injectivelabs/sdk-ts/node_modules/@cosmjs/amino": {
+      "version": "0.30.1",
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "@cosmjs/crypto": "^0.30.1",
+        "@cosmjs/encoding": "^0.30.1",
+        "@cosmjs/math": "^0.30.1",
+        "@cosmjs/utils": "^0.30.1"
+      }
+    },
+    "node_modules/@injectivelabs/sdk-ts/node_modules/@cosmjs/crypto": {
+      "version": "0.30.1",
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "@cosmjs/encoding": "^0.30.1",
+        "@cosmjs/math": "^0.30.1",
+        "@cosmjs/utils": "^0.30.1",
+        "@noble/hashes": "^1",
+        "bn.js": "^5.2.0",
+        "elliptic": "^6.5.4",
+        "libsodium-wrappers": "^0.7.6"
+      }
+    },
+    "node_modules/@injectivelabs/sdk-ts/node_modules/@cosmjs/encoding": {
+      "version": "0.30.1",
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "base64-js": "^1.3.0",
+        "bech32": "^1.1.4",
+        "readonly-date": "^1.0.0"
+      }
+    },
+    "node_modules/@injectivelabs/sdk-ts/node_modules/@cosmjs/encoding/node_modules/bech32": {
+      "version": "1.1.4",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/@injectivelabs/sdk-ts/node_modules/@cosmjs/json-rpc": {
+      "version": "0.30.1",
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "@cosmjs/stream": "^0.30.1",
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/@injectivelabs/sdk-ts/node_modules/@cosmjs/math": {
+      "version": "0.30.1",
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "bn.js": "^5.2.0"
+      }
+    },
+    "node_modules/@injectivelabs/sdk-ts/node_modules/@cosmjs/proto-signing": {
+      "version": "0.30.1",
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "@cosmjs/amino": "^0.30.1",
+        "@cosmjs/crypto": "^0.30.1",
+        "@cosmjs/encoding": "^0.30.1",
+        "@cosmjs/math": "^0.30.1",
+        "@cosmjs/utils": "^0.30.1",
+        "cosmjs-types": "^0.7.1",
+        "long": "^4.0.0"
+      }
+    },
+    "node_modules/@injectivelabs/sdk-ts/node_modules/@cosmjs/socket": {
+      "version": "0.30.1",
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "@cosmjs/stream": "^0.30.1",
+        "isomorphic-ws": "^4.0.1",
+        "ws": "^7",
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/@injectivelabs/sdk-ts/node_modules/@cosmjs/stargate": {
+      "version": "0.30.1",
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "@confio/ics23": "^0.6.8",
+        "@cosmjs/amino": "^0.30.1",
+        "@cosmjs/encoding": "^0.30.1",
+        "@cosmjs/math": "^0.30.1",
+        "@cosmjs/proto-signing": "^0.30.1",
+        "@cosmjs/stream": "^0.30.1",
+        "@cosmjs/tendermint-rpc": "^0.30.1",
+        "@cosmjs/utils": "^0.30.1",
+        "cosmjs-types": "^0.7.1",
+        "long": "^4.0.0",
+        "protobufjs": "~6.11.3",
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/@injectivelabs/sdk-ts/node_modules/@cosmjs/stream": {
+      "version": "0.30.1",
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/@injectivelabs/sdk-ts/node_modules/@cosmjs/tendermint-rpc": {
+      "version": "0.30.1",
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "@cosmjs/crypto": "^0.30.1",
+        "@cosmjs/encoding": "^0.30.1",
+        "@cosmjs/json-rpc": "^0.30.1",
+        "@cosmjs/math": "^0.30.1",
+        "@cosmjs/socket": "^0.30.1",
+        "@cosmjs/stream": "^0.30.1",
+        "@cosmjs/utils": "^0.30.1",
+        "axios": "^0.21.2",
+        "readonly-date": "^1.0.0",
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/@injectivelabs/sdk-ts/node_modules/@cosmjs/tendermint-rpc/node_modules/axios": {
+      "version": "0.21.4",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "follow-redirects": "^1.14.0"
+      }
+    },
+    "node_modules/@injectivelabs/sdk-ts/node_modules/@cosmjs/utils": {
+      "version": "0.30.1",
+      "license": "Apache-2.0",
+      "optional": true
+    },
+    "node_modules/@injectivelabs/sdk-ts/node_modules/axios": {
+      "version": "0.27.2",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "follow-redirects": "^1.14.9",
+        "form-data": "^4.0.0"
+      }
+    },
+    "node_modules/@injectivelabs/sdk-ts/node_modules/bech32": {
+      "version": "2.0.0",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/@injectivelabs/sdk-ts/node_modules/cosmjs-types": {
+      "version": "0.7.2",
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "long": "^4.0.0",
+        "protobufjs": "~6.11.2"
+      }
+    },
+    "node_modules/@injectivelabs/sdk-ts/node_modules/rxjs": {
+      "version": "7.8.1",
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@injectivelabs/test-utils": {
+      "version": "1.14.3",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "axios": "^0.21.1",
+        "bignumber.js": "^9.0.1",
+        "link-module-alias": "^1.2.0",
+        "shx": "^0.3.2",
+        "snakecase-keys": "^5.1.2",
+        "store2": "^2.12.0"
+      }
+    },
+    "node_modules/@injectivelabs/token-metadata": {
+      "version": "1.14.5",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "@injectivelabs/exceptions": "^1.14.5",
+        "@injectivelabs/networks": "^1.14.5",
+        "@injectivelabs/ts-types": "^1.14.5",
+        "@injectivelabs/utils": "^1.14.5",
+        "@types/lodash.values": "^4.3.6",
+        "copyfiles": "^2.4.1",
+        "jsonschema": "^1.4.0",
+        "link-module-alias": "^1.2.0",
+        "lodash": "^4.17.21",
+        "lodash.values": "^4.3.0",
+        "shx": "^0.3.2"
+      }
+    },
+    "node_modules/@injectivelabs/token-metadata/node_modules/@injectivelabs/networks": {
+      "version": "1.14.5",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "@injectivelabs/exceptions": "^1.14.5",
+        "@injectivelabs/ts-types": "^1.14.5",
+        "@injectivelabs/utils": "^1.14.5",
+        "link-module-alias": "^1.2.0",
+        "shx": "^0.3.2"
+      }
+    },
+    "node_modules/@injectivelabs/token-metadata/node_modules/@injectivelabs/utils": {
+      "version": "1.14.5",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "@injectivelabs/exceptions": "^1.14.5",
+        "@injectivelabs/ts-types": "^1.14.5",
+        "axios": "^0.21.1",
+        "bignumber.js": "^9.0.1",
+        "http-status-codes": "^2.2.0",
+        "link-module-alias": "^1.2.0",
+        "shx": "^0.3.2",
+        "snakecase-keys": "^5.1.2",
+        "store2": "^2.12.0"
+      }
+    },
+    "node_modules/@injectivelabs/ts-types": {
+      "version": "1.14.5",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "link-module-alias": "^1.2.0",
+        "shx": "^0.3.2"
+      }
+    },
+    "node_modules/@injectivelabs/utils": {
+      "version": "1.10.12",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "@injectivelabs/exceptions": "^1.10.12",
+        "@injectivelabs/ts-types": "^1.10.12",
+        "axios": "^0.21.1",
+        "bignumber.js": "^9.0.1",
+        "http-status-codes": "^2.2.0",
+        "link-module-alias": "^1.2.0",
+        "shx": "^0.3.2",
+        "snakecase-keys": "^5.1.2",
+        "store2": "^2.12.0"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config": {
+      "version": "1.1.0",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "camelcase": "^5.3.1",
+        "find-up": "^4.1.0",
+        "get-package-type": "^0.1.0",
+        "js-yaml": "^3.13.1",
+        "resolve-from": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/schema": {
+      "version": "0.1.3",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/console": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/types": "^29.4.1",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "jest-message-util": "^29.4.1",
+        "jest-util": "^29.4.1",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/core": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/console": "^29.4.1",
+        "@jest/reporters": "^29.4.1",
+        "@jest/test-result": "^29.4.1",
+        "@jest/transform": "^29.4.1",
+        "@jest/types": "^29.4.1",
+        "@types/node": "*",
+        "ansi-escapes": "^4.2.1",
+        "chalk": "^4.0.0",
+        "ci-info": "^3.2.0",
+        "exit": "^0.1.2",
+        "graceful-fs": "^4.2.9",
+        "jest-changed-files": "^29.4.0",
+        "jest-config": "^29.4.1",
+        "jest-haste-map": "^29.4.1",
+        "jest-message-util": "^29.4.1",
+        "jest-regex-util": "^29.2.0",
+        "jest-resolve": "^29.4.1",
+        "jest-resolve-dependencies": "^29.4.1",
+        "jest-runner": "^29.4.1",
+        "jest-runtime": "^29.4.1",
+        "jest-snapshot": "^29.4.1",
+        "jest-util": "^29.4.1",
+        "jest-validate": "^29.4.1",
+        "jest-watcher": "^29.4.1",
+        "micromatch": "^4.0.4",
+        "pretty-format": "^29.4.1",
+        "slash": "^3.0.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+      },
+      "peerDependenciesMeta": {
+        "node-notifier": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@jest/environment": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/fake-timers": "^29.4.1",
+        "@jest/types": "^29.4.1",
+        "@types/node": "*",
+        "jest-mock": "^29.4.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/expect": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "expect": "^29.4.1",
+        "jest-snapshot": "^29.4.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/expect-utils": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "jest-get-type": "^29.2.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/fake-timers": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/types": "^29.4.1",
+        "@sinonjs/fake-timers": "^10.0.2",
+        "@types/node": "*",
+        "jest-message-util": "^29.4.1",
+        "jest-mock": "^29.4.1",
+        "jest-util": "^29.4.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/globals": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/environment": "^29.4.1",
+        "@jest/expect": "^29.4.1",
+        "@jest/types": "^29.4.1",
+        "jest-mock": "^29.4.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/reporters": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@bcoe/v8-coverage": "^0.2.3",
+        "@jest/console": "^29.4.1",
+        "@jest/test-result": "^29.4.1",
+        "@jest/transform": "^29.4.1",
+        "@jest/types": "^29.4.1",
+        "@jridgewell/trace-mapping": "^0.3.15",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "collect-v8-coverage": "^1.0.0",
+        "exit": "^0.1.2",
+        "glob": "^7.1.3",
+        "graceful-fs": "^4.2.9",
+        "istanbul-lib-coverage": "^3.0.0",
+        "istanbul-lib-instrument": "^5.1.0",
+        "istanbul-lib-report": "^3.0.0",
+        "istanbul-lib-source-maps": "^4.0.0",
+        "istanbul-reports": "^3.1.3",
+        "jest-message-util": "^29.4.1",
+        "jest-util": "^29.4.1",
+        "jest-worker": "^29.4.1",
+        "slash": "^3.0.0",
+        "string-length": "^4.0.1",
+        "strip-ansi": "^6.0.0",
+        "v8-to-istanbul": "^9.0.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+      },
+      "peerDependenciesMeta": {
+        "node-notifier": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@jest/reporters/node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.17",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "3.1.0",
+        "@jridgewell/sourcemap-codec": "1.4.14"
+      }
+    },
+    "node_modules/@jest/schemas": {
+      "version": "29.4.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@sinclair/typebox": "^0.25.16"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/source-map": {
+      "version": "29.2.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/trace-mapping": "^0.3.15",
+        "callsites": "^3.0.0",
+        "graceful-fs": "^4.2.9"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/source-map/node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.17",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "3.1.0",
+        "@jridgewell/sourcemap-codec": "1.4.14"
+      }
+    },
+    "node_modules/@jest/test-result": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/console": "^29.4.1",
+        "@jest/types": "^29.4.1",
+        "@types/istanbul-lib-coverage": "^2.0.0",
+        "collect-v8-coverage": "^1.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/test-sequencer": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/test-result": "^29.4.1",
+        "graceful-fs": "^4.2.9",
+        "jest-haste-map": "^29.4.1",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/transform": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/core": "^7.11.6",
+        "@jest/types": "^29.4.1",
+        "@jridgewell/trace-mapping": "^0.3.15",
+        "babel-plugin-istanbul": "^6.1.1",
+        "chalk": "^4.0.0",
+        "convert-source-map": "^2.0.0",
+        "fast-json-stable-stringify": "^2.1.0",
+        "graceful-fs": "^4.2.9",
+        "jest-haste-map": "^29.4.1",
+        "jest-regex-util": "^29.2.0",
+        "jest-util": "^29.4.1",
+        "micromatch": "^4.0.4",
+        "pirates": "^4.0.4",
+        "slash": "^3.0.0",
+        "write-file-atomic": "^5.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/transform/node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.17",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "3.1.0",
+        "@jridgewell/sourcemap-codec": "1.4.14"
+      }
+    },
+    "node_modules/@jest/types": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/schemas": "^29.4.0",
+        "@types/istanbul-lib-coverage": "^2.0.0",
+        "@types/istanbul-reports": "^3.0.0",
+        "@types/node": "*",
+        "@types/yargs": "^17.0.8",
+        "chalk": "^4.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jridgewell/gen-mapping": {
+      "version": "0.1.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/set-array": "^1.0.0",
+        "@jridgewell/sourcemap-codec": "^1.4.10"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/set-array": {
+      "version": "1.1.2",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.4.14",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.9",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.0.3",
+        "@jridgewell/sourcemap-codec": "^1.4.10"
+      }
+    },
+    "node_modules/@ledgerhq/devices": {
+      "version": "5.51.1",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@ledgerhq/errors": "^5.50.0",
+        "@ledgerhq/logs": "^5.50.0",
+        "rxjs": "6",
+        "semver": "^7.3.5"
+      }
+    },
+    "node_modules/@ledgerhq/errors": {
+      "version": "5.50.0",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@ledgerhq/hw-transport": {
+      "version": "5.51.1",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@ledgerhq/devices": "^5.51.1",
+        "@ledgerhq/errors": "^5.50.0",
+        "events": "^3.3.0"
+      }
+    },
+    "node_modules/@ledgerhq/logs": {
+      "version": "5.50.0",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@metamask/eth-sig-util": {
+      "version": "4.0.1",
+      "license": "ISC",
+      "optional": true,
+      "dependencies": {
+        "ethereumjs-abi": "^0.6.8",
+        "ethereumjs-util": "^6.2.1",
+        "ethjs-util": "^0.1.6",
+        "tweetnacl": "^1.0.3",
+        "tweetnacl-util": "^0.15.1"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/@metamask/eth-sig-util/node_modules/@types/bn.js": {
+      "version": "4.11.6",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@metamask/eth-sig-util/node_modules/bn.js": {
+      "version": "4.12.0",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/@metamask/eth-sig-util/node_modules/ethereumjs-util": {
+      "version": "6.2.1",
+      "license": "MPL-2.0",
+      "optional": true,
+      "dependencies": {
+        "@types/bn.js": "^4.11.3",
+        "bn.js": "^4.11.0",
+        "create-hash": "^1.1.2",
+        "elliptic": "^6.5.2",
+        "ethereum-cryptography": "^0.1.3",
+        "ethjs-util": "0.1.6",
+        "rlp": "^2.2.3"
+      }
+    },
+    "node_modules/@mysten/bcs": {
+      "version": "0.7.1",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "bs58": "^5.0.0"
+      }
+    },
+    "node_modules/@mysten/bcs/node_modules/base-x": {
+      "version": "4.0.0",
+      "license": "MIT"
+    },
+    "node_modules/@mysten/bcs/node_modules/bs58": {
+      "version": "5.0.0",
+      "license": "MIT",
+      "dependencies": {
+        "base-x": "^4.0.0"
+      }
+    },
+    "node_modules/@mysten/sui.js": {
+      "version": "0.32.2",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@mysten/bcs": "0.7.1",
+        "@noble/curves": "^1.0.0",
+        "@noble/hashes": "^1.3.0",
+        "@scure/bip32": "^1.3.0",
+        "@scure/bip39": "^1.2.0",
+        "@suchipi/femver": "^1.0.0",
+        "jayson": "^4.0.0",
+        "rpc-websockets": "^7.5.1",
+        "superstruct": "^1.0.3",
+        "tweetnacl": "^1.0.3"
+      },
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/@mysten/sui.js/node_modules/@noble/hashes": {
+      "version": "1.3.3",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 16"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/@mysten/sui.js/node_modules/@types/node": {
+      "version": "12.20.55",
+      "license": "MIT"
+    },
+    "node_modules/@mysten/sui.js/node_modules/jayson": {
+      "version": "4.1.0",
+      "license": "MIT",
+      "dependencies": {
+        "@types/connect": "^3.4.33",
+        "@types/node": "^12.12.54",
+        "@types/ws": "^7.4.4",
+        "commander": "^2.20.3",
+        "delay": "^5.0.0",
+        "es6-promisify": "^5.0.0",
+        "eyes": "^0.1.8",
+        "isomorphic-ws": "^4.0.1",
+        "json-stringify-safe": "^5.0.1",
+        "JSONStream": "^1.3.5",
+        "uuid": "^8.3.2",
+        "ws": "^7.4.5"
+      },
+      "bin": {
+        "jayson": "bin/jayson.js"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@mysten/sui.js/node_modules/superstruct": {
+      "version": "1.0.3",
+      "license": "MIT",
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/@noble/curves": {
+      "version": "1.3.0",
+      "license": "MIT",
+      "dependencies": {
+        "@noble/hashes": "1.3.3"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/@noble/curves/node_modules/@noble/hashes": {
+      "version": "1.3.3",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 16"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/@noble/ed25519": {
+      "version": "1.7.1",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/@noble/hashes": {
+      "version": "1.1.4",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/@noble/secp256k1": {
+      "version": "1.7.1",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/@project-serum/anchor": {
+      "version": "0.25.0",
+      "license": "(MIT OR Apache-2.0)",
+      "dependencies": {
+        "@project-serum/borsh": "^0.2.5",
+        "@solana/web3.js": "^1.36.0",
+        "base64-js": "^1.5.1",
+        "bn.js": "^5.1.2",
+        "bs58": "^4.0.1",
+        "buffer-layout": "^1.2.2",
+        "camelcase": "^5.3.1",
+        "cross-fetch": "^3.1.5",
+        "crypto-hash": "^1.3.0",
+        "eventemitter3": "^4.0.7",
+        "js-sha256": "^0.9.0",
+        "pako": "^2.0.3",
+        "snake-case": "^3.0.4",
+        "superstruct": "^0.15.4",
+        "toml": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=11"
+      }
+    },
+    "node_modules/@project-serum/borsh": {
+      "version": "0.2.5",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "bn.js": "^5.1.2",
+        "buffer-layout": "^1.2.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "@solana/web3.js": "^1.2.0"
+      }
+    },
+    "node_modules/@protobufjs/aspromise": {
+      "version": "1.1.2",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/base64": {
+      "version": "1.1.2",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/codegen": {
+      "version": "2.0.4",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/eventemitter": {
+      "version": "1.1.0",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/fetch": {
+      "version": "1.1.0",
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.1",
+        "@protobufjs/inquire": "^1.1.0"
+      }
+    },
+    "node_modules/@protobufjs/float": {
+      "version": "1.0.2",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/inquire": {
+      "version": "1.1.0",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/path": {
+      "version": "1.1.2",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/pool": {
+      "version": "1.1.0",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/utf8": {
+      "version": "1.1.0",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@scure/base": {
+      "version": "1.1.5",
+      "license": "MIT",
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/@scure/bip32": {
+      "version": "1.3.3",
+      "license": "MIT",
+      "dependencies": {
+        "@noble/curves": "~1.3.0",
+        "@noble/hashes": "~1.3.2",
+        "@scure/base": "~1.1.4"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/@scure/bip32/node_modules/@noble/hashes": {
+      "version": "1.3.3",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 16"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/@scure/bip39": {
+      "version": "1.2.2",
+      "license": "MIT",
+      "dependencies": {
+        "@noble/hashes": "~1.3.2",
+        "@scure/base": "~1.1.4"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/@scure/bip39/node_modules/@noble/hashes": {
+      "version": "1.3.3",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 16"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/@sinclair/typebox": {
+      "version": "0.25.21",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@sinonjs/commons": {
+      "version": "2.0.0",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "type-detect": "4.0.8"
+      }
+    },
+    "node_modules/@sinonjs/fake-timers": {
+      "version": "10.0.2",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@sinonjs/commons": "^2.0.0"
+      }
+    },
+    "node_modules/@solana/buffer-layout": {
+      "version": "4.0.1",
+      "license": "MIT",
+      "dependencies": {
+        "buffer": "~6.0.3"
+      },
+      "engines": {
+        "node": ">=5.10"
+      }
+    },
+    "node_modules/@solana/buffer-layout-utils": {
+      "version": "0.2.0",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@solana/buffer-layout": "^4.0.0",
+        "@solana/web3.js": "^1.32.0",
+        "bigint-buffer": "^1.1.5",
+        "bignumber.js": "^9.0.1"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@solana/spl-token": {
+      "version": "0.3.7",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@solana/buffer-layout": "^4.0.0",
+        "@solana/buffer-layout-utils": "^0.2.0",
+        "buffer": "^6.0.3"
+      },
+      "engines": {
+        "node": ">=16"
+      },
+      "peerDependencies": {
+        "@solana/web3.js": "^1.47.4"
+      }
+    },
+    "node_modules/@solana/web3.js": {
+      "version": "1.73.0",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.12.5",
+        "@noble/ed25519": "^1.7.0",
+        "@noble/hashes": "^1.1.2",
+        "@noble/secp256k1": "^1.6.3",
+        "@solana/buffer-layout": "^4.0.0",
+        "agentkeepalive": "^4.2.1",
+        "bigint-buffer": "^1.1.5",
+        "bn.js": "^5.0.0",
+        "borsh": "^0.7.0",
+        "bs58": "^4.0.1",
+        "buffer": "6.0.1",
+        "fast-stable-stringify": "^1.0.0",
+        "jayson": "^3.4.4",
+        "node-fetch": "2",
+        "rpc-websockets": "^7.5.0",
+        "superstruct": "^0.14.2"
+      },
+      "engines": {
+        "node": ">=12.20.0"
+      }
+    },
+    "node_modules/@solana/web3.js/node_modules/buffer": {
+      "version": "6.0.1",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.2.1"
+      }
+    },
+    "node_modules/@solana/web3.js/node_modules/superstruct": {
+      "version": "0.14.2",
+      "license": "MIT"
+    },
+    "node_modules/@suchipi/femver": {
+      "version": "1.0.0",
+      "license": "MIT"
+    },
+    "node_modules/@terra-money/legacy.proto": {
+      "name": "@terra-money/terra.proto",
+      "version": "0.1.7",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "google-protobuf": "^3.17.3",
+        "long": "^4.0.0",
+        "protobufjs": "~6.11.2"
+      }
+    },
+    "node_modules/@terra-money/terra.js": {
+      "version": "3.1.9",
+      "license": "MIT",
+      "dependencies": {
+        "@classic-terra/terra.proto": "^1.1.0",
+        "@terra-money/terra.proto": "^2.1.0",
+        "axios": "^0.27.2",
+        "bech32": "^2.0.0",
+        "bip32": "^2.0.6",
+        "bip39": "^3.0.3",
+        "bufferutil": "^4.0.3",
+        "decimal.js": "^10.2.1",
+        "jscrypto": "^1.0.1",
+        "readable-stream": "^3.6.0",
+        "secp256k1": "^4.0.2",
+        "tmp": "^0.2.1",
+        "utf-8-validate": "^5.0.5",
+        "ws": "^7.5.9"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/@terra-money/terra.js/node_modules/axios": {
+      "version": "0.27.2",
+      "license": "MIT",
+      "dependencies": {
+        "follow-redirects": "^1.14.9",
+        "form-data": "^4.0.0"
+      }
+    },
+    "node_modules/@terra-money/terra.js/node_modules/bech32": {
+      "version": "2.0.0",
+      "license": "MIT"
+    },
+    "node_modules/@terra-money/terra.proto": {
+      "version": "2.1.0",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@improbable-eng/grpc-web": "^0.14.1",
+        "google-protobuf": "^3.17.3",
+        "long": "^4.0.0",
+        "protobufjs": "~6.11.2"
+      }
+    },
+    "node_modules/@terra-money/terra.proto/node_modules/@improbable-eng/grpc-web": {
+      "version": "0.14.1",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "browser-headers": "^0.4.1"
+      },
+      "peerDependencies": {
+        "google-protobuf": "^3.14.0"
+      }
+    },
+    "node_modules/@tsconfig/node10": {
+      "version": "1.0.9",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@tsconfig/node12": {
+      "version": "1.0.11",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@tsconfig/node14": {
+      "version": "1.0.3",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@tsconfig/node16": {
+      "version": "1.0.3",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/babel__core": {
+      "version": "7.20.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.20.7",
+        "@babel/types": "^7.20.7",
+        "@types/babel__generator": "*",
+        "@types/babel__template": "*",
+        "@types/babel__traverse": "*"
+      }
+    },
+    "node_modules/@types/babel__generator": {
+      "version": "7.6.4",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "node_modules/@types/babel__template": {
+      "version": "7.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.1.0",
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "node_modules/@types/babel__traverse": {
+      "version": "7.18.3",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.3.0"
+      }
+    },
+    "node_modules/@types/bn.js": {
+      "version": "5.1.1",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/connect": {
+      "version": "3.4.35",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/elliptic": {
+      "version": "6.4.14",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/bn.js": "*"
+      }
+    },
+    "node_modules/@types/graceful-fs": {
+      "version": "4.1.6",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/istanbul-lib-coverage": {
+      "version": "2.0.4",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/istanbul-lib-report": {
+      "version": "3.0.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/istanbul-lib-coverage": "*"
+      }
+    },
+    "node_modules/@types/istanbul-reports": {
+      "version": "3.0.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/istanbul-lib-report": "*"
+      }
+    },
+    "node_modules/@types/jest": {
+      "version": "29.4.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "expect": "^29.0.0",
+        "pretty-format": "^29.0.0"
+      }
+    },
+    "node_modules/@types/lodash": {
+      "version": "4.14.202",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/@types/lodash.values": {
+      "version": "4.3.9",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@types/lodash": "*"
+      }
+    },
+    "node_modules/@types/long": {
+      "version": "4.0.2",
+      "license": "MIT"
+    },
+    "node_modules/@types/node": {
+      "version": "18.11.15",
+      "license": "MIT"
+    },
+    "node_modules/@types/pbkdf2": {
+      "version": "3.1.0",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/prettier": {
+      "version": "2.7.2",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/secp256k1": {
+      "version": "4.0.3",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/stack-utils": {
+      "version": "2.0.1",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/ws": {
+      "version": "7.4.7",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/yargs": {
+      "version": "17.0.22",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/yargs-parser": "*"
+      }
+    },
+    "node_modules/@types/yargs-parser": {
+      "version": "21.0.0",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@wry/caches": {
+      "version": "1.0.1",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@wry/context": {
+      "version": "0.7.4",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@wry/equality": {
+      "version": "0.5.7",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@wry/trie": {
+      "version": "0.5.0",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@xpla/xpla.js": {
+      "version": "0.2.3",
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/bytes": "^5.6.1",
+        "@ethersproject/keccak256": "^5.6.1",
+        "@ethersproject/signing-key": "^5.6.2",
+        "@terra-money/legacy.proto": "npm:@terra-money/terra.proto@^0.1.7",
+        "@terra-money/terra.proto": "^2.1.0",
+        "axios": "^0.26.1",
+        "bech32": "^2.0.0",
+        "bip32": "^2.0.6",
+        "bip39": "^3.0.3",
+        "bufferutil": "^4.0.3",
+        "crypto-addr-codec": "^0.1.7",
+        "decimal.js": "^10.2.1",
+        "elliptic": "^6.5.4",
+        "ethereumjs-util": "^7.1.5",
+        "jscrypto": "^1.0.1",
+        "readable-stream": "^3.6.0",
+        "secp256k1": "^4.0.2",
+        "tmp": "^0.2.1",
+        "utf-8-validate": "^5.0.5",
+        "ws": "^7.5.8"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/@xpla/xpla.js/node_modules/axios": {
+      "version": "0.26.1",
+      "license": "MIT",
+      "dependencies": {
+        "follow-redirects": "^1.14.8"
+      }
+    },
+    "node_modules/@xpla/xpla.js/node_modules/bech32": {
+      "version": "2.0.0",
+      "license": "MIT"
+    },
+    "node_modules/acorn": {
+      "version": "8.8.1",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-walk": {
+      "version": "8.2.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/aes-js": {
+      "version": "3.0.0",
+      "license": "MIT"
+    },
+    "node_modules/agentkeepalive": {
+      "version": "4.2.1",
+      "license": "MIT",
+      "dependencies": {
+        "debug": "^4.1.0",
+        "depd": "^1.1.2",
+        "humanize-ms": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 8.0.0"
+      }
+    },
+    "node_modules/algo-msgpack-with-bigint": {
+      "version": "2.1.1",
+      "license": "ISC",
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/algosdk": {
+      "version": "2.7.0",
+      "license": "MIT",
+      "dependencies": {
+        "algo-msgpack-with-bigint": "^2.1.1",
+        "buffer": "^6.0.3",
+        "hi-base32": "^0.5.1",
+        "js-sha256": "^0.9.0",
+        "js-sha3": "^0.8.0",
+        "js-sha512": "^0.8.0",
+        "json-bigint": "^1.0.0",
+        "tweetnacl": "^1.0.3",
+        "vlq": "^2.0.4"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/ansi-escapes": {
+      "version": "4.3.2",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "type-fest": "^0.21.3"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/ansi-escapes/node_modules/type-fest": {
+      "version": "0.21.3",
+      "dev": true,
+      "license": "(MIT OR CC0-1.0)",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/anymatch": {
+      "version": "3.1.3",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/aptos": {
+      "version": "1.5.0",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@noble/hashes": "1.1.3",
+        "@scure/bip39": "1.1.0",
+        "axios": "0.27.2",
+        "form-data": "4.0.0",
+        "tweetnacl": "1.0.3"
+      },
+      "engines": {
+        "node": ">=11.0.0"
+      }
+    },
+    "node_modules/aptos/node_modules/@noble/hashes": {
+      "version": "1.1.3",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/aptos/node_modules/@scure/bip39": {
+      "version": "1.1.0",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@noble/hashes": "~1.1.1",
+        "@scure/base": "~1.1.0"
+      }
+    },
+    "node_modules/aptos/node_modules/axios": {
+      "version": "0.27.2",
+      "license": "MIT",
+      "dependencies": {
+        "follow-redirects": "^1.14.9",
+        "form-data": "^4.0.0"
+      }
+    },
+    "node_modules/arg": {
+      "version": "4.1.3",
+      "license": "MIT"
+    },
+    "node_modules/argparse": {
+      "version": "1.0.10",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
+    "node_modules/ast-types": {
+      "version": "0.14.2",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "license": "MIT"
+    },
+    "node_modules/axios": {
+      "version": "0.21.4",
+      "license": "MIT",
+      "dependencies": {
+        "follow-redirects": "^1.14.0"
+      }
+    },
+    "node_modules/babel-jest": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/transform": "^29.4.1",
+        "@types/babel__core": "^7.1.14",
+        "babel-plugin-istanbul": "^6.1.1",
+        "babel-preset-jest": "^29.4.0",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.9",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.8.0"
+      }
+    },
+    "node_modules/babel-plugin-istanbul": {
+      "version": "6.1.1",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.0.0",
+        "@istanbuljs/load-nyc-config": "^1.0.0",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-instrument": "^5.0.4",
+        "test-exclude": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/babel-plugin-jest-hoist": {
+      "version": "29.4.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/template": "^7.3.3",
+        "@babel/types": "^7.3.3",
+        "@types/babel__core": "^7.1.14",
+        "@types/babel__traverse": "^7.0.6"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/babel-preset-current-node-syntax": {
+      "version": "1.0.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/plugin-syntax-async-generators": "^7.8.4",
+        "@babel/plugin-syntax-bigint": "^7.8.3",
+        "@babel/plugin-syntax-class-properties": "^7.8.3",
+        "@babel/plugin-syntax-import-meta": "^7.8.3",
+        "@babel/plugin-syntax-json-strings": "^7.8.3",
+        "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3",
+        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
+        "@babel/plugin-syntax-numeric-separator": "^7.8.3",
+        "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+        "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
+        "@babel/plugin-syntax-optional-chaining": "^7.8.3",
+        "@babel/plugin-syntax-top-level-await": "^7.8.3"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/babel-preset-jest": {
+      "version": "29.4.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "babel-plugin-jest-hoist": "^29.4.0",
+        "babel-preset-current-node-syntax": "^1.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/babylon": {
+      "version": "6.18.0",
+      "license": "MIT",
+      "bin": {
+        "babylon": "bin/babylon.js"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "license": "MIT"
+    },
+    "node_modules/base-x": {
+      "version": "3.0.9",
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "node_modules/base64-js": {
+      "version": "1.5.1",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/bech32": {
+      "version": "1.1.4",
+      "license": "MIT"
+    },
+    "node_modules/big-integer": {
+      "version": "1.6.36",
+      "license": "Unlicense",
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/bigint-buffer": {
+      "version": "1.1.5",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "bindings": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 10.0.0"
+      }
+    },
+    "node_modules/bignumber.js": {
+      "version": "9.1.1",
+      "license": "MIT",
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/binary-parser": {
+      "version": "2.2.1",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/bindings": {
+      "version": "1.5.0",
+      "license": "MIT",
+      "dependencies": {
+        "file-uri-to-path": "1.0.0"
+      }
+    },
+    "node_modules/bip32": {
+      "version": "2.0.6",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "10.12.18",
+        "bs58check": "^2.1.1",
+        "create-hash": "^1.2.0",
+        "create-hmac": "^1.1.7",
+        "tiny-secp256k1": "^1.1.3",
+        "typeforce": "^1.11.5",
+        "wif": "^2.0.6"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/bip32/node_modules/@types/node": {
+      "version": "10.12.18",
+      "license": "MIT"
+    },
+    "node_modules/bip39": {
+      "version": "3.0.4",
+      "license": "ISC",
+      "dependencies": {
+        "@types/node": "11.11.6",
+        "create-hash": "^1.1.0",
+        "pbkdf2": "^3.0.9",
+        "randombytes": "^2.0.1"
+      }
+    },
+    "node_modules/bip39/node_modules/@types/node": {
+      "version": "11.11.6",
+      "license": "MIT"
+    },
+    "node_modules/bip66": {
+      "version": "1.1.5",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "node_modules/blakejs": {
+      "version": "1.2.1",
+      "license": "MIT"
+    },
+    "node_modules/bn.js": {
+      "version": "5.2.1",
+      "license": "MIT"
+    },
+    "node_modules/borsh": {
+      "version": "0.7.0",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "bn.js": "^5.2.0",
+        "bs58": "^4.0.0",
+        "text-encoding-utf-8": "^1.0.2"
+      }
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.2",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fill-range": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/brorand": {
+      "version": "1.1.0",
+      "license": "MIT"
+    },
+    "node_modules/browser-headers": {
+      "version": "0.4.1",
+      "license": "Apache-2.0"
+    },
+    "node_modules/browserify-aes": {
+      "version": "1.2.0",
+      "license": "MIT",
+      "dependencies": {
+        "buffer-xor": "^1.0.3",
+        "cipher-base": "^1.0.0",
+        "create-hash": "^1.1.0",
+        "evp_bytestokey": "^1.0.3",
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "node_modules/browserslist": {
+      "version": "4.21.5",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "caniuse-lite": "^1.0.30001449",
+        "electron-to-chromium": "^1.4.284",
+        "node-releases": "^2.0.8",
+        "update-browserslist-db": "^1.0.10"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/bs-logger": {
+      "version": "0.2.6",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fast-json-stable-stringify": "2.x"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/bs58": {
+      "version": "4.0.1",
+      "license": "MIT",
+      "dependencies": {
+        "base-x": "^3.0.2"
+      }
+    },
+    "node_modules/bs58check": {
+      "version": "2.1.2",
+      "license": "MIT",
+      "dependencies": {
+        "bs58": "^4.0.0",
+        "create-hash": "^1.1.0",
+        "safe-buffer": "^5.1.2"
+      }
+    },
+    "node_modules/bser": {
+      "version": "2.1.1",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "node-int64": "^0.4.0"
+      }
+    },
+    "node_modules/buffer": {
+      "version": "6.0.3",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.2.1"
+      }
+    },
+    "node_modules/buffer-from": {
+      "version": "1.1.2",
+      "license": "MIT"
+    },
+    "node_modules/buffer-layout": {
+      "version": "1.2.2",
+      "license": "MIT",
+      "engines": {
+        "node": ">=4.5"
+      }
+    },
+    "node_modules/buffer-xor": {
+      "version": "1.0.3",
+      "license": "MIT"
+    },
+    "node_modules/bufferutil": {
+      "version": "4.0.7",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "dependencies": {
+        "node-gyp-build": "^4.3.0"
+      },
+      "engines": {
+        "node": ">=6.14.2"
+      }
+    },
+    "node_modules/callsites": {
+      "version": "3.1.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/camelcase": {
+      "version": "5.3.1",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001450",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        }
+      ],
+      "license": "CC-BY-4.0"
+    },
+    "node_modules/capability": {
+      "version": "0.2.5",
+      "license": "MIT"
+    },
+    "node_modules/chalk": {
+      "version": "4.1.2",
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/char-regex": {
+      "version": "1.0.2",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/ci-info": {
+      "version": "3.7.1",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/sibiraj-s"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/cipher-base": {
+      "version": "1.0.4",
+      "license": "MIT",
+      "dependencies": {
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "node_modules/cjs-module-lexer": {
+      "version": "1.2.2",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/cliui": {
+      "version": "8.0.1",
+      "license": "ISC",
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.1",
+        "wrap-ansi": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/co": {
+      "version": "4.6.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "iojs": ">= 1.0.0",
+        "node": ">= 0.12.0"
+      }
+    },
+    "node_modules/collect-v8-coverage": {
+      "version": "1.0.1",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "license": "MIT"
+    },
+    "node_modules/combined-stream": {
+      "version": "1.0.8",
+      "license": "MIT",
+      "dependencies": {
+        "delayed-stream": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/commander": {
+      "version": "2.20.3",
+      "license": "MIT"
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "license": "MIT"
+    },
+    "node_modules/convert-source-map": {
+      "version": "2.0.0",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/copyfiles": {
+      "version": "2.4.1",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "glob": "^7.0.5",
+        "minimatch": "^3.0.3",
+        "mkdirp": "^1.0.4",
+        "noms": "0.0.0",
+        "through2": "^2.0.1",
+        "untildify": "^4.0.0",
+        "yargs": "^16.1.0"
+      },
+      "bin": {
+        "copyfiles": "copyfiles",
+        "copyup": "copyfiles"
+      }
+    },
+    "node_modules/copyfiles/node_modules/cliui": {
+      "version": "7.0.4",
+      "license": "ISC",
+      "optional": true,
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^7.0.0"
+      }
+    },
+    "node_modules/copyfiles/node_modules/yargs": {
+      "version": "16.2.0",
+      "license": "MIT",
+      "optional": true,
+      "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"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/copyfiles/node_modules/yargs-parser": {
+      "version": "20.2.9",
+      "license": "ISC",
+      "optional": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/core-util-is": {
+      "version": "1.0.3",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/cosmjs-types": {
+      "version": "0.5.2",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "long": "^4.0.0",
+        "protobufjs": "~6.11.2"
+      }
+    },
+    "node_modules/cosmwasm": {
+      "version": "1.1.1",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/amino": "^0.28.3",
+        "@cosmjs/cli": "^0.28.3",
+        "@cosmjs/cosmwasm-stargate": "^0.28.3",
+        "@cosmjs/crypto": "^0.28.3",
+        "@cosmjs/encoding": "^0.28.3",
+        "@cosmjs/faucet-client": "^0.28.3",
+        "@cosmjs/ledger-amino": "^0.28.3",
+        "@cosmjs/math": "^0.28.3",
+        "@cosmjs/proto-signing": "^0.28.3",
+        "@cosmjs/stargate": "^0.28.3",
+        "@cosmjs/utils": "^0.28.3"
+      },
+      "bin": {
+        "cosmwasm": "src/cli/bin/cli"
+      }
+    },
+    "node_modules/cosmwasm/node_modules/@cosmjs/amino": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/crypto": "0.28.13",
+        "@cosmjs/encoding": "0.28.13",
+        "@cosmjs/math": "0.28.13",
+        "@cosmjs/utils": "0.28.13"
+      }
+    },
+    "node_modules/cosmwasm/node_modules/@cosmjs/cosmwasm-stargate": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/amino": "0.28.13",
+        "@cosmjs/crypto": "0.28.13",
+        "@cosmjs/encoding": "0.28.13",
+        "@cosmjs/math": "0.28.13",
+        "@cosmjs/proto-signing": "0.28.13",
+        "@cosmjs/stargate": "0.28.13",
+        "@cosmjs/tendermint-rpc": "0.28.13",
+        "@cosmjs/utils": "0.28.13",
+        "cosmjs-types": "^0.4.0",
+        "long": "^4.0.0",
+        "pako": "^2.0.2"
+      }
+    },
+    "node_modules/cosmwasm/node_modules/@cosmjs/crypto": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/encoding": "0.28.13",
+        "@cosmjs/math": "0.28.13",
+        "@cosmjs/utils": "0.28.13",
+        "@noble/hashes": "^1",
+        "bn.js": "^5.2.0",
+        "elliptic": "^6.5.3",
+        "libsodium-wrappers": "^0.7.6"
+      }
+    },
+    "node_modules/cosmwasm/node_modules/@cosmjs/encoding": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "base64-js": "^1.3.0",
+        "bech32": "^1.1.4",
+        "readonly-date": "^1.0.0"
+      }
+    },
+    "node_modules/cosmwasm/node_modules/@cosmjs/json-rpc": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/stream": "0.28.13",
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/cosmwasm/node_modules/@cosmjs/math": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "bn.js": "^5.2.0"
+      }
+    },
+    "node_modules/cosmwasm/node_modules/@cosmjs/proto-signing": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/amino": "0.28.13",
+        "@cosmjs/crypto": "0.28.13",
+        "@cosmjs/encoding": "0.28.13",
+        "@cosmjs/math": "0.28.13",
+        "@cosmjs/utils": "0.28.13",
+        "cosmjs-types": "^0.4.0",
+        "long": "^4.0.0"
+      }
+    },
+    "node_modules/cosmwasm/node_modules/@cosmjs/socket": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/stream": "0.28.13",
+        "isomorphic-ws": "^4.0.1",
+        "ws": "^7",
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/cosmwasm/node_modules/@cosmjs/stargate": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@confio/ics23": "^0.6.8",
+        "@cosmjs/amino": "0.28.13",
+        "@cosmjs/encoding": "0.28.13",
+        "@cosmjs/math": "0.28.13",
+        "@cosmjs/proto-signing": "0.28.13",
+        "@cosmjs/stream": "0.28.13",
+        "@cosmjs/tendermint-rpc": "0.28.13",
+        "@cosmjs/utils": "0.28.13",
+        "cosmjs-types": "^0.4.0",
+        "long": "^4.0.0",
+        "protobufjs": "~6.11.3",
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/cosmwasm/node_modules/@cosmjs/stream": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/cosmwasm/node_modules/@cosmjs/tendermint-rpc": {
+      "version": "0.28.13",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/crypto": "0.28.13",
+        "@cosmjs/encoding": "0.28.13",
+        "@cosmjs/json-rpc": "0.28.13",
+        "@cosmjs/math": "0.28.13",
+        "@cosmjs/socket": "0.28.13",
+        "@cosmjs/stream": "0.28.13",
+        "@cosmjs/utils": "0.28.13",
+        "axios": "^0.21.2",
+        "readonly-date": "^1.0.0",
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/cosmwasm/node_modules/@cosmjs/utils": {
+      "version": "0.28.13",
+      "license": "Apache-2.0"
+    },
+    "node_modules/cosmwasm/node_modules/cosmjs-types": {
+      "version": "0.4.1",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "long": "^4.0.0",
+        "protobufjs": "~6.11.2"
+      }
+    },
+    "node_modules/crc-32": {
+      "version": "1.2.2",
+      "license": "Apache-2.0",
+      "optional": true,
+      "bin": {
+        "crc32": "bin/crc32.njs"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/create-hash": {
+      "version": "1.2.0",
+      "license": "MIT",
+      "dependencies": {
+        "cipher-base": "^1.0.1",
+        "inherits": "^2.0.1",
+        "md5.js": "^1.3.4",
+        "ripemd160": "^2.0.1",
+        "sha.js": "^2.4.0"
+      }
+    },
+    "node_modules/create-hmac": {
+      "version": "1.1.7",
+      "license": "MIT",
+      "dependencies": {
+        "cipher-base": "^1.0.3",
+        "create-hash": "^1.1.0",
+        "inherits": "^2.0.1",
+        "ripemd160": "^2.0.0",
+        "safe-buffer": "^5.0.1",
+        "sha.js": "^2.4.8"
+      }
+    },
+    "node_modules/create-require": {
+      "version": "1.1.1",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/cross-fetch": {
+      "version": "3.1.5",
+      "license": "MIT",
+      "dependencies": {
+        "node-fetch": "2.6.7"
+      }
+    },
+    "node_modules/cross-fetch/node_modules/node-fetch": {
+      "version": "2.6.7",
+      "license": "MIT",
+      "dependencies": {
+        "whatwg-url": "^5.0.0"
+      },
+      "engines": {
+        "node": "4.x || >=6.0.0"
+      },
+      "peerDependencies": {
+        "encoding": "^0.1.0"
+      },
+      "peerDependenciesMeta": {
+        "encoding": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.3",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/crypto-addr-codec": {
+      "version": "0.1.7",
+      "license": "MIT",
+      "dependencies": {
+        "base-x": "^3.0.8",
+        "big-integer": "1.6.36",
+        "blakejs": "^1.1.0",
+        "bs58": "^4.0.1",
+        "ripemd160-min": "0.0.6",
+        "safe-buffer": "^5.2.0",
+        "sha3": "^2.1.1"
+      }
+    },
+    "node_modules/crypto-hash": {
+      "version": "1.3.0",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/debug": {
+      "version": "4.3.4",
+      "license": "MIT",
+      "dependencies": {
+        "ms": "2.1.2"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/decamelize": {
+      "version": "1.2.0",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/decimal.js": {
+      "version": "10.4.3",
+      "license": "MIT"
+    },
+    "node_modules/dedent": {
+      "version": "0.7.0",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/deepmerge": {
+      "version": "4.3.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/define-properties": {
+      "version": "1.1.4",
+      "license": "MIT",
+      "dependencies": {
+        "has-property-descriptors": "^1.0.0",
+        "object-keys": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/delay": {
+      "version": "5.0.0",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/delayed-stream": {
+      "version": "1.0.0",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/depd": {
+      "version": "1.1.2",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/detect-newline": {
+      "version": "3.1.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/diff": {
+      "version": "4.0.2",
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.3.1"
+      }
+    },
+    "node_modules/diff-sequences": {
+      "version": "29.3.1",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/dot-case": {
+      "version": "3.0.4",
+      "license": "MIT",
+      "dependencies": {
+        "no-case": "^3.0.4",
+        "tslib": "^2.0.3"
+      }
+    },
+    "node_modules/dotenv": {
+      "version": "16.0.3",
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/drbg.js": {
+      "version": "1.0.1",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "browserify-aes": "^1.0.6",
+        "create-hash": "^1.1.2",
+        "create-hmac": "^1.1.4"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/eccrypto": {
+      "version": "1.1.6",
+      "hasInstallScript": true,
+      "license": "CC0-1.0",
+      "optional": true,
+      "dependencies": {
+        "acorn": "7.1.1",
+        "elliptic": "6.5.4",
+        "es6-promise": "4.2.8",
+        "nan": "2.14.0"
+      },
+      "optionalDependencies": {
+        "secp256k1": "3.7.1"
+      }
+    },
+    "node_modules/eccrypto/node_modules/acorn": {
+      "version": "7.1.1",
+      "license": "MIT",
+      "optional": true,
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/eccrypto/node_modules/bn.js": {
+      "version": "4.12.0",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/eccrypto/node_modules/secp256k1": {
+      "version": "3.7.1",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "bindings": "^1.5.0",
+        "bip66": "^1.1.5",
+        "bn.js": "^4.11.8",
+        "create-hash": "^1.2.0",
+        "drbg.js": "^1.0.1",
+        "elliptic": "^6.4.1",
+        "nan": "^2.14.0",
+        "safe-buffer": "^5.1.2"
+      },
+      "engines": {
+        "node": ">=4.0.0"
+      }
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.4.286",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/elliptic": {
+      "version": "6.6.1",
+      "license": "MIT",
+      "dependencies": {
+        "bn.js": "^4.11.9",
+        "brorand": "^1.1.0",
+        "hash.js": "^1.0.0",
+        "hmac-drbg": "^1.0.1",
+        "inherits": "^2.0.4",
+        "minimalistic-assert": "^1.0.1",
+        "minimalistic-crypto-utils": "^1.0.1"
+      }
+    },
+    "node_modules/elliptic/node_modules/bn.js": {
+      "version": "4.12.0",
+      "license": "MIT"
+    },
+    "node_modules/emittery": {
+      "version": "0.13.1",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/emittery?sponsor=1"
+      }
+    },
+    "node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "license": "MIT"
+    },
+    "node_modules/error-ex": {
+      "version": "1.3.2",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "node_modules/error-polyfill": {
+      "version": "0.1.3",
+      "license": "MIT",
+      "dependencies": {
+        "capability": "^0.2.5",
+        "o3": "^1.0.3",
+        "u3": "^0.1.1"
+      }
+    },
+    "node_modules/es6-promise": {
+      "version": "4.2.8",
+      "license": "MIT"
+    },
+    "node_modules/es6-promisify": {
+      "version": "5.0.0",
+      "license": "MIT",
+      "dependencies": {
+        "es6-promise": "^4.0.3"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.1.1",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "devOptional": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/esprima": {
+      "version": "4.0.1",
+      "license": "BSD-2-Clause",
+      "bin": {
+        "esparse": "bin/esparse.js",
+        "esvalidate": "bin/esvalidate.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/eth-crypto": {
+      "version": "2.6.0",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@babel/runtime": "7.20.13",
+        "@ethereumjs/tx": "3.5.2",
+        "@types/bn.js": "5.1.1",
+        "eccrypto": "1.1.6",
+        "ethereumjs-util": "7.1.5",
+        "ethers": "5.7.2",
+        "secp256k1": "5.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/pubkey"
+      }
+    },
+    "node_modules/eth-crypto/node_modules/node-addon-api": {
+      "version": "5.1.0",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/eth-crypto/node_modules/secp256k1": {
+      "version": "5.0.0",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "elliptic": "^6.5.4",
+        "node-addon-api": "^5.0.0",
+        "node-gyp-build": "^4.2.0"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/ethereum-bloom-filters": {
+      "version": "1.0.10",
+      "license": "MIT",
+      "dependencies": {
+        "js-sha3": "^0.8.0"
+      }
+    },
+    "node_modules/ethereum-cryptography": {
+      "version": "0.1.3",
+      "license": "MIT",
+      "dependencies": {
+        "@types/pbkdf2": "^3.0.0",
+        "@types/secp256k1": "^4.0.1",
+        "blakejs": "^1.1.0",
+        "browserify-aes": "^1.2.0",
+        "bs58check": "^2.1.2",
+        "create-hash": "^1.2.0",
+        "create-hmac": "^1.1.7",
+        "hash.js": "^1.1.7",
+        "keccak": "^3.0.0",
+        "pbkdf2": "^3.0.17",
+        "randombytes": "^2.1.0",
+        "safe-buffer": "^5.1.2",
+        "scrypt-js": "^3.0.0",
+        "secp256k1": "^4.0.1",
+        "setimmediate": "^1.0.5"
+      }
+    },
+    "node_modules/ethereumjs-abi": {
+      "version": "0.6.8",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "bn.js": "^4.11.8",
+        "ethereumjs-util": "^6.0.0"
+      }
+    },
+    "node_modules/ethereumjs-abi/node_modules/@types/bn.js": {
+      "version": "4.11.6",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/ethereumjs-abi/node_modules/bn.js": {
+      "version": "4.12.0",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/ethereumjs-abi/node_modules/ethereumjs-util": {
+      "version": "6.2.1",
+      "license": "MPL-2.0",
+      "optional": true,
+      "dependencies": {
+        "@types/bn.js": "^4.11.3",
+        "bn.js": "^4.11.0",
+        "create-hash": "^1.1.2",
+        "elliptic": "^6.5.2",
+        "ethereum-cryptography": "^0.1.3",
+        "ethjs-util": "0.1.6",
+        "rlp": "^2.2.3"
+      }
+    },
+    "node_modules/ethereumjs-util": {
+      "version": "7.1.5",
+      "license": "MPL-2.0",
+      "dependencies": {
+        "@types/bn.js": "^5.1.0",
+        "bn.js": "^5.1.2",
+        "create-hash": "^1.1.2",
+        "ethereum-cryptography": "^0.1.3",
+        "rlp": "^2.2.4"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/ethers": {
+      "version": "5.7.2",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.buymeacoffee.com/ricmoo"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@ethersproject/abi": "5.7.0",
+        "@ethersproject/abstract-provider": "5.7.0",
+        "@ethersproject/abstract-signer": "5.7.0",
+        "@ethersproject/address": "5.7.0",
+        "@ethersproject/base64": "5.7.0",
+        "@ethersproject/basex": "5.7.0",
+        "@ethersproject/bignumber": "5.7.0",
+        "@ethersproject/bytes": "5.7.0",
+        "@ethersproject/constants": "5.7.0",
+        "@ethersproject/contracts": "5.7.0",
+        "@ethersproject/hash": "5.7.0",
+        "@ethersproject/hdnode": "5.7.0",
+        "@ethersproject/json-wallets": "5.7.0",
+        "@ethersproject/keccak256": "5.7.0",
+        "@ethersproject/logger": "5.7.0",
+        "@ethersproject/networks": "5.7.1",
+        "@ethersproject/pbkdf2": "5.7.0",
+        "@ethersproject/properties": "5.7.0",
+        "@ethersproject/providers": "5.7.2",
+        "@ethersproject/random": "5.7.0",
+        "@ethersproject/rlp": "5.7.0",
+        "@ethersproject/sha2": "5.7.0",
+        "@ethersproject/signing-key": "5.7.0",
+        "@ethersproject/solidity": "5.7.0",
+        "@ethersproject/strings": "5.7.0",
+        "@ethersproject/transactions": "5.7.0",
+        "@ethersproject/units": "5.7.0",
+        "@ethersproject/wallet": "5.7.0",
+        "@ethersproject/web": "5.7.1",
+        "@ethersproject/wordlists": "5.7.0"
+      }
+    },
+    "node_modules/ethjs-unit": {
+      "version": "0.1.6",
+      "license": "MIT",
+      "dependencies": {
+        "bn.js": "4.11.6",
+        "number-to-bn": "1.7.0"
+      },
+      "engines": {
+        "node": ">=6.5.0",
+        "npm": ">=3"
+      }
+    },
+    "node_modules/ethjs-unit/node_modules/bn.js": {
+      "version": "4.11.6",
+      "license": "MIT"
+    },
+    "node_modules/ethjs-util": {
+      "version": "0.1.6",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "is-hex-prefixed": "1.0.0",
+        "strip-hex-prefix": "1.0.0"
+      },
+      "engines": {
+        "node": ">=6.5.0",
+        "npm": ">=3"
+      }
+    },
+    "node_modules/eventemitter3": {
+      "version": "4.0.7",
+      "license": "MIT"
+    },
+    "node_modules/events": {
+      "version": "3.3.0",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.8.x"
+      }
+    },
+    "node_modules/evp_bytestokey": {
+      "version": "1.0.3",
+      "license": "MIT",
+      "dependencies": {
+        "md5.js": "^1.3.4",
+        "safe-buffer": "^5.1.1"
+      }
+    },
+    "node_modules/execa": {
+      "version": "5.1.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "cross-spawn": "^7.0.3",
+        "get-stream": "^6.0.0",
+        "human-signals": "^2.1.0",
+        "is-stream": "^2.0.0",
+        "merge-stream": "^2.0.0",
+        "npm-run-path": "^4.0.1",
+        "onetime": "^5.1.2",
+        "signal-exit": "^3.0.3",
+        "strip-final-newline": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/execa?sponsor=1"
+      }
+    },
+    "node_modules/exit": {
+      "version": "0.1.2",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/expect": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/expect-utils": "^29.4.1",
+        "jest-get-type": "^29.2.0",
+        "jest-matcher-utils": "^29.4.1",
+        "jest-message-util": "^29.4.1",
+        "jest-util": "^29.4.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/eyes": {
+      "version": "0.1.8",
+      "engines": {
+        "node": "> 0.1.90"
+      }
+    },
+    "node_modules/fast-json-stable-stringify": {
+      "version": "2.1.0",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fast-stable-stringify": {
+      "version": "1.0.0",
+      "license": "MIT"
+    },
+    "node_modules/fb-watchman": {
+      "version": "2.0.2",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "bser": "2.1.1"
+      }
+    },
+    "node_modules/file-uri-to-path": {
+      "version": "1.0.0",
+      "license": "MIT"
+    },
+    "node_modules/fill-range": {
+      "version": "7.0.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/find-up": {
+      "version": "4.1.0",
+      "license": "MIT",
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/follow-redirects": {
+      "version": "1.15.2",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/RubenVerborgh"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependenciesMeta": {
+        "debug": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/form-data": {
+      "version": "4.0.0",
+      "license": "MIT",
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "license": "ISC"
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.1",
+      "license": "MIT"
+    },
+    "node_modules/gensync": {
+      "version": "1.0.0-beta.2",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "license": "ISC",
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
+    "node_modules/get-intrinsic": {
+      "version": "1.1.3",
+      "license": "MIT",
+      "dependencies": {
+        "function-bind": "^1.1.1",
+        "has": "^1.0.3",
+        "has-symbols": "^1.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-package-type": {
+      "version": "0.1.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/get-stream": {
+      "version": "6.0.1",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/glob": {
+      "version": "7.2.3",
+      "license": "ISC",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/globals": {
+      "version": "11.12.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/globalthis": {
+      "version": "1.0.3",
+      "license": "MIT",
+      "dependencies": {
+        "define-properties": "^1.1.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/google-protobuf": {
+      "version": "3.21.2",
+      "license": "(BSD-3-Clause AND Apache-2.0)"
+    },
+    "node_modules/graceful-fs": {
+      "version": "4.2.10",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/graphql": {
+      "version": "16.8.1",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
+      }
+    },
+    "node_modules/graphql-tag": {
+      "version": "2.12.6",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
+      }
+    },
+    "node_modules/has": {
+      "version": "1.0.3",
+      "license": "MIT",
+      "dependencies": {
+        "function-bind": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/has-flag": {
+      "version": "4.0.0",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/has-property-descriptors": {
+      "version": "1.0.0",
+      "license": "MIT",
+      "dependencies": {
+        "get-intrinsic": "^1.1.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.0.3",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/hash-base": {
+      "version": "3.1.0",
+      "license": "MIT",
+      "dependencies": {
+        "inherits": "^2.0.4",
+        "readable-stream": "^3.6.0",
+        "safe-buffer": "^5.2.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/hash.js": {
+      "version": "1.1.7",
+      "license": "MIT",
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "minimalistic-assert": "^1.0.1"
+      }
+    },
+    "node_modules/hi-base32": {
+      "version": "0.5.1",
+      "license": "MIT"
+    },
+    "node_modules/hmac-drbg": {
+      "version": "1.0.1",
+      "license": "MIT",
+      "dependencies": {
+        "hash.js": "^1.0.3",
+        "minimalistic-assert": "^1.0.0",
+        "minimalistic-crypto-utils": "^1.0.1"
+      }
+    },
+    "node_modules/hoist-non-react-statics": {
+      "version": "3.3.2",
+      "license": "BSD-3-Clause",
+      "optional": true,
+      "dependencies": {
+        "react-is": "^16.7.0"
+      }
+    },
+    "node_modules/html-escaper": {
+      "version": "2.0.2",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/http-errors": {
+      "version": "1.8.1",
+      "license": "MIT",
+      "dependencies": {
+        "depd": "~1.1.2",
+        "inherits": "2.0.4",
+        "setprototypeof": "1.2.0",
+        "statuses": ">= 1.5.0 < 2",
+        "toidentifier": "1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/http-status-codes": {
+      "version": "2.3.0",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/human-signals": {
+      "version": "2.1.0",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=10.17.0"
+      }
+    },
+    "node_modules/humanize-ms": {
+      "version": "1.2.1",
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.0.0"
+      }
+    },
+    "node_modules/ieee754": {
+      "version": "1.2.1",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/import-local": {
+      "version": "3.1.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "pkg-dir": "^4.2.0",
+        "resolve-cwd": "^3.0.0"
+      },
+      "bin": {
+        "import-local-fixture": "fixtures/cli.js"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/imurmurhash": {
+      "version": "0.1.4",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.8.19"
+      }
+    },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "license": "ISC",
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "license": "ISC"
+    },
+    "node_modules/interpret": {
+      "version": "1.4.0",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/is-arrayish": {
+      "version": "0.2.1",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/is-core-module": {
+      "version": "2.11.0",
+      "devOptional": true,
+      "license": "MIT",
+      "dependencies": {
+        "has": "^1.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-generator-fn": {
+      "version": "2.1.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/is-hex-prefixed": {
+      "version": "1.0.0",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.5.0",
+        "npm": ">=3"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/is-stream": {
+      "version": "2.0.1",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/isarray": {
+      "version": "0.0.1",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/isexe": {
+      "version": "2.0.0",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/isomorphic-ws": {
+      "version": "4.0.1",
+      "license": "MIT",
+      "peerDependencies": {
+        "ws": "*"
+      }
+    },
+    "node_modules/istanbul-lib-coverage": {
+      "version": "3.2.0",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-instrument": {
+      "version": "5.2.1",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@babel/core": "^7.12.3",
+        "@babel/parser": "^7.14.7",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-coverage": "^3.2.0",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-instrument/node_modules/semver": {
+      "version": "6.3.0",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/istanbul-lib-report": {
+      "version": "3.0.0",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "istanbul-lib-coverage": "^3.0.0",
+        "make-dir": "^3.0.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-source-maps": {
+      "version": "4.0.1",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "debug": "^4.1.1",
+        "istanbul-lib-coverage": "^3.0.0",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/istanbul-reports": {
+      "version": "3.1.5",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "html-escaper": "^2.0.0",
+        "istanbul-lib-report": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jayson": {
+      "version": "3.7.0",
+      "license": "MIT",
+      "dependencies": {
+        "@types/connect": "^3.4.33",
+        "@types/node": "^12.12.54",
+        "@types/ws": "^7.4.4",
+        "commander": "^2.20.3",
+        "delay": "^5.0.0",
+        "es6-promisify": "^5.0.0",
+        "eyes": "^0.1.8",
+        "isomorphic-ws": "^4.0.1",
+        "json-stringify-safe": "^5.0.1",
+        "JSONStream": "^1.3.5",
+        "lodash": "^4.17.20",
+        "uuid": "^8.3.2",
+        "ws": "^7.4.5"
+      },
+      "bin": {
+        "jayson": "bin/jayson.js"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jayson/node_modules/@types/node": {
+      "version": "12.20.55",
+      "license": "MIT"
+    },
+    "node_modules/jest": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/core": "^29.4.1",
+        "@jest/types": "^29.4.1",
+        "import-local": "^3.0.2",
+        "jest-cli": "^29.4.1"
+      },
+      "bin": {
+        "jest": "bin/jest.js"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+      },
+      "peerDependenciesMeta": {
+        "node-notifier": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/jest-changed-files": {
+      "version": "29.4.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "execa": "^5.0.0",
+        "p-limit": "^3.1.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-changed-files/node_modules/p-limit": {
+      "version": "3.1.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "yocto-queue": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/jest-circus": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/environment": "^29.4.1",
+        "@jest/expect": "^29.4.1",
+        "@jest/test-result": "^29.4.1",
+        "@jest/types": "^29.4.1",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "co": "^4.6.0",
+        "dedent": "^0.7.0",
+        "is-generator-fn": "^2.0.0",
+        "jest-each": "^29.4.1",
+        "jest-matcher-utils": "^29.4.1",
+        "jest-message-util": "^29.4.1",
+        "jest-runtime": "^29.4.1",
+        "jest-snapshot": "^29.4.1",
+        "jest-util": "^29.4.1",
+        "p-limit": "^3.1.0",
+        "pretty-format": "^29.4.1",
+        "slash": "^3.0.0",
+        "stack-utils": "^2.0.3"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-circus/node_modules/p-limit": {
+      "version": "3.1.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "yocto-queue": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/jest-cli": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/core": "^29.4.1",
+        "@jest/test-result": "^29.4.1",
+        "@jest/types": "^29.4.1",
+        "chalk": "^4.0.0",
+        "exit": "^0.1.2",
+        "graceful-fs": "^4.2.9",
+        "import-local": "^3.0.2",
+        "jest-config": "^29.4.1",
+        "jest-util": "^29.4.1",
+        "jest-validate": "^29.4.1",
+        "prompts": "^2.0.1",
+        "yargs": "^17.3.1"
+      },
+      "bin": {
+        "jest": "bin/jest.js"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+      },
+      "peerDependenciesMeta": {
+        "node-notifier": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/jest-config": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/core": "^7.11.6",
+        "@jest/test-sequencer": "^29.4.1",
+        "@jest/types": "^29.4.1",
+        "babel-jest": "^29.4.1",
+        "chalk": "^4.0.0",
+        "ci-info": "^3.2.0",
+        "deepmerge": "^4.2.2",
+        "glob": "^7.1.3",
+        "graceful-fs": "^4.2.9",
+        "jest-circus": "^29.4.1",
+        "jest-environment-node": "^29.4.1",
+        "jest-get-type": "^29.2.0",
+        "jest-regex-util": "^29.2.0",
+        "jest-resolve": "^29.4.1",
+        "jest-runner": "^29.4.1",
+        "jest-util": "^29.4.1",
+        "jest-validate": "^29.4.1",
+        "micromatch": "^4.0.4",
+        "parse-json": "^5.2.0",
+        "pretty-format": "^29.4.1",
+        "slash": "^3.0.0",
+        "strip-json-comments": "^3.1.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "@types/node": "*",
+        "ts-node": ">=9.0.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "ts-node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/jest-diff": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "chalk": "^4.0.0",
+        "diff-sequences": "^29.3.1",
+        "jest-get-type": "^29.2.0",
+        "pretty-format": "^29.4.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-docblock": {
+      "version": "29.2.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "detect-newline": "^3.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-each": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/types": "^29.4.1",
+        "chalk": "^4.0.0",
+        "jest-get-type": "^29.2.0",
+        "jest-util": "^29.4.1",
+        "pretty-format": "^29.4.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-environment-node": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/environment": "^29.4.1",
+        "@jest/fake-timers": "^29.4.1",
+        "@jest/types": "^29.4.1",
+        "@types/node": "*",
+        "jest-mock": "^29.4.1",
+        "jest-util": "^29.4.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-get-type": {
+      "version": "29.2.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-haste-map": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/types": "^29.4.1",
+        "@types/graceful-fs": "^4.1.3",
+        "@types/node": "*",
+        "anymatch": "^3.0.3",
+        "fb-watchman": "^2.0.0",
+        "graceful-fs": "^4.2.9",
+        "jest-regex-util": "^29.2.0",
+        "jest-util": "^29.4.1",
+        "jest-worker": "^29.4.1",
+        "micromatch": "^4.0.4",
+        "walker": "^1.0.8"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "^2.3.2"
+      }
+    },
+    "node_modules/jest-leak-detector": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "jest-get-type": "^29.2.0",
+        "pretty-format": "^29.4.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-matcher-utils": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "chalk": "^4.0.0",
+        "jest-diff": "^29.4.1",
+        "jest-get-type": "^29.2.0",
+        "pretty-format": "^29.4.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-message-util": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.12.13",
+        "@jest/types": "^29.4.1",
+        "@types/stack-utils": "^2.0.0",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.9",
+        "micromatch": "^4.0.4",
+        "pretty-format": "^29.4.1",
+        "slash": "^3.0.0",
+        "stack-utils": "^2.0.3"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-mock": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/types": "^29.4.1",
+        "@types/node": "*",
+        "jest-util": "^29.4.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-pnp-resolver": {
+      "version": "1.2.3",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      },
+      "peerDependencies": {
+        "jest-resolve": "*"
+      },
+      "peerDependenciesMeta": {
+        "jest-resolve": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/jest-regex-util": {
+      "version": "29.2.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-resolve": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.9",
+        "jest-haste-map": "^29.4.1",
+        "jest-pnp-resolver": "^1.2.2",
+        "jest-util": "^29.4.1",
+        "jest-validate": "^29.4.1",
+        "resolve": "^1.20.0",
+        "resolve.exports": "^2.0.0",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-resolve-dependencies": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "jest-regex-util": "^29.2.0",
+        "jest-snapshot": "^29.4.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-runner": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/console": "^29.4.1",
+        "@jest/environment": "^29.4.1",
+        "@jest/test-result": "^29.4.1",
+        "@jest/transform": "^29.4.1",
+        "@jest/types": "^29.4.1",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "emittery": "^0.13.1",
+        "graceful-fs": "^4.2.9",
+        "jest-docblock": "^29.2.0",
+        "jest-environment-node": "^29.4.1",
+        "jest-haste-map": "^29.4.1",
+        "jest-leak-detector": "^29.4.1",
+        "jest-message-util": "^29.4.1",
+        "jest-resolve": "^29.4.1",
+        "jest-runtime": "^29.4.1",
+        "jest-util": "^29.4.1",
+        "jest-watcher": "^29.4.1",
+        "jest-worker": "^29.4.1",
+        "p-limit": "^3.1.0",
+        "source-map-support": "0.5.13"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-runner/node_modules/p-limit": {
+      "version": "3.1.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "yocto-queue": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/jest-runner/node_modules/source-map-support": {
+      "version": "0.5.13",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
+    "node_modules/jest-runtime": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/environment": "^29.4.1",
+        "@jest/fake-timers": "^29.4.1",
+        "@jest/globals": "^29.4.1",
+        "@jest/source-map": "^29.2.0",
+        "@jest/test-result": "^29.4.1",
+        "@jest/transform": "^29.4.1",
+        "@jest/types": "^29.4.1",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "cjs-module-lexer": "^1.0.0",
+        "collect-v8-coverage": "^1.0.0",
+        "glob": "^7.1.3",
+        "graceful-fs": "^4.2.9",
+        "jest-haste-map": "^29.4.1",
+        "jest-message-util": "^29.4.1",
+        "jest-mock": "^29.4.1",
+        "jest-regex-util": "^29.2.0",
+        "jest-resolve": "^29.4.1",
+        "jest-snapshot": "^29.4.1",
+        "jest-util": "^29.4.1",
+        "semver": "^7.3.5",
+        "slash": "^3.0.0",
+        "strip-bom": "^4.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-snapshot": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/core": "^7.11.6",
+        "@babel/generator": "^7.7.2",
+        "@babel/plugin-syntax-jsx": "^7.7.2",
+        "@babel/plugin-syntax-typescript": "^7.7.2",
+        "@babel/traverse": "^7.7.2",
+        "@babel/types": "^7.3.3",
+        "@jest/expect-utils": "^29.4.1",
+        "@jest/transform": "^29.4.1",
+        "@jest/types": "^29.4.1",
+        "@types/babel__traverse": "^7.0.6",
+        "@types/prettier": "^2.1.5",
+        "babel-preset-current-node-syntax": "^1.0.0",
+        "chalk": "^4.0.0",
+        "expect": "^29.4.1",
+        "graceful-fs": "^4.2.9",
+        "jest-diff": "^29.4.1",
+        "jest-get-type": "^29.2.0",
+        "jest-haste-map": "^29.4.1",
+        "jest-matcher-utils": "^29.4.1",
+        "jest-message-util": "^29.4.1",
+        "jest-util": "^29.4.1",
+        "natural-compare": "^1.4.0",
+        "pretty-format": "^29.4.1",
+        "semver": "^7.3.5"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-util": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/types": "^29.4.1",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "ci-info": "^3.2.0",
+        "graceful-fs": "^4.2.9",
+        "picomatch": "^2.2.3"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-validate": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/types": "^29.4.1",
+        "camelcase": "^6.2.0",
+        "chalk": "^4.0.0",
+        "jest-get-type": "^29.2.0",
+        "leven": "^3.1.0",
+        "pretty-format": "^29.4.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-validate/node_modules/camelcase": {
+      "version": "6.3.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/jest-watcher": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/test-result": "^29.4.1",
+        "@jest/types": "^29.4.1",
+        "@types/node": "*",
+        "ansi-escapes": "^4.2.1",
+        "chalk": "^4.0.0",
+        "emittery": "^0.13.1",
+        "jest-util": "^29.4.1",
+        "string-length": "^4.0.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-worker": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*",
+        "jest-util": "^29.4.1",
+        "merge-stream": "^2.0.0",
+        "supports-color": "^8.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-worker/node_modules/supports-color": {
+      "version": "8.1.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/supports-color?sponsor=1"
+      }
+    },
+    "node_modules/js-base64": {
+      "version": "3.7.4",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/js-sha256": {
+      "version": "0.9.0",
+      "license": "MIT"
+    },
+    "node_modules/js-sha3": {
+      "version": "0.8.0",
+      "license": "MIT"
+    },
+    "node_modules/js-sha512": {
+      "version": "0.8.0",
+      "license": "MIT"
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "devOptional": true,
+      "license": "MIT"
+    },
+    "node_modules/js-yaml": {
+      "version": "3.14.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/jscrypto": {
+      "version": "1.0.3",
+      "license": "MIT",
+      "bin": {
+        "jscrypto": "bin/cli.js"
+      }
+    },
+    "node_modules/jsesc": {
+      "version": "2.5.2",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "jsesc": "bin/jsesc"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/json-bigint": {
+      "version": "1.0.0",
+      "license": "MIT",
+      "dependencies": {
+        "bignumber.js": "^9.0.0"
+      }
+    },
+    "node_modules/json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/json-stringify-safe": {
+      "version": "5.0.1",
+      "license": "ISC"
+    },
+    "node_modules/json5": {
+      "version": "2.2.3",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "json5": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/jsonparse": {
+      "version": "1.3.1",
+      "engines": [
+        "node >= 0.2.0"
+      ],
+      "license": "MIT"
+    },
+    "node_modules/jsonschema": {
+      "version": "1.4.1",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/JSONStream": {
+      "version": "1.3.5",
+      "license": "(MIT OR Apache-2.0)",
+      "dependencies": {
+        "jsonparse": "^1.2.0",
+        "through": ">=2.2.7 <3"
+      },
+      "bin": {
+        "JSONStream": "bin.js"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/keccak": {
+      "version": "3.0.2",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "dependencies": {
+        "node-addon-api": "^2.0.0",
+        "node-gyp-build": "^4.2.0",
+        "readable-stream": "^3.6.0"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/keccak256": {
+      "version": "1.0.6",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "bn.js": "^5.2.0",
+        "buffer": "^6.0.3",
+        "keccak": "^3.0.2"
+      }
+    },
+    "node_modules/kleur": {
+      "version": "3.0.3",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/ledger-cosmos-js": {
+      "version": "2.1.8",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@babel/runtime": "^7.11.2",
+        "@ledgerhq/hw-transport": "^5.25.0",
+        "bech32": "^1.1.4",
+        "ripemd160": "^2.0.2"
+      }
+    },
+    "node_modules/leven": {
+      "version": "3.1.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/libsodium": {
+      "version": "0.7.10",
+      "license": "ISC"
+    },
+    "node_modules/libsodium-wrappers": {
+      "version": "0.7.10",
+      "license": "ISC",
+      "dependencies": {
+        "libsodium": "^0.7.0"
+      }
+    },
+    "node_modules/lines-and-columns": {
+      "version": "1.2.4",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/link-module-alias": {
+      "version": "1.2.0",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "chalk": "^2.4.1"
+      },
+      "bin": {
+        "link-module-alias": "index.js"
+      },
+      "engines": {
+        "node": "> 8.0.0"
+      }
+    },
+    "node_modules/link-module-alias/node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/link-module-alias/node_modules/chalk": {
+      "version": "2.4.2",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/link-module-alias/node_modules/color-convert": {
+      "version": "1.9.3",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/link-module-alias/node_modules/color-name": {
+      "version": "1.1.3",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/link-module-alias/node_modules/has-flag": {
+      "version": "3.0.0",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/link-module-alias/node_modules/supports-color": {
+      "version": "5.5.0",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/locate-path": {
+      "version": "5.0.0",
+      "license": "MIT",
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/lodash": {
+      "version": "4.17.21",
+      "license": "MIT"
+    },
+    "node_modules/lodash.memoize": {
+      "version": "4.1.2",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lodash.values": {
+      "version": "4.3.0",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/long": {
+      "version": "4.0.0",
+      "license": "Apache-2.0"
+    },
+    "node_modules/loose-envify": {
+      "version": "1.4.0",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "js-tokens": "^3.0.0 || ^4.0.0"
+      },
+      "bin": {
+        "loose-envify": "cli.js"
+      }
+    },
+    "node_modules/lower-case": {
+      "version": "2.0.2",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.0.3"
+      }
+    },
+    "node_modules/lru-cache": {
+      "version": "6.0.0",
+      "license": "ISC",
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/make-dir": {
+      "version": "3.1.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "semver": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/make-dir/node_modules/semver": {
+      "version": "6.3.0",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/make-error": {
+      "version": "1.3.6",
+      "license": "ISC"
+    },
+    "node_modules/makeerror": {
+      "version": "1.0.12",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "tmpl": "1.0.5"
+      }
+    },
+    "node_modules/map-obj": {
+      "version": "4.3.0",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/md5.js": {
+      "version": "1.3.5",
+      "license": "MIT",
+      "dependencies": {
+        "hash-base": "^3.0.0",
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.1.2"
+      }
+    },
+    "node_modules/merge-stream": {
+      "version": "2.0.0",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/micromatch": {
+      "version": "4.0.5",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "braces": "^3.0.2",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/mime-db": {
+      "version": "1.52.0",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "2.1.35",
+      "license": "MIT",
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mimic-fn": {
+      "version": "2.1.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/minimalistic-assert": {
+      "version": "1.0.1",
+      "license": "ISC"
+    },
+    "node_modules/minimalistic-crypto-utils": {
+      "version": "1.0.1",
+      "license": "MIT"
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.2",
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.8",
+      "license": "MIT",
+      "optional": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/mkdirp": {
+      "version": "1.0.4",
+      "license": "MIT",
+      "optional": true,
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.1.2",
+      "license": "MIT"
+    },
+    "node_modules/mustache": {
+      "version": "4.2.0",
+      "license": "MIT",
+      "bin": {
+        "mustache": "bin/mustache"
+      }
+    },
+    "node_modules/nan": {
+      "version": "2.14.0",
+      "license": "MIT"
+    },
+    "node_modules/natural-compare": {
+      "version": "1.4.0",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/near-api-js": {
+      "version": "1.1.0",
+      "license": "(MIT AND Apache-2.0)",
+      "dependencies": {
+        "bn.js": "5.2.1",
+        "borsh": "^0.7.0",
+        "bs58": "^4.0.0",
+        "depd": "^2.0.0",
+        "error-polyfill": "^0.1.3",
+        "http-errors": "^1.7.2",
+        "js-sha256": "^0.9.0",
+        "mustache": "^4.0.0",
+        "node-fetch": "^2.6.1",
+        "text-encoding-utf-8": "^1.0.2",
+        "tweetnacl": "^1.0.1"
+      }
+    },
+    "node_modules/near-api-js/node_modules/depd": {
+      "version": "2.0.0",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/no-case": {
+      "version": "3.0.4",
+      "license": "MIT",
+      "dependencies": {
+        "lower-case": "^2.0.2",
+        "tslib": "^2.0.3"
+      }
+    },
+    "node_modules/node-addon-api": {
+      "version": "2.0.2",
+      "license": "MIT"
+    },
+    "node_modules/node-fetch": {
+      "version": "2.6.8",
+      "license": "MIT",
+      "dependencies": {
+        "whatwg-url": "^5.0.0"
+      },
+      "engines": {
+        "node": "4.x || >=6.0.0"
+      },
+      "peerDependencies": {
+        "encoding": "^0.1.0"
+      },
+      "peerDependenciesMeta": {
+        "encoding": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/node-gyp-build": {
+      "version": "4.5.0",
+      "license": "MIT",
+      "bin": {
+        "node-gyp-build": "bin.js",
+        "node-gyp-build-optional": "optional.js",
+        "node-gyp-build-test": "build-test.js"
+      }
+    },
+    "node_modules/node-int64": {
+      "version": "0.4.0",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.9",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/noms": {
+      "version": "0.0.0",
+      "license": "ISC",
+      "optional": true,
+      "dependencies": {
+        "inherits": "^2.0.1",
+        "readable-stream": "~1.0.31"
+      }
+    },
+    "node_modules/noms/node_modules/readable-stream": {
+      "version": "1.0.34",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.1",
+        "isarray": "0.0.1",
+        "string_decoder": "~0.10.x"
+      }
+    },
+    "node_modules/noms/node_modules/string_decoder": {
+      "version": "0.10.31",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/npm-run-path": {
+      "version": "4.0.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "path-key": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/number-to-bn": {
+      "version": "1.7.0",
+      "license": "MIT",
+      "dependencies": {
+        "bn.js": "4.11.6",
+        "strip-hex-prefix": "1.0.0"
+      },
+      "engines": {
+        "node": ">=6.5.0",
+        "npm": ">=3"
+      }
+    },
+    "node_modules/number-to-bn/node_modules/bn.js": {
+      "version": "4.11.6",
+      "license": "MIT"
+    },
+    "node_modules/o3": {
+      "version": "1.0.3",
+      "license": "MIT",
+      "dependencies": {
+        "capability": "^0.2.5"
+      }
+    },
+    "node_modules/object-assign": {
+      "version": "4.1.1",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-keys": {
+      "version": "1.1.1",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "license": "ISC",
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/onetime": {
+      "version": "5.1.2",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mimic-fn": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/optimism": {
+      "version": "0.18.0",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@wry/caches": "^1.0.0",
+        "@wry/context": "^0.7.0",
+        "@wry/trie": "^0.4.3",
+        "tslib": "^2.3.0"
+      }
+    },
+    "node_modules/optimism/node_modules/@wry/trie": {
+      "version": "0.4.3",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/p-limit": {
+      "version": "2.3.0",
+      "license": "MIT",
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-locate": {
+      "version": "4.1.0",
+      "license": "MIT",
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/p-try": {
+      "version": "2.2.0",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/pako": {
+      "version": "2.1.0",
+      "license": "(MIT AND Zlib)"
+    },
+    "node_modules/parse-json": {
+      "version": "5.2.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.0.0",
+        "error-ex": "^1.3.1",
+        "json-parse-even-better-errors": "^2.3.0",
+        "lines-and-columns": "^1.1.6"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/path-exists": {
+      "version": "4.0.0",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/path-key": {
+      "version": "3.1.1",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-parse": {
+      "version": "1.0.7",
+      "devOptional": true,
+      "license": "MIT"
+    },
+    "node_modules/pbkdf2": {
+      "version": "3.1.2",
+      "license": "MIT",
+      "dependencies": {
+        "create-hash": "^1.1.2",
+        "create-hmac": "^1.1.4",
+        "ripemd160": "^2.0.1",
+        "safe-buffer": "^5.0.1",
+        "sha.js": "^2.4.8"
+      },
+      "engines": {
+        "node": ">=0.12"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "1.0.0",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/pirates": {
+      "version": "4.0.5",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/pkg-dir": {
+      "version": "4.2.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "find-up": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pretty-format": {
+      "version": "29.4.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/schemas": "^29.4.0",
+        "ansi-styles": "^5.0.0",
+        "react-is": "^18.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/pretty-format/node_modules/ansi-styles": {
+      "version": "5.2.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/pretty-format/node_modules/react-is": {
+      "version": "18.2.0",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/process-nextick-args": {
+      "version": "2.0.1",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/prompts": {
+      "version": "2.4.2",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "kleur": "^3.0.3",
+        "sisteransi": "^1.0.5"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/prop-types": {
+      "version": "15.8.1",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "loose-envify": "^1.4.0",
+        "object-assign": "^4.1.1",
+        "react-is": "^16.13.1"
+      }
+    },
+    "node_modules/protobufjs": {
+      "version": "6.11.3",
+      "hasInstallScript": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.2",
+        "@protobufjs/base64": "^1.1.2",
+        "@protobufjs/codegen": "^2.0.4",
+        "@protobufjs/eventemitter": "^1.1.0",
+        "@protobufjs/fetch": "^1.1.0",
+        "@protobufjs/float": "^1.0.2",
+        "@protobufjs/inquire": "^1.1.0",
+        "@protobufjs/path": "^1.1.2",
+        "@protobufjs/pool": "^1.1.0",
+        "@protobufjs/utf8": "^1.1.0",
+        "@types/long": "^4.0.1",
+        "@types/node": ">=13.7.0",
+        "long": "^4.0.0"
+      },
+      "bin": {
+        "pbjs": "bin/pbjs",
+        "pbts": "bin/pbts"
+      }
+    },
+    "node_modules/randombytes": {
+      "version": "2.1.0",
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "^5.1.0"
+      }
+    },
+    "node_modules/react-is": {
+      "version": "16.13.1",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/readable-stream": {
+      "version": "3.6.0",
+      "license": "MIT",
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/readonly-date": {
+      "version": "1.0.0",
+      "license": "Apache-2.0"
+    },
+    "node_modules/recast": {
+      "version": "0.20.5",
+      "license": "MIT",
+      "dependencies": {
+        "ast-types": "0.14.2",
+        "esprima": "~4.0.0",
+        "source-map": "~0.6.1",
+        "tslib": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/rechoir": {
+      "version": "0.6.2",
+      "optional": true,
+      "dependencies": {
+        "resolve": "^1.1.6"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/regenerator-runtime": {
+      "version": "0.13.11",
+      "license": "MIT"
+    },
+    "node_modules/rehackt": {
+      "version": "0.0.5",
+      "license": "MIT",
+      "optional": true,
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "*"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/require-main-filename": {
+      "version": "2.0.0",
+      "license": "ISC"
+    },
+    "node_modules/resolve": {
+      "version": "1.22.1",
+      "devOptional": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-core-module": "^2.9.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/resolve-cwd": {
+      "version": "3.0.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "resolve-from": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/resolve-from": {
+      "version": "5.0.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/resolve.exports": {
+      "version": "2.0.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/response-iterator": {
+      "version": "0.2.6",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/rimraf": {
+      "version": "3.0.2",
+      "license": "ISC",
+      "dependencies": {
+        "glob": "^7.1.3"
+      },
+      "bin": {
+        "rimraf": "bin.js"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/ripemd160": {
+      "version": "2.0.2",
+      "license": "MIT",
+      "dependencies": {
+        "hash-base": "^3.0.0",
+        "inherits": "^2.0.1"
+      }
+    },
+    "node_modules/ripemd160-min": {
+      "version": "0.0.6",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/rlp": {
+      "version": "2.2.7",
+      "license": "MPL-2.0",
+      "dependencies": {
+        "bn.js": "^5.2.0"
+      },
+      "bin": {
+        "rlp": "bin/rlp"
+      }
+    },
+    "node_modules/rpc-websockets": {
+      "version": "7.9.0",
+      "license": "LGPL-3.0-only",
+      "dependencies": {
+        "@babel/runtime": "^7.17.2",
+        "eventemitter3": "^4.0.7",
+        "uuid": "^8.3.2",
+        "ws": "^8.5.0"
+      },
+      "funding": {
+        "type": "paypal",
+        "url": "https://paypal.me/kozjak"
+      },
+      "optionalDependencies": {
+        "bufferutil": "^4.0.1",
+        "utf-8-validate": "^5.0.2"
+      }
+    },
+    "node_modules/rpc-websockets/node_modules/ws": {
+      "version": "8.12.0",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "peerDependencies": {
+        "bufferutil": "^4.0.1",
+        "utf-8-validate": ">=5.0.2"
+      },
+      "peerDependenciesMeta": {
+        "bufferutil": {
+          "optional": true
+        },
+        "utf-8-validate": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/rxjs": {
+      "version": "6.6.7",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^1.9.0"
+      },
+      "engines": {
+        "npm": ">=2.0.0"
+      }
+    },
+    "node_modules/rxjs/node_modules/tslib": {
+      "version": "1.14.1",
+      "license": "0BSD"
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/scrypt-js": {
+      "version": "3.0.1",
+      "license": "MIT"
+    },
+    "node_modules/secp256k1": {
+      "version": "4.0.3",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "dependencies": {
+        "elliptic": "^6.5.4",
+        "node-addon-api": "^2.0.0",
+        "node-gyp-build": "^4.2.0"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/semver": {
+      "version": "7.3.8",
+      "license": "ISC",
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/set-blocking": {
+      "version": "2.0.0",
+      "license": "ISC"
+    },
+    "node_modules/setimmediate": {
+      "version": "1.0.5",
+      "license": "MIT"
+    },
+    "node_modules/setprototypeof": {
+      "version": "1.2.0",
+      "license": "ISC"
+    },
+    "node_modules/sha.js": {
+      "version": "2.4.11",
+      "license": "(MIT AND BSD-3-Clause)",
+      "dependencies": {
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.0.1"
+      },
+      "bin": {
+        "sha.js": "bin.js"
+      }
+    },
+    "node_modules/sha3": {
+      "version": "2.1.4",
+      "license": "MIT",
+      "dependencies": {
+        "buffer": "6.0.3"
+      }
+    },
+    "node_modules/shebang-command": {
+      "version": "2.0.0",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "shebang-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shebang-regex": {
+      "version": "3.0.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shelljs": {
+      "version": "0.8.5",
+      "license": "BSD-3-Clause",
+      "optional": true,
+      "dependencies": {
+        "glob": "^7.0.0",
+        "interpret": "^1.0.0",
+        "rechoir": "^0.6.2"
+      },
+      "bin": {
+        "shjs": "bin/shjs"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/shx": {
+      "version": "0.3.4",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "minimist": "^1.2.3",
+        "shelljs": "^0.8.5"
+      },
+      "bin": {
+        "shx": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/signal-exit": {
+      "version": "3.0.7",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/sisteransi": {
+      "version": "1.0.5",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/slash": {
+      "version": "3.0.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/snake-case": {
+      "version": "3.0.4",
+      "license": "MIT",
+      "dependencies": {
+        "dot-case": "^3.0.4",
+        "tslib": "^2.0.3"
+      }
+    },
+    "node_modules/snakecase-keys": {
+      "version": "5.5.0",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "map-obj": "^4.1.0",
+        "snake-case": "^3.0.4",
+        "type-fest": "^3.12.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/source-map": {
+      "version": "0.6.1",
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-support": {
+      "version": "0.5.21",
+      "license": "MIT",
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
+    "node_modules/sprintf-js": {
+      "version": "1.0.3",
+      "dev": true,
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/stack-utils": {
+      "version": "2.0.6",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "escape-string-regexp": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/stack-utils/node_modules/escape-string-regexp": {
+      "version": "2.0.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/statuses": {
+      "version": "1.5.0",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/store2": {
+      "version": "2.14.3",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/string_decoder": {
+      "version": "1.3.0",
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "~5.2.0"
+      }
+    },
+    "node_modules/string-length": {
+      "version": "4.0.2",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "char-regex": "^1.0.2",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/string-width": {
+      "version": "4.2.3",
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-bom": {
+      "version": "4.0.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-final-newline": {
+      "version": "2.0.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/strip-hex-prefix": {
+      "version": "1.0.0",
+      "license": "MIT",
+      "dependencies": {
+        "is-hex-prefixed": "1.0.0"
+      },
+      "engines": {
+        "node": ">=6.5.0",
+        "npm": ">=3"
+      }
+    },
+    "node_modules/strip-json-comments": {
+      "version": "3.1.1",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/superstruct": {
+      "version": "0.15.5",
+      "license": "MIT"
+    },
+    "node_modules/supports-color": {
+      "version": "7.2.0",
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "devOptional": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/symbol-observable": {
+      "version": "2.0.3",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/test-exclude": {
+      "version": "6.0.0",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "@istanbuljs/schema": "^0.1.2",
+        "glob": "^7.1.4",
+        "minimatch": "^3.0.4"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/text-encoding-utf-8": {
+      "version": "1.0.2"
+    },
+    "node_modules/through": {
+      "version": "2.3.8",
+      "license": "MIT"
+    },
+    "node_modules/through2": {
+      "version": "2.0.5",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "readable-stream": "~2.3.6",
+        "xtend": "~4.0.1"
+      }
+    },
+    "node_modules/through2/node_modules/isarray": {
+      "version": "1.0.0",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/through2/node_modules/readable-stream": {
+      "version": "2.3.8",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      }
+    },
+    "node_modules/through2/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/through2/node_modules/string_decoder": {
+      "version": "1.1.1",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "node_modules/tiny-secp256k1": {
+      "version": "1.1.6",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "dependencies": {
+        "bindings": "^1.3.0",
+        "bn.js": "^4.11.8",
+        "create-hmac": "^1.1.7",
+        "elliptic": "^6.4.0",
+        "nan": "^2.13.2"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/tiny-secp256k1/node_modules/bn.js": {
+      "version": "4.12.0",
+      "license": "MIT"
+    },
+    "node_modules/tmp": {
+      "version": "0.2.1",
+      "license": "MIT",
+      "dependencies": {
+        "rimraf": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8.17.0"
+      }
+    },
+    "node_modules/tmpl": {
+      "version": "1.0.5",
+      "dev": true,
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/to-fast-properties": {
+      "version": "2.0.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/toidentifier": {
+      "version": "1.0.1",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/toml": {
+      "version": "3.0.0",
+      "license": "MIT"
+    },
+    "node_modules/tr46": {
+      "version": "0.0.3",
+      "license": "MIT"
+    },
+    "node_modules/ts-invariant": {
+      "version": "0.10.3",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ts-jest": {
+      "version": "29.0.5",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "bs-logger": "0.x",
+        "fast-json-stable-stringify": "2.x",
+        "jest-util": "^29.0.0",
+        "json5": "^2.2.3",
+        "lodash.memoize": "4.x",
+        "make-error": "1.x",
+        "semver": "7.x",
+        "yargs-parser": "^21.0.1"
+      },
+      "bin": {
+        "ts-jest": "cli.js"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "@babel/core": ">=7.0.0-beta.0 <8",
+        "@jest/types": "^29.0.0",
+        "babel-jest": "^29.0.0",
+        "jest": "^29.0.0",
+        "typescript": ">=4.3"
+      },
+      "peerDependenciesMeta": {
+        "@babel/core": {
+          "optional": true
+        },
+        "@jest/types": {
+          "optional": true
+        },
+        "babel-jest": {
+          "optional": true
+        },
+        "esbuild": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/ts-node": {
+      "version": "10.9.1",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@cspotcode/source-map-support": "^0.8.0",
+        "@tsconfig/node10": "^1.0.7",
+        "@tsconfig/node12": "^1.0.7",
+        "@tsconfig/node14": "^1.0.0",
+        "@tsconfig/node16": "^1.0.2",
+        "acorn": "^8.4.1",
+        "acorn-walk": "^8.1.1",
+        "arg": "^4.1.0",
+        "create-require": "^1.1.0",
+        "diff": "^4.0.1",
+        "make-error": "^1.1.1",
+        "v8-compile-cache-lib": "^3.0.1",
+        "yn": "3.1.1"
+      },
+      "bin": {
+        "ts-node": "dist/bin.js",
+        "ts-node-cwd": "dist/bin-cwd.js",
+        "ts-node-esm": "dist/bin-esm.js",
+        "ts-node-script": "dist/bin-script.js",
+        "ts-node-transpile-only": "dist/bin-transpile.js",
+        "ts-script": "dist/bin-script-deprecated.js"
+      },
+      "peerDependencies": {
+        "@swc/core": ">=1.2.50",
+        "@swc/wasm": ">=1.2.50",
+        "@types/node": "*",
+        "typescript": ">=2.7"
+      },
+      "peerDependenciesMeta": {
+        "@swc/core": {
+          "optional": true
+        },
+        "@swc/wasm": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/tslib": {
+      "version": "2.4.1",
+      "license": "0BSD"
+    },
+    "node_modules/tweetnacl": {
+      "version": "1.0.3",
+      "license": "Unlicense"
+    },
+    "node_modules/tweetnacl-util": {
+      "version": "0.15.1",
+      "license": "Unlicense",
+      "optional": true
+    },
+    "node_modules/type-detect": {
+      "version": "4.0.8",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/type-fest": {
+      "version": "3.13.1",
+      "license": "(MIT OR CC0-1.0)",
+      "optional": true,
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/typeforce": {
+      "version": "1.18.0",
+      "license": "MIT"
+    },
+    "node_modules/typescript": {
+      "version": "4.9.4",
+      "dev": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=4.2.0"
+      }
+    },
+    "node_modules/u3": {
+      "version": "0.1.1",
+      "license": "MIT"
+    },
+    "node_modules/untildify": {
+      "version": "4.0.0",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.0.10",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "escalade": "^3.1.1",
+        "picocolors": "^1.0.0"
+      },
+      "bin": {
+        "browserslist-lint": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
+    "node_modules/utf-8-validate": {
+      "version": "5.0.10",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "dependencies": {
+        "node-gyp-build": "^4.3.0"
+      },
+      "engines": {
+        "node": ">=6.14.2"
+      }
+    },
+    "node_modules/utf8": {
+      "version": "3.0.0",
+      "license": "MIT"
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "license": "MIT"
+    },
+    "node_modules/uuid": {
+      "version": "8.3.2",
+      "license": "MIT",
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
+    "node_modules/v8-compile-cache-lib": {
+      "version": "3.0.1",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/v8-to-istanbul": {
+      "version": "9.0.1",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "@jridgewell/trace-mapping": "^0.3.12",
+        "@types/istanbul-lib-coverage": "^2.0.1",
+        "convert-source-map": "^1.6.0"
+      },
+      "engines": {
+        "node": ">=10.12.0"
+      }
+    },
+    "node_modules/v8-to-istanbul/node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.17",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "3.1.0",
+        "@jridgewell/sourcemap-codec": "1.4.14"
+      }
+    },
+    "node_modules/v8-to-istanbul/node_modules/convert-source-map": {
+      "version": "1.9.0",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/vlq": {
+      "version": "2.0.4",
+      "license": "MIT"
+    },
+    "node_modules/walker": {
+      "version": "1.0.8",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "makeerror": "1.0.12"
+      }
+    },
+    "node_modules/web3-eth-abi": {
+      "version": "1.8.1",
+      "license": "LGPL-3.0",
+      "dependencies": {
+        "@ethersproject/abi": "^5.6.3",
+        "web3-utils": "1.8.1"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/web3-utils": {
+      "version": "1.8.1",
+      "license": "LGPL-3.0",
+      "dependencies": {
+        "bn.js": "^5.2.1",
+        "ethereum-bloom-filters": "^1.0.6",
+        "ethereumjs-util": "^7.1.0",
+        "ethjs-unit": "0.1.6",
+        "number-to-bn": "1.7.0",
+        "randombytes": "^2.1.0",
+        "utf8": "3.0.0"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/webidl-conversions": {
+      "version": "3.0.1",
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/whatwg-url": {
+      "version": "5.0.0",
+      "license": "MIT",
+      "dependencies": {
+        "tr46": "~0.0.3",
+        "webidl-conversions": "^3.0.0"
+      }
+    },
+    "node_modules/which": {
+      "version": "2.0.2",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/which-module": {
+      "version": "2.0.0",
+      "license": "ISC"
+    },
+    "node_modules/wif": {
+      "version": "2.0.6",
+      "license": "MIT",
+      "dependencies": {
+        "bs58check": "<3.0.0"
+      }
+    },
+    "node_modules/wrap-ansi": {
+      "version": "7.0.0",
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "license": "ISC"
+    },
+    "node_modules/write-file-atomic": {
+      "version": "5.0.0",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "imurmurhash": "^0.1.4",
+        "signal-exit": "^3.0.7"
+      },
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/ws": {
+      "version": "7.5.9",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.3.0"
+      },
+      "peerDependencies": {
+        "bufferutil": "^4.0.1",
+        "utf-8-validate": "^5.0.2"
+      },
+      "peerDependenciesMeta": {
+        "bufferutil": {
+          "optional": true
+        },
+        "utf-8-validate": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/xstream": {
+      "version": "11.14.0",
+      "license": "MIT",
+      "dependencies": {
+        "globalthis": "^1.0.1",
+        "symbol-observable": "^2.0.3"
+      }
+    },
+    "node_modules/xtend": {
+      "version": "4.0.2",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=0.4"
+      }
+    },
+    "node_modules/y18n": {
+      "version": "5.0.8",
+      "license": "ISC",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yallist": {
+      "version": "4.0.0",
+      "license": "ISC"
+    },
+    "node_modules/yargs": {
+      "version": "17.6.2",
+      "license": "MIT",
+      "dependencies": {
+        "cliui": "^8.0.1",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.3",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^21.1.1"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "21.1.1",
+      "license": "ISC",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/yn": {
+      "version": "3.1.1",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/yocto-queue": {
+      "version": "0.1.0",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/zen-observable": {
+      "version": "0.8.15",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/zen-observable-ts": {
+      "version": "1.2.5",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "zen-observable": "0.8.15"
+      }
+    }
+  }
+}

+ 33 - 0
testing/contract-integrations/custom_consistency_level/package.json

@@ -0,0 +1,33 @@
+{
+  "name": "@wormhole-foundation/test-custom-consistency-level",
+  "version": "0.0.1",
+  "description": "scripts for testing the custom consistency contract",
+  "scripts": {
+    "test-custom-consistency-level": "jest test_custom_consistency_level.ts --verbose --setupFiles ./ci-config.js"
+  },
+  "keywords": [],
+  "author": "",
+  "dependencies": {
+    "@certusone/wormhole-sdk": "0.10.10",
+    "@cosmjs/cosmwasm-stargate": "0.29.5",
+    "@improbable-eng/grpc-web-node-http-transport": "0.15.0",
+    "cosmwasm": "1.1.1",
+    "dotenv": "16.0.3",
+    "elliptic": "^6.6.1",
+    "ethers": "5.7.2",
+    "js-sha3": "0.8.0",
+    "web3-eth-abi": "1.8.1",
+    "yargs": "17.6.2"
+  },
+  "devDependencies": {
+    "@types/elliptic": "6.4.14",
+    "@types/jest": "^29.4.0",
+    "jest": "29.4.1",
+    "ts-jest": "29.0.5",
+    "ts-node": "10.9.1",
+    "typescript": "4.9.4"
+  },
+  "overrides": {
+    "elliptic": "^6.6.1"
+  }
+}

+ 9 - 0
testing/contract-integrations/custom_consistency_level/test_custom_consistency_level.sh

@@ -0,0 +1,9 @@
+#!/bin/sh
+set -e
+num=${NUM_GUARDIANS:-1} # default value for NUM_GUARDIANS = 1
+for ((i=0; i<num; i++)); do
+    while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' guardian-$i.guardian:6060/readyz)" != "200" ]]; do sleep 5; done
+done
+cd contract-integrations/custom_consistency_level
+npm ci
+CI=true npm run test-custom-consistency-level

+ 14 - 0
testing/contract-integrations/custom_consistency_level/tsconfig.json

@@ -0,0 +1,14 @@
+{
+  "compilerOptions": {
+    "outDir": "lib",
+    "target": "es5",
+    "module": "commonjs",
+    "moduleResolution": "node",
+    "lib": ["es2019"],
+    "skipLibCheck": true,
+    "resolveJsonModule": true,
+    "allowJs": true
+  },
+  "include": ["./src"],
+  "exclude": ["node_modules", "ethers-contracts"]
+}

+ 33 - 0
whitepapers/0001_generic_message_passing.md

@@ -189,12 +189,45 @@ level meanings and enforcing them.
 
 
 - `200` - publish immediately
 - `200` - publish immediately
 - `201` - `safe`, if available, otherwise falls back to `finalized`
 - `201` - `safe`, if available, otherwise falls back to `finalized`
+- `202` - `finalized`
+- `203` - custom handling
 - anything else is treated as `finalized`
 - anything else is treated as `finalized`
 
 
 Historically, the EVM watcher specified the consistency level as the block depth (from `latest`) the transaction
 Historically, the EVM watcher specified the consistency level as the block depth (from `latest`) the transaction
 should reach before publishing. However, since [The Merge](https://ethereum.org/en/roadmap/merge/), adoption of
 should reach before publishing. However, since [The Merge](https://ethereum.org/en/roadmap/merge/), adoption of
 `safe` and `finalized` block tags have become widespread and offer a more exact measure of commitment.
 `safe` and `finalized` block tags have become widespread and offer a more exact measure of commitment.
 
 
+### Custom Handling
+
+The consistency level of 203 indicates that the integrator desires special handling. When the watcher sees this value,
+it reads the `CustomConsistencyLevel` on-chain contract, using the emitter address as the key to determine the
+special handling to be performed. If the emitter address is not configured in the contract, then the observation
+is treated as though it had consistency level 202 (finalized).
+
+#### Additional Blocks handling
+
+Currently, the only supported custom handling is to wait the configured number of additional blocks after the specified
+consistency level. For instance, if the integrator has configured their emitter address in the `CustomConsistencyLevel`
+contract as consistencyLevel == `201` and additional blocks == 5, then the watcher will not approve the observation until
+five safe blocks after when the observation block is marked safe.
+
+##### Usage on chains that publish bursts
+
+Since safe and finalized blocks on Ethereum advance in bursts, rather than one-by-one, it probably does not make sense to use
+this feature for safe or finalized. Either "safe plus two" will happen at the same time as the observed block is marked safe,
+or it will wait until the next burst, which could be an arbitrarily long time.
+
+However, this feature might be useful on Ethereum to wait X blocks after the block is published as latest. For instance,
+if an integrator has configured their emitter address in the `CustomConsistencyLevel` contract as consistencyLevel == `200`
+and additional blocks == 2, the observation would get published two blocks after the observed block.
+
+##### Usage on chains that publish incrementally
+
+On chains like Hyper EVM, where safe and finalized are published regularly, this feature might be useful to wait X blocks
+after the block is published as safe or finalized, since that would happen in a predictable fashion. For instance,
+if an integrator has configured their emitter address in the `CustomConsistencyLevel` contract as consistencyLevel == `201`
+and additional blocks == 2, the observation would get published two safe blocks after the observed block is marked safe.
+
 #### Solana
 #### Solana
 
 
 The Solana core contract provides an enum for `ConsistencyLevel` used by the instruction data:
 The Solana core contract provides an enum for `ConsistencyLevel` used by the instruction data: