diff --git a/.env.example b/.env.example index 2c0bdbe3bd5..0760c86af36 100644 --- a/.env.example +++ b/.env.example @@ -183,6 +183,9 @@ EVM_PROVIDER_URL= AVALANCHE_PRIVATE_KEY= AVALANCHE_PUBLIC_KEY= +# Arthera +ARTHERA_PRIVATE_KEY= + # Solana SOLANA_PRIVATE_KEY= SOLANA_PUBLIC_KEY= diff --git a/agent/package.json b/agent/package.json index f4fa0f33e03..30c968925e3 100644 --- a/agent/package.json +++ b/agent/package.json @@ -61,6 +61,7 @@ "@elizaos/plugin-fuel": "workspace:*", "@elizaos/plugin-avalanche": "workspace:*", "@elizaos/plugin-web-search": "workspace:*", + "@elizaos/plugin-arthera": "workspace:*", "readline": "1.3.0", "ws": "8.18.0", "yargs": "17.7.2" diff --git a/agent/src/index.ts b/agent/src/index.ts index 53058cf4ece..3be3c25d580 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -64,6 +64,7 @@ import { abstractPlugin } from "@elizaos/plugin-abstract"; import { avalanchePlugin } from "@elizaos/plugin-avalanche"; import { webSearchPlugin } from "@elizaos/plugin-web-search"; import { echoChamberPlugin } from "@elizaos/plugin-echochambers"; +import { artheraPlugin } from "@elizaos/plugin-arthera"; import Database from "better-sqlite3"; import fs from "fs"; import path from "path"; @@ -609,6 +610,9 @@ export async function createAgent( getSecret(character, "ECHOCHAMBERS_API_KEY") ? echoChamberPlugin : null, + getSecret(character, "ARTHERA_PRIVATE_KEY")?.startsWith("0x") + ? artheraPlugin + : null, ].filter(Boolean), providers: [], actions: [], diff --git a/packages/plugin-arthera/README.md b/packages/plugin-arthera/README.md new file mode 100644 index 00000000000..b634635d469 --- /dev/null +++ b/packages/plugin-arthera/README.md @@ -0,0 +1,68 @@ +# `@elizaos/plugin-arthera` + +This plugin provides actions and providers for interacting with Arthera. + +--- + +## Configuration + +### Default Setup + +By default, **Arthera** is enabled. To use it, simply add your private key to the `.env` file: + +```env +ARTHERA_PRIVATE_KEY=your-private-key-here +``` + +### Custom RPC URLs + +By default, the RPC URL is inferred from the `viem/chains` config. To use a custom RPC URL for a specific chain, add the following to your `.env` file: + +```env +ETHEREUM_PROVIDER_=https://your-custom-rpc-url +``` + +**Example usage:** + +```env +ETHEREUM_PROVIDER_ARTHERA=https://rpc.arthera.net +``` + +## Provider + +The **Wallet Provider** initializes with Arthera. It: + +- Provides the **context** of the currently connected address and its balance. +- Creates **Public** and **Wallet clients** to interact with the supported chain. + +--- + +## Actions + +### Transfer + +Transfer tokens from one address to another on Arthera. Just specify the: + +- **Amount** +- **Chain** +- **Recipient Address** + +**Example usage:** + +```bash +Transfer 1 AA to 0xRecipient on arthera. +``` + +--- + +## Contribution + +The plugin contains tests. Whether you're using **TDD** or not, please make sure to run the tests before submitting a PR. + +### Running Tests + +Navigate to the `plugin-arthera` directory and run: + +```bash +pnpm test +``` diff --git a/packages/plugin-arthera/eslint.config.mjs b/packages/plugin-arthera/eslint.config.mjs new file mode 100644 index 00000000000..92fe5bbebef --- /dev/null +++ b/packages/plugin-arthera/eslint.config.mjs @@ -0,0 +1,3 @@ +import eslintGlobalConfig from "../../eslint.config.mjs"; + +export default [...eslintGlobalConfig]; diff --git a/packages/plugin-arthera/package.json b/packages/plugin-arthera/package.json new file mode 100644 index 00000000000..3431ecf67e0 --- /dev/null +++ b/packages/plugin-arthera/package.json @@ -0,0 +1,24 @@ +{ + "name": "@elizaos/plugin-arthera", + "version": "0.1.7-alpha.2", + "main": "dist/index.js", + "type": "module", + "types": "dist/index.d.ts", + "dependencies": { + "@elizaos/core": "workspace:*", + "tsup": "8.3.5", + "viem": "2.21.58" + }, + "scripts": { + "build": "tsup --format esm --dts", + "dev": "tsup --format esm --dts --watch", + "test": "vitest run", + "lint": "eslint --fix --cache ." + }, + "devDependencies": { + "whatwg-url": "7.1.0" + }, + "peerDependencies": { + "whatwg-url": "7.1.0" + } +} diff --git a/packages/plugin-arthera/src/actions/transfer.ts b/packages/plugin-arthera/src/actions/transfer.ts new file mode 100644 index 00000000000..2ad25281de5 --- /dev/null +++ b/packages/plugin-arthera/src/actions/transfer.ts @@ -0,0 +1,176 @@ +import { ByteArray, formatEther, parseEther, type Hex } from "viem"; +import { + composeContext, + generateObjectDeprecated, + HandlerCallback, + ModelClass, + type IAgentRuntime, + type Memory, + type State, +} from "@elizaos/core"; + +import { initWalletProvider, WalletProvider } from "../providers/wallet"; +import type { Transaction, TransferParams } from "../types"; +import { transferTemplate } from "../templates"; + +export { transferTemplate }; + +// Exported for tests +export class TransferAction { + constructor(private walletProvider: WalletProvider) {} + + async transfer(params: TransferParams): Promise { + const walletClient = this.walletProvider.getWalletClient( + params.fromChain + ); + + console.log( + `Transferring: ${params.amount} tokens from (${walletClient.account.address} to (${params.toAddress} on ${params.fromChain})` + ); + + if (!params.data) { + params.data = "0x"; + } + + try { + const hash = await walletClient.sendTransaction({ + account: walletClient.account, + to: params.toAddress, + value: parseEther(params.amount), + data: params.data as Hex, + kzg: { + blobToKzgCommitment: function (_: ByteArray): ByteArray { + throw new Error("Function not implemented."); + }, + computeBlobKzgProof: function ( + _blob: ByteArray, + _commitment: ByteArray + ): ByteArray { + throw new Error("Function not implemented."); + }, + }, + chain: undefined, + }); + + return { + hash, + from: walletClient.account.address, + to: params.toAddress, + value: parseEther(params.amount), + data: params.data as Hex, + }; + } catch (error) { + throw new Error(`Transfer failed: ${error.message}`); + } + } +} + +const buildTransferDetails = async ( + state: State, + runtime: IAgentRuntime, + wp: WalletProvider +): Promise => { + const context = composeContext({ + state, + template: transferTemplate, + }); + + const chains = Object.keys(wp.chains); + + const contextWithChains = context.replace( + "SUPPORTED_CHAINS", + chains.map((item) => `"${item}"`).join("|") + ); + + const transferDetails = (await generateObjectDeprecated({ + runtime, + context: contextWithChains, + modelClass: ModelClass.SMALL, + })) as TransferParams; + + const existingChain = wp.chains[transferDetails.fromChain]; + + if (!existingChain) { + throw new Error( + "The chain " + + transferDetails.fromChain + + " not configured yet. Add the chain or choose one from configured: " + + chains.toString() + ); + } + + return transferDetails; +}; + +export const transferAction = { + name: "transfer", + description: "Transfer tokens between addresses on the same chain", + handler: async ( + runtime: IAgentRuntime, + _message: Memory, + state: State, + _options: Record, + callback?: HandlerCallback + ) => { + console.log("Transfer action handler called"); + const walletProvider = initWalletProvider(runtime); + const action = new TransferAction(walletProvider); + + // Compose transfer context + const paramOptions = await buildTransferDetails( + state, + runtime, + walletProvider + ); + + try { + const transferResp = await action.transfer(paramOptions); + if (callback) { + callback({ + text: `Successfully transferred ${paramOptions.amount} tokens to ${paramOptions.toAddress}\nTransaction Hash: ${transferResp.hash}`, + content: { + success: true, + hash: transferResp.hash, + amount: formatEther(transferResp.value), + recipient: transferResp.to, + chain: paramOptions.fromChain, + }, + }); + } + return true; + } catch (error) { + console.error("Error during token transfer:", error); + if (callback) { + callback({ + text: `Error transferring tokens: ${error.message}`, + content: { error: error.message }, + }); + } + return false; + } + }, + template: transferTemplate, + validate: async (runtime: IAgentRuntime) => { + const privateKey = runtime.getSetting("ARTHERA_PRIVATE_KEY"); + return typeof privateKey === "string" && privateKey.startsWith("0x"); + }, + examples: [ + [ + { + user: "assistant", + content: { + text: "I'll help you transfer 1 AA to 0x742d35Cc6634C0532925a3b844Bc454e4438f44e", + action: "SEND_TOKENS", + }, + }, + { + user: "user", + content: { + text: "Transfer 1 AA to 0x742d35Cc6634C0532925a3b844Bc454e4438f44e", + action: "SEND_TOKENS", + }, + }, + ], + ], + similes: ["SEND_TOKENS", "TOKEN_TRANSFER", "MOVE_TOKENS"], +}; diff --git a/packages/plugin-arthera/src/index.ts b/packages/plugin-arthera/src/index.ts new file mode 100644 index 00000000000..3fe8d585945 --- /dev/null +++ b/packages/plugin-arthera/src/index.ts @@ -0,0 +1,18 @@ +export * from "./actions/transfer"; +export * from "./providers/wallet"; +export * from "./types"; + +import type { Plugin } from "@elizaos/core"; +import { transferAction } from "./actions/transfer"; +import { artheraWalletProvider } from "./providers/wallet"; + +export const artheraPlugin: Plugin = { + name: "arthera", + description: "Arthera blockchain integration plugin", + providers: [artheraWalletProvider], + evaluators: [], + services: [], + actions: [transferAction], +}; + +export default artheraPlugin; diff --git a/packages/plugin-arthera/src/providers/wallet.ts b/packages/plugin-arthera/src/providers/wallet.ts new file mode 100644 index 00000000000..7d724fbf4a7 --- /dev/null +++ b/packages/plugin-arthera/src/providers/wallet.ts @@ -0,0 +1,203 @@ +import { + createPublicClient, + createWalletClient, + formatUnits, + http, +} from "viem"; +import { privateKeyToAccount } from "viem/accounts"; +import type { IAgentRuntime, Provider, Memory, State } from "@elizaos/core"; +import type { + Address, + WalletClient, + PublicClient, + Chain, + HttpTransport, + Account, + PrivateKeyAccount, +} from "viem"; +import * as viemChains from "viem/chains"; + +import type { SupportedChain } from "../types"; + +export class WalletProvider { + private currentChain: SupportedChain = "arthera"; + chains: Record = { arthera: viemChains.arthera }; + account: PrivateKeyAccount; + + constructor(privateKey: `0x${string}`, chains?: Record) { + this.setAccount(privateKey); + this.setChains(chains); + + if (chains && Object.keys(chains).length > 0) { + this.setCurrentChain(Object.keys(chains)[0] as SupportedChain); + } + } + + getAddress(): Address { + return this.account.address; + } + + getCurrentChain(): Chain { + return this.chains[this.currentChain]; + } + + getPublicClient( + chainName: SupportedChain + ): PublicClient { + const transport = this.createHttpTransport(chainName); + + const publicClient = createPublicClient({ + chain: this.chains[chainName], + transport, + }); + return publicClient; + } + + getWalletClient(chainName: SupportedChain): WalletClient { + const transport = this.createHttpTransport(chainName); + + const walletClient = createWalletClient({ + chain: this.chains[chainName], + transport, + account: this.account, + }); + + return walletClient; + } + + getChainConfigs(chainName: SupportedChain): Chain { + const chain = viemChains[chainName]; + + if (!chain?.id) { + throw new Error("Invalid chain name"); + } + + return chain; + } + + async getWalletBalance(): Promise { + try { + const client = this.getPublicClient(this.currentChain); + const balance = await client.getBalance({ + address: this.account.address, + }); + return formatUnits(balance, 18); + } catch (error) { + console.error("Error getting wallet balance:", error); + return null; + } + } + + async getWalletBalanceForChain( + chainName: SupportedChain + ): Promise { + try { + const client = this.getPublicClient(chainName); + const balance = await client.getBalance({ + address: this.account.address, + }); + return formatUnits(balance, 18); + } catch (error) { + console.error("Error getting wallet balance:", error); + return null; + } + } + + private setAccount = (pk: `0x${string}`) => { + this.account = privateKeyToAccount(pk); + }; + + private setChains = (chains?: Record) => { + if (!chains) { + return; + } + Object.keys(chains).forEach((chain: string) => { + this.chains[chain] = chains[chain]; + }); + }; + + private setCurrentChain = (chain: SupportedChain) => { + this.currentChain = chain; + }; + + private createHttpTransport = (chainName: SupportedChain) => { + const chain = this.chains[chainName]; + + if (chain.rpcUrls.custom) { + return http(chain.rpcUrls.custom.http[0]); + } + return http(chain.rpcUrls.default.http[0]); + }; + + static genChainFromName( + chainName: string, + customRpcUrl?: string | null + ): Chain { + const baseChain = viemChains[chainName]; + + if (!baseChain?.id) { + throw new Error("Invalid chain name"); + } + + const viemChain: Chain = customRpcUrl + ? { + ...baseChain, + rpcUrls: { + ...baseChain.rpcUrls, + custom: { + http: [customRpcUrl], + }, + }, + } + : baseChain; + + return viemChain; + } +} + +const genChainsFromRuntime = ( + runtime: IAgentRuntime +): Record => { + const chainNames = ["arthera"]; + const chains = {}; + + chainNames.forEach((chainName) => { + const rpcUrl = runtime.getSetting( + "ETHEREUM_PROVIDER_" + chainName.toUpperCase() + ); + const chain = WalletProvider.genChainFromName(chainName, rpcUrl); + chains[chainName] = chain; + }); + + return chains; +}; + +export const initWalletProvider = (runtime: IAgentRuntime) => { + const privateKey = runtime.getSetting("ARTHERA_PRIVATE_KEY"); + if (!privateKey) { + throw new Error("ARTHERA_PRIVATE_KEY is missing"); + } + + const chains = genChainsFromRuntime(runtime); + + return new WalletProvider(privateKey as `0x${string}`, chains); +}; + +export const artheraWalletProvider: Provider = { + async get( + runtime: IAgentRuntime, + _message: Memory, + _state?: State + ): Promise { + try { + const walletProvider = initWalletProvider(runtime); + const address = walletProvider.getAddress(); + const balance = await walletProvider.getWalletBalance(); + const chain = walletProvider.getCurrentChain(); + return `Arthera Wallet Address: ${address}\nBalance: ${balance} ${chain.nativeCurrency.symbol}\nChain ID: ${chain.id}, Name: ${chain.name}`; + } catch (error) { + console.error("Error in Arthera wallet provider:", error); + return null; + } + }, +}; diff --git a/packages/plugin-arthera/src/templates/index.ts b/packages/plugin-arthera/src/templates/index.ts new file mode 100644 index 00000000000..d8206074bce --- /dev/null +++ b/packages/plugin-arthera/src/templates/index.ts @@ -0,0 +1,23 @@ +export const transferTemplate = `Given the recent messages and wallet information below: + +{{recentMessages}} + +{{walletInfo}} + +Extract the following information about the requested transfer: +- Chain to execute on: Must be one of ["arthera", "base", ...] (like in viem/chains) +- Amount to transfer: Must be a string representing the amount in AA (only number without coin symbol, e.g., "0.1") +- Recipient address: Must be a valid Arthera address starting with "0x" +- Token symbol or address (if not native token): Optional, leave as null for AA transfers + +Respond with a JSON markdown block containing only the extracted values. All fields except 'token' are required: + +\`\`\`json +{ + "fromChain": SUPPORTED_CHAINS, + "amount": string, + "toAddress": string, + "token": string | null +} +\`\`\` +`; diff --git a/packages/plugin-arthera/src/tests/transfer.test.ts b/packages/plugin-arthera/src/tests/transfer.test.ts new file mode 100644 index 00000000000..aaecf38d7c7 --- /dev/null +++ b/packages/plugin-arthera/src/tests/transfer.test.ts @@ -0,0 +1,83 @@ +import { describe, it, expect, beforeEach } from "vitest"; +import { generatePrivateKey } from "viem/accounts"; +import { Chain } from "viem"; +import { getEnvVariable } from "@elizaos/core"; + +import { TransferAction } from "../actions/transfer"; +import { WalletProvider } from "../providers/wallet"; + +describe("Transfer Action", () => { + let wp: WalletProvider; + let wp1: WalletProvider; + + beforeEach(async () => { + const pk = generatePrivateKey(); + const pk1 = getEnvVariable("ARTHERA_PRIVATE_KEY") as `0x${string}`; + const customChains = prepareChains(); + wp = new WalletProvider(pk, customChains); + if (pk1) { + wp1 = new WalletProvider(pk1, customChains); + } + }); + describe("Constructor", () => { + it("should initialize with wallet provider", () => { + const ta = new TransferAction(wp); + + expect(ta).toBeDefined(); + }); + }); + describe("Transfer", () => { + let ta: TransferAction; + let ta1: TransferAction; + let receiverAddress: `0x${string}`; + + beforeEach(() => { + ta = new TransferAction(wp); + if (wp1) { + ta1 = new TransferAction(wp1); + receiverAddress = wp1.getAddress(); + } + else { + receiverAddress = wp.getAddress(); + } + }); + + it("throws if not enough gas", async () => { + await expect( + ta.transfer({ + fromChain: "arthera", + toAddress: receiverAddress, + amount: "1", + }) + ).rejects.toThrow( + "Transfer failed: The total cost (gas * gas fee + value) of executing this transaction exceeds the balance of the account." + ); + }); + + if (wp1) { + it("transfers tokens", async () => { + const tx = await ta1.transfer({ + fromChain: "arthera", + toAddress: receiverAddress, + amount: "0.001", + }); + + expect(tx).toBeDefined(); + expect(tx.from).toEqual(wp1.getAddress()); + expect(tx.to).toEqual(receiverAddress); + expect(tx.value).toEqual(1000000000000000n); + }); + } + }); +}); + +const prepareChains = () => { + const customChains: Record = {}; + const chainNames = ["arthera"]; + chainNames.forEach( + (chain) => + (customChains[chain] = WalletProvider.genChainFromName(chain)) + ); + + return customChains; +}; diff --git a/packages/plugin-arthera/src/tests/wallet.test.ts b/packages/plugin-arthera/src/tests/wallet.test.ts new file mode 100644 index 00000000000..07cb1494ed3 --- /dev/null +++ b/packages/plugin-arthera/src/tests/wallet.test.ts @@ -0,0 +1,175 @@ +import { describe, it, expect, beforeAll, beforeEach } from "vitest"; +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; +import { arthera, Chain } from "viem/chains"; + +import { WalletProvider } from "../providers/wallet"; + +const customRpcUrls = { + arthera: "custom-rpc.arthera.io", +}; + +describe("Wallet provider", () => { + let walletProvider: WalletProvider; + let pk: `0x${string}`; + const customChains: Record = {}; + + beforeAll(() => { + pk = generatePrivateKey(); + + const chainNames = ["arthera"]; + chainNames.forEach( + (chain) => + (customChains[chain] = WalletProvider.genChainFromName(chain)) + ); + }); + + describe("Constructor", () => { + it("sets address", () => { + const account = privateKeyToAccount(pk); + const expectedAddress = account.address; + + walletProvider = new WalletProvider(pk); + + expect(walletProvider.getAddress()).toEqual(expectedAddress); + }); + it("sets default chain to arthera", () => { + walletProvider = new WalletProvider(pk); + + expect(walletProvider.chains.arthera.id).toEqual(arthera.id); + expect(walletProvider.getCurrentChain().id).toEqual(arthera.id); + }); + it("sets custom chains", () => { + walletProvider = new WalletProvider(pk, customChains); + + expect(walletProvider.chains.arthera.id).toEqual(arthera.id); + }); + it("sets the first provided custom chain as current chain", () => { + walletProvider = new WalletProvider(pk, customChains); + + expect(walletProvider.getCurrentChain().id).toEqual(arthera.id); + }); + }); + describe("Clients", () => { + beforeEach(() => { + walletProvider = new WalletProvider(pk); + }); + it("generates public client", () => { + const client = walletProvider.getPublicClient("arthera"); + expect(client.chain.id).toEqual(arthera.id); + expect(client.transport.url).toEqual( + arthera.rpcUrls.default.http[0] + ); + }); + it("generates public client with custom rpcurl", () => { + const chain = WalletProvider.genChainFromName( + "arthera", + customRpcUrls.arthera + ); + const wp = new WalletProvider(pk, { ["arthera"]: chain }); + + const client = wp.getPublicClient("arthera"); + expect(client.chain.id).toEqual(arthera.id); + expect(client.chain.rpcUrls.default.http[0]).toEqual( + arthera.rpcUrls.default.http[0] + ); + expect(client.chain.rpcUrls.custom.http[0]).toEqual( + customRpcUrls.arthera + ); + expect(client.transport.url).toEqual(customRpcUrls.arthera); + }); + it("generates wallet client", () => { + const account = privateKeyToAccount(pk); + const expectedAddress = account.address; + + const client = walletProvider.getWalletClient("arthera"); + + expect(client.account.address).toEqual(expectedAddress); + expect(client.transport.url).toEqual( + arthera.rpcUrls.default.http[0] + ); + }); + it("generates wallet client with custom rpcurl", () => { + const account = privateKeyToAccount(pk); + const expectedAddress = account.address; + const chain = WalletProvider.genChainFromName( + "arthera", + customRpcUrls.arthera + ); + const wp = new WalletProvider(pk, { ["arthera"]: chain }); + + const client = wp.getWalletClient("arthera"); + + expect(client.account.address).toEqual(expectedAddress); + expect(client.chain.id).toEqual(arthera.id); + expect(client.chain.rpcUrls.default.http[0]).toEqual( + arthera.rpcUrls.default.http[0] + ); + expect(client.chain.rpcUrls.custom.http[0]).toEqual( + customRpcUrls.arthera + ); + expect(client.transport.url).toEqual(customRpcUrls.arthera); + }); + }); + describe("Balance", () => { + beforeEach(() => { + walletProvider = new WalletProvider(pk, customChains); + }); + it("should fetch balance", async () => { + const bal = await walletProvider.getWalletBalance(); + + expect(bal).toEqual("0"); + }); + it("should fetch balance for a specific added chain", async () => { + const bal = await walletProvider.getWalletBalanceForChain("arthera"); + + expect(bal).toEqual("0"); + }); + it("should return null if chain is not added", async () => { + const bal = await walletProvider.getWalletBalanceForChain("base"); + expect(bal).toBeNull(); + }); + }); + describe("Chain", () => { + beforeEach(() => { + walletProvider = new WalletProvider(pk, customChains); + }); + it("generates chains from chain name", () => { + const chainName = "arthera"; + const chain: Chain = WalletProvider.genChainFromName(chainName); + + expect(chain.rpcUrls.default.http[0]).toEqual( + arthera.rpcUrls.default.http[0] + ); + }); + it("generates chains from chain name with custom rpc url", () => { + const chainName = "arthera"; + const customRpcUrl = customRpcUrls.arthera; + const chain: Chain = WalletProvider.genChainFromName( + chainName, + customRpcUrl + ); + + expect(chain.rpcUrls.default.http[0]).toEqual( + arthera.rpcUrls.default.http[0] + ); + expect(chain.rpcUrls.custom.http[0]).toEqual(customRpcUrl); + }); + it("gets chain configs", () => { + const chain = walletProvider.getChainConfigs("arthera"); + + expect(chain.id).toEqual(arthera.id); + }); + it("throws if unsupported chain name", () => { + // intentionally set unsupported chain, ts will complain + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + expect(() => WalletProvider.genChainFromName("ethereum")).toThrow(); + }); + it("throws if invalid chain name", () => { + // intentionally set incorrect chain, ts will complain + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + expect(() => WalletProvider.genChainFromName("eth")).toThrow(); + }); + }); +}); diff --git a/packages/plugin-arthera/src/types/index.ts b/packages/plugin-arthera/src/types/index.ts new file mode 100644 index 00000000000..f772c842a62 --- /dev/null +++ b/packages/plugin-arthera/src/types/index.ts @@ -0,0 +1,73 @@ +import type { + Account, + Address, + Chain, + Hash, + HttpTransport, + PublicClient, + WalletClient, +} from "viem"; +import * as viemChains from "viem/chains"; + +const _SupportedChainList = Object.keys(viemChains) as Array< + keyof typeof viemChains +>; +export type SupportedChain = (typeof _SupportedChainList)[number]; + +// Transaction types +export interface Transaction { + hash: Hash; + from: Address; + to: Address; + value: bigint; + data?: `0x${string}`; + chainId?: number; +} + +// Chain configuration +export interface ChainMetadata { + chainId: number; + name: string; + chain: Chain; + rpcUrl: string; + nativeCurrency: { + name: string; + symbol: string; + decimals: number; + }; + blockExplorerUrl: string; +} + +export interface ChainConfig { + chain: Chain; + publicClient: PublicClient; + walletClient?: WalletClient; +} + +// Action parameters +export interface TransferParams { + fromChain: SupportedChain; + toAddress: Address; + amount: string; + data?: `0x${string}`; +} + +// Plugin configuration +export interface ArtheraPluginConfig { + rpcUrl?: { + arthera?: string; + }; + secrets?: { + ARTHERA_PRIVATE_KEY: string; + }; + testMode?: boolean; + multicall?: { + batchSize?: number; + wait?: number; + }; +} + +export interface ProviderError extends Error { + code?: number; + data?: unknown; +} diff --git a/packages/plugin-arthera/tsconfig.json b/packages/plugin-arthera/tsconfig.json new file mode 100644 index 00000000000..b6ce190d989 --- /dev/null +++ b/packages/plugin-arthera/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../core/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "./src", + "typeRoots": [ + "./node_modules/@types", + "./src/types" + ], + "declaration": true + }, + "include": [ + "src" + ] +} diff --git a/packages/plugin-arthera/tsup.config.ts b/packages/plugin-arthera/tsup.config.ts new file mode 100644 index 00000000000..04abb285562 --- /dev/null +++ b/packages/plugin-arthera/tsup.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + outDir: "dist", + sourcemap: true, + clean: true, + format: ["esm"], // Ensure you're targeting CommonJS + external: [ + "dotenv", // Externalize dotenv to prevent bundling + "fs", // Externalize fs to use Node.js built-in module + "path", // Externalize other built-ins if necessary + "@reflink/reflink", + "@node-llama-cpp", + "https", + "http", + "agentkeepalive", + "viem", + ], +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 90f147c715c..206752bb0cd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -150,6 +150,9 @@ importers: '@elizaos/plugin-aptos': specifier: workspace:* version: link:../packages/plugin-aptos + '@elizaos/plugin-arthera': + specifier: workspace:* + version: link:../packages/plugin-arthera '@elizaos/plugin-avalanche': specifier: workspace:* version: link:../packages/plugin-avalanche @@ -1040,11 +1043,30 @@ importers: specifier: 7.1.0 version: 7.1.0 + packages/plugin-arthera: + dependencies: + '@elizaos/core': + specifier: workspace:* + version: link:../core + tsup: + specifier: 8.3.5 + version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + viem: + specifier: 2.21.58 + version: 2.21.58(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) + devDependencies: + whatwg-url: + specifier: 7.1.0 + version: 7.1.0 + packages/plugin-avalanche: dependencies: '@elizaos/core': specifier: workspace:* version: link:../core + viem: + specifier: 2.21.49 + version: 2.21.49(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -15056,6 +15078,14 @@ packages: typescript: optional: true + ox@0.4.4: + resolution: {integrity: sha512-oJPEeCDs9iNiPs6J0rTx+Y0KGeCGyCAA3zo94yZhm8G5WpOxrwUtn2Ie/Y8IyARSqqY/j9JTKA3Fc1xs1DvFnw==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + p-cancelable@2.1.1: resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} engines: {node: '>=8'} @@ -18912,6 +18942,14 @@ packages: typescript: optional: true + viem@2.21.54: + resolution: {integrity: sha512-G9mmtbua3UtnVY9BqAtWdNp+3AO+oWhD0B9KaEsZb6gcrOWgmA4rz02yqEMg+qW9m6KgKGie7q3zcHqJIw6AqA==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + viem@2.21.58: resolution: {integrity: sha512-mGVKlu3ici7SueEQatn44I7KePP8Nwb5JUjZaQOciWxWHCFP/WLyjdZDIK09qyaozHNTH/t78K3ptXCe+AnMuQ==} peerDependencies: @@ -19623,7 +19661,7 @@ snapshots: '@acuminous/bitsyntax@0.1.2': dependencies: buffer-more-ints: 1.0.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) safe-buffer: 5.1.2 transitivePeerDependencies: - supports-color @@ -20690,7 +20728,7 @@ snapshots: '@babel/traverse': 7.26.4 '@babel/types': 7.26.3 convert-source-map: 2.0.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -21480,7 +21518,7 @@ snapshots: '@babel/parser': 7.26.3 '@babel/template': 7.25.9 '@babel/types': 7.26.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -21492,13 +21530,13 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} - '@bigmi/core@0.0.4(bitcoinjs-lib@7.0.0-rc.0(typescript@5.6.3))(bs58@6.0.0)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))': + '@bigmi/core@0.0.4(bitcoinjs-lib@7.0.0-rc.0(typescript@5.6.3))(bs58@6.0.0)(viem@2.21.53(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))': dependencies: - '@noble/hashes': 1.7.0 + '@noble/hashes': 1.6.1 bech32: 2.0.0 bitcoinjs-lib: 7.0.0-rc.0(typescript@5.6.3) bs58: 6.0.0 - viem: 2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) + viem: 2.21.53(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) '@braintree/sanitize-url@7.1.1': {} @@ -21556,7 +21594,7 @@ snapshots: dependencies: '@scure/bip32': 1.6.1 abitype: 1.0.8(typescript@5.6.3)(zod@3.23.8) - axios: 1.7.9(debug@4.4.0) + axios: 1.7.9 axios-mock-adapter: 1.22.0(axios@1.7.9) axios-retry: 4.5.0(axios@1.7.9) bip32: 4.0.0 @@ -23391,7 +23429,7 @@ snapshots: '@eslint/config-array@0.19.1': dependencies: '@eslint/object-schema': 2.1.5 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -23417,7 +23455,7 @@ snapshots: '@eslint/eslintrc@3.2.0': dependencies: ajv: 6.12.6 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) espree: 10.3.0 globals: 14.0.0 ignore: 5.3.2 @@ -24727,16 +24765,16 @@ snapshots: '@lifi/sdk@3.4.1(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)))(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(typescript@5.6.3)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))': dependencies: - '@bigmi/core': 0.0.4(bitcoinjs-lib@7.0.0-rc.0(typescript@5.6.3))(bs58@6.0.0)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)) + '@bigmi/core': 0.0.4(bitcoinjs-lib@7.0.0-rc.0(typescript@5.6.3))(bs58@6.0.0)(viem@2.21.53(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)) '@lifi/types': 16.3.0 - '@noble/curves': 1.8.0 - '@noble/hashes': 1.7.0 - '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) - '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 + '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.95.8(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/web3.js': 1.95.8(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) bech32: 2.0.0 bitcoinjs-lib: 7.0.0-rc.0(typescript@5.6.3) bs58: 6.0.0 - viem: 2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) + viem: 2.21.53(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) transitivePeerDependencies: - typescript @@ -26427,7 +26465,7 @@ snapshots: '@pm2/pm2-version-check@1.0.4': dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -28297,7 +28335,7 @@ snapshots: '@types/connect@3.4.38': dependencies: - '@types/node': 20.17.9 + '@types/node': 22.10.2 '@types/cors@2.8.17': dependencies: @@ -28751,11 +28789,11 @@ snapshots: '@types/ws@7.4.7': dependencies: - '@types/node': 20.17.9 + '@types/node': 22.10.2 '@types/ws@8.5.13': dependencies: - '@types/node': 20.17.9 + '@types/node': 22.10.2 '@types/ws@8.5.3': dependencies: @@ -28831,7 +28869,7 @@ snapshots: '@typescript-eslint/types': 8.16.0 '@typescript-eslint/typescript-estree': 8.16.0(typescript@5.6.3) '@typescript-eslint/visitor-keys': 8.16.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) eslint: 9.16.0(jiti@2.4.2) optionalDependencies: typescript: 5.6.3 @@ -28864,7 +28902,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 8.16.0(typescript@5.6.3) '@typescript-eslint/utils': 8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3) - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) eslint: 9.16.0(jiti@2.4.2) ts-api-utils: 1.4.3(typescript@5.6.3) optionalDependencies: @@ -28895,7 +28933,7 @@ snapshots: dependencies: '@typescript-eslint/types': 8.16.0 '@typescript-eslint/visitor-keys': 8.16.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 @@ -28983,7 +29021,7 @@ snapshots: dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.6 @@ -29685,7 +29723,7 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -30077,13 +30115,13 @@ snapshots: axios-mock-adapter@1.22.0(axios@1.7.9): dependencies: - axios: 1.7.9(debug@4.4.0) + axios: 1.7.9 fast-deep-equal: 3.1.3 is-buffer: 2.0.5 axios-retry@4.5.0(axios@1.7.9): dependencies: - axios: 1.7.9(debug@4.4.0) + axios: 1.7.9 is-retry-allowed: 2.2.0 axios@0.21.4: @@ -30094,7 +30132,7 @@ snapshots: axios@0.27.2: dependencies: - follow-redirects: 1.15.9(debug@4.4.0) + follow-redirects: 1.15.9(debug@4.3.7) form-data: 4.0.1 transitivePeerDependencies: - debug @@ -30123,6 +30161,14 @@ snapshots: transitivePeerDependencies: - debug + axios@1.7.9: + dependencies: + follow-redirects: 1.15.9(debug@4.3.7) + form-data: 4.0.1 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + axios@1.7.9(debug@4.4.0): dependencies: follow-redirects: 1.15.9(debug@4.4.0) @@ -33059,7 +33105,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) escape-string-regexp: 4.0.0 eslint-scope: 8.2.0 eslint-visitor-keys: 4.2.0 @@ -33984,7 +34030,7 @@ snapshots: dependencies: basic-ftp: 5.0.5 data-uri-to-buffer: 6.0.2 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -34728,7 +34774,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -34784,14 +34830,14 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) transitivePeerDependencies: - supports-color https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -35357,7 +35403,7 @@ snapshots: istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -35366,7 +35412,7 @@ snapshots: istanbul-lib-source-maps@5.0.6: dependencies: '@jridgewell/trace-mapping': 0.3.25 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color @@ -36263,7 +36309,7 @@ snapshots: zod: 3.23.8 zod-to-json-schema: 3.24.1(zod@3.23.8) optionalDependencies: - axios: 1.7.9(debug@4.4.0) + axios: 1.7.9 handlebars: 4.7.8 transitivePeerDependencies: - encoding @@ -38110,8 +38156,8 @@ snapshots: '@yarnpkg/lockfile': 1.1.0 '@yarnpkg/parsers': 3.0.0-rc.46 '@zkochan/js-yaml': 0.0.7 - axios: 1.7.9(debug@4.4.0) - chalk: 4.1.0 + axios: 1.7.9 + chalk: 4.1.2 cli-cursor: 3.1.0 cli-spinners: 2.6.1 cliui: 8.0.1 @@ -38386,11 +38432,11 @@ snapshots: ox@0.1.2(typescript@5.6.3)(zod@3.23.8): dependencies: '@adraffy/ens-normalize': 1.11.0 - '@noble/curves': 1.6.0 - '@noble/hashes': 1.5.0 - '@scure/bip32': 1.5.0 - '@scure/bip39': 1.4.0 - abitype: 1.0.6(typescript@5.6.3)(zod@3.23.8) + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 + '@scure/bip32': 1.6.0 + '@scure/bip39': 1.5.0 + abitype: 1.0.8(typescript@5.6.3)(zod@3.23.8) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.6.3 @@ -38404,7 +38450,7 @@ snapshots: '@noble/hashes': 1.6.1 '@scure/bip32': 1.6.0 '@scure/bip39': 1.5.0 - abitype: 1.0.7(typescript@5.6.3)(zod@3.23.8) + abitype: 1.0.8(typescript@5.6.3)(zod@3.23.8) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.6.3 @@ -38491,7 +38537,7 @@ snapshots: dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) get-uri: 6.0.4 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 @@ -38856,7 +38902,7 @@ snapshots: pm2-axon-rpc@0.7.1: dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -38864,7 +38910,7 @@ snapshots: dependencies: amp: 0.3.1 amp-message: 0.1.2 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) escape-string-regexp: 4.0.0 transitivePeerDependencies: - supports-color @@ -38881,7 +38927,7 @@ snapshots: pm2-sysmonit@1.2.8: dependencies: async: 3.2.6 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) pidusage: 2.0.21 systeminformation: 5.23.5 tx2: 1.0.5 @@ -38903,7 +38949,7 @@ snapshots: commander: 2.15.1 croner: 4.1.97 dayjs: 1.11.13 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) enquirer: 2.3.6 eventemitter2: 5.0.1 fclone: 1.0.11 @@ -39772,7 +39818,7 @@ snapshots: proxy-agent@6.3.1: dependencies: agent-base: 7.1.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 lru-cache: 7.18.3 @@ -40525,7 +40571,7 @@ snapshots: require-in-the-middle@5.2.0: dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) module-details-from-path: 1.0.3 resolve: 1.22.10 transitivePeerDependencies: @@ -41173,7 +41219,7 @@ snapshots: socks-proxy-agent@8.0.5: dependencies: agent-base: 7.1.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -42019,6 +42065,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.26.0) + esbuild: 0.24.2 ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)))(typescript@5.6.3): dependencies: @@ -42147,8 +42194,8 @@ snapshots: bundle-require: 5.1.0(esbuild@0.24.2) cac: 6.7.14 chokidar: 4.0.3 - consola: 3.3.3 - debug: 4.4.0(supports-color@8.1.1) + consola: 3.3.1 + debug: 4.4.0(supports-color@5.5.0) esbuild: 0.24.2 joycon: 3.1.1 picocolors: 1.1.1 @@ -42182,7 +42229,7 @@ snapshots: tuf-js@2.2.1: dependencies: '@tufjs/models': 2.0.1 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) make-fetch-happen: 13.0.1 transitivePeerDependencies: - supports-color @@ -42825,17 +42872,35 @@ snapshots: - utf-8-validate - zod - viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8): + viem@2.21.54(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8): dependencies: '@noble/curves': 1.7.0 '@noble/hashes': 1.6.1 '@scure/bip32': 1.6.0 '@scure/bip39': 1.5.0 abitype: 1.0.7(typescript@5.6.3)(zod@3.23.8) - isows: 1.0.6(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + isows: 1.0.6(ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + ox: 0.1.2(typescript@5.6.3)(zod@3.23.8) + webauthn-p256: 0.0.10 + ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + + viem@2.21.58(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8): + dependencies: + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 + '@scure/bip32': 1.6.0 + '@scure/bip39': 1.5.0 + abitype: 1.0.7(typescript@5.6.3)(zod@3.23.8) + isows: 1.0.6(ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) ox: 0.4.4(typescript@5.6.3)(zod@3.23.8) webauthn-p256: 0.0.10 - ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: @@ -42843,7 +42908,7 @@ snapshots: - utf-8-validate - zod - vite-node@2.1.4(@types/node@22.10.4)(terser@5.37.0): + vite-node@2.1.4(@types/node@22.10.2)(terser@5.37.0): dependencies: cac: 6.7.14 debug: 4.4.0(supports-color@8.1.1) @@ -42863,8 +42928,8 @@ snapshots: vite-node@2.1.5(@types/node@22.10.4)(terser@5.37.0): dependencies: cac: 6.7.14 - debug: 4.4.0(supports-color@8.1.1) - es-module-lexer: 1.6.0 + debug: 4.4.0(supports-color@5.5.0) + es-module-lexer: 1.5.4 pathe: 1.1.2 vite: 5.4.11(@types/node@22.10.4)(terser@5.37.0) transitivePeerDependencies: @@ -42976,7 +43041,7 @@ snapshots: '@vitest/spy': 2.1.5 '@vitest/utils': 2.1.5 chai: 5.1.2 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) expect-type: 1.1.0 magic-string: 0.30.17 pathe: 1.1.2 @@ -43012,7 +43077,7 @@ snapshots: '@vitest/spy': 2.1.5 '@vitest/utils': 2.1.5 chai: 5.1.2 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@5.5.0) expect-type: 1.1.0 magic-string: 0.30.17 pathe: 1.1.2