From a9fecd37e07a24fd1cf4dfed32943240864eb5cf Mon Sep 17 00:00:00 2001 From: KacperKoza34 Date: Wed, 8 Jan 2025 13:47:25 +0100 Subject: [PATCH 1/9] 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/9] 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/9] 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/9] 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/9] 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/9] 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/9] 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/9] 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; From 8d5b3a33761fb41ff3f900ddbbecd73abb01f883 Mon Sep 17 00:00:00 2001 From: Michal Rozek Date: Thu, 16 Jan 2025 11:11:32 +0100 Subject: [PATCH 9/9] feat: add readme for access token generating --- .../generating-access-token.md | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 docs/docs/Linkedin Client/generating-access-token.md diff --git a/docs/docs/Linkedin Client/generating-access-token.md b/docs/docs/Linkedin Client/generating-access-token.md new file mode 100644 index 00000000000..2d5b2a68d4b --- /dev/null +++ b/docs/docs/Linkedin Client/generating-access-token.md @@ -0,0 +1,62 @@ +# How to Generate an Access Token Manually Using the LinkedIn Developer Portal + +The LinkedIn access token is essential for enabling API calls on behalf of a user. It allows your application to interact with LinkedIn's API to perform actions such as posting updates, accessing user profiles, and managing LinkedIn pages. The following instructions will guide you through the process of generating this token. + +## Step 1: Create a New Application + +1. Navigate to the [LinkedIn Developer Portal](https://developer.linkedin.com/). +2. Click the **Create app** button. +3. Fill in the **App name** field. +4. Specify a **LinkedIn Page** (either select an existing page or create a new one). +5. Upload a **logo** from your local device. +6. Agree to the terms and conditions by selecting **I have read and agree to these terms**. +7. Complete the process by clicking the **Create app** button. + +## Step 2: Configure Your Linkedin Application + +1. Navigate to the **Products** tab in your application. +2. Under **OAuth Permissions**, select the following scopes: + - **Sign In with LinkedIn using OpenID Connect** + - **Share on LinkedIn** + +## Step 3: Generate an Access Token + +1. Open the **Auth** tab in your application. +2. Click on the **OAuth 2.0 tools** link (you can also navigate via **Docs and tools > OAuth Token Tools** in the navigation bar). +3. Press **Create token** to start the process. +4. Ensure the **OAuth flow** is set to **Member authorization code (3-legged)**. +5. Under **Select scopes**, check the boxes for: + - `openid` + - `profile` + - `w_member_social` +6. Click the **Request access token** button. +7. Log in using your LinkedIn credentials and click **Sign In**. +8. Grant your application the requested permissions by selecting **Allow**. +9. After successful authorization, your **access token** will be displayed and is ready for use. + +### Resolving Common Issues + +If you encounter the error: + +> "We can’t verify the authenticity of your request because the state parameter was modified." + +This may indicate that your browser is blocking the request. To resolve: + +- Disable all browser extensions temporarily. +- Try generating the token in another browser (e.g., Google Chrome). + +``` +Important! Be aware that some browsers, such as Brave, have built-in protections that might block token generation. +``` + +## Important Notes + +- The access token is valid for **2 months**. After expiration, you must repeat the steps above to generate a new token. +- If the token does not have all the required permissions, regenerate it and ensure the correct scopes are selected. +- Generating the access token automatically updates the **Authorized redirect URLs for your app** field in your application. + +### What Is a Redirect URL? + +A **redirect URL** is the URI where users are sent after authorization. It must match one of the redirect URLs defined in your application configuration. + +For more detailed information, visit Microsoft's official documentation on the [Authorization Code Flow (3-legged OAuth)](https://learn.microsoft.com/en-us/linkedin/shared/authentication/authorization-code-flow?tabs=HTTPS1).