瀏覽代碼

skeleton of swap adapter

ani 1 年之前
父節點
當前提交
5c4d3e8771

+ 21 - 0
express_relay/swap-beacon/package.json

@@ -0,0 +1,21 @@
+{
+  "name": "swap-beacon",
+  "version": "1.0.0",
+  "description": "",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "keywords": [],
+  "author": "",
+  "license": "ISC",
+  "devDependencies": {
+    "@types/node": "^22.0.0",
+    "typescript": "^5.5.4"
+  },
+  "dependencies": {
+    "@graphprotocol/graph-ts": "^0.35.1",
+    "@pythnetwork/express-relay-evm-js": "^0.8.1",
+    "viem": "^2.18.6"
+  }
+}

+ 34 - 0
express_relay/swap-beacon/src/adapter/kim.ts

@@ -0,0 +1,34 @@
+import { Adapter, Pair, ExtendedTargetCall, TokenToSend } from "../types";
+import { Address, Hex } from "viem";
+import { TokenAmount } from "@pythnetwork/express-relay-evm-js";
+
+export class KimAdapter implements Adapter {
+  chainIds: string[] = ["34443"];
+  getPrice(chainId: string, pair: Pair): Promise<number> {
+    return Promise.resolve(1);
+  }
+  constructSwap(
+    chainId: string,
+    tokenIn: Address,
+    tokenOut: Address,
+    amountIn?: bigint,
+    amountOut?: bigint
+  ): ExtendedTargetCall {
+    // construct the swap calldata manually
+    let targetContract: Address = "0x59F78DE21a0b05d96Ae00c547BA951a3B905602f";
+    let targetCalldata: Hex = "0x";
+    let targetCallValue: bigint = 0n;
+    let tokensToSend: TokenToSend[] = [];
+
+    // TODO: figure out this
+    let tokensToReceive: TokenAmount[] = [];
+
+    return {
+      targetContract,
+      targetCalldata,
+      targetCallValue,
+      tokensToSend,
+      tokensToReceive,
+    };
+  }
+}

+ 9 - 0
express_relay/swap-beacon/src/const.ts

@@ -0,0 +1,9 @@
+import { SwapAdapterConfig } from "./types";
+
+export const SWAP_ADAPTER_CONFIGS: Record<string, SwapAdapterConfig> = {
+  mode: {
+    chainId: 34443,
+    multicallAdapter: "0xabc",
+    liquidAssets: ["0x123", "0x456"],
+  },
+};

+ 165 - 0
express_relay/swap-beacon/src/index.ts

@@ -0,0 +1,165 @@
+import { KimAdapter } from "./adapter/kim";
+import { SWAP_ADAPTER_CONFIGS } from "./const";
+import {
+  Client,
+  Opportunity,
+  OpportunityParams,
+  ChainId,
+  TokenAmount,
+} from "@pythnetwork/express-relay-evm-js";
+import { Adapter, ExtendedTargetCall, TargetCall } from "./types";
+import { Address } from "viem";
+
+export class SwapBeaconError extends Error {}
+
+function getSwapAdapterConfig(chainId: string) {
+  const swapAdapterConfig = SWAP_ADAPTER_CONFIGS[chainId];
+  if (!swapAdapterConfig) {
+    throw new SwapBeaconError(
+      `Opportunity adapter config not found for chain id: ${chainId}`
+    );
+  }
+  return swapAdapterConfig;
+}
+
+export class SwapBeacon {
+  private client: Client;
+  private adapters: Adapter[];
+
+  constructor(public endpoint: string) {
+    this.client = new Client(
+      {
+        baseUrl: endpoint,
+      },
+      undefined,
+      this.opportunityHandler.bind(this)
+    );
+    this.adapters = [new KimAdapter()];
+  }
+
+  private async getOptimalAdapter(
+    chainId: ChainId,
+    tokenIn: Address,
+    tokenOut: Address
+  ) {
+    const pair = {
+      token0: tokenIn,
+      token1: tokenOut,
+    };
+    const prices = await Promise.all(
+      this.adapters.map((adapter) => adapter.getPrice(chainId, pair))
+    );
+
+    return this.adapters[
+      prices.reduce(
+        (prev, curr, currIndex) => (prices[prev] < curr ? currIndex : prev),
+        0
+      )
+    ];
+  }
+
+  private createSwapOpportunity(
+    opportunity: Opportunity,
+    asset: Address,
+    swapsSell: ExtendedTargetCall[],
+    swapsBuy: ExtendedTargetCall[]
+  ): Opportunity {
+    const targetContract =
+      SWAP_ADAPTER_CONFIGS[opportunity.chainId].multicallAdapter;
+    const targetCallValue =
+      swapsSell.reduce((prev, curr) => prev + curr.targetCallValue, 0n) +
+      swapsBuy.reduce((prev, curr) => prev + curr.targetCallValue, 0n) +
+      opportunity.targetCallValue;
+    const targetCalldata = "0x"; // TODO: construct multicall calldata
+
+    // TODO: extract new sellTokens and buyTokens correctly!
+    const sellTokens: TokenAmount[] = [
+      {
+        token: asset,
+        amount: swapsSell.reduce(
+          (prev, curr) =>
+            prev +
+            curr.tokensToSend.reduce(
+              (prev, curr) => prev + curr.tokenAmount.amount,
+              0n
+            ),
+          0n
+        ),
+      },
+    ];
+    const buyTokens: TokenAmount[] = [
+      {
+        token: asset,
+        amount: swapsBuy.reduce(
+          (prev, curr) =>
+            prev +
+            curr.tokensToReceive.reduce((prev, curr) => prev + curr.amount, 0n),
+          0n
+        ),
+      },
+    ];
+
+    return {
+      ...opportunity,
+      targetContract,
+      targetCalldata,
+      targetCallValue,
+      sellTokens,
+      buyTokens,
+    };
+  }
+
+  async convertOpportunity(
+    opportunity: Opportunity,
+    asset: Address
+  ): Promise<Opportunity> {
+    const promisesOptimalAdaptersSell = opportunity.sellTokens.map(
+      (sellToken) =>
+        this.getOptimalAdapter(opportunity.chainId, asset, sellToken.token)
+    );
+    const promisesOptimalAdaptersBuy = opportunity.buyTokens.map((buyToken) =>
+      this.getOptimalAdapter(opportunity.chainId, buyToken.token, asset)
+    );
+
+    const [optimalAdaptersSell, optimalAdaptersBuy] = await Promise.all([
+      Promise.all(promisesOptimalAdaptersSell),
+      Promise.all(promisesOptimalAdaptersBuy),
+    ]);
+
+    const swapsSell = optimalAdaptersSell.map((adapter, index) =>
+      adapter.constructSwap(
+        opportunity.chainId,
+        asset,
+        opportunity.sellTokens[index].token,
+        undefined,
+        opportunity.sellTokens[index].amount
+      )
+    );
+    const swapsBuy = optimalAdaptersBuy.map((adapter, index) =>
+      adapter.constructSwap(
+        opportunity.chainId,
+        opportunity.buyTokens[index].token,
+        asset,
+        opportunity.buyTokens[index].amount,
+        undefined
+      )
+    );
+
+    return this.createSwapOpportunity(opportunity, asset, swapsSell, swapsBuy);
+  }
+
+  async opportunityHandler(opportunity: Opportunity) {
+    // check opportunity
+    const swapAdapterConfig = getSwapAdapterConfig(opportunity.chainId);
+
+    await Promise.all(
+      swapAdapterConfig.liquidAssets.map(async (asset) => {
+        const { opportunityId, ...params } = await this.convertOpportunity(
+          opportunity,
+          asset
+        );
+        await this.client.submitOpportunity(params);
+      })
+    );
+  }
+}

+ 51 - 0
express_relay/swap-beacon/src/types.ts

@@ -0,0 +1,51 @@
+import { Address, Hex } from "viem";
+import { TokenAmount } from "@pythnetwork/express-relay-evm-js";
+
+export type SwapAdapterConfig = {
+  /**
+   * The chain id as a u64
+   */
+  chainId: number;
+  /**
+   * The multicall adapter address
+   */
+  multicallAdapter: Address;
+  /**
+   * List of liquid assets to swap into/from
+   */
+  liquidAssets: Address[];
+};
+
+export type Pair = {
+  token0: Address;
+  token1: Address;
+};
+
+export type TokenToSend = {
+  tokenAmount: TokenAmount;
+  destination: Address;
+};
+
+export type TargetCall = {
+  targetContract: Address;
+  targetCalldata: Hex;
+  targetCallValue: bigint;
+  tokensToSend: TokenToSend[];
+};
+
+// TODO: better name
+export type ExtendedTargetCall = TargetCall & {
+  tokensToReceive: TokenAmount[];
+};
+
+export interface Adapter {
+  chainIds: string[];
+  getPrice: (chainId: string, pair: Pair) => Promise<number>;
+  constructSwap: (
+    chainId: string,
+    tokenIn: Address,
+    tokenOut: Address,
+    amountIn?: bigint,
+    amountOut?: bigint
+  ) => ExtendedTargetCall;
+}

+ 16 - 0
express_relay/swap-beacon/tsconfig.json

@@ -0,0 +1,16 @@
+{
+  "compilerOptions": {
+    "target": "es2020",
+    "lib": ["es6"],
+    "module": "commonjs",
+    "rootDir": "src",
+    "resolveJsonModule": true,
+    "allowJs": true,
+    "outDir": "build",
+    "esModuleInterop": true,
+    "forceConsistentCasingInFileNames": true,
+    "strict": true,
+    "noImplicitAny": true,
+    "skipLibCheck": true
+  }
+}

+ 143 - 15
pnpm-lock.yaml

@@ -4,16 +4,6 @@ settings:
   autoInstallPeers: true
   excludeLinksFromLockfile: false
 
-overrides:
-  '@injectivelabs/sdk-ts@1.10.72>@injectivelabs/token-metadata': 1.10.42
-  eslint-config-next>@typescript-eslint/parser: ^7.0.0
-  '@solana/web3.js@^1.93.0': 1.92.3
-
-patchedDependencies:
-  eccrypto@1.1.6:
-    hash: rjcfmtfgn3z72mudpdif5oxmye
-    path: patches/eccrypto@1.1.6.patch
-
 importers:
 
   .:
@@ -547,6 +537,25 @@ importers:
         specifier: ^1.0.0-rc.1
         version: 1.1.3(prettier@2.8.8)
 
+  express_relay/swaps-beacon:
+    dependencies:
+      '@graphprotocol/graph-ts':
+        specifier: ^0.35.1
+        version: 0.35.1
+      '@pythnetwork/express-relay-evm-js':
+        specifier: ^0.8.1
+        version: 0.8.1(axios@1.7.2)(bufferutil@4.0.8)(js-yaml@4.1.0)(typescript@5.5.4)(utf-8-validate@6.0.4)(zod@3.23.8)
+      viem:
+        specifier: ^2.18.6
+        version: 2.18.6(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@6.0.4)(zod@3.23.8)
+    devDependencies:
+      '@types/node':
+        specifier: ^22.0.0
+        version: 22.0.0
+      typescript:
+        specifier: ^5.5.4
+        version: 5.5.4
+
   governance/xc_admin/packages/crank_executor:
     dependencies:
       '@certusone/wormhole-sdk':
@@ -4007,6 +4016,9 @@ packages:
       graphql: ^15.5.0 || ^16.0.0 || ^17.0.0
       typescript: ^5.0.0
 
+  '@graphprotocol/graph-ts@0.35.1':
+    resolution: {integrity: sha512-74CfuQmf7JI76/XCC34FTkMMKeaf+3Pn0FIV3m9KNeaOJ+OI3CvjMIVRhOZdKcJxsFCBGaCCl0eQjh47xTjxKA==}
+
   '@graphql-tools/batch-execute@8.5.1':
     resolution: {integrity: sha512-hRVDduX0UDEneVyEWtc2nu5H2PxpfSfM/riUlgZvo/a/nG475uyehxR5cFGvTEPEQUKY3vGIlqvtRigzqTfCew==}
     peerDependencies:
@@ -5674,6 +5686,9 @@ packages:
     peerDependencies:
       '@solana/web3.js': 1.92.3
 
+  '@pythnetwork/express-relay-evm-js@0.8.1':
+    resolution: {integrity: sha512-1/cDhqdgjN+UV+HKaHpSPY3y5/+nozw4Fe6QMsIpYTBoDchMx7W052Y2tONfSKaP8fA/kvHmJ9E58er3BdqWXw==}
+
   '@pythnetwork/price-service-client@1.9.0':
     resolution: {integrity: sha512-SLm3IFcfmy9iMqHeT4Ih6qMNZhJEefY14T9yTlpsH2D/FE5+BaGGnfcexUifVlfH6M7mwRC4hEFdNvZ6ebZjJg==}
     deprecated: This package is deprecated and is no longer maintained. Please use @pythnetwork/hermes-client instead.
@@ -7212,6 +7227,9 @@ packages:
   '@types/node@20.14.9':
     resolution: {integrity: sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==}
 
+  '@types/node@22.0.0':
+    resolution: {integrity: sha512-VT7KSYudcPOzP5Q0wfbowyNLaVR8QWUdw+088uFWwfvpY6uCWaXpqV6ieLAu9WBcnTa7H4Z5RLK8I5t2FuOcqw==}
+
   '@types/normalize-package-data@2.4.1':
     resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
 
@@ -7997,6 +8015,17 @@ packages:
       zod:
         optional: true
 
+  abitype@1.0.5:
+    resolution: {integrity: sha512-YzDhti7cjlfaBhHutMaboYB21Ha3rXR9QTkNJFzYC4kC8YclaiwPBBBJY8ejFdu2wnJeZCVZSMlQJ7fi8S6hsw==}
+    peerDependencies:
+      typescript: '>=5.0.4'
+      zod: ^3 >=3.22.0
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+      zod:
+        optional: true
+
   abort-controller@3.0.0:
     resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
     engines: {node: '>=6.5'}
@@ -8408,6 +8437,10 @@ packages:
   asn1@0.2.6:
     resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
 
+  assemblyscript@0.19.10:
+    resolution: {integrity: sha512-HavcUBXB3mBTRGJcpvaQjmnmaqKHBGREjSPNsIvnAk2f9dj78y4BkMaSSdvBQYWcDDzsHQjyUC8stICFkD1Odg==}
+    hasBin: true
+
   assert-plus@1.0.0:
     resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==}
     engines: {node: '>=0.8'}
@@ -8724,6 +8757,10 @@ packages:
     resolution: {integrity: sha512-5ATpz/uPDgq5GgEDxTB4ouXCde7q2lqAQlSdBRQVl/AJnxmQmhIfyxJx+0MGu//D5rHQifkfGbWWlaysG0o9NA==}
     engines: {node: '>=12'}
 
+  binaryen@101.0.0-nightly.20210723:
+    resolution: {integrity: sha512-eioJNqhHlkguVSbblHOtLqlhtC882SOEPKmNFZaDuz1hzQjolxZ+eu3/kaS10n3sGPONsIZsO7R9fR00UyhEUA==}
+    hasBin: true
+
   bindings@1.5.0:
     resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
 
@@ -17009,6 +17046,11 @@ packages:
     engines: {node: '>=14.17'}
     hasBin: true
 
+  typescript@5.5.4:
+    resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==}
+    engines: {node: '>=14.17'}
+    hasBin: true
+
   typical@4.0.0:
     resolution: {integrity: sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==}
     engines: {node: '>=8'}
@@ -17049,6 +17091,9 @@ packages:
   undici-types@5.26.5:
     resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
 
+  undici-types@6.11.1:
+    resolution: {integrity: sha512-mIDEX2ek50x0OlRgxryxsenE5XaQD4on5U2inY7RApK3SOJpofyw7uW2AyfMKkhAxXIceo2DeWGVGwyvng1GNQ==}
+
   undici@5.26.5:
     resolution: {integrity: sha512-cSb4bPFd5qgR7qr2jYAi0hlX9n5YKK2ONKkLFkxl+v/9BvC0sOpZjBHDBSXc5lWAf5ty9oZdRXytBIHzgUcerw==}
     engines: {node: '>=14.0'}
@@ -17396,6 +17441,14 @@ packages:
       typescript:
         optional: true
 
+  viem@2.18.6:
+    resolution: {integrity: sha512-KughUodIEjzkC+KfQ4+259yRXYfo0VLkZQ7NVC3RGfCMMOiVWaOxHjmcaY0FnZzKX3pwrlMyTAZbwH9tVAN/Yw==}
+    peerDependencies:
+      typescript: '>=5.0.4'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
   viem@2.8.13:
     resolution: {integrity: sha512-jEbRUjsiBwmoDr3fnKL1Bh1GhK5ERhmZcPLeARtEaQoBTPB6bcO2siKhNPVOF8qrYRnGHGQrZHncBWMQhTjGYg==}
     peerDependencies:
@@ -17830,6 +17883,9 @@ packages:
     resolution: {integrity: sha512-kQSF2NlHk8yjS3SRiJW3S+U5ibkEmVRhB4/GYsVwGvdAkFC2b+EIE1Ob7J56OmqW9VBZgkx1+SuWqo5JTIJSYQ==}
     engines: {node: '>=14.0.0', npm: '>=6.12.0'}
 
+  webauthn-p256@0.0.5:
+    resolution: {integrity: sha512-drMGNWKdaixZNobeORVIqq7k5DsRC9FnG201K2QjeOoQLmtSDaSsVZdkg6n5jUALJKcAG++zBPJXmv6hy0nWFg==}
+
   webextension-polyfill@0.10.0:
     resolution: {integrity: sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==}
 
@@ -22865,6 +22921,10 @@ snapshots:
       graphql: 16.9.0
       typescript: 5.4.5
 
+  '@graphprotocol/graph-ts@0.35.1':
+    dependencies:
+      assemblyscript: 0.19.10
+
   '@graphql-tools/batch-execute@8.5.1(graphql@15.8.0)':
     dependencies:
       '@graphql-tools/utils': 8.9.0(graphql@15.8.0)
@@ -26126,6 +26186,21 @@ snapshots:
       - encoding
       - utf-8-validate
 
+  '@pythnetwork/express-relay-evm-js@0.8.1(axios@1.7.2)(bufferutil@4.0.8)(js-yaml@4.1.0)(typescript@5.5.4)(utf-8-validate@6.0.4)(zod@3.23.8)':
+    dependencies:
+      isomorphic-ws: 5.0.0(ws@8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+      openapi-client-axios: 7.5.5(axios@1.7.2)(js-yaml@4.1.0)
+      openapi-fetch: 0.8.2
+      viem: 2.18.6(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@6.0.4)(zod@3.23.8)
+      ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)
+    transitivePeerDependencies:
+      - axios
+      - bufferutil
+      - js-yaml
+      - typescript
+      - utf-8-validate
+      - zod
+
   '@pythnetwork/price-service-client@1.9.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)':
     dependencies:
       '@pythnetwork/price-service-sdk': 1.7.1
@@ -26834,7 +26909,7 @@ snapshots:
     dependencies:
       '@noble/curves': 1.2.0
       '@noble/hashes': 1.3.3
-      '@scure/base': 1.1.6
+      '@scure/base': 1.1.7
 
   '@scure/bip32@1.3.3':
     dependencies:
@@ -26844,9 +26919,9 @@ snapshots:
 
   '@scure/bip32@1.4.0':
     dependencies:
-      '@noble/curves': 1.4.0
+      '@noble/curves': 1.4.2
       '@noble/hashes': 1.4.0
-      '@scure/base': 1.1.6
+      '@scure/base': 1.1.7
 
   '@scure/bip39@1.1.0':
     dependencies:
@@ -26856,7 +26931,7 @@ snapshots:
   '@scure/bip39@1.2.1':
     dependencies:
       '@noble/hashes': 1.3.3
-      '@scure/base': 1.1.6
+      '@scure/base': 1.1.7
 
   '@scure/bip39@1.2.2':
     dependencies:
@@ -28784,6 +28859,10 @@ snapshots:
     dependencies:
       undici-types: 5.26.5
 
+  '@types/node@22.0.0':
+    dependencies:
+      undici-types: 6.11.1
+
   '@types/normalize-package-data@2.4.1': {}
 
   '@types/parse-json@4.0.0': {}
@@ -30466,6 +30545,11 @@ snapshots:
       typescript: 5.5.2
       zod: 3.23.8
 
+  abitype@1.0.5(typescript@5.5.4)(zod@3.23.8):
+    optionalDependencies:
+      typescript: 5.5.4
+      zod: 3.23.8
+
   abort-controller@3.0.0:
     dependencies:
       event-target-shim: 5.0.1
@@ -30972,6 +31056,11 @@ snapshots:
     dependencies:
       safer-buffer: 2.1.2
 
+  assemblyscript@0.19.10:
+    dependencies:
+      binaryen: 101.0.0-nightly.20210723
+      long: 4.0.0
+
   assert-plus@1.0.0: {}
 
   assert@2.1.0:
@@ -31132,7 +31221,7 @@ snapshots:
 
   axios@1.7.2:
     dependencies:
-      follow-redirects: 1.15.6(debug@4.3.4)
+      follow-redirects: 1.15.6
       form-data: 4.0.0
       proxy-from-env: 1.1.0
     transitivePeerDependencies:
@@ -31414,6 +31503,8 @@ snapshots:
 
   binary-parser@2.2.1: {}
 
+  binaryen@101.0.0-nightly.20210723: {}
+
   bindings@1.5.0:
     dependencies:
       file-uri-to-path: 1.0.0
@@ -34891,6 +34982,8 @@ snapshots:
 
   flow-parser@0.238.2: {}
 
+  follow-redirects@1.15.6: {}
+
   follow-redirects@1.15.6(debug@4.3.4):
     optionalDependencies:
       debug: 4.3.4(supports-color@8.1.1)
@@ -36245,6 +36338,10 @@ snapshots:
     dependencies:
       ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@5.0.10)
 
+  isomorphic-ws@5.0.0(ws@8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)):
+    dependencies:
+      ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)
+
   isows@1.0.3(ws@8.13.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)):
     dependencies:
       ws: 8.13.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)
@@ -36257,6 +36354,10 @@ snapshots:
     dependencies:
       ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@5.0.10)
 
+  isows@1.0.4(ws@8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)):
+    dependencies:
+      ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)
+
   isstream@0.1.2: {}
 
   istanbul-lib-coverage@3.2.2: {}
@@ -43676,6 +43777,8 @@ snapshots:
 
   typescript@5.5.2: {}
 
+  typescript@5.5.4: {}
+
   typical@4.0.0: {}
 
   typical@7.1.1: {}
@@ -43709,6 +43812,8 @@ snapshots:
 
   undici-types@5.26.5: {}
 
+  undici-types@6.11.1: {}
+
   undici@5.26.5:
     dependencies:
       '@fastify/busboy': 2.1.1
@@ -44072,6 +44177,24 @@ snapshots:
       - utf-8-validate
       - zod
 
+  viem@2.18.6(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@6.0.4)(zod@3.23.8):
+    dependencies:
+      '@adraffy/ens-normalize': 1.10.0
+      '@noble/curves': 1.4.0
+      '@noble/hashes': 1.4.0
+      '@scure/bip32': 1.4.0
+      '@scure/bip39': 1.3.0
+      abitype: 1.0.5(typescript@5.5.4)(zod@3.23.8)
+      isows: 1.0.4(ws@8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+      webauthn-p256: 0.0.5
+      ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)
+    optionalDependencies:
+      typescript: 5.5.4
+    transitivePeerDependencies:
+      - bufferutil
+      - utf-8-validate
+      - zod
+
   viem@2.8.13(bufferutil@4.0.8)(typescript@5.4.5)(utf-8-validate@6.0.4)(zod@3.23.8):
     dependencies:
       '@adraffy/ens-normalize': 1.10.0
@@ -45149,6 +45272,11 @@ snapshots:
       - utf-8-validate
       - zod
 
+  webauthn-p256@0.0.5:
+    dependencies:
+      '@noble/curves': 1.4.2
+      '@noble/hashes': 1.4.0
+
   webextension-polyfill@0.10.0: {}
 
   webidl-conversions@3.0.1: {}