Skip to content

Commit

Permalink
Merge branch 'main' into remove-get-push-links-call
Browse files Browse the repository at this point in the history
  • Loading branch information
Prithpal-Sooriya authored Feb 18, 2025
2 parents 7c056db + 8e348d8 commit 1e570fd
Show file tree
Hide file tree
Showing 17 changed files with 302 additions and 70 deletions.
4 changes: 4 additions & 0 deletions packages/accounts-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- Bump `@metamask/keyring-internal-api` from `^4.0.1` to `^4.0.2` ([#5356](https://github.com/MetaMask/core/pull/5356))

## [24.0.0]

### Added
Expand Down
2 changes: 1 addition & 1 deletion packages/accounts-controller/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"@metamask/base-controller": "^8.0.0",
"@metamask/eth-snap-keyring": "^10.0.0",
"@metamask/keyring-api": "^17.0.0",
"@metamask/keyring-internal-api": "^4.0.1",
"@metamask/keyring-internal-api": "^4.0.2",
"@metamask/network-controller": "^22.2.1",
"@metamask/snaps-sdk": "^6.17.1",
"@metamask/snaps-utils": "^8.10.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/assets-controllers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@
"@metamask/auto-changelog": "^3.4.4",
"@metamask/ethjs-provider-http": "^0.3.0",
"@metamask/keyring-controller": "^19.2.0",
"@metamask/keyring-internal-api": "^4.0.1",
"@metamask/keyring-snap-client": "^3.0.3",
"@metamask/keyring-internal-api": "^4.0.2",
"@metamask/keyring-snap-client": "^4.0.0",
"@metamask/network-controller": "^22.2.1",
"@metamask/permission-controller": "^11.0.6",
"@metamask/preferences-controller": "^15.0.2",
Expand Down
4 changes: 4 additions & 0 deletions packages/keyring-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- Bump `@metamask/keyring-internal-api` from `^4.0.1` to `^4.0.2` ([#5356](https://github.com/MetaMask/core/pull/5356))

## [19.2.0]

### Added
Expand Down
2 changes: 1 addition & 1 deletion packages/keyring-controller/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
"@metamask/eth-sig-util": "^8.2.0",
"@metamask/eth-simple-keyring": "^8.1.0",
"@metamask/keyring-api": "^17.0.0",
"@metamask/keyring-internal-api": "^4.0.1",
"@metamask/keyring-internal-api": "^4.0.2",
"@metamask/utils": "^11.2.0",
"async-mutex": "^0.5.0",
"ethereumjs-wallet": "^1.0.1",
Expand Down
5 changes: 5 additions & 0 deletions packages/multichain-transactions-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- Bump `@metamask/keyring-internal-api` from `^4.0.1` to `^4.0.2` ([#5356](https://github.com/MetaMask/core/pull/5356))
- Bump `@metamask/keyring-snap-client` from `^3.0.3` to `^4.0.0` ([#5356](https://github.com/MetaMask/core/pull/5356))

## [0.4.0]

### Changed
Expand Down
4 changes: 2 additions & 2 deletions packages/multichain-transactions-controller/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@
"dependencies": {
"@metamask/base-controller": "^8.0.0",
"@metamask/keyring-api": "^17.0.0",
"@metamask/keyring-internal-api": "^4.0.1",
"@metamask/keyring-snap-client": "^3.0.3",
"@metamask/keyring-internal-api": "^4.0.2",
"@metamask/keyring-snap-client": "^4.0.0",
"@metamask/polling-controller": "^12.0.3",
"@metamask/snaps-controllers": "^9.19.0",
"@metamask/snaps-sdk": "^6.17.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/profile-sync-controller/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
"@lavamoat/preinstall-always-fail": "^2.1.0",
"@metamask/accounts-controller": "^24.0.0",
"@metamask/auto-changelog": "^3.4.4",
"@metamask/keyring-internal-api": "^4.0.1",
"@metamask/keyring-internal-api": "^4.0.2",
"@metamask/providers": "^18.1.1",
"@metamask/snaps-controllers": "^9.19.0",
"@types/jest": "^27.4.1",
Expand Down
11 changes: 11 additions & 0 deletions packages/token-search-discovery-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- All param types (e.g. `TokenSearchParams`, `TrendingTokensParams`, etc.) inherit from `ParamsBase`
- Add eponymous methods to the `TokenDiscoveryApiService`
- Add `getTopGainersByChains`
- Add `getTopLosersByChains`

### Changed

- **BREAKING:** Renamed `TokenTrendingResponseItem` name to `MoralisTokenResponseItem`

## [2.1.0]

### Added
Expand Down
4 changes: 3 additions & 1 deletion packages/token-search-discovery-controller/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ export type {
} from './token-search-discovery-controller';
export type {
TokenSearchResponseItem,
TokenTrendingResponseItem,
MoralisTokenResponseItem,
TokenSearchParams,
TrendingTokensParams,
TopGainersParams,
TopLosersParams,
} from './types';

export { AbstractTokenSearchApiService } from './token-search-api-service/abstract-token-search-api-service';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import type { TokenTrendingResponseItem } from '../types';
import type {
MoralisTokenResponseItem,
TrendingTokensParams,
TopLosersParams,
TopGainersParams,
} from '../types';

/**
* Abstract class for fetching token discovery results.
Expand All @@ -10,8 +15,15 @@ export abstract class AbstractTokenDiscoveryApiService {
* @param params - Optional parameters including chains and limit
* @returns A promise resolving to an array of {@link TokenTrendingResponseItem}
*/
abstract getTrendingTokensByChains(params: {
chains?: string[];
limit?: string;
}): Promise<TokenTrendingResponseItem[]>;
abstract getTrendingTokensByChains(
params?: TrendingTokensParams,
): Promise<MoralisTokenResponseItem[]>;

abstract getTopLosersByChains(
params?: TopLosersParams,
): Promise<MoralisTokenResponseItem[]>;

abstract getTopGainersByChains(
params?: TopGainersParams,
): Promise<MoralisTokenResponseItem[]>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import nock, { cleanAll } from 'nock';

import { TokenDiscoveryApiService } from './token-discovery-api-service';
import { TEST_API_URLS } from '../test/constants';
import type { TokenTrendingResponseItem } from '../types';
import type { MoralisTokenResponseItem } from '../types';

describe('TokenDiscoveryApiService', () => {
let service: TokenDiscoveryApiService;
const mockTrendingResponse: TokenTrendingResponseItem[] = [
const mockTrendingResponse: MoralisTokenResponseItem[] = [
{
chain_id: '1',
token_address: '0x123',
Expand Down Expand Up @@ -124,4 +124,110 @@ describe('TokenDiscoveryApiService', () => {
expect(results).toStrictEqual(mockTrendingResponse);
});
});

describe('getTopGainersByChains', () => {
it('should return top gainers results', async () => {
nock(TEST_API_URLS.PORTFOLIO_API)
.get('/tokens-search/top-gainers-by-chains')
.reply(200, mockTrendingResponse);

const results = await service.getTopGainersByChains({});
expect(results).toStrictEqual(mockTrendingResponse);
});

it('should handle API errors', async () => {
nock(TEST_API_URLS.PORTFOLIO_API)
.get('/tokens-search/top-gainers-by-chains')
.reply(500, 'Server Error');

await expect(service.getTopGainersByChains({})).rejects.toThrow(
'Portfolio API request failed with status: 500',
);
});

it.each([
{
params: { chains: ['1'], limit: '5' },
expectedPath: '/tokens-search/top-gainers-by-chains?chains=1&limit=5',
},
{
params: { chains: ['1', '137'] },
expectedPath: '/tokens-search/top-gainers-by-chains?chains=1,137',
},
])(
'should construct correct URL for params: $params',
async ({ params, expectedPath }) => {
nock(TEST_API_URLS.PORTFOLIO_API)
.get(expectedPath)
.reply(200, mockTrendingResponse);

const result = await service.getTopGainersByChains(params);
expect(result).toStrictEqual(mockTrendingResponse);
},
);
});

describe('getTopLosersByChains', () => {
it('should return top losers results', async () => {
nock(TEST_API_URLS.PORTFOLIO_API)
.get('/tokens-search/top-losers-by-chains')
.reply(200, mockTrendingResponse);

const results = await service.getTopLosersByChains({});
expect(results).toStrictEqual(mockTrendingResponse);
});

it('should handle API errors', async () => {
nock(TEST_API_URLS.PORTFOLIO_API)
.get('/tokens-search/top-losers-by-chains')
.reply(500, 'Server Error');

await expect(service.getTopLosersByChains({})).rejects.toThrow(
'Portfolio API request failed with status: 500',
);
});

it.each([
{
params: { chains: ['1'], limit: '5' },
expectedPath: '/tokens-search/top-losers-by-chains?chains=1&limit=5',
},
{
params: { chains: ['1', '137'] },
expectedPath: '/tokens-search/top-losers-by-chains?chains=1,137',
},
])(
'should construct correct URL for params: $params',
async ({ params, expectedPath }) => {
nock(TEST_API_URLS.PORTFOLIO_API)
.get(expectedPath)
.reply(200, mockTrendingResponse);

const result = await service.getTopLosersByChains(params);
expect(result).toStrictEqual(mockTrendingResponse);
},
);
});

describe('error handling', () => {
it('should handle network errors', async () => {
nock(TEST_API_URLS.PORTFOLIO_API)
.get('/tokens-search/trending-by-chains')
.reply(500, 'Server Error');

await expect(service.getTrendingTokensByChains({})).rejects.toThrow(
'Portfolio API request failed with status: 500',
);
});

it('should handle malformed JSON responses', async () => {
nock(TEST_API_URLS.PORTFOLIO_API)
.get('/tokens-search/trending-by-chains')
.reply(200, 'invalid json');

await expect(service.getTrendingTokensByChains({})).rejects.toThrow(
'invalid json response body at',
);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { AbstractTokenDiscoveryApiService } from './abstract-token-discovery-api-service';
import type { TokenTrendingResponseItem, TrendingTokensParams } from '../types';
import type {
MoralisTokenResponseItem,
TopGainersParams,
TopLosersParams,
TrendingTokensParams,
} from '../types';

export class TokenDiscoveryApiService extends AbstractTokenDiscoveryApiService {
readonly #baseUrl: string;
Expand All @@ -13,14 +18,17 @@ export class TokenDiscoveryApiService extends AbstractTokenDiscoveryApiService {
}

async getTrendingTokensByChains(
trendingTokensParams: TrendingTokensParams,
): Promise<TokenTrendingResponseItem[]> {
trendingTokensParams?: TrendingTokensParams,
): Promise<MoralisTokenResponseItem[]> {
const url = new URL('/tokens-search/trending-by-chains', this.#baseUrl);

if (trendingTokensParams.chains && trendingTokensParams.chains.length > 0) {
if (
trendingTokensParams?.chains &&
trendingTokensParams.chains.length > 0
) {
url.searchParams.append('chains', trendingTokensParams.chains.join());
}
if (trendingTokensParams.limit) {
if (trendingTokensParams?.limit) {
url.searchParams.append('limit', trendingTokensParams.limit);
}

Expand All @@ -39,4 +47,60 @@ export class TokenDiscoveryApiService extends AbstractTokenDiscoveryApiService {

return response.json();
}

async getTopLosersByChains(
topLosersParams?: TopLosersParams,
): Promise<MoralisTokenResponseItem[]> {
const url = new URL('/tokens-search/top-losers-by-chains', this.#baseUrl);

if (topLosersParams?.chains && topLosersParams.chains.length > 0) {
url.searchParams.append('chains', topLosersParams.chains.join());
}
if (topLosersParams?.limit) {
url.searchParams.append('limit', topLosersParams.limit);
}

const response = await fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});

if (!response.ok) {
throw new Error(
`Portfolio API request failed with status: ${response.status}`,
);
}

return response.json();
}

async getTopGainersByChains(
topGainersParams?: TopGainersParams,
): Promise<MoralisTokenResponseItem[]> {
const url = new URL('/tokens-search/top-gainers-by-chains', this.#baseUrl);

if (topGainersParams?.chains && topGainersParams.chains.length > 0) {
url.searchParams.append('chains', topGainersParams.chains.join());
}
if (topGainersParams?.limit) {
url.searchParams.append('limit', topGainersParams.limit);
}

const response = await fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});

if (!response.ok) {
throw new Error(
`Portfolio API request failed with status: ${response.status}`,
);
}

return response.json();
}
}
Loading

0 comments on commit 1e570fd

Please sign in to comment.