Skip to content

Commit

Permalink
refactor: make bridge data fetcher reusable across the project
Browse files Browse the repository at this point in the history
  • Loading branch information
KacperKoza343 committed Jan 10, 2025
1 parent 8e467ff commit 63acdd4
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 80 deletions.
6 changes: 3 additions & 3 deletions packages/plugin-cosmos/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# `@ai16z/plugin-cosmos`
# `@elizaos/plugin-cosmos`

This plugin provides actions and utilities for interacting with Cosmos-compatible blockchains.

Expand All @@ -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

Expand Down
28 changes: 0 additions & 28 deletions packages/plugin-cosmos/src/actions/ibc-transfer/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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),
})
),
});
Original file line number Diff line number Diff line change
@@ -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
);
Expand Down
16 changes: 1 addition & 15 deletions packages/plugin-cosmos/src/actions/ibc-transfer/types.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,4 @@
import { z } from "zod";
import {
bridgeDataProviderParamsSchema,
bridgeDataProviderResponseAssetsSchema,
bridgeDataProviderResponseSchema,
IBCTransferParamsSchema,
} from "./schema";
import { IBCTransferParamsSchema } from "./schema";

export type IBCTransferActionParams = z.infer<typeof IBCTransferParamsSchema>;
export type BridgeDataProviderParams = z.infer<
typeof bridgeDataProviderParamsSchema
>;
export type BridgeDataProviderResponseAsset = z.infer<
typeof bridgeDataProviderResponseAssetsSchema
>;
export type BridgeDataProviderResponse = z.infer<
typeof bridgeDataProviderResponseSchema
>;
Original file line number Diff line number Diff line change
@@ -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
>;
Original file line number Diff line number Diff line change
@@ -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),
})
),
});
Original file line number Diff line number Diff line change
@@ -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<CacheKey, BridgeDataProviderResponse>;
export class SkipApiAssetsFromSourceFetcher {
private static instance: SkipApiAssetsFromSourceFetcher;
private cache: Map<CacheKey, SkipApiAssetsFromSourceResponse>;
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(
Expand All @@ -31,10 +34,10 @@ export class BridgeDataFetcher {
return `${sourceAssetDenom}_${sourceAssetChainId}`;
}

public async fetchBridgeData(
public async fetch(
sourceAssetDenom: string,
sourceAssetChainId: string
): Promise<BridgeDataProviderResponse> {
): Promise<SkipApiAssetsFromSourceResponse> {
const cacheKey = this.generateCacheKey(
sourceAssetDenom,
sourceAssetChainId
Expand All @@ -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,
Expand All @@ -57,7 +60,7 @@ export class BridgeDataFetcher {
},
});

const validResponse = bridgeDataProviderResponseSchema.parse(
const validResponse = skipApiAssetsFromSourceResponseSchema.parse(
response.data
);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const skipApiBaseUrl = "https://api.skip.build/v2/";
Original file line number Diff line number Diff line change
@@ -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(),
}),
},
}));
Expand All @@ -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 () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
});

Expand Down Expand Up @@ -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 () => {
Expand Down Expand Up @@ -82,7 +82,7 @@ describe("BridgeDataFetcher", () => {
const sourceAssetDenom = "atom";
const sourceAssetChainId = "cosmos";

const result = await fetcher.fetchBridgeData(
const result = await fetcher.fetch(
sourceAssetDenom,
sourceAssetChainId
);
Expand All @@ -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
);
Expand Down

0 comments on commit 63acdd4

Please sign in to comment.