浏览代码

feat(target_chains/sui): add iota network (#2428)

* chore(target_chains/sui): vendor wormhole dependencies for iota

* chore(target_chains/sui): add new chain ids for new networks

* chore(target_chains/sui): add iota cli and sdk packages with no change

* chore(target_chains/sui): update iota_testnet move.toml and use iota libs

* feat(target_chains/sui): add iota js sdk

* feat(contract_manager): add support for iota

* feat(target_chains/sui): add iota cli lib

* chore(target_chains/sui): add some misc files

math lib is deprecated.

* fix: address feedbacks

* fix: remove any
Ali Behjati 8 月之前
父节点
当前提交
f61d4dd546
共有 100 个文件被更改,包括 12656 次插入126 次删除
  1. 2 0
      contract_manager/package.json
  2. 2 0
      contract_manager/scripts/sync_wormhole_guardian_set.ts
  3. 80 6
      contract_manager/src/chains.ts
  4. 1 0
      contract_manager/src/contracts/index.ts
  5. 565 0
      contract_manager/src/contracts/iota.ts
  6. 9 14
      contract_manager/src/contracts/sui.ts
  7. 7 0
      contract_manager/src/store.ts
  8. 5 0
      contract_manager/store/chains/IotaChains.yaml
  9. 4 0
      contract_manager/store/contracts/IotaPriceFeedContracts.yaml
  10. 3 0
      contract_manager/store/contracts/IotaWormholeContracts.yaml
  11. 7 1
      contract_manager/store/contracts/SuiWormholeContracts.yaml
  12. 1 0
      governance/xc_admin/packages/xc_admin_common/src/chains.ts
  13. 407 74
      pnpm-lock.yaml
  14. 2 0
      pnpm-workspace.yaml
  15. 1 0
      target_chains/sui/cli-iota/.gitignore
  16. 69 0
      target_chains/sui/cli-iota/README.md
  17. 27 0
      target_chains/sui/cli-iota/package.json
  18. 288 0
      target_chains/sui/cli-iota/src/cli.ts
  19. 185 0
      target_chains/sui/cli-iota/src/pyth_deploy.ts
  20. 115 0
      target_chains/sui/cli-iota/src/upgrade_pyth.ts
  21. 9 0
      target_chains/sui/cli-iota/tsconfig.json
  22. 7 16
      target_chains/sui/cli/src/cli.ts
  23. 24 12
      target_chains/sui/cli/src/pyth_deploy.ts
  24. 15 0
      target_chains/sui/contracts/Move.iota_testnet.toml
  25. 36 0
      target_chains/sui/iota-patch-libs.sh
  26. 9 0
      target_chains/sui/sdk/js-iota/.eslintrc.js
  27. 1 0
      target_chains/sui/sdk/js-iota/.gitignore
  28. 155 0
      target_chains/sui/sdk/js-iota/README.md
  29. 5 0
      target_chains/sui/sdk/js-iota/jest.config.js
  30. 59 0
      target_chains/sui/sdk/js-iota/package.json
  31. 21 0
      target_chains/sui/sdk/js-iota/src/IotaPriceServiceConnection.ts
  32. 304 0
      target_chains/sui/sdk/js-iota/src/client.ts
  33. 97 0
      target_chains/sui/sdk/js-iota/src/examples/IotaRelay.ts
  34. 11 0
      target_chains/sui/sdk/js-iota/src/index.ts
  35. 14 0
      target_chains/sui/sdk/js-iota/tsconfig.json
  36. 3 3
      target_chains/sui/vendor/README.md
  37. 2 0
      target_chains/sui/vendor/wormhole_iota_testnet/.gitignore
  38. 13 0
      target_chains/sui/vendor/wormhole_iota_testnet/Docker.md
  39. 33 0
      target_chains/sui/vendor/wormhole_iota_testnet/Dockerfile
  40. 24 0
      target_chains/sui/vendor/wormhole_iota_testnet/Dockerfile.base
  41. 15 0
      target_chains/sui/vendor/wormhole_iota_testnet/Makefile
  42. 114 0
      target_chains/sui/vendor/wormhole_iota_testnet/NOTES.md
  43. 130 0
      target_chains/sui/vendor/wormhole_iota_testnet/README.md
  44. 125 0
      target_chains/sui/vendor/wormhole_iota_testnet/devnet/127.0.0.1-36219.yaml
  45. 125 0
      target_chains/sui/vendor/wormhole_iota_testnet/devnet/127.0.0.1-36853.yaml
  46. 125 0
      target_chains/sui/vendor/wormhole_iota_testnet/devnet/127.0.0.1-39101.yaml
  47. 125 0
      target_chains/sui/vendor/wormhole_iota_testnet/devnet/127.0.0.1-39187.yaml
  48. 12 0
      target_chains/sui/vendor/wormhole_iota_testnet/devnet/client.yaml
  49. 34 0
      target_chains/sui/vendor/wormhole_iota_testnet/devnet/fullnode.yaml
  50. 二进制
      target_chains/sui/vendor/wormhole_iota_testnet/devnet/genesis.blob
  51. 55 0
      target_chains/sui/vendor/wormhole_iota_testnet/devnet/genesis_config
  52. 499 0
      target_chains/sui/vendor/wormhole_iota_testnet/devnet/network.yaml
  53. 1 0
      target_chains/sui/vendor/wormhole_iota_testnet/examples/coins/.gitignore
  54. 15 0
      target_chains/sui/vendor/wormhole_iota_testnet/examples/coins/Makefile
  55. 17 0
      target_chains/sui/vendor/wormhole_iota_testnet/examples/coins/Move.devnet.toml
  56. 52 0
      target_chains/sui/vendor/wormhole_iota_testnet/examples/coins/Move.lock
  57. 28 0
      target_chains/sui/vendor/wormhole_iota_testnet/examples/coins/Move.toml
  58. 210 0
      target_chains/sui/vendor/wormhole_iota_testnet/examples/coins/sources/coin.move
  59. 72 0
      target_chains/sui/vendor/wormhole_iota_testnet/examples/coins/sources/coin_10.move
  60. 72 0
      target_chains/sui/vendor/wormhole_iota_testnet/examples/coins/sources/coin_8.move
  61. 20 0
      target_chains/sui/vendor/wormhole_iota_testnet/examples/core_messages/Makefile
  62. 14 0
      target_chains/sui/vendor/wormhole_iota_testnet/examples/core_messages/Move.devnet.toml
  63. 39 0
      target_chains/sui/vendor/wormhole_iota_testnet/examples/core_messages/Move.lock
  64. 21 0
      target_chains/sui/vendor/wormhole_iota_testnet/examples/core_messages/Move.toml
  65. 149 0
      target_chains/sui/vendor/wormhole_iota_testnet/examples/core_messages/sources/sender.move
  66. 3 0
      target_chains/sui/vendor/wormhole_iota_testnet/examples/templates/README.md
  67. 19 0
      target_chains/sui/vendor/wormhole_iota_testnet/examples/templates/wrapped_coin/Move.toml
  68. 21 0
      target_chains/sui/vendor/wormhole_iota_testnet/examples/templates/wrapped_coin/sources/coin.move
  69. 119 0
      target_chains/sui/vendor/wormhole_iota_testnet/scripts/deploy.sh
  70. 11 0
      target_chains/sui/vendor/wormhole_iota_testnet/scripts/node_builder.sh
  71. 22 0
      target_chains/sui/vendor/wormhole_iota_testnet/scripts/register_devnet.sh
  72. 3 0
      target_chains/sui/vendor/wormhole_iota_testnet/scripts/setup_rust.sh
  73. 5 0
      target_chains/sui/vendor/wormhole_iota_testnet/scripts/start_node.sh
  74. 31 0
      target_chains/sui/vendor/wormhole_iota_testnet/scripts/switch.sh
  75. 6 0
      target_chains/sui/vendor/wormhole_iota_testnet/scripts/wait_for_devnet.sh
  76. 4 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/.gitignore
  77. 13 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/Makefile
  78. 78 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/js/00_environment.ts
  79. 109 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/js/01_wormhole.ts
  80. 32 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/js/helpers/build.ts
  81. 40 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/js/helpers/consts.ts
  82. 42 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/js/helpers/error/moveAbort.ts
  83. 22 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/js/helpers/error/wormhole.ts
  84. 75 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/js/helpers/setup.ts
  85. 73 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/js/helpers/upgrade.ts
  86. 27 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/js/helpers/utils.ts
  87. 31 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/js/helpers/wormhole/testPublishMessage.ts
  88. 5917 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/package-lock.json
  89. 22 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/package.json
  90. 35 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/run_integration_test.sh
  91. 300 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/scripts/upgrade-token-bridge.ts
  92. 267 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/scripts/upgrade-wormhole.ts
  93. 12 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/sui_config/client.yaml
  94. 53 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/sui_config/fullnode.yaml
  95. 二进制
      target_chains/sui/vendor/wormhole_iota_testnet/testing/sui_config/genesis.blob
  96. 323 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/sui_config/network.yaml
  97. 7 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/sui_config/sui.keystore
  98. 81 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/sui_config/validator-config-0.yaml
  99. 81 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/sui_config/validator-config-1.yaml
  100. 81 0
      target_chains/sui/vendor/wormhole_iota_testnet/testing/sui_config/validator-config-2.yaml

+ 2 - 0
contract_manager/package.json

@@ -26,6 +26,7 @@
     "@cosmjs/cosmwasm-stargate": "^0.32.3",
     "@cosmjs/stargate": "^0.32.3",
     "@injectivelabs/networks": "^1.14.6",
+    "@iota/iota-sdk": "^0.5.0",
     "@mysten/sui": "^1.3.0",
     "@pythnetwork/client": "catalog:",
     "@pythnetwork/cosmwasm-deploy-tools": "workspace:*",
@@ -36,6 +37,7 @@
     "@pythnetwork/pyth-sdk-solidity": "workspace:^",
     "@pythnetwork/pyth-starknet-js": "^0.2.1",
     "@pythnetwork/pyth-sui-js": "workspace:*",
+    "@pythnetwork/pyth-iota-js": "workspace:*",
     "@pythnetwork/pyth-ton": "workspace:*",
     "@pythnetwork/pyth-ton-js": "workspace:*",
     "@pythnetwork/solana-utils": "workspace:^",

+ 2 - 0
contract_manager/scripts/sync_wormhole_guardian_set.ts

@@ -5,6 +5,7 @@ import {
   CosmWasmPriceFeedContract,
   DefaultStore,
   EvmPriceFeedContract,
+  IotaWormholeContract,
   SuiWormholeContract,
   toPrivateKey,
 } from "../src";
@@ -32,6 +33,7 @@ async function main() {
   for (const contract of Object.values(DefaultStore.wormhole_contracts)) {
     if (
       contract instanceof SuiWormholeContract ||
+      contract instanceof IotaWormholeContract ||
       contract instanceof AptosWormholeContract
     ) {
       if (chains && !chains.includes(contract.getChain().getId())) {

+ 80 - 6
contract_manager/src/chains.ts

@@ -20,8 +20,10 @@ import {
   InjectiveExecutor,
 } from "@pythnetwork/cosmwasm-deploy-tools";
 import { Network } from "@injectivelabs/networks";
+import { IotaClient } from "@iota/iota-sdk/client";
 import { SuiClient } from "@mysten/sui/client";
-import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";
+import { Ed25519Keypair as IotaEd25519Keypair } from "@iota/iota-sdk/keypairs/ed25519";
+import { Ed25519Keypair as SuiEd25519Keypair } from "@mysten/sui/keypairs/ed25519";
 import { TokenId } from "./token";
 import { BN, Provider, Wallet, WalletUnlocked } from "fuels";
 import { FUEL_ETH_ASSET_ID } from "@pythnetwork/pyth-fuel-js";
@@ -38,6 +40,8 @@ import { keyPairFromSeed } from "@ton/crypto";
 import { PythContract } from "@pythnetwork/pyth-ton-js";
 import * as nearAPI from "near-api-js";
 import * as bs58 from "bs58";
+import { MIST_PER_SUI } from "@mysten/sui/utils";
+import { NANOS_PER_IOTA } from "@iota/iota-sdk/utils";
 import * as chains from "viem/chains";
 
 /**
@@ -337,8 +341,8 @@ export class SuiChain extends Chain {
   }
 
   async getAccountAddress(privateKey: PrivateKey): Promise<string> {
-    const keypair = Ed25519Keypair.fromSecretKey(
-      Buffer.from(privateKey, "hex")
+    const keypair = SuiEd25519Keypair.fromSecretKey(
+      new Uint8Array(Buffer.from(privateKey, "hex"))
     );
     return keypair.toSuiAddress();
   }
@@ -348,7 +352,73 @@ export class SuiChain extends Chain {
     const balance = await provider.getBalance({
       owner: await this.getAccountAddress(privateKey),
     });
-    return Number(balance.totalBalance) / 10 ** 9;
+    return Number(balance.totalBalance) / Number(MIST_PER_SUI);
+  }
+}
+
+export class IotaChain extends Chain {
+  static type = "IotaChain";
+
+  constructor(
+    id: string,
+    mainnet: boolean,
+    wormholeChainName: string,
+    nativeToken: TokenId | undefined,
+    public rpcUrl: string
+  ) {
+    super(id, mainnet, wormholeChainName, nativeToken);
+  }
+
+  static fromJson(parsed: ChainConfig): IotaChain {
+    if (parsed.type !== IotaChain.type) throw new Error("Invalid type");
+    return new IotaChain(
+      parsed.id,
+      parsed.mainnet,
+      parsed.wormholeChainName,
+      parsed.nativeToken,
+      parsed.rpcUrl
+    );
+  }
+
+  toJson(): KeyValueConfig {
+    return {
+      id: this.id,
+      wormholeChainName: this.wormholeChainName,
+      mainnet: this.mainnet,
+      rpcUrl: this.rpcUrl,
+      type: IotaChain.type,
+    };
+  }
+
+  getType(): string {
+    return IotaChain.type;
+  }
+
+  /**
+   * Returns the payload for a governance contract upgrade instruction for contracts deployed on this chain
+   * @param digest hex string of the 32 byte digest for the new package without the 0x prefix
+   */
+  generateGovernanceUpgradePayload(digest: string): Buffer {
+    return new UpgradeContract256Bit(this.wormholeChainName, digest).encode();
+  }
+
+  getProvider(): IotaClient {
+    return new IotaClient({ url: this.rpcUrl });
+  }
+
+  async getAccountAddress(privateKey: PrivateKey): Promise<string> {
+    const keypair = IotaEd25519Keypair.fromSecretKey(
+      new Uint8Array(Buffer.from(privateKey, "hex"))
+    );
+    return keypair.toIotaAddress();
+  }
+
+  async getAccountBalance(privateKey: PrivateKey): Promise<number> {
+    const provider = this.getProvider();
+    const balance = await provider.getBalance({
+      owner: await this.getAccountAddress(privateKey),
+    });
+    return Number(balance.totalBalance) / Number(NANOS_PER_IOTA);
   }
 }
 
@@ -932,7 +1002,9 @@ export class NearChain extends Chain {
 
   async getAccountAddress(privateKey: PrivateKey): Promise<string> {
     return Buffer.from(
-      Ed25519Keypair.fromSecretKey(Buffer.from(privateKey, "hex"))
+      SuiEd25519Keypair.fromSecretKey(
+        new Uint8Array(Buffer.from(privateKey, "hex"))
+      )
         .getPublicKey()
         .toRawBytes()
     ).toString("hex");
@@ -951,7 +1023,9 @@ export class NearChain extends Chain {
   ): Promise<nearAPI.Account> {
     const keyStore = new nearAPI.keyStores.InMemoryKeyStore();
     if (typeof senderPrivateKey !== "undefined") {
-      const key = bs58.encode(Buffer.from(senderPrivateKey, "hex"));
+      const key = bs58.encode(
+        new Uint8Array(Buffer.from(senderPrivateKey, "hex"))
+      );
       const keyPair = nearAPI.KeyPair.fromString(key);
       const address = await this.getAccountAddress(senderPrivateKey);
       await keyStore.setKey(this.networkId, address, keyPair);

+ 1 - 0
contract_manager/src/contracts/index.ts

@@ -3,6 +3,7 @@ export * from "./cosmwasm";
 export * from "./evm";
 export * from "./fuel";
 export * from "./sui";
+export * from "./iota";
 export * from "./wormhole";
 export * from "./evm_abis";
 export * from "./ton";

+ 565 - 0
contract_manager/src/contracts/iota.ts

@@ -0,0 +1,565 @@
+import { Chain, IotaChain } from "../chains";
+import { DataSource } from "@pythnetwork/xc-admin-common";
+import { WormholeContract } from "./wormhole";
+import { PriceFeedContract, PrivateKey, TxResult } from "../base";
+import { IotaPythClient } from "@pythnetwork/pyth-iota-js";
+import { IOTA_CLOCK_OBJECT_ID } from "@iota/iota-sdk/utils";
+import { Ed25519Keypair } from "@iota/iota-sdk/keypairs/ed25519";
+import { Transaction } from "@iota/iota-sdk/transactions";
+import { uint8ArrayToBCS } from "@certusone/wormhole-sdk/lib/cjs/sui";
+
+type ObjectId = string;
+
+export class IotaPriceFeedContract extends PriceFeedContract {
+  static type = "IotaPriceFeedContract";
+  private client: IotaPythClient;
+
+  /**
+   * Given the ids of the pyth state and wormhole state, create a new IotaPriceFeedContract
+   * The package ids are derived based on the state ids
+   *
+   * @param chain the chain which this contract is deployed on
+   * @param stateId id of the pyth state for the deployed contract
+   * @param wormholeStateId id of the wormhole state for the wormhole contract that pyth binds to
+   */
+  constructor(
+    public chain: IotaChain,
+    public stateId: string,
+    public wormholeStateId: string
+  ) {
+    super();
+    this.client = new IotaPythClient(
+      this.getProvider(),
+      this.stateId,
+      this.wormholeStateId
+    );
+  }
+
+  static fromJson(
+    chain: Chain,
+    parsed: { type: string; stateId: string; wormholeStateId: string }
+  ): IotaPriceFeedContract {
+    if (parsed.type !== IotaPriceFeedContract.type)
+      throw new Error("Invalid type");
+    if (!(chain instanceof IotaChain))
+      throw new Error(`Wrong chain type ${chain}`);
+    return new IotaPriceFeedContract(
+      chain,
+      parsed.stateId,
+      parsed.wormholeStateId
+    );
+  }
+
+  getType(): string {
+    return IotaPriceFeedContract.type;
+  }
+
+  getChain(): IotaChain {
+    return this.chain;
+  }
+
+  toJson() {
+    return {
+      chain: this.chain.getId(),
+      stateId: this.stateId,
+      wormholeStateId: this.wormholeStateId,
+      type: IotaPriceFeedContract.type,
+    };
+  }
+
+  /**
+   * Given a objectId, returns the id for the package that the object belongs to.
+   * @param objectId
+   */
+  async getPackageId(objectId: ObjectId): Promise<ObjectId> {
+    return this.client.getPackageId(objectId);
+  }
+
+  async getPythPackageId(): Promise<ObjectId> {
+    return await this.getPackageId(this.stateId);
+  }
+
+  async getWormholePackageId(): Promise<ObjectId> {
+    return await this.getPackageId(this.wormholeStateId);
+  }
+
+  getId(): string {
+    return `${this.chain.getId()}_${this.stateId}`;
+  }
+
+  private async parsePrice(priceInfo: {
+    type: string;
+    fields: {
+      expo: { fields: { magnitude: string; negative: boolean } };
+      price: { fields: { magnitude: string; negative: boolean } };
+      conf: string;
+      timestamp: string;
+    };
+  }) {
+    let expo = priceInfo.fields.expo.fields.magnitude;
+    if (priceInfo.fields.expo.fields.negative) expo = "-" + expo;
+    let price = priceInfo.fields.price.fields.magnitude;
+    if (priceInfo.fields.price.fields.negative) price = "-" + price;
+    return {
+      conf: priceInfo.fields.conf,
+      publishTime: priceInfo.fields.timestamp,
+      expo,
+      price,
+    };
+  }
+
+  async getPriceFeed(feedId: string) {
+    const provider = this.getProvider();
+    const priceInfoObjectId = await this.client.getPriceFeedObjectId(feedId);
+    if (!priceInfoObjectId) return undefined;
+    const priceInfo = await provider.getObject({
+      id: priceInfoObjectId,
+      options: { showContent: true },
+    });
+    if (!priceInfo.data || !priceInfo.data.content) {
+      throw new Error(
+        `Price feed ID ${priceInfoObjectId} in price table but object not found!!`
+      );
+    }
+    if (priceInfo.data.content.dataType !== "moveObject") {
+      throw new Error(
+        `Expected ${priceInfoObjectId} to be a moveObject (PriceInfoObject)`
+      );
+    }
+    return {
+      emaPrice: await this.parsePrice(
+        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+        // @ts-ignore
+        priceInfo.data.content.fields.price_info.fields.price_feed.fields
+          .ema_price
+      ),
+      price: await this.parsePrice(
+        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+        // @ts-ignore
+        priceInfo.data.content.fields.price_info.fields.price_feed.fields.price
+      ),
+    };
+  }
+
+  /**
+   * Given a signed VAA, execute the migration instruction on the pyth contract.
+   * The payload of the VAA can be obtained from the `getUpgradePackagePayload` method.
+   * @param vaa
+   * @param keypair used to sign the transaction
+   */
+  async executeMigrateInstruction(vaa: Buffer, keypair: Ed25519Keypair) {
+    const tx = new Transaction();
+    const packageId = await this.getPythPackageId();
+    const verificationReceipt = await this.getVaaVerificationReceipt(
+      tx,
+      packageId,
+      vaa
+    );
+
+    tx.moveCall({
+      target: `${packageId}::migrate::migrate`,
+      arguments: [tx.object(this.stateId), verificationReceipt],
+    });
+
+    return this.executeTransaction(tx, keypair);
+  }
+
+  async executeUpdatePriceFeed(): Promise<TxResult> {
+    // We need the feed ids to be able to execute the transaction
+    // it may be possible to get them from the VAA but in batch transactions,
+    // it is also possible to hava fewer feeds that user wants to update compared to
+    // what exists in the VAA.
+    throw new Error("Use executeUpdatePriceFeedWithFeeds instead");
+  }
+
+  async executeUpdatePriceFeedWithFeeds(
+    senderPrivateKey: string,
+    vaas: Buffer[],
+    feedIds: string[]
+  ): Promise<TxResult> {
+    const tx = new Transaction();
+    await this.client.updatePriceFeeds(tx, vaas, feedIds);
+    const keypair = Ed25519Keypair.fromSecretKey(
+      new Uint8Array(Buffer.from(senderPrivateKey, "hex"))
+    );
+    const result = await this.executeTransaction(tx, keypair);
+    return { id: result.digest, info: result };
+  }
+  async executeCreatePriceFeed(
+    senderPrivateKey: string,
+    vaas: Buffer[]
+  ): Promise<TxResult> {
+    const tx = new Transaction();
+    await this.client.createPriceFeed(tx, vaas);
+    const keypair = Ed25519Keypair.fromSecretKey(
+      new Uint8Array(Buffer.from(senderPrivateKey, "hex"))
+    );
+
+    const result = await this.executeTransaction(tx, keypair);
+    return { id: result.digest, info: result };
+  }
+
+  async executeGovernanceInstruction(
+    senderPrivateKey: PrivateKey,
+    vaa: Buffer
+  ): Promise<TxResult> {
+    const keypair = Ed25519Keypair.fromSecretKey(
+      new Uint8Array(Buffer.from(senderPrivateKey, "hex"))
+    );
+    const tx = new Transaction();
+    const packageId = await this.getPythPackageId();
+    const verificationReceipt = await this.getVaaVerificationReceipt(
+      tx,
+      packageId,
+      vaa
+    );
+
+    tx.moveCall({
+      target: `${packageId}::governance::execute_governance_instruction`,
+      arguments: [tx.object(this.stateId), verificationReceipt],
+    });
+
+    const result = await this.executeTransaction(tx, keypair);
+    return { id: result.digest, info: result };
+  }
+
+  async executeUpgradeInstruction(
+    vaa: Buffer,
+    keypair: Ed25519Keypair,
+    modules: number[][],
+    dependencies: string[]
+  ) {
+    const tx = new Transaction();
+    const packageId = await this.getPythPackageId();
+    const verificationReceipt = await this.getVaaVerificationReceipt(
+      tx,
+      packageId,
+      vaa
+    );
+
+    const [upgradeTicket] = tx.moveCall({
+      target: `${packageId}::contract_upgrade::authorize_upgrade`,
+      arguments: [tx.object(this.stateId), verificationReceipt],
+    });
+
+    const [upgradeReceipt] = tx.upgrade({
+      modules,
+      dependencies,
+      package: packageId,
+      ticket: upgradeTicket,
+    });
+
+    tx.moveCall({
+      target: `${packageId}::contract_upgrade::commit_upgrade`,
+      arguments: [tx.object(this.stateId), upgradeReceipt],
+    });
+    const result = await this.executeTransaction(tx, keypair);
+    return { id: result.digest, info: result };
+  }
+
+  /**
+   * Utility function to get the verification receipt object for a VAA that can be
+   * used to authorize a governance instruction.
+   * @param tx
+   * @param packageId pyth package id
+   * @param vaa
+   * @private
+   */
+  async getVaaVerificationReceipt(
+    tx: Transaction,
+    packageId: string,
+    vaa: Buffer
+  ) {
+    const wormholePackageId = await this.getWormholePackageId();
+
+    const [verifiedVAA] = tx.moveCall({
+      target: `${wormholePackageId}::vaa::parse_and_verify`,
+      arguments: [
+        tx.object(this.wormholeStateId),
+        tx.pure.arguments(Array.from(vaa)),
+        tx.object(IOTA_CLOCK_OBJECT_ID),
+      ],
+    });
+
+    const [verificationReceipt] = tx.moveCall({
+      target: `${packageId}::governance::verify_vaa`,
+      arguments: [tx.object(this.stateId), verifiedVAA],
+    });
+    return verificationReceipt;
+  }
+
+  /**
+   * Given a transaction block and a keypair, sign and execute it
+   * Sets the gas budget to 2x the estimated gas cost
+   * @param tx
+   * @param keypair
+   * @private
+   */
+  private async executeTransaction(tx: Transaction, keypair: Ed25519Keypair) {
+    const provider = this.getProvider();
+    tx.setSender(keypair.toIotaAddress());
+    const dryRun = await provider.dryRunTransactionBlock({
+      transactionBlock: await tx.build({ client: provider }),
+    });
+    tx.setGasBudget(BigInt(dryRun.input.gasData.budget.toString()) * BigInt(2));
+    return provider.signAndExecuteTransaction({
+      signer: keypair,
+      transaction: tx,
+      options: {
+        showEffects: true,
+        showEvents: true,
+      },
+    });
+  }
+
+  async getValidTimePeriod() {
+    const fields = await this.getStateFields();
+    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+    // @ts-ignore
+    return Number(fields.stale_price_threshold);
+  }
+
+  async getDataSources(): Promise<DataSource[]> {
+    const provider = this.getProvider();
+    const result = await provider.getDynamicFieldObject({
+      parentId: this.stateId,
+      name: {
+        type: "vector<u8>",
+        value: "data_sources",
+      },
+    });
+    if (!result.data || !result.data.content) {
+      throw new Error(
+        "Data Sources not found, contract may not be initialized"
+      );
+    }
+    if (result.data.content.dataType !== "moveObject") {
+      throw new Error("Data Sources type mismatch");
+    }
+    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+    // @ts-ignore
+    return result.data.content.fields.value.fields.keys.map(
+      ({
+        fields,
+      }: {
+        fields: {
+          emitter_address: { fields: { value: { fields: { data: string } } } };
+          emitter_chain: string;
+        };
+      }) => {
+        return {
+          emitterChain: Number(fields.emitter_chain),
+          emitterAddress: Buffer.from(
+            fields.emitter_address.fields.value.fields.data
+          ).toString("hex"),
+        };
+      }
+    );
+  }
+
+  async getGovernanceDataSource(): Promise<DataSource> {
+    const fields = await this.getStateFields();
+    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+    // @ts-ignore
+    const governanceFields = fields.governance_data_source.fields;
+    const chainId = governanceFields.emitter_chain;
+    const emitterAddress =
+      governanceFields.emitter_address.fields.value.fields.data;
+    return {
+      emitterChain: Number(chainId),
+      emitterAddress: Buffer.from(emitterAddress).toString("hex"),
+    };
+  }
+
+  async getBaseUpdateFee() {
+    const fields = await this.getStateFields();
+    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+    // @ts-ignore
+    return { amount: fields.base_update_fee };
+  }
+
+  async getLastExecutedGovernanceSequence() {
+    const fields = await this.getStateFields();
+    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+    // @ts-ignore
+    return Number(fields.last_executed_governance_sequence);
+  }
+
+  getProvider() {
+    return this.chain.getProvider();
+  }
+
+  private async getStateFields() {
+    const provider = this.getProvider();
+    const result = await provider.getObject({
+      id: this.stateId,
+      options: { showContent: true },
+    });
+    if (
+      !result.data ||
+      !result.data.content ||
+      result.data.content.dataType !== "moveObject"
+    )
+      throw new Error("Unable to fetch pyth state object");
+    return result.data.content.fields;
+  }
+}
+
+export class IotaWormholeContract extends WormholeContract {
+  public static type = "IotaWormholeContract";
+  private client: IotaPythClient;
+
+  getId(): string {
+    return `${this.chain.getId()}_${this.stateId}`;
+  }
+
+  getType(): string {
+    return IotaWormholeContract.type;
+  }
+
+  toJson() {
+    return {
+      chain: this.chain.getId(),
+      stateId: this.stateId,
+      type: IotaWormholeContract.type,
+    };
+  }
+
+  static fromJson(
+    chain: Chain,
+    parsed: {
+      type: string;
+      address: string;
+      stateId: string;
+    }
+  ): IotaWormholeContract {
+    if (parsed.type !== IotaWormholeContract.type)
+      throw new Error("Invalid type");
+    if (!(chain instanceof IotaChain))
+      throw new Error(`Wrong chain type ${chain}`);
+    return new IotaWormholeContract(chain, parsed.stateId);
+  }
+
+  constructor(public chain: IotaChain, public stateId: string) {
+    super();
+    this.client = new IotaPythClient(
+      this.chain.getProvider(),
+      // HACK:
+      // We're using the IotaPythClient to work with the Wormhole contract
+      // so there is no Pyth contract here, passing empty string to type-
+      // check.
+      "",
+      this.stateId
+    );
+  }
+
+  async getCurrentGuardianSetIndex(): Promise<number> {
+    const data = await this.getStateFields();
+    return Number(data.guardian_set_index);
+  }
+
+  // There doesn't seem to be a way to get a value out of any function call
+  // via a Iota transaction due to the linear nature of the language, this is
+  // enforced at the TransactionBlock level by only allowing you to receive
+  // receipts.
+  async getChainId(): Promise<number> {
+    return this.chain.getWormholeChainId();
+  }
+
+  // NOTE: There's no way to getChain() on the main interface, should update
+  // that interface.
+  public getChain(): IotaChain {
+    return this.chain;
+  }
+
+  async getGuardianSet(): Promise<string[]> {
+    const data = await this.getStateFields();
+    const guardian_sets = data.guardian_sets;
+    return guardian_sets;
+  }
+
+  async upgradeGuardianSets(
+    senderPrivateKey: PrivateKey,
+    vaa: Buffer
+  ): Promise<TxResult> {
+    const tx = new Transaction();
+    const coreObjectId = this.stateId;
+    const corePackageId = await this.client.getWormholePackageId();
+    const [verifiedVaa] = tx.moveCall({
+      target: `${corePackageId}::vaa::parse_and_verify`,
+      arguments: [
+        tx.object(coreObjectId),
+        tx.pure(uint8ArrayToBCS(new Uint8Array(vaa))),
+        tx.object(IOTA_CLOCK_OBJECT_ID),
+      ],
+    });
+
+    const [decreeTicket] = tx.moveCall({
+      target: `${corePackageId}::update_guardian_set::authorize_governance`,
+      arguments: [tx.object(coreObjectId)],
+    });
+
+    const [decreeReceipt] = tx.moveCall({
+      target: `${corePackageId}::governance_message::verify_vaa`,
+      arguments: [tx.object(coreObjectId), verifiedVaa, decreeTicket],
+      typeArguments: [
+        `${corePackageId}::update_guardian_set::GovernanceWitness`,
+      ],
+    });
+
+    tx.moveCall({
+      target: `${corePackageId}::update_guardian_set::update_guardian_set`,
+      arguments: [
+        tx.object(coreObjectId),
+        decreeReceipt,
+        tx.object(IOTA_CLOCK_OBJECT_ID),
+      ],
+    });
+
+    const keypair = Ed25519Keypair.fromSecretKey(
+      new Uint8Array(Buffer.from(senderPrivateKey, "hex"))
+    );
+    const result = await this.executeTransaction(tx, keypair);
+    return { id: result.digest, info: result };
+  }
+
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  private async getStateFields(): Promise<any> {
+    const provider = this.chain.getProvider();
+    const result = await provider.getObject({
+      id: this.stateId,
+      options: { showContent: true },
+    });
+    if (
+      !result.data ||
+      !result.data.content ||
+      result.data.content.dataType !== "moveObject"
+    )
+      throw new Error("Unable to fetch pyth state object");
+    return result.data.content.fields;
+  }
+
+  /**
+   * Given a transaction block and a keypair, sign and execute it
+   * Sets the gas budget to 2x the estimated gas cost
+   * @param tx
+   * @param keypair
+   * @private
+   */
+  private async executeTransaction(tx: Transaction, keypair: Ed25519Keypair) {
+    const provider = this.chain.getProvider();
+    tx.setSender(keypair.toIotaAddress());
+    const dryRun = await provider.dryRunTransactionBlock({
+      transactionBlock: await tx.build({ client: provider }),
+    });
+    tx.setGasBudget(BigInt(dryRun.input.gasData.budget.toString()) * BigInt(2));
+    return provider.signAndExecuteTransaction({
+      signer: keypair,
+      transaction: tx,
+      options: {
+        showEffects: true,
+        showEvents: true,
+      },
+    });
+  }
+}

+ 9 - 14
contract_manager/src/contracts/sui.ts

@@ -180,7 +180,7 @@ export class SuiPriceFeedContract extends PriceFeedContract {
     const tx = new Transaction();
     await this.client.updatePriceFeeds(tx, vaas, feedIds);
     const keypair = Ed25519Keypair.fromSecretKey(
-      Buffer.from(senderPrivateKey, "hex")
+      new Uint8Array(Buffer.from(senderPrivateKey, "hex"))
     );
     const result = await this.executeTransaction(tx, keypair);
     return { id: result.digest, info: result };
@@ -192,7 +192,7 @@ export class SuiPriceFeedContract extends PriceFeedContract {
     const tx = new Transaction();
     await this.client.createPriceFeed(tx, vaas);
     const keypair = Ed25519Keypair.fromSecretKey(
-      Buffer.from(senderPrivateKey, "hex")
+      new Uint8Array(Buffer.from(senderPrivateKey, "hex"))
     );
 
     const result = await this.executeTransaction(tx, keypair);
@@ -204,7 +204,7 @@ export class SuiPriceFeedContract extends PriceFeedContract {
     vaa: Buffer
   ): Promise<TxResult> {
     const keypair = Ed25519Keypair.fromSecretKey(
-      Buffer.from(senderPrivateKey, "hex")
+      new Uint8Array(Buffer.from(senderPrivateKey, "hex"))
     );
     const tx = new Transaction();
     const packageId = await this.getPythPackageId();
@@ -410,7 +410,7 @@ export class SuiWormholeContract extends WormholeContract {
   private client: SuiPythClient;
 
   getId(): string {
-    return `${this.chain.getId()}_${this.address}`;
+    return `${this.chain.getId()}_${this.stateId}`;
   }
 
   getType(): string {
@@ -420,7 +420,7 @@ export class SuiWormholeContract extends WormholeContract {
   toJson() {
     return {
       chain: this.chain.getId(),
-      address: this.address,
+      stateId: this.stateId,
       type: SuiWormholeContract.type,
     };
   }
@@ -429,7 +429,6 @@ export class SuiWormholeContract extends WormholeContract {
     chain: Chain,
     parsed: {
       type: string;
-      address: string;
       stateId: string;
     }
   ): SuiWormholeContract {
@@ -437,14 +436,10 @@ export class SuiWormholeContract extends WormholeContract {
       throw new Error("Invalid type");
     if (!(chain instanceof SuiChain))
       throw new Error(`Wrong chain type ${chain}`);
-    return new SuiWormholeContract(chain, parsed.address, parsed.stateId);
+    return new SuiWormholeContract(chain, parsed.stateId);
   }
 
-  constructor(
-    public chain: SuiChain,
-    public address: string,
-    public stateId: string
-  ) {
+  constructor(public chain: SuiChain, public stateId: string) {
     super();
     this.client = new SuiPythClient(
       this.chain.getProvider(),
@@ -493,7 +488,7 @@ export class SuiWormholeContract extends WormholeContract {
       target: `${corePackageId}::vaa::parse_and_verify`,
       arguments: [
         tx.object(coreObjectId),
-        tx.pure(uint8ArrayToBCS(vaa)),
+        tx.pure(uint8ArrayToBCS(new Uint8Array(vaa))),
         tx.object(SUI_CLOCK_OBJECT_ID),
       ],
     });
@@ -521,7 +516,7 @@ export class SuiWormholeContract extends WormholeContract {
     });
 
     const keypair = Ed25519Keypair.fromSecretKey(
-      Buffer.from(senderPrivateKey, "hex")
+      new Uint8Array(Buffer.from(senderPrivateKey, "hex"))
     );
     const result = await this.executeTransaction(tx, keypair);
     return { id: result.digest, info: result };

+ 7 - 0
contract_manager/src/store.ts

@@ -9,6 +9,7 @@ import {
   SuiChain,
   TonChain,
   NearChain,
+  IotaChain,
 } from "./chains";
 import {
   AptosPriceFeedContract,
@@ -26,6 +27,8 @@ import {
   EvmExpressRelayContract,
   TonPriceFeedContract,
   TonWormholeContract,
+  IotaWormholeContract,
+  IotaPriceFeedContract,
   EvmPulseContract,
 } from "./contracts";
 import { Token } from "./token";
@@ -90,6 +93,8 @@ export class Store {
       [StarknetChain.type]: StarknetChain,
       [TonChain.type]: TonChain,
       [NearChain.type]: NearChain,
+      [SuiChain.type]: SuiChain,
+      [IotaChain.type]: IotaChain,
     };
 
     this.getYamlFiles(`${this.path}/chains/`).forEach((yamlFile) => {
@@ -163,6 +168,8 @@ export class Store {
       [TonWormholeContract.type]: TonWormholeContract,
       [NearPriceFeedContract.type]: NearPriceFeedContract,
       [NearWormholeContract.type]: NearWormholeContract,
+      [IotaPriceFeedContract.type]: IotaPriceFeedContract,
+      [IotaWormholeContract.type]: IotaWormholeContract,
     };
     this.getYamlFiles(`${this.path}/contracts/`).forEach((yamlFile) => {
       const parsedArray = parse(readFileSync(yamlFile, "utf-8"));

+ 5 - 0
contract_manager/store/chains/IotaChains.yaml

@@ -0,0 +1,5 @@
+- id: iota_testnet
+  wormholeChainName: iota_sui_testnet
+  mainnet: false
+  rpcUrl: https://api.testnet.iota.cafe/
+  type: IotaChain

+ 4 - 0
contract_manager/store/contracts/IotaPriceFeedContracts.yaml

@@ -0,0 +1,4 @@
+- chain: iota_testnet
+  stateId: "0x68dda579251917b3db28e35c4df495c6e664ccc085ede867a9b773c8ebedc2c1"
+  wormholeStateId: "0x8bc490f69520a97ca1b3de864c96aa2265a0cf5d90f5f3f016b2eddf0cf2af2b"
+  type: IotaPriceFeedContract

+ 3 - 0
contract_manager/store/contracts/IotaWormholeContracts.yaml

@@ -0,0 +1,3 @@
+- chain: iota_testnet
+  stateId: "0x8bc490f69520a97ca1b3de864c96aa2265a0cf5d90f5f3f016b2eddf0cf2af2b"
+  type: IotaWormholeContract

+ 7 - 1
contract_manager/store/contracts/SuiWormholeContracts.yaml

@@ -1,3 +1,9 @@
+- chain: sui_mainnet
+  stateId: "0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c"
+  type: SuiWormholeContract
+- chain: sui_testnet
+  stateId: "0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790"
+  type: SuiWormholeContract
 - chain: movement_m2_devnet
-  address: "0x23a373b70e6e23a39e4846fa6896fa12beb08da061b3d4ec856bc8ead54f1e22"
+  stateId: "0xcf185fbc1af3a437a600587e0b39e5fede163336ffbb7ff24dca9b6eb19d2656"
   type: SuiWormholeContract

+ 1 - 0
governance/xc_admin/packages/xc_admin_common/src/chains.ts

@@ -232,6 +232,7 @@ export const RECEIVER_CHAINS = {
   bittensor_testnet: 50115,
   monad_devnet: 50116,
   monad_testnet: 50117,
+  iota_sui_testnet: 50118,
 };
 
 // If there is any overlapping value the receiver chain will replace the wormhole

文件差异内容过多而无法显示
+ 407 - 74
pnpm-lock.yaml


+ 2 - 0
pnpm-workspace.yaml

@@ -21,7 +21,9 @@ packages:
   - "target_chains/fuel/sdk/js"
   - "target_chains/starknet/sdk/js"
   - "target_chains/sui/sdk/js"
+  - "target_chains/sui/sdk/js-iota"
   - "target_chains/sui/cli"
+  - "target_chains/sui/cli-iota "
   - "target_chains/solana/sdk/js/solana_utils"
   - "target_chains/solana/sdk/js/pyth_solana_receiver"
   - "target_chains/ton/contracts"

+ 1 - 0
target_chains/sui/cli-iota/.gitignore

@@ -0,0 +1 @@
+lib

+ 69 - 0
target_chains/sui/cli-iota/README.md

@@ -0,0 +1,69 @@
+# Pre-requisites
+
+Install move cli according to this [doc](../contracts/README.md)
+
+# Deploying from scratch
+
+Configure the `Move.toml` file accordingly. The wormhole address should be specified based on the target chain in the `Move.toml` and the pyth address should be `0x0`.
+We can deploy the pyth oracle and initialize it with the following command:
+
+```bash
+npm run cli -- deploy --private-key <private-key> --chain [iota_sui|iota_sui]
+```
+
+You can then add your iota contract configs to the contract manager store.
+
+You can also manually create all the price feeds available at the moment to make it easier for devs to test the oracle.
+
+```bash
+npm run cli -- create-all --private-key <private-key> --contract <contract-id>
+```
+
+# Updating price feeds:
+
+You can use the `create` and `update-feeds` commands to create and update price feeds respectively.
+
+```bash
+npm run cli -- create --feed-id <feed-id> --private-key <private-key> --contract <contract-id>
+```
+
+```bash
+npm run cli -- update-feeds --feed-id <feed-id> --private-key <private-key> --contract <contract-id>
+```
+
+# Upgrade process:
+
+The following steps are needed to upgrade our iota contracts:
+
+- Contract changes:
+  - Create a new struct for the new version and update `current_version` and `previous_version` functions in `version_control` module
+  - Implement any custom logic needed to migrate the data from the old struct to the new one in the `migrate` module
+  - Update dependency (e.g. wormhole) addresses if needed
+- Generate the digest for the new contract build
+- Create a governance proposal, proposing the iota package to be upgraded to this specific digest
+- Approve and execute the governance proposal
+- Run the upgrade transaction and publish the new package
+
+## Generating the new contract hash:
+
+Run the following command to generate the new hash, make sure the contract addresses are identical to the deployed ones:
+
+```bash
+npm run cli -- generate-digest
+```
+
+## Upgrading the contract
+
+To upgrade the contract after the governance vaa was executed run:
+
+```bash
+npm run cli -- upgrade --private-key <private-key> --contract <contract-id> --vaa <upgrade-vaa>
+```
+
+The upgrade procedure consists of 2 transactions. The first one is to upgrade the contract (iota level) and the second one is to run the `migrate` function and upgrade the version (package level).
+Since clients try to fetch the latest version of the package automatically, it's important to run the second transaction as soon as possible after the first one.
+
+### FAQ:
+
+- I'm seeing the error `Transaction has non recoverable errors from at least 1/3 of validators`. What should I do?
+  Make sure you have enough funding in the wallet and try again. Usually a more descriptive error message is available in the returned value of the transaction.

+ 27 - 0
target_chains/sui/cli-iota/package.json

@@ -0,0 +1,27 @@
+{
+  "name": "pyth-iota-cli",
+  "version": "0.1.0",
+  "description": "Pyth IOTA Integration Cli tools",
+  "main": "index.js",
+  "license": "Apache-2.0",
+  "scripts": {
+    "cli": "ts-node src/cli.ts",
+    "build": "tsc"
+  },
+  "private": "true",
+  "dependencies": {
+    "@certusone/wormhole-sdk": "^0.9.12",
+    "@iota/iota-sdk": "^0.5.0",
+    "@pythnetwork/contract-manager": "workspace:*",
+    "@pythnetwork/price-service-client": "^1.4.0",
+    "@pythnetwork/price-service-sdk": "^1.2.0",
+    "@pythnetwork/xc-admin-common": "workspace:*",
+    "prettier": "^2.8.7",
+    "ts-node": "^10.9.1",
+    "typescript": "^5.0.4",
+    "yargs": "^17.7.2"
+  },
+  "devDependencies": {
+    "@types/yargs": "^17.0.32"
+  }
+}

+ 288 - 0
target_chains/sui/cli-iota/src/cli.ts

@@ -0,0 +1,288 @@
+import yargs from "yargs";
+import { hideBin } from "yargs/helpers";
+import {
+  DefaultStore,
+  getDefaultDeploymentConfig,
+  IotaChain,
+  IotaPriceFeedContract,
+} from "@pythnetwork/contract-manager";
+import { PriceServiceConnection } from "@pythnetwork/price-service-client";
+import { execSync } from "child_process";
+import { initPyth, publishPackage } from "./pyth_deploy";
+import { Ed25519Keypair } from "@iota/iota-sdk/keypairs/ed25519";
+import { resolve } from "path";
+import {
+  buildForBytecodeAndDigest,
+  migratePyth,
+  upgradePyth,
+} from "./upgrade_pyth";
+
+const OPTIONS = {
+  "private-key": {
+    type: "string",
+    demandOption: true,
+    desc: "Private key to use to sign transaction",
+  },
+  contract: {
+    type: "string",
+    demandOption: true,
+    desc: "Contract to use for the command (e.g iota_0x68dda579251917b3db28e35c4df495c6e664ccc085ede867a9b773c8ebedc2c1)",
+  },
+  path: {
+    type: "string",
+    default: "../../contracts",
+    desc: "Path to the iota contracts, will use ../../contracts by default",
+  },
+  endpoint: {
+    type: "string",
+    default: "https://hermes.pyth.network",
+    desc: "Price service endpoint to use, defaults to https://hermes.pyth.network",
+  },
+  "feed-id": {
+    type: "array",
+    demandOption: true,
+    desc: "Price feed ids to create without the leading 0x (e.g f9c0172ba10dfa4d19088d94f5bf61d3b54d5bd7483a322a982e1373ee8ea31b). Can be provided multiple times for multiple feed updates",
+  },
+} as const;
+
+function getContract(contractId: string): IotaPriceFeedContract {
+  const contract = DefaultStore.contracts[contractId] as IotaPriceFeedContract;
+  if (!contract) {
+    throw new Error(`Contract ${contractId} not found`);
+  }
+  return contract;
+}
+
+yargs(hideBin(process.argv))
+  .command(
+    "create",
+    "Create a new price feed",
+    (yargs) => {
+      return yargs
+        .options({
+          contract: OPTIONS.contract,
+          "feed-id": OPTIONS["feed-id"],
+          "private-key": OPTIONS["private-key"],
+          endpoint: OPTIONS.endpoint,
+        })
+        .usage(
+          "$0 create --contract <contract-id> --feed-id <feed-id> --private-key <private-key>"
+        );
+    },
+    async (argv) => {
+      const contract = getContract(argv.contract);
+      const priceService = new PriceServiceConnection(argv.endpoint);
+      const feedIds = argv["feed-id"] as string[];
+      const vaas = await priceService.getLatestVaas(feedIds);
+      const digest = await contract.executeCreatePriceFeed(
+        argv["private-key"],
+        vaas.map((vaa) => Buffer.from(vaa, "base64"))
+      );
+      console.log("Transaction successful. Digest:", digest);
+    }
+  )
+  .command(
+    "create-all",
+    "Create all price feeds for a contract",
+    (yargs) => {
+      return yargs
+        .options({
+          contract: OPTIONS.contract,
+          "private-key": OPTIONS["private-key"],
+          endpoint: OPTIONS.endpoint,
+        })
+        .usage(
+          "$0 create-all --contract <contract-id> --private-key <private-key>"
+        );
+    },
+    async (argv) => {
+      const contract = getContract(argv.contract);
+      const priceService = new PriceServiceConnection(argv.endpoint);
+      const feedIds = await priceService.getPriceFeedIds();
+      const BATCH_SIZE = 10;
+      for (let i = 0; i < feedIds.length; i += BATCH_SIZE) {
+        const batch = feedIds.slice(i, i + BATCH_SIZE);
+        const vaas = await priceService.getLatestVaas(batch);
+        const digest = await contract.executeCreatePriceFeed(
+          argv["private-key"],
+          vaas.map((vaa) => Buffer.from(vaa, "base64"))
+        );
+        console.log("Transaction successful. Digest:", digest);
+        console.log(`Progress: ${i + BATCH_SIZE}/${feedIds.length}`);
+      }
+    }
+  )
+  .command(
+    "generate-digest",
+    "Generate digest for a contract",
+    (yargs) => {
+      return yargs
+        .options({
+          path: OPTIONS.path,
+        })
+        .usage("$0 generate-digest --path <path-to-contracts>");
+    },
+    async (argv) => {
+      const buildOutput: {
+        modules: string[];
+        dependencies: string[];
+        digest: number[];
+      } = JSON.parse(
+        execSync(
+          `iota move build --dump-bytecode-as-base64 --path ${__dirname}/${argv.path} 2> /dev/null`,
+          {
+            encoding: "utf-8",
+          }
+        )
+      );
+      console.log("Contract digest:");
+      console.log(Buffer.from(buildOutput.digest).toString("hex"));
+    }
+  )
+  .command(
+    "deploy",
+    "Deploy a contract",
+    (yargs) => {
+      return yargs
+        .options({
+          "private-key": OPTIONS["private-key"],
+          chain: {
+            type: "string",
+            demandOption: true,
+            desc: "Chain to deploy the code to. Can be iota_mainnet or iota_testnet",
+          },
+          path: OPTIONS.path,
+        })
+        .usage(
+          "$0 deploy --private-key <private-key> --chain [iota_mainnet|iota_testnet] --path <path-to-contracts>"
+        );
+    },
+    async (argv) => {
+      const walletPrivateKey = argv["private-key"];
+      const chain = DefaultStore.chains[argv.chain] as IotaChain;
+      const keypair = Ed25519Keypair.fromSecretKey(
+        new Uint8Array(Buffer.from(walletPrivateKey, "hex"))
+      );
+      const result = await publishPackage(
+        keypair,
+        chain.getProvider(),
+        argv.path
+      );
+      const deploymentType = "stable";
+      const config = getDefaultDeploymentConfig(deploymentType);
+      await initPyth(
+        keypair,
+        chain.getProvider(),
+        result.packageId,
+        result.deployerCapId,
+        result.upgradeCapId,
+        config
+      );
+    }
+  )
+  .command(
+    "update-feeds",
+    "Update price feeds for a contract",
+    (yargs) => {
+      return yargs
+        .options({
+          contract: OPTIONS.contract,
+          "feed-id": OPTIONS["feed-id"],
+          "private-key": OPTIONS["private-key"],
+          endpoint: OPTIONS.endpoint,
+        })
+        .usage(
+          "$0 update-feeds --contract <contract-id> --feed-id <feed-id> --private-key <private-key>"
+        );
+    },
+    async (argv) => {
+      const contract = getContract(argv.contract);
+      const priceService = new PriceServiceConnection(argv.endpoint);
+      const feedIds = argv["feed-id"] as string[];
+      const vaas = await priceService.getLatestVaas(feedIds);
+      const digest = await contract.executeUpdatePriceFeedWithFeeds(
+        argv["private-key"],
+        vaas.map((vaa) => Buffer.from(vaa, "base64")),
+        feedIds
+      );
+      console.log("Transaction successful. Digest:", digest);
+    }
+  )
+  .command(
+    "upgrade",
+    "Upgrade a contract",
+    (yargs) => {
+      return yargs
+        .options({
+          "private-key": OPTIONS["private-key"],
+          contract: OPTIONS.contract,
+          vaa: {
+            type: "string",
+            demandOption: true,
+            desc: "Signed Vaa for upgrading the package in hex format",
+          },
+          path: OPTIONS.path,
+        })
+        .usage(
+          "$0 upgrade --private-key <private-key> --contract <contract-id> --vaa <upgrade-vaa>"
+        );
+    },
+    async (argv) => {
+      const contract = getContract(argv.contract);
+      const keypair = Ed25519Keypair.fromSecretKey(
+        new Uint8Array(Buffer.from(argv["private-key"], "hex"))
+      );
+
+      const pythContractsPath = resolve(`${__dirname}/${argv.path}`);
+
+      // Build for modules and dependencies
+      const { modules, dependencies, digest } =
+        buildForBytecodeAndDigest(pythContractsPath);
+      //Execute upgrade with signed governance VAA.
+      console.log("Digest is", digest.toString("hex"));
+      const pythPackageOld = await contract.getPackageId(contract.stateId);
+      console.log("Old package id:", pythPackageOld);
+      const signedVaa = Buffer.from(argv.vaa, "hex");
+      const upgradeResults = await upgradePyth(
+        keypair,
+        contract.chain.getProvider(),
+        modules,
+        dependencies,
+        signedVaa,
+        contract
+      );
+      console.log("Tx digest", upgradeResults.digest);
+      if (
+        !upgradeResults.effects ||
+        upgradeResults.effects.status.status !== "success"
+      ) {
+        throw new Error("Upgrade failed");
+      }
+
+      console.log(
+        "Upgrade successful, Executing the migrate function in a separate transaction..."
+      );
+
+      // We can not do the migration in the same transaction since the newly published package is not found
+      // on chain at the beginning of the transaction.
+
+      const migrateResults = await migratePyth(
+        keypair,
+        contract.chain.getProvider(),
+        signedVaa,
+        contract,
+        pythPackageOld
+      );
+      console.log("Tx digest", migrateResults.digest);
+      if (
+        !migrateResults.effects ||
+        migrateResults.effects.status.status !== "success"
+      ) {
+        throw new Error(
+          `Migrate failed. Old package id is ${pythPackageOld}. Please do the migration manually`
+        );
+      }
+      console.log("Migrate successful");
+    }
+  )
+  .demandCommand().argv;

+ 185 - 0
target_chains/sui/cli-iota/src/pyth_deploy.ts

@@ -0,0 +1,185 @@
+import { Transaction } from "@iota/iota-sdk/transactions";
+
+import {
+  NANOS_PER_IOTA,
+  normalizeIotaObjectId,
+  fromB64,
+} from "@iota/iota-sdk/utils";
+
+import { Ed25519Keypair } from "@iota/iota-sdk/keypairs/ed25519";
+import { execSync } from "child_process";
+import { DataSource } from "@pythnetwork/xc-admin-common";
+import { IotaClient } from "@iota/iota-sdk/client";
+import { bcs } from "@iota/iota-sdk/bcs";
+
+export async function publishPackage(
+  keypair: Ed25519Keypair,
+  provider: IotaClient,
+  packagePath: string
+): Promise<{ packageId: string; upgradeCapId: string; deployerCapId: string }> {
+  // Build contracts
+  const buildOutput: {
+    modules: string[];
+    dependencies: string[];
+  } = JSON.parse(
+    execSync(
+      `iota move build --dump-bytecode-as-base64 --path ${__dirname}/${packagePath} 2> /dev/null`,
+      {
+        encoding: "utf-8",
+      }
+    )
+  );
+
+  console.log("buildOutput: ", buildOutput);
+
+  // Publish contracts
+  const txb = new Transaction();
+
+  txb.setGasBudget(NANOS_PER_IOTA / 2n); // 0.5 IOTA
+
+  const [upgradeCap] = txb.publish({
+    modules: buildOutput.modules.map((m: string) => Array.from(fromB64(m))),
+    dependencies: buildOutput.dependencies.map((d: string) =>
+      normalizeIotaObjectId(d)
+    ),
+  });
+
+  // Transfer upgrade capability to deployer
+  txb.transferObjects([upgradeCap], txb.pure.address(keypair.toIotaAddress()));
+
+  // Execute transactions
+  const result = await provider.signAndExecuteTransaction({
+    signer: keypair,
+    transaction: txb,
+    options: {
+      showInput: true,
+      showObjectChanges: true,
+    },
+  });
+
+  const publishedChanges = result.objectChanges?.filter(
+    (change) => change.type === "published"
+  );
+
+  if (
+    publishedChanges?.length !== 1 ||
+    publishedChanges[0].type !== "published"
+  ) {
+    throw new Error(
+      "No publish event found in transaction:" +
+        JSON.stringify(result.objectChanges, null, 2)
+    );
+  }
+
+  const packageId = publishedChanges[0].packageId;
+
+  console.log("Published with package id: ", packageId);
+  console.log("Tx digest", result.digest);
+  let upgradeCapId: string | undefined;
+  let deployerCapId: string | undefined;
+  for (const objectChange of result.objectChanges!) {
+    if (objectChange.type === "created") {
+      if (objectChange.objectType === "0x2::package::UpgradeCap") {
+        upgradeCapId = objectChange.objectId;
+      }
+      if (objectChange.objectType === `${packageId}::setup::DeployerCap`) {
+        deployerCapId = objectChange.objectId;
+      }
+    }
+  }
+  if (!upgradeCapId || !deployerCapId) {
+    throw new Error("Could not find upgrade cap or deployer cap");
+  }
+  console.log("UpgradeCapId: ", upgradeCapId);
+  console.log("DeployerCapId: ", deployerCapId);
+  return {
+    packageId,
+    upgradeCapId: upgradeCapId,
+    deployerCapId: deployerCapId,
+  };
+}
+
+export async function initPyth(
+  keypair: Ed25519Keypair,
+  provider: IotaClient,
+  pythPackageId: string,
+  deployerCapId: string,
+  upgradeCapId: string,
+  config: {
+    dataSources: DataSource[];
+    governanceDataSource: DataSource;
+  }
+) {
+  const tx = new Transaction();
+
+  const baseUpdateFee = tx.pure.u64(1);
+  const dataSourceEmitterAddresses = tx.pure(
+    bcs
+      .vector(bcs.vector(bcs.u8()))
+      .serialize(
+        config.dataSources.map((dataSource) => [
+          ...Buffer.from(dataSource.emitterAddress, "hex"),
+        ])
+      )
+  );
+  const dataSourceEmitterChainIds = tx.pure(
+    bcs
+      .vector(bcs.u64())
+      .serialize(
+        config.dataSources.map((dataSource) => dataSource.emitterChain)
+      )
+  );
+  const governanceEmitterAddress = tx.pure(
+    bcs
+      .vector(bcs.u8())
+      .serialize([
+        ...Buffer.from(config.governanceDataSource.emitterAddress, "hex"),
+      ])
+  );
+  const governanceEmitterChainId = tx.pure(
+    bcs.u64().serialize(config.governanceDataSource.emitterChain)
+  );
+  const stalePriceThreshold = tx.pure.u64(60);
+  tx.moveCall({
+    target: `${pythPackageId}::pyth::init_pyth`,
+    arguments: [
+      tx.object(deployerCapId),
+      tx.object(upgradeCapId),
+      stalePriceThreshold,
+      governanceEmitterChainId,
+      governanceEmitterAddress,
+      dataSourceEmitterChainIds,
+      dataSourceEmitterAddresses,
+      baseUpdateFee,
+    ],
+  });
+
+  tx.setGasBudget(NANOS_PER_IOTA / 10n); // 0.1 IOTA
+
+  let result = await provider.signAndExecuteTransaction({
+    signer: keypair,
+    transaction: tx,
+    options: {
+      showInput: true,
+      showEffects: true,
+      showEvents: true,
+      showObjectChanges: true,
+      showBalanceChanges: true,
+    },
+  });
+  if (!result.effects || !result.objectChanges) {
+    throw new Error("No effects or object changes found in transaction");
+  }
+  if (result.effects.status.status === "success") {
+    console.log("Pyth init successful");
+    console.log("Tx digest", result.digest);
+  }
+  for (const objectChange of result.objectChanges) {
+    if (objectChange.type === "created") {
+      if (objectChange.objectType === `${pythPackageId}::state::State`) {
+        console.log("Pyth state id: ", objectChange.objectId);
+      }
+    }
+  }
+  return result;
+}

+ 115 - 0
target_chains/sui/cli-iota/src/upgrade_pyth.ts

@@ -0,0 +1,115 @@
+import { Transaction } from "@iota/iota-sdk/transactions";
+import {
+  fromB64,
+  NANOS_PER_IOTA,
+  normalizeIotaObjectId,
+} from "@iota/iota-sdk/utils";
+import { IotaClient } from "@iota/iota-sdk/client";
+import { Ed25519Keypair } from "@iota/iota-sdk/keypairs/ed25519";
+
+import { execSync } from "child_process";
+import { IotaPriceFeedContract } from "@pythnetwork/contract-manager";
+
+export function buildForBytecodeAndDigest(packagePath: string) {
+  const buildOutput: {
+    modules: string[];
+    dependencies: string[];
+    digest: number[];
+  } = JSON.parse(
+    execSync(
+      `iota move build --dump-bytecode-as-base64 -p ${packagePath} 2> /dev/null`,
+      { encoding: "utf-8" }
+    )
+  );
+  return {
+    modules: buildOutput.modules.map((m: string) => Array.from(fromB64(m))),
+    dependencies: buildOutput.dependencies.map((d: string) =>
+      normalizeIotaObjectId(d)
+    ),
+    digest: Buffer.from(buildOutput.digest),
+  };
+}
+
+export async function upgradePyth(
+  keypair: Ed25519Keypair,
+  provider: IotaClient,
+  modules: number[][],
+  dependencies: string[],
+  signedVaa: Buffer,
+  contract: IotaPriceFeedContract
+) {
+  const pythPackage = await contract.getPackageId(contract.stateId);
+
+  const tx = new Transaction();
+
+  const verificationReceipt = await contract.getVaaVerificationReceipt(
+    tx as any,
+    pythPackage,
+    signedVaa
+  );
+
+  // Authorize upgrade.
+  const [upgradeTicket] = tx.moveCall({
+    target: `${pythPackage}::contract_upgrade::authorize_upgrade`,
+    arguments: [tx.object(contract.stateId), verificationReceipt as any],
+  });
+
+  // Build and generate modules and dependencies for upgrade.
+  const [upgradeReceipt] = tx.upgrade({
+    modules,
+    dependencies,
+    package: pythPackage,
+    ticket: upgradeTicket,
+  });
+
+  // Commit upgrade.
+  tx.moveCall({
+    target: `${pythPackage}::contract_upgrade::commit_upgrade`,
+    arguments: [tx.object(contract.stateId), upgradeReceipt],
+  });
+
+  tx.setGasBudget(NANOS_PER_IOTA / 4n); // 0.25 IOTA
+
+  return provider.signAndExecuteTransaction({
+    signer: keypair,
+    transaction: tx,
+    options: {
+      showEffects: true,
+      showEvents: true,
+    },
+  });
+}
+
+export async function migratePyth(
+  keypair: Ed25519Keypair,
+  provider: IotaClient,
+  signedUpgradeVaa: Buffer,
+  contract: IotaPriceFeedContract,
+  pythPackageOld: string
+) {
+  const pythPackage = await contract.getPackageId(contract.stateId);
+  const tx = new Transaction();
+  // The pyth package version is not updated yet, therefore we can not get the verification receipts from the new
+  // package yet. We need to use the old package id to get the verification receipt in this transaction and then submit
+  // it to the migrate function in the new package!
+  const verificationReceipt = await contract.getVaaVerificationReceipt(
+    tx,
+    pythPackageOld,
+    signedUpgradeVaa
+  );
+  tx.moveCall({
+    target: `${pythPackage}::migrate::migrate`,
+    arguments: [tx.object(contract.stateId), verificationReceipt as any],
+  });
+
+  tx.setGasBudget(NANOS_PER_IOTA / 10n); //0.1 IOTA
+
+  return provider.signAndExecuteTransaction({
+    signer: keypair,
+    transaction: tx,
+    options: {
+      showEffects: true,
+      showEvents: true,
+    },
+  });
+}

+ 9 - 0
target_chains/sui/cli-iota/tsconfig.json

@@ -0,0 +1,9 @@
+{
+  "extends": "../../../tsconfig.base.json",
+  "include": ["src"],
+  "exclude": ["node_modules", "**/__tests__/*"],
+  "compilerOptions": {
+    "rootDir": "src/",
+    "outDir": "./lib"
+  }
+}

+ 7 - 16
target_chains/sui/cli/src/cli.ts

@@ -35,7 +35,8 @@ const OPTIONS = {
   },
   endpoint: {
     type: "string",
-    desc: "Price service endpoint to use, defaults to https://hermes.pyth.network for mainnet and https://hermes-beta.pyth.network for testnet",
+    default: "https://hermes.pyth.network",
+    desc: "Price service endpoint to use, defaults to https://hermes.pyth.network",
   },
   "feed-id": {
     type: "array",
@@ -52,16 +53,6 @@ function getContract(contractId: string): SuiPriceFeedContract {
   return contract;
 }
 
-function getPriceService(
-  contract: SuiPriceFeedContract,
-  endpointOverride: string | undefined
-): PriceServiceConnection {
-  const defaultEndpoint = contract.getChain().isMainnet()
-    ? "https://hermes.pyth.network"
-    : "https://hermes-beta.pyth.network";
-  return new PriceServiceConnection(endpointOverride || defaultEndpoint);
-}
-
 yargs(hideBin(process.argv))
   .command(
     "create",
@@ -80,7 +71,7 @@ yargs(hideBin(process.argv))
     },
     async (argv) => {
       const contract = getContract(argv.contract);
-      const priceService = getPriceService(contract, argv.endpoint);
+      const priceService = new PriceServiceConnection(argv.endpoint);
       const feedIds = argv["feed-id"] as string[];
       const vaas = await priceService.getLatestVaas(feedIds);
       const digest = await contract.executeCreatePriceFeed(
@@ -106,7 +97,7 @@ yargs(hideBin(process.argv))
     },
     async (argv) => {
       const contract = getContract(argv.contract);
-      const priceService = getPriceService(contract, argv.endpoint);
+      const priceService = new PriceServiceConnection(argv.endpoint);
       const feedIds = await priceService.getPriceFeedIds();
       const BATCH_SIZE = 10;
       for (let i = 0; i < feedIds.length; i += BATCH_SIZE) {
@@ -170,7 +161,7 @@ yargs(hideBin(process.argv))
       const walletPrivateKey = argv["private-key"];
       const chain = DefaultStore.chains[argv.chain] as SuiChain;
       const keypair = Ed25519Keypair.fromSecretKey(
-        Buffer.from(walletPrivateKey, "hex")
+        new Uint8Array(Buffer.from(walletPrivateKey, "hex"))
       );
       const result = await publishPackage(
         keypair,
@@ -206,7 +197,7 @@ yargs(hideBin(process.argv))
     },
     async (argv) => {
       const contract = getContract(argv.contract);
-      const priceService = getPriceService(contract, argv.endpoint);
+      const priceService = new PriceServiceConnection(argv.endpoint);
       const feedIds = argv["feed-id"] as string[];
       const vaas = await priceService.getLatestVaas(feedIds);
       const digest = await contract.executeUpdatePriceFeedWithFeeds(
@@ -239,7 +230,7 @@ yargs(hideBin(process.argv))
     async (argv) => {
       const contract = getContract(argv.contract);
       const keypair = Ed25519Keypair.fromSecretKey(
-        Buffer.from(argv["private-key"], "hex")
+        new Uint8Array(Buffer.from(argv["private-key"], "hex"))
       );
 
       const pythContractsPath = resolve(`${__dirname}/${argv.path}`);

+ 24 - 12
target_chains/sui/cli/src/pyth_deploy.ts

@@ -6,6 +6,7 @@ import { Ed25519Keypair } from "@mysten/sui/dist/cjs/keypairs/ed25519";
 import { execSync } from "child_process";
 import { DataSource } from "@pythnetwork/xc-admin-common";
 import { SuiClient } from "@mysten/sui/client";
+import { bcs } from "@mysten/sui/dist/cjs/bcs";
 
 export async function publishPackage(
   keypair: Ed25519Keypair,
@@ -28,7 +29,6 @@ export async function publishPackage(
   console.log("buildOutput: ", buildOutput);
 
   // Publish contracts
-  // const transactionBlock = new TransactionBlock();
   const txb = new Transaction();
 
   txb.setGasBudget(MIST_PER_SUI / 2n); // 0.5 SUI
@@ -109,19 +109,31 @@ export async function initPyth(
   const tx = new Transaction();
 
   const baseUpdateFee = tx.pure.u64(1);
-  const dataSourceEmitterAddresses = tx.pure.arguments(
-    config.dataSources.map((dataSource) => [
-      ...Buffer.from(dataSource.emitterAddress, "hex"),
-    ])
+  const dataSourceEmitterAddresses = tx.pure(
+    bcs
+      .vector(bcs.vector(bcs.u8()))
+      .serialize(
+        config.dataSources.map((dataSource) => [
+          ...Buffer.from(dataSource.emitterAddress, "hex"),
+        ])
+      )
   );
-  const dataSourceEmitterChainIds = tx.pure.arguments(
-    config.dataSources.map((dataSource) => dataSource.emitterChain)
+  const dataSourceEmitterChainIds = tx.pure(
+    bcs
+      .vector(bcs.u64())
+      .serialize(
+        config.dataSources.map((dataSource) => dataSource.emitterChain)
+      )
   );
-  const governanceEmitterAddress = tx.pure.arguments([
-    ...Buffer.from(config.governanceDataSource.emitterAddress, "hex"),
-  ]);
-  const governanceEmitterChainId = tx.pure.arguments(
-    config.governanceDataSource.emitterChain
+  const governanceEmitterAddress = tx.pure(
+    bcs
+      .vector(bcs.u8())
+      .serialize([
+        ...Buffer.from(config.governanceDataSource.emitterAddress, "hex"),
+      ])
+  );
+  const governanceEmitterChainId = tx.pure(
+    bcs.u64().serialize(config.governanceDataSource.emitterChain)
   );
   const stalePriceThreshold = tx.pure.u64(60);
   tx.moveCall({

+ 15 - 0
target_chains/sui/contracts/Move.iota_testnet.toml

@@ -0,0 +1,15 @@
+[package]
+name = "Pyth"
+version = "0.0.2"
+published-at = "0x23994dd119480ea614f7623520337058dca913cb1bb6e5d8d51c7b067d3ca3bb"
+
+[dependencies.Iota]
+git = "https://github.com/iotaledger/iota.git"
+subdir = "crates/iota-framework/packages/iota-framework"
+rev = "751c23caf24efd071463b9ffd07eabcb15f44f31"
+
+[dependencies.Wormhole]
+local = "../vendor/wormhole_iota_testnet/wormhole"
+
+[addresses]
+pyth = "0x23994dd119480ea614f7623520337058dca913cb1bb6e5d8d51c7b067d3ca3bb"

+ 36 - 0
target_chains/sui/iota-patch-libs.sh

@@ -0,0 +1,36 @@
+#!/bin/bash
+
+set -euo pipefail
+
+# This script patches the SUI code to be compatible with IOTA.  IOTA is a fork
+# of SUI but is not compatible with SUI.  You'd need to run this script for
+# deploying Pyth contracts and updating the vendored libs.
+#
+# Note: Do not commit the patched Pyth code to the repo.
+
+# Check if exactly one argument (base path) is provided
+if [ $# -ne 1 ]; then
+    echo "Usage: $0 <base-path>"
+    exit 1
+fi
+
+# Detect OS to determine correct sed syntax
+if sed --version >/dev/null 2>&1; then
+    SED_CMD=sed
+else
+    if ! command -v gsed >/dev/null 2>&1; then
+        echo "Error: GNU sed (gsed) is required for macOS/BSD. Install core-utils via Homebrew."
+        exit 1
+    fi
+    SED_CMD=gsed
+fi
+
+# Use find to get all .move files recursively and process them
+find "$1" -type f -name "*.move" | while read -r file; do
+    echo "Processing: $file"
+    $SED_CMD -i -e 's/\bSUI\b/IOTA/g' \
+           -e 's/\bSui\b/Iota/g' \
+           -e 's/\bsui\b/iota/g' "$file"
+done
+
+echo "Replacements complete."

+ 9 - 0
target_chains/sui/sdk/js-iota/.eslintrc.js

@@ -0,0 +1,9 @@
+module.exports = {
+  root: true,
+  parser: "@typescript-eslint/parser",
+  plugins: ["@typescript-eslint"],
+  extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
+  rules: {
+    "@typescript-eslint/no-explicit-any": "off",
+  },
+};

+ 1 - 0
target_chains/sui/sdk/js-iota/.gitignore

@@ -0,0 +1 @@
+lib

+ 155 - 0
target_chains/sui/sdk/js-iota/README.md

@@ -0,0 +1,155 @@
+# Pyth IOTA JS SDK
+
+[Pyth](https://pyth.network/) provides real-time pricing data in a variety of asset classes, including cryptocurrency, equities, FX and commodities.
+This library allows you to use these real-time prices on the [IOTA network](https://www.iota.org/).
+
+## Installation
+
+### npm
+
+```
+$ npm install --save @pythnetwork/pyth-iota-js
+```
+
+### Yarn
+
+```
+$ yarn add @pythnetwork/pyth-iota-js
+```
+
+## Quickstart
+
+Pyth stores prices off-chain to minimize gas fees, which allows us to offer a wider selection of products and faster update times.
+See [On-Demand Updates](https://docs.pyth.network/documentation/pythnet-price-feeds/on-demand) for more information about this approach.
+Typically, to use Pyth prices on chain,
+they must be fetched from an off-chain Hermes instance. The `IotaPriceServiceConnection` class can be used to interact with these services,
+providing a way to fetch these prices directly in your code. The following example wraps an existing RPC provider and shows how to obtain
+Pyth prices and submit them to the network:
+
+```typescript
+const connection = new IotaPriceServiceConnection(
+  "https://hermes.pyth.network"
+); // See Hermes endpoints section below for other endpoints
+
+const priceIds = [
+  // You can find the ids of prices at https://pyth.network/developers/price-feed-ids
+  "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43", // BTC/USD price id
+  "0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace", // ETH/USD price id
+];
+
+// In order to use Pyth prices in your protocol you need to submit the price update data to Pyth contract in your target
+// chain. `getPriceUpdateData` creates the update data which can be submitted to your contract.
+
+const priceUpdateData = await connection.getPriceFeedsUpdateData(priceIds);
+```
+
+## On-chain prices
+
+### **_Important Note for Integrators_**
+
+Your IOTA Move module **should NOT** have a hard-coded call to `pyth::update_single_price_feed`. In other words, the Iota Pyth `pyth::update_single_price_feed` entry point should never be called by a contract, instead it should be called directly from client code (e.g. Typescript or Rust).
+
+This is because when a IOTA contract is [upgraded](https://docs.iota.org/developer/iota-101/move-overview/package-upgrades/upgrade), the new address is different from the original. If your module has a hard-coded call to `pyth::update_single_price_feed` living at a fixed call-site, it may eventually get bricked due to the way Pyth upgrades are implemented. (We only allows users to interact with the most recent package version for security reasons).
+
+Therefore, you should build a [Iota programmable transaction](https://docs.iota.org/ts-sdk/typescript/transaction-building/basics) that first updates the price by calling `pyth::update_single_price_feed` at the latest call-site from the client-side and then call a function in your contract that invokes `pyth::get_price` on the `PriceInfoObject` to get the recently updated price.
+You can use `IotaPythClient` to build such transactions.
+
+### Example
+
+```ts
+import { IotaPythClient } from "@pythnetwork/pyth-iota-js";
+import { Transaction } from "@iota/iota-sdk/transactions";
+import { IotaClient } from "@iota/iota-sdk/client";
+
+const priceUpdateData = await connection.getPriceFeedsUpdateData(priceIds); // see quickstart section
+
+
+// It is either injected from browser or instantiated in backend via some private key
+const wallet: SignerWithProvider = getWallet();
+// Get the state ids of the Pyth and Wormhole contracts from
+// https://docs.pyth.network/documentation/pythnet-price-feeds/sui
+const wormholeStateId = " 0xFILL_ME";
+const pythStateId = "0xFILL_ME";
+
+const provider = new IotaClient({ url: "https://fill-iota-endpoint" });
+const client = new IotaPythClient(wallet.provider, pythStateId, wormholeStateId);
+const tx = new Transaction();
+const priceInfoObjectIds = await client.updatePriceFeeds(tx, priceFeedUpdateData, priceIds);
+
+tx.moveCall({
+    target: `YOUR_PACKAGE::YOUR_MODULE::use_pyth_for_defi`,
+    arguments: [
+        ..., // other arguments needed for your contract
+        tx.object(pythStateId),
+        tx.object(priceInfoObjectIds[0]),
+    ],
+});
+
+const result = await provider.signAndExecuteTransaction({
+  signer: wallet,
+  transaction: tx,
+  options: {
+    showEffects: true,
+    showEvents: true,
+  },
+});
+```
+
+Now in your contract you can consume the price by calling `pyth::get_price` or other utility functions on the `PriceInfoObject`.
+
+### CLI Example
+
+[This example](./src/examples/IotaRelay.ts) shows how to update prices on an IOTA network. It does the following:
+
+1. Fetches update data from Hermes for the given price feeds.
+2. Calls the Pyth IOTA contract with the update data.
+
+You can run this example with `npm run example-relay`. A full command that updates prices on IOTA testnet looks like:
+
+```bash
+export IOTA_KEY=YOUR_PRIV_KEY;
+npm run example-relay -- --feed-id "ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace" \
+--price-service "https://hermes.pyth.network" \
+--full-node "https://api.testnet.iota.cafe" \
+--pyth-state-id "0x68dda579251917b3db28e35c4df495c6e664ccc085ede867a9b773c8ebedc2c1" \
+--wormhole-state-id "0x8bc490f69520a97ca1b3de864c96aa2265a0cf5d90f5f3f016b2eddf0cf2af2b"
+```
+
+## Off-chain prices
+
+Many applications additionally need to display Pyth prices off-chain, for example, in their frontend application.
+The `IotaPriceServiceConnection` provides two different ways to fetch the current Pyth price.
+The code blocks below assume that the `connection` and `priceIds` objects have been initialized as shown above.
+The first method is a single-shot query:
+
+```typescript
+// `getLatestPriceFeeds` returns a `PriceFeed` for each price id. It contains all information about a price and has
+// utility functions to get the current and exponentially-weighted moving average price, and other functionality.
+const priceFeeds = await connection.getLatestPriceFeeds(priceIds);
+// Get the price if it is not older than 60 seconds from the current time.
+console.log(priceFeeds[0].getPriceNoOlderThan(60)); // Price { conf: '1234', expo: -8, price: '12345678' }
+// Get the exponentially-weighted moving average price if it is not older than 60 seconds from the current time.
+console.log(priceFeeds[1].getEmaPriceNoOlderThan(60));
+```
+
+The object also supports a streaming websocket connection that allows you to subscribe to every new price update for a given feed.
+This method is useful if you want to show continuously updating real-time prices in your frontend:
+
+```typescript
+// Subscribe to the price feeds given by `priceId`. The callback will be invoked every time the requested feed
+// gets a price update.
+connection.subscribePriceFeedUpdates(priceIds, (priceFeed) => {
+  console.log(
+    `Received update for ${priceFeed.id}: ${priceFeed.getPriceNoOlderThan(60)}`
+  );
+});
+
+// When using the subscription, make sure to close the websocket upon termination to finish the process gracefully.
+setTimeout(() => {
+  connection.closeWebSocket();
+}, 60000);
+```
+
+## Hermes endpoints
+
+You can find the list of Hermes public endpoints [here](https://docs.pyth.network/documentation/pythnet-price-feeds/hermes#public-endpoints).

+ 5 - 0
target_chains/sui/sdk/js-iota/jest.config.js

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

+ 59 - 0
target_chains/sui/sdk/js-iota/package.json

@@ -0,0 +1,59 @@
+{
+  "name": "@pythnetwork/pyth-iota-js",
+  "version": "2.1.0",
+  "description": "Pyth Network IOTA Utilities",
+  "homepage": "https://pyth.network",
+  "author": {
+    "name": "Pyth Data Association"
+  },
+  "main": "lib/index.js",
+  "types": "lib/index.d.ts",
+  "files": [
+    "lib/**/*"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/pyth-network/pyth-crosschain",
+    "directory": "target_chains/sui/sdk/js-iota"
+  },
+  "publishConfig": {
+    "access": "public"
+  },
+  "scripts": {
+    "build": "tsc",
+    "example-relay": "pnpm run build && node lib/examples/SuiRelay.js",
+    "format": "prettier --write \"src/**/*.ts\"",
+    "test:lint": "eslint src/",
+    "prepublishOnly": "pnpm run build && pnpm test:lint",
+    "preversion": "pnpm run test:lint",
+    "version": "pnpm run format && git add -A src"
+  },
+  "keywords": [
+    "pyth",
+    "oracle",
+    "iota"
+  ],
+  "license": "Apache-2.0",
+  "devDependencies": {
+    "@truffle/hdwallet-provider": "^2.1.5",
+    "@types/ethereum-protocol": "^1.0.2",
+    "@types/jest": "^29.4.0",
+    "@types/node": "^18.11.18",
+    "@types/web3-provider-engine": "^14.0.1",
+    "@types/yargs": "^17.0.20",
+    "@typescript-eslint/eslint-plugin": "^6.0.0",
+    "@typescript-eslint/parser": "^6.0.0",
+    "eslint": "^8.14.0",
+    "jest": "^29.4.1",
+    "prettier": "^2.6.2",
+    "ts-jest": "^29.0.5",
+    "typescript": "^5.3.3",
+    "web3": "^1.8.2",
+    "yargs": "^17.0.20"
+  },
+  "dependencies": {
+    "@iota/iota-sdk": "^0.5.0",
+    "@pythnetwork/price-service-client": "workspace:*",
+    "buffer": "^6.0.3"
+  }
+}

+ 21 - 0
target_chains/sui/sdk/js-iota/src/IotaPriceServiceConnection.ts

@@ -0,0 +1,21 @@
+import {
+  PriceServiceConnection,
+  HexString,
+} from "@pythnetwork/price-service-client";
+import { Buffer } from "buffer";
+
+export class IotaPriceServiceConnection extends PriceServiceConnection {
+  /**
+   * Gets price update data (either batch price attestation VAAs or accumulator messages, depending on the chosen endpoint), which then
+   * can be submitted to the Pyth contract to update the prices. This will throw an axios error if there is a network problem or
+   * the price service returns a non-ok response (e.g: Invalid price ids)
+   *
+   * @param priceIds Array of hex-encoded price ids.
+   * @returns Array of buffers containing the price update data.
+   */
+  async getPriceFeedsUpdateData(priceIds: HexString[]): Promise<Buffer[]> {
+    // Fetch the latest price feed update VAAs from the price service
+    const latestVaas = await this.getLatestVaas(priceIds);
+    return latestVaas.map((vaa) => Buffer.from(vaa, "base64"));
+  }
+}

+ 304 - 0
target_chains/sui/sdk/js-iota/src/client.ts

@@ -0,0 +1,304 @@
+import { IotaClient } from "@iota/iota-sdk/client";
+import { IOTA_CLOCK_OBJECT_ID } from "@iota/iota-sdk/utils";
+import { Transaction } from "@iota/iota-sdk/transactions";
+import { bcs } from "@iota/iota-sdk/bcs";
+import { HexString } from "@pythnetwork/price-service-client";
+import { Buffer } from "buffer";
+
+const MAX_ARGUMENT_SIZE = 16 * 1024;
+export type ObjectId = string;
+
+export class IotaPythClient {
+  private pythPackageId: ObjectId | undefined;
+  private wormholePackageId: ObjectId | undefined;
+  private priceTableInfo: { id: ObjectId; fieldType: ObjectId } | undefined;
+  private priceFeedObjectIdCache: Map<HexString, ObjectId> = new Map();
+  private baseUpdateFee: number | undefined;
+  constructor(
+    public provider: IotaClient,
+    public pythStateId: ObjectId,
+    public wormholeStateId: ObjectId
+  ) {
+    this.pythPackageId = undefined;
+    this.wormholePackageId = undefined;
+  }
+
+  async getBaseUpdateFee(): Promise<number> {
+    if (this.baseUpdateFee === undefined) {
+      const result = await this.provider.getObject({
+        id: this.pythStateId,
+        options: { showContent: true },
+      });
+      if (
+        !result.data ||
+        !result.data.content ||
+        result.data.content.dataType !== "moveObject"
+      )
+        throw new Error("Unable to fetch pyth state object");
+      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+      // @ts-ignore
+      this.baseUpdateFee = result.data.content.fields.base_update_fee as number;
+    }
+
+    return this.baseUpdateFee;
+  }
+
+  /**
+   * getPackageId returns the latest package id that the object belongs to. Use this to
+   * fetch the latest package id for a given object id and handle package upgrades automatically.
+   * @param objectId
+   * @returns package id
+   */
+  async getPackageId(objectId: ObjectId): Promise<ObjectId> {
+    const state = await this.provider
+      .getObject({
+        id: objectId,
+        options: {
+          showContent: true,
+        },
+      })
+      .then((result) => {
+        if (result.data?.content?.dataType == "moveObject") {
+          return result.data.content.fields;
+        }
+        console.log(result.data?.content);
+
+        throw new Error(`Cannot fetch package id for object ${objectId}`);
+      });
+
+    if ("upgrade_cap" in state) {
+      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+      // @ts-ignore
+      return state.upgrade_cap.fields.package;
+    }
+
+    throw new Error("upgrade_cap not found");
+  }
+
+  /**
+   * Adds the commands for calling wormhole and verifying the vaas and returns the verified vaas.
+   * @param vaas array of vaas to verify
+   * @param tx transaction block to add commands to
+   */
+  async verifyVaas(vaas: Buffer[], tx: Transaction) {
+    const wormholePackageId = await this.getWormholePackageId();
+    const verifiedVaas = [];
+    for (const vaa of vaas) {
+      const [verifiedVaa] = tx.moveCall({
+        target: `${wormholePackageId}::vaa::parse_and_verify`,
+        arguments: [
+          tx.object(this.wormholeStateId),
+          tx.pure(
+            bcs
+              .vector(bcs.U8)
+              .serialize(Array.from(vaa), {
+                maxSize: MAX_ARGUMENT_SIZE,
+              })
+              .toBytes()
+          ),
+          tx.object(IOTA_CLOCK_OBJECT_ID),
+        ],
+      });
+      verifiedVaas.push(verifiedVaa);
+    }
+    return verifiedVaas;
+  }
+
+  /**
+   * Adds the necessary commands for updating the pyth price feeds to the transaction block.
+   * @param tx transaction block to add commands to
+   * @param updates array of price feed updates received from the price service
+   * @param feedIds array of feed ids to update (in hex format)
+   */
+  async updatePriceFeeds(
+    tx: Transaction,
+    updates: Buffer[],
+    feedIds: HexString[]
+  ): Promise<ObjectId[]> {
+    const packageId = await this.getPythPackageId();
+
+    let priceUpdatesHotPotato;
+    if (updates.length > 1) {
+      throw new Error(
+        "SDK does not support sending multiple accumulator messages in a single transaction"
+      );
+    }
+    const vaa = this.extractVaaBytesFromAccumulatorMessage(updates[0]);
+    const verifiedVaas = await this.verifyVaas([vaa], tx);
+    [priceUpdatesHotPotato] = tx.moveCall({
+      target: `${packageId}::pyth::create_authenticated_price_infos_using_accumulator`,
+      arguments: [
+        tx.object(this.pythStateId),
+        tx.pure(
+          bcs
+            .vector(bcs.U8)
+            .serialize(Array.from(updates[0]), {
+              maxSize: MAX_ARGUMENT_SIZE,
+            })
+            .toBytes()
+        ),
+        verifiedVaas[0],
+        tx.object(IOTA_CLOCK_OBJECT_ID),
+      ],
+    });
+
+    const priceInfoObjects: ObjectId[] = [];
+    const baseUpdateFee = await this.getBaseUpdateFee();
+    const coins = tx.splitCoins(
+      tx.gas,
+      feedIds.map(() => tx.pure.u64(baseUpdateFee))
+    );
+    let coinId = 0;
+    for (const feedId of feedIds) {
+      const priceInfoObjectId = await this.getPriceFeedObjectId(feedId);
+      if (!priceInfoObjectId) {
+        throw new Error(
+          `Price feed ${feedId} not found, please create it first`
+        );
+      }
+      priceInfoObjects.push(priceInfoObjectId);
+      [priceUpdatesHotPotato] = tx.moveCall({
+        target: `${packageId}::pyth::update_single_price_feed`,
+        arguments: [
+          tx.object(this.pythStateId),
+          priceUpdatesHotPotato,
+          tx.object(priceInfoObjectId),
+          coins[coinId],
+          tx.object(IOTA_CLOCK_OBJECT_ID),
+        ],
+      });
+      coinId++;
+    }
+    tx.moveCall({
+      target: `${packageId}::hot_potato_vector::destroy`,
+      arguments: [priceUpdatesHotPotato],
+      typeArguments: [`${packageId}::price_info::PriceInfo`],
+    });
+    return priceInfoObjects;
+  }
+  async createPriceFeed(tx: Transaction, updates: Buffer[]) {
+    const packageId = await this.getPythPackageId();
+    if (updates.length > 1) {
+      throw new Error(
+        "SDK does not support sending multiple accumulator messages in a single transaction"
+      );
+    }
+    const vaa = this.extractVaaBytesFromAccumulatorMessage(updates[0]);
+    const verifiedVaas = await this.verifyVaas([vaa], tx);
+    tx.moveCall({
+      target: `${packageId}::pyth::create_price_feeds_using_accumulator`,
+      arguments: [
+        tx.object(this.pythStateId),
+        tx.pure(
+          bcs
+            .vector(bcs.U8)
+            .serialize(Array.from(updates[0]), {
+              maxSize: MAX_ARGUMENT_SIZE,
+            })
+            .toBytes()
+        ),
+        verifiedVaas[0],
+        tx.object(IOTA_CLOCK_OBJECT_ID),
+      ],
+    });
+  }
+
+  /**
+   * Get the packageId for the wormhole package if not already cached
+   */
+  async getWormholePackageId() {
+    if (!this.wormholePackageId) {
+      this.wormholePackageId = await this.getPackageId(this.wormholeStateId);
+    }
+    return this.wormholePackageId;
+  }
+
+  /**
+   * Get the packageId for the pyth package if not already cached
+   */
+  async getPythPackageId() {
+    if (!this.pythPackageId) {
+      this.pythPackageId = await this.getPackageId(this.pythStateId);
+    }
+    return this.pythPackageId;
+  }
+
+  /**
+   * Get the priceFeedObjectId for a given feedId if not already cached
+   * @param feedId
+   */
+  async getPriceFeedObjectId(feedId: HexString): Promise<ObjectId | undefined> {
+    const normalizedFeedId = feedId.replace("0x", "");
+    if (!this.priceFeedObjectIdCache.has(normalizedFeedId)) {
+      const { id: tableId, fieldType } = await this.getPriceTableInfo();
+      const result = await this.provider.getDynamicFieldObject({
+        parentId: tableId,
+        name: {
+          type: `${fieldType}::price_identifier::PriceIdentifier`,
+          value: {
+            bytes: Array.from(Buffer.from(normalizedFeedId, "hex")),
+          },
+        },
+      });
+      if (!result.data || !result.data.content) {
+        return undefined;
+      }
+      if (result.data.content.dataType !== "moveObject") {
+        throw new Error("Price feed type mismatch");
+      }
+      this.priceFeedObjectIdCache.set(
+        normalizedFeedId,
+        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+        // @ts-ignore
+        result.data.content.fields.value
+      );
+    }
+    return this.priceFeedObjectIdCache.get(normalizedFeedId);
+  }
+
+  /**
+   * Fetches the price table object id for the current state id if not cached
+   * @returns price table object id
+   */
+  async getPriceTableInfo(): Promise<{ id: ObjectId; fieldType: ObjectId }> {
+    if (this.priceTableInfo === undefined) {
+      const result = await this.provider.getDynamicFieldObject({
+        parentId: this.pythStateId,
+        name: {
+          type: "vector<u8>",
+          value: "price_info",
+        },
+      });
+      if (!result.data || !result.data.type) {
+        throw new Error(
+          "Price Table not found, contract may not be initialized"
+        );
+      }
+      let type = result.data.type.replace("0x2::table::Table<", "");
+      type = type.replace(
+        "::price_identifier::PriceIdentifier, 0x2::object::ID>",
+        ""
+      );
+      this.priceTableInfo = { id: result.data.objectId, fieldType: type };
+    }
+    return this.priceTableInfo;
+  }
+
+  /**
+   * Obtains the vaa bytes embedded in an accumulator message.
+   * @param accumulatorMessage - the accumulator price update message
+   * @returns vaa bytes as a uint8 array
+   */
+  extractVaaBytesFromAccumulatorMessage(accumulatorMessage: Buffer): Buffer {
+    // the first 6 bytes in the accumulator message encode the header, major, and minor bytes
+    // we ignore them, since we are only interested in the VAA bytes
+    const trailingPayloadSize = accumulatorMessage.readUint8(6);
+    const vaaSizeOffset =
+      7 + // header bytes (header(4) + major(1) + minor(1) + trailing payload size(1))
+      trailingPayloadSize + // trailing payload (variable number of bytes)
+      1; // proof_type (1 byte)
+    const vaaSize = accumulatorMessage.readUint16BE(vaaSizeOffset);
+    const vaaOffset = vaaSizeOffset + 2;
+    return accumulatorMessage.subarray(vaaOffset, vaaOffset + vaaSize);
+  }
+}

+ 97 - 0
target_chains/sui/sdk/js-iota/src/examples/IotaRelay.ts

@@ -0,0 +1,97 @@
+import yargs from "yargs";
+import { hideBin } from "yargs/helpers";
+import { IotaClient } from "@iota/iota-sdk/client";
+import { Transaction } from "@iota/iota-sdk/transactions";
+import { Ed25519Keypair } from "@iota/iota-sdk/keypairs/ed25519";
+
+import { Buffer } from "buffer";
+import { IotaPythClient } from "../client";
+import { IotaPriceServiceConnection } from "../index";
+
+const argvPromise = yargs(hideBin(process.argv))
+  .option("feed-id", {
+    description:
+      "Price feed ids to update without the leading 0x (e.g f9c0172ba10dfa4d19088d94f5bf61d3b54d5bd7483a322a982e1373ee8ea31b). Can be provided multiple times for multiple feed updates",
+    type: "array",
+    demandOption: true,
+  })
+  .option("hermes", {
+    description: "Endpoint URL for Hermes. e.g: https://hermes.pyth.network",
+    type: "string",
+    demandOption: true,
+  })
+  .option("full-node", {
+    description:
+      "URL of the full IOTA node RPC endpoint. e.g: https://api.testnet.iota.cafe/",
+    type: "string",
+    demandOption: true,
+  })
+  .option("pyth-state-id", {
+    description: "Pyth state object id.",
+    type: "string",
+    demandOption: true,
+  })
+  .option("wormhole-state-id", {
+    description: "Wormhole state object id.",
+    type: "string",
+    demandOption: true,
+  }).argv;
+
+export function getProvider(url: string) {
+  return new IotaClient({ url });
+}
+async function run() {
+  if (process.env.IOTA_KEY === undefined) {
+    throw new Error(`IOTA_KEY environment variable should be set.`);
+  }
+
+  const argv = await argvPromise;
+
+  // Fetch the latest price feed update data from the Price Service
+  const connection = new IotaPriceServiceConnection(argv["hermes"]);
+  const feeds = argv["feed-id"] as string[];
+
+  const provider = getProvider(argv["full-node"]);
+  const wormholeStateId = argv["wormhole-state-id"];
+  const pythStateId = argv["pyth-state-id"];
+
+  const client = new IotaPythClient(provider, pythStateId, wormholeStateId);
+  const newFeeds = [];
+  const existingFeeds = [];
+  for (const feed of feeds) {
+    if ((await client.getPriceFeedObjectId(feed)) == undefined) {
+      newFeeds.push(feed);
+    } else {
+      existingFeeds.push(feed);
+    }
+  }
+  console.log({
+    newFeeds,
+    existingFeeds,
+  });
+  const tx = new Transaction();
+  if (existingFeeds.length > 0) {
+    const updateData = await connection.getPriceFeedsUpdateData(existingFeeds);
+    await client.updatePriceFeeds(tx, updateData, existingFeeds);
+  }
+  if (newFeeds.length > 0) {
+    const updateData = await connection.getPriceFeedsUpdateData(newFeeds);
+    await client.createPriceFeed(tx, updateData);
+  }
+
+  const wallet = Ed25519Keypair.fromSecretKey(
+    Buffer.from(process.env.IOTA_KEY, "hex")
+  );
+
+  const result = await provider.signAndExecuteTransaction({
+    signer: wallet,
+    transaction: tx,
+    options: {
+      showEffects: true,
+      showEvents: true,
+    },
+  });
+  console.dir(result, { depth: null });
+}
+
+run();

+ 11 - 0
target_chains/sui/sdk/js-iota/src/index.ts

@@ -0,0 +1,11 @@
+export { IotaPriceServiceConnection } from "./IotaPriceServiceConnection";
+export { IotaPythClient } from "./client";
+
+export {
+  DurationInMs,
+  HexString,
+  Price,
+  PriceFeed,
+  PriceServiceConnectionConfig,
+  UnixTimestamp,
+} from "@pythnetwork/price-service-client";

+ 14 - 0
target_chains/sui/sdk/js-iota/tsconfig.json

@@ -0,0 +1,14 @@
+{
+  "extends": "../../../../tsconfig.base.json",
+  "compilerOptions": {
+    "target": "esnext",
+    "module": "commonjs",
+    "declaration": true,
+    "outDir": "./lib",
+    "rootDir": "src/",
+    "strict": true,
+    "esModuleInterop": true
+  },
+  "include": ["src"],
+  "exclude": ["node_modules", "**/__tests__/*"]
+}

+ 3 - 3
target_chains/sui/vendor/README.md

@@ -1,8 +1,8 @@
 # Vendored dependencies for SUI contract
 
-This directory contains the wormhole dependencies used for deploying Pyth contracts on the chains
-that Wormhole is not officially deployed on. For each network, a slightly different variant of the
-code should be used that has the `CHAIN_ID` and `Move.toml` modified. Therefore, we are storing
+This directory contains the wormhole dependencies used for deploying Pyth contracts on the chains that Wormhole is not
+officially deployed on. For each network, a slightly different variant of the code should be used that has the
+`CHAIN_ID` constant (in `wormhole/sources/state.move`) and `Move.toml` modified. Therefore, we are storing
 each of them in a separate directory.
 
 The Wormhole contract is taken out of commit

+ 2 - 0
target_chains/sui/vendor/wormhole_iota_testnet/.gitignore

@@ -0,0 +1,2 @@
+deploy.out
+sui.log.*

+ 13 - 0
target_chains/sui/vendor/wormhole_iota_testnet/Docker.md

@@ -0,0 +1,13 @@
+# first build the image
+
+cd ..; DOCKER_BUILDKIT=1 docker build --no-cache --progress plain -f sui/Dockerfile.base -t sui .
+
+# tag the image with the appropriate version
+
+docker tag sui:latest ghcr.io/wormhole-foundation/sui:1.19.1-mainnet
+
+# push to ghcr
+
+docker push ghcr.io/wormhole-foundation/sui:1.19.1-mainnet
+
+echo remember to update both Dockerfile and Dockerfile.export

+ 33 - 0
target_chains/sui/vendor/wormhole_iota_testnet/Dockerfile

@@ -0,0 +1,33 @@
+FROM cli-gen AS cli-export
+FROM const-gen AS const-export
+FROM ghcr.io/wormhole-foundation/sui:1.19.1-mainnet@sha256:544a1b2aa5701fae25a19aed3c5e8c24e0caf7d1c9f511b6844d339a8f0b2a00 as sui
+
+# initial run
+# COPY sui/devnet/genesis_config genesis_config
+# RUN sui genesis -f --from-config genesis_config
+
+# subsequent runs after committing files from /root/.sui/sui_config/
+COPY sui/devnet/ /root/.sui/sui_config/
+
+WORKDIR /tmp
+
+COPY sui/scripts/ scripts
+COPY sui/wormhole/ wormhole
+COPY sui/token_bridge/ token_bridge
+COPY sui/examples/ examples
+COPY sui/Makefile Makefile
+
+# Copy .env and CLI
+COPY --from=const-export .env .env
+COPY --from=cli-export clients/js /cli
+
+# Link `worm`
+WORKDIR /cli
+
+RUN npm link
+
+FROM sui AS tests
+
+WORKDIR /tmp
+
+RUN --mount=type=cache,target=/root/.move,id=move_cache make test

+ 24 - 0
target_chains/sui/vendor/wormhole_iota_testnet/Dockerfile.base

@@ -0,0 +1,24 @@
+FROM rust:1.62@sha256:5777f201f507075309c4d2d1c1e8d8219e654ae1de154c844341050016a64a0c as sui-node
+
+WORKDIR /tmp
+
+RUN curl -L https://github.com/MystenLabs/sui/releases/download/mainnet-v1.19.1/sui-mainnet-v1.19.1-ubuntu-x86_64.tgz > sui-mainnet-v1.19.1-ubuntu-x86_64.tgz
+RUN echo "6a8cc96759760293143a00fe7031a5fea70d2dff5b98d18c0470c09555da63e0  sui-mainnet-v1.19.1-ubuntu-x86_64.tgz" | sha256sum -c --status
+
+RUN tar -xvf sui-mainnet-v1.19.1-ubuntu-x86_64.tgz
+RUN mv target/release/sui-ubuntu-x86_64 /bin/sui
+RUN mv target/release/sui-faucet-ubuntu-x86_64 /bin/sui-faucet
+RUN mv target/release/sui-node-ubuntu-x86_64 /bin/sui-node
+
+RUN rm sui-mainnet-v1.19.1-ubuntu-x86_64.tgz
+
+RUN apt-get update
+RUN apt-get install -y ca-certificates curl gnupg
+RUN mkdir -p /etc/apt/keyrings
+RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
+
+ARG NODE_MAJOR=18
+RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
+
+RUN apt-get update
+RUN apt-get install nodejs -y

+ 15 - 0
target_chains/sui/vendor/wormhole_iota_testnet/Makefile

@@ -0,0 +1,15 @@
+TEST_CONTRACT_DIRS := wormhole token_bridge examples/coins examples/core_messages
+CLEAN_CONTRACT_DIRS := wormhole token_bridge examples/coins examples/core_messages
+
+.PHONY: clean
+clean:
+	$(foreach dir,$(TEST_CONTRACT_DIRS), make -C $(dir) $@ &&) true
+
+.PHONY: test
+test:
+	$(foreach dir,$(TEST_CONTRACT_DIRS), make -C $(dir) $@ &&) true
+
+test-docker:
+	DOCKER_BUILDKIT=1 docker build --progress plain  -f ../Dockerfile.cli -t cli-gen ..
+	DOCKER_BUILDKIT=1 docker build --build-arg num_guardians=1 --progress plain -f ../Dockerfile.const -t const-gen ..
+	DOCKER_BUILDKIT=1 docker build -f Dockerfile ..

+ 114 - 0
target_chains/sui/vendor/wormhole_iota_testnet/NOTES.md

@@ -0,0 +1,114 @@
+brew install cmake
+
+ rustup install stable-x86_64-apple-darwin
+ #rustup target add stable-x86_64-apple-darwin
+ rustup target add x86_64-apple-darwin
+
+=== Building
+
+  % ./node_builder.sh
+
+=== Running
+
+  % ./start_node.sh
+
+# If you don't remember your newly generated address
+
+   % sui client addresses
+   Showing 1 results.
+   0x13b3cb89cf3226d3b860294fc75dc6c91f0c5ecf
+
+# Give yourself some money
+
+   % scripts/faucet.sh `sui client addresses | tail -1`
+
+# Looking at the prefunded address
+
+   % sui client objects --address 0x13b3cb89cf3226d3b860294fc75dc6c91f0c5ecf
+
+=== Boot tilt
+
+# fund our standard account
+
+ We don't run a faucet since it doesn't always unlock the client LOCK files.  So, instead we just steal a chunk of coins
+ from the default accounts created when the node was initialized.  Once sui is showing as live...
+
+``` sh
+ % kubectl exec -it sui-0 -c sui-node -- /tmp/funder.sh
+```
+
+# getting into the sui k8s node (if you need to crawl around)
+
+   kubectl exec -it sui-0 -c sui-node -- /bin/bash
+   kubectl exec -it guardian-0 -c guardiand -- /bin/bash
+
+# setup the client.yaml
+
+``` sh
+  % rm -rf $HOME/.sui
+  % sui keytool import "daughter exclude wheat pudding police weapon giggle taste space whip satoshi occur" ed25519
+  % sui client
+```
+     point it at http://localhost:9000.  The key you create doesn't matter.
+
+# edit $HOME/.sui/sui_config/client.yaml
+
+``` sh
+   sed -i -e 's/active_address.*/active_address: "0x13b3cb89cf3226d3b860294fc75dc6c91f0c5ecf"/' ~/.sui/sui_config/client.yaml 
+```
+
+
+# deploy the contract
+
+``` sh
+  % scripts/deploy.sh
+```
+
+# start the watcher
+
+``` sh
+  % . env.sh
+  % python3 tests/ws.py
+```
+
+# publish a message (different window)
+
+``` sh
+  % . env.sh
+  % scripts/publish_message.sh
+```
+
+==
+
+docker run -it -v `pwd`:`pwd` -w `pwd` --net=host ghcr.io/wormhole-foundation/sui:0.16.0 bash
+dnf -y install git make
+
+``` sh
+  % rm -rf $HOME/.sui
+  % sui keytool import "daughter exclude wheat pudding police weapon giggle taste space whip satoshi occur" secp256k1
+  % sui client
+```
+
+to get a new emitter
+
+  kubectl exec -it sui-0 -c sui-node -- /tmp/funder.sh
+  scripts/deploy.sh
+  . env.sh
+  sui client call --function get_new_emitter --module wormhole --package $WORM_PACKAGE --gas-budget 20000 --args \"$WORM_STATE\" 
+
+  sui client objects
+  scripts/publish_message.sh 0x165ef7366c4267c6506bcf63d2419556f34f48d6
+
+
+curl -s -X POST -d '{"jsonrpc":"2.0", "id": 1, "method": "sui_getEvents", "params": [{"MoveEvent": "0xf4179152ab02e4212d7e7b20f37a9a86ab6d50fb::state::WormholeMessage"}, null, 10, true]}' -H 'Content-Type: application/json' http://127.0.0.1:9002 | jq
+
+curl -s -X POST -d '{"jsonrpc":"2.0", "id": 1, "method": "sui_getEvents", "params": [{"Transaction": "cL+uWFEVcQrkAiOxOJmaK7JmlOJdE3/8X5JFbJwBxCQ="}, null, 10, true]}' -H 'Content-Type: application/json' http://127.0.0.1:9002 | jq
+
+"txhash": "0x70bfae585115710ae40223b138999a2bb26694e25d137ffc5f92456c9c01c424", "txhash_b58": "8b8Bn8MUqAWeVz2BE5hMicC9KaRkV6UM4v1JLWGUjxcT", "
+Digest: cL+uWFEVcQrkAiOxOJmaK7JmlOJdE3/8X5JFbJwBxCQ=
+
+  kubectl exec -it guardian-0 -- /guardiand admin send-observation-request --socket /tmp/admin.sock 21 70bfae585115710ae40223b138999a2bb26694e25d137ffc5f92456c9c01c424
+
+// curl -s -X POST -d '{"jsonrpc":"2.0", "id": 1, "method": "sui_getCommitteeInfo", "params": []}' -H 'Content-Type: application/json' http://127.0.0.1:9002 | jq
+
+// curl -s -X POST -d '{"jsonrpc":"2.0", "id": 1, "method": "sui_getLatestCheckpointSequenceNumber", "params": []}' -H 'Content-Type: application/json' http://127.0.0.1:9000 

+ 130 - 0
target_chains/sui/vendor/wormhole_iota_testnet/README.md

@@ -0,0 +1,130 @@
+# Wormhole on Sui
+
+This folder contains the reference implementation of the Wormhole cross-chain
+messaging protocol smart contracts on the [Sui](https://mystenlabs.com/)
+blockchain, implemented in the [Move](https://move-book.com/) programming
+language.
+
+# Project structure
+
+The project is laid out as follows:
+
+- [wormhole](./wormhole) the core messaging layer
+- [token_bridge](./token_bridge) the asset transfer layer
+- [coin](./coin) a template for creating Wormhole wrapped coins
+
+# Installation
+
+Make sure your Cargo version is at least 1.65.0 and then follow the steps below:
+
+- https://docs.sui.io/build/install
+
+#https://docs.sui.io/guides/developer/getting-started/sui-install# Prerequisites
+
+Install the `Sui` CLI. This tool is used to compile the contracts and run the tests.
+
+```sh
+cargo install --locked --git https://github.com/MystenLabs/sui.git --rev 041c5f2bae2fe52079e44b70514333532d69f4e6 sui
+```
+
+Some useful Sui CLI commands are
+
+- `sui start` to spin up a local network
+- `rpc-server` to start a server for handling rpc calls
+
+Next, install the [worm](../clients/js/README.md) CLI tool by running
+
+```sh
+wormhole/clients/js $ make install
+```
+
+`worm` is the swiss army knife for interacting with wormhole contracts on all
+supported chains, and generating signed messages (VAAs) for testing.
+
+As an optional, but recommended step, install the
+[move-analyzer](https://github.com/move-language/move/tree/main/language/move-analyzer)
+Language Server (LSP):
+
+```sh
+cargo install --git https://github.com/move-language/move.git move-analyzer --branch main --features "address32"
+```
+
+This installs the LSP backend which is then supported by most popular editors such as [emacs](https://github.com/emacs-lsp/lsp-mode), [vim](https://github.com/neoclide/coc.nvim), and even [vscode](https://marketplace.visualstudio.com/items?itemName=move.move-analyzer).
+
+<details>
+    <summary>For emacs, you may need to add the following to your config file:</summary>
+
+```lisp
+;; Move
+(define-derived-mode move-mode rust-mode "Move"
+  :group 'move-mode)
+
+(add-to-list 'auto-mode-alist '("\\.move\\'" . move-mode))
+
+(with-eval-after-load 'lsp-mode
+  (add-to-list 'lsp-language-id-configuration
+    '(move-mode . "move"))
+
+  (lsp-register-client
+    (make-lsp-client :new-connection (lsp-stdio-connection "move-analyzer")
+                     :activation-fn (lsp-activate-on "move")
+                     :server-id 'move-analyzer)))
+```
+
+</details>
+
+## Building & running tests
+
+The project uses a simple `make`-based build system for building and running
+tests. Running `make test` in this directory will run the tests for each
+contract. If you only want to run the tests for, say, the token bridge contract,
+then you can run `make test` in the `token_bridge` directory, or run `make -C
+token_bridge test` from this directory.
+
+Additionally, `make test-docker` runs the tests in a docker container which is
+set up with all the necessary dependencies. This is the command that runs in CI.
+
+## Running a local validator and deploying the contracts to it
+
+Simply run
+
+```sh
+worm start-validator sui
+```
+
+which will start a local sui validator with an RPC endpoint at `0.0.0.0:9000`.
+
+Once the validator is running, the contracts are ready to deploy. In the
+[scripts](./scripts) directory, run
+
+```sh
+scripts $ ./deploy.sh devnet
+```
+
+This will deploy the core contract and the token bridge.
+
+When you make a change to the contract, you can simply restart the validator and
+run the deploy script again.
+
+<!-- However, a better way is to run one of the following scripts:
+
+``` sh
+scripts $ ./upgrade devnet Core # for upgrading the wormhole contract
+scripts $ ./upgrade devnet TokenBridge # for upgrading the token bridge contract
+scripts $ ./upgrade devnet NFTBridge # for upgrading the NFT bridge contract
+```
+
+Behind the scenes, these scripts exercise the whole contract upgrade code path
+(see below), including generating and verifying a signed governance action, and
+the Move bytecode verifier checking ABI compatibility. If an upgrade here fails
+due to incompatibility, it will likely on mainnet too. (TODO: add CI action to
+simulate upgrades against main when there's a stable version) -->
+
+# Implementation notes / coding practices
+
+In this section, we describe some of the implementation design decisions and
+coding practices we converged on along the way. Note that the coding guidelines
+are prescriptive rather than descriptive, and the goal is for the contracts to
+ultimately follow these, but they might not during earlier development phases.
+
+### TODO

+ 125 - 0
target_chains/sui/vendor/wormhole_iota_testnet/devnet/127.0.0.1-36219.yaml

@@ -0,0 +1,125 @@
+---
+protocol-key-pair:
+  value: avYcyVgYMXTyaUYh9IRwLK0gSzl7YF6ZQDAbrS1Bhvo=
+worker-key-pair:
+  value: AAvfYqj1HPsXmthZ1t2Uw19vU6tdhK48YAFgkhJ7P/sV
+account-key-pair:
+  value: ABmHnCaxw0GWzW+1MZYfTDonS1wZsO8KO37SXgm6pqc6
+network-key-pair:
+  value: AEpJ6PVCvnrtaxREy8UNSiDwLPPrZMh12TbgELadmAHB
+db-path: /root/.sui/sui_config/authorities_db/8dcff6d15504
+network-address: /ip4/127.0.0.1/tcp/36219/http
+json-rpc-address: "127.0.0.1:37179"
+enable-experimental-rest-api: true
+metrics-address: "127.0.0.1:44423"
+admin-interface-port: 35585
+consensus-config:
+  address: /ip4/127.0.0.1/tcp/35107/http
+  db-path: /root/.sui/sui_config/consensus_db/8dcff6d15504
+  internal-worker-address: ~
+  max-pending-transactions: ~
+  max-submit-position: ~
+  submit-delay-step-override-millis: ~
+  narwhal-config:
+    header_num_of_batches_threshold: 32
+    max_header_num_of_batches: 1000
+    max_header_delay: 1000ms
+    min_header_delay: 500ms
+    gc_depth: 50
+    sync_retry_delay: 5000ms
+    sync_retry_nodes: 3
+    batch_size: 5000000
+    max_batch_delay: 100ms
+    max_concurrent_requests: 500000
+    prometheus_metrics:
+      socket_addr: /ip4/127.0.0.1/tcp/42177/http
+    network_admin_server:
+      primary_network_admin_server_port: 34745
+      worker_network_admin_server_base_port: 43111
+    anemo:
+      send_certificate_rate_limit: ~
+      report_batch_rate_limit: ~
+      request_batches_rate_limit: ~
+enable-event-processing: false
+enable-index-processing: true
+grpc-load-shed: ~
+grpc-concurrency-limit: 20000000000
+p2p-config:
+  listen-address: "127.0.0.1:41551"
+  external-address: /ip4/127.0.0.1/udp/41551
+  state-sync:
+    checkpoint-content-timeout-ms: 10000
+genesis:
+  genesis-file-location: /root/.sui/sui_config/genesis.blob
+authority-store-pruning-config:
+  num-latest-epoch-dbs-to-retain: 3
+  epoch-db-pruning-period-secs: 3600
+  num-epochs-to-retain: 0
+  max-checkpoints-in-batch: 10
+  max-transactions-in-batch: 1000
+end-of-epoch-broadcast-channel-capacity: 128
+checkpoint-executor-config:
+  checkpoint-execution-max-concurrency: 200
+  local-execution-timeout-sec: 30
+db-checkpoint-config:
+  perform-db-checkpoints-at-epoch-end: false
+indirect-objects-threshold: 18446744073709551615
+expensive-safety-check-config:
+  enable-epoch-sui-conservation-check: false
+  enable-deep-per-tx-sui-conservation-check: false
+  force-disable-epoch-sui-conservation-check: false
+  enable-state-consistency-check: false
+  force-disable-state-consistency-check: false
+  enable-secondary-index-checks: false
+transaction-deny-config:
+  package-publish-disabled: false
+  package-upgrade-disabled: false
+  shared-object-disabled: false
+  user-transaction-disabled: false
+  receiving-objects-disabled: false
+  zklogin-sig-disabled: false
+  zklogin-disabled-providers: []
+certificate-deny-config: {}
+state-debug-dump-config: {}
+state-archive-write-config:
+  concurrency: 0
+  use-for-pruning-watermark: false
+state-archive-read-config: []
+state-snapshot-write-config:
+  concurrency: 0
+indexer-max-subscriptions: ~
+transaction-kv-store-read-config:
+  base-url: ""
+jwk-fetch-interval-seconds: 3600
+zklogin-oauth-providers:
+  Mainnet:
+    - Facebook
+    - Google
+    - Twitch
+  Testnet:
+    - Facebook
+    - Google
+    - Twitch
+  Unknown:
+    - Apple
+    - Facebook
+    - Google
+    - Kakao
+    - Slack
+    - Twitch
+authority-overload-config:
+  max-txn-age-in-queue:
+    secs: 1
+    nanos: 0
+  overload-monitor-interval:
+    secs: 10
+    nanos: 0
+  execution-queue-latency-soft-limit:
+    secs: 1
+    nanos: 0
+  execution-queue-latency-hard-limit:
+    secs: 10
+    nanos: 0
+  max-load-shedding-percentage: 95
+  min-load-shedding-percentage-above-hard-limit: 50
+  safe-transaction-ready-rate: 100

+ 125 - 0
target_chains/sui/vendor/wormhole_iota_testnet/devnet/127.0.0.1-36853.yaml

@@ -0,0 +1,125 @@
+---
+protocol-key-pair:
+  value: OXnx3yM1C/ppgnDMx/o1d49fJs7E05kq11mXNae/O+I=
+worker-key-pair:
+  value: AE4ZKvLhbIyoYlv0y7q7aPHyU/Jty/D1AzILgYUs4VqC
+account-key-pair:
+  value: AEAh/lnBSwKKrazfLNz3J7DBu7W2EMuhcShk6MHJhxpT
+network-key-pair:
+  value: AHdOWNkwAgBFMTlwVSGkhI4COGDX40frs5xOz72DHvNm
+db-path: /root/.sui/sui_config/authorities_db/addeef94d898
+network-address: /ip4/127.0.0.1/tcp/36853/http
+json-rpc-address: "127.0.0.1:34043"
+enable-experimental-rest-api: true
+metrics-address: "127.0.0.1:45007"
+admin-interface-port: 36657
+consensus-config:
+  address: /ip4/127.0.0.1/tcp/45105/http
+  db-path: /root/.sui/sui_config/consensus_db/addeef94d898
+  internal-worker-address: ~
+  max-pending-transactions: ~
+  max-submit-position: ~
+  submit-delay-step-override-millis: ~
+  narwhal-config:
+    header_num_of_batches_threshold: 32
+    max_header_num_of_batches: 1000
+    max_header_delay: 1000ms
+    min_header_delay: 500ms
+    gc_depth: 50
+    sync_retry_delay: 5000ms
+    sync_retry_nodes: 3
+    batch_size: 5000000
+    max_batch_delay: 100ms
+    max_concurrent_requests: 500000
+    prometheus_metrics:
+      socket_addr: /ip4/127.0.0.1/tcp/44505/http
+    network_admin_server:
+      primary_network_admin_server_port: 45567
+      worker_network_admin_server_base_port: 43075
+    anemo:
+      send_certificate_rate_limit: ~
+      report_batch_rate_limit: ~
+      request_batches_rate_limit: ~
+enable-event-processing: false
+enable-index-processing: true
+grpc-load-shed: ~
+grpc-concurrency-limit: 20000000000
+p2p-config:
+  listen-address: "127.0.0.1:37183"
+  external-address: /ip4/127.0.0.1/udp/37183
+  state-sync:
+    checkpoint-content-timeout-ms: 10000
+genesis:
+  genesis-file-location: /root/.sui/sui_config/genesis.blob
+authority-store-pruning-config:
+  num-latest-epoch-dbs-to-retain: 3
+  epoch-db-pruning-period-secs: 3600
+  num-epochs-to-retain: 0
+  max-checkpoints-in-batch: 10
+  max-transactions-in-batch: 1000
+end-of-epoch-broadcast-channel-capacity: 128
+checkpoint-executor-config:
+  checkpoint-execution-max-concurrency: 200
+  local-execution-timeout-sec: 30
+db-checkpoint-config:
+  perform-db-checkpoints-at-epoch-end: false
+indirect-objects-threshold: 18446744073709551615
+expensive-safety-check-config:
+  enable-epoch-sui-conservation-check: false
+  enable-deep-per-tx-sui-conservation-check: false
+  force-disable-epoch-sui-conservation-check: false
+  enable-state-consistency-check: false
+  force-disable-state-consistency-check: false
+  enable-secondary-index-checks: false
+transaction-deny-config:
+  package-publish-disabled: false
+  package-upgrade-disabled: false
+  shared-object-disabled: false
+  user-transaction-disabled: false
+  receiving-objects-disabled: false
+  zklogin-sig-disabled: false
+  zklogin-disabled-providers: []
+certificate-deny-config: {}
+state-debug-dump-config: {}
+state-archive-write-config:
+  concurrency: 0
+  use-for-pruning-watermark: false
+state-archive-read-config: []
+state-snapshot-write-config:
+  concurrency: 0
+indexer-max-subscriptions: ~
+transaction-kv-store-read-config:
+  base-url: ""
+jwk-fetch-interval-seconds: 3600
+zklogin-oauth-providers:
+  Mainnet:
+    - Facebook
+    - Google
+    - Twitch
+  Testnet:
+    - Facebook
+    - Google
+    - Twitch
+  Unknown:
+    - Apple
+    - Facebook
+    - Google
+    - Kakao
+    - Slack
+    - Twitch
+authority-overload-config:
+  max-txn-age-in-queue:
+    secs: 1
+    nanos: 0
+  overload-monitor-interval:
+    secs: 10
+    nanos: 0
+  execution-queue-latency-soft-limit:
+    secs: 1
+    nanos: 0
+  execution-queue-latency-hard-limit:
+    secs: 10
+    nanos: 0
+  max-load-shedding-percentage: 95
+  min-load-shedding-percentage-above-hard-limit: 50
+  safe-transaction-ready-rate: 100

+ 125 - 0
target_chains/sui/vendor/wormhole_iota_testnet/devnet/127.0.0.1-39101.yaml

@@ -0,0 +1,125 @@
+---
+protocol-key-pair:
+  value: CyNkjqNVr3HrHTH7f/NLs7u5lUHJzuPAw0PqMTD2y2s=
+worker-key-pair:
+  value: AOuUqLZBJxwz++dkJA9sY0wvTykcCC6jSS3Jqz77IlRI
+account-key-pair:
+  value: AEUws4dzsXHsai5hVbK1O8jWOpPAJjtzdJl32Vxvoj83
+network-key-pair:
+  value: ADGySwzr54kpKui4vTatL4CtV4/1ffyyHuZ6CMyzZPGI
+db-path: /root/.sui/sui_config/authorities_db/b3fd5efb5c87
+network-address: /ip4/127.0.0.1/tcp/39101/http
+json-rpc-address: "127.0.0.1:38815"
+enable-experimental-rest-api: true
+metrics-address: "127.0.0.1:32833"
+admin-interface-port: 39835
+consensus-config:
+  address: /ip4/127.0.0.1/tcp/43831/http
+  db-path: /root/.sui/sui_config/consensus_db/b3fd5efb5c87
+  internal-worker-address: ~
+  max-pending-transactions: ~
+  max-submit-position: ~
+  submit-delay-step-override-millis: ~
+  narwhal-config:
+    header_num_of_batches_threshold: 32
+    max_header_num_of_batches: 1000
+    max_header_delay: 1000ms
+    min_header_delay: 500ms
+    gc_depth: 50
+    sync_retry_delay: 5000ms
+    sync_retry_nodes: 3
+    batch_size: 5000000
+    max_batch_delay: 100ms
+    max_concurrent_requests: 500000
+    prometheus_metrics:
+      socket_addr: /ip4/127.0.0.1/tcp/40195/http
+    network_admin_server:
+      primary_network_admin_server_port: 45269
+      worker_network_admin_server_base_port: 39967
+    anemo:
+      send_certificate_rate_limit: ~
+      report_batch_rate_limit: ~
+      request_batches_rate_limit: ~
+enable-event-processing: false
+enable-index-processing: true
+grpc-load-shed: ~
+grpc-concurrency-limit: 20000000000
+p2p-config:
+  listen-address: "127.0.0.1:36503"
+  external-address: /ip4/127.0.0.1/udp/36503
+  state-sync:
+    checkpoint-content-timeout-ms: 10000
+genesis:
+  genesis-file-location: /root/.sui/sui_config/genesis.blob
+authority-store-pruning-config:
+  num-latest-epoch-dbs-to-retain: 3
+  epoch-db-pruning-period-secs: 3600
+  num-epochs-to-retain: 0
+  max-checkpoints-in-batch: 10
+  max-transactions-in-batch: 1000
+end-of-epoch-broadcast-channel-capacity: 128
+checkpoint-executor-config:
+  checkpoint-execution-max-concurrency: 200
+  local-execution-timeout-sec: 30
+db-checkpoint-config:
+  perform-db-checkpoints-at-epoch-end: false
+indirect-objects-threshold: 18446744073709551615
+expensive-safety-check-config:
+  enable-epoch-sui-conservation-check: false
+  enable-deep-per-tx-sui-conservation-check: false
+  force-disable-epoch-sui-conservation-check: false
+  enable-state-consistency-check: false
+  force-disable-state-consistency-check: false
+  enable-secondary-index-checks: false
+transaction-deny-config:
+  package-publish-disabled: false
+  package-upgrade-disabled: false
+  shared-object-disabled: false
+  user-transaction-disabled: false
+  receiving-objects-disabled: false
+  zklogin-sig-disabled: false
+  zklogin-disabled-providers: []
+certificate-deny-config: {}
+state-debug-dump-config: {}
+state-archive-write-config:
+  concurrency: 0
+  use-for-pruning-watermark: false
+state-archive-read-config: []
+state-snapshot-write-config:
+  concurrency: 0
+indexer-max-subscriptions: ~
+transaction-kv-store-read-config:
+  base-url: ""
+jwk-fetch-interval-seconds: 3600
+zklogin-oauth-providers:
+  Mainnet:
+    - Facebook
+    - Google
+    - Twitch
+  Testnet:
+    - Facebook
+    - Google
+    - Twitch
+  Unknown:
+    - Apple
+    - Facebook
+    - Google
+    - Kakao
+    - Slack
+    - Twitch
+authority-overload-config:
+  max-txn-age-in-queue:
+    secs: 1
+    nanos: 0
+  overload-monitor-interval:
+    secs: 10
+    nanos: 0
+  execution-queue-latency-soft-limit:
+    secs: 1
+    nanos: 0
+  execution-queue-latency-hard-limit:
+    secs: 10
+    nanos: 0
+  max-load-shedding-percentage: 95
+  min-load-shedding-percentage-above-hard-limit: 50
+  safe-transaction-ready-rate: 100

+ 125 - 0
target_chains/sui/vendor/wormhole_iota_testnet/devnet/127.0.0.1-39187.yaml

@@ -0,0 +1,125 @@
+---
+protocol-key-pair:
+  value: VTDx4HjVmRBqdqBWg2zN+zcFE20io3CrBchGy/iV1lo=
+worker-key-pair:
+  value: ACsedxHqp9Son+iep5m4+eKM+yMc8hYyqhrDJLUucJ+G
+account-key-pair:
+  value: AAAujq3QBAO4JNOYeKBW5dMn+8N4zE4bEHx+Bv9Y5tKr
+network-key-pair:
+  value: AOFPA8/e6v4OpU5U0308llf51JfsxVla/pclVq9Ztajb
+db-path: /root/.sui/sui_config/authorities_db/99f25ef61f80
+network-address: /ip4/127.0.0.1/tcp/39187/http
+json-rpc-address: "127.0.0.1:33519"
+enable-experimental-rest-api: true
+metrics-address: "127.0.0.1:33765"
+admin-interface-port: 33957
+consensus-config:
+  address: /ip4/127.0.0.1/tcp/41413/http
+  db-path: /root/.sui/sui_config/consensus_db/99f25ef61f80
+  internal-worker-address: ~
+  max-pending-transactions: ~
+  max-submit-position: ~
+  submit-delay-step-override-millis: ~
+  narwhal-config:
+    header_num_of_batches_threshold: 32
+    max_header_num_of_batches: 1000
+    max_header_delay: 1000ms
+    min_header_delay: 500ms
+    gc_depth: 50
+    sync_retry_delay: 5000ms
+    sync_retry_nodes: 3
+    batch_size: 5000000
+    max_batch_delay: 100ms
+    max_concurrent_requests: 500000
+    prometheus_metrics:
+      socket_addr: /ip4/127.0.0.1/tcp/35645/http
+    network_admin_server:
+      primary_network_admin_server_port: 44333
+      worker_network_admin_server_base_port: 43351
+    anemo:
+      send_certificate_rate_limit: ~
+      report_batch_rate_limit: ~
+      request_batches_rate_limit: ~
+enable-event-processing: false
+enable-index-processing: true
+grpc-load-shed: ~
+grpc-concurrency-limit: 20000000000
+p2p-config:
+  listen-address: "127.0.0.1:40869"
+  external-address: /ip4/127.0.0.1/udp/40869
+  state-sync:
+    checkpoint-content-timeout-ms: 10000
+genesis:
+  genesis-file-location: /root/.sui/sui_config/genesis.blob
+authority-store-pruning-config:
+  num-latest-epoch-dbs-to-retain: 3
+  epoch-db-pruning-period-secs: 3600
+  num-epochs-to-retain: 0
+  max-checkpoints-in-batch: 10
+  max-transactions-in-batch: 1000
+end-of-epoch-broadcast-channel-capacity: 128
+checkpoint-executor-config:
+  checkpoint-execution-max-concurrency: 200
+  local-execution-timeout-sec: 30
+db-checkpoint-config:
+  perform-db-checkpoints-at-epoch-end: false
+indirect-objects-threshold: 18446744073709551615
+expensive-safety-check-config:
+  enable-epoch-sui-conservation-check: false
+  enable-deep-per-tx-sui-conservation-check: false
+  force-disable-epoch-sui-conservation-check: false
+  enable-state-consistency-check: false
+  force-disable-state-consistency-check: false
+  enable-secondary-index-checks: false
+transaction-deny-config:
+  package-publish-disabled: false
+  package-upgrade-disabled: false
+  shared-object-disabled: false
+  user-transaction-disabled: false
+  receiving-objects-disabled: false
+  zklogin-sig-disabled: false
+  zklogin-disabled-providers: []
+certificate-deny-config: {}
+state-debug-dump-config: {}
+state-archive-write-config:
+  concurrency: 0
+  use-for-pruning-watermark: false
+state-archive-read-config: []
+state-snapshot-write-config:
+  concurrency: 0
+indexer-max-subscriptions: ~
+transaction-kv-store-read-config:
+  base-url: ""
+jwk-fetch-interval-seconds: 3600
+zklogin-oauth-providers:
+  Mainnet:
+    - Facebook
+    - Google
+    - Twitch
+  Testnet:
+    - Facebook
+    - Google
+    - Twitch
+  Unknown:
+    - Apple
+    - Facebook
+    - Google
+    - Kakao
+    - Slack
+    - Twitch
+authority-overload-config:
+  max-txn-age-in-queue:
+    secs: 1
+    nanos: 0
+  overload-monitor-interval:
+    secs: 10
+    nanos: 0
+  execution-queue-latency-soft-limit:
+    secs: 1
+    nanos: 0
+  execution-queue-latency-hard-limit:
+    secs: 10
+    nanos: 0
+  max-load-shedding-percentage: 95
+  min-load-shedding-percentage-above-hard-limit: 50
+  safe-transaction-ready-rate: 100

+ 12 - 0
target_chains/sui/vendor/wormhole_iota_testnet/devnet/client.yaml

@@ -0,0 +1,12 @@
+---
+keystore:
+  File: /root/.sui/sui_config/sui.keystore
+envs:
+  - alias: localnet
+    rpc: "http://0.0.0.0:9000"
+    ws: ~
+  - alias: devnet
+    rpc: "https://fullnode.devnet.sui.io:443"
+    ws: ~
+active_env: localnet
+active_address: ~

文件差异内容过多而无法显示
+ 34 - 0
target_chains/sui/vendor/wormhole_iota_testnet/devnet/fullnode.yaml


二进制
target_chains/sui/vendor/wormhole_iota_testnet/devnet/genesis.blob


+ 55 - 0
target_chains/sui/vendor/wormhole_iota_testnet/devnet/genesis_config

@@ -0,0 +1,55 @@
+---
+ssfn_config_info: ~
+validator_config_info: ~
+parameters:
+  chain_start_timestamp_ms: 1709486339140
+  protocol_version: 36
+  allow_insertion_of_extra_objects: true
+  epoch_duration_ms: 86400000
+  stake_subsidy_start_epoch: 0
+  stake_subsidy_initial_distribution_amount: 1000000000000000
+  stake_subsidy_period_length: 10
+  stake_subsidy_decrease_rate: 1000
+accounts:
+  - address: "0x2e425dd30f43ff1d59547322839cfc4b8fbaae54d72075181ebd7388b644fdbe"
+    gas_amounts:
+      - 30000000000000000
+      - 30000000000000000
+      - 30000000000000000
+      - 30000000000000000
+      - 30000000000000000
+  - address: "0x8a8bb058d6c86aa175566c9e2d19278dd22ed9fecdda8fb486018f93a0629bb5"
+    gas_amounts:
+      - 30000000000000000
+      - 30000000000000000
+      - 30000000000000000
+      - 30000000000000000
+      - 30000000000000000
+  - address: "0xa0f33ce147ecae789f535c64634851724284dd618a529672702b991a5f7bf816"
+    gas_amounts:
+      - 30000000000000000
+      - 30000000000000000
+      - 30000000000000000
+      - 30000000000000000
+      - 30000000000000000
+  - address: "0xbd00a48078c0513a5f9a0d1c9352cd5c23a0e0cf3e6a82673cdae857cd00021e"
+    gas_amounts:
+      - 30000000000000000
+      - 30000000000000000
+      - 30000000000000000
+      - 30000000000000000
+      - 30000000000000000
+  - address: "0xfd5f84cf9285f2b206e03727224b9daffa6092661b840d92434751792010b7de"
+    gas_amounts:
+      - 30000000000000000
+      - 30000000000000000
+      - 30000000000000000
+      - 30000000000000000
+      - 30000000000000000
+  - address: "0xed867315e3f7c83ae82e6d5858b6a6cc57c291fd84f7509646ebc8162169cf96"
+    gas_amounts:
+      - 30000000000000000
+      - 30000000000000000
+      - 30000000000000000
+      - 30000000000000000
+      - 30000000000000000

文件差异内容过多而无法显示
+ 499 - 0
target_chains/sui/vendor/wormhole_iota_testnet/devnet/network.yaml


+ 1 - 0
target_chains/sui/vendor/wormhole_iota_testnet/examples/coins/.gitignore

@@ -0,0 +1 @@
+build

+ 15 - 0
target_chains/sui/vendor/wormhole_iota_testnet/examples/coins/Makefile

@@ -0,0 +1,15 @@
+.PHONY: all clean test check
+
+all: check
+
+.PHONY: clean
+clean:
+	rm -rf build
+
+.PHONY: check
+check:
+	sui move build -d
+
+.PHONY: test
+test: check
+	sui move test -d

+ 17 - 0
target_chains/sui/vendor/wormhole_iota_testnet/examples/coins/Move.devnet.toml

@@ -0,0 +1,17 @@
+[package]
+name = "Coins"
+version = "0.1.0"
+
+[dependencies.Sui]
+git = "https://github.com/MystenLabs/sui.git"
+subdir = "crates/sui-framework/packages/sui-framework"
+rev = "041c5f2bae2fe52079e44b70514333532d69f4e6"
+
+[dependencies.Wormhole]
+local = "../../wormhole"
+
+[dependencies.TokenBridge]
+local = "../../token_bridge"
+
+[addresses]
+coins = "_"

+ 52 - 0
target_chains/sui/vendor/wormhole_iota_testnet/examples/coins/Move.lock

@@ -0,0 +1,52 @@
+# @generated by Move, please check-in and do not edit manually.
+
+[move]
+version = 0
+manifest_digest = "F1027436A2346E82F07F1149F91C26F61778F611858CEA83F9D22BDEF50A7FD8"
+deps_digest = "397E6A9F7A624706DBDFEE056CE88391A15876868FD18A88504DA74EB458D697"
+
+dependencies = [
+  { name = "Sui" },
+]
+
+dev-dependencies = [
+  { name = "TokenBridge" },
+  { name = "Wormhole" },
+]
+
+[[move.package]]
+name = "MoveStdlib"
+source = { git = "https://github.com/MystenLabs/sui.git", rev = "041c5f2bae2fe52079e44b70514333532d69f4e6", subdir = "crates/sui-framework/packages/move-stdlib" }
+
+[[move.package]]
+name = "Sui"
+source = { git = "https://github.com/MystenLabs/sui.git", rev = "041c5f2bae2fe52079e44b70514333532d69f4e6", subdir = "crates/sui-framework/packages/sui-framework" }
+
+dependencies = [
+  { name = "MoveStdlib" },
+]
+
+[[move.package]]
+name = "TokenBridge"
+source = { local = "../../token_bridge" }
+
+dependencies = [
+  { name = "Sui" },
+]
+
+dev-dependencies = [
+  { name = "Wormhole" },
+]
+
+[[move.package]]
+name = "Wormhole"
+source = { local = "../../wormhole" }
+
+dependencies = [
+  { name = "Sui" },
+]
+
+[move.toolchain-version]
+compiler-version = "1.19.0"
+edition = "legacy"
+flavor = "sui"

+ 28 - 0
target_chains/sui/vendor/wormhole_iota_testnet/examples/coins/Move.toml

@@ -0,0 +1,28 @@
+[package]
+name = "Coins"
+version = "0.1.0"
+
+[dependencies.Sui]
+git = "https://github.com/MystenLabs/sui.git"
+subdir = "crates/sui-framework/packages/sui-framework"
+rev = "041c5f2bae2fe52079e44b70514333532d69f4e6"
+
+[dependencies.Wormhole]
+local = "../../wormhole"
+
+[dependencies.TokenBridge]
+local = "../../token_bridge"
+
+[addresses]
+coins = "_"
+
+[dev-dependencies.Wormhole]
+local = "../../wormhole"
+
+[dev-dependencies.TokenBridge]
+local = "../../token_bridge"
+
+[dev-addresses]
+wormhole = "0x100"
+token_bridge = "0x200"
+coins = "0x20c"

+ 210 - 0
target_chains/sui/vendor/wormhole_iota_testnet/examples/coins/sources/coin.move

@@ -0,0 +1,210 @@
+// Example wrapped coin for testing purposes
+
+#[test_only]
+module coins::coin {
+    use iota::object::{Self};
+    use iota::package::{Self};
+    use iota::transfer::{Self};
+    use iota::tx_context::{Self, TxContext};
+
+    use token_bridge::create_wrapped::{Self};
+
+    struct COIN has drop {}
+
+    fun init(witness: COIN, ctx: &mut TxContext) {
+        use token_bridge::version_control::{V__0_2_0 as V__CURRENT};
+
+        transfer::public_transfer(
+            create_wrapped::prepare_registration<COIN, V__CURRENT>(
+                witness,
+                // TODO: create a version of this for each decimal to be used
+                8,
+                ctx
+            ),
+            tx_context::sender(ctx)
+        );
+    }
+
+    #[test_only]
+    /// NOTE: Even though this module is `#[test_only]`, this method is tagged
+    /// with the same macro  as a trick to allow another method within this
+    /// module to call `init` using OTW.
+    public fun init_test_only(ctx: &mut TxContext) {
+        init(COIN {}, ctx);
+
+        // This will be created and sent to the transaction sender
+        // automatically when the contract is published.
+        transfer::public_transfer(
+            package::test_publish(object::id_from_address(@coins), ctx),
+            tx_context::sender(ctx)
+        );
+    }
+}
+
+#[test_only]
+module coins::coin_tests {
+    use iota::coin::{Self};
+    use iota::package::{UpgradeCap};
+    use iota::test_scenario::{Self};
+    use token_bridge::create_wrapped::{Self, WrappedAssetSetup};
+    use token_bridge::state::{Self};
+    use token_bridge::token_bridge_scenario::{
+        register_dummy_emitter,
+        return_state,
+        set_up_wormhole_and_token_bridge,
+        take_state,
+        two_people
+    };
+    use token_bridge::token_registry::{Self};
+    use token_bridge::vaa::{Self};
+    use token_bridge::wrapped_asset::{Self};
+    use wormhole::bytes32::{Self};
+    use wormhole::external_address::{Self};
+    use wormhole::wormhole_scenario::{parse_and_verify_vaa};
+
+    use token_bridge::version_control::{V__0_2_0 as V__CURRENT};
+
+    use coins::coin::{COIN};
+
+// +------------------------------------------------------------------------------+
+// | Wormhole VAA v1         | nonce: 1                | time: 1                  |
+// | guardian set #0         | #22080291               | consistency: 0           |
+// |------------------------------------------------------------------------------|
+// | Signature:                                                                   |
+// |   #0: 80366065746148420220f25a6275097370e8db40984529a6676b7a5fc9fe...        |
+// |------------------------------------------------------------------------------|
+// | Emitter: 0x00000000000000000000000000000000deadbeef (Ethereum)               |
+// |==============================================================================|
+// | Token attestation                                                            |
+// | decimals: 12                                                                 |
+// | Token: 0x00000000000000000000000000000000beefface (Ethereum)                 |
+// | Symbol: BEEF                                                                 |
+// | Name: Beef face Token                                                        |
+// +------------------------------------------------------------------------------+
+    const VAA: vector<u8> =
+        x"0100000000010080366065746148420220f25a6275097370e8db40984529a6676b7a5fc9feb11755ec49ca626b858ddfde88d15601f85ab7683c5f161413b0412143241c700aff010000000100000001000200000000000000000000000000000000000000000000000000000000deadbeef000000000150eb23000200000000000000000000000000000000000000000000000000000000beefface00020c424545460000000000000000000000000000000000000000000000000000000042656566206661636520546f6b656e0000000000000000000000000000000000";
+
+// +------------------------------------------------------------------------------+
+// | Wormhole VAA v1         | nonce: 69               | time: 0                  |
+// | guardian set #0         | #1                      | consistency: 15          |
+// |------------------------------------------------------------------------------|
+// | Signature:                                                                   |
+// |   #0: b0571650590e147fce4eb60105e0463522c1244a97bd5dcb365d3e7bc7f3...        |
+// |------------------------------------------------------------------------------|
+// | Emitter: 0x00000000000000000000000000000000deadbeef (Ethereum)               |
+// |==============================================================================|
+// | Token attestation                                                            |
+// | decimals: 12                                                                 |
+// | Token: 0x00000000000000000000000000000000beefface (Ethereum)                 |
+// | Symbol: BEEF??? and profit                                                   |
+// | Name: Beef face Token??? and profit                                          |
+// +------------------------------------------------------------------------------+
+    const UPDATED_VAA: vector<u8> =
+        x"0100000000010062f4dcd21bbbc4af8b8baaa2da3a0b168efc4c975de5b828c7a3c710b67a0a0d476d10a74aba7a7867866daf97d1372d8e6ee62ccc5ae522e3e603c67fa23787000000000000000045000200000000000000000000000000000000000000000000000000000000deadbeef00000000000000010f0200000000000000000000000000000000000000000000000000000000beefface00020c424545463f3f3f20616e642070726f666974000000000000000000000000000042656566206661636520546f6b656e3f3f3f20616e642070726f666974000000";
+
+
+    #[test]
+    public fun test_complete_and_update_attestation() {
+        let (caller, coin_deployer) = two_people();
+        let my_scenario = test_scenario::begin(caller);
+        let scenario = &mut my_scenario;
+
+        // Set up contracts.
+        let wormhole_fee = 350;
+        set_up_wormhole_and_token_bridge(scenario, wormhole_fee);
+
+        // Register foreign emitter on chain ID == 2.
+        let expected_source_chain = 2;
+        register_dummy_emitter(scenario, expected_source_chain);
+
+        // Ignore effects. Make sure `coin_deployer` receives
+        // `WrappedAssetSetup`.
+        test_scenario::next_tx(scenario, coin_deployer);
+
+        // Publish coin.
+        coins::coin::init_test_only(test_scenario::ctx(scenario));
+
+        // Ignore effects.
+        test_scenario::next_tx(scenario, coin_deployer);
+
+        let wrapped_asset_setup =
+            test_scenario::take_from_address<WrappedAssetSetup<COIN, V__CURRENT>>(
+                scenario,
+                coin_deployer
+            );
+
+        let token_bridge_state = take_state(scenario);
+
+        let verified_vaa = parse_and_verify_vaa(scenario, VAA);
+        let msg = vaa::verify_only_once(&mut token_bridge_state, verified_vaa);
+
+        let coin_meta = test_scenario::take_shared(scenario);
+
+        // Ignore effects.
+        test_scenario::next_tx(scenario, caller);
+
+        create_wrapped::complete_registration(
+            &mut token_bridge_state,
+            &mut coin_meta,
+            wrapped_asset_setup,
+            test_scenario::take_from_address<UpgradeCap>(
+                scenario,
+                coin_deployer
+            ),
+            msg
+        );
+
+        // Check registry.
+        {
+            let verified = state::verified_asset<COIN>(&token_bridge_state);
+            assert!(token_bridge::token_registry::is_wrapped<COIN>(&verified), 0);
+
+            let registry = state::borrow_token_registry(&token_bridge_state);
+            let asset =
+                token_registry::borrow_wrapped<COIN>(registry);
+            assert!(wrapped_asset::total_supply(asset) == 0, 0);
+
+            // Decimals are capped for this wrapped asset.
+            assert!(coin::get_decimals(&coin_meta) == 8, 0);
+
+            // Check metadata against asset metadata.
+            let info = wrapped_asset::info(asset);
+            assert!(wrapped_asset::token_chain(info) == 2, 0);
+            assert!(wrapped_asset::token_address(info) == external_address::new(bytes32::from_bytes(x"00000000000000000000000000000000beefface")), 0);
+            assert!(
+                wrapped_asset::native_decimals(info) == 12,
+                0
+            );
+            assert!(coin::get_symbol(&coin_meta) == std::ascii::string(b"BEEF"), 0);
+            assert!(coin::get_name(&coin_meta) == std::string::utf8(b"Beef face Token"), 0);
+        };
+
+        let verified_vaa =
+            parse_and_verify_vaa(scenario, UPDATED_VAA);
+        let msg = vaa::verify_only_once(&mut token_bridge_state, verified_vaa);
+
+        // Ignore effects.
+        test_scenario::next_tx(scenario, caller);
+
+        // Now update metadata.
+        create_wrapped::update_attestation<COIN>(&mut token_bridge_state, &mut coin_meta, msg);
+
+        // Check updated name and symbol.
+        assert!(
+            coin::get_name(&coin_meta) == std::string::utf8(b"Beef face Token??? and profit"),
+            0
+        );
+        assert!(
+            coin::get_symbol(&coin_meta) == std::ascii::string(b"BEEF??? and profit"),
+            0
+        );
+
+        // Clean up.
+        return_state(token_bridge_state);
+        test_scenario::return_shared(coin_meta);
+
+
+        // Done.
+        test_scenario::end(my_scenario);
+    }
+}

+ 72 - 0
target_chains/sui/vendor/wormhole_iota_testnet/examples/coins/sources/coin_10.move

@@ -0,0 +1,72 @@
+module coins::coin_10 {
+    use std::option;
+    use iota::coin::{Self, TreasuryCap, CoinMetadata};
+    use iota::transfer;
+    use iota::tx_context::{Self, TxContext};
+
+    /// The type identifier of coin. The coin will have a type
+    /// tag of kind: `Coin<package_object::coin_10::COIN_10>`
+    /// Make sure that the name of the type matches the module's name.
+    struct COIN_10 has drop {}
+
+    /// Module initializer is called once on module publish. A treasury
+    /// cap is sent to the publisher, who then controls minting and burning
+    fun init(witness: COIN_10, ctx: &mut TxContext) {
+        let (treasury, metadata) = create_coin(witness, ctx);
+        transfer::public_freeze_object(metadata);
+        transfer::public_transfer(treasury, tx_context::sender(ctx));
+    }
+
+    fun create_coin(
+        witness: COIN_10,
+        ctx: &mut TxContext
+    ): (TreasuryCap<COIN_10>, CoinMetadata<COIN_10>) {
+        coin::create_currency(
+            witness,
+            10, // decimals
+            b"COIN_10", // symbol
+            b"10-Decimal Coin", // name
+            b"", // description
+            option::none(), // icon_url
+            ctx
+        )
+    }
+
+    #[test_only]
+    public fun create_coin_test_only(
+        ctx: &mut TxContext
+    ): (TreasuryCap<COIN_10>, CoinMetadata<COIN_10>) {
+        create_coin(COIN_10 {}, ctx)
+    }
+
+    #[test_only]
+    public fun init_test_only(ctx: &mut TxContext) {
+        init(COIN_10 {}, ctx)
+    }
+}
+
+#[test_only]
+module coins::coin_10_tests {
+    use iota::test_scenario::{Self};
+
+    use coins::coin_10::{Self};
+
+    #[test]
+    public fun init_test() {
+        let my_scenario = test_scenario::begin(@0x0);
+        let scenario = &mut my_scenario;
+        let creator = @0xDEADBEEF;
+
+        // Proceed.
+        test_scenario::next_tx(scenario, creator);
+
+        // Init.
+        coin_10::init_test_only(test_scenario::ctx(scenario));
+
+        // Proceed.
+        test_scenario::next_tx(scenario, creator);
+
+        // Done.
+        test_scenario::end(my_scenario);
+    }
+}

+ 72 - 0
target_chains/sui/vendor/wormhole_iota_testnet/examples/coins/sources/coin_8.move

@@ -0,0 +1,72 @@
+module coins::coin_8 {
+    use std::option::{Self};
+    use iota::coin::{Self, TreasuryCap, CoinMetadata};
+    use iota::transfer::{Self};
+    use iota::tx_context::{Self, TxContext};
+
+    /// The type identifier of coin. The coin will have a type
+    /// tag of kind: `Coin<package_object::coin_8::COIN_8>`
+    /// Make sure that the name of the type matches the module's name.
+    struct COIN_8 has drop {}
+
+    /// Module initializer is called once on module publish. A treasury
+    /// cap is sent to the publisher, who then controls minting and burning
+    fun init(witness: COIN_8, ctx: &mut TxContext) {
+        let (treasury, metadata) = create_coin(witness, ctx);
+        transfer::public_freeze_object(metadata);
+        transfer::public_transfer(treasury, tx_context::sender(ctx));
+    }
+
+    fun create_coin(
+        witness: COIN_8,
+        ctx: &mut TxContext
+    ): (TreasuryCap<COIN_8>, CoinMetadata<COIN_8>) {
+        coin::create_currency(
+            witness,
+            8, // decimals
+            b"COIN_8", // symbol
+            b"8-Decimal Coin", // name
+            b"", // description
+            option::none(), // icon_url
+            ctx
+        )
+    }
+
+    #[test_only]
+    public fun create_coin_test_only(
+        ctx: &mut TxContext
+    ): (TreasuryCap<COIN_8>, CoinMetadata<COIN_8>) {
+        create_coin(COIN_8 {}, ctx)
+    }
+
+    #[test_only]
+    public fun init_test_only(ctx: &mut TxContext) {
+        init(COIN_8 {}, ctx)
+    }
+}
+
+#[test_only]
+module coins::coin_8_tests {
+    use iota::test_scenario::{Self};
+
+    use coins::coin_8::{Self};
+
+    #[test]
+    public fun init_test() {
+        let my_scenario = test_scenario::begin(@0x0);
+        let scenario = &mut my_scenario;
+        let creator = @0xDEADBEEF;
+
+        // Proceed.
+        test_scenario::next_tx(scenario, creator);
+
+        // Init.
+        coin_8::init_test_only(test_scenario::ctx(scenario));
+
+        // Proceed.
+        test_scenario::next_tx(scenario, creator);
+
+        // Done.
+        test_scenario::end(my_scenario);
+    }
+}

+ 20 - 0
target_chains/sui/vendor/wormhole_iota_testnet/examples/core_messages/Makefile

@@ -0,0 +1,20 @@
+-include ../../../Makefile.help
+
+.PHONY: artifacts
+artifacts: clean
+
+.PHONY: clean
+# Clean build artifacts
+clean:
+	rm -rf build
+
+.PHONY: build
+# Build contract
+build:
+	sui move build
+
+.PHONY: test
+# Run tests
+test:
+	sui move build -d || exit $?
+	sui move test -t 1

+ 14 - 0
target_chains/sui/vendor/wormhole_iota_testnet/examples/core_messages/Move.devnet.toml

@@ -0,0 +1,14 @@
+[package]
+name = "CoreMessages"
+version = "1.0.0"
+
+[dependencies.Sui]
+git = "https://github.com/MystenLabs/sui.git"
+subdir = "crates/sui-framework/packages/sui-framework"
+rev = "041c5f2bae2fe52079e44b70514333532d69f4e6"
+
+[dependencies.Wormhole]
+local = "../../wormhole"
+
+[addresses]
+core_messages = "_"

+ 39 - 0
target_chains/sui/vendor/wormhole_iota_testnet/examples/core_messages/Move.lock

@@ -0,0 +1,39 @@
+# @generated by Move, please check-in and do not edit manually.
+
+[move]
+version = 0
+manifest_digest = "E0D2B32F0A5B6F9A76311FD7A68260A698BD9ECCEAF95A779183CB374EC933FB"
+deps_digest = "060AD7E57DFB13104F21BE5F5C3759D03F0553FC3229247D9A7A6B45F50D03A3"
+
+dependencies = [
+  { name = "Sui" },
+]
+
+dev-dependencies = [
+  { name = "Wormhole" },
+]
+
+[[move.package]]
+name = "MoveStdlib"
+source = { git = "https://github.com/MystenLabs/sui.git", rev = "041c5f2bae2fe52079e44b70514333532d69f4e6", subdir = "crates/sui-framework/packages/move-stdlib" }
+
+[[move.package]]
+name = "Sui"
+source = { git = "https://github.com/MystenLabs/sui.git", rev = "041c5f2bae2fe52079e44b70514333532d69f4e6", subdir = "crates/sui-framework/packages/sui-framework" }
+
+dependencies = [
+  { name = "MoveStdlib" },
+]
+
+[[move.package]]
+name = "Wormhole"
+source = { local = "../../wormhole" }
+
+dependencies = [
+  { name = "Sui" },
+]
+
+[move.toolchain-version]
+compiler-version = "1.19.0"
+edition = "legacy"
+flavor = "sui"

+ 21 - 0
target_chains/sui/vendor/wormhole_iota_testnet/examples/core_messages/Move.toml

@@ -0,0 +1,21 @@
+[package]
+name = "CoreMessages"
+version = "1.0.0"
+
+[dependencies.Sui]
+git = "https://github.com/MystenLabs/sui.git"
+subdir = "crates/sui-framework/packages/sui-framework"
+rev = "041c5f2bae2fe52079e44b70514333532d69f4e6"
+
+[dependencies.Wormhole]
+local = "../../wormhole"
+
+[addresses]
+core_messages = "_"
+
+[dev-dependencies.Wormhole]
+local = "../../wormhole"
+
+[dev-addresses]
+wormhole = "0x100"
+core_messages = "0x169"

+ 149 - 0
target_chains/sui/vendor/wormhole_iota_testnet/examples/core_messages/sources/sender.move

@@ -0,0 +1,149 @@
+/// A simple contracts that demonstrates how to send messages with wormhole.
+module core_messages::sender {
+    use iota::clock::{Clock};
+    use iota::coin::{Self};
+    use iota::object::{Self, UID};
+    use iota::transfer::{Self};
+    use iota::tx_context::{TxContext};
+    use wormhole::emitter::{Self, EmitterCap};
+    use wormhole::state::{State as WormholeState};
+
+    struct State has key, store {
+        id: UID,
+        emitter_cap: EmitterCap,
+    }
+
+    /// Register ourselves as a wormhole emitter. This gives back an
+    /// `EmitterCap` which will be required to send messages through
+    /// wormhole.
+    public fun init_with_params(
+        wormhole_state: &WormholeState,
+        ctx: &mut TxContext
+    ) {
+        transfer::share_object(
+            State {
+                id: object::new(ctx),
+                emitter_cap: emitter::new(wormhole_state, ctx)
+            }
+        );
+    }
+
+    public fun send_message_entry(
+        state: &mut State,
+        wormhole_state: &mut WormholeState,
+        payload: vector<u8>,
+        the_clock: &Clock,
+        ctx: &mut TxContext
+    ) {
+        send_message(
+            state,
+            wormhole_state,
+            payload,
+            the_clock,
+            ctx
+        );
+    }
+
+    /// NOTE: This is NOT the proper way of using the `prepare_message` and
+    /// `publish_message` workflow. This example app is meant for testing for
+    /// observing Wormhole messages via the guardian.
+    ///
+    /// See `publish_message` module for more info.
+    public fun send_message(
+        state: &mut State,
+        wormhole_state: &mut WormholeState,
+        payload: vector<u8>,
+        the_clock: &Clock,
+        ctx: &mut TxContext
+    ): u64 {
+        use wormhole::publish_message::{prepare_message, publish_message};
+
+        // NOTE AGAIN: Integrators should NEVER call this within their contract.
+        publish_message(
+            wormhole_state,
+            coin::zero(ctx),
+            prepare_message(
+                &mut state.emitter_cap,
+                0, // Set nonce to 0, intended for batch VAAs.
+                payload
+            ),
+            the_clock
+        )
+    }
+}
+
+#[test_only]
+module core_messages::sender_test {
+    use iota::test_scenario::{Self};
+    use wormhole::wormhole_scenario::{
+        return_clock,
+        return_state,
+        set_up_wormhole,
+        take_clock,
+        take_state,
+        two_people,
+    };
+
+    use core_messages::sender::{
+        State,
+        init_with_params,
+        send_message,
+    };
+
+    #[test]
+    public fun test_send_message() {
+        let (user, admin) = two_people();
+        let my_scenario = test_scenario::begin(admin);
+        let scenario = &mut my_scenario;
+
+        // Initialize Wormhole.
+        let wormhole_message_fee = 0;
+        set_up_wormhole(scenario, wormhole_message_fee);
+
+        // Initialize sender module.
+        test_scenario::next_tx(scenario, admin);
+        {
+            let wormhole_state = take_state(scenario);
+            init_with_params(&wormhole_state, test_scenario::ctx(scenario));
+            return_state(wormhole_state);
+        };
+
+        // Send message as an ordinary user.
+        test_scenario::next_tx(scenario, user);
+        {
+            let state = test_scenario::take_shared<State>(scenario);
+            let wormhole_state = take_state(scenario);
+            let the_clock = take_clock(scenario);
+
+            let first_message_sequence = send_message(
+                &mut state,
+                &mut wormhole_state,
+                b"Hello",
+                &the_clock,
+                test_scenario::ctx(scenario)
+            );
+            assert!(first_message_sequence == 0, 0);
+
+            let second_message_sequence = send_message(
+                &mut state,
+                &mut wormhole_state,
+                b"World",
+                &the_clock,
+                test_scenario::ctx(scenario)
+            );
+            assert!(second_message_sequence == 1, 0);
+
+            // Clean up.
+            test_scenario::return_shared(state);
+            return_state(wormhole_state);
+            return_clock(the_clock);
+        };
+
+        // Check effects.
+        let effects = test_scenario::next_tx(scenario, user);
+        assert!(test_scenario::num_user_events(&effects) == 2, 0);
+
+        // End test.
+        test_scenario::end(my_scenario);
+    }
+}

+ 3 - 0
target_chains/sui/vendor/wormhole_iota_testnet/examples/templates/README.md

@@ -0,0 +1,3 @@
+# Templates
+
+This directory contains templates for Sui contracts. These templates aren't fully functional contracts and require substitution of variables prior to deployment. For example, the `wrapped_coin` template requires the version control struct name as well as the decimals of the wrapped token.

+ 19 - 0
target_chains/sui/vendor/wormhole_iota_testnet/examples/templates/wrapped_coin/Move.toml

@@ -0,0 +1,19 @@
+[package]
+name = "WrappedCoin"
+version = "0.0.1"
+
+[dependencies.Sui]
+git = "https://github.com/MystenLabs/sui.git"
+subdir = "crates/sui-framework/packages/sui-framework"
+rev = "041c5f2bae2fe52079e44b70514333532d69f4e6"
+
+[dependencies.Wormhole]
+local = "../../wormhole"
+
+[dependencies.TokenBridge]
+local = "../../token_bridge"
+
+[addresses]
+wormhole = "_"
+token_bridge = "_"
+wrapped_coin = "0x0"

+ 21 - 0
target_chains/sui/vendor/wormhole_iota_testnet/examples/templates/wrapped_coin/sources/coin.move

@@ -0,0 +1,21 @@
+module wrapped_coin::coin {
+    use iota::transfer::{Self};
+    use iota::tx_context::{Self, TxContext};
+
+    use token_bridge::create_wrapped::{Self};
+
+    struct COIN has drop {}
+
+    fun init(witness: COIN, ctx: &mut TxContext) {
+        use token_bridge::version_control::{{{VERSION}}};
+
+        transfer::public_transfer(
+            create_wrapped::prepare_registration<COIN, {{VERSION}}>(
+                witness,
+                {{DECIMALS}},
+                ctx
+            ),
+            tx_context::sender(ctx)
+        );
+    }
+}

+ 119 - 0
target_chains/sui/vendor/wormhole_iota_testnet/scripts/deploy.sh

@@ -0,0 +1,119 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+# Help message
+function usage() {
+cat <<EOF >&2
+Deploy and initialize Sui core bridge and token bridge contracts to the
+specified network. Additionally deploys an example messaging contract in
+devnet.
+
+  Usage: $(basename "$0") <network> [options]
+
+  Positional args:
+    <network>          Network to deploy to (devnet, testnet, mainnet)
+
+  Options:
+    -k, --private-key  Use given key to sign transactions
+    -h, --help         Show this help message
+EOF
+exit 1
+}
+
+# If positional args are missing, print help message and exit
+if [ $# -lt 1 ]; then
+  usage
+fi
+
+# Default values
+PRIVATE_KEY_ARG=
+
+# Set network
+NETWORK=$1 || usage
+shift
+
+# Set guardian address
+if [ "$NETWORK" = mainnet ]; then
+  echo "Mainnet not supported yet"
+  exit 1
+elif [ "$NETWORK" = testnet ]; then
+  echo "Testnet not supported yet"
+  exit 1
+elif [ "$NETWORK" = devnet ]; then
+  GUARDIAN_ADDR=befa429d57cd18b7f8a4d91a2da9ab4af05d0fbe
+else
+  usage
+fi
+
+# Parse short/long flags
+while [[ $# -gt 0 ]]; do
+  case "$1" in
+    -k|--private-key)
+      if [[ ! -z "$2" ]]; then
+        PRIVATE_KEY_ARG="-k $2"
+      fi
+      shift 2
+      ;;
+    -h|--help)
+      usage
+      exit 0
+      ;;
+    *)
+      echo "Unknown option: $1"
+      usage
+      exit 1
+      ;;
+  esac
+done
+
+# Assumes this script is in a sibling directory to contract dirs
+DIRNAME=$(dirname "$0")
+WORMHOLE_PATH=$(realpath "$DIRNAME"/../wormhole)
+TOKEN_BRIDGE_PATH=$(realpath "$DIRNAME"/../token_bridge)
+EXAMPLE_APP_PATH=$(realpath "$DIRNAME"/../examples/core_messages)
+EXAMPLE_COIN_PATH=$(realpath "$DIRNAME"/../examples/coins)
+
+echo -e "[1/4] Publishing core bridge contracts..."
+WORMHOLE_PUBLISH_OUTPUT=$($(echo worm sui deploy "$WORMHOLE_PATH" -n "$NETWORK" "$PRIVATE_KEY_ARG"))
+echo "$WORMHOLE_PUBLISH_OUTPUT"
+
+echo -e "\n[2/4] Initializing core bridge..."
+WORMHOLE_PACKAGE_ID=$(echo "$WORMHOLE_PUBLISH_OUTPUT" | grep -oP 'Published to +\K.*')
+WORMHOLE_INIT_OUTPUT=$($(echo worm sui init-wormhole -n "$NETWORK" --initial-guardian "$GUARDIAN_ADDR" -p "$WORMHOLE_PACKAGE_ID" "$PRIVATE_KEY_ARG"))
+WORMHOLE_STATE_OBJECT_ID=$(echo "$WORMHOLE_INIT_OUTPUT" | grep -oP 'Wormhole state object ID +\K.*')
+echo "$WORMHOLE_INIT_OUTPUT"
+
+echo -e "\n[3/4] Publishing token bridge contracts..."
+TOKEN_BRIDGE_PUBLISH_OUTPUT=$($(echo worm sui deploy "$TOKEN_BRIDGE_PATH" -n "$NETWORK" "$PRIVATE_KEY_ARG"))
+echo "$TOKEN_BRIDGE_PUBLISH_OUTPUT"
+
+echo -e "\n[4/4] Initializing token bridge..."
+TOKEN_BRIDGE_PACKAGE_ID=$(echo "$TOKEN_BRIDGE_PUBLISH_OUTPUT" | grep -oP 'Published to +\K.*')
+TOKEN_BRIDGE_INIT_OUTPUT=$($(echo worm sui init-token-bridge -n "$NETWORK" -p "$TOKEN_BRIDGE_PACKAGE_ID" -w "$WORMHOLE_STATE_OBJECT_ID" "$PRIVATE_KEY_ARG"))
+TOKEN_BRIDGE_STATE_OBJECT_ID=$(echo "$TOKEN_BRIDGE_INIT_OUTPUT" | grep -oP 'Token bridge state object ID +\K.*')
+echo "$TOKEN_BRIDGE_INIT_OUTPUT"
+
+if [ "$NETWORK" = devnet ]; then
+  echo -e "\n[+1/2] Deploying and initializing example app..."
+  EXAMPLE_APP_PUBLISH_OUTPUT=$($(echo worm sui deploy "$EXAMPLE_APP_PATH" -n "$NETWORK" "$PRIVATE_KEY_ARG"))
+  EXAMPLE_APP_PACKAGE_ID=$(echo "$EXAMPLE_APP_PUBLISH_OUTPUT" | grep -oP 'Published to +\K.*')
+  echo "$EXAMPLE_APP_PUBLISH_OUTPUT"
+
+  EXAMPLE_INIT_OUTPUT=$($(echo worm sui init-example-message-app -n "$NETWORK" -p "$EXAMPLE_APP_PACKAGE_ID" -w "$WORMHOLE_STATE_OBJECT_ID" "$PRIVATE_KEY_ARG"))
+  EXAMPLE_APP_STATE_OBJECT_ID=$(echo "$EXAMPLE_INIT_OUTPUT" | grep -oP 'Example app state object ID +\K.*')
+  echo "$EXAMPLE_INIT_OUTPUT"
+
+  echo -e "\n[+2/2] Deploying example coins..."
+  EXAMPLE_COIN_PUBLISH_OUTPUT=$($(echo worm sui deploy "$EXAMPLE_COIN_PATH" -n "$NETWORK" "$PRIVATE_KEY_ARG"))
+  echo "$EXAMPLE_COIN_PUBLISH_OUTPUT"
+
+  echo -e "\nWormhole package ID: $WORMHOLE_PACKAGE_ID"
+  echo "Token bridge package ID: $TOKEN_BRIDGE_PACKAGE_ID"
+  echo "Wormhole state object ID: $WORMHOLE_STATE_OBJECT_ID"
+  echo "Token bridge state object ID: $TOKEN_BRIDGE_STATE_OBJECT_ID"
+
+  echo -e "\nPublish message command:" worm sui publish-example-message -n devnet -p "$EXAMPLE_APP_PACKAGE_ID" -s "$EXAMPLE_APP_STATE_OBJECT_ID" -w "$WORMHOLE_STATE_OBJECT_ID" -m "hello" "$PRIVATE_KEY_ARG"
+fi
+
+echo -e "\nDeployments successful!"

+ 11 - 0
target_chains/sui/vendor/wormhole_iota_testnet/scripts/node_builder.sh

@@ -0,0 +1,11 @@
+#!/bin/bash
+
+git clone https://github.com/MystenLabs/sui.git --branch devnet
+cd sui
+# Corresponds to https://github.com/MystenLabs/sui/releases/tag/mainnet-v1.19.1
+git reset --hard 041c5f2bae2fe52079e44b70514333532d69f4e6
+
+cargo --locked install --path crates/sui
+cargo --locked install --path crates/sui-faucet
+cargo --locked install --path crates/sui-gateway
+cargo --locked install --path crates/sui-node

+ 22 - 0
target_chains/sui/vendor/wormhole_iota_testnet/scripts/register_devnet.sh

@@ -0,0 +1,22 @@
+#!/bin/bash
+
+set -e
+
+DOTENV=$(realpath "$(dirname "$0")"/../.env)
+[ -f $DOTENV ] || (echo "$DOTENV does not exist." >&2; exit 1)
+
+# 1. load variables from .env file
+. $DOTENV
+
+# 2. next we get all the token bridge registration VAAs from the environment
+# if a new VAA is added, this will automatically pick it up
+VAAS=$(set | grep "REGISTER_.*_TOKEN_BRIDGE_VAA" | grep -v SUI | cut -d '=' -f1)
+
+# 3. use 'worm' to submit each registration VAA
+for VAA in $VAAS
+do
+    VAA=${!VAA}
+    worm submit $VAA --chain sui --network devnet
+done
+
+echo "Registrations successful."

+ 3 - 0
target_chains/sui/vendor/wormhole_iota_testnet/scripts/setup_rust.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+
+curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y

+ 5 - 0
target_chains/sui/vendor/wormhole_iota_testnet/scripts/start_node.sh

@@ -0,0 +1,5 @@
+#!/bin/bash
+
+set -x
+
+sui start 2>&1

+ 31 - 0
target_chains/sui/vendor/wormhole_iota_testnet/scripts/switch.sh

@@ -0,0 +1,31 @@
+#!/bin/bash
+
+network="$1"
+valid_networks=("devnet" "testnet" "mainnet" "reset")
+
+usage() {
+    echo "Usage: $0 {devnet|testnet|mainnet|reset}" >&2
+    exit 1
+}
+
+if [[ ! " ${valid_networks[@]} " =~ " ${network} " ]]; then
+    echo "Error: Unrecognized network '${network}'."
+    usage
+fi
+
+git ls-files | grep 'Move.toml' | while read -r file; do
+    if [[ "$network" == "reset" ]]; then
+        echo "Resetting $file"
+        git checkout "$file" --quiet
+    else
+        dir=$(dirname "$file")
+        base=$(basename "$file")
+        new_file="${dir}/Move.$network.toml"
+        if [ -f "$new_file" ]; then
+            echo "Switching $file to $new_file"
+            rm "$file"
+            # Create a relative symlink
+            (cd "$dir" && ln -s "$(basename "$new_file")" "$base")
+        fi
+    fi
+done

+ 6 - 0
target_chains/sui/vendor/wormhole_iota_testnet/scripts/wait_for_devnet.sh

@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+
+# Wait for sui to start
+while [[ "$(curl -X POST -H "Content-Type: application/json" -d '{ "jsonrpc":"2.0", "method":"rpc.discover","id":1 }' -s -o /dev/null -w '%{http_code}' 0.0.0.0:9000/)" != "200" ]]; do sleep 1; done

+ 4 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/.gitignore

@@ -0,0 +1,4 @@
+node_modules
+sui.log.*
+./token_bridge/
+./wormhole/

+ 13 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/Makefile

@@ -0,0 +1,13 @@
+-include ../Makefile.help
+
+.PHONY: clean
+clean:
+	rm -rf node_modules
+
+node_modules:
+	pnpm i
+
+.PHONY: test
+## Run tests
+test: node_modules
+	bash run_integration_test.sh

+ 78 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/js/00_environment.ts

@@ -0,0 +1,78 @@
+import { expect } from "chai";
+import * as mock from "@certusone/wormhole-sdk/lib/cjs/mock";
+
+import {
+  CREATOR_PRIVATE_KEY,
+  GUARDIAN_PRIVATE_KEY,
+  RELAYER_PRIVATE_KEY,
+  WALLET_PRIVATE_KEY,
+} from "./helpers/consts";
+import {
+  Ed25519Keypair,
+  JsonRpcProvider,
+  localnetConnection,
+  RawSigner,
+} from "@mysten/sui.js";
+
+describe(" 0. Environment", () => {
+  const provider = new JsonRpcProvider(localnetConnection);
+
+  // User wallet.
+  const wallet = new RawSigner(
+    Ed25519Keypair.fromSecretKey(WALLET_PRIVATE_KEY),
+    provider
+  );
+
+  // Relayer wallet.
+  const relayer = new RawSigner(
+    Ed25519Keypair.fromSecretKey(RELAYER_PRIVATE_KEY),
+    provider
+  );
+
+  // Deployer wallet.
+  const creator = new RawSigner(
+    Ed25519Keypair.fromSecretKey(CREATOR_PRIVATE_KEY),
+    provider
+  );
+
+  describe("Verify Local Validator", () => {
+    it("Balance", async () => {
+      // Balance check wallet.
+      {
+        const coinData = await wallet
+          .getAddress()
+          .then((owner) =>
+            provider
+              .getCoins({ owner, coinType: "0x2::sui::SUI" })
+              .then((result) => result.data)
+          );
+        expect(coinData).has.length(5);
+      }
+
+      // Balance check relayer.
+      {
+        const coinData = await relayer
+          .getAddress()
+          .then((owner) =>
+            provider
+              .getCoins({ owner, coinType: "0x2::sui::SUI" })
+              .then((result) => result.data)
+          );
+        expect(coinData).has.length(5);
+      }
+
+      // Balance check creator. This should only have one gas object at this
+      // point.
+      {
+        const coinData = await creator
+          .getAddress()
+          .then((owner) =>
+            provider
+              .getCoins({ owner, coinType: "0x2::sui::SUI" })
+              .then((result) => result.data)
+          );
+        expect(coinData).has.length(1);
+      }
+    });
+  });
+});

+ 109 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/js/01_wormhole.ts

@@ -0,0 +1,109 @@
+import { expect } from "chai";
+
+import { WALLET_PRIVATE_KEY, WORMHOLE_STATE_ID } from "./helpers/consts";
+import {
+  Ed25519Keypair,
+  JsonRpcProvider,
+  localnetConnection,
+  RawSigner,
+  SUI_CLOCK_OBJECT_ID,
+  TransactionBlock,
+} from "@mysten/sui.js";
+import { getPackageId } from "./helpers/utils";
+import { addPrepareMessageAndPublishMessage } from "./helpers/wormhole/testPublishMessage";
+
+describe(" 1. Wormhole", () => {
+  const provider = new JsonRpcProvider(localnetConnection);
+
+  // User wallet.
+  const wallet = new RawSigner(
+    Ed25519Keypair.fromSecretKey(WALLET_PRIVATE_KEY),
+    provider
+  );
+
+  describe("Publish Message", () => {
+    it("Check `WormholeMessage` Event", async () => {
+      const wormholePackage = await getPackageId(
+        wallet.provider,
+        WORMHOLE_STATE_ID
+      );
+
+      const owner = await wallet.getAddress();
+
+      // Create emitter cap.
+      const emitterCapId = await (async () => {
+        const tx = new TransactionBlock();
+        const [emitterCap] = tx.moveCall({
+          target: `${wormholePackage}::emitter::new`,
+          arguments: [tx.object(WORMHOLE_STATE_ID)],
+        });
+        tx.transferObjects([emitterCap], tx.pure(owner));
+
+        // Execute and fetch created Emitter cap.
+        return wallet
+          .signAndExecuteTransactionBlock({
+            transactionBlock: tx,
+            options: {
+              showObjectChanges: true,
+            },
+          })
+          .then((result) => {
+            const found = result.objectChanges?.filter(
+              (item) => "created" === item.type!
+            );
+            if (found?.length == 1 && "objectId" in found[0]) {
+              return found[0].objectId;
+            }
+
+            throw new Error("no objects found");
+          });
+      })();
+
+      // Publish messages using emitter cap.
+      {
+        const nonce = 69;
+        const basePayload = "All your base are belong to us.";
+
+        const numMessages = 32;
+        const payloads: string[] = [];
+        const tx = new TransactionBlock();
+
+        // Construct transaction block to send multiple messages.
+        for (let i = 0; i < numMessages; ++i) {
+          // Make a unique message.
+          const payload = basePayload + `... ${i}`;
+          payloads.push(payload);
+
+          addPrepareMessageAndPublishMessage(
+            tx,
+            wormholePackage,
+            WORMHOLE_STATE_ID,
+            emitterCapId,
+            nonce,
+            payload
+          );
+        }
+
+        const events = await wallet
+          .signAndExecuteTransactionBlock({
+            transactionBlock: tx,
+            options: {
+              showEvents: true,
+            },
+          })
+          .then((result) => result.events!);
+        expect(events).has.length(numMessages);
+
+        for (let i = 0; i < numMessages; ++i) {
+          const eventData = events[i].parsedJson!;
+          expect(eventData.consistency_level).equals(0);
+          expect(eventData.nonce).equals(nonce);
+          expect(eventData.payload).deep.equals([...Buffer.from(payloads[i])]);
+          expect(eventData.sender).equals(emitterCapId);
+          expect(eventData.sequence).equals(i.toString());
+          expect(BigInt(eventData.timestamp) > 0n).is.true;
+        }
+      }
+    });
+  });
+});

+ 32 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/js/helpers/build.ts

@@ -0,0 +1,32 @@
+import { fromB64, normalizeSuiObjectId } from "@mysten/sui.js";
+import { execSync, ExecSyncOptionsWithStringEncoding } from "child_process";
+import { UTF8 } from "./consts";
+
+export const EXEC_UTF8: ExecSyncOptionsWithStringEncoding = { encoding: UTF8 };
+
+export function buildForBytecode(packagePath: string) {
+  const buildOutput: {
+    modules: string[];
+    dependencies: string[];
+  } = JSON.parse(
+    execSync(
+      `sui move build --dump-bytecode-as-base64 -p ${packagePath} 2> /dev/null`,
+      EXEC_UTF8
+    )
+  );
+  return {
+    modules: buildOutput.modules.map((m: string) => Array.from(fromB64(m))),
+    dependencies: buildOutput.dependencies.map((d: string) =>
+      normalizeSuiObjectId(d)
+    ),
+  };
+}
+
+export function buildForDigest(packagePath: string) {
+  const digest = execSync(
+    `sui move build --dump-package-digest -p ${packagePath} 2> /dev/null`,
+    EXEC_UTF8
+  ).substring(0, 64);
+
+  return Buffer.from(digest, "hex");
+}

+ 40 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/js/helpers/consts.ts

@@ -0,0 +1,40 @@
+// NOTE: modify these to reflect current versions of packages
+export const VERSION_WORMHOLE = 1;
+export const VERSION_TOKEN_BRIDGE = 1;
+
+// keystore
+export const KEYSTORE = [
+  "AB522qKKEsXMTFRD2SG3Het/02S/ZBOugmcH3R1CDG6l",
+  "AOmPq9B16F3W3ijO/4s9hI6v8LdiYCawKAW31PKpg4Qp",
+  "AGA20wtGcwbcNAG4nwapbQ5wIuXwkYQEWFUoSVAxctHb",
+];
+
+// wallets
+export const WALLET_PRIVATE_KEY = Buffer.from(KEYSTORE[0], "base64").subarray(
+  1
+);
+export const RELAYER_PRIVATE_KEY = Buffer.from(KEYSTORE[1], "base64").subarray(
+  1
+);
+export const CREATOR_PRIVATE_KEY = Buffer.from(KEYSTORE[2], "base64").subarray(
+  1
+);
+
+// guardian signer
+export const GUARDIAN_PRIVATE_KEY =
+  "cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0";
+
+// wormhole
+export const WORMHOLE_STATE_ID =
+  "0xc561a02a143575e53b87ba6c1476f053a307eac5179cb1c8121a3d3b220b81c1";
+
+// token bridge
+export const TOKEN_BRIDGE_STATE_ID =
+  "0x1c8de839f6331f2d745eb53b1b595bc466b4001c11617b0b66214b2e25ee72fc";
+
+// governance
+export const GOVERNANCE_EMITTER =
+  "0000000000000000000000000000000000000000000000000000000000000004";
+
+// file encoding
+export const UTF8: BufferEncoding = "utf-8";

+ 42 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/js/helpers/error/moveAbort.ts

@@ -0,0 +1,42 @@
+export function parseMoveAbort(errorMessage: string) {
+  const parsed = errorMessage.matchAll(
+    /MoveAbort\(MoveLocation { module: ModuleId { address: ([0-9a-f]{64}), name: Identifier\("([A-Za-z_]+)"\) }, function: ([0-9]+), instruction: ([0-9]+), function_name: Some\("([A-Za-z_]+)"\) }, ([0-9]+)\) in command ([0-9]+)/g
+  );
+
+  return parsed.next().value.slice(1, 8);
+}
+
+export class MoveAbort {
+  packageId: string;
+  moduleName: string;
+  functionName: string;
+  errorCode: bigint;
+  command: number;
+
+  constructor(
+    packageId: string,
+    moduleName: string,
+    functionName: string,
+    errorCode: string,
+    command: string
+  ) {
+    this.packageId = packageId;
+    this.moduleName = moduleName;
+    this.functionName = functionName;
+    this.errorCode = BigInt(errorCode);
+    this.command = Number(command);
+  }
+
+  static parseError(errorMessage: string): MoveAbort {
+    const [packageId, moduleName, , , functionName, errorCode, command] =
+      parseMoveAbort(errorMessage);
+
+    return new MoveAbort(
+      "0x" + packageId,
+      moduleName,
+      functionName,
+      errorCode,
+      command
+    );
+  }
+}

+ 22 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/js/helpers/error/wormhole.ts

@@ -0,0 +1,22 @@
+import { MoveAbort } from "./moveAbort";
+
+export function parseWormholeError(errorMessage: string) {
+  const abort = MoveAbort.parseError(errorMessage);
+  const code = abort.errorCode;
+
+  switch (abort.moduleName) {
+    case "required_version": {
+      switch (code) {
+        case 0n: {
+          return "E_OUTDATED_VERSION";
+        }
+        default: {
+          throw new Error(`unrecognized error code: ${abort}`);
+        }
+      }
+    }
+    default: {
+      throw new Error(`unrecognized module: ${abort}`);
+    }
+  }
+}

+ 75 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/js/helpers/setup.ts

@@ -0,0 +1,75 @@
+import * as fs from "fs";
+import * as mock from "@certusone/wormhole-sdk/lib/cjs/mock";
+import { GUARDIAN_PRIVATE_KEY, UTF8 } from "./consts";
+
+export function generateVaaFromDigest(
+  digest: Buffer,
+  governance: mock.GovernanceEmitter
+) {
+  const timestamp = 12345678;
+  const published = governance.publishWormholeUpgradeContract(
+    timestamp,
+    2,
+    "0x" + digest.toString("hex")
+  );
+
+  // Sui is not supported yet by the SDK, so we need to adjust the payload.
+  published.writeUInt16BE(21, published.length - 34);
+
+  // We will use the signed VAA when we execute the upgrade.
+  const guardians = new mock.MockGuardians(0, [GUARDIAN_PRIVATE_KEY]);
+  return guardians.addSignatures(published, [0]);
+}
+
+export function modifyHardCodedVersionControl(
+  packagePath: string,
+  currentVersion: number,
+  newVersion: number
+) {
+  const versionControlDotMove = `${packagePath}/sources/version_control.move`;
+
+  const contents = fs.readFileSync(versionControlDotMove, UTF8);
+  const src = `const CURRENT_BUILD_VERSION: u64 = ${currentVersion}`;
+  if (contents.indexOf(src) < 0) {
+    throw new Error("current version not found");
+  }
+
+  const dst = `const CURRENT_BUILD_VERSION: u64 = ${newVersion}`;
+  fs.writeFileSync(versionControlDotMove, contents.replace(src, dst), UTF8);
+}
+
+export function setUpWormholeDirectory(
+  srcWormholePath: string,
+  dstWormholePath: string
+) {
+  fs.cpSync(srcWormholePath, dstWormholePath, { recursive: true });
+
+  // Remove irrelevant files. This part is not necessary, but is helpful
+  // for debugging a clean package directory.
+  const removeThese = [
+    "Move.devnet.toml",
+    "Move.lock",
+    "Makefile",
+    "README.md",
+    "build",
+  ];
+  for (const basename of removeThese) {
+    fs.rmSync(`${dstWormholePath}/${basename}`, {
+      recursive: true,
+      force: true,
+    });
+  }
+
+  // Fix Move.toml file.
+  const moveTomlPath = `${dstWormholePath}/Move.toml`;
+  const moveToml = fs.readFileSync(moveTomlPath, UTF8);
+  fs.writeFileSync(
+    moveTomlPath,
+    moveToml.replace(`wormhole = "_"`, `wormhole = "0x0"`),
+    UTF8
+  );
+}
+
+export function cleanUpPackageDirectory(packagePath: string) {
+  fs.rmSync(packagePath, { recursive: true, force: true });
+}

+ 73 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/js/helpers/upgrade.ts

@@ -0,0 +1,73 @@
+import {
+  RawSigner,
+  SUI_CLOCK_OBJECT_ID,
+  TransactionBlock,
+} from "@mysten/sui.js";
+import { buildForBytecode } from "./build";
+import { getPackageId } from "./utils";
+
+export async function buildAndUpgradeWormhole(
+  signer: RawSigner,
+  signedVaa: Buffer,
+  wormholePath: string,
+  wormholeStateId: string
+) {
+  const wormholePackage = await getPackageId(signer.provider, wormholeStateId);
+
+  const tx = new TransactionBlock();
+
+  // Authorize upgrade.
+  const [upgradeTicket] = tx.moveCall({
+    target: `${wormholePackage}::upgrade_contract::authorize_upgrade`,
+    arguments: [
+      tx.object(wormholeStateId),
+      tx.pure(Array.from(signedVaa)),
+      tx.object(SUI_CLOCK_OBJECT_ID),
+    ],
+  });
+
+  // Build and generate modules and dependencies for upgrade.
+  const { modules, dependencies } = buildForBytecode(wormholePath);
+  const [upgradeReceipt] = tx.upgrade({
+    modules,
+    dependencies,
+    packageId: wormholePackage,
+    ticket: upgradeTicket,
+  });
+
+  // Commit upgrade.
+  tx.moveCall({
+    target: `${wormholePackage}::upgrade_contract::commit_upgrade`,
+    arguments: [tx.object(wormholeStateId), upgradeReceipt],
+  });
+
+  // Cannot auto compute gas budget, so we need to configure it manually.
+  // Gas ~215m.
+  tx.setGasBudget(215_000_000n);
+
+  return signer.signAndExecuteTransactionBlock({
+    transactionBlock: tx,
+    options: {
+      showEffects: true,
+      showEvents: true,
+    },
+  });
+}
+
+export async function migrate(signer: RawSigner, stateId: string) {
+  const contractPackage = await getPackageId(signer.provider, stateId);
+
+  const tx = new TransactionBlock();
+  tx.moveCall({
+    target: `${contractPackage}::migrate::migrate`,
+    arguments: [tx.object(stateId)],
+  });
+
+  return signer.signAndExecuteTransactionBlock({
+    transactionBlock: tx,
+    options: {
+      showEffects: true,
+      showEvents: true,
+    },
+  });
+}

+ 27 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/js/helpers/utils.ts

@@ -0,0 +1,27 @@
+import { JsonRpcProvider } from "@mysten/sui.js";
+
+export async function getPackageId(
+  provider: JsonRpcProvider,
+  stateId: string
+): Promise<string> {
+  const state = await provider
+    .getObject({
+      id: stateId,
+      options: {
+        showContent: true,
+      },
+    })
+    .then((result) => {
+      if (result.data?.content?.dataType == "moveObject") {
+        return result.data.content.fields;
+      }
+
+      throw new Error("not move object");
+    });
+
+  if ("upgrade_cap" in state) {
+    return state.upgrade_cap.fields.package;
+  }
+
+  throw new Error("upgrade_cap not found");
+}

+ 31 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/js/helpers/wormhole/testPublishMessage.ts

@@ -0,0 +1,31 @@
+import { SUI_CLOCK_OBJECT_ID, TransactionBlock } from "@mysten/sui.js";
+
+export function addPrepareMessageAndPublishMessage(
+  tx: TransactionBlock,
+  wormholePackage: string,
+  wormholeStateId: string,
+  emitterCapId: string,
+  nonce: number,
+  payload: number[] | string
+): TransactionBlock {
+  const [feeAmount] = tx.moveCall({
+    target: `${wormholePackage}::state::message_fee`,
+    arguments: [tx.object(wormholeStateId)],
+  });
+  const [wormholeFee] = tx.splitCoins(tx.gas, [feeAmount]);
+  const [messageTicket] = tx.moveCall({
+    target: `${wormholePackage}::publish_message::prepare_message`,
+    arguments: [tx.object(emitterCapId), tx.pure(nonce), tx.pure(payload)],
+  });
+  tx.moveCall({
+    target: `${wormholePackage}::publish_message::publish_message`,
+    arguments: [
+      tx.object(wormholeStateId),
+      wormholeFee,
+      messageTicket,
+      tx.object(SUI_CLOCK_OBJECT_ID),
+    ],
+  });
+
+  return tx;
+}

+ 5917 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/package-lock.json

@@ -0,0 +1,5917 @@
+{
+  "name": "wormhole-sui-integration-test",
+  "version": "1.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "wormhole-sui-integration-test",
+      "version": "1.0.0",
+      "license": "MIT",
+      "dependencies": {
+        "@certusone/wormhole-sdk": "^0.9.12",
+        "@mysten/sui.js": "^0.32.2",
+        "chai": "^4.3.7",
+        "mocha": "^10.2.0",
+        "prettier": "^2.8.7",
+        "ts-mocha": "^10.0.0",
+        "ts-node": "^10.9.1",
+        "typescript": "^5.0.4"
+      },
+      "devDependencies": {
+        "@types/chai": "^4.3.4",
+        "@types/mocha": "^10.0.1",
+        "@types/node": "^18.15.11"
+      }
+    },
+    "node_modules/@apollo/client": {
+      "version": "3.7.11",
+      "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.7.11.tgz",
+      "integrity": "sha512-uLg2KtxoAyj9ta7abLxXx8cGRM7HypCkXVmxtL7Ko//N5g37aoJ3ca7VYoFCMUFO1BXBulj+yKVl0U3+ILj5AQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@graphql-typed-document-node/core": "^3.1.1",
+        "@wry/context": "^0.7.0",
+        "@wry/equality": "^0.5.0",
+        "@wry/trie": "^0.3.0",
+        "graphql-tag": "^2.12.6",
+        "hoist-non-react-statics": "^3.3.2",
+        "optimism": "^0.16.2",
+        "prop-types": "^15.7.2",
+        "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": "^14.0.0 || ^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/@babel/runtime": {
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz",
+      "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==",
+      "license": "MIT",
+      "dependencies": {
+        "regenerator-runtime": "^0.13.11"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@certusone/wormhole-sdk": {
+      "version": "0.9.12",
+      "resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.9.12.tgz",
+      "integrity": "sha512-ywMNc/tHg6qb9dcZLND1BMUISp7eFN+ksymOgjhwQcZZ/KUA/N1uVvbMVs0uSx+i0y4VloO9MwGc/uFnYKNsMQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@certusone/wormhole-sdk-proto-web": "0.0.6",
+        "@certusone/wormhole-sdk-wasm": "^0.0.1",
+        "@coral-xyz/borsh": "0.2.6",
+        "@injectivelabs/networks": "^1.0.73",
+        "@injectivelabs/sdk-ts": "^1.0.368",
+        "@injectivelabs/utils": "^1.0.63",
+        "@project-serum/anchor": "^0.25.0",
+        "@solana/spl-token": "^0.3.5",
+        "@solana/web3.js": "^1.66.2",
+        "@terra-money/terra.js": "^3.1.3",
+        "@xpla/xpla.js": "^0.2.1",
+        "algosdk": "^1.15.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"
+      }
+    },
+    "node_modules/@certusone/wormhole-sdk-proto-web": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk-proto-web/-/wormhole-sdk-proto-web-0.0.6.tgz",
+      "integrity": "sha512-LTyjsrWryefx5WmkoBP6FQ2EjLxhMExAGxLkloHUhufVQZdrbGh0htBBUviP+HaDSJBCMPMtulNFwkBJV6muqQ==",
+      "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/@improbable-eng/grpc-web": {
+      "version": "0.15.0",
+      "resolved": "https://registry.npmjs.org/@improbable-eng/grpc-web/-/grpc-web-0.15.0.tgz",
+      "integrity": "sha512-ERft9/0/8CmYalqOVnJnpdDry28q+j+nAlFFARdjyxXDJ+Mhgv9+F600QC8BR9ygOfrXRlAk6CvST2j+JCpQPg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "browser-headers": "^0.4.1"
+      },
+      "peerDependencies": {
+        "google-protobuf": "^3.14.0"
+      }
+    },
+    "node_modules/@certusone/wormhole-sdk-proto-web/node_modules/long": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz",
+      "integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@certusone/wormhole-sdk-proto-web/node_modules/protobufjs": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.3.tgz",
+      "integrity": "sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==",
+      "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-wasm": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk-wasm/-/wormhole-sdk-wasm-0.0.1.tgz",
+      "integrity": "sha512-LdIwLhOyr4pPs2jqYubqC7d4UkqYBX0EG/ppspQlW3qlVE0LZRMrH6oVzzLMyHtV0Rw7O9sIKzORW/T3mrJv2w==",
+      "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",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
+      "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
+      "license": "MIT",
+      "dependencies": {
+        "follow-redirects": "^1.14.4"
+      }
+    },
+    "node_modules/@classic-terra/terra.proto": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@classic-terra/terra.proto/-/terra.proto-1.1.0.tgz",
+      "integrity": "sha512-bYhQG5LUaGF0KPRY9hYT/HEcd1QExZPQd6zLV/rQkCe/eDxfwFRLzZHpaaAdfWoAAZjsRWqJbUCqCg7gXBbJpw==",
+      "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/@confio/ics23": {
+      "version": "0.6.8",
+      "resolved": "https://registry.npmjs.org/@confio/ics23/-/ics23-0.6.8.tgz",
+      "integrity": "sha512-wB6uo+3A50m0sW/EWcU64xpV/8wShZ6bMTa7pF8eYsTrSkQA7oLUIJcs/wb8g4y2Oyq701BaGiO6n/ak5WXO1w==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@noble/hashes": "^1.0.0",
+        "protobufjs": "^6.8.8"
+      }
+    },
+    "node_modules/@coral-xyz/borsh": {
+      "version": "0.2.6",
+      "resolved": "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.2.6.tgz",
+      "integrity": "sha512-y6nmHw1bFcJib7sMHsQPpC8r47xhqDZVvhUdna7NUPzpSbOZG6f46N21+aXsQ2w/tG8Ggls488J/ZmwbgVmyjg==",
+      "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.30.1",
+      "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.30.1.tgz",
+      "integrity": "sha512-yNHnzmvAlkETDYIpeCTdVqgvrdt1qgkOXwuRVi8s27UKI5hfqyE9fJ/fuunXE6ZZPnKkjIecDznmuUOMrMvw4w==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/crypto": "^0.30.1",
+        "@cosmjs/encoding": "^0.30.1",
+        "@cosmjs/math": "^0.30.1",
+        "@cosmjs/utils": "^0.30.1"
+      }
+    },
+    "node_modules/@cosmjs/crypto": {
+      "version": "0.30.1",
+      "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.30.1.tgz",
+      "integrity": "sha512-rAljUlake3MSXs9xAm87mu34GfBLN0h/1uPPV6jEwClWjNkAMotzjC0ab9MARy5FFAvYHL3lWb57bhkbt2GtzQ==",
+      "license": "Apache-2.0",
+      "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/@cosmjs/encoding": {
+      "version": "0.30.1",
+      "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.30.1.tgz",
+      "integrity": "sha512-rXmrTbgqwihORwJ3xYhIgQFfMSrwLu1s43RIK9I8EBudPx3KmnmyAKzMOVsRDo9edLFNuZ9GIvysUCwQfq3WlQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "base64-js": "^1.3.0",
+        "bech32": "^1.1.4",
+        "readonly-date": "^1.0.0"
+      }
+    },
+    "node_modules/@cosmjs/encoding/node_modules/bech32": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz",
+      "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==",
+      "license": "MIT"
+    },
+    "node_modules/@cosmjs/json-rpc": {
+      "version": "0.30.1",
+      "resolved": "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.30.1.tgz",
+      "integrity": "sha512-pitfC/2YN9t+kXZCbNuyrZ6M8abnCC2n62m+JtU9vQUfaEtVsgy+1Fk4TRQ175+pIWSdBMFi2wT8FWVEE4RhxQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/stream": "^0.30.1",
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/@cosmjs/math": {
+      "version": "0.30.1",
+      "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.30.1.tgz",
+      "integrity": "sha512-yaoeI23pin9ZiPHIisa6qqLngfnBR/25tSaWpkTm8Cy10MX70UF5oN4+/t1heLaM6SSmRrhk3psRkV4+7mH51Q==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "bn.js": "^5.2.0"
+      }
+    },
+    "node_modules/@cosmjs/proto-signing": {
+      "version": "0.30.1",
+      "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.30.1.tgz",
+      "integrity": "sha512-tXh8pPYXV4aiJVhTKHGyeZekjj+K9s2KKojMB93Gcob2DxUjfKapFYBMJSgfKPuWUPEmyr8Q9km2hplI38ILgQ==",
+      "license": "Apache-2.0",
+      "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/@cosmjs/socket": {
+      "version": "0.30.1",
+      "resolved": "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.30.1.tgz",
+      "integrity": "sha512-r6MpDL+9N+qOS/D5VaxnPaMJ3flwQ36G+vPvYJsXArj93BjgyFB7BwWwXCQDzZ+23cfChPUfhbINOenr8N2Kow==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@cosmjs/stream": "^0.30.1",
+        "isomorphic-ws": "^4.0.1",
+        "ws": "^7",
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/@cosmjs/stargate": {
+      "version": "0.30.1",
+      "resolved": "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.30.1.tgz",
+      "integrity": "sha512-RdbYKZCGOH8gWebO7r6WvNnQMxHrNXInY/gPHPzMjbQF6UatA6fNM2G2tdgS5j5u7FTqlCI10stNXrknaNdzog==",
+      "license": "Apache-2.0",
+      "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/@cosmjs/stream": {
+      "version": "0.30.1",
+      "resolved": "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.30.1.tgz",
+      "integrity": "sha512-Fg0pWz1zXQdoxQZpdHRMGvUH5RqS6tPv+j9Eh7Q953UjMlrwZVo0YFLC8OTf/HKVf10E4i0u6aM8D69Q6cNkgQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "xstream": "^11.14.0"
+      }
+    },
+    "node_modules/@cosmjs/tendermint-rpc": {
+      "version": "0.30.1",
+      "resolved": "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.30.1.tgz",
+      "integrity": "sha512-Z3nCwhXSbPZJ++v85zHObeUggrEHVfm1u18ZRwXxFE9ZMl5mXTybnwYhczuYOl7KRskgwlB+rID0WYACxj4wdQ==",
+      "license": "Apache-2.0",
+      "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/@cosmjs/utils": {
+      "version": "0.30.1",
+      "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.30.1.tgz",
+      "integrity": "sha512-KvvX58MGMWh7xA+N+deCfunkA/ZNDvFLw4YbOmX3f/XBIkqrVY7qlotfy2aNb1kgp6h4B6Yc8YawJPDTfvWX7g==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@cspotcode/source-map-support": {
+      "version": "0.8.1",
+      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+      "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+      "dependencies": {
+        "@jridgewell/trace-mapping": "0.3.9"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@ethereumjs/common": {
+      "version": "2.6.5",
+      "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.6.5.tgz",
+      "integrity": "sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA==",
+      "license": "MIT",
+      "dependencies": {
+        "crc-32": "^1.2.0",
+        "ethereumjs-util": "^7.1.5"
+      }
+    },
+    "node_modules/@ethereumjs/tx": {
+      "version": "3.5.2",
+      "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.5.2.tgz",
+      "integrity": "sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw==",
+      "license": "MPL-2.0",
+      "dependencies": {
+        "@ethereumjs/common": "^2.6.4",
+        "ethereumjs-util": "^7.1.5"
+      }
+    },
+    "node_modules/@ethersproject/abi": {
+      "version": "5.7.0",
+      "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz",
+      "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz",
+      "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz",
+      "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz",
+      "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz",
+      "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz",
+      "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz",
+      "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz",
+      "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz",
+      "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz",
+      "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz",
+      "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz",
+      "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz",
+      "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz",
+      "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz",
+      "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz",
+      "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz",
+      "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz",
+      "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz",
+      "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==",
+      "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/bech32": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz",
+      "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==",
+      "license": "MIT"
+    },
+    "node_modules/@ethersproject/providers/node_modules/ws": {
+      "version": "7.4.6",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
+      "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz",
+      "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz",
+      "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz",
+      "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz",
+      "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz",
+      "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz",
+      "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz",
+      "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz",
+      "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz",
+      "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz",
+      "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz",
+      "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz",
+      "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==",
+      "license": "MIT",
+      "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.14.1",
+      "resolved": "https://registry.npmjs.org/@improbable-eng/grpc-web/-/grpc-web-0.14.1.tgz",
+      "integrity": "sha512-XaIYuunepPxoiGVLLHmlnVminUGzBTnXr8Wv7khzmLWbNw4TCwJKX09GSMJlKhu/TRk6gms0ySFxewaETSBqgw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "browser-headers": "^0.4.1"
+      },
+      "peerDependencies": {
+        "google-protobuf": "^3.14.0"
+      }
+    },
+    "node_modules/@injectivelabs/core-proto-ts": {
+      "version": "0.0.11",
+      "resolved": "https://registry.npmjs.org/@injectivelabs/core-proto-ts/-/core-proto-ts-0.0.11.tgz",
+      "integrity": "sha512-gYMzkoZ0olXLbEhSQVarUCMR6VAHytvENDv2Psjl9EjO5Pg93vTGLViS4E4vA5fezRfdF/x0Uic31w+ogp66jA==",
+      "license": "MIT",
+      "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.1",
+      "resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz",
+      "integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@injectivelabs/core-proto-ts/node_modules/protobufjs": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.3.tgz",
+      "integrity": "sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==",
+      "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/@injectivelabs/exceptions": {
+      "version": "1.10.2",
+      "resolved": "https://registry.npmjs.org/@injectivelabs/exceptions/-/exceptions-1.10.2.tgz",
+      "integrity": "sha512-JLHgU/MjxRYSpn/9G9mJvHuNiA5ze6w86sXz09kQh7tlSaTC4PGqBBbBSu0hrUBBX86O+vk2ULkn1Ks1n7FlOw==",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@injectivelabs/grpc-web": "^0.0.1",
+        "@injectivelabs/ts-types": "^1.10.1",
+        "http-status-codes": "^2.2.0",
+        "link-module-alias": "^1.2.0",
+        "shx": "^0.3.2"
+      }
+    },
+    "node_modules/@injectivelabs/exceptions/dist": {
+      "extraneous": true
+    },
+    "node_modules/@injectivelabs/grpc-web": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/@injectivelabs/grpc-web/-/grpc-web-0.0.1.tgz",
+      "integrity": "sha512-Pu5YgaZp+OvR5UWfqbrPdHer3+gDf+b5fQoY+t2VZx1IAVHX8bzbN9EreYTvTYtFeDpYRWM8P7app2u4EX5wTw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "browser-headers": "^0.4.1"
+      },
+      "peerDependencies": {
+        "google-protobuf": "^3.14.0"
+      }
+    },
+    "node_modules/@injectivelabs/grpc-web-node-http-transport": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/@injectivelabs/grpc-web-node-http-transport/-/grpc-web-node-http-transport-0.0.2.tgz",
+      "integrity": "sha512-rpyhXLiGY/UMs6v6YmgWHJHiO9l0AgDyVNv+jcutNVt4tQrmNvnpvz2wCAGOFtq5LuX/E9ChtTVpk3gWGqXcGA==",
+      "license": "Apache-2.0",
+      "peerDependencies": {
+        "@injectivelabs/grpc-web": ">=0.0.1"
+      }
+    },
+    "node_modules/@injectivelabs/grpc-web-react-native-transport": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/@injectivelabs/grpc-web-react-native-transport/-/grpc-web-react-native-transport-0.0.2.tgz",
+      "integrity": "sha512-mk+aukQXnYNgPsPnu3KBi+FD0ZHQpazIlaBZ2jNZG7QAVmxTWtv3R66Zoq99Wx2dnE946NsZBYAoa0K5oSjnow==",
+      "license": "Apache-2.0",
+      "peerDependencies": {
+        "@injectivelabs/grpc-web": ">=0.0.1"
+      }
+    },
+    "node_modules/@injectivelabs/indexer-proto-ts": {
+      "version": "0.0.9",
+      "resolved": "https://registry.npmjs.org/@injectivelabs/indexer-proto-ts/-/indexer-proto-ts-0.0.9.tgz",
+      "integrity": "sha512-ZFTUKlHAY2WYnB9RPPf11nq7SNm7wcKFTmFTavTiHV8UvNEni7dCR3Un6U5Mo1qD0xHEsfoCDMdqGcIguliPMA==",
+      "license": "MIT",
+      "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.1",
+      "resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz",
+      "integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@injectivelabs/indexer-proto-ts/node_modules/protobufjs": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.3.tgz",
+      "integrity": "sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==",
+      "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/@injectivelabs/mito-proto-ts": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@injectivelabs/mito-proto-ts/-/mito-proto-ts-1.0.2.tgz",
+      "integrity": "sha512-A/5Nf/RJiBRiwYNqH2K0nNrOuuVcYCebqgEt3btpDfQXcyaHIssjDmZOtmMT1M7P/enEVgDu0auxE7tsmSFijg==",
+      "license": "MIT",
+      "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.1",
+      "resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz",
+      "integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@injectivelabs/mito-proto-ts/node_modules/protobufjs": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.3.tgz",
+      "integrity": "sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==",
+      "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/@injectivelabs/networks": {
+      "version": "1.10.4",
+      "resolved": "https://registry.npmjs.org/@injectivelabs/networks/-/networks-1.10.4.tgz",
+      "integrity": "sha512-EjWdTXpU+j8YFikxiMacVhPK8dzamMD4czkrst7NfcMRoBCMNMrOp5lItF5GFq0BSx3xu/zfkb2+3wWTIdWUxQ==",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@injectivelabs/exceptions": "^1.10.2",
+        "@injectivelabs/ts-types": "^1.10.1",
+        "@injectivelabs/utils": "^1.10.2",
+        "link-module-alias": "^1.2.0",
+        "shx": "^0.3.2"
+      }
+    },
+    "node_modules/@injectivelabs/networks/dist": {
+      "extraneous": true
+    },
+    "node_modules/@injectivelabs/sdk-ts": {
+      "version": "1.10.37",
+      "resolved": "https://registry.npmjs.org/@injectivelabs/sdk-ts/-/sdk-ts-1.10.37.tgz",
+      "integrity": "sha512-+7LzC1iDiN3oT7PZ3yV2PchsrH1WQfS+tV8/geesi0EBKT4AW4v2Ur3OYhtDXvQia1zSxWJY9phS3iAmaBd9vQ==",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "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.11",
+        "@injectivelabs/exceptions": "^1.10.2",
+        "@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": "^0.0.9",
+        "@injectivelabs/mito-proto-ts": "1.0.2",
+        "@injectivelabs/networks": "^1.10.4",
+        "@injectivelabs/test-utils": "^1.10.1",
+        "@injectivelabs/token-metadata": "^1.10.17",
+        "@injectivelabs/ts-types": "^1.10.1",
+        "@injectivelabs/utils": "^1.10.2",
+        "@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/dist": {
+      "extraneous": true
+    },
+    "node_modules/@injectivelabs/sdk-ts/node_modules/axios": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
+      "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
+      "license": "MIT",
+      "dependencies": {
+        "follow-redirects": "^1.14.9",
+        "form-data": "^4.0.0"
+      }
+    },
+    "node_modules/@injectivelabs/test-utils": {
+      "version": "1.10.1",
+      "resolved": "https://registry.npmjs.org/@injectivelabs/test-utils/-/test-utils-1.10.1.tgz",
+      "integrity": "sha512-ULP3XJBZN8Muv0jVpo0rfUOD/CDlyg4rij6YuRpYhTg6P0wIlKq9dL36cZlylay+F+4HeLn9qB0D2Cr3+FrhPw==",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "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/test-utils/dist": {
+      "extraneous": true
+    },
+    "node_modules/@injectivelabs/token-metadata": {
+      "version": "1.10.17",
+      "resolved": "https://registry.npmjs.org/@injectivelabs/token-metadata/-/token-metadata-1.10.17.tgz",
+      "integrity": "sha512-1TFZMs38B21Y0uzqxRuIHifmj6VrJCZLEJnjGuhzIfhtLqSB/ZtCf3JNAarujwwgj6xWb7vzqzqNpo+SIYKvwg==",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@injectivelabs/exceptions": "^1.10.2",
+        "@injectivelabs/networks": "^1.10.4",
+        "@injectivelabs/ts-types": "^1.10.1",
+        "@injectivelabs/utils": "^1.10.2",
+        "@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/dist": {
+      "extraneous": true
+    },
+    "node_modules/@injectivelabs/ts-types": {
+      "version": "1.10.1",
+      "resolved": "https://registry.npmjs.org/@injectivelabs/ts-types/-/ts-types-1.10.1.tgz",
+      "integrity": "sha512-gQQjcnRx2TjLmZDMV8IIkRvLtAzTPptJuWKwPCfSlCRKOIv7Eafzy2qFINUIkKDOeu/lZUtSykEsAIUBEmXqFg==",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "link-module-alias": "^1.2.0",
+        "shx": "^0.3.2"
+      }
+    },
+    "node_modules/@injectivelabs/ts-types/dist": {
+      "extraneous": true
+    },
+    "node_modules/@injectivelabs/utils": {
+      "version": "1.10.2",
+      "resolved": "https://registry.npmjs.org/@injectivelabs/utils/-/utils-1.10.2.tgz",
+      "integrity": "sha512-XMO7RRbXs06cChr5Wezr0Dbl1Z9hq+ceB4Dn3qyulzupGepeivkoPTcyG4IdjOiwf7PnFeGQ/aVG3hr0rJI7dQ==",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@injectivelabs/exceptions": "^1.10.2",
+        "@injectivelabs/ts-types": "^1.10.1",
+        "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/utils/dist": {
+      "extraneous": true
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
+      "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.4.15",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
+      "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.9",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+      "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.0.3",
+        "@jridgewell/sourcemap-codec": "^1.4.10"
+      }
+    },
+    "node_modules/@metamask/eth-sig-util": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz",
+      "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==",
+      "license": "ISC",
+      "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",
+      "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz",
+      "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@metamask/eth-sig-util/node_modules/bn.js": {
+      "version": "4.12.0",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+      "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+      "license": "MIT"
+    },
+    "node_modules/@metamask/eth-sig-util/node_modules/ethereumjs-util": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz",
+      "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==",
+      "license": "MPL-2.0",
+      "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",
+      "resolved": "https://registry.npmjs.org/@mysten/bcs/-/bcs-0.7.1.tgz",
+      "integrity": "sha512-wFPb8bkhwrbiStfZMV5rFM7J+umpke59/dNjDp+UYJKykNlW23LCk2ePyEUvGdb62HGJM1jyOJ8g4egE3OmdKA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "bs58": "^5.0.0"
+      }
+    },
+    "node_modules/@mysten/bcs/node_modules/base-x": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz",
+      "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==",
+      "license": "MIT"
+    },
+    "node_modules/@mysten/bcs/node_modules/bs58": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz",
+      "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==",
+      "license": "MIT",
+      "dependencies": {
+        "base-x": "^4.0.0"
+      }
+    },
+    "node_modules/@mysten/sui.js": {
+      "version": "0.32.2",
+      "resolved": "https://registry.npmjs.org/@mysten/sui.js/-/sui.js-0.32.2.tgz",
+      "integrity": "sha512-/Hm4xkGolJhqj8FvQr7QSHDTlxIvL52mtbOao9f75YjrBh7y1Uh9kbJSY7xiTF1NY9sv6p5hUVlYRJuM0Hvn9A==",
+      "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/@noble/curves": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.0.0.tgz",
+      "integrity": "sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@noble/hashes": "1.3.0"
+      }
+    },
+    "node_modules/@noble/ed25519": {
+      "version": "1.7.3",
+      "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.3.tgz",
+      "integrity": "sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/@noble/hashes": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz",
+      "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/@noble/secp256k1": {
+      "version": "1.7.1",
+      "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz",
+      "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/@project-serum/anchor": {
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.25.0.tgz",
+      "integrity": "sha512-E6A5Y/ijqpfMJ5psJvbw0kVTzLZFUcOFgs6eSM2M2iWE1lVRF18T6hWZVNl6zqZsoz98jgnNHtVGJMs+ds9A7A==",
+      "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/anchor/node_modules/superstruct": {
+      "version": "0.15.5",
+      "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz",
+      "integrity": "sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==",
+      "license": "MIT"
+    },
+    "node_modules/@project-serum/borsh": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/@project-serum/borsh/-/borsh-0.2.5.tgz",
+      "integrity": "sha512-UmeUkUoKdQ7rhx6Leve1SssMR/Ghv8qrEiyywyxSWg7ooV7StdpPBhciiy5eB3T0qU1BXvdRNC8TdrkxK7WC5Q==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
+      "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/base64": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
+      "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/codegen": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
+      "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/eventemitter": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
+      "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/fetch": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
+      "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.1",
+        "@protobufjs/inquire": "^1.1.0"
+      }
+    },
+    "node_modules/@protobufjs/float": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
+      "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/inquire": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
+      "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/path": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
+      "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/pool": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
+      "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/utf8": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
+      "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@scure/base": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz",
+      "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/@scure/bip32": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.0.tgz",
+      "integrity": "sha512-bcKpo1oj54hGholplGLpqPHRbIsnbixFtc06nwuNM5/dwSXOq/AAYoIBRsBmnZJSdfeNW5rnff7NTAz3ZCqR9Q==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@noble/curves": "~1.0.0",
+        "@noble/hashes": "~1.3.0",
+        "@scure/base": "~1.1.0"
+      }
+    },
+    "node_modules/@scure/bip39": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.0.tgz",
+      "integrity": "sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@noble/hashes": "~1.3.0",
+        "@scure/base": "~1.1.0"
+      }
+    },
+    "node_modules/@solana/buffer-layout": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz",
+      "integrity": "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==",
+      "license": "MIT",
+      "dependencies": {
+        "buffer": "~6.0.3"
+      },
+      "engines": {
+        "node": ">=5.10"
+      }
+    },
+    "node_modules/@solana/buffer-layout-utils": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz",
+      "integrity": "sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.3.7.tgz",
+      "integrity": "sha512-bKGxWTtIw6VDdCBngjtsGlKGLSmiu/8ghSt/IOYJV24BsymRbgq7r12GToeetpxmPaZYLddKwAz7+EwprLfkfg==",
+      "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.75.0",
+      "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.75.0.tgz",
+      "integrity": "sha512-rHQgdo1EWfb+nPUpHe4O7i8qJPELHKNR5PAZRK+a7XxiykqOfbaAlPt5boDWAGPnYbSv0ziWZv5mq9DlFaQCxg==",
+      "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.3",
+        "fast-stable-stringify": "^1.0.0",
+        "jayson": "^3.4.4",
+        "node-fetch": "^2.6.7",
+        "rpc-websockets": "^7.5.1",
+        "superstruct": "^0.14.2"
+      }
+    },
+    "node_modules/@solana/web3.js/node_modules/@types/node": {
+      "version": "12.20.55",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz",
+      "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==",
+      "license": "MIT"
+    },
+    "node_modules/@solana/web3.js/node_modules/jayson": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/jayson/-/jayson-3.7.0.tgz",
+      "integrity": "sha512-tfy39KJMrrXJ+mFcMpxwBvFDetS8LAID93+rycFglIQM4kl3uNR3W4lBLE/FFhsoUCEox5Dt2adVpDm/XtebbQ==",
+      "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/@solana/web3.js/node_modules/superstruct": {
+      "version": "0.14.2",
+      "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.14.2.tgz",
+      "integrity": "sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==",
+      "license": "MIT"
+    },
+    "node_modules/@suchipi/femver": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@suchipi/femver/-/femver-1.0.0.tgz",
+      "integrity": "sha512-bprE8+K5V+DPX7q2e2K57ImqNBdfGHDIWaGI5xHxZoxbKOuQZn4wzPiUxOAHnsUr3w3xHrWXwN7gnG/iIuEMIg==",
+      "license": "MIT"
+    },
+    "node_modules/@terra-money/legacy.proto": {
+      "name": "@terra-money/terra.proto",
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/@terra-money/terra.proto/-/terra.proto-0.1.7.tgz",
+      "integrity": "sha512-NXD7f6pQCulvo6+mv6MAPzhOkUzRjgYVuHZE/apih+lVnPG5hDBU0rRYnOGGofwvKT5/jQoOENnFn/gioWWnyQ==",
+      "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.8",
+      "resolved": "https://registry.npmjs.org/@terra-money/terra.js/-/terra.js-3.1.8.tgz",
+      "integrity": "sha512-Cd/fh4MswT00fDGVckoZ0cm77EpIy4+CjSDO0RqZ3Qfp4CJBp7sWTLRNsyzUWjdYOT5iTx+1wOMCYbbyKo6LAw==",
+      "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",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
+      "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
+      "license": "MIT",
+      "dependencies": {
+        "follow-redirects": "^1.14.9",
+        "form-data": "^4.0.0"
+      }
+    },
+    "node_modules/@terra-money/terra.proto": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@terra-money/terra.proto/-/terra.proto-2.1.0.tgz",
+      "integrity": "sha512-rhaMslv3Rkr+QsTQEZs64FKA4QlfO0DfQHaR6yct/EovenMkibDEQ63dEL6yJA6LCaEQGYhyVB9JO9pTUA8ybw==",
+      "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/@tsconfig/node10": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
+      "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA=="
+    },
+    "node_modules/@tsconfig/node12": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+      "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag=="
+    },
+    "node_modules/@tsconfig/node14": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+      "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow=="
+    },
+    "node_modules/@tsconfig/node16": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
+      "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ=="
+    },
+    "node_modules/@types/bn.js": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz",
+      "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/chai": {
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz",
+      "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/connect": {
+      "version": "3.4.35",
+      "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
+      "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/json5": {
+      "version": "0.0.29",
+      "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
+      "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/@types/lodash": {
+      "version": "4.14.192",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.192.tgz",
+      "integrity": "sha512-km+Vyn3BYm5ytMO13k9KTp27O75rbQ0NFw+U//g+PX7VZyjCioXaRFisqSIJRECljcTv73G3i6BpglNGHgUQ5A==",
+      "license": "MIT"
+    },
+    "node_modules/@types/lodash.values": {
+      "version": "4.3.7",
+      "resolved": "https://registry.npmjs.org/@types/lodash.values/-/lodash.values-4.3.7.tgz",
+      "integrity": "sha512-Moex9/sWxtKEa+BKiH5zvmhfcieDlcz4wRxMhO/oJ2qOKUdujoU6dQjUTxWA8jwEREpHXmiY4HCwNRpycW8JQA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/lodash": "*"
+      }
+    },
+    "node_modules/@types/long": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz",
+      "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==",
+      "license": "MIT"
+    },
+    "node_modules/@types/mocha": {
+      "version": "10.0.1",
+      "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz",
+      "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/node": {
+      "version": "18.15.11",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz",
+      "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==",
+      "license": "MIT"
+    },
+    "node_modules/@types/pbkdf2": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz",
+      "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/secp256k1": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.3.tgz",
+      "integrity": "sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/ws": {
+      "version": "7.4.7",
+      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz",
+      "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@wry/context": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.7.0.tgz",
+      "integrity": "sha512-LcDAiYWRtwAoSOArfk7cuYvFXytxfVrdX7yxoUmK7pPITLk5jYh2F8knCwS7LjgYL8u1eidPlKKV6Ikqq0ODqQ==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@wry/equality": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.5.3.tgz",
+      "integrity": "sha512-avR+UXdSrsF2v8vIqIgmeTY0UR91UT+IyablCyKe/uk22uOJ8fusKZnH9JH9e1/EtLeNJBtagNmL3eJdnOV53g==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@wry/trie": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.3.2.tgz",
+      "integrity": "sha512-yRTyhWSls2OY/pYLfwff867r8ekooZ4UI+/gxot5Wj8EFwSf2rG+n+Mo/6LoLQm1TKA4GRj2+LCpbfS937dClQ==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@xpla/xpla.js": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/@xpla/xpla.js/-/xpla.js-0.2.3.tgz",
+      "integrity": "sha512-Tfk7hCGWXtwr08reY3Pi6dmzIqFbzri9jcyzJdfNmdo4cN0PMwpRJuZZcPmtxiIUnNef3AN1E/6nJUD5MKniuA==",
+      "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",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
+      "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
+      "license": "MIT",
+      "dependencies": {
+        "follow-redirects": "^1.14.8"
+      }
+    },
+    "node_modules/acorn": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz",
+      "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==",
+      "license": "MIT",
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-walk": {
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+      "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/aes-js": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz",
+      "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==",
+      "license": "MIT"
+    },
+    "node_modules/agentkeepalive": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz",
+      "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==",
+      "license": "MIT",
+      "dependencies": {
+        "debug": "^4.1.0",
+        "depd": "^2.0.0",
+        "humanize-ms": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 8.0.0"
+      }
+    },
+    "node_modules/algo-msgpack-with-bigint": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/algo-msgpack-with-bigint/-/algo-msgpack-with-bigint-2.1.1.tgz",
+      "integrity": "sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ==",
+      "license": "ISC",
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/algosdk": {
+      "version": "1.24.1",
+      "resolved": "https://registry.npmjs.org/algosdk/-/algosdk-1.24.1.tgz",
+      "integrity": "sha512-9moZxdqeJ6GdE4N6fA/GlUP4LrbLZMYcYkt141J4Ss68OfEgH9qW0wBuZ3ZOKEx/xjc5bg7mLP2Gjg7nwrkmww==",
+      "license": "MIT",
+      "dependencies": {
+        "algo-msgpack-with-bigint": "^2.1.1",
+        "buffer": "^6.0.2",
+        "cross-fetch": "^3.1.5",
+        "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": ">=14.0.0"
+      }
+    },
+    "node_modules/ansi-colors": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+      "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "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",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+      "license": "ISC",
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/aptos": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/aptos/-/aptos-1.5.0.tgz",
+      "integrity": "sha512-N7OuRtU7IYHkDkNx+4QS3g/QQGCp+36KzYn3oXPmT7Kttfuv+UKliQVdjy3cLmwd/DCQSh9ObTovwdxnHjUn0g==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.3.tgz",
+      "integrity": "sha512-CE0FCR57H2acVI5UOzIGSSIYxZ6v/HOhDR0Ro9VLyhnzLwx0o8W1mmgaqlEUx4049qJDlIBRztv5k+MM8vbO3A==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/aptos/node_modules/@scure/bip39": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.0.tgz",
+      "integrity": "sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w==",
+      "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/@scure/bip39/node_modules/@noble/hashes": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.5.tgz",
+      "integrity": "sha512-LTMZiiLc+V4v1Yi16TD6aX2gmtKszNye0pQgbaLqkvhIqP7nVsSaJsWloGQjJfJ8offaoP5GtX3yY5swbcJxxQ==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/aptos/node_modules/axios": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
+      "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
+      "license": "MIT",
+      "dependencies": {
+        "follow-redirects": "^1.14.9",
+        "form-data": "^4.0.0"
+      }
+    },
+    "node_modules/arg": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+      "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="
+    },
+    "node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "license": "Python-2.0"
+    },
+    "node_modules/arrify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+      "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/assertion-error": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
+      "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
+      "license": "MIT",
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+      "license": "MIT"
+    },
+    "node_modules/axios": {
+      "version": "0.21.4",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
+      "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
+      "license": "MIT",
+      "dependencies": {
+        "follow-redirects": "^1.14.0"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "license": "MIT"
+    },
+    "node_modules/base-x": {
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
+      "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "node_modules/base64-js": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+      "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": "2.0.0",
+      "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz",
+      "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==",
+      "license": "MIT"
+    },
+    "node_modules/big-integer": {
+      "version": "1.6.36",
+      "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz",
+      "integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg==",
+      "license": "Unlicense",
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/bigint-buffer": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz",
+      "integrity": "sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "bindings": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 10.0.0"
+      }
+    },
+    "node_modules/bignumber.js": {
+      "version": "9.1.1",
+      "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz",
+      "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==",
+      "license": "MIT",
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/binary-extensions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+      "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/binary-parser": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/binary-parser/-/binary-parser-2.2.1.tgz",
+      "integrity": "sha512-5ATpz/uPDgq5GgEDxTB4ouXCde7q2lqAQlSdBRQVl/AJnxmQmhIfyxJx+0MGu//D5rHQifkfGbWWlaysG0o9NA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/bindings": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+      "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+      "license": "MIT",
+      "dependencies": {
+        "file-uri-to-path": "1.0.0"
+      }
+    },
+    "node_modules/bip32": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/bip32/-/bip32-2.0.6.tgz",
+      "integrity": "sha512-HpV5OMLLGTjSVblmrtYRfFFKuQB+GArM0+XP8HGWfJ5vxYBqo+DesvJwOdC2WJ3bCkZShGf0QIfoIpeomVzVdA==",
+      "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",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz",
+      "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==",
+      "license": "MIT"
+    },
+    "node_modules/bip39": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz",
+      "integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==",
+      "license": "ISC",
+      "dependencies": {
+        "@noble/hashes": "^1.2.0"
+      }
+    },
+    "node_modules/bip66": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz",
+      "integrity": "sha512-nemMHz95EmS38a26XbbdxIYj5csHd3RMP3H5bwQknX0WYHF01qhpufP42mLOwVICuH2JmhIhXiWs89MfUGL7Xw==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "node_modules/blakejs": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz",
+      "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==",
+      "license": "MIT"
+    },
+    "node_modules/bn.js": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
+      "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
+      "license": "MIT"
+    },
+    "node_modules/borsh": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz",
+      "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==",
+      "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",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "license": "MIT",
+      "dependencies": {
+        "fill-range": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/brorand": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
+      "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==",
+      "license": "MIT"
+    },
+    "node_modules/browser-headers": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/browser-headers/-/browser-headers-0.4.1.tgz",
+      "integrity": "sha512-CA9hsySZVo9371qEHjHZtYxV2cFtVj5Wj/ZHi8ooEsrtm4vOnl9Y9HmyYWk9q+05d7K3rdoAE0j3MVEFVvtQtg==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/browser-stdout": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
+      "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
+      "license": "ISC"
+    },
+    "node_modules/browserify-aes": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
+      "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
+      "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/bs58": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
+      "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==",
+      "license": "MIT",
+      "dependencies": {
+        "base-x": "^3.0.2"
+      }
+    },
+    "node_modules/bs58check": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
+      "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
+      "license": "MIT",
+      "dependencies": {
+        "bs58": "^4.0.0",
+        "create-hash": "^1.1.0",
+        "safe-buffer": "^5.1.2"
+      }
+    },
+    "node_modules/buffer": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+      "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",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
+    },
+    "node_modules/buffer-layout": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz",
+      "integrity": "sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=4.5"
+      }
+    },
+    "node_modules/buffer-xor": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
+      "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==",
+      "license": "MIT"
+    },
+    "node_modules/bufferutil": {
+      "version": "4.0.7",
+      "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz",
+      "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "dependencies": {
+        "node-gyp-build": "^4.3.0"
+      },
+      "engines": {
+        "node": ">=6.14.2"
+      }
+    },
+    "node_modules/camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/capability": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/capability/-/capability-0.2.5.tgz",
+      "integrity": "sha512-rsJZYVCgXd08sPqwmaIqjAd5SUTfonV0z/gDJ8D6cN8wQphky1kkAYEqQ+hmDxTw7UihvBfjUVUSY+DBEe44jg==",
+      "license": "MIT"
+    },
+    "node_modules/chai": {
+      "version": "4.3.7",
+      "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz",
+      "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==",
+      "license": "MIT",
+      "dependencies": {
+        "assertion-error": "^1.1.0",
+        "check-error": "^1.0.2",
+        "deep-eql": "^4.1.2",
+        "get-func-name": "^2.0.0",
+        "loupe": "^2.3.1",
+        "pathval": "^1.1.1",
+        "type-detect": "^4.0.5"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "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/chalk/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/check-error": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
+      "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==",
+      "license": "MIT",
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/chokidar": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+      "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/cipher-base": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+      "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+      "license": "MIT",
+      "dependencies": {
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "node_modules/cliui": {
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+      "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+      "license": "ISC",
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^7.0.0"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "license": "MIT"
+    },
+    "node_modules/combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "license": "MIT",
+      "dependencies": {
+        "delayed-stream": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/commander": {
+      "version": "2.20.3",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+      "license": "MIT"
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+      "license": "MIT"
+    },
+    "node_modules/copyfiles": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz",
+      "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==",
+      "license": "MIT",
+      "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/mkdirp": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+      "license": "MIT",
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/core-util-is": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+      "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+      "license": "MIT"
+    },
+    "node_modules/cosmjs-types": {
+      "version": "0.7.2",
+      "resolved": "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.7.2.tgz",
+      "integrity": "sha512-vf2uLyktjr/XVAgEq0DjMxeAWh1yYREe7AMHDKd7EiHVqxBPCaBS+qEEQUkXbR9ndnckqr1sUG8BQhazh4X5lA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "long": "^4.0.0",
+        "protobufjs": "~6.11.2"
+      }
+    },
+    "node_modules/crc-32": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
+      "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
+      "license": "Apache-2.0",
+      "bin": {
+        "crc32": "bin/crc32.njs"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/create-hash": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
+      "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
+      "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",
+      "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
+      "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
+      "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",
+      "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+      "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="
+    },
+    "node_modules/cross-fetch": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
+      "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
+      "license": "MIT",
+      "dependencies": {
+        "node-fetch": "2.6.7"
+      }
+    },
+    "node_modules/cross-fetch/node_modules/node-fetch": {
+      "version": "2.6.7",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+      "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+      "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/crypto-addr-codec": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/crypto-addr-codec/-/crypto-addr-codec-0.1.7.tgz",
+      "integrity": "sha512-X4hzfBzNhy4mAc3UpiXEC/L0jo5E8wAa9unsnA8nNXYzXjCcGk83hfC5avJWCSGT8V91xMnAS9AKMHmjw5+XCg==",
+      "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",
+      "resolved": "https://registry.npmjs.org/crypto-hash/-/crypto-hash-1.3.0.tgz",
+      "integrity": "sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/debug": {
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+      "license": "MIT",
+      "dependencies": {
+        "ms": "2.1.2"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/debug/node_modules/ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+      "license": "MIT"
+    },
+    "node_modules/decamelize": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+      "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/decimal.js": {
+      "version": "10.4.3",
+      "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
+      "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==",
+      "license": "MIT"
+    },
+    "node_modules/deep-eql": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
+      "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
+      "license": "MIT",
+      "dependencies": {
+        "type-detect": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/define-properties": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz",
+      "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==",
+      "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",
+      "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz",
+      "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/depd": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/diff": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
+      "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.3.1"
+      }
+    },
+    "node_modules/dot-case": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
+      "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
+      "license": "MIT",
+      "dependencies": {
+        "no-case": "^3.0.4",
+        "tslib": "^2.0.3"
+      }
+    },
+    "node_modules/drbg.js": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz",
+      "integrity": "sha512-F4wZ06PvqxYLFEZKkFxTDcns9oFNk34hvmJSEwdzsxVQ8YI5YaxtACgQatkYgv2VI2CFkUd2Y+xosPQnHv809g==",
+      "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",
+      "resolved": "https://registry.npmjs.org/eccrypto/-/eccrypto-1.1.6.tgz",
+      "integrity": "sha512-d78ivVEzu7Tn0ZphUUaL43+jVPKTMPFGtmgtz1D0LrFn7cY3K8CdrvibuLz2AAkHBLKZtR8DMbB2ukRYFk987A==",
+      "hasInstallScript": true,
+      "license": "CC0-1.0",
+      "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/bn.js": {
+      "version": "4.12.0",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+      "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/eccrypto/node_modules/nan": {
+      "version": "2.14.0",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
+      "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
+      "license": "MIT"
+    },
+    "node_modules/eccrypto/node_modules/secp256k1": {
+      "version": "3.7.1",
+      "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.7.1.tgz",
+      "integrity": "sha512-1cf8sbnRreXrQFdH6qsg2H71Xw91fCCS9Yp021GnUNJzWJS/py96fS4lHbnTnouLp08Xj6jBoBB6V78Tdbdu5g==",
+      "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/eccrypto/node_modules/secp256k1/node_modules/nan": {
+      "version": "2.17.0",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz",
+      "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/elliptic": {
+      "version": "6.5.4",
+      "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
+      "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
+      "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",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+      "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+      "license": "MIT"
+    },
+    "node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "license": "MIT"
+    },
+    "node_modules/error-polyfill": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/error-polyfill/-/error-polyfill-0.1.3.tgz",
+      "integrity": "sha512-XHJk60ufE+TG/ydwp4lilOog549iiQF2OAPhkk9DdiYWMrltz5yhDz/xnKuenNwP7gy3dsibssO5QpVhkrSzzg==",
+      "license": "MIT",
+      "dependencies": {
+        "capability": "^0.2.5",
+        "o3": "^1.0.3",
+        "u3": "^0.1.1"
+      }
+    },
+    "node_modules/es6-promise": {
+      "version": "4.2.8",
+      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
+      "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
+      "license": "MIT"
+    },
+    "node_modules/es6-promisify": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
+      "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==",
+      "license": "MIT",
+      "dependencies": {
+        "es6-promise": "^4.0.3"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eth-crypto": {
+      "version": "2.6.0",
+      "resolved": "https://registry.npmjs.org/eth-crypto/-/eth-crypto-2.6.0.tgz",
+      "integrity": "sha512-GCX4ffFYRUGgnuWR5qxcZIRQJ1KEqPFiyXU9yVy7s6dtXIMlUXZQ2h+5ID6rFaOHWbpJbjfkC6YdhwtwRYCnug==",
+      "license": "MIT",
+      "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/@babel/runtime": {
+      "version": "7.20.13",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz",
+      "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==",
+      "license": "MIT",
+      "dependencies": {
+        "regenerator-runtime": "^0.13.11"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/eth-crypto/node_modules/node-addon-api": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz",
+      "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==",
+      "license": "MIT"
+    },
+    "node_modules/eth-crypto/node_modules/secp256k1": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-5.0.0.tgz",
+      "integrity": "sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "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-cryptography": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz",
+      "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==",
+      "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",
+      "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz",
+      "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==",
+      "license": "MIT",
+      "dependencies": {
+        "bn.js": "^4.11.8",
+        "ethereumjs-util": "^6.0.0"
+      }
+    },
+    "node_modules/ethereumjs-abi/node_modules/@types/bn.js": {
+      "version": "4.11.6",
+      "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz",
+      "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/ethereumjs-abi/node_modules/bn.js": {
+      "version": "4.12.0",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+      "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+      "license": "MIT"
+    },
+    "node_modules/ethereumjs-abi/node_modules/ethereumjs-util": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz",
+      "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==",
+      "license": "MPL-2.0",
+      "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",
+      "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz",
+      "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==",
+      "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",
+      "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz",
+      "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==",
+      "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-util": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz",
+      "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==",
+      "license": "MIT",
+      "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",
+      "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+      "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+      "license": "MIT"
+    },
+    "node_modules/evp_bytestokey": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+      "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
+      "license": "MIT",
+      "dependencies": {
+        "md5.js": "^1.3.4",
+        "safe-buffer": "^5.1.1"
+      }
+    },
+    "node_modules/eyes": {
+      "version": "0.1.8",
+      "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz",
+      "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==",
+      "engines": {
+        "node": "> 0.1.90"
+      }
+    },
+    "node_modules/fast-stable-stringify": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz",
+      "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==",
+      "license": "MIT"
+    },
+    "node_modules/file-uri-to-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+      "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+      "license": "MIT"
+    },
+    "node_modules/fill-range": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "license": "MIT",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/find-up": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+      "license": "MIT",
+      "dependencies": {
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/flat": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+      "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+      "license": "BSD-3-Clause",
+      "bin": {
+        "flat": "cli.js"
+      }
+    },
+    "node_modules/follow-redirects": {
+      "version": "1.15.2",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
+      "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
+      "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",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+      "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",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+      "license": "ISC"
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+      "license": "MIT"
+    },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "license": "ISC",
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
+    "node_modules/get-func-name": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
+      "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==",
+      "license": "MIT",
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/get-intrinsic": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
+      "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
+      "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/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "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/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/globalthis": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz",
+      "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==",
+      "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",
+      "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz",
+      "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==",
+      "license": "(BSD-3-Clause AND Apache-2.0)"
+    },
+    "node_modules/graphql": {
+      "version": "16.6.0",
+      "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz",
+      "integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==",
+      "license": "MIT",
+      "engines": {
+        "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
+      }
+    },
+    "node_modules/graphql-tag": {
+      "version": "2.12.6",
+      "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz",
+      "integrity": "sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==",
+      "license": "MIT",
+      "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",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "license": "MIT",
+      "dependencies": {
+        "function-bind": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/has-property-descriptors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
+      "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
+      "license": "MIT",
+      "dependencies": {
+        "get-intrinsic": "^1.1.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/hash-base": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
+      "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
+      "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",
+      "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
+      "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
+      "license": "MIT",
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "minimalistic-assert": "^1.0.1"
+      }
+    },
+    "node_modules/he": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+      "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+      "license": "MIT",
+      "bin": {
+        "he": "bin/he"
+      }
+    },
+    "node_modules/hi-base32": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/hi-base32/-/hi-base32-0.5.1.tgz",
+      "integrity": "sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA==",
+      "license": "MIT"
+    },
+    "node_modules/hmac-drbg": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
+      "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==",
+      "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",
+      "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+      "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "react-is": "^16.7.0"
+      }
+    },
+    "node_modules/http-errors": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
+      "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
+      "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-errors/node_modules/depd": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+      "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/http-status-codes": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.2.0.tgz",
+      "integrity": "sha512-feERVo9iWxvnejp3SEfm/+oNG517npqL2/PIA8ORjyOZjGC7TwCRQsZylciLS64i6pJ0wRYz3rkXLRwbtFa8Ng==",
+      "license": "MIT"
+    },
+    "node_modules/humanize-ms": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
+      "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.0.0"
+      }
+    },
+    "node_modules/ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+      "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/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "license": "ISC",
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "license": "ISC"
+    },
+    "node_modules/interpret": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
+      "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "license": "MIT",
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-core-module": {
+      "version": "2.11.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
+      "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
+      "license": "MIT",
+      "dependencies": {
+        "has": "^1.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "license": "MIT",
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-hex-prefixed": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz",
+      "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.5.0",
+        "npm": ">=3"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/is-plain-obj": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+      "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-unicode-supported": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+      "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/isarray": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+      "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==",
+      "license": "MIT"
+    },
+    "node_modules/isomorphic-ws": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz",
+      "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==",
+      "license": "MIT",
+      "peerDependencies": {
+        "ws": "*"
+      }
+    },
+    "node_modules/jayson": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.0.0.tgz",
+      "integrity": "sha512-v2RNpDCMu45fnLzSk47vx7I+QUaOsox6f5X0CUlabAFwxoP+8MfAY0NQRFwOEYXIxm8Ih5y6OaEa5KYiQMkyAA==",
+      "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/jayson/node_modules/@types/node": {
+      "version": "12.20.55",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz",
+      "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==",
+      "license": "MIT"
+    },
+    "node_modules/js-base64": {
+      "version": "3.7.5",
+      "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.5.tgz",
+      "integrity": "sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/js-sha256": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz",
+      "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==",
+      "license": "MIT"
+    },
+    "node_modules/js-sha3": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
+      "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==",
+      "license": "MIT"
+    },
+    "node_modules/js-sha512": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/js-sha512/-/js-sha512-0.8.0.tgz",
+      "integrity": "sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==",
+      "license": "MIT"
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "license": "MIT"
+    },
+    "node_modules/js-yaml": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+      "license": "MIT",
+      "dependencies": {
+        "argparse": "^2.0.1"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/jscrypto": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/jscrypto/-/jscrypto-1.0.3.tgz",
+      "integrity": "sha512-lryZl0flhodv4SZHOqyb1bx5sKcJxj0VBo0Kzb4QMAg3L021IC9uGpl0RCZa+9KJwlRGSK2C80ITcwbe19OKLQ==",
+      "license": "MIT",
+      "bin": {
+        "jscrypto": "bin/cli.js"
+      }
+    },
+    "node_modules/json-bigint": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
+      "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
+      "license": "MIT",
+      "dependencies": {
+        "bignumber.js": "^9.0.0"
+      }
+    },
+    "node_modules/json-stringify-safe": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+      "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
+      "license": "ISC"
+    },
+    "node_modules/json5": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+      "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "minimist": "^1.2.0"
+      },
+      "bin": {
+        "json5": "lib/cli.js"
+      }
+    },
+    "node_modules/jsonparse": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+      "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==",
+      "engines": [
+        "node >= 0.2.0"
+      ],
+      "license": "MIT"
+    },
+    "node_modules/jsonschema": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz",
+      "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==",
+      "license": "MIT",
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/JSONStream": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
+      "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
+      "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.3",
+      "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.3.tgz",
+      "integrity": "sha512-JZrLIAJWuZxKbCilMpNz5Vj7Vtb4scDG3dMXLOsbzBmQGyjwE61BbW7bJkfKKCShXiQZt3T6sBgALRtmd+nZaQ==",
+      "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",
+      "resolved": "https://registry.npmjs.org/keccak256/-/keccak256-1.0.6.tgz",
+      "integrity": "sha512-8GLiM01PkdJVGUhR1e6M/AvWnSqYS0HaERI+K/QtStGDGlSTx2B1zTqZk4Zlqu5TxHJNTxWAdP9Y+WI50OApUw==",
+      "license": "MIT",
+      "dependencies": {
+        "bn.js": "^5.2.0",
+        "buffer": "^6.0.3",
+        "keccak": "^3.0.2"
+      }
+    },
+    "node_modules/libsodium": {
+      "version": "0.7.11",
+      "resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.11.tgz",
+      "integrity": "sha512-WPfJ7sS53I2s4iM58QxY3Inb83/6mjlYgcmZs7DJsvDlnmVUwNinBCi5vBT43P6bHRy01O4zsMU2CoVR6xJ40A==",
+      "license": "ISC"
+    },
+    "node_modules/libsodium-wrappers": {
+      "version": "0.7.11",
+      "resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.11.tgz",
+      "integrity": "sha512-SrcLtXj7BM19vUKtQuyQKiQCRJPgbpauzl3s0rSwD+60wtHqSUuqcoawlMDheCJga85nKOQwxNYQxf/CKAvs6Q==",
+      "license": "ISC",
+      "dependencies": {
+        "libsodium": "^0.7.11"
+      }
+    },
+    "node_modules/link-module-alias": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/link-module-alias/-/link-module-alias-1.2.0.tgz",
+      "integrity": "sha512-ahPjXepbSVKbahTB6LxR//VHm8HPfI+QQygCH+E82spBY4HR5VPJTvlhKBc9F7muVxnS6C1rRfoPOXAbWO/fyw==",
+      "license": "MIT",
+      "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",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/link-module-alias/node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "license": "MIT",
+      "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",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/link-module-alias/node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+      "license": "MIT"
+    },
+    "node_modules/link-module-alias/node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/link-module-alias/node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/link-module-alias/node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/locate-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+      "license": "MIT",
+      "dependencies": {
+        "p-locate": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+      "license": "MIT"
+    },
+    "node_modules/lodash.values": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/lodash.values/-/lodash.values-4.3.0.tgz",
+      "integrity": "sha512-r0RwvdCv8id9TUblb/O7rYPwVy6lerCbcawrfdo9iC/1t1wsNMJknO79WNBgwkH0hIeJ08jmvvESbFpNb4jH0Q==",
+      "license": "MIT"
+    },
+    "node_modules/log-symbols": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+      "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+      "license": "MIT",
+      "dependencies": {
+        "chalk": "^4.1.0",
+        "is-unicode-supported": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/long": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
+      "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/loose-envify": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+      "license": "MIT",
+      "dependencies": {
+        "js-tokens": "^3.0.0 || ^4.0.0"
+      },
+      "bin": {
+        "loose-envify": "cli.js"
+      }
+    },
+    "node_modules/loupe": {
+      "version": "2.3.6",
+      "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz",
+      "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==",
+      "license": "MIT",
+      "dependencies": {
+        "get-func-name": "^2.0.0"
+      }
+    },
+    "node_modules/lower-case": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
+      "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.0.3"
+      }
+    },
+    "node_modules/make-error": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+      "license": "ISC"
+    },
+    "node_modules/map-obj": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
+      "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/md5.js": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+      "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+      "license": "MIT",
+      "dependencies": {
+        "hash-base": "^3.0.0",
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.1.2"
+      }
+    },
+    "node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "license": "MIT",
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/minimalistic-assert": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+      "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
+      "license": "ISC"
+    },
+    "node_modules/minimalistic-crypto-utils": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
+      "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==",
+      "license": "MIT"
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/mkdirp": {
+      "version": "0.5.6",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+      "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+      "dependencies": {
+        "minimist": "^1.2.6"
+      },
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      }
+    },
+    "node_modules/mocha": {
+      "version": "10.2.0",
+      "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
+      "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
+      "license": "MIT",
+      "dependencies": {
+        "ansi-colors": "4.1.1",
+        "browser-stdout": "1.3.1",
+        "chokidar": "3.5.3",
+        "debug": "4.3.4",
+        "diff": "5.0.0",
+        "escape-string-regexp": "4.0.0",
+        "find-up": "5.0.0",
+        "glob": "7.2.0",
+        "he": "1.2.0",
+        "js-yaml": "4.1.0",
+        "log-symbols": "4.1.0",
+        "minimatch": "5.0.1",
+        "ms": "2.1.3",
+        "nanoid": "3.3.3",
+        "serialize-javascript": "6.0.0",
+        "strip-json-comments": "3.1.1",
+        "supports-color": "8.1.1",
+        "workerpool": "6.2.1",
+        "yargs": "16.2.0",
+        "yargs-parser": "20.2.4",
+        "yargs-unparser": "2.0.0"
+      },
+      "bin": {
+        "_mocha": "bin/_mocha",
+        "mocha": "bin/mocha.js"
+      },
+      "engines": {
+        "node": ">= 14.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/mochajs"
+      }
+    },
+    "node_modules/mocha/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/mocha/node_modules/glob": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+      "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+      "license": "ISC",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/mocha/node_modules/glob/node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/mocha/node_modules/glob/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/mocha/node_modules/minimatch": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
+      "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "license": "MIT"
+    },
+    "node_modules/mustache": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
+      "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==",
+      "license": "MIT",
+      "bin": {
+        "mustache": "bin/mustache"
+      }
+    },
+    "node_modules/nan": {
+      "version": "2.17.0",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz",
+      "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==",
+      "license": "MIT"
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
+      "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
+      "license": "MIT",
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/near-api-js": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/near-api-js/-/near-api-js-1.1.0.tgz",
+      "integrity": "sha512-qYKv1mYsaDZc2uYndhS+ttDhR9+60qFc+ZjD6lWsAxr3ZskMjRwPffDGQZYhC7BRDQMe1HEbk6d5mf+TVm0Lqg==",
+      "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/no-case": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
+      "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
+      "license": "MIT",
+      "dependencies": {
+        "lower-case": "^2.0.2",
+        "tslib": "^2.0.3"
+      }
+    },
+    "node_modules/node-addon-api": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
+      "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==",
+      "license": "MIT"
+    },
+    "node_modules/node-fetch": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz",
+      "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==",
+      "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.6.0",
+      "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz",
+      "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==",
+      "license": "MIT",
+      "bin": {
+        "node-gyp-build": "bin.js",
+        "node-gyp-build-optional": "optional.js",
+        "node-gyp-build-test": "build-test.js"
+      }
+    },
+    "node_modules/noms": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz",
+      "integrity": "sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==",
+      "license": "ISC",
+      "dependencies": {
+        "inherits": "^2.0.1",
+        "readable-stream": "~1.0.31"
+      }
+    },
+    "node_modules/noms/node_modules/readable-stream": {
+      "version": "1.0.34",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+      "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==",
+      "license": "MIT",
+      "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",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+      "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==",
+      "license": "MIT"
+    },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/o3": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/o3/-/o3-1.0.3.tgz",
+      "integrity": "sha512-f+4n+vC6s4ysy7YO7O2gslWZBUu8Qj2i2OUJOvjRxQva7jVjYjB29jrr9NCjmxZQR0gzrOcv1RnqoYOeMs5VRQ==",
+      "license": "MIT",
+      "dependencies": {
+        "capability": "^0.2.5"
+      }
+    },
+    "node_modules/object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-keys": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "license": "ISC",
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/optimism": {
+      "version": "0.16.2",
+      "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.16.2.tgz",
+      "integrity": "sha512-zWNbgWj+3vLEjZNIh/okkY2EUfX+vB9TJopzIZwT1xxaMqC5hRLLraePod4c5n4He08xuXNH+zhKFFCu390wiQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@wry/context": "^0.7.0",
+        "@wry/trie": "^0.3.0"
+      }
+    },
+    "node_modules/p-limit": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+      "license": "MIT",
+      "dependencies": {
+        "yocto-queue": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-locate": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "license": "MIT",
+      "dependencies": {
+        "p-limit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/pako": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
+      "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
+      "license": "(MIT AND Zlib)"
+    },
+    "node_modules/path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+      "license": "MIT"
+    },
+    "node_modules/pathval": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
+      "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
+      "license": "MIT",
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/pbkdf2": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
+      "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
+      "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/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/prettier": {
+      "version": "2.8.7",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz",
+      "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==",
+      "license": "MIT",
+      "bin": {
+        "prettier": "bin-prettier.js"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      },
+      "funding": {
+        "url": "https://github.com/prettier/prettier?sponsor=1"
+      }
+    },
+    "node_modules/process-nextick-args": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+      "license": "MIT"
+    },
+    "node_modules/prop-types": {
+      "version": "15.8.1",
+      "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+      "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+      "license": "MIT",
+      "dependencies": {
+        "loose-envify": "^1.4.0",
+        "object-assign": "^4.1.1",
+        "react-is": "^16.13.1"
+      }
+    },
+    "node_modules/protobufjs": {
+      "version": "6.11.3",
+      "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz",
+      "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==",
+      "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",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "^5.1.0"
+      }
+    },
+    "node_modules/react-is": {
+      "version": "16.13.1",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+      "license": "MIT"
+    },
+    "node_modules/readable-stream": {
+      "version": "3.6.2",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+      "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+      "license": "MIT",
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "license": "MIT",
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
+    "node_modules/readonly-date": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/readonly-date/-/readonly-date-1.0.0.tgz",
+      "integrity": "sha512-tMKIV7hlk0h4mO3JTmmVuIlJVXjKk3Sep9Bf5OH0O+758ruuVkUy2J9SttDLm91IEX/WHlXPSpxMGjPj4beMIQ==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/rechoir": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
+      "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==",
+      "dependencies": {
+        "resolve": "^1.1.6"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/regenerator-runtime": {
+      "version": "0.13.11",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+      "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
+      "license": "MIT"
+    },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/resolve": {
+      "version": "1.22.2",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
+      "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
+      "license": "MIT",
+      "dependencies": {
+        "is-core-module": "^2.11.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/response-iterator": {
+      "version": "0.2.6",
+      "resolved": "https://registry.npmjs.org/response-iterator/-/response-iterator-0.2.6.tgz",
+      "integrity": "sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/rimraf": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+      "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",
+      "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
+      "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
+      "license": "MIT",
+      "dependencies": {
+        "hash-base": "^3.0.0",
+        "inherits": "^2.0.1"
+      }
+    },
+    "node_modules/ripemd160-min": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/ripemd160-min/-/ripemd160-min-0.0.6.tgz",
+      "integrity": "sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/rlp": {
+      "version": "2.2.7",
+      "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz",
+      "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==",
+      "license": "MPL-2.0",
+      "dependencies": {
+        "bn.js": "^5.2.0"
+      },
+      "bin": {
+        "rlp": "bin/rlp"
+      }
+    },
+    "node_modules/rpc-websockets": {
+      "version": "7.5.1",
+      "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.5.1.tgz",
+      "integrity": "sha512-kGFkeTsmd37pHPMaHIgN1LVKXMi0JD782v4Ds9ZKtLlwdTKjn+CxM9A9/gLT2LaOuEcEFGL98h1QWQtlOIdW0w==",
+      "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.13.0",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
+      "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
+      "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": "7.8.0",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz",
+      "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "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",
+      "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz",
+      "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==",
+      "license": "MIT"
+    },
+    "node_modules/secp256k1": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz",
+      "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==",
+      "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/serialize-javascript": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
+      "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "randombytes": "^2.1.0"
+      }
+    },
+    "node_modules/setimmediate": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+      "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
+      "license": "MIT"
+    },
+    "node_modules/setprototypeof": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+      "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+      "license": "ISC"
+    },
+    "node_modules/sha.js": {
+      "version": "2.4.11",
+      "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+      "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+      "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",
+      "resolved": "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz",
+      "integrity": "sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==",
+      "license": "MIT",
+      "dependencies": {
+        "buffer": "6.0.3"
+      }
+    },
+    "node_modules/shelljs": {
+      "version": "0.8.5",
+      "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz",
+      "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==",
+      "license": "BSD-3-Clause",
+      "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",
+      "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz",
+      "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==",
+      "license": "MIT",
+      "dependencies": {
+        "minimist": "^1.2.3",
+        "shelljs": "^0.8.5"
+      },
+      "bin": {
+        "shx": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/snake-case": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz",
+      "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==",
+      "license": "MIT",
+      "dependencies": {
+        "dot-case": "^3.0.4",
+        "tslib": "^2.0.3"
+      }
+    },
+    "node_modules/snakecase-keys": {
+      "version": "5.4.5",
+      "resolved": "https://registry.npmjs.org/snakecase-keys/-/snakecase-keys-5.4.5.tgz",
+      "integrity": "sha512-qSQVcgcWk8mQUN1miVGnRMAUye1dbj9+F9PVkR7wZUXNCidQwrl/kOKmoYf+WbH2ju6c9pXnlmbS2he7pb2/9A==",
+      "license": "MIT",
+      "dependencies": {
+        "map-obj": "^4.1.0",
+        "snake-case": "^3.0.4",
+        "type-fest": "^2.5.2"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-support": {
+      "version": "0.5.21",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+      "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
+    "node_modules/statuses": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+      "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/store2": {
+      "version": "2.14.2",
+      "resolved": "https://registry.npmjs.org/store2/-/store2-2.14.2.tgz",
+      "integrity": "sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==",
+      "license": "(MIT OR GPL-3.0)"
+    },
+    "node_modules/string_decoder": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "~5.2.0"
+      }
+    },
+    "node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "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",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-bom": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+      "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/strip-hex-prefix": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz",
+      "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==",
+      "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",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/superstruct": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.3.tgz",
+      "integrity": "sha512-8iTn3oSS8nRGn+C2pgXSKPI3jmpm6FExNazNpjvqS6ZUJQCej3PUXEKM8NjHBOs54ExM+LPW/FBRhymrdcCiSg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+      "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/supports-color?sponsor=1"
+      }
+    },
+    "node_modules/supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/symbol-observable": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz",
+      "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/text-encoding-utf-8": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz",
+      "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg=="
+    },
+    "node_modules/through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+      "license": "MIT"
+    },
+    "node_modules/through2": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+      "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+      "license": "MIT",
+      "dependencies": {
+        "readable-stream": "~2.3.6",
+        "xtend": "~4.0.1"
+      }
+    },
+    "node_modules/through2/node_modules/isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+      "license": "MIT"
+    },
+    "node_modules/through2/node_modules/readable-stream": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+      "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+      "license": "MIT",
+      "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",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "license": "MIT"
+    },
+    "node_modules/through2/node_modules/string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "node_modules/tiny-secp256k1": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.1.6.tgz",
+      "integrity": "sha512-FmqJZGduTyvsr2cF3375fqGHUovSwDi/QytexX1Se4BPuPZpTE5Ftp5fg+EFSuEf3lhZqgCRjEG3ydUQ/aNiwA==",
+      "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",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+      "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+      "license": "MIT"
+    },
+    "node_modules/tmp": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+      "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+      "license": "MIT",
+      "dependencies": {
+        "rimraf": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8.17.0"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "license": "MIT",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/toidentifier": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+      "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/toml": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz",
+      "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==",
+      "license": "MIT"
+    },
+    "node_modules/tr46": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+      "license": "MIT"
+    },
+    "node_modules/ts-invariant": {
+      "version": "0.10.3",
+      "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz",
+      "integrity": "sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ts-mocha": {
+      "version": "10.0.0",
+      "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-10.0.0.tgz",
+      "integrity": "sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw==",
+      "license": "MIT",
+      "dependencies": {
+        "ts-node": "7.0.1"
+      },
+      "bin": {
+        "ts-mocha": "bin/ts-mocha"
+      },
+      "engines": {
+        "node": ">= 6.X.X"
+      },
+      "optionalDependencies": {
+        "tsconfig-paths": "^3.5.0"
+      },
+      "peerDependencies": {
+        "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X"
+      }
+    },
+    "node_modules/ts-mocha/node_modules/diff": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
+      "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
+      "engines": {
+        "node": ">=0.3.1"
+      }
+    },
+    "node_modules/ts-mocha/node_modules/ts-node": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz",
+      "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==",
+      "dependencies": {
+        "arrify": "^1.0.0",
+        "buffer-from": "^1.1.0",
+        "diff": "^3.1.0",
+        "make-error": "^1.1.1",
+        "minimist": "^1.2.0",
+        "mkdirp": "^0.5.1",
+        "source-map-support": "^0.5.6",
+        "yn": "^2.0.0"
+      },
+      "bin": {
+        "ts-node": "dist/bin.js"
+      },
+      "engines": {
+        "node": ">=4.2.0"
+      }
+    },
+    "node_modules/ts-mocha/node_modules/yn": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz",
+      "integrity": "sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/ts-node": {
+      "version": "10.9.1",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
+      "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
+      "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/ts-node/node_modules/acorn": {
+      "version": "8.8.2",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
+      "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/ts-node/node_modules/diff": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+      "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+      "engines": {
+        "node": ">=0.3.1"
+      }
+    },
+    "node_modules/tsconfig-paths": {
+      "version": "3.14.2",
+      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz",
+      "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@types/json5": "^0.0.29",
+        "json5": "^1.0.2",
+        "minimist": "^1.2.6",
+        "strip-bom": "^3.0.0"
+      }
+    },
+    "node_modules/tslib": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+      "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
+      "license": "0BSD"
+    },
+    "node_modules/tweetnacl": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
+      "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
+      "license": "Unlicense"
+    },
+    "node_modules/tweetnacl-util": {
+      "version": "0.15.1",
+      "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz",
+      "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==",
+      "license": "Unlicense"
+    },
+    "node_modules/type-detect": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+      "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/type-fest": {
+      "version": "2.19.0",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
+      "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
+      "license": "(MIT OR CC0-1.0)",
+      "engines": {
+        "node": ">=12.20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/typeforce": {
+      "version": "1.18.0",
+      "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz",
+      "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==",
+      "license": "MIT"
+    },
+    "node_modules/typescript": {
+      "version": "5.0.4",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz",
+      "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==",
+      "license": "Apache-2.0",
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=12.20"
+      }
+    },
+    "node_modules/u3": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/u3/-/u3-0.1.1.tgz",
+      "integrity": "sha512-+J5D5ir763y+Am/QY6hXNRlwljIeRMZMGs0cT6qqZVVzzT3X3nFPXVyPOFRMOR4kupB0T8JnCdpWdp6Q/iXn3w==",
+      "license": "MIT"
+    },
+    "node_modules/untildify": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
+      "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/utf-8-validate": {
+      "version": "5.0.10",
+      "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz",
+      "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "dependencies": {
+        "node-gyp-build": "^4.3.0"
+      },
+      "engines": {
+        "node": ">=6.14.2"
+      }
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+      "license": "MIT"
+    },
+    "node_modules/uuid": {
+      "version": "8.3.2",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+      "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+      "license": "MIT",
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
+    "node_modules/v8-compile-cache-lib": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+      "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg=="
+    },
+    "node_modules/vlq": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/vlq/-/vlq-2.0.4.tgz",
+      "integrity": "sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA==",
+      "license": "MIT"
+    },
+    "node_modules/webidl-conversions": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/whatwg-url": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+      "license": "MIT",
+      "dependencies": {
+        "tr46": "~0.0.3",
+        "webidl-conversions": "^3.0.0"
+      }
+    },
+    "node_modules/wif": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz",
+      "integrity": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==",
+      "license": "MIT",
+      "dependencies": {
+        "bs58check": "<3.0.0"
+      }
+    },
+    "node_modules/workerpool": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
+      "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "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",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+      "license": "ISC"
+    },
+    "node_modules/ws": {
+      "version": "7.5.9",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
+      "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+      "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",
+      "resolved": "https://registry.npmjs.org/xstream/-/xstream-11.14.0.tgz",
+      "integrity": "sha512-1bLb+kKKtKPbgTK6i/BaoAn03g47PpFstlbe1BA+y3pNS/LfvcaghS5BFf9+EE1J+KwSQsEpfJvFN5GqFtiNmw==",
+      "license": "MIT",
+      "dependencies": {
+        "globalthis": "^1.0.1",
+        "symbol-observable": "^2.0.3"
+      }
+    },
+    "node_modules/xstream/node_modules/symbol-observable": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-2.0.3.tgz",
+      "integrity": "sha512-sQV7phh2WCYAn81oAkakC5qjq2Ml0g8ozqz03wOGnx9dDlG1de6yrF+0RAzSJD8fPUow3PTSMf2SAbOGxb93BA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/xtend": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.4"
+      }
+    },
+    "node_modules/y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+      "license": "ISC",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yargs": {
+      "version": "16.2.0",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+      "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+      "license": "MIT",
+      "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/yargs-parser": {
+      "version": "20.2.4",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
+      "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+      "license": "ISC",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yargs-unparser": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
+      "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
+      "license": "MIT",
+      "dependencies": {
+        "camelcase": "^6.0.0",
+        "decamelize": "^4.0.0",
+        "flat": "^5.0.2",
+        "is-plain-obj": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yargs-unparser/node_modules/camelcase": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+      "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/yargs/node_modules/yargs-parser": {
+      "version": "20.2.9",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+      "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+      "license": "ISC",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yn": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+      "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/yocto-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/zen-observable": {
+      "version": "0.8.15",
+      "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz",
+      "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==",
+      "license": "MIT"
+    },
+    "node_modules/zen-observable-ts": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz",
+      "integrity": "sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==",
+      "license": "MIT",
+      "dependencies": {
+        "zen-observable": "0.8.15"
+      }
+    }
+  }
+}

+ 22 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/package.json

@@ -0,0 +1,22 @@
+{
+  "name": "@wormhole-foundation/wormhole-sui-integration-test",
+  "version": "0.0.1",
+  "description": "Wormhole Sui Integration Test",
+  "main": "index.js",
+  "license": "MIT",
+  "dependencies": {
+    "@certusone/wormhole-sdk": "^0.9.12",
+    "@mysten/sui.js": "^0.32.2",
+    "chai": "^4.3.7",
+    "mocha": "^10.2.0",
+    "prettier": "^2.8.7",
+    "ts-mocha": "^10.0.0",
+    "ts-node": "^10.9.1",
+    "typescript": "^5.0.4"
+  },
+  "devDependencies": {
+    "@types/chai": "^4.3.4",
+    "@types/mocha": "^10.0.1",
+    "@types/node": "^18.15.11"
+  }
+}

+ 35 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/run_integration_test.sh

@@ -0,0 +1,35 @@
+#/bin/bash
+
+pgrep -f sui > /dev/null
+if [ $? -eq 0 ]; then
+    echo "sui local validator already running"
+    exit 1;
+fi
+
+TEST_DIR=$(dirname $0)
+SUI_CONFIG=$TEST_DIR/sui_config
+
+### Remove databases generated by localnet
+rm -rf $SUI_CONFIG/*_db
+
+### Start local node
+echo "$(date) :: starting localnet"
+sui start --network.config $SUI_CONFIG/network.yaml > /dev/null 2>&1 &
+sleep 1
+
+echo "$(date) :: deploying wormhole and token bridge"
+cd $TEST_DIR/..
+bash scripts/deploy.sh devnet \
+    -k AGA20wtGcwbcNAG4nwapbQ5wIuXwkYQEWFUoSVAxctHb > deploy.out 2>&1
+cd testing
+
+## run contract tests here
+echo "$(date) :: running tests"
+pnpm exec ts-mocha -t 1000000 $TEST_DIR/js/*.ts
+
+# nuke
+echo "$(date) :: done"
+pkill sui
+
+# remove databases generated by localnet
+rm -rf $SUI_CONFIG/*_db

+ 300 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/scripts/upgrade-token-bridge.ts

@@ -0,0 +1,300 @@
+import * as mock from "@certusone/wormhole-sdk/lib/cjs/mock";
+import {
+  RawSigner,
+  SUI_CLOCK_OBJECT_ID,
+  TransactionBlock,
+  fromB64,
+  normalizeSuiObjectId,
+  JsonRpcProvider,
+  Ed25519Keypair,
+  testnetConnection,
+} from "@mysten/sui.js";
+import { execSync } from "child_process";
+import { resolve } from "path";
+import * as fs from "fs";
+
+const GOVERNANCE_EMITTER =
+  "0000000000000000000000000000000000000000000000000000000000000004";
+
+const TOKEN_BRIDGE_STATE_ID =
+  "0x32422cb2f929b6a4e3f81b4791ea11ac2af896b310f3d9442aa1fe924ce0bab4";
+const WORMHOLE_STATE_ID =
+  "0x69ae41bdef4770895eb4e7aaefee5e4673acc08f6917b4856cf55549c4573ca8";
+
+async function main() {
+  const guardianPrivateKey = process.env.TESTNET_GUARDIAN_PRIVATE_KEY;
+  if (guardianPrivateKey === undefined) {
+    throw new Error("TESTNET_GUARDIAN_PRIVATE_KEY unset in environment");
+  }
+
+  const walletPrivateKey = process.env.TESTNET_WALLET_PRIVATE_KEY;
+  if (walletPrivateKey === undefined) {
+    throw new Error("TESTNET_WALLET_PRIVATE_KEY unset in environment");
+  }
+
+  const provider = new JsonRpcProvider(testnetConnection);
+  const wallet = new RawSigner(
+    Ed25519Keypair.fromSecretKey(
+      Buffer.from(walletPrivateKey, "base64").subarray(1)
+    ),
+    provider
+  );
+
+  const dstTokenBridgePath = resolve(`${__dirname}/../../token_bridge`);
+
+  // Build for digest.
+  const { modules, dependencies, digest } =
+    buildForBytecodeAndDigest(dstTokenBridgePath);
+  console.log("dependencies", dependencies);
+  console.log("digest", digest.toString("hex"));
+
+  // We will use the signed VAA when we execute the upgrade.
+  const guardians = new mock.MockGuardians(0, [guardianPrivateKey]);
+
+  const timestamp = 12345678;
+  const governance = new mock.GovernanceEmitter(GOVERNANCE_EMITTER);
+  const published = governance.publishWormholeUpgradeContract(
+    timestamp,
+    2,
+    "0x" + digest.toString("hex")
+  );
+  const moduleName = Buffer.alloc(32);
+  moduleName.write("TokenBridge", 32 - "TokenBridge".length);
+  published.write(moduleName.toString(), 84 - 33);
+  published.writeUInt16BE(21, 84);
+  published.writeUInt8(2, 83);
+  //message.writeUInt8(1, 83);
+  published.writeUInt16BE(21, published.length - 34);
+
+  const signedVaa = guardians.addSignatures(published, [0]);
+  console.log("Upgrade VAA:", signedVaa.toString("hex"));
+
+  // // And execute upgrade with governance VAA.
+  // const upgradeResults = await upgradeTokenBridge(
+  //   wallet,
+  //   TOKEN_BRIDGE_STATE_ID,
+  //   WORMHOLE_STATE_ID,
+  //   modules,
+  //   dependencies,
+  //   signedVaa
+  // );
+
+  // console.log("tx digest", upgradeResults.digest);
+  // console.log("tx effects", JSON.stringify(upgradeResults.effects!));
+  // console.log("tx events", JSON.stringify(upgradeResults.events!));
+
+  // TODO: grab new package ID from the events above. Do not rely on the RPC
+  // call because it may give you a stale package ID after the upgrade.
+
+  const migrateResults = await migrateTokenBridge(
+    wallet,
+    TOKEN_BRIDGE_STATE_ID,
+    WORMHOLE_STATE_ID,
+    signedVaa
+  );
+  console.log("tx digest", migrateResults.digest);
+  console.log("tx effects", JSON.stringify(migrateResults.effects!));
+  console.log("tx events", JSON.stringify(migrateResults.events!));
+}
+
+main();
+
+// Yeah buddy.
+
+function buildForBytecodeAndDigest(packagePath: string) {
+  const buildOutput: {
+    modules: string[];
+    dependencies: string[];
+    digest: number[];
+  } = JSON.parse(
+    execSync(
+      `sui move build --dump-bytecode-as-base64 -p ${packagePath} 2> /dev/null`,
+      { encoding: "utf-8" }
+    )
+  );
+  return {
+    modules: buildOutput.modules.map((m: string) => Array.from(fromB64(m))),
+    dependencies: buildOutput.dependencies.map((d: string) =>
+      normalizeSuiObjectId(d)
+    ),
+    digest: Buffer.from(buildOutput.digest),
+  };
+}
+
+async function getPackageId(
+  provider: JsonRpcProvider,
+  stateId: string
+): Promise<string> {
+  const state = await provider
+    .getObject({
+      id: stateId,
+      options: {
+        showContent: true,
+      },
+    })
+    .then((result) => {
+      if (result.data?.content?.dataType == "moveObject") {
+        return result.data.content.fields;
+      }
+
+      throw new Error("not move object");
+    });
+
+  if ("upgrade_cap" in state) {
+    return state.upgrade_cap.fields.package;
+  }
+
+  throw new Error("upgrade_cap not found");
+}
+
+async function upgradeTokenBridge(
+  signer: RawSigner,
+  tokenBridgeStateId: string,
+  wormholeStateId: string,
+  modules: number[][],
+  dependencies: string[],
+  signedVaa: Buffer
+) {
+  const tokenBridgePackage = await getPackageId(
+    signer.provider,
+    tokenBridgeStateId
+  );
+  const wormholePackage = await getPackageId(signer.provider, wormholeStateId);
+
+  const tx = new TransactionBlock();
+
+  const [verifiedVaa] = tx.moveCall({
+    target: `${wormholePackage}::vaa::parse_and_verify`,
+    arguments: [
+      tx.object(wormholeStateId),
+      tx.pure(Array.from(signedVaa)),
+      tx.object(SUI_CLOCK_OBJECT_ID),
+    ],
+  });
+  const [decreeTicket] = tx.moveCall({
+    target: `${tokenBridgePackage}::upgrade_contract::authorize_governance`,
+    arguments: [tx.object(tokenBridgeStateId)],
+  });
+  const [decreeReceipt] = tx.moveCall({
+    target: `${wormholePackage}::governance_message::verify_vaa`,
+    arguments: [tx.object(wormholeStateId), verifiedVaa, decreeTicket],
+    typeArguments: [
+      `${tokenBridgePackage}::upgrade_contract::GovernanceWitness`,
+    ],
+  });
+
+  // Authorize upgrade.
+  const [upgradeTicket] = tx.moveCall({
+    target: `${tokenBridgePackage}::upgrade_contract::authorize_upgrade`,
+    arguments: [tx.object(tokenBridgeStateId), decreeReceipt],
+  });
+
+  // Build and generate modules and dependencies for upgrade.
+  const [upgradeReceipt] = tx.upgrade({
+    modules,
+    dependencies,
+    packageId: tokenBridgePackage,
+    ticket: upgradeTicket,
+  });
+
+  // Commit upgrade.
+  tx.moveCall({
+    target: `${tokenBridgePackage}::upgrade_contract::commit_upgrade`,
+    arguments: [tx.object(tokenBridgeStateId), upgradeReceipt],
+  });
+
+  // Cannot auto compute gas budget, so we need to configure it manually.
+  // Gas ~215m.
+  //tx.setGasBudget(1_000_000_000n);
+
+  return signer.signAndExecuteTransactionBlock({
+    transactionBlock: tx,
+    options: {
+      showEffects: true,
+      showEvents: true,
+    },
+  });
+}
+
+async function migrateTokenBridge(
+  signer: RawSigner,
+  tokenBridgeStateId: string,
+  wormholeStateId: string,
+  signedUpgradeVaa: Buffer
+) {
+  const tokenBridgePackage = await getPackageId(
+    signer.provider,
+    tokenBridgeStateId
+  );
+  const wormholePackage = await getPackageId(signer.provider, wormholeStateId);
+
+  const tx = new TransactionBlock();
+
+  const [verifiedVaa] = tx.moveCall({
+    target: `${wormholePackage}::vaa::parse_and_verify`,
+    arguments: [
+      tx.object(wormholeStateId),
+      tx.pure(Array.from(signedUpgradeVaa)),
+      tx.object(SUI_CLOCK_OBJECT_ID),
+    ],
+  });
+  const [decreeTicket] = tx.moveCall({
+    target: `${tokenBridgePackage}::upgrade_contract::authorize_governance`,
+    arguments: [tx.object(tokenBridgeStateId)],
+  });
+  const [decreeReceipt] = tx.moveCall({
+    target: `${wormholePackage}::governance_message::verify_vaa`,
+    arguments: [tx.object(wormholeStateId), verifiedVaa, decreeTicket],
+    typeArguments: [
+      `${tokenBridgePackage}::upgrade_contract::GovernanceWitness`,
+    ],
+  });
+  tx.moveCall({
+    target: `${tokenBridgePackage}::migrate::migrate`,
+    arguments: [tx.object(tokenBridgeStateId), decreeReceipt],
+  });
+
+  return signer.signAndExecuteTransactionBlock({
+    transactionBlock: tx,
+    options: {
+      showEffects: true,
+      showEvents: true,
+    },
+  });
+}
+
+function setUpWormholeDirectory(
+  srcWormholePath: string,
+  dstWormholePath: string
+) {
+  fs.cpSync(srcWormholePath, dstWormholePath, { recursive: true });
+
+  // Remove irrelevant files. This part is not necessary, but is helpful
+  // for debugging a clean package directory.
+  const removeThese = [
+    "Move.devnet.toml",
+    "Move.lock",
+    "Makefile",
+    "README.md",
+    "build",
+  ];
+  for (const basename of removeThese) {
+    fs.rmSync(`${dstWormholePath}/${basename}`, {
+      recursive: true,
+      force: true,
+    });
+  }
+
+  // Fix Move.toml file.
+  const moveTomlPath = `${dstWormholePath}/Move.toml`;
+  const moveToml = fs.readFileSync(moveTomlPath, "utf-8");
+  fs.writeFileSync(
+    moveTomlPath,
+    moveToml.replace(`wormhole = "_"`, `wormhole = "0x0"`),
+    "utf-8"
+  );
+}
+
+function cleanUpPackageDirectory(packagePath: string) {
+  fs.rmSync(packagePath, { recursive: true, force: true });
+}

+ 267 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/scripts/upgrade-wormhole.ts

@@ -0,0 +1,267 @@
+import * as mock from "@certusone/wormhole-sdk/lib/cjs/mock";
+import {
+  RawSigner,
+  SUI_CLOCK_OBJECT_ID,
+  TransactionBlock,
+  fromB64,
+  normalizeSuiObjectId,
+  JsonRpcProvider,
+  Ed25519Keypair,
+  testnetConnection,
+} from "@mysten/sui.js";
+import { execSync } from "child_process";
+import { resolve } from "path";
+import * as fs from "fs";
+
+const GOVERNANCE_EMITTER =
+  "0000000000000000000000000000000000000000000000000000000000000004";
+
+const WORMHOLE_STATE_ID =
+  "0x69ae41bdef4770895eb4e7aaefee5e4673acc08f6917b4856cf55549c4573ca8";
+
+async function main() {
+  const guardianPrivateKey = process.env.TESTNET_GUARDIAN_PRIVATE_KEY;
+  if (guardianPrivateKey === undefined) {
+    throw new Error("TESTNET_GUARDIAN_PRIVATE_KEY unset in environment");
+  }
+
+  const walletPrivateKey = process.env.TESTNET_WALLET_PRIVATE_KEY;
+  if (walletPrivateKey === undefined) {
+    throw new Error("TESTNET_WALLET_PRIVATE_KEY unset in environment");
+  }
+
+  const provider = new JsonRpcProvider(testnetConnection);
+  const wallet = new RawSigner(
+    Ed25519Keypair.fromSecretKey(
+      Buffer.from(walletPrivateKey, "base64").subarray(1)
+    ),
+    provider
+  );
+
+  const srcWormholePath = resolve(`${__dirname}/../../wormhole`);
+  const dstWormholePath = resolve(`${__dirname}/wormhole`);
+
+  // Stage build(s).
+  setUpWormholeDirectory(srcWormholePath, dstWormholePath);
+
+  // Build for digest.
+  const { modules, dependencies, digest } =
+    buildForBytecodeAndDigest(dstWormholePath);
+
+  // We will use the signed VAA when we execute the upgrade.
+  const guardians = new mock.MockGuardians(0, [guardianPrivateKey]);
+
+  const timestamp = 12345678;
+  const governance = new mock.GovernanceEmitter(GOVERNANCE_EMITTER);
+  const published = governance.publishWormholeUpgradeContract(
+    timestamp,
+    2,
+    "0x" + digest.toString("hex")
+  );
+  published.writeUInt16BE(21, published.length - 34);
+
+  const signedVaa = guardians.addSignatures(published, [0]);
+  console.log("Upgrade VAA:", signedVaa.toString("hex"));
+
+  // And execute upgrade with governance VAA.
+  const upgradeResults = await buildAndUpgradeWormhole(
+    wallet,
+    WORMHOLE_STATE_ID,
+    modules,
+    dependencies,
+    signedVaa
+  );
+
+  console.log("tx digest", upgradeResults.digest);
+  console.log("tx effects", JSON.stringify(upgradeResults.effects!));
+  console.log("tx events", JSON.stringify(upgradeResults.events!));
+
+  // TODO: grab new package ID from the events above. Do not rely on the RPC
+  // call because it may give you a stale package ID after the upgrade.
+
+  // const migrateResults = await migrateWormhole(
+  //   wallet,
+  //   WORMHOLE_STATE_ID,
+  //   signedVaa
+  // );
+  // console.log("tx digest", migrateResults.digest);
+  // console.log("tx effects", JSON.stringify(migrateResults.effects!));
+  // console.log("tx events", JSON.stringify(migrateResults.events!));
+
+  // Clean up.
+  cleanUpPackageDirectory(dstWormholePath);
+}
+
+main();
+
+// Yeah buddy.
+
+function buildForBytecodeAndDigest(packagePath: string) {
+  const buildOutput: {
+    modules: string[];
+    dependencies: string[];
+    digest: number[];
+  } = JSON.parse(
+    execSync(
+      `sui move build --dump-bytecode-as-base64 -p ${packagePath} 2> /dev/null`,
+      { encoding: "utf-8" }
+    )
+  );
+  return {
+    modules: buildOutput.modules.map((m: string) => Array.from(fromB64(m))),
+    dependencies: buildOutput.dependencies.map((d: string) =>
+      normalizeSuiObjectId(d)
+    ),
+    digest: Buffer.from(buildOutput.digest),
+  };
+}
+
+async function getPackageId(
+  provider: JsonRpcProvider,
+  stateId: string
+): Promise<string> {
+  const state = await provider
+    .getObject({
+      id: stateId,
+      options: {
+        showContent: true,
+      },
+    })
+    .then((result) => {
+      if (result.data?.content?.dataType == "moveObject") {
+        return result.data.content.fields;
+      }
+
+      throw new Error("not move object");
+    });
+
+  if ("upgrade_cap" in state) {
+    return state.upgrade_cap.fields.package;
+  }
+
+  throw new Error("upgrade_cap not found");
+}
+
+async function buildAndUpgradeWormhole(
+  signer: RawSigner,
+  wormholeStateId: string,
+  modules: number[][],
+  dependencies: string[],
+  signedVaa: Buffer
+) {
+  const wormholePackage = await getPackageId(signer.provider, wormholeStateId);
+
+  const tx = new TransactionBlock();
+
+  const [verifiedVaa] = tx.moveCall({
+    target: `${wormholePackage}::vaa::parse_and_verify`,
+    arguments: [
+      tx.object(wormholeStateId),
+      tx.pure(Array.from(signedVaa)),
+      tx.object(SUI_CLOCK_OBJECT_ID),
+    ],
+  });
+  const [decreeTicket] = tx.moveCall({
+    target: `${wormholePackage}::upgrade_contract::authorize_governance`,
+    arguments: [tx.object(wormholeStateId)],
+  });
+  const [decreeReceipt] = tx.moveCall({
+    target: `${wormholePackage}::governance_message::verify_vaa`,
+    arguments: [tx.object(wormholeStateId), verifiedVaa, decreeTicket],
+    typeArguments: [`${wormholePackage}::upgrade_contract::GovernanceWitness`],
+  });
+
+  // Authorize upgrade.
+  const [upgradeTicket] = tx.moveCall({
+    target: `${wormholePackage}::upgrade_contract::authorize_upgrade`,
+    arguments: [tx.object(wormholeStateId), decreeReceipt],
+  });
+
+  // Build and generate modules and dependencies for upgrade.
+  const [upgradeReceipt] = tx.upgrade({
+    modules,
+    dependencies,
+    packageId: wormholePackage,
+    ticket: upgradeTicket,
+  });
+
+  // Commit upgrade.
+  tx.moveCall({
+    target: `${wormholePackage}::upgrade_contract::commit_upgrade`,
+    arguments: [tx.object(wormholeStateId), upgradeReceipt],
+  });
+
+  // Cannot auto compute gas budget, so we need to configure it manually.
+  // Gas ~215m.
+  //tx.setGasBudget(1_000_000_000n);
+
+  return signer.signAndExecuteTransactionBlock({
+    transactionBlock: tx,
+    options: {
+      showEffects: true,
+      showEvents: true,
+    },
+  });
+}
+
+async function migrateWormhole(
+  signer: RawSigner,
+  wormholeStateId: string,
+  signedUpgradeVaa: Buffer
+) {
+  const contractPackage = await getPackageId(signer.provider, wormholeStateId);
+
+  const tx = new TransactionBlock();
+  tx.moveCall({
+    target: `${contractPackage}::migrate::migrate`,
+    arguments: [
+      tx.object(wormholeStateId),
+      tx.pure(Array.from(signedUpgradeVaa)),
+      tx.object(SUI_CLOCK_OBJECT_ID),
+    ],
+  });
+
+  return signer.signAndExecuteTransactionBlock({
+    transactionBlock: tx,
+    options: {
+      showEffects: true,
+      showEvents: true,
+    },
+  });
+}
+
+function setUpWormholeDirectory(
+  srcWormholePath: string,
+  dstWormholePath: string
+) {
+  fs.cpSync(srcWormholePath, dstWormholePath, { recursive: true });
+
+  // Remove irrelevant files. This part is not necessary, but is helpful
+  // for debugging a clean package directory.
+  const removeThese = [
+    "Move.devnet.toml",
+    "Move.lock",
+    "Makefile",
+    "README.md",
+    "build",
+  ];
+  for (const basename of removeThese) {
+    fs.rmSync(`${dstWormholePath}/${basename}`, {
+      recursive: true,
+      force: true,
+    });
+  }
+
+  // Fix Move.toml file.
+  const moveTomlPath = `${dstWormholePath}/Move.toml`;
+  const moveToml = fs.readFileSync(moveTomlPath, "utf-8");
+  fs.writeFileSync(
+    moveTomlPath,
+    moveToml.replace(`wormhole = "_"`, `wormhole = "0x0"`),
+    "utf-8"
+  );
+}
+
+function cleanUpPackageDirectory(packagePath: string) {
+  fs.rmSync(packagePath, { recursive: true, force: true });
+}

+ 12 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/sui_config/client.yaml

@@ -0,0 +1,12 @@
+---
+keystore:
+  File: sui_config/sui.keystore
+envs:
+  - alias: localnet
+    rpc: "http://0.0.0.0:9000"
+    ws: ~
+  - alias: devnet
+    rpc: "https://fullnode.devnet.sui.io:443"
+    ws: ~
+active_env: localnet
+active_address: "0xed867315e3f7c83ae82e6d5858b6a6cc57c291fd84f7509646ebc8162169cf96"

+ 53 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/sui_config/fullnode.yaml

@@ -0,0 +1,53 @@
+---
+protocol-key-pair:
+  value: W+hPTVWhdFgzHs3YuRHV6gLfgFhHA1WG0pisIXiN8E8=
+worker-key-pair:
+  value: AApEvpZE1O+2GMqZ1AbRE3+Kmgr1O5mdsMZ6I/gLpVSy
+account-key-pair:
+  value: AN7ZHgjN8G7Nw7Q8NtY9TisPBjmEYpdUzbczjqR98XLh
+network-key-pair:
+  value: AAnB6/zZooq4xDtB7oM/GeTSCh5tBxKAyJwWOMPlEJ4R
+db-path: sui_config/authorities_db/full_node_db
+network-address: /ip4/127.0.0.1/tcp/36683/http
+json-rpc-address: "0.0.0.0:9000"
+metrics-address: "127.0.0.1:35915"
+admin-interface-port: 44319
+enable-event-processing: true
+enable-index-processing: true
+grpc-load-shed: ~
+grpc-concurrency-limit: ~
+p2p-config:
+  listen-address: "127.0.0.1:38187"
+  external-address: /ip4/127.0.0.1/udp/38187
+  seed-peers:
+    - peer-id: ce60e3077e02a3683436af450f3a4511b4c40b158956637caf9ccf11391e7e10
+      address: /ip4/127.0.0.1/udp/44061
+    - peer-id: 5f0f42cb3fb20dd577703388320964f9351d997313c04a032247060d214b2e71
+      address: /ip4/127.0.0.1/udp/46335
+    - peer-id: 6d9095130b1536c0c9218ea9feb0f36685a6fa0b3b1e67d256cc4fb340a48d69
+      address: /ip4/127.0.0.1/udp/32965
+    - peer-id: b2915bf787845a55c24e18fdc162a575eb02d23bae3f9e566d7c51ebcfeb4a42
+      address: /ip4/127.0.0.1/udp/39889
+genesis:
+  genesis-file-location: sui_config/genesis.blob
+authority-store-pruning-config:
+  num-latest-epoch-dbs-to-retain: 3
+  epoch-db-pruning-period-secs: 3600
+  num-epochs-to-retain: 2
+  max-checkpoints-in-batch: 200
+  max-transactions-in-batch: 1000
+  use-range-deletion: true
+end-of-epoch-broadcast-channel-capacity: 128
+checkpoint-executor-config:
+  checkpoint-execution-max-concurrency: 200
+  local-execution-timeout-sec: 30
+db-checkpoint-config:
+  perform-db-checkpoints-at-epoch-end: false
+indirect-objects-threshold: 18446744073709551615
+expensive-safety-check-config:
+  enable-epoch-sui-conservation-check: false
+  enable-deep-per-tx-sui-conservation-check: false
+  force-disable-epoch-sui-conservation-check: false
+  enable-state-consistency-check: false
+  force-disable-state-consistency-check: false
+  enable-move-vm-paranoid-checks: false

二进制
target_chains/sui/vendor/wormhole_iota_testnet/testing/sui_config/genesis.blob


文件差异内容过多而无法显示
+ 323 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/sui_config/network.yaml


+ 7 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/sui_config/sui.keystore

@@ -0,0 +1,7 @@
+[
+  "AB522qKKEsXMTFRD2SG3Het/02S/ZBOugmcH3R1CDG6l",
+  "AOmPq9B16F3W3ijO/4s9hI6v8LdiYCawKAW31PKpg4Qp",
+  "AOLhc0ryVWnD5LmqH3kCHruBpVV+68EWjEGu2eC9gndK",
+  "AKCo1FyhQ0zUpnoZLmGJJ+8LttTrt56W87Ho4vBF+R+8",
+  "AGA20wtGcwbcNAG4nwapbQ5wIuXwkYQEWFUoSVAxctHb"
+]

+ 81 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/sui_config/validator-config-0.yaml

@@ -0,0 +1,81 @@
+---
+protocol-key-pair:
+  value: VTDx4HjVmRBqdqBWg2zN+zcFE20io3CrBchGy/iV1lo=
+worker-key-pair:
+  value: ABlC9PMmIQHjxila3AEOXDxwCSuodcvJh2Q5O5HIB00K
+account-key-pair:
+  value: AIV4Ng6OYQf6irjVCZly5X7dSpdFpwoWtdAx9u4PANRl
+network-key-pair:
+  value: AOqJl2rHMnroe26vjkkIuWGBD/y6HzQG6MK5bC9njF0s
+db-path: sui_config/authorities_db/99f25ef61f80
+network-address: /ip4/127.0.0.1/tcp/36459/http
+json-rpc-address: "127.0.0.1:38133"
+metrics-address: "127.0.0.1:44135"
+admin-interface-port: 33917
+consensus-config:
+  address: /ip4/127.0.0.1/tcp/41459/http
+  db-path: sui_config/consensus_db/99f25ef61f80
+  internal-worker-address: ~
+  max-pending-transactions: ~
+  narwhal-config:
+    header_num_of_batches_threshold: 32
+    max_header_num_of_batches: 1000
+    max_header_delay: 2000ms
+    min_header_delay: 500ms
+    gc_depth: 50
+    sync_retry_delay: 5000ms
+    sync_retry_nodes: 3
+    batch_size: 500000
+    max_batch_delay: 100ms
+    block_synchronizer:
+      range_synchronize_timeout: 30000ms
+      certificates_synchronize_timeout: 30000ms
+      payload_synchronize_timeout: 30000ms
+      payload_availability_timeout: 30000ms
+      handler_certificate_deliver_timeout: 30000ms
+    consensus_api_grpc:
+      socket_addr: /ip4/127.0.0.1/tcp/44689/http
+      get_collections_timeout: 5000ms
+      remove_collections_timeout: 5000ms
+    max_concurrent_requests: 500000
+    prometheus_metrics:
+      socket_addr: /ip4/127.0.0.1/tcp/33219/http
+    network_admin_server:
+      primary_network_admin_server_port: 33945
+      worker_network_admin_server_base_port: 38081
+    anemo:
+      send_certificate_rate_limit: ~
+      get_payload_availability_rate_limit: ~
+      get_certificates_rate_limit: ~
+      report_batch_rate_limit: ~
+      request_batch_rate_limit: ~
+enable-event-processing: false
+enable-index-processing: true
+grpc-load-shed: ~
+grpc-concurrency-limit: 20000000000
+p2p-config:
+  listen-address: "127.0.0.1:44061"
+  external-address: /ip4/127.0.0.1/udp/44061
+genesis:
+  genesis-file-location: sui_config/genesis.blob
+authority-store-pruning-config:
+  num-latest-epoch-dbs-to-retain: 3
+  epoch-db-pruning-period-secs: 3600
+  num-epochs-to-retain: 2
+  max-checkpoints-in-batch: 200
+  max-transactions-in-batch: 1000
+  use-range-deletion: true
+end-of-epoch-broadcast-channel-capacity: 128
+checkpoint-executor-config:
+  checkpoint-execution-max-concurrency: 200
+  local-execution-timeout-sec: 30
+db-checkpoint-config:
+  perform-db-checkpoints-at-epoch-end: false
+indirect-objects-threshold: 18446744073709551615
+expensive-safety-check-config:
+  enable-epoch-sui-conservation-check: false
+  enable-deep-per-tx-sui-conservation-check: false
+  force-disable-epoch-sui-conservation-check: false
+  enable-state-consistency-check: false
+  force-disable-state-consistency-check: false
+  enable-move-vm-paranoid-checks: false

+ 81 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/sui_config/validator-config-1.yaml

@@ -0,0 +1,81 @@
+---
+protocol-key-pair:
+  value: avYcyVgYMXTyaUYh9IRwLK0gSzl7YF6ZQDAbrS1Bhvo=
+worker-key-pair:
+  value: AGsxCVxeIZ6fscvGECzV93Hi4JkqM4zMYEA8wBGfXQrz
+account-key-pair:
+  value: AF9cOMxTRAUTOws2M8W5slHf41HITA+M3nqXHT6nlH6S
+network-key-pair:
+  value: ALH/8qz2YlwAuxY/hOvuXiglYq0e4LLU1/lyf5uKgPY8
+db-path: sui_config/authorities_db/8dcff6d15504
+network-address: /ip4/127.0.0.1/tcp/33355/http
+json-rpc-address: "127.0.0.1:39573"
+metrics-address: "127.0.0.1:45851"
+admin-interface-port: 35739
+consensus-config:
+  address: /ip4/127.0.0.1/tcp/42959/http
+  db-path: sui_config/consensus_db/8dcff6d15504
+  internal-worker-address: ~
+  max-pending-transactions: ~
+  narwhal-config:
+    header_num_of_batches_threshold: 32
+    max_header_num_of_batches: 1000
+    max_header_delay: 2000ms
+    min_header_delay: 500ms
+    gc_depth: 50
+    sync_retry_delay: 5000ms
+    sync_retry_nodes: 3
+    batch_size: 500000
+    max_batch_delay: 100ms
+    block_synchronizer:
+      range_synchronize_timeout: 30000ms
+      certificates_synchronize_timeout: 30000ms
+      payload_synchronize_timeout: 30000ms
+      payload_availability_timeout: 30000ms
+      handler_certificate_deliver_timeout: 30000ms
+    consensus_api_grpc:
+      socket_addr: /ip4/127.0.0.1/tcp/37001/http
+      get_collections_timeout: 5000ms
+      remove_collections_timeout: 5000ms
+    max_concurrent_requests: 500000
+    prometheus_metrics:
+      socket_addr: /ip4/127.0.0.1/tcp/39831/http
+    network_admin_server:
+      primary_network_admin_server_port: 39853
+      worker_network_admin_server_base_port: 36429
+    anemo:
+      send_certificate_rate_limit: ~
+      get_payload_availability_rate_limit: ~
+      get_certificates_rate_limit: ~
+      report_batch_rate_limit: ~
+      request_batch_rate_limit: ~
+enable-event-processing: false
+enable-index-processing: true
+grpc-load-shed: ~
+grpc-concurrency-limit: 20000000000
+p2p-config:
+  listen-address: "127.0.0.1:46335"
+  external-address: /ip4/127.0.0.1/udp/46335
+genesis:
+  genesis-file-location: sui_config/genesis.blob
+authority-store-pruning-config:
+  num-latest-epoch-dbs-to-retain: 3
+  epoch-db-pruning-period-secs: 3600
+  num-epochs-to-retain: 2
+  max-checkpoints-in-batch: 200
+  max-transactions-in-batch: 1000
+  use-range-deletion: true
+end-of-epoch-broadcast-channel-capacity: 128
+checkpoint-executor-config:
+  checkpoint-execution-max-concurrency: 200
+  local-execution-timeout-sec: 30
+db-checkpoint-config:
+  perform-db-checkpoints-at-epoch-end: false
+indirect-objects-threshold: 18446744073709551615
+expensive-safety-check-config:
+  enable-epoch-sui-conservation-check: false
+  enable-deep-per-tx-sui-conservation-check: false
+  force-disable-epoch-sui-conservation-check: false
+  enable-state-consistency-check: false
+  force-disable-state-consistency-check: false
+  enable-move-vm-paranoid-checks: false

+ 81 - 0
target_chains/sui/vendor/wormhole_iota_testnet/testing/sui_config/validator-config-2.yaml

@@ -0,0 +1,81 @@
+---
+protocol-key-pair:
+  value: OXnx3yM1C/ppgnDMx/o1d49fJs7E05kq11mXNae/O+I=
+worker-key-pair:
+  value: AHXs8DP7EccyxtxAGq/m33LgvOApXs4JStH3PLAe9vGw
+account-key-pair:
+  value: AC8vF9E3QYf0aTyBZWlSzJJXETvV5vYkOtEJl+DWQMlk
+network-key-pair:
+  value: AOapcKU6mW5SopFM6eBSiXgbuPJTz11CiEqM+SJGIEOF
+db-path: sui_config/authorities_db/addeef94d898
+network-address: /ip4/127.0.0.1/tcp/34633/http
+json-rpc-address: "127.0.0.1:38025"
+metrics-address: "127.0.0.1:43451"
+admin-interface-port: 36793
+consensus-config:
+  address: /ip4/127.0.0.1/tcp/40307/http
+  db-path: sui_config/consensus_db/addeef94d898
+  internal-worker-address: ~
+  max-pending-transactions: ~
+  narwhal-config:
+    header_num_of_batches_threshold: 32
+    max_header_num_of_batches: 1000
+    max_header_delay: 2000ms
+    min_header_delay: 500ms
+    gc_depth: 50
+    sync_retry_delay: 5000ms
+    sync_retry_nodes: 3
+    batch_size: 500000
+    max_batch_delay: 100ms
+    block_synchronizer:
+      range_synchronize_timeout: 30000ms
+      certificates_synchronize_timeout: 30000ms
+      payload_synchronize_timeout: 30000ms
+      payload_availability_timeout: 30000ms
+      handler_certificate_deliver_timeout: 30000ms
+    consensus_api_grpc:
+      socket_addr: /ip4/127.0.0.1/tcp/37445/http
+      get_collections_timeout: 5000ms
+      remove_collections_timeout: 5000ms
+    max_concurrent_requests: 500000
+    prometheus_metrics:
+      socket_addr: /ip4/127.0.0.1/tcp/43943/http
+    network_admin_server:
+      primary_network_admin_server_port: 39611
+      worker_network_admin_server_base_port: 38377
+    anemo:
+      send_certificate_rate_limit: ~
+      get_payload_availability_rate_limit: ~
+      get_certificates_rate_limit: ~
+      report_batch_rate_limit: ~
+      request_batch_rate_limit: ~
+enable-event-processing: false
+enable-index-processing: true
+grpc-load-shed: ~
+grpc-concurrency-limit: 20000000000
+p2p-config:
+  listen-address: "127.0.0.1:32965"
+  external-address: /ip4/127.0.0.1/udp/32965
+genesis:
+  genesis-file-location: sui_config/genesis.blob
+authority-store-pruning-config:
+  num-latest-epoch-dbs-to-retain: 3
+  epoch-db-pruning-period-secs: 3600
+  num-epochs-to-retain: 2
+  max-checkpoints-in-batch: 200
+  max-transactions-in-batch: 1000
+  use-range-deletion: true
+end-of-epoch-broadcast-channel-capacity: 128
+checkpoint-executor-config:
+  checkpoint-execution-max-concurrency: 200
+  local-execution-timeout-sec: 30
+db-checkpoint-config:
+  perform-db-checkpoints-at-epoch-end: false
+indirect-objects-threshold: 18446744073709551615
+expensive-safety-check-config:
+  enable-epoch-sui-conservation-check: false
+  enable-deep-per-tx-sui-conservation-check: false
+  force-disable-epoch-sui-conservation-check: false
+  enable-state-consistency-check: false
+  force-disable-state-consistency-check: false
+  enable-move-vm-paranoid-checks: false

部分文件因为文件数量过多而无法显示