From 328a6feef425d23a0b27f7db5c2f3d36b7e927b0 Mon Sep 17 00:00:00 2001 From: Baurain Olivier <11538800+olivbau@users.noreply.github.com> Date: Wed, 30 Oct 2024 10:14:51 +0800 Subject: [PATCH] ahead src --- src/Fetcher.ts | 5 ++++ src/TokenRegistry.ts | 5 ++++ src/fetchers/evm.ts | 22 ++++++++++++++ src/fetchers/index.ts | 4 +++ src/fetchers/solana.ts | 22 ++++++++++++++ src/helpers.ts | 25 ++++++++++++++++ src/index.ts | 13 +++----- tests/TokenRegistry.test.local.ts | 37 +++++++++++++++++++++++ tests/fetchers/solana.test.ts | 50 +++++++++++++++++++++++++++++++ tests/index.test.ts | 7 ----- 10 files changed, 174 insertions(+), 16 deletions(-) create mode 100644 src/Fetcher.ts create mode 100644 src/fetchers/evm.ts create mode 100644 src/fetchers/index.ts create mode 100644 src/fetchers/solana.ts create mode 100644 src/helpers.ts create mode 100644 tests/TokenRegistry.test.local.ts create mode 100644 tests/fetchers/solana.test.ts delete mode 100644 tests/index.test.ts diff --git a/src/Fetcher.ts b/src/Fetcher.ts new file mode 100644 index 0000000..936504d --- /dev/null +++ b/src/Fetcher.ts @@ -0,0 +1,5 @@ +import { UniTokenInfo } from '@sonarwatch/portfolio-core'; + +export default abstract class Fetcher { + abstract fetch(address: string): Promise; +} diff --git a/src/TokenRegistry.ts b/src/TokenRegistry.ts index c246124..5df0468 100644 --- a/src/TokenRegistry.ts +++ b/src/TokenRegistry.ts @@ -4,12 +4,15 @@ import { S3Client, S3ClientConfig, } from '@aws-sdk/client-s3'; +import { NetworkIdType } from '@sonarwatch/portfolio-core'; import { Logger } from './Logger'; +import Fetcher from './Fetcher'; export type TokenRegistryConfig = { logger?: Logger; redisOptions: RedisOptions; s3Config: S3ClientConfig & { bucket: string }; + fetchers: Partial>; }; export class TokenRegistry { @@ -17,9 +20,11 @@ export class TokenRegistry { private redisClient: Redis; private s3Client: S3Client; private s3Bucket: string; + private fetchers: Partial>; constructor(config: TokenRegistryConfig) { this.logger = config.logger; + this.fetchers = config.fetchers; // Redis this.redisClient = new Redis(config.redisOptions); diff --git a/src/fetchers/evm.ts b/src/fetchers/evm.ts new file mode 100644 index 0000000..70b473a --- /dev/null +++ b/src/fetchers/evm.ts @@ -0,0 +1,22 @@ +import { UniTokenInfo } from '@sonarwatch/portfolio-core'; +import axios from 'axios'; +import Fetcher from '../Fetcher'; + +export default class EvmFetcher extends Fetcher { + private rpc: string; + + constructor(rpc: string) { + super(); + this.rpc = rpc; + } + + async fetch(address: string): Promise { + const res = await axios.post(this.rpc, { + jsonrpc: '2.0', + id: 'text', + method: 'getAsset', + params: { id: address }, + }); + return res.data; + } +} diff --git a/src/fetchers/index.ts b/src/fetchers/index.ts new file mode 100644 index 0000000..fa066f5 --- /dev/null +++ b/src/fetchers/index.ts @@ -0,0 +1,4 @@ +import SolanaFetcher from './solana'; +import EvmFetcher from './evm'; + +export { SolanaFetcher, EvmFetcher }; diff --git a/src/fetchers/solana.ts b/src/fetchers/solana.ts new file mode 100644 index 0000000..28328f1 --- /dev/null +++ b/src/fetchers/solana.ts @@ -0,0 +1,22 @@ +import { UniTokenInfo } from '@sonarwatch/portfolio-core'; +import axios from 'axios'; +import Fetcher from '../Fetcher'; + +export default class SolanaFetcher extends Fetcher { + private dasUrl: string; + + constructor(dasUrl: string) { + super(); + this.dasUrl = dasUrl; + } + + async fetch(address: string): Promise { + const res = await axios.post(this.dasUrl, { + jsonrpc: '2.0', + id: 'text', + method: 'getAsset', + params: { id: address }, + }); + return res.data; + } +} diff --git a/src/helpers.ts b/src/helpers.ts new file mode 100644 index 0000000..1bcdc7d --- /dev/null +++ b/src/helpers.ts @@ -0,0 +1,25 @@ +import { NetworkIdType } from '@sonarwatch/portfolio-core'; +import Fetcher from './Fetcher'; +import { EvmFetcher, SolanaFetcher } from './fetchers'; + +export type GetDefaultFetchersConfig = { + solana: { + dasUrl: string; + }; + ethereum: { + rpc: string; + }; +}; + +export function getDefaultFetchers( + config: GetDefaultFetchersConfig +): Partial> { + return { + solana: new SolanaFetcher(config.solana.dasUrl), + ethereum: new EvmFetcher(config.ethereum.rpc), + }; +} + +export function stringToBoolean(str: string): boolean { + return str === 'true'; +} diff --git a/src/index.ts b/src/index.ts index 9d122f6..240a4b5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,4 @@ -import axios from 'axios'; - -const foo = 'bar'; -function baz() { - return axios.get(''); -} - -export { foo, baz }; -export { TokenRegistry } from './TokenRegistry'; +export * from './Logger'; +export * from './Fetcher'; +export * from './TokenRegistry'; +export * from './fetchers'; diff --git a/tests/TokenRegistry.test.local.ts b/tests/TokenRegistry.test.local.ts new file mode 100644 index 0000000..74bb57f --- /dev/null +++ b/tests/TokenRegistry.test.local.ts @@ -0,0 +1,37 @@ +import { TokenRegistry } from '../src/TokenRegistry'; +import { getDefaultFetchers } from '../src/helpers'; + +describe('TokenRegistry', () => { + it('sould be instantiable', async () => { + const s3Endpoint = process.env.S3_ENDPOINT; + const s3AccessKeyId = process.env.S3_ACCESS_KEY_ID; + const s3SecretAccessKey = process.env.S3_SECRET_ACCESS_KEY; + const s3Bucket = process.env.S3_BUCKET; + const s3Region = process.env.S3_REGION; + if (!s3Endpoint) return; + if (!s3AccessKeyId) return; + if (!s3SecretAccessKey) return; + if (!s3Bucket) return; + + const fetchers = getDefaultFetchers({ + solana: { dasUrl: '' }, + ethereum: { rpc: '' }, + }); + const tokenRegistry = new TokenRegistry({ + fetchers, + redisOptions: {}, + s3Config: { + bucket: s3Bucket || '', + endpoint: s3Endpoint, + credentials: { + accessKeyId: s3AccessKeyId || '', + secretAccessKey: s3SecretAccessKey || '', + }, + forcePathStyle: true, + region: s3Region, + }, + }); + await tokenRegistry.checkS3Client(); + expect(tokenRegistry).toBeDefined(); + }); +}); diff --git a/tests/fetchers/solana.test.ts b/tests/fetchers/solana.test.ts new file mode 100644 index 0000000..2a06150 --- /dev/null +++ b/tests/fetchers/solana.test.ts @@ -0,0 +1,50 @@ +import axios from 'axios'; +import { UniTokenInfo } from '@sonarwatch/portfolio-core'; +import SolanaFetcher from '../../src/fetchers/solana'; + +// Mock the axios module +jest.mock('axios'); +const mockedAxios = axios as jest.Mocked; + +describe('SolanaFetcher', () => { + const dasUrl = 'https://example.com'; + let fetcher: SolanaFetcher; + + beforeEach(() => { + fetcher = new SolanaFetcher(dasUrl); + }); + + it('should call the correct URL and return data when fetch is called', async () => { + const address = 'sample-address'; + const mockResponse: UniTokenInfo = { + name: 'Sample Token', + symbol: 'STK', + decimals: 6, + address, + chainId: 101, + }; + + // Mocking axios.post to return a resolved promise with mock data + mockedAxios.post.mockResolvedValueOnce({ data: mockResponse }); + + // Call the fetch method + const result = await fetcher.fetch(address); + + // Check if axios.post was called with correct parameters + expect(mockedAxios.post).toHaveBeenCalledWith(dasUrl, { + jsonrpc: '2.0', + id: 'text', + method: 'getAsset', + params: { id: address }, + }); + + // Check if the fetch method returned the expected data + expect(result).toEqual(mockResponse); + }); + + it('should throw an error if axios.post fails', async () => { + const address = 'sample-address'; + mockedAxios.post.mockRejectedValueOnce(new Error('Network error')); + await expect(fetcher.fetch(address)).rejects.toThrow('Network error'); + }); +}); diff --git a/tests/index.test.ts b/tests/index.test.ts deleted file mode 100644 index 81ddd03..0000000 --- a/tests/index.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { foo } from '../src/index'; - -describe('Constants', () => { - test('foo sould be bar', () => { - expect(foo).toBe('bar'); - }); -});