Skip to content

Commit

Permalink
pools pages (#2468)
Browse files Browse the repository at this point in the history
* pools pages

* fixes and changes

* revert demo config
  • Loading branch information
isstuev authored Dec 16, 2024
1 parent 8538b69 commit df9e291
Show file tree
Hide file tree
Showing 63 changed files with 1,183 additions and 201 deletions.
1 change: 1 addition & 0 deletions configs/app/features/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export { default as mixpanel } from './mixpanel';
export { default as mudFramework } from './mudFramework';
export { default as multichainButton } from './multichainButton';
export { default as nameService } from './nameService';
export { default as pools } from './pools';
export { default as publicTagsSubmission } from './publicTagsSubmission';
export { default as restApiDocs } from './restApiDocs';
export { default as rewards } from './rewards';
Expand Down
28 changes: 28 additions & 0 deletions configs/app/features/pools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { Feature } from './types';

import { getEnvValue } from '../utils';

const contractInfoApiHost = getEnvValue('NEXT_PUBLIC_CONTRACT_INFO_API_HOST');
const dexPoolsEnabled = getEnvValue('NEXT_PUBLIC_DEX_POOLS_ENABLED') === 'true';

const title = 'DEX Pools';

const config: Feature<{ api: { endpoint: string; basePath: string } }> = (() => {
if (contractInfoApiHost && dexPoolsEnabled) {
return Object.freeze({
title,
isEnabled: true,
api: {
endpoint: contractInfoApiHost,
basePath: '',
},
});
}

return Object.freeze({
title,
isEnabled: false,
});
})();

export default config;
3 changes: 2 additions & 1 deletion configs/envs/.env.eth_sepolia
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ NEXT_PUBLIC_API_BASE_PATH=/
NEXT_PUBLIC_API_HOST=eth-sepolia.k8s-dev.blockscout.com
NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml
NEXT_PUBLIC_CONTRACT_CODE_IDES=[{'title':'Remix IDE','url':'https://remix.ethereum.org/?address={hash}&blockscout={domain}','icon_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/ide-icons/remix.png'}]
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info-test.k8s-dev.blockscout.com
NEXT_PUBLIC_DATA_AVAILABILITY_ENABLED=true
NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS=[{'text':'Swap','icon':'swap','dappId':'cow-swap'},{'text':'Payment link','icon':'payment_link','dappId':'peanut-protocol'}]
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/eth-sepolia.json
Expand Down Expand Up @@ -69,3 +69,4 @@ NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=noves
NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
NEXT_PUBLIC_XSTAR_SCORE_URL=https://docs.xname.app/the-solution-adaptive-proof-of-humanity-on-blockchain/xhs-scoring-algorithm?utm_source=blockscout&utm_medium=address
NEXT_PUBLIC_DEX_POOLS_ENABLED=true
10 changes: 10 additions & 0 deletions deploy/tools/envs-validator/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,16 @@ const schema = yup
value => value === undefined,
),
}),
NEXT_PUBLIC_DEX_POOLS_ENABLED: yup.boolean()
.when('NEXT_PUBLIC_CONTRACT_INFO_API_HOST', {
is: (value: string) => Boolean(value),
then: (schema) => schema,
otherwise: (schema) => schema.test(
'not-exist',
'NEXT_PUBLIC_DEX_POOLS_ENABLED can only be used with NEXT_PUBLIC_CONTRACT_INFO_API_HOST',
value => value === undefined,
),
}),
NEXT_PUBLIC_SAVE_ON_GAS_ENABLED: yup.boolean(),
NEXT_PUBLIC_ADDRESS_USERNAME_TAG: yup
.mixed()
Expand Down
10 changes: 10 additions & 0 deletions docs/ENVS.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ Please be aware that all environment variables prefixed with `NEXT_PUBLIC_` will
- [Get gas button](ENVS.md#get-gas-button)
- [Save on gas with GasHawk](ENVS.md#save-on-gas-with-gashawk)
- [Rewards service API](ENVS.md#rewards-service-api)
- [DEX pools](ENVS.md#dex-pools)
- [3rd party services configuration](ENVS.md#external-services-configuration)

&nbsp;
Expand Down Expand Up @@ -852,6 +853,15 @@ This feature enables Blockscout Merits program. It requires that the [My account
| --- | --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_REWARDS_SERVICE_API_HOST | `string` | API URL | - | - | `https://example.com` | v1.36.0+ |

&nbsp;

### DEX pools

| Variable | Type| Description | Compulsoriness | Default value | Example value | Version |
| --- | --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_DEX_POOLS_ENABLED | `boolean` | Set to true to enable the feature | Required | - | `true` | v1.37.0+ |
| NEXT_PUBLIC_CONTRACT_INFO_API_HOST | `string` | Contract Info API endpoint url | Required | - | `https://contracts-info.services.blockscout.com` | v1.0.x+ |

## External services configuration

### Google ReCaptcha
Expand Down
4 changes: 4 additions & 0 deletions icons/dex-tracker.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 21 additions & 1 deletion lib/api/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ import type {
OptimismL2BatchTxs,
OptimismL2BatchBlocks,
} from 'types/api/optimisticL2';
import type { Pool, PoolsResponse } from 'types/api/pools';
import type { RawTracesResponse } from 'types/api/rawTrace';
import type {
RewardsConfigResponse,
Expand Down Expand Up @@ -1128,6 +1129,22 @@ export const RESOURCES = {
path: '/api/v2/advanced-filters/csv',
},

// POOLS
pools: {
path: '/api/v1/chains/:chainId/pools',
pathParams: [ 'chainId' as const ],
filterFields: [ 'query' as const ],
endpoint: getFeaturePayload(config.features.pools)?.api.endpoint,
basePath: getFeaturePayload(config.features.pools)?.api.basePath,
},

pool: {
path: '/api/v1/chains/:chainId/pools/:hash',
pathParams: [ 'chainId' as const, 'hash' as const ],
endpoint: getFeaturePayload(config.features.pools)?.api.endpoint,
basePath: getFeaturePayload(config.features.pools)?.api.basePath,
},

// CONFIGS
config_backend_version: {
path: '/api/v2/config/backend-version',
Expand Down Expand Up @@ -1222,7 +1239,7 @@ export type PaginatedResources = 'blocks' | 'block_txs' | 'block_election_reward
'watchlist' | 'private_tags_address' | 'private_tags_tx' |
'domains_lookup' | 'addresses_lookup' | 'user_ops' | 'validators_stability' | 'validators_blackfort' | 'noves_address_history' |
'token_transfers_all' | 'scroll_l2_txn_batches' | 'scroll_l2_txn_batch_txs' | 'scroll_l2_txn_batch_blocks' |
'scroll_l2_deposits' | 'scroll_l2_withdrawals' | 'advanced_filter';
'scroll_l2_deposits' | 'scroll_l2_withdrawals' | 'advanced_filter' | 'pools';

export type PaginatedResponse<Q extends PaginatedResources> = ResourcePayload<Q>;

Expand Down Expand Up @@ -1416,6 +1433,8 @@ Q extends 'scroll_l2_withdrawals' ? ScrollL2MessagesResponse :
Q extends 'scroll_l2_withdrawals_count' ? number :
Q extends 'advanced_filter' ? AdvancedFilterResponse :
Q extends 'advanced_filter_methods' ? AdvancedFilterMethodsResponse :
Q extends 'pools' ? PoolsResponse :
Q extends 'pool' ? Pool :
never;
/* eslint-enable @stylistic/indent */

Expand Down Expand Up @@ -1452,6 +1471,7 @@ Q extends 'address_mud_tables' ? AddressMudTablesFilter :
Q extends 'address_mud_records' ? AddressMudRecordsFilter :
Q extends 'token_transfers_all' ? TokenTransferFilters :
Q extends 'advanced_filter' ? AdvancedFilterParams :
Q extends 'pools' ? { query: string } :
never;
/* eslint-enable @stylistic/indent */

Expand Down
5 changes: 5 additions & 0 deletions lib/getItemIndex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const DEFAULT_PAGE_SIZE = 50;

export default function getItemIndex(index: number, page: number, pageSize: number = DEFAULT_PAGE_SIZE) {
return (page - 1) * pageSize + index + 1;
};
8 changes: 7 additions & 1 deletion lib/hooks/useNavItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,13 @@ export default function useNavItems(): ReturnType {
icon: 'token-transfers',
isActive: pathname === '/token-transfers',
},
];
config.features.pools.isEnabled && {
text: 'DEX tracker',
nextRoute: { pathname: '/pools' as const },
icon: 'dex-tracker',
isActive: pathname === '/pools' || pathname.startsWith('/pool/'),
},
].filter(Boolean);

const apiNavItems: Array<NavItem> = [
config.features.restApiDocs.isEnabled ? {
Expand Down
2 changes: 2 additions & 0 deletions lib/metadata/getPageOgType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ const OG_TYPE_DICT: Record<Route['pathname'], OGPageType> = {
'/mud-worlds': 'Root page',
'/token-transfers': 'Root page',
'/advanced-filter': 'Root page',
'/pools': 'Root page',
'/pools/[hash]': 'Regular page',

// service routes, added only to make typescript happy
'/login': 'Regular page',
Expand Down
2 changes: 2 additions & 0 deletions lib/metadata/templates/description.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ const TEMPLATE_MAP: Record<Route['pathname'], string> = {
'/mud-worlds': DEFAULT_TEMPLATE,
'/token-transfers': DEFAULT_TEMPLATE,
'/advanced-filter': DEFAULT_TEMPLATE,
'/pools': DEFAULT_TEMPLATE,
'/pools/[hash]': DEFAULT_TEMPLATE,

// service routes, added only to make typescript happy
'/login': DEFAULT_TEMPLATE,
Expand Down
2 changes: 2 additions & 0 deletions lib/metadata/templates/title.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ const TEMPLATE_MAP: Record<Route['pathname'], string> = {
'/mud-worlds': '%network_name% MUD worlds list',
'/token-transfers': '%network_name% token transfers',
'/advanced-filter': '%network_name% advanced filter',
'/pools': '%network_name% DEX pools',
'/pools/[hash]': '%network_name% pool details',

// service routes, added only to make typescript happy
'/login': '%network_name% login',
Expand Down
2 changes: 2 additions & 0 deletions lib/mixpanel/getPageType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ export const PAGE_TYPE_DICT: Record<Route['pathname'], string> = {
'/mud-worlds': 'MUD worlds',
'/token-transfers': 'Token transfers',
'/advanced-filter': 'Advanced filter',
'/pools': 'DEX pools',
'/pools/[hash]': 'Pool details',

// service routes, added only to make typescript happy
'/login': 'Login',
Expand Down
21 changes: 21 additions & 0 deletions lib/pools/getPoolLinks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Pool } from 'types/api/pools';

type PoolLink = {
url: string;
image: string;
title: string;
};

export default function getPoolLinks(pool?: Pool): Array<PoolLink> {
if (!pool) {
return [];
}

return [
{
url: pool.coin_gecko_terminal_url,
image: '/static/gecko_terminal.png',
title: 'GeckoTerminal',
},
].filter(link => Boolean(link.url));
}
5 changes: 5 additions & 0 deletions lib/pools/getPoolTitle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type { Pool } from 'types/api/pools';

export const getPoolTitle = (pool: Pool) => {
return `${ pool.base_token_symbol } / ${ pool.quote_token_symbol } ${ pool.fee ? `(${ pool.fee }%)` : '' }`;
};
24 changes: 24 additions & 0 deletions mocks/pools/pool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { Pool } from 'types/api/pools';

export const base: Pool = {
contract_address: '0x06da0fd433c1a5d7a4faa01111c044910a184553',
chain_id: '1',
base_token_address: '0xdac17f958d2ee523a2206206994597c13d831ec7',
base_token_symbol: 'USDT',
base_token_icon_url: 'https://localhost:3000/utia.jpg',
quote_token_address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
quote_token_symbol: 'WETH',
quote_token_icon_url: 'https://localhost:3000/secondary_utia.jpg',
fully_diluted_valuation_usd: '75486579078',
market_cap_usd: '139312819076.195',
liquidity: '2099941.2238',
dex: { id: 'sushiswap', name: 'SushiSwap' },
fee: '0.03',
coin_gecko_terminal_url: 'https://www.geckoterminal.com/eth/pools/0x06da0fd433c1a5d7a4faa01111c044910a184553',
};

export const noIcons: Pool = {
...base,
base_token_icon_url: null,
quote_token_icon_url: null,
};
10 changes: 10 additions & 0 deletions nextjs/getServerSideProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,3 +315,13 @@ export const mud: GetServerSideProps<Props> = async(context) => {

return base(context);
};

export const pools: GetServerSideProps<Props> = async(context) => {
if (!config.features.pools.isEnabled) {
return {
notFound: true,
};
}

return base(context);
};
2 changes: 2 additions & 0 deletions nextjs/nextjs-routes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ declare module "nextjs-routes" {
| DynamicRoute<"/op/[hash]", { "hash": string }>
| StaticRoute<"/ops">
| StaticRoute<"/output-roots">
| DynamicRoute<"/pools/[hash]", { "hash": string }>
| StaticRoute<"/pools">
| StaticRoute<"/public-tags/submit">
| StaticRoute<"/search-results">
| StaticRoute<"/sprite">
Expand Down
20 changes: 20 additions & 0 deletions pages/pools/[hash].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { NextPage } from 'next';
import dynamic from 'next/dynamic';
import React from 'react';

import type { Props } from 'nextjs/getServerSideProps';
import PageNextJs from 'nextjs/PageNextJs';

const Pool = dynamic(() => import('ui/pages/Pool'), { ssr: false });

const Page: NextPage<Props> = (props: Props) => {
return (
<PageNextJs pathname="/pools/[hash]" query={ props.query }>
<Pool/>
</PageNextJs>
);
};

export default Page;

export { pools as getServerSideProps } from 'nextjs/getServerSideProps';
19 changes: 19 additions & 0 deletions pages/pools/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { NextPage } from 'next';
import dynamic from 'next/dynamic';
import React from 'react';

import PageNextJs from 'nextjs/PageNextJs';

const Pools = dynamic(() => import('ui/pages/Pools'), { ssr: false });

const Page: NextPage = () => {
return (
<PageNextJs pathname="/pools">
<Pools/>
</PageNextJs>
);
};

export default Page;

export { pools as getServerSideProps } from 'nextjs/getServerSideProps';
1 change: 1 addition & 0 deletions public/icons/name.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
| "copy"
| "cross"
| "delete"
| "dex-tracker"
| "docs"
| "donate"
| "dots"
Expand Down
Binary file added public/static/gecko_terminal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions stubs/pools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export const POOL = {
contract_address: '0x6a1041865b76d1dc33da0257582591227c57832c',
chain_id: '1',
base_token_address: '0xf63e309818e4ea13782678ce6c31c1234fa61809',
base_token_symbol: 'JANET',
base_token_icon_url: null,
quote_token_address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
quote_token_symbol: 'WETH',
quote_token_icon_url: 'https://coin-images.coingecko.com/coins/images/2518/small/weth.png?1696503332',
fully_diluted_valuation_usd: '15211385',
market_cap_usd: '15211385',
liquidity: '394101.2428',
dex: { id: 'uniswap_v2', name: 'Uniswap V2' },
coin_gecko_terminal_url: 'https://www.geckoterminal.com/eth/pools/0x6a1041865b76d1dc33da0257582591227c57832c',
};
27 changes: 27 additions & 0 deletions types/api/pools.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export type PoolsResponse = {
items: Array<Pool>;
next_page_params: {
page_token: string;
page_size: number;
} | null;
};

export type Pool = {
contract_address: string;
chain_id: string;
base_token_address: string;
base_token_symbol: string;
base_token_icon_url: string | null;
quote_token_address: string;
quote_token_symbol: string;
quote_token_icon_url: string | null;
fully_diluted_valuation_usd: string;
market_cap_usd: string;
liquidity: string;
dex: {
id: string;
name: string;
};
fee?: string;
coin_gecko_terminal_url: string;
};
2 changes: 1 addition & 1 deletion ui/marketplace/MarketplaceAppInfo.pw.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ test.describe('mobile', () => {

test('base view', async({ render, page }) => {
await render(<MarketplaceAppInfo data={ appsMock[0] }/>);
await page.getByLabel('Show project info').click();
await page.getByLabel('Show info').click();
await expect(page).toHaveScreenshot();
});
});
Loading

0 comments on commit df9e291

Please sign in to comment.