From a9fecd37e07a24fd1cf4dfed32943240864eb5cf Mon Sep 17 00:00:00 2001 From: KacperKoza34 Date: Wed, 8 Jan 2025 13:47:25 +0100 Subject: [PATCH 1/8] feat: ibc transfer action --- packages/plugin-cosmos/package.json | 1 + .../src/actions/ibc-transfer/index.ts | 226 +++++++++++++ .../src/actions/ibc-transfer/schema.ts | 37 +++ .../services/bridge-data-fetcher.ts | 68 ++++ .../services/bridge-data-provider.ts | 33 ++ .../services/ibc-transfer-action-service.ts | 129 ++++++++ .../src/actions/ibc-transfer/types.ts | 18 + .../src/shared/helpers/cosmos-messages.ts | 11 + .../plugin-cosmos/src/shared/interfaces.ts | 7 + .../cosmos-transaction-fee-estimator.ts | 14 + packages/plugin-cosmos/src/templates/index.ts | 47 +++ .../src/tests/bridge-data-fetcher.test.ts | 101 ++++++ .../src/tests/bridge-data-provider.test.ts | 103 ++++++ ...cosmos-ibc-transfer-action-service.test.ts | 309 ++++++++++++++++++ .../src/tests/cosmos-message.test.ts | 33 ++ .../cosmos-transaction-fee-estimator.test.ts | 102 ++++++ pnpm-lock.yaml | 99 +++++- 17 files changed, 1337 insertions(+), 1 deletion(-) create mode 100644 packages/plugin-cosmos/src/actions/ibc-transfer/index.ts create mode 100644 packages/plugin-cosmos/src/actions/ibc-transfer/schema.ts create mode 100644 packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-data-fetcher.ts create mode 100644 packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-data-provider.ts create mode 100644 packages/plugin-cosmos/src/actions/ibc-transfer/services/ibc-transfer-action-service.ts create mode 100644 packages/plugin-cosmos/src/actions/ibc-transfer/types.ts create mode 100644 packages/plugin-cosmos/src/shared/helpers/cosmos-messages.ts create mode 100644 packages/plugin-cosmos/src/tests/bridge-data-fetcher.test.ts create mode 100644 packages/plugin-cosmos/src/tests/bridge-data-provider.test.ts create mode 100644 packages/plugin-cosmos/src/tests/cosmos-ibc-transfer-action-service.test.ts create mode 100644 packages/plugin-cosmos/src/tests/cosmos-message.test.ts diff --git a/packages/plugin-cosmos/package.json b/packages/plugin-cosmos/package.json index 80512fa9696..b052b3060ed 100644 --- a/packages/plugin-cosmos/package.json +++ b/packages/plugin-cosmos/package.json @@ -10,6 +10,7 @@ "@cosmjs/cosmwasm-stargate": "^0.32.4", "@cosmjs/proto-signing": "^0.32.4", "@cosmjs/stargate": "^0.32.4", + "axios": "^1.7.9", "bignumber.js": "9.1.2", "chain-registry": "^1.69.68", "tsup": "8.3.5", diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts new file mode 100644 index 00000000000..f0833c3983b --- /dev/null +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts @@ -0,0 +1,226 @@ +import { + composeContext, + generateObjectDeprecated, + HandlerCallback, + IAgentRuntime, + Memory, + ModelClass, + State, +} from "@ai16z/eliza"; +import { initWalletChainsData } from "../../providers/wallet/utils"; +import { + cosmosIBCTransferTemplate, + cosmosTransferTemplate, +} from "../../templates"; +import type { + ICosmosPluginOptions, + ICosmosWalletChains, +} from "../../shared/interfaces"; +import { IBCTransferActionParams } from "./types"; +import { CosmosIBCTransferAction } from "./services/ibc-transfer-action-service"; +import { bridgeDataProvider } from "./services/bridge-data-provider"; + +export const createIBCTransferAction = ( + pluginOptions: ICosmosPluginOptions +) => ({ + name: "COSMOS_IBC_TRANSFER", + description: "Transfer tokens between addresses on cosmos chains", + handler: async ( + _runtime: IAgentRuntime, + _message: Memory, + state: State, + _options: { [key: string]: unknown }, + _callback?: HandlerCallback + ) => { + const cosmosIBCTransferContext = composeContext({ + state: state, + template: cosmosIBCTransferTemplate, + templatingEngine: "handlebars", + }); + + const cosmosIBCTransferContent = await generateObjectDeprecated({ + runtime: _runtime, + context: cosmosIBCTransferContext, + modelClass: ModelClass.SMALL, + }); + + const paramOptions: IBCTransferActionParams = { + chainName: cosmosIBCTransferContent.chainName, + symbol: cosmosIBCTransferContent.symbol, + amount: cosmosIBCTransferContent.amount, + toAddress: cosmosIBCTransferContent.toAddress, + targetChainName: cosmosIBCTransferContent.targetChainName, + }; + + try { + const walletProvider: ICosmosWalletChains = + await initWalletChainsData(_runtime); + + const action = new CosmosIBCTransferAction(walletProvider); + + const customAssets = (pluginOptions?.customChainData ?? []).map( + (chainData) => chainData.assets + ); + + const transferResp = await action.execute( + paramOptions, + bridgeDataProvider, + customAssets + ); + + if (_callback) { + await _callback({ + text: `Successfully transferred ${paramOptions.amount} tokens from ${paramOptions.chainName} to ${paramOptions.toAddress} on ${paramOptions.targetChainName}\nGas paid: ${transferResp.gasPaid}\nTransaction Hash: ${transferResp.txHash}`, + content: { + success: true, + hash: transferResp.txHash, + amount: paramOptions.amount, + recipient: transferResp.to, + fromChain: paramOptions.chainName, + toChain: paramOptions.targetChainName, + }, + }); + + const newMemory: Memory = { + userId: _message.agentId, + agentId: _message.agentId, + roomId: _message.roomId, + content: { + text: `Transaction ${paramOptions.amount} ${paramOptions.symbol} to address ${paramOptions.toAddress} from chain ${paramOptions.chainName} to ${paramOptions.targetChainName} was successfully transferred.\n Gas paid: ${transferResp.gasPaid}. Tx hash: ${transferResp.txHash}`, + }, + }; + + await _runtime.messageManager.createMemory(newMemory); + } + return true; + } catch (error) { + console.error("Error during ibc token transfer:", error); + + if (_callback) { + await _callback({ + text: `Error ibc transferring tokens: ${error.message}`, + content: { error: error.message }, + }); + } + + const newMemory: Memory = { + userId: _message.agentId, + agentId: _message.agentId, + roomId: _message.roomId, + content: { + text: `Transaction ${paramOptions.amount} ${paramOptions.symbol} to address ${paramOptions.toAddress} on chain ${paramOptions.chainName} to ${paramOptions.targetChainName} was unsuccessful.`, + }, + }; + + await _runtime.messageManager.createMemory(newMemory); + + return false; + } + }, + template: cosmosTransferTemplate, + validate: async (runtime: IAgentRuntime) => { + const mnemonic = runtime.getSetting("COSMOS_RECOVERY_PHRASE"); + const availableChains = runtime.getSetting("COSMOS_AVAILABLE_CHAINS"); + const availableChainsArray = availableChains?.split(","); + + return !(mnemonic && availableChains && availableChainsArray.length); + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "Make an IBC transfer {{0.0001 ATOM}} to {{osmosis1pcnw46km8m5amvf7jlk2ks5std75k73aralhcf}} from {{cosmoshub}} to {{osmosis}}", + action: "COSMOS_IBC_TRANSFER", + }, + }, + { + user: "{{user2}}", + content: { + text: "Do you confirm the IBC transfer action?", + action: "COSMOS_IBC_TRANSFER", + }, + }, + { + user: "{{user1}}", + content: { + text: "Yes", + action: "COSMOS_IBC_TRANSFER", + }, + }, + { + user: "{{user2}}", + content: { + text: "", + action: "COSMOS_IBC_TRANSFER", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Send {{50 OSMO}} to {{juno13248w8dtnn07sxc3gq4l3ts4rvfyat6f4qkdd6}} from {{osmosis}} to {{juno}}", + action: "COSMOS_IBC_TRANSFER", + }, + }, + { + user: "{{user2}}", + content: { + text: "Do you confirm the IBC transfer action?", + action: "COSMOS_IBC_TRANSFER", + }, + }, + { + user: "{{user1}}", + content: { + text: "Yes", + action: "COSMOS_IBC_TRANSFER", + }, + }, + { + user: "{{user2}}", + content: { + text: "", + action: "COSMOS_IBC_TRANSFER", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Transfer {{0.005 JUNO}} from {{juno}} to {{cosmos1n0xv7z2pkl4eppnm7g2rqhe2q8q6v69h7w93fc}} on {{cosmoshub}}", + action: "COSMOS_IBC_TRANSFER", + }, + }, + { + user: "{{user2}}", + content: { + text: "Do you confirm the IBC transfer action?", + action: "COSMOS_IBC_TRANSFER", + }, + }, + { + user: "{{user1}}", + content: { + text: "Yes", + action: "COSMOS_IBC_TRANSFER", + }, + }, + { + user: "{{user2}}", + content: { + text: "", + action: "COSMOS_IBC_TRANSFER", + }, + }, + ], + ], + similes: [ + "COSMOS_TRANSFER", + "COSMOS_SEND_TOKENS", + "COSMOS_TOKEN_TRANSFER", + "COSMOS_MOVE_TOKENS", + ], +}); diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/schema.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/schema.ts new file mode 100644 index 00000000000..018e892d242 --- /dev/null +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/schema.ts @@ -0,0 +1,37 @@ +import { z } from "zod"; + +export const IBCTransferParamsSchema = z.object({ + chainName: z.string(), + symbol: z.string(), + amount: z.string(), + toAddress: z.string(), + targetChainName: z.string(), +}); + +export const bridgeDataProviderParamsSchema = z.object({ + source_asset_denom: z.string(), + source_asset_chain_id: z.string(), + allow_multi_tx: z.boolean(), +}); + +export const bridgeDataProviderResponseAssetsSchema = z.object({ + denom: z.string(), + chain_id: z.string(), + origin_denom: z.string(), + origin_chain_id: z.string(), + trace: z.string(), + symbol: z.string().optional(), + name: z.string().optional(), + logo_uri: z.string().optional(), + decimals: z.number().optional(), + recommended_symbol: z.string().optional(), +}); + +export const bridgeDataProviderResponseSchema = z.object({ + dest_assets: z.record( + z.string(), + z.object({ + assets: z.array(bridgeDataProviderResponseAssetsSchema), + }) + ), +}); diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-data-fetcher.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-data-fetcher.ts new file mode 100644 index 00000000000..1ababb35214 --- /dev/null +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-data-fetcher.ts @@ -0,0 +1,68 @@ +import { bridgeDataProviderResponseSchema } from "../schema"; +import { BridgeDataProviderParams, BridgeDataProviderResponse } from "../types"; +import axios from "axios"; + +type CacheKey = `${string}_${string}`; + +export class BridgeDataFetcher { + private static instance: BridgeDataFetcher; + private cache: Map; + private readonly apiUrl: string; + + private constructor() { + this.cache = new Map(); + this.apiUrl = "https://api.skip.build/v2/fungible/assets_from_source"; + } + + public static getInstance(): BridgeDataFetcher { + if (!BridgeDataFetcher.instance) { + BridgeDataFetcher.instance = new BridgeDataFetcher(); + } + return BridgeDataFetcher.instance; + } + + private generateCacheKey( + sourceAssetDenom: string, + sourceAssetChainId: string + ): CacheKey { + return `${sourceAssetDenom}_${sourceAssetChainId}`; + } + + public async fetchBridgeData( + sourceAssetDenom: string, + sourceAssetChainId: string + ): Promise { + const cacheKey = this.generateCacheKey( + sourceAssetDenom, + sourceAssetChainId + ); + + if (this.cache.has(cacheKey)) { + return this.cache.get(cacheKey)!; + } + + const requestData: BridgeDataProviderParams = { + source_asset_denom: sourceAssetDenom, + source_asset_chain_id: sourceAssetChainId, + allow_multi_tx: false, + }; + + try { + const response = await axios.post(this.apiUrl, requestData, { + headers: { + "Content-Type": "application/json", + }, + }); + + const validResponse = bridgeDataProviderResponseSchema.parse( + response.data + ); + + this.cache.set(cacheKey, validResponse); + return response.data; + } catch (error) { + console.error("Error fetching assets:", error); + throw error; + } + } +} diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-data-provider.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-data-provider.ts new file mode 100644 index 00000000000..b20cc68124e --- /dev/null +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-data-provider.ts @@ -0,0 +1,33 @@ +import { IBridgeDataProvider } from "../../../shared/interfaces"; +import { BridgeDataFetcher } from "./bridge-data-fetcher"; + +export const bridgeDataProvider: IBridgeDataProvider = async ( + sourceAssetDenom: string, + sourceAssetChainId: string +) => { + const bridgeDataFetcher = BridgeDataFetcher.getInstance(); + const bridgeData = await bridgeDataFetcher.fetchBridgeData( + sourceAssetDenom, + sourceAssetChainId + ); + + const ibcAssetData = bridgeData.dest_assets[ + sourceAssetChainId + ]?.assets?.find(({ origin_denom }) => origin_denom === sourceAssetDenom); + + if (!ibcAssetData) { + throw new Error("No IBC asset data"); + } + + const channelId = ibcAssetData.trace.split("/")[0]; + + if (!channelId) { + throw new Error("No channel for bridge"); + } + + return { + channelId, + ibcDenom: ibcAssetData.denom, + portId: "transfer", + }; +}; diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/services/ibc-transfer-action-service.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/services/ibc-transfer-action-service.ts new file mode 100644 index 00000000000..1ba1e7a6d74 --- /dev/null +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/services/ibc-transfer-action-service.ts @@ -0,0 +1,129 @@ +import { + convertDisplayUnitToBaseUnit, + getAssetBySymbol, + getChainByChainName, +} from "@chain-registry/utils"; +import { assets, chains } from "chain-registry"; +import { getPaidFeeFromReceipt } from "../../../shared/helpers/cosmos-transaction-receipt.ts"; +import type { + IBridgeDataProvider, + ICosmosActionService, + ICosmosPluginCustomChainData, + ICosmosTransaction, + ICosmosWalletChains, +} from "../../../shared/interfaces.ts"; +import { CosmosTransactionFeeEstimator } from "../../../shared/services/cosmos-transaction-fee-estimator.ts"; +import { getAvailableAssets } from "../../../shared/helpers/cosmos-assets.ts"; +import { MsgTransfer } from "interchain/dist/codegen/ibc/applications/transfer/v1/tx"; +import { IBCTransferActionParams } from "../types.ts"; + +export class CosmosIBCTransferAction implements ICosmosActionService { + constructor(private cosmosWalletChains: ICosmosWalletChains) { + this.cosmosWalletChains = cosmosWalletChains; + } + + async execute( + params: IBCTransferActionParams, + bridgeDataProvider: IBridgeDataProvider, + customChainAssets?: ICosmosPluginCustomChainData["assets"][] + ): Promise { + const signingCosmWasmClient = + this.cosmosWalletChains.getSigningCosmWasmClient(params.chainName); + + const senderAddress = await this.cosmosWalletChains.getWalletAddress( + params.chainName + ); + + if (!senderAddress) { + throw new Error( + `Cannot get wallet address for chain ${params.chainName}` + ); + } + + if (!params.toAddress) { + throw new Error("No receiver address"); + } + + if (!params.targetChainName) { + throw new Error("No target chain name"); + } + + if (!params.chainName) { + throw new Error("No chain name"); + } + + if (!params.symbol) { + throw new Error("No symbol"); + } + + const availableAssets = getAvailableAssets(assets, customChainAssets); + + const denom = getAssetBySymbol( + availableAssets, + params.symbol, + params.chainName + ); + + const chain = getChainByChainName(chains, params.chainName); + + if (!denom.base) { + throw new Error("Cannot find asset"); + } + if (!chain) { + throw new Error("Cannot find chain"); + } + + const bridgeData = await bridgeDataProvider(denom.base, chain.chain_id); + + const now = BigInt(Date.now()) * BigInt(1_000_000); + const timeout = now + BigInt(5 * 60 * 1_000_000_000); + + const token: MsgTransfer["token"] = { + denom: bridgeData.ibcDenom, + amount: convertDisplayUnitToBaseUnit( + availableAssets, + params.symbol, + params.amount + ), + }; + + const message: MsgTransfer = { + sender: senderAddress, + receiver: params.toAddress, + sourceChannel: bridgeData.channelId, + sourcePort: bridgeData.portId, + timeoutTimestamp: timeout, + timeoutHeight: { + revisionHeight: BigInt(0), + revisionNumber: BigInt(0), + }, + token, + memo: "", + }; + + const gasFee = + await CosmosTransactionFeeEstimator.estimateGasForIBCTransfer( + signingCosmWasmClient, + message + ); + + const txDeliveryResponse = await signingCosmWasmClient.sendTokens( + senderAddress, + params.toAddress, + [token], + { + gas: gasFee.toString(), + amount: [{ ...token, amount: gasFee.toString() }], + } + ); + + const gasPaid = getPaidFeeFromReceipt(txDeliveryResponse); + + return { + from: senderAddress, + to: params.toAddress, + gasPaid, + txHash: txDeliveryResponse.transactionHash, + }; + } +} diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/types.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/types.ts new file mode 100644 index 00000000000..ba62b9cd48d --- /dev/null +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/types.ts @@ -0,0 +1,18 @@ +import { z } from "zod"; +import { + bridgeDataProviderParamsSchema, + bridgeDataProviderResponseAssetsSchema, + bridgeDataProviderResponseSchema, + IBCTransferParamsSchema, +} from "./schema"; + +export type IBCTransferActionParams = z.infer; +export type BridgeDataProviderParams = z.infer< + typeof bridgeDataProviderParamsSchema +>; +export type BridgeDataProviderResponseAsset = z.infer< + typeof bridgeDataProviderResponseAssetsSchema +>; +export type BridgeDataProviderResponse = z.infer< + typeof bridgeDataProviderResponseSchema +>; diff --git a/packages/plugin-cosmos/src/shared/helpers/cosmos-messages.ts b/packages/plugin-cosmos/src/shared/helpers/cosmos-messages.ts new file mode 100644 index 00000000000..af11af53d62 --- /dev/null +++ b/packages/plugin-cosmos/src/shared/helpers/cosmos-messages.ts @@ -0,0 +1,11 @@ +import { MsgTransferEncodeObject } from "@cosmjs/stargate"; +import { MsgTransfer } from "interchain/dist/codegen/ibc/applications/transfer/v1/tx"; + +export const generateIbcTransferMessage = ( + ibcTransferParams: MsgTransfer +): MsgTransferEncodeObject => { + return { + typeUrl: "/ibc.applications.transfer.v1.MsgTransfer", + value: ibcTransferParams, + }; +}; diff --git a/packages/plugin-cosmos/src/shared/interfaces.ts b/packages/plugin-cosmos/src/shared/interfaces.ts index 13b9b003a37..0c28abf2332 100644 --- a/packages/plugin-cosmos/src/shared/interfaces.ts +++ b/packages/plugin-cosmos/src/shared/interfaces.ts @@ -44,3 +44,10 @@ export interface ICosmosWalletChains { export interface ICosmosWalletChainsData { [chainName: string]: ICosmosChainWallet; } + +export interface IBridgeDataProvider { + ( + sourceAssetDenom: string, + sourceAssetChainId: string + ): Promise<{ channelId: string; portId: string; ibcDenom: string }>; +} diff --git a/packages/plugin-cosmos/src/shared/services/cosmos-transaction-fee-estimator.ts b/packages/plugin-cosmos/src/shared/services/cosmos-transaction-fee-estimator.ts index d9a09c29ffb..9016a5e916d 100644 --- a/packages/plugin-cosmos/src/shared/services/cosmos-transaction-fee-estimator.ts +++ b/packages/plugin-cosmos/src/shared/services/cosmos-transaction-fee-estimator.ts @@ -1,6 +1,8 @@ import type { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate"; import type { EncodeObject } from "@cosmjs/proto-signing"; import type { Coin, MsgSendEncodeObject } from "@cosmjs/stargate"; +import { MsgTransfer } from "interchain/dist/codegen/ibc/applications/transfer/v1/tx"; +import { generateIbcTransferMessage } from "../helpers/cosmos-messages"; export class CosmosTransactionFeeEstimator { private static async estimateGasForTransaction< @@ -46,4 +48,16 @@ export class CosmosTransactionFeeEstimator { memo ); } + static estimateGasForIBCTransfer( + signingCosmWasmClient: SigningCosmWasmClient, + ibcTransferParams: MsgTransfer, + memo = "" + ): Promise { + return this.estimateGasForTransaction( + signingCosmWasmClient, + ibcTransferParams.sender, + [generateIbcTransferMessage(ibcTransferParams)], + memo + ); + } } diff --git a/packages/plugin-cosmos/src/templates/index.ts b/packages/plugin-cosmos/src/templates/index.ts index 44fdf98aa0a..136a5dc78d1 100644 --- a/packages/plugin-cosmos/src/templates/index.ts +++ b/packages/plugin-cosmos/src/templates/index.ts @@ -34,6 +34,53 @@ Example reponse for the input: "Make transfer 0.0001 OM to mantra1pcnw46km8m5amv "toAddress": "mantra1pcnw46km8m5amvf7jlk2ks5std75k73aralhcf", "chainName": "mantrachaintestnet2" \`\`\` +Now respond with a JSON markdown block containing only the extracted values. +`; + +export const cosmosIBCTransferTemplate = `Given the recent messages and cosmos wallet information below: +{{recentMessages}} +{{walletInfo}} +Extract the following information about the requested IBC transfer: +1. **Amount**: + - Extract only the numeric value from the instruction. + - The value must be a string representing the amount in the display denomination (e.g., "0.0001" for ATOM, OSMO, etc.). Do not include the symbol. + +2. **Recipient Address**: + - Must be a valid Bech32 address that matches the target chain's address prefix. + - Example for "cosmoshub": "cosmos1pcnw46km8m5amvf7jlk2ks5std75k73aralhcf". + +3. **Token Symbol**: + - The symbol must be a string representing the token's display denomination (e.g., "ATOM", "OSMO", etc.). + +4. **Source Chain Name**: + - Identify the source chain mentioned in the instruction (e.g., cosmoshub, osmosis, axelar). + - Provide this as a string. + +5. **Target Chain Name**: + - Identify the target chain mentioned in the instruction (e.g., cosmoshub, osmosis, axelar). + - Provide this as a string. + +Respond with a JSON markdown block containing only the extracted values. All fields are required: +\`\`\`json +{ + "symbol": string, // The symbol of the token. + "amount": string, // The amount to transfer as a string. + "toAddress": string, // The recipient's address. + "chainName": string, // The source chain name. + "targetChainName": string // The target chain name. +} +\`\`\` + +Example response for the input: "Make an IBC transfer of 0.0001 ATOM to osmo1pcnw46km8m5amvf7jlk2ks5std75k73aralhcf from cosmoshub to osmosis", the response should be: +\`\`\`json +{ + "symbol": "ATOM", + "amount": "0.0001", + "toAddress": "osmo1pcnw46km8m5amvf7jlk2ks5std75k73aralhcf", + "chainName": "cosmoshub", + "targetChainName": "osmosis" +} +\`\`\` Now respond with a JSON markdown block containing only the extracted values. `; diff --git a/packages/plugin-cosmos/src/tests/bridge-data-fetcher.test.ts b/packages/plugin-cosmos/src/tests/bridge-data-fetcher.test.ts new file mode 100644 index 00000000000..406d8bd032a --- /dev/null +++ b/packages/plugin-cosmos/src/tests/bridge-data-fetcher.test.ts @@ -0,0 +1,101 @@ +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { BridgeDataFetcher } from "../actions/ibc-transfer/services/bridge-data-fetcher"; +import axios from "axios"; + +vi.mock("axios"); + +describe("BridgeDataFetcher", () => { + let fetcher: BridgeDataFetcher; + + beforeEach(() => { + fetcher = BridgeDataFetcher.getInstance(); + vi.clearAllMocks(); + }); + + it("should return the same instance from getInstance", () => { + const fetcher1 = BridgeDataFetcher.getInstance(); + const fetcher2 = BridgeDataFetcher.getInstance(); + expect(fetcher1).toBe(fetcher2); + }); + + it("should use cache when data is already fetched", async () => { + const mockResponse = { + dest_assets: { + someKey: { + assets: [ + { + denom: "atom", + chain_id: "cosmos", + origin_denom: "atom", + origin_chain_id: "cosmos", + trace: "someTrace", + symbol: "ATOM", + name: "Cosmos Atom", + logo_uri: "http://someurl.com/logo.png", + decimals: 6, + recommended_symbol: "ATOM", + }, + ], + }, + }, + }; + + // @ts-expect-error -- ... + axios.post.mockResolvedValueOnce({ data: mockResponse }); + + const sourceAssetDenom = "atom"; + const sourceAssetChainId = "cosmos"; + + await fetcher.fetchBridgeData(sourceAssetDenom, sourceAssetChainId); + + expect(axios.post).toHaveBeenCalledTimes(1); + + await fetcher.fetchBridgeData(sourceAssetDenom, sourceAssetChainId); + expect(axios.post).toHaveBeenCalledTimes(1); // axios nie powinien być wywołany ponownie + }); + + it("should fetch and cache data correctly", async () => { + const mockResponse = { + dest_assets: { + someKey: { + assets: [ + { + denom: "atom", + chain_id: "cosmos", + origin_denom: "atom", + origin_chain_id: "cosmos", + trace: "someTrace", + symbol: "ATOM", + name: "Cosmos Atom", + logo_uri: "http://someurl.com/logo.png", + decimals: 6, + recommended_symbol: "ATOM", + }, + ], + }, + }, + }; + + // @ts-expect-error -- ... + axios.post.mockResolvedValueOnce({ data: mockResponse }); + + const sourceAssetDenom = "atom"; + const sourceAssetChainId = "cosmos"; + + const result = await fetcher.fetchBridgeData( + sourceAssetDenom, + sourceAssetChainId + ); + + expect(result).toEqual(mockResponse); + + const cacheKey = `${sourceAssetDenom}_${sourceAssetChainId}`; + expect(fetcher["cache"].has(cacheKey)).toBe(true); + + const cachedResult = await fetcher.fetchBridgeData( + sourceAssetDenom, + sourceAssetChainId + ); + expect(cachedResult).toEqual(mockResponse); + }); +}); diff --git a/packages/plugin-cosmos/src/tests/bridge-data-provider.test.ts b/packages/plugin-cosmos/src/tests/bridge-data-provider.test.ts new file mode 100644 index 00000000000..f2834ad09a1 --- /dev/null +++ b/packages/plugin-cosmos/src/tests/bridge-data-provider.test.ts @@ -0,0 +1,103 @@ +import { bridgeDataProvider } from "../actions/ibc-transfer/services/bridge-data-provider"; +import { BridgeDataFetcher } from "../actions/ibc-transfer/services/bridge-data-fetcher"; +import { vi, expect, it, beforeEach, describe } from "vitest"; + +vi.mock("./bridge-data-fetcher", () => ({ + BridgeDataFetcher: { + getInstance: vi.fn().mockReturnValue({ + fetchBridgeData: vi.fn(), + }), + }, +})); + +describe("bridgeDataProvider", () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let mockFetchBridgeData: any; + + beforeEach(() => { + mockFetchBridgeData = vi.fn(); + BridgeDataFetcher.getInstance().fetchBridgeData = mockFetchBridgeData; + }); + + it("should return correct channelId and ibcDenom when valid data is returned", async () => { + const mockResponse = { + dest_assets: { + cosmos: { + assets: [ + { + origin_denom: "atom", + denom: "uatom", + trace: "channel-123/abc", + }, + ], + }, + }, + }; + + mockFetchBridgeData.mockResolvedValue(mockResponse); + + const sourceAssetDenom = "atom"; + const sourceAssetChainId = "cosmos"; + + const result = await bridgeDataProvider( + sourceAssetDenom, + sourceAssetChainId + ); + + expect(result).toEqual({ + channelId: "channel-123", + ibcDenom: "uatom", + portId: "transfer", + }); + }); + + it("should throw an error when ibcAssetData is not found", async () => { + const mockResponse = { + dest_assets: { + cosmos: { + assets: [ + { + origin_denom: "btc", + denom: "ubtc", + trace: "channel-123/abc", + }, + ], + }, + }, + }; + + mockFetchBridgeData.mockResolvedValue(mockResponse); + + const sourceAssetDenom = "atom"; + const sourceAssetChainId = "cosmos"; + + await expect( + bridgeDataProvider(sourceAssetDenom, sourceAssetChainId) + ).rejects.toThrowError(); + }); + + it("should throw an error when channelId is missing", async () => { + const mockResponse = { + dest_assets: { + cosmos: { + assets: [ + { + origin_denom: "atom", + denom: "uatom", + trace: "", + }, + ], + }, + }, + }; + + mockFetchBridgeData.mockResolvedValue(mockResponse); + + const sourceAssetDenom = "atom"; + const sourceAssetChainId = "cosmos"; + + await expect( + bridgeDataProvider(sourceAssetDenom, sourceAssetChainId) + ).rejects.toThrowError(); + }); +}); diff --git a/packages/plugin-cosmos/src/tests/cosmos-ibc-transfer-action-service.test.ts b/packages/plugin-cosmos/src/tests/cosmos-ibc-transfer-action-service.test.ts new file mode 100644 index 00000000000..fc7fbd5e6e0 --- /dev/null +++ b/packages/plugin-cosmos/src/tests/cosmos-ibc-transfer-action-service.test.ts @@ -0,0 +1,309 @@ +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { CosmosIBCTransferAction } from "../actions/ibc-transfer/services/ibc-transfer-action-service"; +import { IBCTransferActionParams } from "../actions/ibc-transfer/types"; +import { getAssetBySymbol, getChainByChainName } from "@chain-registry/utils"; + +vi.mock("@cosmjs/cosmwasm-stargate", () => ({ + SigningCosmWasmClient: { + connectWithSigner: vi.fn(), + }, +})); + +vi.mock("@chain-registry/utils", () => ({ + getAssetBySymbol: vi.fn().mockReturnValue({ base: "uatom" }), + getChainByChainName: vi + .fn() + .mockResolvedValue({ chain_id: "cosmos-chain-id" }), + convertDisplayUnitToBaseUnit: vi.fn().mockResolvedValue("100000000"), +})); + +vi.mock("../shared/services/cosmos-transaction-fee-estimator", () => ({ + CosmosTransactionFeeEstimator: { + estimateGasForIBCTransfer: vi.fn().mockResolvedValue(BigInt(200_000)), + }, +})); + +vi.mock("../shared/helpers/cosmos-assets", () => ({ + getAvailableAssets: vi.fn().mockResolvedValue([]), +})); + +vi.mock("../shared/helpers/cosmos-transaction-receipt.ts", () => ({ + getPaidFeeFromReceipt: vi.fn().mockReturnValue("200000"), +})); + +describe("CosmosIBCTransferAction", () => { + const mockSigningCosmWasmClient = { + sendTokens: vi.fn().mockResolvedValue({ + transactionHash: "mockTxHash", + }), + }; + + const mockCosmosWalletChains = { + walletChainsData: {}, + getWalletAddress: vi.fn().mockResolvedValue("senderAddress"), + getSigningCosmWasmClient: vi + .fn() + .mockReturnValue(mockSigningCosmWasmClient), + }; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("should execute transfer successfully", async () => { + const params: IBCTransferActionParams = { + chainName: "cosmos", + toAddress: "cosmosReceiverAddress", + targetChainName: "cosmosTarget", + symbol: "atom", + amount: "100", + }; + + const mockBridgeDataProvider = vi.fn().mockResolvedValue({ + ibcDenom: "uatom", + channelId: "channel-1", + portId: "transfer", + }); + + const cosmosIBCTransferAction = new CosmosIBCTransferAction( + mockCosmosWalletChains + ); + + const expectedResult = { + from: "senderAddress", + to: "cosmosReceiverAddress", + gasPaid: "200000", + txHash: "mockTxHash", + }; + + await expect( + cosmosIBCTransferAction.execute(params, mockBridgeDataProvider) + ).resolves.toEqual(expectedResult); + }); + + it("should throw error if transaction fails", async () => { + const params: IBCTransferActionParams = { + chainName: "cosmos", + toAddress: "cosmosReceiverAddress", + targetChainName: "cosmosTarget", + symbol: "atom", + amount: "100", + }; + + mockSigningCosmWasmClient.sendTokens.mockRejectedValue( + new Error("Transaction Failed") + ); + + const mockBridgeDataProvider = vi.fn().mockResolvedValue({ + ibcDenom: "uatom", + channelId: "channel-1", + portId: "transfer", + }); + + const cosmosIBCTransferAction = new CosmosIBCTransferAction( + mockCosmosWalletChains + ); + + await expect( + cosmosIBCTransferAction.execute(params, mockBridgeDataProvider) + ).rejects.toThrow("Transaction Failed"); + }); + + it("should throw error if no wallet address is found", async () => { + const params: IBCTransferActionParams = { + chainName: "cosmos", + toAddress: "cosmosReceiverAddress", + targetChainName: "cosmosTarget", + symbol: "atom", + amount: "100", + }; + + mockCosmosWalletChains.getWalletAddress.mockResolvedValue(null); // Brak adresu portfela + + const mockBridgeDataProvider = vi.fn().mockResolvedValue({ + ibcDenom: "uatom", + channelId: "channel-1", + portId: "transfer", + }); + + const cosmosIBCTransferAction = new CosmosIBCTransferAction( + mockCosmosWalletChains + ); + + await expect( + cosmosIBCTransferAction.execute(params, mockBridgeDataProvider) + ).rejects.toThrow("Cannot get wallet address for chain cosmos"); + }); + + it("should throw error if no receiver address is provided", async () => { + const params: IBCTransferActionParams = { + chainName: "cosmos", + toAddress: "", + targetChainName: "cosmosTarget", + symbol: "atom", + amount: "100", + }; + + const mockBridgeDataProvider = vi.fn().mockResolvedValue({ + ibcDenom: "uatom", + channelId: "channel-1", + portId: "transfer", + }); + mockCosmosWalletChains.getWalletAddress.mockResolvedValue( + "cosmos1address" + ); + + const cosmosIBCTransferAction = new CosmosIBCTransferAction( + mockCosmosWalletChains + ); + + await expect( + cosmosIBCTransferAction.execute(params, mockBridgeDataProvider) + ).rejects.toThrow("No receiver address"); + }); + + it("should throw error if no symbol is provided", async () => { + const params: IBCTransferActionParams = { + chainName: "cosmos", + toAddress: "cosmosReceiverAddress", + targetChainName: "cosmosTarget", + symbol: "", + amount: "100", + }; + + const mockBridgeDataProvider = vi.fn().mockResolvedValue({ + ibcDenom: "uatom", + channelId: "channel-1", + portId: "transfer", + }); + + mockCosmosWalletChains.getWalletAddress.mockResolvedValue( + "cosmos1address" + ); + + const cosmosIBCTransferAction = new CosmosIBCTransferAction( + mockCosmosWalletChains + ); + + await expect( + cosmosIBCTransferAction.execute(params, mockBridgeDataProvider) + ).rejects.toThrow("No symbol"); + }); + + it("should throw error if no chainName is provided", async () => { + const params: IBCTransferActionParams = { + chainName: "", + toAddress: "cosmosReceiverAddress", + targetChainName: "cosmosTarget", + symbol: "atom", + amount: "100", + }; + + const mockBridgeDataProvider = vi.fn().mockResolvedValue({ + ibcDenom: "uatom", + channelId: "channel-1", + portId: "transfer", + }); + + mockCosmosWalletChains.getWalletAddress.mockResolvedValue( + "cosmos1address" + ); + + const cosmosIBCTransferAction = new CosmosIBCTransferAction( + mockCosmosWalletChains + ); + + await expect( + cosmosIBCTransferAction.execute(params, mockBridgeDataProvider) + ).rejects.toThrow("No chain name"); + }); + it("should throw error if no targetChainName is provided", async () => { + const params: IBCTransferActionParams = { + chainName: "cosmos", + toAddress: "cosmosReceiverAddress", + targetChainName: "", + symbol: "atom", + amount: "100", + }; + + const mockBridgeDataProvider = vi.fn().mockResolvedValue({ + ibcDenom: "uatom", + channelId: "channel-1", + portId: "transfer", + }); + + mockCosmosWalletChains.getWalletAddress.mockResolvedValue( + "cosmos1address" + ); + + const cosmosIBCTransferAction = new CosmosIBCTransferAction( + mockCosmosWalletChains + ); + + await expect( + cosmosIBCTransferAction.execute(params, mockBridgeDataProvider) + ).rejects.toThrow("No target chain name"); + }); + it("should throw error if no base denom in assets list", async () => { + const params: IBCTransferActionParams = { + chainName: "cosmos", + toAddress: "cosmosReceiverAddress", + targetChainName: "cosmosTarget", + symbol: "atom", + amount: "100", + }; + + // @ts-expect-error --- + getAssetBySymbol.mockReturnValue({}); + + const mockBridgeDataProvider = vi.fn().mockResolvedValue({ + ibcDenom: "uatom", + channelId: "channel-1", + portId: "transfer", + }); + + mockCosmosWalletChains.getWalletAddress.mockResolvedValue( + "cosmos1address" + ); + + const cosmosIBCTransferAction = new CosmosIBCTransferAction( + mockCosmosWalletChains + ); + + await expect( + cosmosIBCTransferAction.execute(params, mockBridgeDataProvider) + ).rejects.toThrow("Cannot find asset"); + }); + + it("should throw error if no chain in chain list", async () => { + const params: IBCTransferActionParams = { + chainName: "cosmos", + toAddress: "cosmosReceiverAddress", + targetChainName: "cosmosTarget", + symbol: "atom", + amount: "100", + }; + // @ts-expect-error --- ... + getAssetBySymbol.mockReturnValue({ base: "uatom" }); + // @ts-expect-error --- ... + getChainByChainName.mockReturnValue(undefined); + + const mockBridgeDataProvider = vi.fn().mockResolvedValue({ + ibcDenom: "uatom", + channelId: "channel-1", + portId: "transfer", + }); + + mockCosmosWalletChains.getWalletAddress.mockResolvedValue( + "cosmos1address" + ); + + const cosmosIBCTransferAction = new CosmosIBCTransferAction( + mockCosmosWalletChains + ); + + await expect( + cosmosIBCTransferAction.execute(params, mockBridgeDataProvider) + ).rejects.toThrow("Cannot find chain"); + }); +}); diff --git a/packages/plugin-cosmos/src/tests/cosmos-message.test.ts b/packages/plugin-cosmos/src/tests/cosmos-message.test.ts new file mode 100644 index 00000000000..3a5a46c3d21 --- /dev/null +++ b/packages/plugin-cosmos/src/tests/cosmos-message.test.ts @@ -0,0 +1,33 @@ +import { describe, it, expect } from "vitest"; +import { generateIbcTransferMessage } from "../shared/helpers/cosmos-messages"; +import { MsgTransfer } from "interchain/dist/codegen/ibc/applications/transfer/v1/tx"; +import { MsgTransferEncodeObject } from "@cosmjs/stargate"; + +describe("generateIbcTransferMessage", () => { + it("should return a correctly formatted MsgTransferEncodeObject", () => { + const ibcTransferParams: MsgTransfer = { + sourcePort: "transfer", + sourceChannel: "channel-0", + token: { + denom: "uatom", + amount: "1000", + }, + sender: "cosmos1...", + receiver: "cosmos2...", + timeoutHeight: { + revisionHeight: BigInt(1000), + revisionNumber: BigInt(1), + }, + timeoutTimestamp: BigInt(1625140800), + memo: "", + }; + + const result: MsgTransferEncodeObject = + generateIbcTransferMessage(ibcTransferParams); + + expect(result).toEqual({ + typeUrl: "/ibc.applications.transfer.v1.MsgTransfer", + value: ibcTransferParams, + }); + }); +}); diff --git a/packages/plugin-cosmos/src/tests/cosmos-transaction-fee-estimator.test.ts b/packages/plugin-cosmos/src/tests/cosmos-transaction-fee-estimator.test.ts index bbbd3cc55ef..ed10781ecfe 100644 --- a/packages/plugin-cosmos/src/tests/cosmos-transaction-fee-estimator.test.ts +++ b/packages/plugin-cosmos/src/tests/cosmos-transaction-fee-estimator.test.ts @@ -1,6 +1,8 @@ import { describe, it, expect, vi, beforeEach, Mock } from "vitest"; import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate"; import { CosmosTransactionFeeEstimator } from "../shared/services/cosmos-transaction-fee-estimator"; +import { generateIbcTransferMessage } from "../shared/helpers/cosmos-messages"; +import { MsgTransfer } from "interchain/dist/codegen/ibc/applications/transfer/v1/tx"; vi.mock("@cosmjs/cosmwasm-stargate", () => ({ SigningCosmWasmClient: { @@ -8,6 +10,10 @@ vi.mock("@cosmjs/cosmwasm-stargate", () => ({ }, })); +vi.mock("../shared/helpers/cosmos-messages", () => ({ + generateIbcTransferMessage: vi.fn(), +})); + describe("FeeEstimator", () => { let mockSigningCosmWasmClient: SigningCosmWasmClient; @@ -91,4 +97,100 @@ describe("FeeEstimator", () => { "" ); }); + + it("should estimate gas for an IBC transfer successfully", async () => { + const mockGasEstimation = 300000; + + (mockSigningCosmWasmClient.simulate as Mock).mockResolvedValue( + mockGasEstimation + ); + + const ibcTransferParams: MsgTransfer = { + sourcePort: "transfer", + sourceChannel: "channel-0", + token: { denom: "uatom", amount: "1000000" }, + sender: "cosmos1senderaddress", + receiver: "cosmos1recipientaddress", + timeoutHeight: { + revisionNumber: BigInt(1), + revisionHeight: BigInt(1000), + }, + timeoutTimestamp: BigInt(0), + memo: "", + }; + + (generateIbcTransferMessage as Mock).mockReturnValue({ + typeUrl: "/ibc.applications.transfer.v1.MsgTransfer", + value: ibcTransferParams, + }); + + const memo = "IBC Test Memo"; + + const estimatedGas = + await CosmosTransactionFeeEstimator.estimateGasForIBCTransfer( + mockSigningCosmWasmClient, + ibcTransferParams, + memo + ); + + // Add 20% to the estimated gas to make sure we have enough gas to cover the transaction + expect(estimatedGas).toBe(mockGasEstimation + mockGasEstimation * 0.2); + + expect(mockSigningCosmWasmClient.simulate).toHaveBeenCalledWith( + ibcTransferParams.sender, + [ + { + typeUrl: "/ibc.applications.transfer.v1.MsgTransfer", + value: ibcTransferParams, + }, + ], + memo + ); + expect(generateIbcTransferMessage).toHaveBeenCalledWith( + ibcTransferParams + ); + }); + + it("should throw an error if gas estimation for IBC transfer fails", async () => { + (mockSigningCosmWasmClient.simulate as Mock).mockRejectedValue( + new Error("IBC gas estimation failed") + ); + + const ibcTransferParams: MsgTransfer = { + sourcePort: "transfer", + sourceChannel: "channel-0", + token: { denom: "uatom", amount: "1000000" }, + sender: "cosmos1senderaddress", + receiver: "cosmos1recipientaddress", + timeoutHeight: { + revisionNumber: BigInt(1), + revisionHeight: BigInt(1000), + }, + timeoutTimestamp: BigInt(0), + memo: "", + }; + + (generateIbcTransferMessage as Mock).mockReturnValue({ + typeUrl: "/ibc.applications.transfer.v1.MsgTransfer", + value: ibcTransferParams, + }); + + await expect( + CosmosTransactionFeeEstimator.estimateGasForIBCTransfer( + mockSigningCosmWasmClient, + ibcTransferParams + ) + ).rejects.toThrow("IBC gas estimation failed"); + + expect(mockSigningCosmWasmClient.simulate).toHaveBeenCalledWith( + ibcTransferParams.sender, + [ + { + typeUrl: "/ibc.applications.transfer.v1.MsgTransfer", + value: ibcTransferParams, + }, + ], + "" + ); + }); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dde34c9e572..7e49154580d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1200,18 +1200,28 @@ importers: '@elizaos/core': specifier: workspace:* version: link:../core + axios: + specifier: ^1.7.9 + version: 1.7.9(debug@4.4.0) bignumber.js: specifier: 9.1.2 version: 9.1.2 chain-registry: specifier: ^1.69.68 version: 1.69.86 + interchain: + specifier: ^1.10.4 + version: 1.10.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) tsup: specifier: 8.3.5 version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) zod: specifier: 3.23.8 version: 3.23.8 + devDependencies: + '@chain-registry/types': + specifier: ^0.50.44 + version: 0.50.45 packages/plugin-cronoszkevm: dependencies: @@ -3499,6 +3509,7 @@ packages: '@confio/ics23@0.6.8': resolution: {integrity: sha512-wB6uo+3A50m0sW/EWcU64xpV/8wShZ6bMTa7pF8eYsTrSkQA7oLUIJcs/wb8g4y2Oyq701BaGiO6n/ak5WXO1w==} + deprecated: Unmaintained. The codebase for this package was moved to https://github.com/cosmos/ics23 but then the JS implementation was removed in https://github.com/cosmos/ics23/pull/353. Please consult the maintainers of https://github.com/cosmos for further assistance. '@coral-xyz/anchor-errors@0.30.1': resolution: {integrity: sha512-9Mkradf5yS5xiLWrl9WrpjqOrAV+/W2RQHDlbnAZBivoGpOs1ECjoDCkVk4aRG8ZdiFiB8zQEVlxf+8fKkmSfQ==} @@ -3550,6 +3561,9 @@ packages: peerDependencies: '@solana/web3.js': ^1.68.0 + '@cosmjs/amino@0.32.2': + resolution: {integrity: sha512-lcK5RCVm4OfdAooxKcF2+NwaDVVpghOq6o/A40c2mHXDUzUoRZ33VAHjVJ9Me6vOFxshrw/XEFn1f4KObntjYA==} + '@cosmjs/amino@0.32.4': resolution: {integrity: sha512-zKYOt6hPy8obIFtLie/xtygCkH9ZROiQ12UHfKsOkWaZfPQUvVbtgmu6R4Kn1tFLI/SRkw7eqhaogmW/3NYu/Q==} @@ -3568,24 +3582,36 @@ packages: '@cosmjs/math@0.32.4': resolution: {integrity: sha512-++dqq2TJkoB8zsPVYCvrt88oJWsy1vMOuSOKcdlnXuOA/ASheTJuYy4+oZlTQ3Fr8eALDLGGPhJI02W2HyAQaw==} + '@cosmjs/proto-signing@0.32.2': + resolution: {integrity: sha512-UV4WwkE3W3G3s7wwU9rizNcUEz2g0W8jQZS5J6/3fiN0mRPwtPKQ6EinPN9ASqcAJ7/VQH4/9EPOw7d6XQGnqw==} + '@cosmjs/proto-signing@0.32.4': resolution: {integrity: sha512-QdyQDbezvdRI4xxSlyM1rSVBO2st5sqtbEIl3IX03uJ7YiZIQHyv6vaHVf1V4mapusCqguiHJzm4N4gsFdLBbQ==} '@cosmjs/socket@0.32.4': resolution: {integrity: sha512-davcyYziBhkzfXQTu1l5NrpDYv0K9GekZCC9apBRvL1dvMc9F/ygM7iemHjUA+z8tJkxKxrt/YPjJ6XNHzLrkw==} + '@cosmjs/stargate@0.32.2': + resolution: {integrity: sha512-AsJa29fT7Jd4xt9Ai+HMqhyj7UQu7fyYKdXj/8+/9PD74xe6lZSYhQPcitUmMLJ1ckKPgXSk5Dd2LbsQT0IhZg==} + '@cosmjs/stargate@0.32.4': resolution: {integrity: sha512-usj08LxBSsPRq9sbpCeVdyLx2guEcOHfJS9mHGCLCXpdAPEIEQEtWLDpEUc0LEhWOx6+k/ChXTc5NpFkdrtGUQ==} '@cosmjs/stream@0.32.4': resolution: {integrity: sha512-Gih++NYHEiP+oyD4jNEUxU9antoC0pFSg+33Hpp0JlHwH0wXhtD3OOKnzSfDB7OIoEbrzLJUpEjOgpCp5Z+W3A==} + '@cosmjs/tendermint-rpc@0.32.2': + resolution: {integrity: sha512-DXyJHDmcAfCix4H/7/dKR0UMdshP01KxJOXHdHxBCbLIpck94BsWD3B2ZTXwfA6sv98so9wOzhp7qGQa5malxg==} + '@cosmjs/tendermint-rpc@0.32.4': resolution: {integrity: sha512-MWvUUno+4bCb/LmlMIErLypXxy7ckUuzEmpufYYYd9wgbdCXaTaO08SZzyFM5PI8UJ/0S2AmUrgWhldlbxO8mw==} '@cosmjs/utils@0.32.4': resolution: {integrity: sha512-D1Yc+Zy8oL/hkUkFUL/bwxvuDBzRGpc4cF7/SkdhxX4iHpSLgdOuTt1mhCh9+kl6NQREy9t7SYZ6xeW5gFe60w==} + '@cosmology/lcd@0.13.5': + resolution: {integrity: sha512-CI8KFsJcgp0RINF8wHpv3Y9yR4Fb9ZnGucyoUICjtX2XT4NVBK+fvZuRFj5TP34km8TpEOb+WV2T7IN/pZsD7Q==} + '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -13587,6 +13613,9 @@ packages: int64-buffer@0.1.10: resolution: {integrity: sha512-v7cSY1J8ydZ0GyjUHqF+1bshJ6cnEVLo9EnjB8p+4HDRPZc9N5jjmvUV7NvEsqQOKyH0pmIBFWXVQbiS0+OBbA==} + interchain@1.10.4: + resolution: {integrity: sha512-tyJ3mfcuYqwLb3iZyuXDMOwMjWYptgiZrl6tu50pSSYoWrPN/9B6ztEC4IkYT1oKmWVOAiacNYuSRNmMUuWsmA==} + internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} @@ -23137,6 +23166,13 @@ snapshots: bn.js: 5.2.1 buffer-layout: 1.2.2 + '@cosmjs/amino@0.32.2': + dependencies: + '@cosmjs/crypto': 0.32.4 + '@cosmjs/encoding': 0.32.4 + '@cosmjs/math': 0.32.4 + '@cosmjs/utils': 0.32.4 + '@cosmjs/amino@0.32.4': dependencies: '@cosmjs/crypto': 0.32.4 @@ -23186,6 +23222,15 @@ snapshots: dependencies: bn.js: 5.2.1 + '@cosmjs/proto-signing@0.32.2': + dependencies: + '@cosmjs/amino': 0.32.4 + '@cosmjs/crypto': 0.32.4 + '@cosmjs/encoding': 0.32.4 + '@cosmjs/math': 0.32.4 + '@cosmjs/utils': 0.32.4 + cosmjs-types: 0.9.0 + '@cosmjs/proto-signing@0.32.4': dependencies: '@cosmjs/amino': 0.32.4 @@ -23205,6 +23250,23 @@ snapshots: - bufferutil - utf-8-validate + '@cosmjs/stargate@0.32.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@confio/ics23': 0.6.8 + '@cosmjs/amino': 0.32.4 + '@cosmjs/encoding': 0.32.4 + '@cosmjs/math': 0.32.4 + '@cosmjs/proto-signing': 0.32.4 + '@cosmjs/stream': 0.32.4 + '@cosmjs/tendermint-rpc': 0.32.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@cosmjs/utils': 0.32.4 + cosmjs-types: 0.9.0 + xstream: 11.14.0 + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate + '@cosmjs/stargate@0.32.4(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: '@confio/ics23': 0.6.8 @@ -23226,6 +23288,23 @@ snapshots: dependencies: xstream: 11.14.0 + '@cosmjs/tendermint-rpc@0.32.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@cosmjs/crypto': 0.32.4 + '@cosmjs/encoding': 0.32.4 + '@cosmjs/json-rpc': 0.32.4 + '@cosmjs/math': 0.32.4 + '@cosmjs/socket': 0.32.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@cosmjs/stream': 0.32.4 + '@cosmjs/utils': 0.32.4 + axios: 1.7.9(debug@4.4.0) + readonly-date: 1.0.0 + xstream: 11.14.0 + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate + '@cosmjs/tendermint-rpc@0.32.4(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: '@cosmjs/crypto': 0.32.4 @@ -23245,6 +23324,12 @@ snapshots: '@cosmjs/utils@0.32.4': {} + '@cosmology/lcd@0.13.5': + dependencies: + axios: 1.7.4 + transitivePeerDependencies: + - debug + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 @@ -36319,7 +36404,7 @@ snapshots: extract-zip@2.0.1: dependencies: - debug: 4.3.4 + debug: 4.4.0(supports-color@8.1.1) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -37906,6 +37991,18 @@ snapshots: int64-buffer@0.1.10: {} + interchain@1.10.4(bufferutil@4.0.9)(utf-8-validate@5.0.10): + dependencies: + '@cosmjs/amino': 0.32.2 + '@cosmjs/proto-signing': 0.32.2 + '@cosmjs/stargate': 0.32.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@cosmjs/tendermint-rpc': 0.32.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@cosmology/lcd': 0.13.5 + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 From 6a929a10131ff489d63d4b15520bfd5d216ef31b Mon Sep 17 00:00:00 2001 From: KacperKoza34 Date: Wed, 8 Jan 2025 16:53:09 +0100 Subject: [PATCH 2/8] refactor: remove redundant services and use skipClient --- packages/plugin-cosmos/package.json | 1 + .../src/actions/ibc-transfer/index.ts | 6 +- .../src/actions/ibc-transfer/schema.ts | 28 ----- .../services/bridge-data-fetcher.ts | 68 ------------ .../services/bridge-data-provider.ts | 33 ------ .../services/ibc-transfer-action-service.ts | 97 +++++++---------- .../src/actions/ibc-transfer/types.ts | 16 +-- .../entities/cosmos-wallet-chains-data.ts | 14 +++ .../src/shared/helpers/cosmos-messages.ts | 11 -- .../plugin-cosmos/src/shared/interfaces.ts | 5 +- .../cosmos-transaction-fee-estimator.ts | 14 --- .../src/tests/bridge-data-fetcher.test.ts | 101 ----------------- .../src/tests/bridge-data-provider.test.ts | 103 ------------------ ...cosmos-ibc-transfer-action-service.test.ts | 22 ++-- .../src/tests/cosmos-message.test.ts | 33 ------ .../cosmos-transaction-fee-estimator.test.ts | 98 ----------------- packages/plugin-cosmos/tsup.config.ts | 1 + 17 files changed, 75 insertions(+), 576 deletions(-) delete mode 100644 packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-data-fetcher.ts delete mode 100644 packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-data-provider.ts delete mode 100644 packages/plugin-cosmos/src/shared/helpers/cosmos-messages.ts delete mode 100644 packages/plugin-cosmos/src/tests/bridge-data-fetcher.test.ts delete mode 100644 packages/plugin-cosmos/src/tests/bridge-data-provider.test.ts delete mode 100644 packages/plugin-cosmos/src/tests/cosmos-message.test.ts diff --git a/packages/plugin-cosmos/package.json b/packages/plugin-cosmos/package.json index b052b3060ed..90004ab76bd 100644 --- a/packages/plugin-cosmos/package.json +++ b/packages/plugin-cosmos/package.json @@ -10,6 +10,7 @@ "@cosmjs/cosmwasm-stargate": "^0.32.4", "@cosmjs/proto-signing": "^0.32.4", "@cosmjs/stargate": "^0.32.4", + "@skip-go/client": "^0.16.3", "axios": "^1.7.9", "bignumber.js": "9.1.2", "chain-registry": "^1.69.68", diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts index f0833c3983b..687d315f11f 100644 --- a/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts @@ -17,8 +17,7 @@ import type { ICosmosWalletChains, } from "../../shared/interfaces"; import { IBCTransferActionParams } from "./types"; -import { CosmosIBCTransferAction } from "./services/ibc-transfer-action-service"; -import { bridgeDataProvider } from "./services/bridge-data-provider"; +import { IBCTransferAction } from "./services/ibc-transfer-action-service"; export const createIBCTransferAction = ( pluginOptions: ICosmosPluginOptions @@ -56,7 +55,7 @@ export const createIBCTransferAction = ( const walletProvider: ICosmosWalletChains = await initWalletChainsData(_runtime); - const action = new CosmosIBCTransferAction(walletProvider); + const action = new IBCTransferAction(walletProvider); const customAssets = (pluginOptions?.customChainData ?? []).map( (chainData) => chainData.assets @@ -64,7 +63,6 @@ export const createIBCTransferAction = ( const transferResp = await action.execute( paramOptions, - bridgeDataProvider, customAssets ); diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/schema.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/schema.ts index 018e892d242..62e30be681d 100644 --- a/packages/plugin-cosmos/src/actions/ibc-transfer/schema.ts +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/schema.ts @@ -7,31 +7,3 @@ export const IBCTransferParamsSchema = z.object({ toAddress: z.string(), targetChainName: z.string(), }); - -export const bridgeDataProviderParamsSchema = z.object({ - source_asset_denom: z.string(), - source_asset_chain_id: z.string(), - allow_multi_tx: z.boolean(), -}); - -export const bridgeDataProviderResponseAssetsSchema = z.object({ - denom: z.string(), - chain_id: z.string(), - origin_denom: z.string(), - origin_chain_id: z.string(), - trace: z.string(), - symbol: z.string().optional(), - name: z.string().optional(), - logo_uri: z.string().optional(), - decimals: z.number().optional(), - recommended_symbol: z.string().optional(), -}); - -export const bridgeDataProviderResponseSchema = z.object({ - dest_assets: z.record( - z.string(), - z.object({ - assets: z.array(bridgeDataProviderResponseAssetsSchema), - }) - ), -}); diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-data-fetcher.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-data-fetcher.ts deleted file mode 100644 index 1ababb35214..00000000000 --- a/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-data-fetcher.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { bridgeDataProviderResponseSchema } from "../schema"; -import { BridgeDataProviderParams, BridgeDataProviderResponse } from "../types"; -import axios from "axios"; - -type CacheKey = `${string}_${string}`; - -export class BridgeDataFetcher { - private static instance: BridgeDataFetcher; - private cache: Map; - private readonly apiUrl: string; - - private constructor() { - this.cache = new Map(); - this.apiUrl = "https://api.skip.build/v2/fungible/assets_from_source"; - } - - public static getInstance(): BridgeDataFetcher { - if (!BridgeDataFetcher.instance) { - BridgeDataFetcher.instance = new BridgeDataFetcher(); - } - return BridgeDataFetcher.instance; - } - - private generateCacheKey( - sourceAssetDenom: string, - sourceAssetChainId: string - ): CacheKey { - return `${sourceAssetDenom}_${sourceAssetChainId}`; - } - - public async fetchBridgeData( - sourceAssetDenom: string, - sourceAssetChainId: string - ): Promise { - const cacheKey = this.generateCacheKey( - sourceAssetDenom, - sourceAssetChainId - ); - - if (this.cache.has(cacheKey)) { - return this.cache.get(cacheKey)!; - } - - const requestData: BridgeDataProviderParams = { - source_asset_denom: sourceAssetDenom, - source_asset_chain_id: sourceAssetChainId, - allow_multi_tx: false, - }; - - try { - const response = await axios.post(this.apiUrl, requestData, { - headers: { - "Content-Type": "application/json", - }, - }); - - const validResponse = bridgeDataProviderResponseSchema.parse( - response.data - ); - - this.cache.set(cacheKey, validResponse); - return response.data; - } catch (error) { - console.error("Error fetching assets:", error); - throw error; - } - } -} diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-data-provider.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-data-provider.ts deleted file mode 100644 index b20cc68124e..00000000000 --- a/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-data-provider.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { IBridgeDataProvider } from "../../../shared/interfaces"; -import { BridgeDataFetcher } from "./bridge-data-fetcher"; - -export const bridgeDataProvider: IBridgeDataProvider = async ( - sourceAssetDenom: string, - sourceAssetChainId: string -) => { - const bridgeDataFetcher = BridgeDataFetcher.getInstance(); - const bridgeData = await bridgeDataFetcher.fetchBridgeData( - sourceAssetDenom, - sourceAssetChainId - ); - - const ibcAssetData = bridgeData.dest_assets[ - sourceAssetChainId - ]?.assets?.find(({ origin_denom }) => origin_denom === sourceAssetDenom); - - if (!ibcAssetData) { - throw new Error("No IBC asset data"); - } - - const channelId = ibcAssetData.trace.split("/")[0]; - - if (!channelId) { - throw new Error("No channel for bridge"); - } - - return { - channelId, - ibcDenom: ibcAssetData.denom, - portId: "transfer", - }; -}; diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/services/ibc-transfer-action-service.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/services/ibc-transfer-action-service.ts index 1ba1e7a6d74..7a132eb2995 100644 --- a/packages/plugin-cosmos/src/actions/ibc-transfer/services/ibc-transfer-action-service.ts +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/services/ibc-transfer-action-service.ts @@ -1,39 +1,35 @@ import { - convertDisplayUnitToBaseUnit, getAssetBySymbol, getChainByChainName, + getChainIdByChainName, } from "@chain-registry/utils"; import { assets, chains } from "chain-registry"; -import { getPaidFeeFromReceipt } from "../../../shared/helpers/cosmos-transaction-receipt.ts"; import type { - IBridgeDataProvider, ICosmosActionService, ICosmosPluginCustomChainData, ICosmosTransaction, ICosmosWalletChains, } from "../../../shared/interfaces.ts"; -import { CosmosTransactionFeeEstimator } from "../../../shared/services/cosmos-transaction-fee-estimator.ts"; import { getAvailableAssets } from "../../../shared/helpers/cosmos-assets.ts"; -import { MsgTransfer } from "interchain/dist/codegen/ibc/applications/transfer/v1/tx"; import { IBCTransferActionParams } from "../types.ts"; -export class CosmosIBCTransferAction implements ICosmosActionService { +export class IBCTransferAction implements ICosmosActionService { constructor(private cosmosWalletChains: ICosmosWalletChains) { this.cosmosWalletChains = cosmosWalletChains; } async execute( params: IBCTransferActionParams, - bridgeDataProvider: IBridgeDataProvider, customChainAssets?: ICosmosPluginCustomChainData["assets"][] ): Promise { - const signingCosmWasmClient = - this.cosmosWalletChains.getSigningCosmWasmClient(params.chainName); - const senderAddress = await this.cosmosWalletChains.getWalletAddress( params.chainName ); + const skipClient = this.cosmosWalletChains.getSkipClient( + params.chainName + ); + if (!senderAddress) { throw new Error( `Cannot get wallet address for chain ${params.chainName}` @@ -64,66 +60,55 @@ export class CosmosIBCTransferAction implements ICosmosActionService { params.chainName ); - const chain = getChainByChainName(chains, params.chainName); + const sourceChain = getChainByChainName(chains, params.chainName); + const destChain = getChainByChainName(chains, params.targetChainName); if (!denom.base) { throw new Error("Cannot find asset"); } - if (!chain) { - throw new Error("Cannot find chain"); + if (!sourceChain) { + throw new Error("Cannot find source chain"); } - const bridgeData = await bridgeDataProvider(denom.base, chain.chain_id); + if (!destChain) { + throw new Error("Cannot find destination chain"); + } - const now = BigInt(Date.now()) * BigInt(1_000_000); - const timeout = now + BigInt(5 * 60 * 1_000_000_000); + const route = await skipClient.route({ + destAssetChainID: destChain.chain_id, + destAssetDenom: denom.base, + sourceAssetChainID: sourceChain.chain_id, + sourceAssetDenom: denom.base, + amountOut: params.amount, + }); + + const userAddresses = await Promise.all( + route.requiredChainAddresses.map(async (chainID) => { + const chainName = getChainIdByChainName(chains, chainID); + return { + chainID, + address: + await this.cosmosWalletChains.getWalletAddress( + chainName + ), + }; + }) + ); - const token: MsgTransfer["token"] = { - denom: bridgeData.ibcDenom, - amount: convertDisplayUnitToBaseUnit( - availableAssets, - params.symbol, - params.amount - ), - }; + let txHash: string | undefined; - const message: MsgTransfer = { - sender: senderAddress, - receiver: params.toAddress, - sourceChannel: bridgeData.channelId, - sourcePort: bridgeData.portId, - timeoutTimestamp: timeout, - timeoutHeight: { - revisionHeight: BigInt(0), - revisionNumber: BigInt(0), + await skipClient.executeRoute({ + route, + userAddresses, + onTransactionCompleted: async (_, executeRouteTxHash) => { + txHash = executeRouteTxHash; }, - token, - memo: "", - }; - - const gasFee = - await CosmosTransactionFeeEstimator.estimateGasForIBCTransfer( - signingCosmWasmClient, - message - ); - - const txDeliveryResponse = await signingCosmWasmClient.sendTokens( - senderAddress, - params.toAddress, - [token], - { - gas: gasFee.toString(), - amount: [{ ...token, amount: gasFee.toString() }], - } - ); - - const gasPaid = getPaidFeeFromReceipt(txDeliveryResponse); + }); return { from: senderAddress, to: params.toAddress, - gasPaid, - txHash: txDeliveryResponse.transactionHash, + txHash, }; } } diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/types.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/types.ts index ba62b9cd48d..349bfb2fb81 100644 --- a/packages/plugin-cosmos/src/actions/ibc-transfer/types.ts +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/types.ts @@ -1,18 +1,4 @@ import { z } from "zod"; -import { - bridgeDataProviderParamsSchema, - bridgeDataProviderResponseAssetsSchema, - bridgeDataProviderResponseSchema, - IBCTransferParamsSchema, -} from "./schema"; +import { IBCTransferParamsSchema } from "./schema"; export type IBCTransferActionParams = z.infer; -export type BridgeDataProviderParams = z.infer< - typeof bridgeDataProviderParamsSchema ->; -export type BridgeDataProviderResponseAsset = z.infer< - typeof bridgeDataProviderResponseAssetsSchema ->; -export type BridgeDataProviderResponse = z.infer< - typeof bridgeDataProviderResponseSchema ->; diff --git a/packages/plugin-cosmos/src/shared/entities/cosmos-wallet-chains-data.ts b/packages/plugin-cosmos/src/shared/entities/cosmos-wallet-chains-data.ts index fbe0322c270..3c4cc70f9a4 100644 --- a/packages/plugin-cosmos/src/shared/entities/cosmos-wallet-chains-data.ts +++ b/packages/plugin-cosmos/src/shared/entities/cosmos-wallet-chains-data.ts @@ -8,6 +8,7 @@ import type { ICosmosWalletChainsData, } from "../interfaces"; import { getAvailableChains } from "../helpers/cosmos-chains"; +import { SkipClient } from "@skip-go/client"; export class CosmosWalletChains implements ICosmosWalletChains { public walletChainsData: ICosmosWalletChainsData = {}; @@ -49,9 +50,14 @@ export class CosmosWalletChains implements ICosmosWalletChains { wallet.directSecp256k1HdWallet ); + const skipClient = new SkipClient({ + getCosmosSigner: async () => wallet.directSecp256k1HdWallet, + }); + walletChainsData[chainName] = { wallet, signingCosmWasmClient, + skipClient, }; } @@ -65,4 +71,12 @@ export class CosmosWalletChains implements ICosmosWalletChains { public getSigningCosmWasmClient(chainName: string) { return this.walletChainsData[chainName].signingCosmWasmClient; } + + public getSkipClient(chainName: string): SkipClient { + return this.walletChainsData[chainName].skipClient; + } + + public async getUserAddress(chainName: string): Promise { + return this.walletChainsData[chainName].wallet.getWalletAddress(); + } } diff --git a/packages/plugin-cosmos/src/shared/helpers/cosmos-messages.ts b/packages/plugin-cosmos/src/shared/helpers/cosmos-messages.ts deleted file mode 100644 index af11af53d62..00000000000 --- a/packages/plugin-cosmos/src/shared/helpers/cosmos-messages.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { MsgTransferEncodeObject } from "@cosmjs/stargate"; -import { MsgTransfer } from "interchain/dist/codegen/ibc/applications/transfer/v1/tx"; - -export const generateIbcTransferMessage = ( - ibcTransferParams: MsgTransfer -): MsgTransferEncodeObject => { - return { - typeUrl: "/ibc.applications.transfer.v1.MsgTransfer", - value: ibcTransferParams, - }; -}; diff --git a/packages/plugin-cosmos/src/shared/interfaces.ts b/packages/plugin-cosmos/src/shared/interfaces.ts index 0c28abf2332..2f4dc2438c3 100644 --- a/packages/plugin-cosmos/src/shared/interfaces.ts +++ b/packages/plugin-cosmos/src/shared/interfaces.ts @@ -1,6 +1,7 @@ import type { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate"; import type { Coin, DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"; import type { assets, chains } from "chain-registry"; +import { SkipClient } from "@skip-go/client"; export interface ICosmosPluginCustomChainData { chainData: (typeof chains)[number]; @@ -19,7 +20,7 @@ export interface ICosmosTransaction { from: string; to: string; txHash: string; - gasPaid: number; + gasPaid?: number; } export interface ICosmosWallet { @@ -32,6 +33,7 @@ export interface ICosmosWallet { export interface ICosmosChainWallet { wallet: ICosmosWallet; signingCosmWasmClient: SigningCosmWasmClient; + skipClient: SkipClient; } export interface ICosmosWalletChains { @@ -39,6 +41,7 @@ export interface ICosmosWalletChains { getWalletAddress(chainName: string): Promise; getSigningCosmWasmClient(chainName: string): SigningCosmWasmClient; + getSkipClient(chainName: string): SkipClient; } export interface ICosmosWalletChainsData { diff --git a/packages/plugin-cosmos/src/shared/services/cosmos-transaction-fee-estimator.ts b/packages/plugin-cosmos/src/shared/services/cosmos-transaction-fee-estimator.ts index 9016a5e916d..d9a09c29ffb 100644 --- a/packages/plugin-cosmos/src/shared/services/cosmos-transaction-fee-estimator.ts +++ b/packages/plugin-cosmos/src/shared/services/cosmos-transaction-fee-estimator.ts @@ -1,8 +1,6 @@ import type { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate"; import type { EncodeObject } from "@cosmjs/proto-signing"; import type { Coin, MsgSendEncodeObject } from "@cosmjs/stargate"; -import { MsgTransfer } from "interchain/dist/codegen/ibc/applications/transfer/v1/tx"; -import { generateIbcTransferMessage } from "../helpers/cosmos-messages"; export class CosmosTransactionFeeEstimator { private static async estimateGasForTransaction< @@ -48,16 +46,4 @@ export class CosmosTransactionFeeEstimator { memo ); } - static estimateGasForIBCTransfer( - signingCosmWasmClient: SigningCosmWasmClient, - ibcTransferParams: MsgTransfer, - memo = "" - ): Promise { - return this.estimateGasForTransaction( - signingCosmWasmClient, - ibcTransferParams.sender, - [generateIbcTransferMessage(ibcTransferParams)], - memo - ); - } } diff --git a/packages/plugin-cosmos/src/tests/bridge-data-fetcher.test.ts b/packages/plugin-cosmos/src/tests/bridge-data-fetcher.test.ts deleted file mode 100644 index 406d8bd032a..00000000000 --- a/packages/plugin-cosmos/src/tests/bridge-data-fetcher.test.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { describe, it, expect, vi, beforeEach } from "vitest"; -import { BridgeDataFetcher } from "../actions/ibc-transfer/services/bridge-data-fetcher"; -import axios from "axios"; - -vi.mock("axios"); - -describe("BridgeDataFetcher", () => { - let fetcher: BridgeDataFetcher; - - beforeEach(() => { - fetcher = BridgeDataFetcher.getInstance(); - vi.clearAllMocks(); - }); - - it("should return the same instance from getInstance", () => { - const fetcher1 = BridgeDataFetcher.getInstance(); - const fetcher2 = BridgeDataFetcher.getInstance(); - expect(fetcher1).toBe(fetcher2); - }); - - it("should use cache when data is already fetched", async () => { - const mockResponse = { - dest_assets: { - someKey: { - assets: [ - { - denom: "atom", - chain_id: "cosmos", - origin_denom: "atom", - origin_chain_id: "cosmos", - trace: "someTrace", - symbol: "ATOM", - name: "Cosmos Atom", - logo_uri: "http://someurl.com/logo.png", - decimals: 6, - recommended_symbol: "ATOM", - }, - ], - }, - }, - }; - - // @ts-expect-error -- ... - axios.post.mockResolvedValueOnce({ data: mockResponse }); - - const sourceAssetDenom = "atom"; - const sourceAssetChainId = "cosmos"; - - await fetcher.fetchBridgeData(sourceAssetDenom, sourceAssetChainId); - - expect(axios.post).toHaveBeenCalledTimes(1); - - await fetcher.fetchBridgeData(sourceAssetDenom, sourceAssetChainId); - expect(axios.post).toHaveBeenCalledTimes(1); // axios nie powinien być wywołany ponownie - }); - - it("should fetch and cache data correctly", async () => { - const mockResponse = { - dest_assets: { - someKey: { - assets: [ - { - denom: "atom", - chain_id: "cosmos", - origin_denom: "atom", - origin_chain_id: "cosmos", - trace: "someTrace", - symbol: "ATOM", - name: "Cosmos Atom", - logo_uri: "http://someurl.com/logo.png", - decimals: 6, - recommended_symbol: "ATOM", - }, - ], - }, - }, - }; - - // @ts-expect-error -- ... - axios.post.mockResolvedValueOnce({ data: mockResponse }); - - const sourceAssetDenom = "atom"; - const sourceAssetChainId = "cosmos"; - - const result = await fetcher.fetchBridgeData( - sourceAssetDenom, - sourceAssetChainId - ); - - expect(result).toEqual(mockResponse); - - const cacheKey = `${sourceAssetDenom}_${sourceAssetChainId}`; - expect(fetcher["cache"].has(cacheKey)).toBe(true); - - const cachedResult = await fetcher.fetchBridgeData( - sourceAssetDenom, - sourceAssetChainId - ); - expect(cachedResult).toEqual(mockResponse); - }); -}); diff --git a/packages/plugin-cosmos/src/tests/bridge-data-provider.test.ts b/packages/plugin-cosmos/src/tests/bridge-data-provider.test.ts deleted file mode 100644 index f2834ad09a1..00000000000 --- a/packages/plugin-cosmos/src/tests/bridge-data-provider.test.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { bridgeDataProvider } from "../actions/ibc-transfer/services/bridge-data-provider"; -import { BridgeDataFetcher } from "../actions/ibc-transfer/services/bridge-data-fetcher"; -import { vi, expect, it, beforeEach, describe } from "vitest"; - -vi.mock("./bridge-data-fetcher", () => ({ - BridgeDataFetcher: { - getInstance: vi.fn().mockReturnValue({ - fetchBridgeData: vi.fn(), - }), - }, -})); - -describe("bridgeDataProvider", () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let mockFetchBridgeData: any; - - beforeEach(() => { - mockFetchBridgeData = vi.fn(); - BridgeDataFetcher.getInstance().fetchBridgeData = mockFetchBridgeData; - }); - - it("should return correct channelId and ibcDenom when valid data is returned", async () => { - const mockResponse = { - dest_assets: { - cosmos: { - assets: [ - { - origin_denom: "atom", - denom: "uatom", - trace: "channel-123/abc", - }, - ], - }, - }, - }; - - mockFetchBridgeData.mockResolvedValue(mockResponse); - - const sourceAssetDenom = "atom"; - const sourceAssetChainId = "cosmos"; - - const result = await bridgeDataProvider( - sourceAssetDenom, - sourceAssetChainId - ); - - expect(result).toEqual({ - channelId: "channel-123", - ibcDenom: "uatom", - portId: "transfer", - }); - }); - - it("should throw an error when ibcAssetData is not found", async () => { - const mockResponse = { - dest_assets: { - cosmos: { - assets: [ - { - origin_denom: "btc", - denom: "ubtc", - trace: "channel-123/abc", - }, - ], - }, - }, - }; - - mockFetchBridgeData.mockResolvedValue(mockResponse); - - const sourceAssetDenom = "atom"; - const sourceAssetChainId = "cosmos"; - - await expect( - bridgeDataProvider(sourceAssetDenom, sourceAssetChainId) - ).rejects.toThrowError(); - }); - - it("should throw an error when channelId is missing", async () => { - const mockResponse = { - dest_assets: { - cosmos: { - assets: [ - { - origin_denom: "atom", - denom: "uatom", - trace: "", - }, - ], - }, - }, - }; - - mockFetchBridgeData.mockResolvedValue(mockResponse); - - const sourceAssetDenom = "atom"; - const sourceAssetChainId = "cosmos"; - - await expect( - bridgeDataProvider(sourceAssetDenom, sourceAssetChainId) - ).rejects.toThrowError(); - }); -}); diff --git a/packages/plugin-cosmos/src/tests/cosmos-ibc-transfer-action-service.test.ts b/packages/plugin-cosmos/src/tests/cosmos-ibc-transfer-action-service.test.ts index fc7fbd5e6e0..1c1b3dbf7b3 100644 --- a/packages/plugin-cosmos/src/tests/cosmos-ibc-transfer-action-service.test.ts +++ b/packages/plugin-cosmos/src/tests/cosmos-ibc-transfer-action-service.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; -import { CosmosIBCTransferAction } from "../actions/ibc-transfer/services/ibc-transfer-action-service"; +import { IBCTransferAction } from "../actions/ibc-transfer/services/ibc-transfer-action-service"; import { IBCTransferActionParams } from "../actions/ibc-transfer/types"; import { getAssetBySymbol, getChainByChainName } from "@chain-registry/utils"; @@ -31,7 +31,7 @@ vi.mock("../shared/helpers/cosmos-transaction-receipt.ts", () => ({ getPaidFeeFromReceipt: vi.fn().mockReturnValue("200000"), })); -describe("CosmosIBCTransferAction", () => { +describe("IBCTransferAction", () => { const mockSigningCosmWasmClient = { sendTokens: vi.fn().mockResolvedValue({ transactionHash: "mockTxHash", @@ -65,7 +65,7 @@ describe("CosmosIBCTransferAction", () => { portId: "transfer", }); - const cosmosIBCTransferAction = new CosmosIBCTransferAction( + const cosmosIBCTransferAction = new IBCTransferAction( mockCosmosWalletChains ); @@ -100,7 +100,7 @@ describe("CosmosIBCTransferAction", () => { portId: "transfer", }); - const cosmosIBCTransferAction = new CosmosIBCTransferAction( + const cosmosIBCTransferAction = new IBCTransferAction( mockCosmosWalletChains ); @@ -126,7 +126,7 @@ describe("CosmosIBCTransferAction", () => { portId: "transfer", }); - const cosmosIBCTransferAction = new CosmosIBCTransferAction( + const cosmosIBCTransferAction = new IBCTransferAction( mockCosmosWalletChains ); @@ -153,7 +153,7 @@ describe("CosmosIBCTransferAction", () => { "cosmos1address" ); - const cosmosIBCTransferAction = new CosmosIBCTransferAction( + const cosmosIBCTransferAction = new IBCTransferAction( mockCosmosWalletChains ); @@ -181,7 +181,7 @@ describe("CosmosIBCTransferAction", () => { "cosmos1address" ); - const cosmosIBCTransferAction = new CosmosIBCTransferAction( + const cosmosIBCTransferAction = new IBCTransferAction( mockCosmosWalletChains ); @@ -209,7 +209,7 @@ describe("CosmosIBCTransferAction", () => { "cosmos1address" ); - const cosmosIBCTransferAction = new CosmosIBCTransferAction( + const cosmosIBCTransferAction = new IBCTransferAction( mockCosmosWalletChains ); @@ -236,7 +236,7 @@ describe("CosmosIBCTransferAction", () => { "cosmos1address" ); - const cosmosIBCTransferAction = new CosmosIBCTransferAction( + const cosmosIBCTransferAction = new IBCTransferAction( mockCosmosWalletChains ); @@ -266,7 +266,7 @@ describe("CosmosIBCTransferAction", () => { "cosmos1address" ); - const cosmosIBCTransferAction = new CosmosIBCTransferAction( + const cosmosIBCTransferAction = new IBCTransferAction( mockCosmosWalletChains ); @@ -298,7 +298,7 @@ describe("CosmosIBCTransferAction", () => { "cosmos1address" ); - const cosmosIBCTransferAction = new CosmosIBCTransferAction( + const cosmosIBCTransferAction = new IBCTransferAction( mockCosmosWalletChains ); diff --git a/packages/plugin-cosmos/src/tests/cosmos-message.test.ts b/packages/plugin-cosmos/src/tests/cosmos-message.test.ts deleted file mode 100644 index 3a5a46c3d21..00000000000 --- a/packages/plugin-cosmos/src/tests/cosmos-message.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { describe, it, expect } from "vitest"; -import { generateIbcTransferMessage } from "../shared/helpers/cosmos-messages"; -import { MsgTransfer } from "interchain/dist/codegen/ibc/applications/transfer/v1/tx"; -import { MsgTransferEncodeObject } from "@cosmjs/stargate"; - -describe("generateIbcTransferMessage", () => { - it("should return a correctly formatted MsgTransferEncodeObject", () => { - const ibcTransferParams: MsgTransfer = { - sourcePort: "transfer", - sourceChannel: "channel-0", - token: { - denom: "uatom", - amount: "1000", - }, - sender: "cosmos1...", - receiver: "cosmos2...", - timeoutHeight: { - revisionHeight: BigInt(1000), - revisionNumber: BigInt(1), - }, - timeoutTimestamp: BigInt(1625140800), - memo: "", - }; - - const result: MsgTransferEncodeObject = - generateIbcTransferMessage(ibcTransferParams); - - expect(result).toEqual({ - typeUrl: "/ibc.applications.transfer.v1.MsgTransfer", - value: ibcTransferParams, - }); - }); -}); diff --git a/packages/plugin-cosmos/src/tests/cosmos-transaction-fee-estimator.test.ts b/packages/plugin-cosmos/src/tests/cosmos-transaction-fee-estimator.test.ts index ed10781ecfe..dd205c77d91 100644 --- a/packages/plugin-cosmos/src/tests/cosmos-transaction-fee-estimator.test.ts +++ b/packages/plugin-cosmos/src/tests/cosmos-transaction-fee-estimator.test.ts @@ -1,8 +1,6 @@ import { describe, it, expect, vi, beforeEach, Mock } from "vitest"; import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate"; import { CosmosTransactionFeeEstimator } from "../shared/services/cosmos-transaction-fee-estimator"; -import { generateIbcTransferMessage } from "../shared/helpers/cosmos-messages"; -import { MsgTransfer } from "interchain/dist/codegen/ibc/applications/transfer/v1/tx"; vi.mock("@cosmjs/cosmwasm-stargate", () => ({ SigningCosmWasmClient: { @@ -97,100 +95,4 @@ describe("FeeEstimator", () => { "" ); }); - - it("should estimate gas for an IBC transfer successfully", async () => { - const mockGasEstimation = 300000; - - (mockSigningCosmWasmClient.simulate as Mock).mockResolvedValue( - mockGasEstimation - ); - - const ibcTransferParams: MsgTransfer = { - sourcePort: "transfer", - sourceChannel: "channel-0", - token: { denom: "uatom", amount: "1000000" }, - sender: "cosmos1senderaddress", - receiver: "cosmos1recipientaddress", - timeoutHeight: { - revisionNumber: BigInt(1), - revisionHeight: BigInt(1000), - }, - timeoutTimestamp: BigInt(0), - memo: "", - }; - - (generateIbcTransferMessage as Mock).mockReturnValue({ - typeUrl: "/ibc.applications.transfer.v1.MsgTransfer", - value: ibcTransferParams, - }); - - const memo = "IBC Test Memo"; - - const estimatedGas = - await CosmosTransactionFeeEstimator.estimateGasForIBCTransfer( - mockSigningCosmWasmClient, - ibcTransferParams, - memo - ); - - // Add 20% to the estimated gas to make sure we have enough gas to cover the transaction - expect(estimatedGas).toBe(mockGasEstimation + mockGasEstimation * 0.2); - - expect(mockSigningCosmWasmClient.simulate).toHaveBeenCalledWith( - ibcTransferParams.sender, - [ - { - typeUrl: "/ibc.applications.transfer.v1.MsgTransfer", - value: ibcTransferParams, - }, - ], - memo - ); - expect(generateIbcTransferMessage).toHaveBeenCalledWith( - ibcTransferParams - ); - }); - - it("should throw an error if gas estimation for IBC transfer fails", async () => { - (mockSigningCosmWasmClient.simulate as Mock).mockRejectedValue( - new Error("IBC gas estimation failed") - ); - - const ibcTransferParams: MsgTransfer = { - sourcePort: "transfer", - sourceChannel: "channel-0", - token: { denom: "uatom", amount: "1000000" }, - sender: "cosmos1senderaddress", - receiver: "cosmos1recipientaddress", - timeoutHeight: { - revisionNumber: BigInt(1), - revisionHeight: BigInt(1000), - }, - timeoutTimestamp: BigInt(0), - memo: "", - }; - - (generateIbcTransferMessage as Mock).mockReturnValue({ - typeUrl: "/ibc.applications.transfer.v1.MsgTransfer", - value: ibcTransferParams, - }); - - await expect( - CosmosTransactionFeeEstimator.estimateGasForIBCTransfer( - mockSigningCosmWasmClient, - ibcTransferParams - ) - ).rejects.toThrow("IBC gas estimation failed"); - - expect(mockSigningCosmWasmClient.simulate).toHaveBeenCalledWith( - ibcTransferParams.sender, - [ - { - typeUrl: "/ibc.applications.transfer.v1.MsgTransfer", - value: ibcTransferParams, - }, - ], - "" - ); - }); }); diff --git a/packages/plugin-cosmos/tsup.config.ts b/packages/plugin-cosmos/tsup.config.ts index 12d9ae64f96..90948913ae9 100644 --- a/packages/plugin-cosmos/tsup.config.ts +++ b/packages/plugin-cosmos/tsup.config.ts @@ -21,5 +21,6 @@ export default defineConfig({ "@cosmjs/proto-signing", "@cosmjs/cosmwasm-stargate", "zod", + "@ai16z/eliza", ], }); From b3d8b05f0edb65d82d89a80f4b72465fa72d2527 Mon Sep 17 00:00:00 2001 From: KacperKoza34 Date: Thu, 9 Jan 2025 11:17:03 +0100 Subject: [PATCH 3/8] update: eliza package import --- .../src/actions/ibc-transfer/index.ts | 2 +- .../src/actions/transfer/index.ts | 2 +- packages/plugin-cosmos/src/index.ts | 2 +- .../src/providers/wallet/utils.ts | 2 +- pnpm-lock.yaml | 853 +++++++++++++++++- 5 files changed, 813 insertions(+), 48 deletions(-) diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts index 687d315f11f..6998112ac79 100644 --- a/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts @@ -6,7 +6,7 @@ import { Memory, ModelClass, State, -} from "@ai16z/eliza"; +} from "@elizaos/core"; import { initWalletChainsData } from "../../providers/wallet/utils"; import { cosmosIBCTransferTemplate, diff --git a/packages/plugin-cosmos/src/actions/transfer/index.ts b/packages/plugin-cosmos/src/actions/transfer/index.ts index cf1049a4d62..efb9051b129 100644 --- a/packages/plugin-cosmos/src/actions/transfer/index.ts +++ b/packages/plugin-cosmos/src/actions/transfer/index.ts @@ -6,7 +6,7 @@ import { Memory, ModelClass, State, -} from "@ai16z/eliza"; +} from "@elizaos/core"; import { initWalletChainsData } from "../../providers/wallet/utils"; import { cosmosTransferTemplate } from "../../templates"; import { CosmosTransferActionService } from "./services/cosmos-transfer-action-service"; diff --git a/packages/plugin-cosmos/src/index.ts b/packages/plugin-cosmos/src/index.ts index 8e3eeb9e276..ce2fff5c4b0 100644 --- a/packages/plugin-cosmos/src/index.ts +++ b/packages/plugin-cosmos/src/index.ts @@ -1,5 +1,5 @@ import { createTransferAction } from "./actions/transfer"; -import type { Plugin } from "@ai16z/eliza"; +import type { Plugin } from "@elizaos/core"; import { createCosmosWalletProvider } from "./providers/wallet"; import { ICosmosPluginOptions } from "./shared/interfaces"; diff --git a/packages/plugin-cosmos/src/providers/wallet/utils.ts b/packages/plugin-cosmos/src/providers/wallet/utils.ts index 9c3dac992cb..9163e16bb39 100644 --- a/packages/plugin-cosmos/src/providers/wallet/utils.ts +++ b/packages/plugin-cosmos/src/providers/wallet/utils.ts @@ -1,4 +1,4 @@ -import { IAgentRuntime } from "@ai16z/eliza"; +import { IAgentRuntime } from "@elizaos/core"; import { CosmosWalletChains } from "../../shared/entities/cosmos-wallet-chains-data"; export const initWalletChainsData = async (runtime: IAgentRuntime) => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7e49154580d..6807d9057c1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,7 +23,7 @@ importers: version: 3.9.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@vitest/eslint-plugin': specifier: 1.0.1 - version: 1.0.1(@typescript-eslint/utils@8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3))(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + version: 1.0.1(@typescript-eslint/utils@8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3))(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3)(vitest@2.1.5(@types/node@20.17.9)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) amqplib: specifier: 0.10.5 version: 0.10.5 @@ -48,7 +48,7 @@ importers: devDependencies: '@commitlint/cli': specifier: 18.6.1 - version: 18.6.1(@types/node@22.10.5)(typescript@5.6.3) + version: 18.6.1(@types/node@20.17.9)(typescript@5.6.3) '@commitlint/config-conventional': specifier: 18.6.3 version: 18.6.3 @@ -78,7 +78,7 @@ importers: version: 9.1.7 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@22.10.5) + version: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) lerna: specifier: 8.1.5 version: 8.1.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(encoding@0.1.13) @@ -90,7 +90,7 @@ importers: version: 3.4.1 ts-jest: specifier: ^29.1.1 - version: 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.10.5))(typescript@5.6.3) + version: 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@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)))(typescript@5.6.3) turbo: specifier: 2.3.3 version: 2.3.3 @@ -105,10 +105,10 @@ importers: version: 2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) vite: specifier: 5.4.11 - version: 5.4.11(@types/node@22.10.5)(terser@5.37.0) + version: 5.4.11(@types/node@20.17.9)(terser@5.37.0) vitest: specifier: 2.1.5 - version: 2.1.5(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + version: 2.1.5(@types/node@20.17.9)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) agent: dependencies: @@ -1200,9 +1200,12 @@ importers: '@elizaos/core': specifier: workspace:* version: link:../core + '@skip-go/client': + specifier: ^0.16.3 + version: 0.16.3(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(starknet@6.18.0(encoding@0.1.13))(utf-8-validate@5.0.10)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)) axios: specifier: ^1.7.9 - version: 1.7.9(debug@4.4.0) + version: 1.7.9 bignumber.js: specifier: 9.1.2 version: 9.1.2 @@ -2492,6 +2495,24 @@ packages: resolution: {integrity: sha512-IQD9wkVReKAhsEAbDjh/0KrBGTEXelqZLpOBRDaIRvlzZ9sjmUP+gKbpvzyJnei2JHQiE8JAgj7YcNloINbGBw==} engines: {node: '>= 10'} + '@apollo/client@3.12.4': + resolution: {integrity: sha512-S/eC9jxEW9Jg1BjD6AZonE1fHxYuvC3gFHop8FRQkUdeK63MmBD5r0DOrN2WlJbwha1MSD6A97OwXwjaujEQpA==} + peerDependencies: + graphql: ^15.0.0 || ^16.0.0 + graphql-ws: ^5.5.5 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc + 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 + '@aptos-labs/aptos-cli@1.0.2': resolution: {integrity: sha512-PYPsd0Kk3ynkxNfe3S4fanI3DiUICCoh4ibQderbvjPFL5A0oK6F4lPEO2t0MDsQySTk2t4vh99Xjy6Bd9y+aQ==} hasBin: true @@ -3561,6 +3582,9 @@ packages: peerDependencies: '@solana/web3.js': ^1.68.0 + '@cosmjs/amino@0.31.3': + resolution: {integrity: sha512-36emtUq895sPRX8PTSOnG+lhJDCVyIcE0Tr5ct59sUbgQiI14y43vj/4WAlJ/utSOxy+Zhj9wxcs4AZfu0BHsw==} + '@cosmjs/amino@0.32.2': resolution: {integrity: sha512-lcK5RCVm4OfdAooxKcF2+NwaDVVpghOq6o/A40c2mHXDUzUoRZ33VAHjVJ9Me6vOFxshrw/XEFn1f4KObntjYA==} @@ -3570,42 +3594,72 @@ packages: '@cosmjs/cosmwasm-stargate@0.32.4': resolution: {integrity: sha512-Fuo9BGEiB+POJ5WeRyBGuhyKR1ordvxZGLPuPosFJOH9U0gKMgcjwKMCgAlWFkMlHaTB+tNdA8AifWiHrI7VgA==} + '@cosmjs/crypto@0.31.3': + resolution: {integrity: sha512-vRbvM9ZKR2017TO73dtJ50KxoGcFzKtKI7C8iO302BQ5p+DuB+AirUg1952UpSoLfv5ki9O416MFANNg8UN/EQ==} + '@cosmjs/crypto@0.32.4': resolution: {integrity: sha512-zicjGU051LF1V9v7bp8p7ovq+VyC91xlaHdsFOTo2oVry3KQikp8L/81RkXmUIT8FxMwdx1T7DmFwVQikcSDIw==} + '@cosmjs/encoding@0.31.3': + resolution: {integrity: sha512-6IRtG0fiVYwyP7n+8e54uTx2pLYijO48V3t9TLiROERm5aUAIzIlz6Wp0NYaI5he9nh1lcEGJ1lkquVKFw3sUg==} + '@cosmjs/encoding@0.32.4': resolution: {integrity: sha512-tjvaEy6ZGxJchiizzTn7HVRiyTg1i4CObRRaTRPknm5EalE13SV+TCHq38gIDfyUeden4fCuaBVEdBR5+ti7Hw==} + '@cosmjs/json-rpc@0.31.3': + resolution: {integrity: sha512-7LVYerXjnm69qqYR3uA6LGCrBW2EO5/F7lfJxAmY+iII2C7xO3a0vAjMSt5zBBh29PXrJVS6c2qRP22W1Le2Wg==} + '@cosmjs/json-rpc@0.32.4': resolution: {integrity: sha512-/jt4mBl7nYzfJ2J/VJ+r19c92mUKF0Lt0JxM3MXEJl7wlwW5haHAWtzRujHkyYMXOwIR+gBqT2S0vntXVBRyhQ==} + '@cosmjs/math@0.31.3': + resolution: {integrity: sha512-kZ2C6glA5HDb9hLz1WrftAjqdTBb3fWQsRR+Us2HsjAYdeE6M3VdXMsYCP5M3yiihal1WDwAY2U7HmfJw7Uh4A==} + '@cosmjs/math@0.32.4': resolution: {integrity: sha512-++dqq2TJkoB8zsPVYCvrt88oJWsy1vMOuSOKcdlnXuOA/ASheTJuYy4+oZlTQ3Fr8eALDLGGPhJI02W2HyAQaw==} + '@cosmjs/proto-signing@0.31.3': + resolution: {integrity: sha512-24+10/cGl6lLS4VCrGTCJeDRPQTn1K5JfknzXzDIHOx8THR31JxA7/HV5eWGHqWgAbudA7ccdSvEK08lEHHtLA==} + '@cosmjs/proto-signing@0.32.2': resolution: {integrity: sha512-UV4WwkE3W3G3s7wwU9rizNcUEz2g0W8jQZS5J6/3fiN0mRPwtPKQ6EinPN9ASqcAJ7/VQH4/9EPOw7d6XQGnqw==} '@cosmjs/proto-signing@0.32.4': resolution: {integrity: sha512-QdyQDbezvdRI4xxSlyM1rSVBO2st5sqtbEIl3IX03uJ7YiZIQHyv6vaHVf1V4mapusCqguiHJzm4N4gsFdLBbQ==} + '@cosmjs/socket@0.31.3': + resolution: {integrity: sha512-aqrDGGi7os/hsz5p++avI4L0ZushJ+ItnzbqA7C6hamFSCJwgOkXaOUs+K9hXZdX4rhY7rXO4PH9IH8q09JkTw==} + '@cosmjs/socket@0.32.4': resolution: {integrity: sha512-davcyYziBhkzfXQTu1l5NrpDYv0K9GekZCC9apBRvL1dvMc9F/ygM7iemHjUA+z8tJkxKxrt/YPjJ6XNHzLrkw==} + '@cosmjs/stargate@0.31.3': + resolution: {integrity: sha512-53NxnzmB9FfXpG4KjOUAYAvWLYKdEmZKsutcat/u2BrDXNZ7BN8jim/ENcpwXfs9/Og0K24lEIdvA4gsq3JDQw==} + '@cosmjs/stargate@0.32.2': resolution: {integrity: sha512-AsJa29fT7Jd4xt9Ai+HMqhyj7UQu7fyYKdXj/8+/9PD74xe6lZSYhQPcitUmMLJ1ckKPgXSk5Dd2LbsQT0IhZg==} '@cosmjs/stargate@0.32.4': resolution: {integrity: sha512-usj08LxBSsPRq9sbpCeVdyLx2guEcOHfJS9mHGCLCXpdAPEIEQEtWLDpEUc0LEhWOx6+k/ChXTc5NpFkdrtGUQ==} + '@cosmjs/stream@0.31.3': + resolution: {integrity: sha512-8keYyI7X0RjsLyVcZuBeNjSv5FA4IHwbFKx7H60NHFXszN8/MvXL6aZbNIvxtcIHHsW7K9QSQos26eoEWlAd+w==} + '@cosmjs/stream@0.32.4': resolution: {integrity: sha512-Gih++NYHEiP+oyD4jNEUxU9antoC0pFSg+33Hpp0JlHwH0wXhtD3OOKnzSfDB7OIoEbrzLJUpEjOgpCp5Z+W3A==} + '@cosmjs/tendermint-rpc@0.31.3': + resolution: {integrity: sha512-s3TiWkPCW4QceTQjpYqn4xttUJH36mTPqplMl+qyocdqk5+X5mergzExU/pHZRWQ4pbby8bnR7kMvG4OC1aZ8g==} + '@cosmjs/tendermint-rpc@0.32.2': resolution: {integrity: sha512-DXyJHDmcAfCix4H/7/dKR0UMdshP01KxJOXHdHxBCbLIpck94BsWD3B2ZTXwfA6sv98so9wOzhp7qGQa5malxg==} '@cosmjs/tendermint-rpc@0.32.4': resolution: {integrity: sha512-MWvUUno+4bCb/LmlMIErLypXxy7ckUuzEmpufYYYd9wgbdCXaTaO08SZzyFM5PI8UJ/0S2AmUrgWhldlbxO8mw==} + '@cosmjs/utils@0.31.3': + resolution: {integrity: sha512-VBhAgzrrYdIe0O5IbKRqwszbQa7ZyQLx9nEQuHQ3HUplQW7P44COG/ye2n6AzCudtqxmwdX7nyX8ta1J07GoqA==} + '@cosmjs/utils@0.32.4': resolution: {integrity: sha512-D1Yc+Zy8oL/hkUkFUL/bwxvuDBzRGpc4cF7/SkdhxX4iHpSLgdOuTt1mhCh9+kl6NQREy9t7SYZ6xeW5gFe60w==} @@ -4217,6 +4271,12 @@ packages: '@emnapi/wasi-threads@1.0.1': resolution: {integrity: sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==} + '@ensdomains/ens-validation@0.1.0': + resolution: {integrity: sha512-rbDh2K6GfqXvBcJUISaTTYEt3f079WA4ohTE5Lh4/8EaaPAk/9vk3EisMUQV2UVxeFIZQEEyRCIOmRTpqN0W7A==} + + '@ensdomains/eth-ens-namehash@2.0.15': + resolution: {integrity: sha512-JRDFP6+Hczb1E0/HhIg0PONgBYasfGfDheujmfxaZaAv/NAH4jE6Kf48WbqfRZdxt4IZI3jl3Ri7sZ1nP09lgw==} + '@es-joy/jsdoccomment@0.41.0': resolution: {integrity: sha512-aKUhyn1QI5Ksbqcr3fFJj16p99QdjUxXAEuFst1Z47DRyoiMwivIH9MV/ARcJOCXVjPfjITciej8ZD2O/6qUmw==} engines: {node: '>=16'} @@ -5312,6 +5372,54 @@ packages: peerDependencies: google-protobuf: ^3.14.0 + '@injectivelabs/core-proto-ts@0.0.21': + resolution: {integrity: sha512-RBxSkRBCty60R/l55/D1jsSW0Aof5dyGFhCFdN3A010KjMv/SzZGGr+6DZPY/hflyFeaJzDv/VTopCymKNRBvQ==} + + '@injectivelabs/dmm-proto-ts@1.0.19': + resolution: {integrity: sha512-2FCzCziy1RhzmnkAVIU+Asby/GXAVQqKt5/o1s52j0LJXfJMpiCrV6soLfnjTebj61T+1WvJBPFoZCCiVYBpcw==} + + '@injectivelabs/exceptions@1.14.33': + resolution: {integrity: sha512-2c8YzLgwTOOsyc1WheqdM8jEfgGBhVrXN4cZ0jsikFVsLF619IDRn3hjIYqTeNERaEpeRPiuJGfZDu0DomwFrQ==} + + '@injectivelabs/grpc-web-node-http-transport@0.0.2': + resolution: {integrity: sha512-rpyhXLiGY/UMs6v6YmgWHJHiO9l0AgDyVNv+jcutNVt4tQrmNvnpvz2wCAGOFtq5LuX/E9ChtTVpk3gWGqXcGA==} + peerDependencies: + '@injectivelabs/grpc-web': '>=0.0.1' + + '@injectivelabs/grpc-web-react-native-transport@0.0.2': + resolution: {integrity: sha512-mk+aukQXnYNgPsPnu3KBi+FD0ZHQpazIlaBZ2jNZG7QAVmxTWtv3R66Zoq99Wx2dnE946NsZBYAoa0K5oSjnow==} + peerDependencies: + '@injectivelabs/grpc-web': '>=0.0.1' + + '@injectivelabs/grpc-web@0.0.1': + resolution: {integrity: sha512-Pu5YgaZp+OvR5UWfqbrPdHer3+gDf+b5fQoY+t2VZx1IAVHX8bzbN9EreYTvTYtFeDpYRWM8P7app2u4EX5wTw==} + peerDependencies: + google-protobuf: ^3.14.0 + + '@injectivelabs/indexer-proto-ts@1.11.32': + resolution: {integrity: sha512-gCkbMlBq34MY2xZcauDEsCP0h5l/FgKMwCgJ8aWGaTkh27XBWpl1zvlreuWg/IpSvTPJZBoADW9KqixqyoBdJw==} + + '@injectivelabs/mito-proto-ts@1.0.55': + resolution: {integrity: sha512-clFKpU/LCYvYiPg5PRjhVJFTxKcfJHzaj5saJHuL32LaOaB3Rd8L3CqP9qUrg78L7eKjjXjyG97U3NdRdZBlWg==} + + '@injectivelabs/networks@1.14.33': + resolution: {integrity: sha512-XDhAYwWYKdKBRfwO/MIfMyKjKRWz/AliMJG9yaM1C/cDlGHmA3EY7Au2Nf+PdkRhuxl2FzLV2Hp4uWeC0g8BYw==} + + '@injectivelabs/sdk-ts@1.14.5': + resolution: {integrity: sha512-j/6EcvNgQn563L0P5x80cZDTbYYbsXmHgtIbj8DCzemzgPRadmZLtlMDBjMQZ0ZcMhDSMfVOCINBOB2bBz2qMw==} + + '@injectivelabs/test-utils@1.14.33': + resolution: {integrity: sha512-1SfIRsMnWcJAYNrrpY+ZUWmbD62lWWdIvD6c+FYmFKS14zU3yDIK9NXe9g1lTM/GdUVkVKQgGg2QAYZ5f2G/xA==} + + '@injectivelabs/token-metadata@1.14.11': + resolution: {integrity: sha512-WKJlvjKiTRHxpOeez4kYrzIwgWmpspD1IMxWclkTysAcwGltUfUsvUhu1cKuACleIjFFWmiZv/HoGRFdvEAZ8w==} + + '@injectivelabs/ts-types@1.14.33': + resolution: {integrity: sha512-sJZzMNJtZFFZoPKZ91G09bxrZqQ5aS9omoTjQWy+7OxfiRAakzhsarTueX47hm6oTaN0XeBgD3wkMukkWUaobw==} + + '@injectivelabs/utils@1.14.33': + resolution: {integrity: sha512-zsezML4dTujF0xGLhcGmWBCghfJiy9MW+r6VqR8zJUlxnmnEdNpmsvBhBI6cmmov6Se4FL+yALAIFRvTm3txbg==} + '@ioredis/commands@1.2.0': resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} @@ -5431,6 +5539,14 @@ packages: '@jspm/core@2.1.0': resolution: {integrity: sha512-3sRl+pkyFY/kLmHl0cgHiFp2xEqErA8N3ECjMs7serSUBmoJ70lBa0PG5t0IM6WJgdZNyyI0R8YFfi5wM8+mzg==} + '@keplr-wallet/types@0.12.172': + resolution: {integrity: sha512-SfsUxSEJqVcAhpy0HJFNBxF/4mSCNZy3GxcoYVY+WKSfGMMabp5PwyKKJxKuiNc9Ar752+60l1PQkYy5zYyKOA==} + peerDependencies: + starknet: ^6 + + '@keplr-wallet/unit@0.12.172': + resolution: {integrity: sha512-kMcPgysxy7nS9PtHAYxrBZnweSoT/ifbRAnfdJT2RG+rIvHEsgU0odf3RVu+0eG7XaKeV6+mDkrE59aBvyFTyQ==} + '@kikobeats/time-span@1.0.5': resolution: {integrity: sha512-txRAdmi35N1wnsLS1AO5mTlbY5Cv5/61WXqek2y3L9Q7u4mgdUVq819so5xe753hL5gYeLzlWoJ/VJfXg9nx8g==} engines: {node: '>= 18'} @@ -7672,6 +7788,12 @@ packages: '@sinonjs/fake-timers@10.3.0': resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + '@skip-go/client@0.16.3': + resolution: {integrity: sha512-ucg4WVXRENCOp/i5Sb5CAID6A8UOJRZs9A1lJR4vnYREJUESA8JnS7bh8UQKsREEHTjMYKV4O90EV2W/XCKoFw==} + peerDependencies: + '@solana/web3.js': ^1.95.8 + viem: 2.21.58 + '@slack/events-api@3.0.1': resolution: {integrity: sha512-ReJzZRpCgwGtKrAT0tRMppO3zm72jmxsOlTgR7PGajv2oq/tOJSeVRm7RcGiwn3EPIuovKkD/mr4TTN4n801fQ==} engines: {node: '>=12.13.0', npm: '>=6.12.0'} @@ -8719,6 +8841,9 @@ packages: '@types/lodash.isstring@4.0.9': resolution: {integrity: sha512-sjGPpa15VBpMns/4s6Blm567JgxLVVu/eCYCe7h/TdQyPCz9lIhaLSISjN7ZC9cDXmUT2IM/4mNRw8OtYirziw==} + '@types/lodash.values@4.3.9': + resolution: {integrity: sha512-IJ20OEfqNwm3k8ENwoM3q0yOs4UMpgtD4GqxB4lwBHToGthHWqhyh5DdSgQjioocz0QK2SSBkJfCq95ZTV8BTw==} + '@types/lodash@4.17.14': resolution: {integrity: sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A==} @@ -9329,6 +9454,22 @@ packages: '@webassemblyjs/wast-printer@1.14.1': resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + '@wry/caches@1.0.1': + resolution: {integrity: sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA==} + engines: {node: '>=8'} + + '@wry/context@0.7.4': + resolution: {integrity: sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ==} + engines: {node: '>=8'} + + '@wry/equality@0.5.7': + resolution: {integrity: sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw==} + engines: {node: '>=8'} + + '@wry/trie@0.5.0': + resolution: {integrity: sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA==} + engines: {node: '>=8'} + '@xtuc/ieee754@1.2.0': resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} @@ -9611,6 +9752,10 @@ packages: resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==} engines: {node: '>=0.10.0'} + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -10433,6 +10578,10 @@ packages: resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==} engines: {node: '>=0.10.0'} + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + chalk@3.0.0: resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} engines: {node: '>=8'} @@ -10689,10 +10838,16 @@ packages: collect-v8-coverage@1.0.2: resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -10953,6 +11108,10 @@ packages: peerDependencies: webpack: ^5.1.0 + copyfiles@2.4.1: + resolution: {integrity: sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==} + hasBin: true + core-js-compat@3.39.0: resolution: {integrity: sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==} @@ -11007,6 +11166,12 @@ packages: typescript: optional: true + cosmjs-types@0.7.2: + resolution: {integrity: sha512-vf2uLyktjr/XVAgEq0DjMxeAWh1yYREe7AMHDKd7EiHVqxBPCaBS+qEEQUkXbR9ndnckqr1sUG8BQhazh4X5lA==} + + cosmjs-types@0.8.0: + resolution: {integrity: sha512-Q2Mj95Fl0PYMWEhA2LuGEIhipF7mQwd9gTQ85DdP9jjjopeoGaDxvmPa5nakNzsq7FnO1DMTatXTAx6bxMH7Lg==} + cosmjs-types@0.9.0: resolution: {integrity: sha512-MN/yUe6mkJwHnCFfsNPeCfXVhyxHYW6c/xDUzrSbBycYzw++XvWDMJArXp2pLdgD6FQ8DW79vkPjeNKVrXaHeQ==} @@ -12323,6 +12488,10 @@ packages: ethereumjs-util@6.2.1: resolution: {integrity: sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==} + ethereumjs-util@7.1.5: + resolution: {integrity: sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==} + engines: {node: '>=10.0.0'} + ethers@5.7.2: resolution: {integrity: sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==} @@ -13444,6 +13613,9 @@ packages: resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} engines: {node: '>=0.8', npm: '>=1.3.7'} + http-status-codes@2.3.0: + resolution: {integrity: sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==} + http2-wrapper@1.0.3: resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} engines: {node: '>=10.19.0'} @@ -14305,6 +14477,10 @@ packages: jsbn@1.1.0: resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} + jscrypto@1.0.3: + resolution: {integrity: sha512-lryZl0flhodv4SZHOqyb1bx5sKcJxj0VBo0Kzb4QMAg3L021IC9uGpl0RCZa+9KJwlRGSK2C80ITcwbe19OKLQ==} + hasBin: true + jsdoc-type-pratt-parser@4.0.0: resolution: {integrity: sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==} engines: {node: '>=12.0.0'} @@ -14407,6 +14583,9 @@ packages: resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} engines: {node: '>=0.10.0'} + jsonschema@1.5.0: + resolution: {integrity: sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw==} + jsonwebtoken@9.0.2: resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} engines: {node: '>=12', npm: '>=6'} @@ -14690,6 +14869,11 @@ packages: resolution: {integrity: sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + link-module-alias@1.2.0: + resolution: {integrity: sha512-ahPjXepbSVKbahTB6LxR//VHm8HPfI+QQygCH+E82spBY4HR5VPJTvlhKBc9F7muVxnS6C1rRfoPOXAbWO/fyw==} + engines: {node: '> 8.0.0'} + hasBin: true + linkify-it@5.0.0: resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} @@ -14851,6 +15035,9 @@ packages: lodash.upperfirst@4.3.1: resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==} + lodash.values@4.3.0: + resolution: {integrity: sha512-r0RwvdCv8id9TUblb/O7rYPwVy6lerCbcawrfdo9iC/1t1wsNMJknO79WNBgwkH0hIeJ08jmvvESbFpNb4jH0Q==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -15797,6 +15984,9 @@ packages: engines: {node: '>=10'} hasBin: true + noms@0.0.0: + resolution: {integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==} + nopt@1.0.10: resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==} hasBin: true @@ -16074,6 +16264,9 @@ packages: resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} hasBin: true + optimism@0.18.1: + resolution: {integrity: sha512-mLXNwWPa9dgFyDqkNi54sjDyNJ9/fTI6WGBLgnXku1vdKY/jovHfZT5r+aiVeFFLOz+foPNOm5YJ4mqgld2GBQ==} + optional@0.1.4: resolution: {integrity: sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw==} @@ -17938,6 +18131,17 @@ packages: resolution: {integrity: sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==} hasBin: true + rehackt@0.1.0: + resolution: {integrity: sha512-7kRDOuLHB87D/JESKxQoRwv4DzbIdwkAGQ7p6QKGdVlY1IZheUnVhlk/4UZlNUVxdAXpyxikE3URsG067ybVzw==} + peerDependencies: + '@types/react': '*' + react: '*' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + rehype-parse@7.0.1: resolution: {integrity: sha512-fOiR9a9xH+Le19i4fGzIEowAbwG7idy2Jzs4mOrFWBSJ0sNUgy0ev871dwWnbOo371SjgjG4pwzrbgSVrKxecw==} @@ -18046,6 +18250,10 @@ packages: engines: {node: '>= 0.4'} hasBin: true + response-iterator@0.2.11: + resolution: {integrity: sha512-5tdhcAeGMSyM0/FoxAYjoOxQZ2tRR2H/S/t6kGRXu6iiWcGY5UnZgkVANbTwBVUSGqWu0ADctmoi6lOCIF8uKQ==} + engines: {node: '>=0.8'} + responselike@2.0.1: resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} @@ -18414,6 +18622,11 @@ packages: shimmer@1.2.1: resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==} + shx@0.3.4: + resolution: {integrity: sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==} + engines: {node: '>=6'} + hasBin: true + side-channel-list@1.0.0: resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} engines: {node: '>= 0.4'} @@ -18520,6 +18733,10 @@ packages: snake-case@3.0.4: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + snakecase-keys@5.5.0: + resolution: {integrity: sha512-r3kRtnoPu3FxGJ3fny6PKNnU3pteb29o6qAa0ugzhSseKNWRkw1dw8nIjXMyyKaU9vQxxVIE62Mb3bKbdrgpiw==} + engines: {node: '>=12'} + sockjs@0.3.24: resolution: {integrity: sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==} @@ -18729,6 +18946,9 @@ packages: resolution: {integrity: sha512-yhPIQXjrlt1xv7dyPQg2P17URmXbuM5pdGkpiMB3RenprfiBlvK415Lctfe0eshk90oA7/tNq7WEiMK8RSP39A==} engines: {node: '>=18'} + store2@2.14.4: + resolution: {integrity: sha512-srTItn1GOvyvOycgxjAnPA63FZNwy0PTyUBFMHRM+hVFltAeoh0LmNBz9SZqUS9mMqGk8rfyWyXn3GH5ReJ8Zw==} + stream-browserify@3.0.0: resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} @@ -18958,6 +19178,10 @@ packages: resolution: {integrity: sha512-sQV7phh2WCYAn81oAkakC5qjq2Ml0g8ozqz03wOGnx9dDlG1de6yrF+0RAzSJD8fPUow3PTSMf2SAbOGxb93BA==} engines: {node: '>=0.10'} + symbol-observable@4.0.0: + resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} + engines: {node: '>=0.10'} + symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} @@ -19306,6 +19530,10 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + ts-invariant@0.10.3: + resolution: {integrity: sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==} + engines: {node: '>=8'} + ts-jest@29.2.5: resolution: {integrity: sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==} engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} @@ -19518,6 +19746,10 @@ packages: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} + type-fest@3.13.1: + resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} + engines: {node: '>=14.16'} + type-fest@4.31.0: resolution: {integrity: sha512-yCxltHW07Nkhv/1F6wWBr8kz+5BGMfP+RbRSYFnegVb0qV/UMT0G0ElBloPVerqn4M2ZV80Ir1FtCcYv1cT6vQ==} engines: {node: '>=16'} @@ -19872,6 +20104,10 @@ packages: uploadthing: optional: true + untildify@4.0.0: + resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} + engines: {node: '>=8'} + untyped@1.5.2: resolution: {integrity: sha512-eL/8PlhLcMmlMDtNPKhyyz9kEBDS3Uk4yMu/ewlkT2WFbtzScjHWPJLdQLmaGPUKjXzwe9MumOtOgc4Fro96Kg==} hasBin: true @@ -20777,6 +21013,12 @@ packages: yup@1.6.1: resolution: {integrity: sha512-JED8pB50qbA4FOkDol0bYF/p60qSEDQqBD0/qeIrUCG1KbPBIQ776fCUNb9ldbPcSTxA69g/47XTo4TqWiuXOA==} + zen-observable-ts@1.2.5: + resolution: {integrity: sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==} + + zen-observable@0.8.15: + resolution: {integrity: sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==} + zimmerframe@1.1.2: resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==} @@ -20830,7 +21072,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 safe-buffer: 5.1.2 transitivePeerDependencies: - supports-color @@ -21253,6 +21495,29 @@ snapshots: '@anush008/tokenizers-linux-x64-gnu': 0.0.0 '@anush008/tokenizers-win32-x64-msvc': 0.0.0 + '@apollo/client@3.12.4(@types/react@18.3.12)(graphql@16.10.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@graphql-typed-document-node/core': 3.2.0(graphql@16.10.0) + '@wry/caches': 1.0.1 + '@wry/equality': 0.5.7 + '@wry/trie': 0.5.0 + graphql: 16.10.0 + graphql-tag: 2.12.6(graphql@16.10.0) + hoist-non-react-statics: 3.3.2 + optimism: 0.18.1 + prop-types: 15.8.1 + rehackt: 0.1.0(@types/react@18.3.12)(react@18.3.1) + response-iterator: 0.2.11 + symbol-observable: 4.0.0 + ts-invariant: 0.10.3 + tslib: 2.8.1 + zen-observable-ts: 1.2.5 + optionalDependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - '@types/react' + '@aptos-labs/aptos-cli@1.0.2': dependencies: commander: 12.1.0 @@ -21970,7 +22235,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 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -22760,7 +23025,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 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -22908,7 +23173,7 @@ snapshots: dependencies: '@scure/bip32': 1.6.1 abitype: 1.0.8(typescript@5.6.3)(zod@3.24.1) - 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 @@ -22929,11 +23194,11 @@ snapshots: '@colors/colors@1.5.0': optional: true - '@commitlint/cli@18.6.1(@types/node@22.10.5)(typescript@5.6.3)': + '@commitlint/cli@18.6.1(@types/node@20.17.9)(typescript@5.6.3)': dependencies: '@commitlint/format': 18.6.1 '@commitlint/lint': 18.6.1 - '@commitlint/load': 18.6.1(@types/node@22.10.5)(typescript@5.6.3) + '@commitlint/load': 18.6.1(@types/node@20.17.9)(typescript@5.6.3) '@commitlint/read': 18.6.1 '@commitlint/types': 18.6.1 execa: 5.1.1 @@ -22983,7 +23248,7 @@ snapshots: '@commitlint/rules': 18.6.1 '@commitlint/types': 18.6.1 - '@commitlint/load@18.6.1(@types/node@22.10.5)(typescript@5.6.3)': + '@commitlint/load@18.6.1(@types/node@20.17.9)(typescript@5.6.3)': dependencies: '@commitlint/config-validator': 18.6.1 '@commitlint/execute-rule': 18.6.1 @@ -22991,7 +23256,7 @@ snapshots: '@commitlint/types': 18.6.1 chalk: 4.1.2 cosmiconfig: 8.3.6(typescript@5.6.3) - cosmiconfig-typescript-loader: 5.1.0(@types/node@22.10.5)(cosmiconfig@8.3.6(typescript@5.6.3))(typescript@5.6.3) + cosmiconfig-typescript-loader: 5.1.0(@types/node@20.17.9)(cosmiconfig@8.3.6(typescript@5.6.3))(typescript@5.6.3) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 @@ -23166,6 +23431,13 @@ snapshots: bn.js: 5.2.1 buffer-layout: 1.2.2 + '@cosmjs/amino@0.31.3': + dependencies: + '@cosmjs/crypto': 0.31.3 + '@cosmjs/encoding': 0.31.3 + '@cosmjs/math': 0.31.3 + '@cosmjs/utils': 0.31.3 + '@cosmjs/amino@0.32.2': dependencies: '@cosmjs/crypto': 0.32.4 @@ -23197,6 +23469,16 @@ snapshots: - debug - utf-8-validate + '@cosmjs/crypto@0.31.3': + dependencies: + '@cosmjs/encoding': 0.31.3 + '@cosmjs/math': 0.31.3 + '@cosmjs/utils': 0.31.3 + '@noble/hashes': 1.7.0 + bn.js: 5.2.1 + elliptic: 6.6.1 + libsodium-wrappers-sumo: 0.7.15 + '@cosmjs/crypto@0.32.4': dependencies: '@cosmjs/encoding': 0.32.4 @@ -23207,21 +23489,46 @@ snapshots: elliptic: 6.6.1 libsodium-wrappers-sumo: 0.7.15 + '@cosmjs/encoding@0.31.3': + dependencies: + base64-js: 1.5.1 + bech32: 1.1.4 + readonly-date: 1.0.0 + '@cosmjs/encoding@0.32.4': dependencies: base64-js: 1.5.1 bech32: 1.1.4 readonly-date: 1.0.0 + '@cosmjs/json-rpc@0.31.3': + dependencies: + '@cosmjs/stream': 0.31.3 + xstream: 11.14.0 + '@cosmjs/json-rpc@0.32.4': dependencies: '@cosmjs/stream': 0.32.4 xstream: 11.14.0 + '@cosmjs/math@0.31.3': + dependencies: + bn.js: 5.2.1 + '@cosmjs/math@0.32.4': dependencies: bn.js: 5.2.1 + '@cosmjs/proto-signing@0.31.3': + dependencies: + '@cosmjs/amino': 0.31.3 + '@cosmjs/crypto': 0.31.3 + '@cosmjs/encoding': 0.31.3 + '@cosmjs/math': 0.31.3 + '@cosmjs/utils': 0.31.3 + cosmjs-types: 0.8.0 + long: 4.0.0 + '@cosmjs/proto-signing@0.32.2': dependencies: '@cosmjs/amino': 0.32.4 @@ -23240,6 +23547,16 @@ snapshots: '@cosmjs/utils': 0.32.4 cosmjs-types: 0.9.0 + '@cosmjs/socket@0.31.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@cosmjs/stream': 0.31.3 + isomorphic-ws: 4.0.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + xstream: 11.14.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@cosmjs/socket@0.32.4(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: '@cosmjs/stream': 0.32.4 @@ -23250,6 +23567,25 @@ snapshots: - bufferutil - utf-8-validate + '@cosmjs/stargate@0.31.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@confio/ics23': 0.6.8 + '@cosmjs/amino': 0.31.3 + '@cosmjs/encoding': 0.31.3 + '@cosmjs/math': 0.31.3 + '@cosmjs/proto-signing': 0.31.3 + '@cosmjs/stream': 0.31.3 + '@cosmjs/tendermint-rpc': 0.31.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@cosmjs/utils': 0.31.3 + cosmjs-types: 0.8.0 + long: 4.0.0 + protobufjs: 6.11.4 + xstream: 11.14.0 + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate + '@cosmjs/stargate@0.32.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: '@confio/ics23': 0.6.8 @@ -23284,10 +23620,31 @@ snapshots: - debug - utf-8-validate + '@cosmjs/stream@0.31.3': + dependencies: + xstream: 11.14.0 + '@cosmjs/stream@0.32.4': dependencies: xstream: 11.14.0 + '@cosmjs/tendermint-rpc@0.31.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@cosmjs/crypto': 0.31.3 + '@cosmjs/encoding': 0.31.3 + '@cosmjs/json-rpc': 0.31.3 + '@cosmjs/math': 0.31.3 + '@cosmjs/socket': 0.31.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@cosmjs/stream': 0.31.3 + '@cosmjs/utils': 0.31.3 + axios: 0.21.4 + readonly-date: 1.0.0 + xstream: 11.14.0 + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate + '@cosmjs/tendermint-rpc@0.32.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: '@cosmjs/crypto': 0.32.4 @@ -23297,7 +23654,7 @@ snapshots: '@cosmjs/socket': 0.32.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@cosmjs/stream': 0.32.4 '@cosmjs/utils': 0.32.4 - axios: 1.7.9(debug@4.4.0) + axios: 1.7.9 readonly-date: 1.0.0 xstream: 11.14.0 transitivePeerDependencies: @@ -23314,7 +23671,7 @@ snapshots: '@cosmjs/socket': 0.32.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@cosmjs/stream': 0.32.4 '@cosmjs/utils': 0.32.4 - axios: 1.7.9(debug@4.4.0) + axios: 1.7.9 readonly-date: 1.0.0 xstream: 11.14.0 transitivePeerDependencies: @@ -23322,6 +23679,8 @@ snapshots: - debug - utf-8-validate + '@cosmjs/utils@0.31.3': {} + '@cosmjs/utils@0.32.4': {} '@cosmology/lcd@0.13.5': @@ -24618,6 +24977,10 @@ snapshots: dependencies: tslib: 2.8.1 + '@ensdomains/ens-validation@0.1.0': {} + + '@ensdomains/eth-ens-namehash@2.0.15': {} + '@es-joy/jsdoccomment@0.41.0': dependencies: comment-parser: 1.4.1 @@ -24929,7 +25292,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 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -24955,7 +25318,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 espree: 10.3.0 globals: 14.0.0 ignore: 5.3.2 @@ -25712,6 +26075,165 @@ snapshots: browser-headers: 0.4.1 google-protobuf: 3.21.4 + '@injectivelabs/core-proto-ts@0.0.21': + dependencies: + '@injectivelabs/grpc-web': 0.0.1(google-protobuf@3.21.4) + google-protobuf: 3.21.4 + protobufjs: 7.4.0 + rxjs: 7.8.1 + + '@injectivelabs/dmm-proto-ts@1.0.19': + dependencies: + '@injectivelabs/grpc-web': 0.0.1(google-protobuf@3.21.4) + google-protobuf: 3.21.4 + protobufjs: 7.4.0 + rxjs: 7.8.1 + + '@injectivelabs/exceptions@1.14.33(google-protobuf@3.21.4)': + dependencies: + '@injectivelabs/grpc-web': 0.0.1(google-protobuf@3.21.4) + '@injectivelabs/ts-types': 1.14.33 + http-status-codes: 2.3.0 + shx: 0.3.4 + transitivePeerDependencies: + - google-protobuf + + '@injectivelabs/grpc-web-node-http-transport@0.0.2(@injectivelabs/grpc-web@0.0.1(google-protobuf@3.21.4))': + dependencies: + '@injectivelabs/grpc-web': 0.0.1(google-protobuf@3.21.4) + + '@injectivelabs/grpc-web-react-native-transport@0.0.2(@injectivelabs/grpc-web@0.0.1(google-protobuf@3.21.4))': + dependencies: + '@injectivelabs/grpc-web': 0.0.1(google-protobuf@3.21.4) + + '@injectivelabs/grpc-web@0.0.1(google-protobuf@3.21.4)': + dependencies: + browser-headers: 0.4.1 + google-protobuf: 3.21.4 + + '@injectivelabs/indexer-proto-ts@1.11.32': + dependencies: + '@injectivelabs/grpc-web': 0.0.1(google-protobuf@3.21.4) + google-protobuf: 3.21.4 + protobufjs: 7.4.0 + rxjs: 7.8.1 + + '@injectivelabs/mito-proto-ts@1.0.55': + dependencies: + '@injectivelabs/grpc-web': 0.0.1(google-protobuf@3.21.4) + google-protobuf: 3.21.4 + protobufjs: 7.4.0 + rxjs: 7.8.1 + + '@injectivelabs/networks@1.14.33(google-protobuf@3.21.4)': + dependencies: + '@injectivelabs/exceptions': 1.14.33(google-protobuf@3.21.4) + '@injectivelabs/ts-types': 1.14.33 + '@injectivelabs/utils': 1.14.33(google-protobuf@3.21.4) + shx: 0.3.4 + transitivePeerDependencies: + - debug + - google-protobuf + + '@injectivelabs/sdk-ts@1.14.5(@types/react@18.3.12)(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@5.0.10)': + dependencies: + '@apollo/client': 3.12.4(@types/react@18.3.12)(graphql@16.10.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@cosmjs/amino': 0.31.3 + '@cosmjs/proto-signing': 0.31.3 + '@cosmjs/stargate': 0.31.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@ensdomains/ens-validation': 0.1.0 + '@ensdomains/eth-ens-namehash': 2.0.15 + '@ethersproject/bytes': 5.7.0 + '@injectivelabs/core-proto-ts': 0.0.21 + '@injectivelabs/dmm-proto-ts': 1.0.19 + '@injectivelabs/exceptions': 1.14.33(google-protobuf@3.21.4) + '@injectivelabs/grpc-web': 0.0.1(google-protobuf@3.21.4) + '@injectivelabs/grpc-web-node-http-transport': 0.0.2(@injectivelabs/grpc-web@0.0.1(google-protobuf@3.21.4)) + '@injectivelabs/grpc-web-react-native-transport': 0.0.2(@injectivelabs/grpc-web@0.0.1(google-protobuf@3.21.4)) + '@injectivelabs/indexer-proto-ts': 1.11.32 + '@injectivelabs/mito-proto-ts': 1.0.55 + '@injectivelabs/networks': 1.14.33(google-protobuf@3.21.4) + '@injectivelabs/test-utils': 1.14.33(google-protobuf@3.21.4) + '@injectivelabs/token-metadata': 1.14.11(google-protobuf@3.21.4) + '@injectivelabs/ts-types': 1.14.33 + '@injectivelabs/utils': 1.14.33(google-protobuf@3.21.4) + '@metamask/eth-sig-util': 4.0.1 + axios: 0.27.2 + bech32: 2.0.0 + bip39: 3.1.0 + cosmjs-types: 0.7.2 + ethereumjs-util: 7.1.5 + ethers: 5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + google-protobuf: 3.21.4 + graphql: 16.10.0 + http-status-codes: 2.3.0 + js-sha3: 0.8.0 + jscrypto: 1.0.3 + keccak256: 1.0.6 + link-module-alias: 1.2.0 + secp256k1: 4.0.4 + shx: 0.3.4 + snakecase-keys: 5.5.0 + transitivePeerDependencies: + - '@types/react' + - bufferutil + - debug + - graphql-ws + - react + - react-dom + - subscriptions-transport-ws + - utf-8-validate + + '@injectivelabs/test-utils@1.14.33(google-protobuf@3.21.4)': + dependencies: + '@injectivelabs/exceptions': 1.14.33(google-protobuf@3.21.4) + '@injectivelabs/networks': 1.14.33(google-protobuf@3.21.4) + '@injectivelabs/ts-types': 1.14.33 + '@injectivelabs/utils': 1.14.33(google-protobuf@3.21.4) + axios: 1.7.9 + bignumber.js: 9.1.2 + shx: 0.3.4 + snakecase-keys: 5.5.0 + store2: 2.14.4 + transitivePeerDependencies: + - debug + - google-protobuf + + '@injectivelabs/token-metadata@1.14.11(google-protobuf@3.21.4)': + dependencies: + '@injectivelabs/exceptions': 1.14.33(google-protobuf@3.21.4) + '@injectivelabs/networks': 1.14.33(google-protobuf@3.21.4) + '@injectivelabs/ts-types': 1.14.33 + '@injectivelabs/utils': 1.14.33(google-protobuf@3.21.4) + '@types/lodash.values': 4.3.9 + copyfiles: 2.4.1 + jsonschema: 1.5.0 + link-module-alias: 1.2.0 + lodash: 4.17.21 + lodash.values: 4.3.0 + shx: 0.3.4 + transitivePeerDependencies: + - debug + - google-protobuf + + '@injectivelabs/ts-types@1.14.33': + dependencies: + shx: 0.3.4 + + '@injectivelabs/utils@1.14.33(google-protobuf@3.21.4)': + dependencies: + '@injectivelabs/exceptions': 1.14.33(google-protobuf@3.21.4) + '@injectivelabs/ts-types': 1.14.33 + axios: 1.7.9 + bignumber.js: 9.1.2 + http-status-codes: 2.3.0 + shx: 0.3.4 + snakecase-keys: 5.5.0 + store2: 2.14.4 + transitivePeerDependencies: + - debug + - google-protobuf + '@ioredis/commands@1.2.0': {} '@isaacs/cliui@8.0.2': @@ -26002,6 +26524,19 @@ snapshots: '@jspm/core@2.1.0': {} + '@keplr-wallet/types@0.12.172(starknet@6.18.0(encoding@0.1.13))': + dependencies: + long: 4.0.0 + starknet: 6.18.0(encoding@0.1.13) + + '@keplr-wallet/unit@0.12.172(starknet@6.18.0(encoding@0.1.13))': + dependencies: + '@keplr-wallet/types': 0.12.172(starknet@6.18.0(encoding@0.1.13)) + big-integer: 1.6.52 + utility-types: 3.11.0 + transitivePeerDependencies: + - starknet + '@kikobeats/time-span@1.0.5': {} '@kwsites/file-exists@1.1.1': @@ -29484,6 +30019,36 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 + '@skip-go/client@0.16.3(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(starknet@6.18.0(encoding@0.1.13))(utf-8-validate@5.0.10)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))': + dependencies: + '@cosmjs/amino': 0.32.4 + '@cosmjs/cosmwasm-stargate': 0.32.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@cosmjs/encoding': 0.32.4 + '@cosmjs/math': 0.32.4 + '@cosmjs/proto-signing': 0.32.4 + '@cosmjs/stargate': 0.32.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@cosmjs/tendermint-rpc': 0.32.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@injectivelabs/core-proto-ts': 0.0.21 + '@injectivelabs/sdk-ts': 1.14.5(@types/react@18.3.12)(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@5.0.10) + '@keplr-wallet/unit': 0.12.172(starknet@6.18.0(encoding@0.1.13)) + '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) + axios: 1.7.9 + cosmjs-types: 0.9.0 + create-hash: 1.2.0 + keccak: 3.0.4 + viem: 2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) + transitivePeerDependencies: + - '@types/react' + - bufferutil + - debug + - graphql-ws + - react + - react-dom + - starknet + - subscriptions-transport-ws + - utf-8-validate + '@slack/events-api@3.0.1': dependencies: '@types/debug': 4.1.12 @@ -31227,6 +31792,10 @@ snapshots: dependencies: '@types/lodash': 4.17.14 + '@types/lodash.values@4.3.9': + dependencies: + '@types/lodash': 4.17.14 + '@types/lodash@4.17.14': {} '@types/long@4.0.2': {} @@ -31518,7 +32087,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 eslint: 9.16.0(jiti@2.4.2) optionalDependencies: typescript: 5.6.3 @@ -31564,7 +32133,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 eslint: 9.16.0(jiti@2.4.2) ts-api-utils: 1.4.3(typescript@5.6.3) optionalDependencies: @@ -31607,7 +32176,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 fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -31721,13 +32290,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/eslint-plugin@1.0.1(@typescript-eslint/utils@8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3))(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': + '@vitest/eslint-plugin@1.0.1(@typescript-eslint/utils@8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3))(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3)(vitest@2.1.5(@types/node@20.17.9)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': dependencies: eslint: 9.16.0(jiti@2.4.2) optionalDependencies: '@typescript-eslint/utils': 8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3) typescript: 5.6.3 - vitest: 2.1.5(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + vitest: 2.1.5(@types/node@20.17.9)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) '@vitest/expect@1.2.1': dependencies: @@ -31757,6 +32326,14 @@ snapshots: optionalDependencies: vite: 5.4.11(@types/node@22.10.5)(terser@5.37.0) + '@vitest/mocker@2.1.5(vite@5.4.11(@types/node@20.17.9)(terser@5.37.0))': + dependencies: + '@vitest/spy': 2.1.5 + estree-walker: 3.0.3 + magic-string: 0.30.17 + optionalDependencies: + vite: 5.4.11(@types/node@20.17.9)(terser@5.37.0) + '@vitest/mocker@2.1.5(vite@5.4.11(@types/node@22.10.5)(terser@5.37.0))': dependencies: '@vitest/spy': 2.1.5 @@ -32334,6 +32911,22 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@xtuc/long': 4.2.2 + '@wry/caches@1.0.1': + dependencies: + tslib: 2.8.1 + + '@wry/context@0.7.4': + dependencies: + tslib: 2.8.1 + + '@wry/equality@0.5.7': + dependencies: + tslib: 2.8.1 + + '@wry/trie@0.5.0': + dependencies: + tslib: 2.8.1 + '@xtuc/ieee754@1.2.0': {} '@xtuc/long@4.2.2': {} @@ -32448,7 +33041,7 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -32640,6 +33233,10 @@ snapshots: ansi-styles@2.2.1: {} + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -32879,7 +33476,7 @@ 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 @@ -32890,18 +33487,18 @@ snapshots: 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: dependencies: - follow-redirects: 1.15.9(debug@4.4.0) + follow-redirects: 1.15.9 transitivePeerDependencies: - debug axios@0.27.2: dependencies: - follow-redirects: 1.15.9(debug@4.4.0) + follow-redirects: 1.15.9 form-data: 4.0.1 transitivePeerDependencies: - debug @@ -32916,7 +33513,7 @@ snapshots: axios@1.7.4: dependencies: - follow-redirects: 1.15.9(debug@4.4.0) + follow-redirects: 1.15.9 form-data: 4.0.1 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -32938,6 +33535,14 @@ snapshots: transitivePeerDependencies: - debug + axios@1.7.9: + dependencies: + follow-redirects: 1.15.9 + 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) @@ -33776,6 +34381,12 @@ snapshots: strip-ansi: 3.0.1 supports-color: 2.0.0 + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + chalk@3.0.0: dependencies: ansi-styles: 4.3.0 @@ -34064,10 +34675,16 @@ snapshots: collect-v8-coverage@1.0.2: {} + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + color-convert@2.0.1: dependencies: color-name: 1.1.4 + color-name@1.1.3: {} + color-name@1.1.4: {} color-string@1.9.1: @@ -34338,6 +34955,16 @@ snapshots: serialize-javascript: 6.0.2 webpack: 5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15)) + copyfiles@2.4.1: + dependencies: + glob: 7.2.3 + minimatch: 3.1.2 + mkdirp: 1.0.4 + noms: 0.0.0 + through2: 2.0.5 + untildify: 4.0.0 + yargs: 16.2.0 + core-js-compat@3.39.0: dependencies: browserslist: 4.24.3 @@ -34365,9 +34992,9 @@ snapshots: dependencies: layout-base: 2.0.1 - cosmiconfig-typescript-loader@5.1.0(@types/node@22.10.5)(cosmiconfig@8.3.6(typescript@5.6.3))(typescript@5.6.3): + cosmiconfig-typescript-loader@5.1.0(@types/node@20.17.9)(cosmiconfig@8.3.6(typescript@5.6.3))(typescript@5.6.3): dependencies: - '@types/node': 22.10.5 + '@types/node': 20.17.9 cosmiconfig: 8.3.6(typescript@5.6.3) jiti: 1.21.7 typescript: 5.6.3 @@ -34396,6 +35023,16 @@ snapshots: optionalDependencies: typescript: 5.6.3 + cosmjs-types@0.7.2: + dependencies: + long: 4.0.0 + protobufjs: 6.11.4 + + cosmjs-types@0.8.0: + dependencies: + long: 4.0.0 + protobufjs: 6.11.4 + cosmjs-types@0.9.0: {} crc-32@1.2.2: {} @@ -35011,6 +35648,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.4.0: + dependencies: + ms: 2.1.3 + debug@4.4.0(supports-color@5.5.0): dependencies: ms: 2.1.3 @@ -35973,7 +36614,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 escape-string-regexp: 4.0.0 eslint-scope: 8.2.0 eslint-visitor-keys: 4.2.0 @@ -36190,6 +36831,14 @@ snapshots: ethjs-util: 0.1.6 rlp: 2.2.7 + ethereumjs-util@7.1.5: + dependencies: + '@types/bn.js': 5.1.6 + bn.js: 5.2.1 + create-hash: 1.2.0 + ethereum-cryptography: 0.1.3 + rlp: 2.2.7 + ethers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10): dependencies: '@ethersproject/abi': 5.7.0 @@ -36662,6 +37311,8 @@ snapshots: async: 0.2.10 which: 1.3.1 + follow-redirects@1.15.9: {} + follow-redirects@1.15.9(debug@4.3.7): optionalDependencies: debug: 4.3.7 @@ -37783,7 +38434,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 transitivePeerDependencies: - supports-color @@ -37817,6 +38468,8 @@ snapshots: jsprim: 1.4.2 sshpk: 1.18.0 + http-status-codes@2.3.0: {} + http2-wrapper@1.0.3: dependencies: quick-lru: 5.1.1 @@ -37839,14 +38492,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 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 transitivePeerDependencies: - supports-color @@ -38431,7 +39084,7 @@ snapshots: istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0 istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -39115,6 +39768,8 @@ snapshots: jsbn@1.1.0: {} + jscrypto@1.0.3: {} + jsdoc-type-pratt-parser@4.0.0: {} jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10): @@ -39219,6 +39874,8 @@ snapshots: jsonpointer@5.0.1: {} + jsonschema@1.5.0: {} + jsonwebtoken@9.0.2: dependencies: jws: 3.2.2 @@ -39575,6 +40232,10 @@ snapshots: lines-and-columns@2.0.3: {} + link-module-alias@1.2.0: + dependencies: + chalk: 2.4.2 + linkify-it@5.0.0: dependencies: uc.micro: 2.1.0 @@ -39740,6 +40401,8 @@ snapshots: lodash.upperfirst@4.3.1: {} + lodash.values@4.3.0: {} + lodash@4.17.21: {} log-symbols@4.1.0: @@ -39924,7 +40587,7 @@ snapshots: md5.js@1.3.5: dependencies: - hash-base: 3.0.5 + hash-base: 3.1.0 inherits: 2.0.4 safe-buffer: 5.2.1 @@ -41140,6 +41803,11 @@ snapshots: touch: 3.1.1 undefsafe: 2.0.5 + noms@0.0.0: + dependencies: + inherits: 2.0.4 + readable-stream: 1.0.34 + nopt@1.0.10: dependencies: abbrev: 1.1.1 @@ -41276,7 +41944,7 @@ 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) + axios: 1.7.9 chalk: 4.1.0 cli-cursor: 3.1.0 cli-spinners: 2.6.1 @@ -41550,6 +42218,13 @@ snapshots: opener@1.5.2: {} + optimism@0.18.1: + dependencies: + '@wry/caches': 1.0.1 + '@wry/context': 0.7.4 + '@wry/trie': 0.5.0 + tslib: 2.8.1 + optional@0.1.4: {} optionator@0.9.4: @@ -43664,6 +44339,11 @@ snapshots: dependencies: jsesc: 3.0.2 + rehackt@0.1.0(@types/react@18.3.12)(react@18.3.1): + optionalDependencies: + '@types/react': 18.3.12 + react: 18.3.1 + rehype-parse@7.0.1: dependencies: hast-util-from-parse5: 6.0.1 @@ -43833,6 +44513,8 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + response-iterator@0.2.11: {} + responselike@2.0.1: dependencies: lowercase-keys: 2.0.0 @@ -44305,6 +44987,11 @@ snapshots: shimmer@1.2.1: {} + shx@0.3.4: + dependencies: + minimist: 1.2.8 + shelljs: 0.8.5 + side-channel-list@1.0.0: dependencies: es-errors: 1.3.0 @@ -44443,6 +45130,12 @@ snapshots: dot-case: 3.0.4 tslib: 2.8.1 + snakecase-keys@5.5.0: + dependencies: + map-obj: 4.3.0 + snake-case: 3.0.4 + type-fest: 3.13.1 + sockjs@0.3.24: dependencies: faye-websocket: 0.11.4 @@ -44452,7 +45145,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 socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -44754,6 +45447,8 @@ snapshots: steno@4.0.2: {} + store2@2.14.4: {} + stream-browserify@3.0.0: dependencies: inherits: 2.0.4 @@ -45017,6 +45712,8 @@ snapshots: symbol-observable@2.0.3: {} + symbol-observable@4.0.0: {} + symbol-tree@3.2.4: {} symbol.inspect@1.0.1: {} @@ -45365,6 +46062,10 @@ snapshots: ts-interface-checker@0.1.13: {} + ts-invariant@0.10.3: + dependencies: + tslib: 2.8.1 + 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))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)))(typescript@5.6.3): dependencies: bs-logger: 0.2.6 @@ -45404,12 +46105,12 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.26.0) - 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.10.5))(typescript@5.6.3): + 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@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)))(typescript@5.6.3): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@22.10.5) + jest: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -45560,7 +46261,7 @@ snapshots: cac: 6.7.14 chokidar: 4.0.3 consola: 3.3.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0 esbuild: 0.24.2 joycon: 3.1.1 picocolors: 1.1.1 @@ -45594,7 +46295,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 make-fetch-happen: 13.0.1 transitivePeerDependencies: - supports-color @@ -45673,6 +46374,8 @@ snapshots: type-fest@2.19.0: {} + type-fest@3.13.1: {} + type-fest@4.31.0: {} type-is@1.6.18: @@ -46025,6 +46728,8 @@ snapshots: idb-keyval: 6.2.1 ioredis: 5.4.2 + untildify@4.0.0: {} + untyped@1.5.2: dependencies: '@babel/core': 7.26.0 @@ -46315,6 +47020,24 @@ snapshots: - supports-color - terser + vite-node@2.1.5(@types/node@20.17.9)(terser@5.37.0): + dependencies: + cac: 6.7.14 + debug: 4.4.0 + es-module-lexer: 1.6.0 + pathe: 1.1.2 + vite: 5.4.11(@types/node@20.17.9)(terser@5.37.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + vite-node@2.1.5(@types/node@22.10.5)(terser@5.37.0): dependencies: cac: 6.7.14 @@ -46503,6 +47226,42 @@ snapshots: - supports-color - terser + vitest@2.1.5(@types/node@20.17.9)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0): + dependencies: + '@vitest/expect': 2.1.5 + '@vitest/mocker': 2.1.5(vite@5.4.11(@types/node@20.17.9)(terser@5.37.0)) + '@vitest/pretty-format': 2.1.8 + '@vitest/runner': 2.1.5 + '@vitest/snapshot': 2.1.5 + '@vitest/spy': 2.1.5 + '@vitest/utils': 2.1.5 + chai: 5.1.2 + debug: 4.4.0 + expect-type: 1.1.0 + magic-string: 0.30.17 + pathe: 1.1.2 + std-env: 3.8.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinypool: 1.0.2 + tinyrainbow: 1.2.0 + vite: 5.4.11(@types/node@20.17.9)(terser@5.37.0) + vite-node: 2.1.5(@types/node@20.17.9)(terser@5.37.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 20.17.9 + jsdom: 25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10) + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + vitest@2.1.5(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0): dependencies: '@vitest/expect': 2.1.5 @@ -47402,6 +48161,12 @@ snapshots: toposort: 2.0.2 type-fest: 2.19.0 + zen-observable-ts@1.2.5: + dependencies: + zen-observable: 0.8.15 + + zen-observable@0.8.15: {} + zimmerframe@1.1.2: {} zlibjs@0.3.1: {} From 2c4b037018ddfebe8c73450f9d4d8f145bf3d89d Mon Sep 17 00:00:00 2001 From: KacperKoza34 Date: Thu, 9 Jan 2025 16:35:30 +0100 Subject: [PATCH 4/8] feat: add bridge data fetcher and update tests --- .../src/actions/ibc-transfer/index.ts | 8 +- .../src/actions/ibc-transfer/schema.ts | 28 ++ .../services/bridge-denom-provider.ts | 26 ++ .../services/ibc-transfer-action-service.ts | 32 +- .../src/actions/ibc-transfer/types.ts | 16 +- packages/plugin-cosmos/src/index.ts | 6 +- .../src/providers/wallet/index.ts | 2 +- .../entities/cosmos-wallet-chains-data.ts | 17 +- .../plugin-cosmos/src/shared/interfaces.ts | 7 +- .../shared/services/bridge-data-fetcher.ts | 71 ++++ .../src/tests/bridge-data-fetcher.test.ts | 101 +++++ .../src/tests/bridge-denom-provider.test.ts | 83 ++++ ...cosmos-ibc-transfer-action-service.test.ts | 377 ++++++------------ .../tests/cosmos-wallet-chains-data.test.ts | 5 + packages/plugin-cosmos/tsup.config.ts | 1 - 15 files changed, 503 insertions(+), 277 deletions(-) create mode 100644 packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-denom-provider.ts create mode 100644 packages/plugin-cosmos/src/shared/services/bridge-data-fetcher.ts create mode 100644 packages/plugin-cosmos/src/tests/bridge-data-fetcher.test.ts create mode 100644 packages/plugin-cosmos/src/tests/bridge-denom-provider.test.ts diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts index 6998112ac79..217d4e1c21a 100644 --- a/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts @@ -18,12 +18,13 @@ import type { } from "../../shared/interfaces"; import { IBCTransferActionParams } from "./types"; import { IBCTransferAction } from "./services/ibc-transfer-action-service"; +import { bridgeDenomProvider } from "./services/bridge-denom-provider"; export const createIBCTransferAction = ( pluginOptions: ICosmosPluginOptions ) => ({ name: "COSMOS_IBC_TRANSFER", - description: "Transfer tokens between addresses on cosmos chains", + description: "Transfer tokens between addresses on cosmos chains", handler: async ( _runtime: IAgentRuntime, _message: Memory, @@ -63,12 +64,13 @@ export const createIBCTransferAction = ( const transferResp = await action.execute( paramOptions, + bridgeDenomProvider, customAssets ); if (_callback) { await _callback({ - text: `Successfully transferred ${paramOptions.amount} tokens from ${paramOptions.chainName} to ${paramOptions.toAddress} on ${paramOptions.targetChainName}\nGas paid: ${transferResp.gasPaid}\nTransaction Hash: ${transferResp.txHash}`, + text: `Successfully transferred ${paramOptions.amount} tokens from ${paramOptions.chainName} to ${paramOptions.toAddress} on ${paramOptions.targetChainName}\nTransaction Hash: ${transferResp.txHash}`, content: { success: true, hash: transferResp.txHash, @@ -84,7 +86,7 @@ export const createIBCTransferAction = ( agentId: _message.agentId, roomId: _message.roomId, content: { - text: `Transaction ${paramOptions.amount} ${paramOptions.symbol} to address ${paramOptions.toAddress} from chain ${paramOptions.chainName} to ${paramOptions.targetChainName} was successfully transferred.\n Gas paid: ${transferResp.gasPaid}. Tx hash: ${transferResp.txHash}`, + text: `Transaction ${paramOptions.amount} ${paramOptions.symbol} to address ${paramOptions.toAddress} from chain ${paramOptions.chainName} to ${paramOptions.targetChainName} was successfully transferred. Tx hash: ${transferResp.txHash}`, }, }; diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/schema.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/schema.ts index 62e30be681d..018e892d242 100644 --- a/packages/plugin-cosmos/src/actions/ibc-transfer/schema.ts +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/schema.ts @@ -7,3 +7,31 @@ export const IBCTransferParamsSchema = z.object({ toAddress: z.string(), targetChainName: z.string(), }); + +export const bridgeDataProviderParamsSchema = z.object({ + source_asset_denom: z.string(), + source_asset_chain_id: z.string(), + allow_multi_tx: z.boolean(), +}); + +export const bridgeDataProviderResponseAssetsSchema = z.object({ + denom: z.string(), + chain_id: z.string(), + origin_denom: z.string(), + origin_chain_id: z.string(), + trace: z.string(), + symbol: z.string().optional(), + name: z.string().optional(), + logo_uri: z.string().optional(), + decimals: z.number().optional(), + recommended_symbol: z.string().optional(), +}); + +export const bridgeDataProviderResponseSchema = z.object({ + dest_assets: z.record( + z.string(), + z.object({ + assets: z.array(bridgeDataProviderResponseAssetsSchema), + }) + ), +}); diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-denom-provider.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-denom-provider.ts new file mode 100644 index 00000000000..cab8e79e580 --- /dev/null +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-denom-provider.ts @@ -0,0 +1,26 @@ +import { IDenomProvider } from "../../../shared/interfaces"; +import { BridgeDataFetcher } from "../../../shared/services/bridge-data-fetcher"; + +export const bridgeDenomProvider: IDenomProvider = async ( + sourceAssetDenom: string, + sourceAssetChainId: string, + destChainId: string +) => { + const bridgeDataFetcher = BridgeDataFetcher.getInstance(); + const bridgeData = await bridgeDataFetcher.fetchBridgeData( + sourceAssetDenom, + sourceAssetChainId + ); + + const ibcAssetData = bridgeData.dest_assets[destChainId]?.assets?.find( + ({ origin_denom }) => origin_denom === sourceAssetDenom + ); + + if (!ibcAssetData.denom) { + throw new Error("No IBC asset data"); + } + + return { + denom: ibcAssetData.denom, + }; +}; diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/services/ibc-transfer-action-service.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/services/ibc-transfer-action-service.ts index 7a132eb2995..65c0ab72570 100644 --- a/packages/plugin-cosmos/src/actions/ibc-transfer/services/ibc-transfer-action-service.ts +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/services/ibc-transfer-action-service.ts @@ -1,10 +1,12 @@ import { + convertDisplayUnitToBaseUnit, getAssetBySymbol, + getChainByChainId, getChainByChainName, - getChainIdByChainName, } from "@chain-registry/utils"; import { assets, chains } from "chain-registry"; import type { + IDenomProvider, ICosmosActionService, ICosmosPluginCustomChainData, ICosmosTransaction, @@ -20,6 +22,7 @@ export class IBCTransferAction implements ICosmosActionService { async execute( params: IBCTransferActionParams, + bridgeDenomProvider: IDenomProvider, customChainAssets?: ICosmosPluginCustomChainData["assets"][] ): Promise { const senderAddress = await this.cosmosWalletChains.getWalletAddress( @@ -66,6 +69,7 @@ export class IBCTransferAction implements ICosmosActionService { if (!denom.base) { throw new Error("Cannot find asset"); } + if (!sourceChain) { throw new Error("Cannot find source chain"); } @@ -74,23 +78,34 @@ export class IBCTransferAction implements ICosmosActionService { throw new Error("Cannot find destination chain"); } + const { denom: destAssetDenom } = await bridgeDenomProvider( + denom.base, + sourceChain.chain_id, + destChain.chain_id + ); + const route = await skipClient.route({ destAssetChainID: destChain.chain_id, - destAssetDenom: denom.base, + destAssetDenom, sourceAssetChainID: sourceChain.chain_id, sourceAssetDenom: denom.base, - amountOut: params.amount, + amountIn: convertDisplayUnitToBaseUnit( + availableAssets, + params.symbol, + params.amount, + params.chainName + ), + cumulativeAffiliateFeeBPS: "0", }); const userAddresses = await Promise.all( route.requiredChainAddresses.map(async (chainID) => { - const chainName = getChainIdByChainName(chains, chainID); + const chain = getChainByChainId(chains, chainID); return { chainID, - address: - await this.cosmosWalletChains.getWalletAddress( - chainName - ), + address: await this.cosmosWalletChains.getWalletAddress( + chain.chain_name + ), }; }) ); @@ -104,7 +119,6 @@ export class IBCTransferAction implements ICosmosActionService { txHash = executeRouteTxHash; }, }); - return { from: senderAddress, to: params.toAddress, diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/types.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/types.ts index 349bfb2fb81..ba62b9cd48d 100644 --- a/packages/plugin-cosmos/src/actions/ibc-transfer/types.ts +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/types.ts @@ -1,4 +1,18 @@ import { z } from "zod"; -import { IBCTransferParamsSchema } from "./schema"; +import { + bridgeDataProviderParamsSchema, + bridgeDataProviderResponseAssetsSchema, + bridgeDataProviderResponseSchema, + IBCTransferParamsSchema, +} from "./schema"; export type IBCTransferActionParams = z.infer; +export type BridgeDataProviderParams = z.infer< + typeof bridgeDataProviderParamsSchema +>; +export type BridgeDataProviderResponseAsset = z.infer< + typeof bridgeDataProviderResponseAssetsSchema +>; +export type BridgeDataProviderResponse = z.infer< + typeof bridgeDataProviderResponseSchema +>; diff --git a/packages/plugin-cosmos/src/index.ts b/packages/plugin-cosmos/src/index.ts index ce2fff5c4b0..bbd3ace40ee 100644 --- a/packages/plugin-cosmos/src/index.ts +++ b/packages/plugin-cosmos/src/index.ts @@ -2,6 +2,7 @@ import { createTransferAction } from "./actions/transfer"; import type { Plugin } from "@elizaos/core"; import { createCosmosWalletProvider } from "./providers/wallet"; import { ICosmosPluginOptions } from "./shared/interfaces"; +import { createIBCTransferAction } from "./actions/ibc-transfer"; export const createCosmosPlugin = ( pluginOptions?: ICosmosPluginOptions @@ -11,7 +12,10 @@ export const createCosmosPlugin = ( providers: [createCosmosWalletProvider(pluginOptions)], evaluators: [], services: [], - actions: [createTransferAction(pluginOptions)], + actions: [ + createTransferAction(pluginOptions), + createIBCTransferAction(pluginOptions), + ], }); export default createCosmosPlugin; diff --git a/packages/plugin-cosmos/src/providers/wallet/index.ts b/packages/plugin-cosmos/src/providers/wallet/index.ts index 04b73bf2bb8..a1f3b9dfeaf 100644 --- a/packages/plugin-cosmos/src/providers/wallet/index.ts +++ b/packages/plugin-cosmos/src/providers/wallet/index.ts @@ -1,4 +1,4 @@ -import { IAgentRuntime } from "@ai16z/eliza"; +import { IAgentRuntime } from "@elizaos/core"; import { convertBaseUnitToDisplayUnit, getSymbolByDenom, diff --git a/packages/plugin-cosmos/src/shared/entities/cosmos-wallet-chains-data.ts b/packages/plugin-cosmos/src/shared/entities/cosmos-wallet-chains-data.ts index 3c4cc70f9a4..076366c0daa 100644 --- a/packages/plugin-cosmos/src/shared/entities/cosmos-wallet-chains-data.ts +++ b/packages/plugin-cosmos/src/shared/entities/cosmos-wallet-chains-data.ts @@ -65,7 +65,12 @@ export class CosmosWalletChains implements ICosmosWalletChains { } public async getWalletAddress(chainName: string) { - return await this.walletChainsData[chainName].wallet.getWalletAddress(); + const chainWalletsForGivenChain = this.walletChainsData[chainName]; + if (!chainWalletsForGivenChain) { + throw new Error("Invalid chain name"); + } + + return await chainWalletsForGivenChain.wallet.getWalletAddress(); } public getSigningCosmWasmClient(chainName: string) { @@ -73,10 +78,12 @@ export class CosmosWalletChains implements ICosmosWalletChains { } public getSkipClient(chainName: string): SkipClient { - return this.walletChainsData[chainName].skipClient; - } + const chainWalletsForGivenChain = this.walletChainsData[chainName]; + + if (!chainWalletsForGivenChain) { + throw new Error("Invalid chain name"); + } - public async getUserAddress(chainName: string): Promise { - return this.walletChainsData[chainName].wallet.getWalletAddress(); + return chainWalletsForGivenChain.skipClient; } } diff --git a/packages/plugin-cosmos/src/shared/interfaces.ts b/packages/plugin-cosmos/src/shared/interfaces.ts index 2f4dc2438c3..b9978f821e6 100644 --- a/packages/plugin-cosmos/src/shared/interfaces.ts +++ b/packages/plugin-cosmos/src/shared/interfaces.ts @@ -48,9 +48,10 @@ export interface ICosmosWalletChainsData { [chainName: string]: ICosmosChainWallet; } -export interface IBridgeDataProvider { +export interface IDenomProvider { ( sourceAssetDenom: string, - sourceAssetChainId: string - ): Promise<{ channelId: string; portId: string; ibcDenom: string }>; + sourceAssetChainId: string, + destChainId: string + ): Promise<{ denom: string }>; } diff --git a/packages/plugin-cosmos/src/shared/services/bridge-data-fetcher.ts b/packages/plugin-cosmos/src/shared/services/bridge-data-fetcher.ts new file mode 100644 index 00000000000..84c44277c6f --- /dev/null +++ b/packages/plugin-cosmos/src/shared/services/bridge-data-fetcher.ts @@ -0,0 +1,71 @@ +import { bridgeDataProviderResponseSchema } from "../../actions/ibc-transfer/schema"; +import { + BridgeDataProviderParams, + BridgeDataProviderResponse, +} from "../../actions/ibc-transfer/types"; +import axios from "axios"; + +type CacheKey = `${string}_${string}`; + +export class BridgeDataFetcher { + private static instance: BridgeDataFetcher; + private cache: Map; + private readonly apiUrl: string; + + private constructor() { + this.cache = new Map(); + this.apiUrl = "https://api.skip.build/v2/fungible/assets_from_source"; + } + + public static getInstance(): BridgeDataFetcher { + if (!BridgeDataFetcher.instance) { + BridgeDataFetcher.instance = new BridgeDataFetcher(); + } + return BridgeDataFetcher.instance; + } + + private generateCacheKey( + sourceAssetDenom: string, + sourceAssetChainId: string + ): CacheKey { + return `${sourceAssetDenom}_${sourceAssetChainId}`; + } + + public async fetchBridgeData( + sourceAssetDenom: string, + sourceAssetChainId: string + ): Promise { + const cacheKey = this.generateCacheKey( + sourceAssetDenom, + sourceAssetChainId + ); + + if (this.cache.has(cacheKey)) { + return this.cache.get(cacheKey)!; + } + + const requestData: BridgeDataProviderParams = { + source_asset_denom: sourceAssetDenom, + source_asset_chain_id: sourceAssetChainId, + allow_multi_tx: false, + }; + + try { + const response = await axios.post(this.apiUrl, requestData, { + headers: { + "Content-Type": "application/json", + }, + }); + + const validResponse = bridgeDataProviderResponseSchema.parse( + response.data + ); + + this.cache.set(cacheKey, validResponse); + return response.data; + } catch (error) { + console.error("Error fetching assets:", error); + throw error; + } + } +} diff --git a/packages/plugin-cosmos/src/tests/bridge-data-fetcher.test.ts b/packages/plugin-cosmos/src/tests/bridge-data-fetcher.test.ts new file mode 100644 index 00000000000..d7c7955a0b9 --- /dev/null +++ b/packages/plugin-cosmos/src/tests/bridge-data-fetcher.test.ts @@ -0,0 +1,101 @@ +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { BridgeDataFetcher } from "../shared/services/bridge-data-fetcher"; +import axios from "axios"; + +vi.mock("axios"); + +describe("BridgeDataFetcher", () => { + let fetcher: BridgeDataFetcher; + + beforeEach(() => { + fetcher = BridgeDataFetcher.getInstance(); + vi.clearAllMocks(); + }); + + it("should return the same instance from getInstance", () => { + const fetcher1 = BridgeDataFetcher.getInstance(); + const fetcher2 = BridgeDataFetcher.getInstance(); + expect(fetcher1).toBe(fetcher2); + }); + + it("should use cache when data is already fetched", async () => { + const mockResponse = { + dest_assets: { + someKey: { + assets: [ + { + denom: "atom", + chain_id: "cosmos", + origin_denom: "atom", + origin_chain_id: "cosmos", + trace: "someTrace", + symbol: "ATOM", + name: "Cosmos Atom", + logo_uri: "http://someurl.com/logo.png", + decimals: 6, + recommended_symbol: "ATOM", + }, + ], + }, + }, + }; + + // @ts-expect-error -- ... + axios.post.mockResolvedValueOnce({ data: mockResponse }); + + const sourceAssetDenom = "atom"; + const sourceAssetChainId = "cosmos"; + + await fetcher.fetchBridgeData(sourceAssetDenom, sourceAssetChainId); + + expect(axios.post).toHaveBeenCalledTimes(1); + + await fetcher.fetchBridgeData(sourceAssetDenom, sourceAssetChainId); + expect(axios.post).toHaveBeenCalledTimes(1); // axios nie powinien być wywołany ponownie + }); + + it("should fetch and cache data correctly", async () => { + const mockResponse = { + dest_assets: { + someKey: { + assets: [ + { + denom: "atom", + chain_id: "cosmos", + origin_denom: "atom", + origin_chain_id: "cosmos", + trace: "someTrace", + symbol: "ATOM", + name: "Cosmos Atom", + logo_uri: "http://someurl.com/logo.png", + decimals: 6, + recommended_symbol: "ATOM", + }, + ], + }, + }, + }; + + // @ts-expect-error -- ... + axios.post.mockResolvedValueOnce({ data: mockResponse }); + + const sourceAssetDenom = "atom"; + const sourceAssetChainId = "cosmos"; + + const result = await fetcher.fetchBridgeData( + sourceAssetDenom, + sourceAssetChainId + ); + + expect(result).toEqual(mockResponse); + + const cacheKey = `${sourceAssetDenom}_${sourceAssetChainId}`; + expect(fetcher["cache"].has(cacheKey)).toBe(true); + + const cachedResult = await fetcher.fetchBridgeData( + sourceAssetDenom, + sourceAssetChainId + ); + expect(cachedResult).toEqual(mockResponse); + }); +}); diff --git a/packages/plugin-cosmos/src/tests/bridge-denom-provider.test.ts b/packages/plugin-cosmos/src/tests/bridge-denom-provider.test.ts new file mode 100644 index 00000000000..2363a0e99ae --- /dev/null +++ b/packages/plugin-cosmos/src/tests/bridge-denom-provider.test.ts @@ -0,0 +1,83 @@ +import { vi, expect, it, beforeEach, describe } from "vitest"; +import { BridgeDataFetcher } from "../shared/services/bridge-data-fetcher"; +import { bridgeDenomProvider } from "../actions/ibc-transfer/services/bridge-denom-provider"; + +vi.mock("./bridge-data-fetcher", () => ({ + BridgeDataFetcher: { + getInstance: vi.fn().mockReturnValue({ + fetchBridgeData: vi.fn(), + }), + }, +})); + +describe("bridgeDataProvider", () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let mockFetchBridgeData: any; + + beforeEach(() => { + mockFetchBridgeData = vi.fn(); + BridgeDataFetcher.getInstance().fetchBridgeData = mockFetchBridgeData; + }); + + it("should return correct channelId and ibcDenom when valid data is returned", async () => { + const mockResponse = { + dest_assets: { + osmos: { + assets: [ + { + origin_denom: "atom", + denom: "uatom", + trace: "channel-123/abc", + }, + ], + }, + }, + }; + + mockFetchBridgeData.mockResolvedValue(mockResponse); + + const sourceAssetDenom = "atom"; + const sourceAssetChainId = "cosmos"; + const destinationAdssetChainId = "osmos"; + + const result = await bridgeDenomProvider( + sourceAssetDenom, + sourceAssetChainId, + destinationAdssetChainId + ); + + expect(result).toEqual({ + denom: "uatom", + }); + }); + + it("should throw an error when ibcAssetData is not found", async () => { + const mockResponse = { + dest_assets: { + osmos: { + assets: [ + { + origin_denom: "btc", + denom: "ubtc", + trace: "channel-123/abc", + }, + ], + }, + }, + }; + + mockFetchBridgeData.mockResolvedValue(mockResponse); + + const sourceAssetDenom = "atom"; + const sourceAssetChainId = "cosmos"; + const destinationAdssetChainId = "osmos"; + + await expect( + bridgeDenomProvider( + sourceAssetDenom, + sourceAssetChainId, + destinationAdssetChainId + ) + ).rejects.toThrowError(); + }); +}); diff --git a/packages/plugin-cosmos/src/tests/cosmos-ibc-transfer-action-service.test.ts b/packages/plugin-cosmos/src/tests/cosmos-ibc-transfer-action-service.test.ts index 1c1b3dbf7b3..03311aca8d4 100644 --- a/packages/plugin-cosmos/src/tests/cosmos-ibc-transfer-action-service.test.ts +++ b/packages/plugin-cosmos/src/tests/cosmos-ibc-transfer-action-service.test.ts @@ -1,309 +1,180 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; -import { IBCTransferAction } from "../actions/ibc-transfer/services/ibc-transfer-action-service"; -import { IBCTransferActionParams } from "../actions/ibc-transfer/types"; -import { getAssetBySymbol, getChainByChainName } from "@chain-registry/utils"; - -vi.mock("@cosmjs/cosmwasm-stargate", () => ({ - SigningCosmWasmClient: { - connectWithSigner: vi.fn(), - }, -})); +import { IBCTransferAction } from "../actions/ibc-transfer/services/ibc-transfer-action-service"; // dostosuj ścieżkę do pliku +import { assets } from "chain-registry"; +import * as CosmosAssetsHelpers from "../shared/helpers/cosmos-assets"; +import { getAssetBySymbol } from "@chain-registry/utils"; +import { getAvailableAssets } from "../shared/helpers/cosmos-assets"; vi.mock("@chain-registry/utils", () => ({ - getAssetBySymbol: vi.fn().mockReturnValue({ base: "uatom" }), - getChainByChainName: vi - .fn() - .mockResolvedValue({ chain_id: "cosmos-chain-id" }), - convertDisplayUnitToBaseUnit: vi.fn().mockResolvedValue("100000000"), -})); - -vi.mock("../shared/services/cosmos-transaction-fee-estimator", () => ({ - CosmosTransactionFeeEstimator: { - estimateGasForIBCTransfer: vi.fn().mockResolvedValue(BigInt(200_000)), - }, + getAssetBySymbol: vi.fn(), + getChainByChainName: vi.fn((_, chainName: string) => { + if (chainName === "test-chain") return { chain_id: "source-chain-id" }; + return { chain_id: "target-chain-id" }; + }), + convertDisplayUnitToBaseUnit: vi.fn(() => "1"), + getChainByChainId: vi.fn(() => ({ chainId: "target-chain-id" })), })); vi.mock("../shared/helpers/cosmos-assets", () => ({ - getAvailableAssets: vi.fn().mockResolvedValue([]), -})); - -vi.mock("../shared/helpers/cosmos-transaction-receipt.ts", () => ({ - getPaidFeeFromReceipt: vi.fn().mockReturnValue("200000"), + getAvailableAssets: vi.fn(), })); describe("IBCTransferAction", () => { - const mockSigningCosmWasmClient = { - sendTokens: vi.fn().mockResolvedValue({ - transactionHash: "mockTxHash", - }), + const mockWalletChains = { + getWalletAddress: vi.fn(), + getSkipClient: vi.fn(), }; - const mockCosmosWalletChains = { - walletChainsData: {}, - getWalletAddress: vi.fn().mockResolvedValue("senderAddress"), - getSigningCosmWasmClient: vi - .fn() - .mockReturnValue(mockSigningCosmWasmClient), + const mockBridgeDenomProvider = vi.fn(); + const mockSkipClient = { + route: vi.fn(), + executeRoute: vi.fn(), }; - beforeEach(() => { - vi.clearAllMocks(); - }); - - it("should execute transfer successfully", async () => { - const params: IBCTransferActionParams = { - chainName: "cosmos", - toAddress: "cosmosReceiverAddress", - targetChainName: "cosmosTarget", - symbol: "atom", - amount: "100", - }; - - const mockBridgeDataProvider = vi.fn().mockResolvedValue({ - ibcDenom: "uatom", - channelId: "channel-1", - portId: "transfer", - }); - - const cosmosIBCTransferAction = new IBCTransferAction( - mockCosmosWalletChains - ); + const params = { + chainName: "test-chain", + targetChainName: "target-chain", + symbol: "ATOM", + amount: "10", + toAddress: "cosmos1receiveraddress", + }; - const expectedResult = { - from: "senderAddress", - to: "cosmosReceiverAddress", - gasPaid: "200000", - txHash: "mockTxHash", - }; + const customChainAssets = []; - await expect( - cosmosIBCTransferAction.execute(params, mockBridgeDataProvider) - ).resolves.toEqual(expectedResult); + beforeEach(() => { + vi.clearAllMocks(); + mockWalletChains.getSkipClient.mockReturnValue(mockSkipClient); }); - it("should throw error if transaction fails", async () => { - const params: IBCTransferActionParams = { - chainName: "cosmos", - toAddress: "cosmosReceiverAddress", - targetChainName: "cosmosTarget", - symbol: "atom", - amount: "100", - }; - - mockSigningCosmWasmClient.sendTokens.mockRejectedValue( - new Error("Transaction Failed") - ); - - const mockBridgeDataProvider = vi.fn().mockResolvedValue({ - ibcDenom: "uatom", - channelId: "channel-1", - portId: "transfer", - }); - - const cosmosIBCTransferAction = new IBCTransferAction( - mockCosmosWalletChains - ); + it("throws an error if sender address is not available", async () => { + mockWalletChains.getWalletAddress.mockResolvedValue(null); + // @ts-expect-error --- ... + const ibcTransferAction = new IBCTransferAction(mockWalletChains); await expect( - cosmosIBCTransferAction.execute(params, mockBridgeDataProvider) - ).rejects.toThrow("Transaction Failed"); - }); - - it("should throw error if no wallet address is found", async () => { - const params: IBCTransferActionParams = { - chainName: "cosmos", - toAddress: "cosmosReceiverAddress", - targetChainName: "cosmosTarget", - symbol: "atom", - amount: "100", - }; - - mockCosmosWalletChains.getWalletAddress.mockResolvedValue(null); // Brak adresu portfela - - const mockBridgeDataProvider = vi.fn().mockResolvedValue({ - ibcDenom: "uatom", - channelId: "channel-1", - portId: "transfer", - }); - - const cosmosIBCTransferAction = new IBCTransferAction( - mockCosmosWalletChains + ibcTransferAction.execute( + params, + mockBridgeDenomProvider, + customChainAssets + ) + ).rejects.toThrow( + `Cannot get wallet address for chain ${params.chainName}` ); - - await expect( - cosmosIBCTransferAction.execute(params, mockBridgeDataProvider) - ).rejects.toThrow("Cannot get wallet address for chain cosmos"); }); - it("should throw error if no receiver address is provided", async () => { - const params: IBCTransferActionParams = { - chainName: "cosmos", - toAddress: "", - targetChainName: "cosmosTarget", - symbol: "atom", - amount: "100", - }; - - const mockBridgeDataProvider = vi.fn().mockResolvedValue({ - ibcDenom: "uatom", - channelId: "channel-1", - portId: "transfer", - }); - mockCosmosWalletChains.getWalletAddress.mockResolvedValue( - "cosmos1address" - ); - - const cosmosIBCTransferAction = new IBCTransferAction( - mockCosmosWalletChains + it("throws an error if receiver address is missing", async () => { + const invalidParams = { ...params, toAddress: undefined }; + mockWalletChains.getWalletAddress.mockResolvedValue( + "cosmos1senderaddress" ); + // @ts-expect-error --- ... + const ibcTransferAction = new IBCTransferAction(mockWalletChains); await expect( - cosmosIBCTransferAction.execute(params, mockBridgeDataProvider) + ibcTransferAction.execute( + invalidParams, + mockBridgeDenomProvider, + customChainAssets + ) ).rejects.toThrow("No receiver address"); }); - it("should throw error if no symbol is provided", async () => { - const params: IBCTransferActionParams = { - chainName: "cosmos", - toAddress: "cosmosReceiverAddress", - targetChainName: "cosmosTarget", - symbol: "", - amount: "100", - }; - - const mockBridgeDataProvider = vi.fn().mockResolvedValue({ - ibcDenom: "uatom", - channelId: "channel-1", - portId: "transfer", - }); - - mockCosmosWalletChains.getWalletAddress.mockResolvedValue( - "cosmos1address" - ); - - const cosmosIBCTransferAction = new IBCTransferAction( - mockCosmosWalletChains + it("throws an error if target chain name is missing", async () => { + const invalidParams = { ...params, targetChainName: undefined }; + mockWalletChains.getWalletAddress.mockResolvedValue( + "cosmos1senderaddress" ); + // @ts-expect-error --- ... + const ibcTransferAction = new IBCTransferAction(mockWalletChains); await expect( - cosmosIBCTransferAction.execute(params, mockBridgeDataProvider) - ).rejects.toThrow("No symbol"); + ibcTransferAction.execute( + invalidParams, + mockBridgeDenomProvider, + customChainAssets + ) + ).rejects.toThrow("No target chain name"); }); - it("should throw error if no chainName is provided", async () => { - const params: IBCTransferActionParams = { - chainName: "", - toAddress: "cosmosReceiverAddress", - targetChainName: "cosmosTarget", - symbol: "atom", - amount: "100", - }; - - const mockBridgeDataProvider = vi.fn().mockResolvedValue({ - ibcDenom: "uatom", - channelId: "channel-1", - portId: "transfer", - }); - - mockCosmosWalletChains.getWalletAddress.mockResolvedValue( - "cosmos1address" - ); - - const cosmosIBCTransferAction = new IBCTransferAction( - mockCosmosWalletChains + it("throws an error if symbol is missing", async () => { + const invalidParams = { ...params, symbol: undefined }; + mockWalletChains.getWalletAddress.mockResolvedValue( + "cosmos1senderaddress" ); + // @ts-expect-error --- ... + const ibcTransferAction = new IBCTransferAction(mockWalletChains); await expect( - cosmosIBCTransferAction.execute(params, mockBridgeDataProvider) - ).rejects.toThrow("No chain name"); + ibcTransferAction.execute( + invalidParams, + mockBridgeDenomProvider, + customChainAssets + ) + ).rejects.toThrow("No symbol"); }); - it("should throw error if no targetChainName is provided", async () => { - const params: IBCTransferActionParams = { - chainName: "cosmos", - toAddress: "cosmosReceiverAddress", - targetChainName: "", - symbol: "atom", - amount: "100", - }; - - const mockBridgeDataProvider = vi.fn().mockResolvedValue({ - ibcDenom: "uatom", - channelId: "channel-1", - portId: "transfer", - }); - - mockCosmosWalletChains.getWalletAddress.mockResolvedValue( - "cosmos1address" - ); - const cosmosIBCTransferAction = new IBCTransferAction( - mockCosmosWalletChains + it("throws an error if asset cannot be found", async () => { + mockWalletChains.getWalletAddress.mockResolvedValue( + "cosmos1senderaddress" ); - await expect( - cosmosIBCTransferAction.execute(params, mockBridgeDataProvider) - ).rejects.toThrow("No target chain name"); - }); - it("should throw error if no base denom in assets list", async () => { - const params: IBCTransferActionParams = { - chainName: "cosmos", - toAddress: "cosmosReceiverAddress", - targetChainName: "cosmosTarget", - symbol: "atom", - amount: "100", - }; - - // @ts-expect-error --- - getAssetBySymbol.mockReturnValue({}); - - const mockBridgeDataProvider = vi.fn().mockResolvedValue({ - ibcDenom: "uatom", - channelId: "channel-1", - portId: "transfer", + vi.spyOn(CosmosAssetsHelpers, "getAvailableAssets").mockReturnValue([]); + // @ts-expect-error --- ... + getAssetBySymbol.mockReturnValue({ + base: null, }); - mockCosmosWalletChains.getWalletAddress.mockResolvedValue( - "cosmos1address" - ); - - const cosmosIBCTransferAction = new IBCTransferAction( - mockCosmosWalletChains - ); + // @ts-expect-error --- ... + const ibcTransferAction = new IBCTransferAction(mockWalletChains); await expect( - cosmosIBCTransferAction.execute(params, mockBridgeDataProvider) + ibcTransferAction.execute( + params, + mockBridgeDenomProvider, + customChainAssets + ) ).rejects.toThrow("Cannot find asset"); }); - it("should throw error if no chain in chain list", async () => { - const params: IBCTransferActionParams = { - chainName: "cosmos", - toAddress: "cosmosReceiverAddress", - targetChainName: "cosmosTarget", - symbol: "atom", - amount: "100", - }; - // @ts-expect-error --- ... - getAssetBySymbol.mockReturnValue({ base: "uatom" }); + it("executes the IBC transfer successfully", async () => { + const senderAddress = "cosmos1senderaddress"; + const targetChainId = "target-chain-id"; + const sourceChainId = "source-chain-id"; + + mockWalletChains.getWalletAddress.mockResolvedValue(senderAddress); // @ts-expect-error --- ... - getChainByChainName.mockReturnValue(undefined); + getAvailableAssets.mockReturnValue(assets); - const mockBridgeDataProvider = vi.fn().mockResolvedValue({ - ibcDenom: "uatom", - channelId: "channel-1", - portId: "transfer", + // @ts-expect-error --- ... + getAssetBySymbol.mockReturnValue({ + base: "uatom", }); + const params = { + chainName: "test-chain", + targetChainName: "target-chain", + symbol: "ATOM", + amount: "10", + toAddress: "cosmos1receiveraddress", + }; - mockCosmosWalletChains.getWalletAddress.mockResolvedValue( - "cosmos1address" - ); + mockBridgeDenomProvider.mockResolvedValue({ denom: "uatom" }); + mockSkipClient.route.mockResolvedValue({ + requiredChainAddresses: [sourceChainId, targetChainId], + }); + // @ts-expect-error --- ... + const ibcTransferAction = new IBCTransferAction(mockWalletChains); - const cosmosIBCTransferAction = new IBCTransferAction( - mockCosmosWalletChains + const result = await ibcTransferAction.execute( + params, + mockBridgeDenomProvider, + customChainAssets ); - await expect( - cosmosIBCTransferAction.execute(params, mockBridgeDataProvider) - ).rejects.toThrow("Cannot find chain"); + expect(result).toEqual({ + from: senderAddress, + to: params.toAddress, + txHash: undefined, + }); + expect(mockSkipClient.executeRoute).toHaveBeenCalled(); }); }); diff --git a/packages/plugin-cosmos/src/tests/cosmos-wallet-chains-data.test.ts b/packages/plugin-cosmos/src/tests/cosmos-wallet-chains-data.test.ts index 7fbcf9806b8..7563e3ff9b0 100644 --- a/packages/plugin-cosmos/src/tests/cosmos-wallet-chains-data.test.ts +++ b/packages/plugin-cosmos/src/tests/cosmos-wallet-chains-data.test.ts @@ -17,6 +17,10 @@ vi.mock("@cosmjs/cosmwasm-stargate", () => ({ }, })); +vi.mock("@skip-go/client", () => ({ + SkipClient: vi.fn(() => ({})), +})); + vi.mock("../shared/entities/cosmos-wallet.ts", () => ({ CosmosWallet: { create: vi.fn(), @@ -74,6 +78,7 @@ describe("CosmosWalletChains", () => { chain1: { wallet: mockCosmosWalletCreate, signingCosmWasmClient: {}, + skipClient: {}, }, }, }; diff --git a/packages/plugin-cosmos/tsup.config.ts b/packages/plugin-cosmos/tsup.config.ts index 90948913ae9..12d9ae64f96 100644 --- a/packages/plugin-cosmos/tsup.config.ts +++ b/packages/plugin-cosmos/tsup.config.ts @@ -21,6 +21,5 @@ export default defineConfig({ "@cosmjs/proto-signing", "@cosmjs/cosmwasm-stargate", "zod", - "@ai16z/eliza", ], }); From 8e467ff6bc1252518b3aaff99bf4f34c4ed17bc7 Mon Sep 17 00:00:00 2001 From: KacperKoza34 Date: Thu, 9 Jan 2025 16:50:10 +0100 Subject: [PATCH 5/8] update: add IBC transfer action to README --- packages/plugin-cosmos/README.md | 55 ++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/packages/plugin-cosmos/README.md b/packages/plugin-cosmos/README.md index f32f58a5224..18f26bc2c98 100644 --- a/packages/plugin-cosmos/README.md +++ b/packages/plugin-cosmos/README.md @@ -7,15 +7,17 @@ This plugin provides actions and utilities for interacting with Cosmos-compatibl ## Development Prepare Eliza according to [README](../../README.md) - Add variables required for `@ai16z/plugin-cosmos` : - ``` +Add variables required for `@ai16z/plugin-cosmos` : + +``` COSMOS_RECOVERY_PHRASE=your recovery phrase words COSMOS_AVAILABLE_CHAINS=chain1,chain2,chain3 - ``` +``` Ensure the appropriate environment variables are added for the plugin. If they are correctly configured, the project will run with `@ai16z/plugin-cosmos` -Run Eliza +Run Eliza + ``` pnpm run dev ``` @@ -26,13 +28,12 @@ pnpm run dev To start using the plugin, you need to provide your **Cosmos account recovery phrases** and the list of **available chains**. Add the following to your `.env` file: - ```env COSMOS_RECOVERY_PHRASE=your recovery phrase words COSMOS_AVAILABLE_CHAINS=chain1,chain2,chain3 ``` -Ensure that the chain names in `COSMOS_AVAILABLE_CHAINS` match the identifiers from the [chain-registry](https://github.com/cosmos/chain-registry) library for compatibility. +Ensure that the chain names in `COSMOS_AVAILABLE_CHAINS` match the identifiers from the [chain-registry](https://github.com/cosmos/chain-registry) library for compatibility. ### Using the Cosmos Helper Character @@ -51,9 +52,11 @@ To use the character, pass it with the `--characters` flag: --- ### Custom chain configuration + Plugin allows you to pass you custom chain config to `createCosmosPlugin` function invoked in `../agent/src/index`. Your custom configuration fulfills the interfaces from `chain-registry` + ``` import type { assets, chains } from "chain-registry"; @@ -99,6 +102,46 @@ Yes 4. Action executed. +### Token IBC Transfer + +This plugin supports a token transfer action, which allows users to transfer tokens between addresses on Cosmos-compatible blockchains between different chains. + +#### Requirements + +You need to set both chain that you want to transfer founds between in env file. For example: + +``` +COSMOS_AVAILABLE_CHAINS=osmosistestnet,neutrontestnet +``` + +If you want to transfer your tokens between Osmosis Testnet and Neutron Testnet + +#### Example Prompts + +Below are examples of how the ibc transfer action can be initiated and confirmed: + +**Example** + +1. User input: + +``` +Make an IBC transfer 0.0001 OSMO to neutron1nk3uuw6zt5t5aqw5fvujkd54sa4uws9xg2nk82 from osmosistestnet to neutrontestnet +``` + +2. Plugin response: + +``` +Before making the IBC transfer, I would like to confirm the details. You would like to transfer 0.0001 OSMO from osmosistestnet to neutrontestnet, specifically to the address neutron1nk3uuw6zt5t5aqw5fvujkd54sa4uws9xg2nk82, is that correct? +``` + +3. User confirmation: + +``` +Yes +``` + +4. Action executed. + --- ## Contribution From 63acdd4968e8e698e901d97ff5ba80e00fb05e9a Mon Sep 17 00:00:00 2001 From: KacperKoza34 Date: Fri, 10 Jan 2025 11:03:19 +0100 Subject: [PATCH 6/8] refactor: make bridge data fetcher reusable across the project --- packages/plugin-cosmos/README.md | 6 +-- .../src/actions/ibc-transfer/schema.ts | 28 -------------- .../services/bridge-denom-provider.ts | 7 ++-- .../src/actions/ibc-transfer/types.ts | 16 +------- .../assets-from-source-fetcher/interfaces.ts | 16 ++++++++ .../assets-from-source-fetcher/schema.ts | 29 +++++++++++++++ .../skip-api-assets-from-source-fetcher.ts} | 37 ++++++++++--------- .../src/shared/services/skip-api/config.ts | 1 + .../src/tests/bridge-denom-provider.test.ts | 7 ++-- ...ip-api-assets-from-source-fetcher.test.ts} | 22 +++++------ 10 files changed, 89 insertions(+), 80 deletions(-) create mode 100644 packages/plugin-cosmos/src/shared/services/skip-api/assets-from-source-fetcher/interfaces.ts create mode 100644 packages/plugin-cosmos/src/shared/services/skip-api/assets-from-source-fetcher/schema.ts rename packages/plugin-cosmos/src/shared/services/{bridge-data-fetcher.ts => skip-api/assets-from-source-fetcher/skip-api-assets-from-source-fetcher.ts} (56%) create mode 100644 packages/plugin-cosmos/src/shared/services/skip-api/config.ts rename packages/plugin-cosmos/src/tests/{bridge-data-fetcher.test.ts => skip-api-assets-from-source-fetcher.test.ts} (78%) diff --git a/packages/plugin-cosmos/README.md b/packages/plugin-cosmos/README.md index 18f26bc2c98..610489e8638 100644 --- a/packages/plugin-cosmos/README.md +++ b/packages/plugin-cosmos/README.md @@ -1,4 +1,4 @@ -# `@ai16z/plugin-cosmos` +# `@elizaos/plugin-cosmos` This plugin provides actions and utilities for interacting with Cosmos-compatible blockchains. @@ -7,14 +7,14 @@ This plugin provides actions and utilities for interacting with Cosmos-compatibl ## Development Prepare Eliza according to [README](../../README.md) -Add variables required for `@ai16z/plugin-cosmos` : +Add variables required for `@elizaos/plugin-cosmos` : ``` COSMOS_RECOVERY_PHRASE=your recovery phrase words COSMOS_AVAILABLE_CHAINS=chain1,chain2,chain3 ``` -Ensure the appropriate environment variables are added for the plugin. If they are correctly configured, the project will run with `@ai16z/plugin-cosmos` +Ensure the appropriate environment variables are added for the plugin. If they are correctly configured, the project will run with `@elizaos/plugin-cosmos` Run Eliza diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/schema.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/schema.ts index 018e892d242..62e30be681d 100644 --- a/packages/plugin-cosmos/src/actions/ibc-transfer/schema.ts +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/schema.ts @@ -7,31 +7,3 @@ export const IBCTransferParamsSchema = z.object({ toAddress: z.string(), targetChainName: z.string(), }); - -export const bridgeDataProviderParamsSchema = z.object({ - source_asset_denom: z.string(), - source_asset_chain_id: z.string(), - allow_multi_tx: z.boolean(), -}); - -export const bridgeDataProviderResponseAssetsSchema = z.object({ - denom: z.string(), - chain_id: z.string(), - origin_denom: z.string(), - origin_chain_id: z.string(), - trace: z.string(), - symbol: z.string().optional(), - name: z.string().optional(), - logo_uri: z.string().optional(), - decimals: z.number().optional(), - recommended_symbol: z.string().optional(), -}); - -export const bridgeDataProviderResponseSchema = z.object({ - dest_assets: z.record( - z.string(), - z.object({ - assets: z.array(bridgeDataProviderResponseAssetsSchema), - }) - ), -}); diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-denom-provider.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-denom-provider.ts index cab8e79e580..3fcfdab3705 100644 --- a/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-denom-provider.ts +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/services/bridge-denom-provider.ts @@ -1,13 +1,14 @@ import { IDenomProvider } from "../../../shared/interfaces"; -import { BridgeDataFetcher } from "../../../shared/services/bridge-data-fetcher"; +import { SkipApiAssetsFromSourceFetcher } from "../../../shared/services/skip-api/assets-from-source-fetcher/skip-api-assets-from-source-fetcher"; export const bridgeDenomProvider: IDenomProvider = async ( sourceAssetDenom: string, sourceAssetChainId: string, destChainId: string ) => { - const bridgeDataFetcher = BridgeDataFetcher.getInstance(); - const bridgeData = await bridgeDataFetcher.fetchBridgeData( + const skipApiAssetsFromSourceFetcher = + SkipApiAssetsFromSourceFetcher.getInstance(); + const bridgeData = await skipApiAssetsFromSourceFetcher.fetch( sourceAssetDenom, sourceAssetChainId ); diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/types.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/types.ts index ba62b9cd48d..349bfb2fb81 100644 --- a/packages/plugin-cosmos/src/actions/ibc-transfer/types.ts +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/types.ts @@ -1,18 +1,4 @@ import { z } from "zod"; -import { - bridgeDataProviderParamsSchema, - bridgeDataProviderResponseAssetsSchema, - bridgeDataProviderResponseSchema, - IBCTransferParamsSchema, -} from "./schema"; +import { IBCTransferParamsSchema } from "./schema"; export type IBCTransferActionParams = z.infer; -export type BridgeDataProviderParams = z.infer< - typeof bridgeDataProviderParamsSchema ->; -export type BridgeDataProviderResponseAsset = z.infer< - typeof bridgeDataProviderResponseAssetsSchema ->; -export type BridgeDataProviderResponse = z.infer< - typeof bridgeDataProviderResponseSchema ->; diff --git a/packages/plugin-cosmos/src/shared/services/skip-api/assets-from-source-fetcher/interfaces.ts b/packages/plugin-cosmos/src/shared/services/skip-api/assets-from-source-fetcher/interfaces.ts new file mode 100644 index 00000000000..06b1ba5aa7a --- /dev/null +++ b/packages/plugin-cosmos/src/shared/services/skip-api/assets-from-source-fetcher/interfaces.ts @@ -0,0 +1,16 @@ +import { z } from "zod"; +import { + skipApiAssetsFromSourceParamsSchema, + skipApiAssetsFromSourceResponseAssetSchema, + skipApiAssetsFromSourceResponseSchema, +} from "./schema"; + +export type SkipApiAssetsFromSourceParams = z.infer< + typeof skipApiAssetsFromSourceParamsSchema +>; +export type SkipApiAssetsFromSourceResponseAsset = z.infer< + typeof skipApiAssetsFromSourceResponseAssetSchema +>; +export type SkipApiAssetsFromSourceResponse = z.infer< + typeof skipApiAssetsFromSourceResponseSchema +>; diff --git a/packages/plugin-cosmos/src/shared/services/skip-api/assets-from-source-fetcher/schema.ts b/packages/plugin-cosmos/src/shared/services/skip-api/assets-from-source-fetcher/schema.ts new file mode 100644 index 00000000000..6272e8a1001 --- /dev/null +++ b/packages/plugin-cosmos/src/shared/services/skip-api/assets-from-source-fetcher/schema.ts @@ -0,0 +1,29 @@ +import { z } from "zod"; + +export const skipApiAssetsFromSourceParamsSchema = z.object({ + source_asset_denom: z.string(), + source_asset_chain_id: z.string(), + allow_multi_tx: z.boolean(), +}); + +export const skipApiAssetsFromSourceResponseAssetSchema = z.object({ + denom: z.string(), + chain_id: z.string(), + origin_denom: z.string(), + origin_chain_id: z.string(), + trace: z.string(), + symbol: z.string().optional(), + name: z.string().optional(), + logo_uri: z.string().optional(), + decimals: z.number().optional(), + recommended_symbol: z.string().optional(), +}); + +export const skipApiAssetsFromSourceResponseSchema = z.object({ + dest_assets: z.record( + z.string(), + z.object({ + assets: z.array(skipApiAssetsFromSourceResponseAssetSchema), + }) + ), +}); diff --git a/packages/plugin-cosmos/src/shared/services/bridge-data-fetcher.ts b/packages/plugin-cosmos/src/shared/services/skip-api/assets-from-source-fetcher/skip-api-assets-from-source-fetcher.ts similarity index 56% rename from packages/plugin-cosmos/src/shared/services/bridge-data-fetcher.ts rename to packages/plugin-cosmos/src/shared/services/skip-api/assets-from-source-fetcher/skip-api-assets-from-source-fetcher.ts index 84c44277c6f..caad69d4b3b 100644 --- a/packages/plugin-cosmos/src/shared/services/bridge-data-fetcher.ts +++ b/packages/plugin-cosmos/src/shared/services/skip-api/assets-from-source-fetcher/skip-api-assets-from-source-fetcher.ts @@ -1,27 +1,30 @@ -import { bridgeDataProviderResponseSchema } from "../../actions/ibc-transfer/schema"; -import { - BridgeDataProviderParams, - BridgeDataProviderResponse, -} from "../../actions/ibc-transfer/types"; import axios from "axios"; +import { skipApiAssetsFromSourceResponseSchema } from "./schema"; +import { + SkipApiAssetsFromSourceParams, + SkipApiAssetsFromSourceResponse, +} from "./interfaces"; +import { skipApiBaseUrl } from "../config"; type CacheKey = `${string}_${string}`; +const endpointPath = "fungible/assets_from_source"; -export class BridgeDataFetcher { - private static instance: BridgeDataFetcher; - private cache: Map; +export class SkipApiAssetsFromSourceFetcher { + private static instance: SkipApiAssetsFromSourceFetcher; + private cache: Map; private readonly apiUrl: string; private constructor() { this.cache = new Map(); - this.apiUrl = "https://api.skip.build/v2/fungible/assets_from_source"; + this.apiUrl = `${skipApiBaseUrl}${endpointPath}`; } - public static getInstance(): BridgeDataFetcher { - if (!BridgeDataFetcher.instance) { - BridgeDataFetcher.instance = new BridgeDataFetcher(); + public static getInstance(): SkipApiAssetsFromSourceFetcher { + if (!SkipApiAssetsFromSourceFetcher.instance) { + SkipApiAssetsFromSourceFetcher.instance = + new SkipApiAssetsFromSourceFetcher(); } - return BridgeDataFetcher.instance; + return SkipApiAssetsFromSourceFetcher.instance; } private generateCacheKey( @@ -31,10 +34,10 @@ export class BridgeDataFetcher { return `${sourceAssetDenom}_${sourceAssetChainId}`; } - public async fetchBridgeData( + public async fetch( sourceAssetDenom: string, sourceAssetChainId: string - ): Promise { + ): Promise { const cacheKey = this.generateCacheKey( sourceAssetDenom, sourceAssetChainId @@ -44,7 +47,7 @@ export class BridgeDataFetcher { return this.cache.get(cacheKey)!; } - const requestData: BridgeDataProviderParams = { + const requestData: SkipApiAssetsFromSourceParams = { source_asset_denom: sourceAssetDenom, source_asset_chain_id: sourceAssetChainId, allow_multi_tx: false, @@ -57,7 +60,7 @@ export class BridgeDataFetcher { }, }); - const validResponse = bridgeDataProviderResponseSchema.parse( + const validResponse = skipApiAssetsFromSourceResponseSchema.parse( response.data ); diff --git a/packages/plugin-cosmos/src/shared/services/skip-api/config.ts b/packages/plugin-cosmos/src/shared/services/skip-api/config.ts new file mode 100644 index 00000000000..d3d4d5a16e7 --- /dev/null +++ b/packages/plugin-cosmos/src/shared/services/skip-api/config.ts @@ -0,0 +1 @@ +export const skipApiBaseUrl = "https://api.skip.build/v2/"; diff --git a/packages/plugin-cosmos/src/tests/bridge-denom-provider.test.ts b/packages/plugin-cosmos/src/tests/bridge-denom-provider.test.ts index 2363a0e99ae..622c1dde262 100644 --- a/packages/plugin-cosmos/src/tests/bridge-denom-provider.test.ts +++ b/packages/plugin-cosmos/src/tests/bridge-denom-provider.test.ts @@ -1,11 +1,11 @@ import { vi, expect, it, beforeEach, describe } from "vitest"; -import { BridgeDataFetcher } from "../shared/services/bridge-data-fetcher"; import { bridgeDenomProvider } from "../actions/ibc-transfer/services/bridge-denom-provider"; +import { SkipApiAssetsFromSourceFetcher } from "../shared/services/skip-api/assets-from-source-fetcher/skip-api-assets-from-source-fetcher"; vi.mock("./bridge-data-fetcher", () => ({ BridgeDataFetcher: { getInstance: vi.fn().mockReturnValue({ - fetchBridgeData: vi.fn(), + fetch: vi.fn(), }), }, })); @@ -16,7 +16,8 @@ describe("bridgeDataProvider", () => { beforeEach(() => { mockFetchBridgeData = vi.fn(); - BridgeDataFetcher.getInstance().fetchBridgeData = mockFetchBridgeData; + SkipApiAssetsFromSourceFetcher.getInstance().fetch = + mockFetchBridgeData; }); it("should return correct channelId and ibcDenom when valid data is returned", async () => { diff --git a/packages/plugin-cosmos/src/tests/bridge-data-fetcher.test.ts b/packages/plugin-cosmos/src/tests/skip-api-assets-from-source-fetcher.test.ts similarity index 78% rename from packages/plugin-cosmos/src/tests/bridge-data-fetcher.test.ts rename to packages/plugin-cosmos/src/tests/skip-api-assets-from-source-fetcher.test.ts index d7c7955a0b9..fe69a7ad63d 100644 --- a/packages/plugin-cosmos/src/tests/bridge-data-fetcher.test.ts +++ b/packages/plugin-cosmos/src/tests/skip-api-assets-from-source-fetcher.test.ts @@ -1,20 +1,20 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; -import { BridgeDataFetcher } from "../shared/services/bridge-data-fetcher"; import axios from "axios"; +import { SkipApiAssetsFromSourceFetcher } from "../shared/services/skip-api/assets-from-source-fetcher/skip-api-assets-from-source-fetcher"; vi.mock("axios"); -describe("BridgeDataFetcher", () => { - let fetcher: BridgeDataFetcher; +describe("SkipApiAssetsFromSourceFetcher", () => { + let fetcher: SkipApiAssetsFromSourceFetcher; beforeEach(() => { - fetcher = BridgeDataFetcher.getInstance(); + fetcher = SkipApiAssetsFromSourceFetcher.getInstance(); vi.clearAllMocks(); }); it("should return the same instance from getInstance", () => { - const fetcher1 = BridgeDataFetcher.getInstance(); - const fetcher2 = BridgeDataFetcher.getInstance(); + const fetcher1 = SkipApiAssetsFromSourceFetcher.getInstance(); + const fetcher2 = SkipApiAssetsFromSourceFetcher.getInstance(); expect(fetcher1).toBe(fetcher2); }); @@ -46,12 +46,12 @@ describe("BridgeDataFetcher", () => { const sourceAssetDenom = "atom"; const sourceAssetChainId = "cosmos"; - await fetcher.fetchBridgeData(sourceAssetDenom, sourceAssetChainId); + await fetcher.fetch(sourceAssetDenom, sourceAssetChainId); expect(axios.post).toHaveBeenCalledTimes(1); - await fetcher.fetchBridgeData(sourceAssetDenom, sourceAssetChainId); - expect(axios.post).toHaveBeenCalledTimes(1); // axios nie powinien być wywołany ponownie + await fetcher.fetch(sourceAssetDenom, sourceAssetChainId); + expect(axios.post).toHaveBeenCalledTimes(1); }); it("should fetch and cache data correctly", async () => { @@ -82,7 +82,7 @@ describe("BridgeDataFetcher", () => { const sourceAssetDenom = "atom"; const sourceAssetChainId = "cosmos"; - const result = await fetcher.fetchBridgeData( + const result = await fetcher.fetch( sourceAssetDenom, sourceAssetChainId ); @@ -92,7 +92,7 @@ describe("BridgeDataFetcher", () => { const cacheKey = `${sourceAssetDenom}_${sourceAssetChainId}`; expect(fetcher["cache"].has(cacheKey)).toBe(true); - const cachedResult = await fetcher.fetchBridgeData( + const cachedResult = await fetcher.fetch( sourceAssetDenom, sourceAssetChainId ); From 907ed038ab4dbca305166618f4d7d0ff71c3e2e4 Mon Sep 17 00:00:00 2001 From: KacperKoza34 Date: Fri, 10 Jan 2025 11:06:50 +0100 Subject: [PATCH 7/8] fix: update similes for ibc transfer action --- packages/plugin-cosmos/src/actions/ibc-transfer/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts index 217d4e1c21a..88e92015622 100644 --- a/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/index.ts @@ -218,9 +218,9 @@ export const createIBCTransferAction = ( ], ], similes: [ - "COSMOS_TRANSFER", - "COSMOS_SEND_TOKENS", - "COSMOS_TOKEN_TRANSFER", - "COSMOS_MOVE_TOKENS", + "COSMOS_BRIDGE_TOKEN", + "COSMOS_IBC_SEND_TOKEN", + "COSMOS_TOKEN_IBC_TRANSFER", + "COSMOS_MOVE_IBC_TOKENS", ], }); From 64e6cb2c597af0095e143e145ac53b6ec210fd14 Mon Sep 17 00:00:00 2001 From: KacperKoza343 Date: Mon, 13 Jan 2025 11:04:53 +0100 Subject: [PATCH 8/8] fix: update toAddress in ibc transfer --- packages/plugin-cosmos/README.md | 10 --------- .../services/ibc-transfer-action-service.ts | 22 +++++++++---------- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/packages/plugin-cosmos/README.md b/packages/plugin-cosmos/README.md index 610489e8638..e457b0b1dee 100644 --- a/packages/plugin-cosmos/README.md +++ b/packages/plugin-cosmos/README.md @@ -106,16 +106,6 @@ Yes This plugin supports a token transfer action, which allows users to transfer tokens between addresses on Cosmos-compatible blockchains between different chains. -#### Requirements - -You need to set both chain that you want to transfer founds between in env file. For example: - -``` -COSMOS_AVAILABLE_CHAINS=osmosistestnet,neutrontestnet -``` - -If you want to transfer your tokens between Osmosis Testnet and Neutron Testnet - #### Example Prompts Below are examples of how the ibc transfer action can be initiated and confirmed: diff --git a/packages/plugin-cosmos/src/actions/ibc-transfer/services/ibc-transfer-action-service.ts b/packages/plugin-cosmos/src/actions/ibc-transfer/services/ibc-transfer-action-service.ts index 65c0ab72570..508b1cc29a9 100644 --- a/packages/plugin-cosmos/src/actions/ibc-transfer/services/ibc-transfer-action-service.ts +++ b/packages/plugin-cosmos/src/actions/ibc-transfer/services/ibc-transfer-action-service.ts @@ -1,7 +1,6 @@ import { convertDisplayUnitToBaseUnit, getAssetBySymbol, - getChainByChainId, getChainByChainName, } from "@chain-registry/utils"; import { assets, chains } from "chain-registry"; @@ -97,18 +96,17 @@ export class IBCTransferAction implements ICosmosActionService { ), cumulativeAffiliateFeeBPS: "0", }); + const fromAddress = { + chainID: sourceChain.chain_id, + address: await this.cosmosWalletChains.getWalletAddress(params.chainName) + }; - const userAddresses = await Promise.all( - route.requiredChainAddresses.map(async (chainID) => { - const chain = getChainByChainId(chains, chainID); - return { - chainID, - address: await this.cosmosWalletChains.getWalletAddress( - chain.chain_name - ), - }; - }) - ); + const toAddress = { + chainID: destChain.chain_id, + address: params.toAddress + }; + + const userAddresses = [fromAddress, toAddress]; let txHash: string | undefined;