Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/rich-moments-act.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@stakekit/widget": patch
---

feat: chain + token icon mapping
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { SupportedSKChains } from "@sk-widget/domain/types/chains";
import { type SettingsProps, useSettings } from "@sk-widget/providers/settings";
import { getNetworkLogo } from "@sk-widget/utils";
import type { Networks } from "@stakekit/common";
import { Maybe } from "purify-ts";
import { useMemo } from "react";

export const getVariantNetworkUrl = ({
chainIconMapping,
network,
}: {
network: Networks;
chainIconMapping: SettingsProps["chainIconMapping"];
}) => {
const chainMappingResult = Maybe.fromNullable(chainIconMapping)
.chainNullable((mapping) => {
if (typeof mapping === "function") {
return mapping(network as SupportedSKChains);
}

return mapping[network as SupportedSKChains];
})
.extractNullable();

if (chainMappingResult) {
return chainMappingResult;
}

return getNetworkLogo(network);
};

export const useVariantNetworkUrls = (network: Networks) => {
const { chainIconMapping } = useSettings();

return useMemo(
() => getVariantNetworkUrl({ chainIconMapping, network }),
[chainIconMapping, network]
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const useVariantTokenUrls = (
name: string;
providerIcon: string | undefined;
} => {
const { variant } = useSettings();
const { variant, tokenIconMapping } = useSettings();

return useMemo(() => {
if (metadata) {
Expand All @@ -32,6 +32,26 @@ export const useVariantTokenUrls = (
};
}

const tokenMappingResult = Maybe.fromNullable(tokenIconMapping)
.chainNullable((mapping) => {
if (typeof mapping === "function") {
return mapping(token);
}

return mapping[token.symbol];
})
.map((url) => ({
mainUrl: url,
fallbackUrl: url,
name: token.name,
providerIcon: undefined,
}))
.extractNullable();

if (tokenMappingResult) {
return tokenMappingResult;
}

const mainUrl = Maybe.fromFalsy(variant === "zerion")
.map(() => {
/**
Expand All @@ -54,7 +74,7 @@ export const useVariantTokenUrls = (
name: token.name,
providerIcon: undefined,
};
}, [token, metadata, variant]);
}, [token, metadata, variant, tokenIconMapping]);
};

const skETHIconUrlsSuffix = ["/tokens/eth.svg", "/tokens/steth2.svg"];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Box } from "@sk-widget/components";
import { useVariantTokenUrls } from "@sk-widget/hooks/use-variant-token-urls";
import { getNetworkLogo } from "@sk-widget/utils";
import { useVariantNetworkUrls } from "@sk-widget/components/atoms/token-icon/token-icon-container/hooks/use-variant-network-urls";
import { useVariantTokenUrls } from "@sk-widget/components/atoms/token-icon/token-icon-container/hooks/use-variant-token-urls";
import type { TokenDto, YieldMetadataDto } from "@stakekit/api-hooks";
import type { Networks } from "@stakekit/common";
import type { ReactElement } from "react";
Expand All @@ -26,7 +26,8 @@ export const TokenIconContainer = ({
token,
metadata
);
const networkLogoUri = getNetworkLogo(token.network as Networks);

const networkLogoUri = useVariantNetworkUrls(token.network as Networks);

return (
<Box
Expand Down
9 changes: 8 additions & 1 deletion packages/widget/src/providers/settings.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { SupportedSKChains } from "@sk-widget/domain/types/chains";
import type { Languages, localResources } from "@sk-widget/translation";
import utilaTranslations from "@sk-widget/translation/English/utila-variant.json";
import type { RecursivePartial } from "@sk-widget/types";
import type { TransactionFormat } from "@stakekit/api-hooks";
import type { TokenDto, TransactionFormat } from "@stakekit/api-hooks";
import type { PropsWithChildren, ReactNode } from "react";
import { createContext, useContext, useLayoutEffect } from "react";
import { useTranslation } from "react-i18next";
Expand Down Expand Up @@ -51,6 +52,12 @@ export type SettingsProps = {
preferredTransactionFormat?: TransactionFormat;
hideChainModal?: boolean;
whitelistedValidatorAddresses?: string[];
tokenIconMapping?:
| Record<TokenDto["symbol"], string>
| ((token: TokenDto) => string);
chainIconMapping?:
| Record<SupportedSKChains, string>
| ((chain: SupportedSKChains) => string);
};

export type SettingsContextType = SettingsProps & VariantProps;
Expand Down
61 changes: 54 additions & 7 deletions packages/widget/src/providers/wagmi/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { getVariantNetworkUrl } from "@sk-widget/components/atoms/token-icon/token-icon-container/hooks/use-variant-network-urls";
import type { CosmosChainsMap } from "@sk-widget/domain/types/chains/cosmos";
import type { EvmChainsMap } from "@sk-widget/domain/types/chains/evm";
import type { MiscChainsMap } from "@sk-widget/domain/types/chains/misc";
import type { SubstrateChainsMap } from "@sk-widget/domain/types/chains/substrate";
import { useWhitelistedValidators } from "@sk-widget/hooks/use-whitelisted-validators";
import type { Networks } from "@stakekit/common";
import type { Wallet, WalletList } from "@stakekit/rainbowkit";
import { connectorsForWallets } from "@stakekit/rainbowkit";
import type { Chain as RainbowkitChain } from "@stakekit/rainbowkit";
import type { QueryClient } from "@tanstack/react-query";
import { useQuery } from "@tanstack/react-query";
import { EitherAsync, Left, Maybe, Right } from "purify-ts";
Expand All @@ -27,7 +30,7 @@ import { getConfig as getLedgerLiveConfig } from "../ledger/config";
import { getConfig as getMiscConfig } from "../misc/config";
import { useSKQueryClient } from "../query-client";
import { getConfig as getSafeConnector } from "../safe/config";
import { useSettings } from "../settings";
import { type SettingsProps, useSettings } from "../settings";
import { getConfig as getSubstrateConfig } from "../substrate/config";

export type BuildWagmiConfig = typeof buildWagmiConfig;
Expand All @@ -51,6 +54,7 @@ const buildWagmiConfig = async (opts: {
isLedgerLive: boolean;
isSafe: boolean;
whitelistedValidatorAddresses: Set<string> | null;
chainIconMapping: SettingsProps["chainIconMapping"];
}): Promise<{
evmConfig: GetEitherAsyncRight<ReturnType<typeof getEvmConfig>>;
cosmosConfig: GetEitherAsyncRight<ReturnType<typeof getCosmosConfig>>;
Expand Down Expand Up @@ -132,12 +136,53 @@ const buildWagmiConfig = async (opts: {
substrateConfig,
ledgerLiveConnector,
} = val;
const chains = [
...evmConfig.evmChains,
...cosmosConfig.cosmosWagmiChains,
...miscConfig.miscChains,
...substrateConfig.substrateChains,
] as [Chain, ...Chain[]];

const chains = Maybe.fromNullable(opts.chainIconMapping)
.map((chainIconMapping) => {
const mapWagmiChain = (val: {
wagmiChain: RainbowkitChain;
skChainName: Networks;
}) => {
const res = getVariantNetworkUrl({
network: val.skChainName,
chainIconMapping,
});

if (res === val.wagmiChain.iconUrl) {
return val.wagmiChain;
}

return {
...val.wagmiChain,
iconBackground: undefined,
iconUrl: res,
} as RainbowkitChain;
};

return [
...Object.values(evmConfig.evmChainsMap).map((val) =>
mapWagmiChain(val)
),
...Object.values(cosmosConfig.cosmosChainsMap).map((val) =>
mapWagmiChain(val)
),
...Object.values(miscConfig.miscChainsMap).map((val) =>
mapWagmiChain(val)
),
...Object.values(substrateConfig.substrateChainsMap).map((val) =>
mapWagmiChain(val)
),
] as [RainbowkitChain, ...RainbowkitChain[]];
})
.orDefaultLazy(
() =>
[
...evmConfig.evmChains,
...cosmosConfig.cosmosWagmiChains,
...miscConfig.miscChains,
...substrateConfig.substrateChains,
] as [RainbowkitChain, ...RainbowkitChain[]]
);

const multiInjectedProviderDiscovery =
!opts.disableInjectedProviderDiscovery &&
Expand Down Expand Up @@ -235,6 +280,7 @@ export const useWagmiConfig = () => {
isSafe,
disableInjectedProviderDiscovery,
mapWalletFn,
chainIconMapping,
} = useSettings();

const queryClient = useSKQueryClient();
Expand All @@ -261,6 +307,7 @@ export const useWagmiConfig = () => {
externalProviders: externalProvidersRef,
}),
whitelistedValidatorAddresses,
chainIconMapping,
}),
});
};
Expand Down