Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Issue-3920] Show well-known tokens on top #3934

Open
wants to merge 13 commits into
base: subwallet-dev
Choose a base branch
from
5 changes: 5 additions & 0 deletions packages/extension-base/src/background/KoniTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,13 @@
externalUrl?: string;
rarity?: string;
description?: string;
properties?: Record<any, any> | null;

Check warning on line 235 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

Unexpected any. Specify a different type

Check warning on line 235 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

Unexpected any. Specify a different type
}

interface NftItemExtraInfo {
type?: _AssetType.ERC721 | _AssetType.PSP34 | RMRK_VER; // for sending
rmrk_ver?: RMRK_VER;
onChainOption?: any; // for sending PSP-34 tokens, should be done better

Check warning on line 241 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

Unexpected any. Specify a different type
assetHubType?: AssetHubNftType // for sending assetHub nft. There're 2 types nft
}

Expand Down Expand Up @@ -543,7 +543,7 @@
[ExtrinsicType.STAKING_COMPOUNDING]: RequestTuringStakeCompound,
[ExtrinsicType.STAKING_CANCEL_COMPOUNDING]: RequestTuringCancelStakeCompound,
[ExtrinsicType.STAKING_CANCEL_UNSTAKE]: RequestStakeCancelWithdrawal,
[ExtrinsicType.STAKING_POOL_WITHDRAW]: any,

Check warning on line 546 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

Unexpected any. Specify a different type

// Yield
[ExtrinsicType.JOIN_YIELD_POOL]: RequestYieldStepSubmit,
Expand Down Expand Up @@ -574,9 +574,9 @@
[ExtrinsicType.CLAIM_BRIDGE]: RequestClaimBridge

[ExtrinsicType.EVM_EXECUTE]: TransactionConfig,
[ExtrinsicType.CROWDLOAN]: any,

Check warning on line 577 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

Unexpected any. Specify a different type
[ExtrinsicType.SWAP]: SwapTxData
[ExtrinsicType.UNKNOWN]: any

Check warning on line 579 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

Unexpected any. Specify a different type
}

export enum ExtrinsicStatus {
Expand Down Expand Up @@ -675,7 +675,7 @@
// : T extends ExtrinsicType.MINT_VDOT
// ? Pick<SubmitBifrostLiquidStaking, 'rewardTokenSlug' | 'estimatedAmountReceived'>
// : undefined;
export interface TransactionHistoryItem<ET extends ExtrinsicType = ExtrinsicType.TRANSFER_BALANCE> {

Check warning on line 678 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

'ET' is defined but never used
origin?: 'app' | 'migration' | 'subsquid' | 'subscan', // 'app' or history source
callhash?: string,
signature?: string,
Expand All @@ -700,7 +700,7 @@
tip?: AmountData,
fee?: AmountData,
explorerUrl?: string,
additionalInfo?: any,

Check warning on line 703 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

Unexpected any. Specify a different type
startBlock?: number,
nonce?: number,
addressPrefix?: number
Expand Down Expand Up @@ -931,12 +931,12 @@
recipientAddress: string,

nftItemName?: string, // Use for confirmation view only
params: Record<string, any>,

Check warning on line 934 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

Unexpected any. Specify a different type
nftItem: NftItem
}

export interface EvmNftTransaction extends ValidateTransactionResponse {
tx: Record<string, any> | null;

Check warning on line 939 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

Unexpected any. Specify a different type
}

export interface ValidateNetworkResponse {
Expand Down Expand Up @@ -2294,6 +2294,11 @@

/* Ledger */
'pri(ledger.generic.allow)': [null, string[], string[]];
/* Ledger */

/* Popular tokens */
'pri(popular.tokens)': [null, Record<string, number>, Record<string, number>];
/* Popular tokens */
}

export interface ApplicationMetadataType {
Expand Down
24 changes: 24 additions & 0 deletions packages/extension-base/src/koni/background/handlers/Extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3933,6 +3933,24 @@ export default class KoniExtension {

/* Ledger */

/* Popular tokens */

private subscribePopularTokens (id: string, port: chrome.runtime.Port): Record<string, number> {
const cb = createSubscription<'pri(popular.tokens)'>(id, port);

const subscription = this.#koniState.chainService.observablePopularTokens.popularTokens.subscribe(cb);

this.createUnsubscriptionHandle(id, subscription.unsubscribe);

port.onDisconnect.addListener((): void => {
this.cancelSubscription(id);
});

return this.#koniState.chainService.valuePopularTokens.popularTokens;
}

/* Popular tokens */

// --------------------------------------------------------------
// eslint-disable-next-line @typescript-eslint/require-await
public async handle<TMessageType extends MessageTypes> (id: string, type: TMessageType, request: RequestTypes[TMessageType], port: chrome.runtime.Port): Promise<ResponseType<TMessageType>> {
Expand Down Expand Up @@ -4543,6 +4561,12 @@ export default class KoniExtension {
case 'pri(ledger.generic.allow)':
return this.subscribeLedgerGenericAllowChains(id, port);
/* Ledger */

/* Popular tokens */
case 'pri(popular.tokens)':
return this.subscribePopularTokens(id, port);
/* Popular tokens */

// Default
default:
throw new Error(`Unable to handle message of type ${type}`);
Expand Down
36 changes: 36 additions & 0 deletions packages/extension-base/src/services/chain-service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export class ChainService {
private assetLogoMapSubject = new BehaviorSubject<Record<string, string>>(AssetLogoMap);
private chainLogoMapSubject = new BehaviorSubject<Record<string, string>>(ChainLogoMap);
private ledgerGenericAllowChainsSubject = new BehaviorSubject<string[]>([]);
private popularTokensSubject = new BehaviorSubject<Record<string, number>>({});

// Todo: Update to new store indexed DB
private store: AssetSettingStore = new AssetSettingStore();
Expand Down Expand Up @@ -141,6 +142,26 @@ export class ChainService {
};
}

public get valuePopularTokens () {
PDTnhah marked this conversation as resolved.
Show resolved Hide resolved
const popularTokens = this.popularTokensSubject;

return {
get popularTokens () {
return popularTokens.value;
}
};
}

public get observablePopularTokens () {
PDTnhah marked this conversation as resolved.
Show resolved Hide resolved
const popularTokens = this.popularTokensSubject;

return {
get popularTokens () {
return popularTokens.asObservable();
}
};
}

public subscribeSwapRefMap () {
return this.swapRefMapSubject;
}
Expand Down Expand Up @@ -767,6 +788,11 @@ export class ChainService {
this.logger.log('Finished updating latest ledger generic allow chains');
}

handleLatestPopularTokens (latestPopularTokens: Record<string, number>) {
this.popularTokensSubject.next(latestPopularTokens);
this.logger.log('Finished updating latest popular tokens');
}

handleLatestData () {
this.fetchLatestChainData().then((latestChainInfo) => {
this.lockChainInfoMap = true; // do not need to check current lockChainInfoMap because all remains action is fast enough and don't affect this feature.
Expand All @@ -786,6 +812,12 @@ export class ChainService {
this.handleLatestLedgerGenericAllowChains(latestledgerGenericAllowChains);
})
.catch(console.error);

this.fetchLatestPopularTokens()
.then((latestPopularTokens) => {
this.handleLatestPopularTokens(latestPopularTokens);
})
.catch(console.error);
}

private async initApis () {
Expand Down Expand Up @@ -1088,6 +1120,10 @@ export class ChainService {
return await fetchStaticData<string[]>('chains/ledger-generic-allow-chains') || [];
}

private async fetchLatestPopularTokens () {
return await fetchStaticData<Record<string, number>>('chain-assets/popular-tokens') || [];
}

private async initChains () {
const storedChainSettings = await this.dbService.getAllChainStore();
const defaultChainInfoMap = filterChainInfoMap(ChainInfoMap, ignoredList);
Expand Down
7 changes: 4 additions & 3 deletions packages/extension-koni-ui/src/Popup/Home/Tokens/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { UpperBlock } from '@subwallet/extension-koni-ui/Popup/Home/Tokens/Upper
import { RootState } from '@subwallet/extension-koni-ui/stores';
import { AccountAddressItemType, ThemeProps, TransferParams } from '@subwallet/extension-koni-ui/types';
import { TokenBalanceItemType } from '@subwallet/extension-koni-ui/types/balance';
import { getTransactionFromAccountProxyValue, isAccountAll, sortTokenByValue } from '@subwallet/extension-koni-ui/utils';
import { getTransactionFromAccountProxyValue, isAccountAll, sortToken } from '@subwallet/extension-koni-ui/utils';
import { isTonAddress } from '@subwallet/keyring';
import { Button, Icon, ModalContext, SwAlert } from '@subwallet/react-ui';
import classNames from 'classnames';
Expand Down Expand Up @@ -47,6 +47,7 @@ const Component = (): React.ReactElement => {
totalBalanceInfo }, tokenGroupStructure: { sortedTokenGroups } } = useContext(HomeContext);
const notify = useNotification();
const { onOpenReceive, receiveModalProps } = useCoreReceiveModalHelper();
const popularTokens = useSelector((state: RootState) => state.chainStore.popularTokens);

const isZkModeSyncing = useSelector((state: RootState) => state.mantaPay.isSyncing);
const zkModeSyncProgress = useSelector((state: RootState) => state.mantaPay.progress);
Expand Down Expand Up @@ -300,8 +301,8 @@ const Component = (): React.ReactElement => {
}
});

return result.sort(sortTokenByValue);
}, [sortedTokenGroups, tokenGroupBalanceMap]);
return sortToken(result, popularTokens);
}, [sortedTokenGroups, tokenGroupBalanceMap, popularTokens]);

useEffect(() => {
window.addEventListener('resize', handleResize);
Expand Down
3 changes: 2 additions & 1 deletion packages/extension-koni-ui/src/contexts/DataContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import { ping } from '@subwallet/extension-koni-ui/messaging';
import { persistor, store, StoreName } from '@subwallet/extension-koni-ui/stores';
import { getMissionPoolData, subscribeAccountsData, subscribeAddressBook, subscribeAssetLogoMaps, subscribeAssetRegistry, subscribeAssetSettings, subscribeAuthorizeRequests, subscribeAuthUrls, subscribeBalance, subscribeBuyServices, subscribeBuyTokens, subscribeCampaignBannerData, subscribeCampaignConfirmationData, subscribeCampaignPopupData, subscribeCampaignPopupVisibility, subscribeChainInfoMap, subscribeChainLogoMaps, subscribeChainStakingMetadata, subscribeChainStateMap, subscribeChainStatusMap, subscribeConfirmationRequests, subscribeConfirmationRequestsTon, subscribeConnectWCRequests, subscribeCrowdloan, subscribeKeyringState, subscribeLedgerGenericAllowNetworks, subscribeMantaPayConfig, subscribeMantaPaySyncingState, subscribeMetadataRequests, subscribeMultiChainAssetMap, subscribeNftCollections, subscribeNftItems, subscribePrice, subscribeProcessingCampaign, subscribeRewardHistory, subscribeSigningRequests, subscribeStaking, subscribeStakingNominatorMetadata, subscribeStakingReward, subscribeSwapPairs, subscribeTransactionRequests, subscribeTxHistory, subscribeUiSettings, subscribeUnreadNotificationCount, subscribeWalletConnectSessions, subscribeWCNotSupportRequests, subscribeXcmRefMap, subscribeYieldMinAmountPercent, subscribeYieldPoolInfo, subscribeYieldPositionInfo, subscribeYieldReward } from '@subwallet/extension-koni-ui/stores/utils';
import { getMissionPoolData, subscribeAccountsData, subscribeAddressBook, subscribeAssetLogoMaps, subscribeAssetRegistry, subscribeAssetSettings, subscribeAuthorizeRequests, subscribeAuthUrls, subscribeBalance, subscribeBuyServices, subscribeBuyTokens, subscribeCampaignBannerData, subscribeCampaignConfirmationData, subscribeCampaignPopupData, subscribeCampaignPopupVisibility, subscribeChainInfoMap, subscribeChainLogoMaps, subscribeChainStakingMetadata, subscribeChainStateMap, subscribeChainStatusMap, subscribeConfirmationRequests, subscribeConfirmationRequestsTon, subscribeConnectWCRequests, subscribeCrowdloan, subscribeKeyringState, subscribeLedgerGenericAllowNetworks, subscribeMantaPayConfig, subscribeMantaPaySyncingState, subscribeMetadataRequests, subscribeMultiChainAssetMap, subscribeNftCollections, subscribeNftItems, subscribePopularTokens, subscribePrice, subscribeProcessingCampaign, subscribeRewardHistory, subscribeSigningRequests, subscribeStaking, subscribeStakingNominatorMetadata, subscribeStakingReward, subscribeSwapPairs, subscribeTransactionRequests, subscribeTxHistory, subscribeUiSettings, subscribeUnreadNotificationCount, subscribeWalletConnectSessions, subscribeWCNotSupportRequests, subscribeXcmRefMap, subscribeYieldMinAmountPercent, subscribeYieldPoolInfo, subscribeYieldPositionInfo, subscribeYieldReward } from '@subwallet/extension-koni-ui/stores/utils';
import Bowser from 'bowser';
import React from 'react';
import { Provider } from 'react-redux';
Expand Down Expand Up @@ -200,6 +200,7 @@ export const DataContextProvider = ({ children }: DataContextProviderProps) => {
_DataContext.addHandler({ ...subscribeChainStatusMap, name: 'subscribeChainStatusMap', relatedStores: ['chainStore'], isStartImmediately: true });
_DataContext.addHandler({ ...subscribeChainInfoMap, name: 'subscribeChainInfoMap', relatedStores: ['chainStore'], isStartImmediately: true });
_DataContext.addHandler({ ...subscribeLedgerGenericAllowNetworks, name: 'subscribeLedgerGenericAllowNetworks', relatedStores: ['chainStore'], isStartImmediately: true });
_DataContext.addHandler({ ...subscribePopularTokens, name: 'subscribePopularTokens', relatedStores: ['chainStore'], isStartImmediately: true });
PDTnhah marked this conversation as resolved.
Show resolved Hide resolved

_DataContext.addHandler({ ...subscribeAssetRegistry, name: 'subscribeAssetRegistry', relatedStores: ['assetRegistry'], isStartImmediately: true });
_DataContext.addHandler({ ...subscribeMultiChainAssetMap, name: 'subscribeMultiChainAssetMap', relatedStores: ['assetRegistry'], isStartImmediately: true });
Expand Down
10 changes: 10 additions & 0 deletions packages/extension-koni-ui/src/stores/feature/common/ChainStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const initialState: ChainStore = {
chainStateMap: {},
chainStatusMap: {},
ledgerGenericAllowNetworks: [],
popularTokens: {},
reduxStatus: ReduxStatus.INIT
};

Expand Down Expand Up @@ -53,6 +54,15 @@ const chainStoreSlice = createSlice({
ledgerGenericAllowNetworks: payload,
reduxStatus: ReduxStatus.READY
};
},
updatePopularTokens (state, action: PayloadAction<Record<string, number>>) {
const { payload } = action;

return {
...state,
popularTokens: payload,
reduxStatus: ReduxStatus.READY
};
}
}
});
Expand Down
1 change: 1 addition & 0 deletions packages/extension-koni-ui/src/stores/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export interface ChainStore extends BaseReduxStore {
chainStateMap: Record<string, _ChainState>
chainStatusMap: Record<string, _ChainApiStatus>
ledgerGenericAllowNetworks: string[];
popularTokens: Record<string, number>;
}

export interface BalanceStore extends BaseReduxStore {
Expand Down
8 changes: 8 additions & 0 deletions packages/extension-koni-ui/src/stores/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -508,3 +508,11 @@ export const updateUnreadNotificationCountMap = (data: Record<string, number>) =

export const subscribeUnreadNotificationCount = lazySubscribeMessage('pri(inappNotification.subscribeUnreadNotificationCountMap)', null, updateUnreadNotificationCountMap, updateUnreadNotificationCountMap);
/* Notification service */

/* Popular tokens */
export const updatePopularTokens = (data: Record<string, number>) => {
store.dispatch({ type: 'chainStore/updatePopularTokens', payload: data });
};

export const subscribePopularTokens = lazySubscribeMessage('pri(popular.tokens)', null, updatePopularTokens, updatePopularTokens);
/* Popular tokens */
23 changes: 23 additions & 0 deletions packages/extension-koni-ui/src/utils/sort/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,26 @@ export const sortTokenByValue = (a: TokenBalanceItemType, b: TokenBalanceItemTyp
return b.total.value.minus(a.total.value).toNumber();
}
};

export function sortToken (tokenGroupSlug: TokenBalanceItemType[], popularTokens: Record<string, number>) {
return tokenGroupSlug.sort((a, b) => {
PDTnhah marked this conversation as resolved.
Show resolved Hide resolved
const aIsPiorityToken = Object.keys(popularTokens).includes(a.slug);
const bIsPiorityToken = Object.keys(popularTokens).includes(b.slug);
const aPiority = popularTokens[a.slug];
const bPiority = popularTokens[b.slug];

if (aIsPiorityToken && !bIsPiorityToken) {
return -1;
} else if (!aIsPiorityToken && bIsPiorityToken) {
return 1;
} else if (!aIsPiorityToken && !bIsPiorityToken) {
return sortTokenByValue(a, b);
} else {
if (aPiority < bPiority) {
return -1;
} else {
return 1;
}
}
});
}
Loading