Commit f4f8925a authored by isstuev's avatar isstuev

Zapper integration

parent a904fe54
import type { Feature } from './types'; import type { Feature } from './types';
import type { MultichainProviderConfig } from 'types/client/multichainProviderConfig'; import type { MultichainProviderConfig, MultichainProviderConfigParsed } from 'types/client/multichainProviderConfig';
import { getEnvValue, parseEnvJson } from '../utils'; import { getEnvValue, parseEnvJson } from '../utils';
import marketplace from './marketplace'; import marketplace from './marketplace';
const value = parseEnvJson<MultichainProviderConfig>(getEnvValue('NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG')); const value = parseEnvJson<Array<MultichainProviderConfig>>(getEnvValue('NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG'));
const title = 'Multichain balance'; const title = 'Multichain balance';
const config: Feature<{name: string; logoUrl?: string; urlTemplate: string; dappId?: string }> = (() => { const config: Feature<{ providers: Array<MultichainProviderConfigParsed> }> = (() => {
if (value) { if (value) {
return Object.freeze({ return Object.freeze({
title, title,
isEnabled: true, isEnabled: true,
name: value.name, providers: value.map((provider) => ({
logoUrl: value.logo, name: provider.name,
urlTemplate: value.url_template, logoUrl: provider.logo,
dappId: marketplace.isEnabled ? value.dapp_id : undefined, urlTemplate: provider.url_template,
dappId: marketplace.isEnabled ? provider.dapp_id : undefined,
})),
}); });
} }
......
...@@ -38,7 +38,7 @@ NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6u ...@@ -38,7 +38,7 @@ NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6u
NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form
NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com
NEXT_PUBLIC_METASUITES_ENABLED=true NEXT_PUBLIC_METASUITES_ENABLED=true
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG={'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'} NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'}]
NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com
NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/apps'] NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/apps']
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
......
...@@ -39,7 +39,7 @@ NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKj ...@@ -39,7 +39,7 @@ NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKj
NEXT_PUBLIC_MARKETPLACE_RATING_AIRTABLE_BASE_ID=appGkvtmKI7fXE4Vs NEXT_PUBLIC_MARKETPLACE_RATING_AIRTABLE_BASE_ID=appGkvtmKI7fXE4Vs
NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com
NEXT_PUBLIC_METASUITES_ENABLED=true NEXT_PUBLIC_METASUITES_ENABLED=true
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG={'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'} NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'}, {'name': 'zerion2', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'}]
NEXT_PUBLIC_GAS_REFUEL_PROVIDER_CONFIG={'name': 'Need gas?', 'dapp_id': 'smol-refuel', 'url_template': 'https://smolrefuel.com/?outboundChain={chainId}&partner=blockscout&utm_source=blockscout&utm_medium=address&disableBridges=true', 'logo': 'https://blockscout-content.s3.amazonaws.com/smolrefuel-logo-action-button.png'} NEXT_PUBLIC_GAS_REFUEL_PROVIDER_CONFIG={'name': 'Need gas?', 'dapp_id': 'smol-refuel', 'url_template': 'https://smolrefuel.com/?outboundChain={chainId}&partner=blockscout&utm_source=blockscout&utm_medium=address&disableBridges=true', 'logo': 'https://blockscout-content.s3.amazonaws.com/smolrefuel-logo-action-button.png'}
NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com
NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/apps'] NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/apps']
......
...@@ -38,7 +38,7 @@ NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6u ...@@ -38,7 +38,7 @@ NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6u
NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form
NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com
NEXT_PUBLIC_METASUITES_ENABLED=true NEXT_PUBLIC_METASUITES_ENABLED=true
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG={'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'} NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'}]
NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com
NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/apps'] NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/apps']
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
......
...@@ -45,7 +45,7 @@ NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKj ...@@ -45,7 +45,7 @@ NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKj
NEXT_PUBLIC_MARKETPLACE_GRAPH_LINKS_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/refs/heads/marketplace-graph-test/test-configs/marketplace-graph-links.json NEXT_PUBLIC_MARKETPLACE_GRAPH_LINKS_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/refs/heads/marketplace-graph-test/test-configs/marketplace-graph-links.json
NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com
NEXT_PUBLIC_METASUITES_ENABLED=true NEXT_PUBLIC_METASUITES_ENABLED=true
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG={'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'} NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'}]
NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com
NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/apps'] NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/apps']
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
......
...@@ -39,7 +39,7 @@ NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6u ...@@ -39,7 +39,7 @@ NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6u
NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form
NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata-test.k8s-dev.blockscout.com NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata-test.k8s-dev.blockscout.com
NEXT_PUBLIC_METASUITES_ENABLED=true NEXT_PUBLIC_METASUITES_ENABLED=true
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG={'name': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'} NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'}]
NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens-rs-test.k8s-dev.blockscout.com NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens-rs-test.k8s-dev.blockscout.com
NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/blocks','/apps'] NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/blocks','/apps']
NEXT_PUBLIC_NAVIGATION_LAYOUT=horizontal NEXT_PUBLIC_NAVIGATION_LAYOUT=horizontal
......
...@@ -39,7 +39,7 @@ NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6u ...@@ -39,7 +39,7 @@ NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6u
NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form
NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com
NEXT_PUBLIC_METASUITES_ENABLED=true NEXT_PUBLIC_METASUITES_ENABLED=true
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG={'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'} NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'}]
NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com
NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/apps'] NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/apps']
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
......
...@@ -27,7 +27,7 @@ NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true ...@@ -27,7 +27,7 @@ NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_LOGOUT_URL=https://zksync.us.auth0.com/v2/logout NEXT_PUBLIC_LOGOUT_URL=https://zksync.us.auth0.com/v2/logout
NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com
NEXT_PUBLIC_METASUITES_ENABLED=true NEXT_PUBLIC_METASUITES_ENABLED=true
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG={'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'} NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'}]
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=ETH NEXT_PUBLIC_NETWORK_CURRENCY_NAME=ETH
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
......
...@@ -56,5 +56,5 @@ NEXT_PUBLIC_ROLLUP_TYPE=optimistic ...@@ -56,5 +56,5 @@ NEXT_PUBLIC_ROLLUP_TYPE=optimistic
NEXT_PUBLIC_STATS_API_HOST=https://stats-l2-zora-mainnet.k8s-prod-1.blockscout.com NEXT_PUBLIC_STATS_API_HOST=https://stats-l2-zora-mainnet.k8s-prod-1.blockscout.com
NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG={'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'} NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'}]
NEXT_PUBLIC_ADDRESS_USERNAME_TAG={'api_url_template': 'https://api.zora.co/discover/user/{address}', 'tag_link_template': 'httpszora.co/{username}', 'tag_icon': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/zora.svg', 'tag_bg_color': 'rgba(0,0,0)', 'tag_text_color': 'rgba(255,255,255)'} NEXT_PUBLIC_ADDRESS_USERNAME_TAG={'api_url_template': 'https://api.zora.co/discover/user/{address}', 'tag_link_template': 'httpszora.co/{username}', 'tag_icon': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/zora.svg', 'tag_bg_color': 'rgba(0,0,0)', 'tag_text_color': 'rgba(255,255,255)'}
\ No newline at end of file
...@@ -530,6 +530,13 @@ const deFiDropdownItemSchema: yup.ObjectSchema<DeFiDropdownItem> = yup ...@@ -530,6 +530,13 @@ const deFiDropdownItemSchema: yup.ObjectSchema<DeFiDropdownItem> = yup
return Boolean(value.dappId) || Boolean(value.url); return Boolean(value.dappId) || Boolean(value.url);
}) as yup.ObjectSchema<DeFiDropdownItem>; }) as yup.ObjectSchema<DeFiDropdownItem>;
const multichainProviderConfigSchema: yup.ObjectSchema<MultichainProviderConfig> = yup.object({
name: yup.string().required(),
url_template: yup.string().required(),
logo: yup.string().required(),
dapp_id: yup.string(),
});
const schema = yup const schema = yup
.object() .object()
.noUnknown(true, (params) => { .noUnknown(true, (params) => {
...@@ -768,18 +775,10 @@ const schema = yup ...@@ -768,18 +775,10 @@ const schema = yup
NEXT_PUBLIC_HAS_USER_OPS: yup.boolean(), NEXT_PUBLIC_HAS_USER_OPS: yup.boolean(),
NEXT_PUBLIC_METASUITES_ENABLED: yup.boolean(), NEXT_PUBLIC_METASUITES_ENABLED: yup.boolean(),
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG: yup NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG: yup
.mixed() .array()
.test('shape', 'Invalid schema were provided for NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG, it should have name and url template', (data) => { .transform(replaceQuotes)
const isUndefined = data === undefined; .json()
const valueSchema = yup.object<MultichainProviderConfig>().transform(replaceQuotes).json().shape({ .of(multichainProviderConfigSchema),
name: yup.string().required(),
url_template: yup.string().required(),
logo: yup.string(),
dapp_id: yup.string(),
});
return isUndefined || valueSchema.isValidSync(data);
}),
NEXT_PUBLIC_GAS_REFUEL_PROVIDER_CONFIG: yup NEXT_PUBLIC_GAS_REFUEL_PROVIDER_CONFIG: yup
.mixed() .mixed()
.test('shape', 'Invalid schema were provided for NEXT_PUBLIC_GAS_REFUEL_PROVIDER_CONFIG, it should have name and url template', (data) => { .test('shape', 'Invalid schema were provided for NEXT_PUBLIC_GAS_REFUEL_PROVIDER_CONFIG, it should have name and url template', (data) => {
......
...@@ -83,6 +83,6 @@ NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET=false ...@@ -83,6 +83,6 @@ NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET=false
NEXT_PUBLIC_WEB3_WALLETS=['coinbase','metamask','token_pocket'] NEXT_PUBLIC_WEB3_WALLETS=['coinbase','metamask','token_pocket']
NEXT_PUBLIC_VALIDATORS_CHAIN_TYPE=stability NEXT_PUBLIC_VALIDATORS_CHAIN_TYPE=stability
NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS=[{'text':'Swap','icon':'swap','dappId':'uniswap'},{'text':'Payment link','icon':'payment_link','url':'https://example.com'}] NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS=[{'text':'Swap','icon':'swap','dappId':'uniswap'},{'text':'Payment link','icon':'payment_link','url':'https://example.com'}]
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG={'name': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'} NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'}]
NEXT_PUBLIC_GAS_REFUEL_PROVIDER_CONFIG={'name': 'Need gas?', 'dapp_id': 'smol-refuel', 'url_template': 'https://smolrefuel.com/?outboundChain={chainId}&partner=blockscout&utm_source=blockscout&utm_medium=address&disableBridges=true', 'logo': 'https://blockscout-content.s3.amazonaws.com/smolrefuel-logo-action-button.png'} NEXT_PUBLIC_GAS_REFUEL_PROVIDER_CONFIG={'name': 'Need gas?', 'dapp_id': 'smol-refuel', 'url_template': 'https://smolrefuel.com/?outboundChain={chainId}&partner=blockscout&utm_source=blockscout&utm_medium=address&disableBridges=true', 'logo': 'https://blockscout-content.s3.amazonaws.com/smolrefuel-logo-action-button.png'}
NEXT_PUBLIC_SAVE_ON_GAS_ENABLED=true NEXT_PUBLIC_SAVE_ON_GAS_ENABLED=true
...@@ -746,7 +746,7 @@ If the feature is enabled, a Multichain balance button will be displayed on the ...@@ -746,7 +746,7 @@ If the feature is enabled, a Multichain balance button will be displayed on the
| Variable | Type| Description | Compulsoriness | Default value | Example value | Version | | Variable | Type| Description | Compulsoriness | Default value | Example value | Version |
| --- | --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG | `{ name: string; url_template: string; dapp_id?: string; logo?: string }` | Multichain portfolio application config See [below](#multichain-button-configuration-properties) | - | - | `{ name: 'zerion', url_template: 'https://app.zerion.io/{address}/overview', logo: 'https://example.com/icon.svg'` | v1.31.0+ | | NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG | `[{ name: string; url_template: string; dapp_id?: string; logo: string }]` | Multichain portfolio application config See [below](#multichain-button-configuration-properties) | - | - | `[{ name: 'zerion', url_template: 'https://app.zerion.io/{address}/overview', logo: 'https://example.com/icon.svg'}]` | v1.31.0+ |
&nbsp; &nbsp;
......
...@@ -2,5 +2,12 @@ export type MultichainProviderConfig = { ...@@ -2,5 +2,12 @@ export type MultichainProviderConfig = {
name: string; name: string;
dapp_id?: string; dapp_id?: string;
url_template: string; url_template: string;
logo?: string; logo: string;
};
export type MultichainProviderConfigParsed = {
name: string;
logoUrl: string;
urlTemplate: string;
dappId?: string;
}; };
import { Image, Tooltip } from '@chakra-ui/react';
import _capitalize from 'lodash/capitalize';
import React from 'react';
import type { MultichainProviderConfigParsed } from 'types/client/multichainProviderConfig';
import { route } from 'nextjs-routes';
import LinkExternal from 'ui/shared/links/LinkExternal';
import LinkInternal from 'ui/shared/links/LinkInternal';
const TEMPLATE_ADDRESS = '{address}';
type Props = {
hasSingleProvider: boolean;
item: MultichainProviderConfigParsed;
addressHash: string;
onClick?: () => void;
}
const AddressMultichainButton = ({ item, addressHash, onClick, hasSingleProvider }: Props) => {
const buttonIcon = <Image src={ item.logoUrl } alt={ item.name } boxSize={ 5 } mr={ hasSingleProvider ? 2 : 0 } borderRadius="4px" overflow="hidden"/>;
const buttonContent = hasSingleProvider ? (
<>
{ buttonIcon }
{ _capitalize(item.name) }
</>
) : (
<Tooltip label={ _capitalize(item.name) }>{ buttonIcon }</Tooltip>
);
const linkProps = {
variant: hasSingleProvider ? 'subtle' as const : undefined,
display: 'flex',
alignItems: 'center',
fontSize: 'sm',
lineHeight: 5,
fontWeight: 500,
onClick,
};
try {
const portfolioUrlString = item.urlTemplate.replace(TEMPLATE_ADDRESS, addressHash);
const portfolioUrl = new URL(portfolioUrlString);
portfolioUrl.searchParams.append('utm_source', 'blockscout');
portfolioUrl.searchParams.append('utm_medium', 'address');
const dappId = item.dappId;
return typeof dappId === 'string' ? (
<LinkInternal
href={ route({ pathname: '/apps/[id]', query: { id: dappId, url: portfolioUrl.toString() } }) }
{ ...linkProps }
>
{ buttonContent }
</LinkInternal>
) : (
<LinkExternal
href={ portfolioUrl.toString() }
{ ...linkProps }
>
{ buttonContent }
</LinkExternal>
);
} catch (error) {}
return null;
};
export default AddressMultichainButton;
...@@ -23,11 +23,11 @@ test('base view', async({ render }) => { ...@@ -23,11 +23,11 @@ test('base view', async({ render }) => {
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
test('with multichain button internal +@dark-mode', async({ render, mockEnvs, mockAssetResponse }) => { test('with single multichain button internal +@dark-mode', async({ render, mockEnvs, mockAssetResponse }) => {
await mockEnvs([ await mockEnvs([
[ [
'NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG', 'NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG',
`{"name": "duck", "dapp_id": "duck", "url_template": "https://duck.url/{address}", "logo": "${ ICON_URL }"}` ], `[{"name": "duck", "dapp_id": "duck", "url_template": "https://duck.url/{address}", "logo": "${ ICON_URL }"}]` ],
]); ]);
await mockAssetResponse(ICON_URL, './playwright/mocks/image_svg.svg'); await mockAssetResponse(ICON_URL, './playwright/mocks/image_svg.svg');
...@@ -36,9 +36,23 @@ test('with multichain button internal +@dark-mode', async({ render, mockEnvs, mo ...@@ -36,9 +36,23 @@ test('with multichain button internal +@dark-mode', async({ render, mockEnvs, mo
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
test('with multichain button external', async({ render, mockEnvs, mockAssetResponse }) => { test('with single multichain button external', async({ render, mockEnvs, mockAssetResponse }) => {
await mockEnvs([ await mockEnvs([
[ 'NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG', `{"name": "duck", "url_template": "https://duck.url/{address}", "logo": "${ ICON_URL }"}` ], [ 'NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG', `[{"name": "duck", "url_template": "https://duck.url/{address}", "logo": "${ ICON_URL }"}]` ],
]);
await mockAssetResponse(ICON_URL, './playwright/mocks/image_svg.svg');
const component = await render(<AddressNetWorth addressData={ addressMock.eoa } addressHash={ ADDRESS_HASH }/>);
await expect(component).toHaveScreenshot();
});
test('with two multichain button external', async({ render, mockEnvs, mockAssetResponse }) => {
await mockEnvs([
[ 'NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG', `[
{"name": "duck", "url_template": "https://duck.url/{address}", "logo": "${ ICON_URL }"},
{"name": "duck2", "url_template": "https://duck.url/{address}", "logo": "${ ICON_URL }"}
]` ],
]); ]);
await mockAssetResponse(ICON_URL, './playwright/mocks/image_svg.svg'); await mockAssetResponse(ICON_URL, './playwright/mocks/image_svg.svg');
...@@ -51,7 +65,7 @@ test('with multichain button internal small screen', async({ render, mockEnvs, m ...@@ -51,7 +65,7 @@ test('with multichain button internal small screen', async({ render, mockEnvs, m
await mockEnvs([ await mockEnvs([
[ [
'NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG', 'NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG',
`{"name": "duck", "dapp_id": "duck", "url_template": "https://duck.url/{address}", "logo": "${ ICON_URL }"}` ], `[{"name": "duck", "dapp_id": "duck", "url_template": "https://duck.url/{address}", "logo": "${ ICON_URL }"}]` ],
]); ]);
await mockAssetResponse(ICON_URL, './playwright/mocks/image_svg.svg'); await mockAssetResponse(ICON_URL, './playwright/mocks/image_svg.svg');
......
import { Image, Skeleton, Text, Flex } from '@chakra-ui/react'; import { Skeleton, Text, Flex } from '@chakra-ui/react';
import _capitalize from 'lodash/capitalize';
import React from 'react'; import React from 'react';
import type { Address } from 'types/api/address'; import type { Address } from 'types/api/address';
import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import getCurrencyValue from 'lib/getCurrencyValue'; import getCurrencyValue from 'lib/getCurrencyValue';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import LinkExternal from 'ui/shared/links/LinkExternal';
import LinkInternal from 'ui/shared/links/LinkInternal';
import TextSeparator from 'ui/shared/TextSeparator'; import TextSeparator from 'ui/shared/TextSeparator';
import { getTokensTotalInfo } from '../utils/tokenUtils'; import { getTokensTotalInfo } from '../utils/tokenUtils';
import useFetchTokens from '../utils/useFetchTokens'; import useFetchTokens from '../utils/useFetchTokens';
import AddressMultichainButton from './AddressMultichainButton';
const TEMPLATE_ADDRESS = '{address}';
const multichainFeature = config.features.multichainButton; const multichainFeature = config.features.multichainButton;
...@@ -46,58 +40,30 @@ const AddressNetWorth = ({ addressData, isLoading, addressHash }: Props) => { ...@@ -46,58 +40,30 @@ const AddressNetWorth = ({ addressData, isLoading, addressHash }: Props) => {
mixpanel.logEvent(mixpanel.EventTypes.BUTTON_CLICK, { Content: 'Multichain', Source: 'address' }); mixpanel.logEvent(mixpanel.EventTypes.BUTTON_CLICK, { Content: 'Multichain', Source: 'address' });
}, []); }, []);
let multichainItem = null; let multichainItems = null;
if (multichainFeature.isEnabled && !addressData?.is_contract) { if (multichainFeature.isEnabled && !addressData?.is_contract) {
const buttonContent = ( const { providers } = multichainFeature;
const hasSingleProvider = providers.length === 1;
multichainItems = (
<> <>
{ multichainFeature.logoUrl && <TextSeparator mx={ 0 } color="gray.500"/>
<Image src={ multichainFeature.logoUrl } alt={ multichainFeature.name } boxSize={ 5 } mr={ 2 } borderRadius="4px" overflow="hidden"/> <Flex alignItems="center" gap={ 2 }>
} <Text>Multichain</Text>
{ _capitalize(multichainFeature.name) }</> { providers.map((item) => (
<AddressMultichainButton
key={ item.name }
item={ item }
addressHash={ addressHash }
onClick={ onMultichainClick }
hasSingleProvider={ hasSingleProvider }
/>
))
}
</Flex>
</>
); );
const linkProps = {
variant: 'subtle' as const,
display: 'flex',
alignItems: 'center',
fontSize: 'sm',
lineHeight: 5,
fontWeight: 500,
onClick: onMultichainClick,
};
try {
const portfolioUrlString = multichainFeature.urlTemplate.replace(TEMPLATE_ADDRESS, addressHash);
const portfolioUrl = new URL(portfolioUrlString);
portfolioUrl.searchParams.append('utm_source', 'blockscout');
portfolioUrl.searchParams.append('utm_medium', 'address');
const dappId = multichainFeature.dappId;
multichainItem = (
<>
<TextSeparator mx={ 0 } color="gray.500"/>
<Flex alignItems="center" gap={ 2 }>
<Text>Multichain</Text>
{ typeof dappId === 'string' ? (
<LinkInternal
href={ route({ pathname: '/apps/[id]', query: { id: dappId, url: portfolioUrl.toString() } }) }
{ ...linkProps }
>
{ buttonContent }
</LinkInternal>
) : (
<LinkExternal
href={ portfolioUrl.toString() }
{ ...linkProps }
>
{ buttonContent }
</LinkExternal>
) }
</Flex>
</>
);
} catch (error) {}
} }
return ( return (
...@@ -105,7 +71,7 @@ const AddressNetWorth = ({ addressData, isLoading, addressHash }: Props) => { ...@@ -105,7 +71,7 @@ const AddressNetWorth = ({ addressData, isLoading, addressHash }: Props) => {
<Text> <Text>
{ (isError || !addressData?.exchange_rate) ? 'N/A' : `${ prefix }$${ totalUsd.toFormat(2) }` } { (isError || !addressData?.exchange_rate) ? 'N/A' : `${ prefix }$${ totalUsd.toFormat(2) }` }
</Text> </Text>
{ multichainItem } { multichainItems }
</Skeleton> </Skeleton>
); );
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment