From 1a6f787c5b3b1cbe1ef48b0ba436ef84f1e1b88e Mon Sep 17 00:00:00 2001 From: Angel Castillo Date: Thu, 31 Oct 2024 12:24:42 +0800 Subject: [PATCH] feat: providers are now consumed from the service worker instead of the UI script --- .../DappTransactionContainer.tsx | 9 ++- .../DappTransactionContainer.test.tsx | 21 +++--- .../src/hooks/index.ts | 1 - .../src/hooks/useChainHistoryProvider.ts | 21 ------ .../src/lib/scripts/background/wallet.ts | 24 ++++++- .../slices/blockchain-provider-slice.ts | 66 ++++++++----------- .../QRInfoWalletDrawer/QRInfoWalletDrawer.tsx | 8 +-- .../restore-wallet/steps/WalletOverview.tsx | 4 +- packages/cardano/src/wallet/lib/providers.ts | 43 ++++++++++++ 9 files changed, 117 insertions(+), 80 deletions(-) delete mode 100644 apps/browser-extension-wallet/src/hooks/useChainHistoryProvider.ts diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DappTransactionContainer.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DappTransactionContainer.tsx index a387dc64c..aaf64d5bc 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DappTransactionContainer.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DappTransactionContainer.tsx @@ -12,7 +12,7 @@ import { useViewsFlowContext } from '@providers/ViewFlowProvider'; import { Wallet } from '@lace/cardano'; import { useAddressBookContext, withAddressBookContext } from '@src/features/address-book/context'; import { useWalletStore } from '@stores'; -import { useFetchCoinPrice, useChainHistoryProvider } from '@hooks'; +import { useFetchCoinPrice } from '@hooks'; import { createTxInspector, TransactionSummaryInspection, @@ -25,7 +25,7 @@ import { import { createWalletAssetProvider } from '@cardano-sdk/wallet'; import { Skeleton } from 'antd'; -import { useCurrencyStore, useAppSettingsContext } from '@providers'; +import { useCurrencyStore } from '@providers'; import { logger, walletRepository } from '@lib/wallet-api-ui'; import { useComputeTxCollateral } from '@hooks/useComputeTxCollateral'; import { utxoAndBackendChainHistoryResolver } from '@src/utils/utxo-chain-history-resolver'; @@ -34,6 +34,7 @@ import { AddressBookSchema, useDbStateValue } from '@lib/storage'; import { getAllWalletsAddresses } from '@src/utils/get-all-wallets-addresses'; import { useCexplorerBaseUrl, useDisallowSignTx } from './hooks'; import { NonRegisteredUserModal } from './NonRegisteredUserModal/NonRegisteredUserModal'; +import { getProviders } from '@stores/slices'; interface DappTransactionContainerProps { errorMessage?: string; @@ -69,8 +70,6 @@ export const DappTransactionContainer = withAddressBookContext( const { fiatCurrency } = useCurrencyStore(); const { priceResult } = useFetchCoinPrice(); - const [{ chainName }] = useAppSettingsContext(); - const [fromAddressTokens, setFromAddressTokens] = useState< Map | undefined >(); @@ -81,7 +80,7 @@ export const DappTransactionContainer = withAddressBookContext( TransactionSummaryInspection | undefined >(); - const chainHistoryProvider = useChainHistoryProvider({ chainName }); + const { chainHistoryProvider } = getProviders(); const txInputResolver = useMemo( () => diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/DappTransactionContainer.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/DappTransactionContainer.test.tsx index 9d98f1a56..11f94b793 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/DappTransactionContainer.test.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/DappTransactionContainer.test.tsx @@ -19,11 +19,6 @@ const mockWithAddressBookContext = jest.fn((children) => children); const mockUseCurrencyStore = jest.fn().mockReturnValue({ fiatCurrency: { code: 'usd', symbol: '$' } }); const mockUseFetchCoinPrice = jest.fn().mockReturnValue({ priceResult: { cardano: { price: 2 }, tokens: new Map() } }); const mockUseComputeTxCollateral = jest.fn().mockReturnValue(BigInt(1_000_000)); -const mockUseChainHistoryProvider = jest.fn().mockReturnValue({ - transactionsByAddress: jest.fn().mockResolvedValue([]), - transactionsByHashes: jest.fn().mockResolvedValue([]), - blocksByHashes: jest.fn().mockResolvedValue([]) -}); import * as React from 'react'; import { cleanup, render } from '@testing-library/react'; import { DappTransactionContainer } from '../DappTransactionContainer'; @@ -127,9 +122,19 @@ jest.mock('@providers/currency', (): typeof CurrencyProvider => ({ useCurrencyStore: mockUseCurrencyStore })); -jest.mock('@hooks/useChainHistoryProvider', (): typeof CurrencyProvider => ({ - ...jest.requireActual('@hooks/useChainHistoryProvider'), - useChainHistoryProvider: mockUseChainHistoryProvider +const mockProviders = { + chainHistoryProvider: { + transactionsByAddress: jest.fn().mockResolvedValue([]), + transactionsByHashes: jest.fn().mockResolvedValue([]), + blocksByHashes: jest.fn().mockResolvedValue([]) + }, + assetProvider +}; + +jest.mock('@stores/slices/blockchain-provider-slice', () => ({ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ...jest.requireActual('@stores/slices/blockchain-provider-slice'), + getProviders: () => mockProviders })); jest.mock('@lace/core', () => { diff --git a/apps/browser-extension-wallet/src/hooks/index.ts b/apps/browser-extension-wallet/src/hooks/index.ts index 4b7a8e4f8..18a7f3052 100644 --- a/apps/browser-extension-wallet/src/hooks/index.ts +++ b/apps/browser-extension-wallet/src/hooks/index.ts @@ -21,7 +21,6 @@ export * from './useAssetInfo'; export * from './useUpdateAddressStatus'; export * from './useOnAddressSave'; export * from './useAppInit'; -export * from './useChainHistoryProvider'; export * from './useWalletAvatar'; export * from './useActionExecution'; export * from './useCustomSubmitApi'; diff --git a/apps/browser-extension-wallet/src/hooks/useChainHistoryProvider.ts b/apps/browser-extension-wallet/src/hooks/useChainHistoryProvider.ts deleted file mode 100644 index 4165ef9e8..000000000 --- a/apps/browser-extension-wallet/src/hooks/useChainHistoryProvider.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { getBaseUrlForChain } from '@src/utils/chain'; -import { useMemo } from 'react'; -import { chainHistoryHttpProvider } from '@cardano-sdk/cardano-services-client'; -import { logger } from '@lib/wallet-api-ui'; -import axiosFetchAdapter from '@shiroyasha9/axios-fetch-adapter'; - -export type NetworkType = 'Mainnet' | 'Preprod' | 'Preview' | 'Sanchonet'; - -type UseChainHistoryProviderArgs = { - chainName: NetworkType; -}; - -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -export const useChainHistoryProvider = ({ chainName }: UseChainHistoryProviderArgs) => { - const baseCardanoServicesUrl = getBaseUrlForChain(chainName); - - return useMemo( - () => chainHistoryHttpProvider({ adapter: axiosFetchAdapter, baseUrl: baseCardanoServicesUrl, logger }), - [baseCardanoServicesUrl] - ); -}; diff --git a/apps/browser-extension-wallet/src/lib/scripts/background/wallet.ts b/apps/browser-extension-wallet/src/lib/scripts/background/wallet.ts index 2bc05ff73..39a3cc045 100644 --- a/apps/browser-extension-wallet/src/lib/scripts/background/wallet.ts +++ b/apps/browser-extension-wallet/src/lib/scripts/background/wallet.ts @@ -1,5 +1,5 @@ import { runtime, storage as webStorage } from 'webextension-polyfill'; -import { of, combineLatest, map, EMPTY } from 'rxjs'; +import { of, combineLatest, map, EMPTY, from, switchMap, filter } from 'rxjs'; import { getProviders } from './config'; import { DEFAULT_LOOK_AHEAD_SEARCH, @@ -232,6 +232,28 @@ walletManager }, { logger, runtime } ); + + exposeApi( + { + api$: walletManager.activeWallet$.pipe( + filter((activeWallet) => !!activeWallet), + switchMap((activeWallet) => { + if (!activeWallet) { + return; + } + + const chainId = activeWallet.props.chainId; + const chainName: Wallet.ChainName = chainIdToChainName(chainId); + + // eslint-disable-next-line consistent-return + return from(getProviders(chainName)); + }) + ), + baseChannel: Wallet.walletProvidersChannel(process.env.WALLET_NAME), + properties: Wallet.walletProvidersProperties + }, + { logger, runtime } + ); }) .catch((error) => { logger.error('Failed to initialize wallet manager', error); diff --git a/apps/browser-extension-wallet/src/stores/slices/blockchain-provider-slice.ts b/apps/browser-extension-wallet/src/stores/slices/blockchain-provider-slice.ts index d8de1d50e..b7a5d0245 100644 --- a/apps/browser-extension-wallet/src/stores/slices/blockchain-provider-slice.ts +++ b/apps/browser-extension-wallet/src/stores/slices/blockchain-provider-slice.ts @@ -1,10 +1,7 @@ import { BlockchainProviderSlice, SliceCreator } from '../types'; import { Wallet } from '@lace/cardano'; -import { getBaseUrlForChain } from '@src/utils/chain'; -import axiosFetchAdapter from '@shiroyasha9/axios-fetch-adapter'; -import { config } from '@src/config'; - -const { CHAIN } = config(); +import { consumeRemoteApi } from '@cardano-sdk/web-extension'; +import { runtime } from 'webextension-polyfill'; export interface IBlockchainProvider { stakePoolProvider: Wallet.StakePoolProvider; @@ -16,45 +13,38 @@ export interface IBlockchainProvider { rewardsProvider: Wallet.RewardsProvider; } -export type BlockchainProviderFactory = (chainName: Wallet.ChainName) => IBlockchainProvider; +export type BlockchainProviderFactory = () => IBlockchainProvider; export const IBlockchainProvider = { toWalletProviders: (providers: IBlockchainProvider): Wallet.WalletProvidersDependencies => ({ - stakePoolProvider: providers.stakePoolProvider, - assetProvider: providers.assetProvider, - txSubmitProvider: providers.txSubmitProvider, - networkInfoProvider: providers.networkInfoProvider, - utxoProvider: providers.utxoProvider, - rewardsProvider: providers.rewardsProvider, - chainHistoryProvider: providers.chainHistoryProvider + stakePoolProvider: providers?.stakePoolProvider, + assetProvider: providers?.assetProvider, + txSubmitProvider: providers?.txSubmitProvider, + networkInfoProvider: providers?.networkInfoProvider, + utxoProvider: providers?.utxoProvider, + rewardsProvider: providers?.rewardsProvider, + chainHistoryProvider: providers?.chainHistoryProvider }), fromWalletProviders: (providers: Wallet.WalletProvidersDependencies): IBlockchainProvider => ({ - txSubmitProvider: providers.txSubmitProvider, - assetProvider: providers.assetProvider, - stakePoolProvider: providers.stakePoolProvider, - networkInfoProvider: providers.networkInfoProvider, - utxoProvider: providers.utxoProvider, - rewardsProvider: providers.rewardsProvider, - chainHistoryProvider: providers.chainHistoryProvider + txSubmitProvider: providers?.txSubmitProvider, + assetProvider: providers?.assetProvider, + stakePoolProvider: providers?.stakePoolProvider, + networkInfoProvider: providers?.networkInfoProvider, + utxoProvider: providers?.utxoProvider, + rewardsProvider: providers?.rewardsProvider, + chainHistoryProvider: providers?.chainHistoryProvider }) }; -export const getProviderByChain: BlockchainProviderFactory = (chain = CHAIN) => { - const baseCardanoServicesUrl = getBaseUrlForChain(chain); - - // TODO: LW-11761 reuse providers that are running in SW instead - const providers = Wallet.createProviders({ - axiosAdapter: axiosFetchAdapter, - env: { - baseCardanoServicesUrl, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - blockfrostConfig: {} as any - }, - experiments: {} - }); +const providers = consumeRemoteApi( + { + baseChannel: Wallet.walletProvidersChannel(process.env.WALLET_NAME), + properties: Wallet.walletProvidersProperties + }, + { logger: console, runtime } +); - return IBlockchainProvider.fromWalletProviders(providers); -}; +export const getProviders: BlockchainProviderFactory = () => IBlockchainProvider.fromWalletProviders(providers); /** * has all wallet info related actions and states @@ -63,7 +53,7 @@ export const blockchainProviderSlice: SliceCreator< BlockchainProviderSlice, BlockchainProviderSlice, { currentChainName: Wallet.ChainName; blockchainProviderFactory?: BlockchainProviderFactory } -> = ({ set }, { currentChainName, blockchainProviderFactory = getProviderByChain }) => ({ - blockchainProvider: blockchainProviderFactory(currentChainName), - setBlockchainProvider: (chain) => set({ blockchainProvider: blockchainProviderFactory(chain) }) +> = ({ set }, { blockchainProviderFactory = getProviders }) => ({ + blockchainProvider: blockchainProviderFactory(), + setBlockchainProvider: () => set({ blockchainProvider: blockchainProviderFactory() }) }); diff --git a/apps/browser-extension-wallet/src/views/browser-view/components/QRInfoWalletDrawer/QRInfoWalletDrawer.tsx b/apps/browser-extension-wallet/src/views/browser-view/components/QRInfoWalletDrawer/QRInfoWalletDrawer.tsx index a14fe2371..6e0a5f861 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/components/QRInfoWalletDrawer/QRInfoWalletDrawer.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/components/QRInfoWalletDrawer/QRInfoWalletDrawer.tsx @@ -9,16 +9,17 @@ import { useDrawer } from '../../stores'; import { getQRCodeOptions } from '@src/utils/qrCodeHelpers'; import { Banner, useKeyboardShortcut, useObservable } from '@lace/common'; import { getAssetImageUrl } from '@src/utils/get-asset-image-url'; -import { useAnalyticsContext, useAppSettingsContext } from '@providers'; +import { useAnalyticsContext } from '@providers'; import { PostHogAction } from '@providers/AnalyticsProvider/analyticsTracker'; import { Button, Flex } from '@input-output-hk/lace-ui-toolkit'; import { ExclamationCircleOutlined, PlusCircleOutlined } from '@ant-design/icons'; -import { useChainHistoryProvider, useLocalStorage } from '@hooks'; +import { useLocalStorage } from '@hooks'; import { Divider } from 'antd'; import { Wallet } from '@lace/cardano'; import { getTransactionTotalOutputByAddress } from '@src/utils/get-transaction-total-output'; import { getTotalAssetsByAddress } from '@src/utils/assets-transformers'; import { formatBalance } from '@src/utils/format-number'; +import { getProviders } from '@stores/slices'; type WalletData = { address: Wallet.Cardano.PaymentAddress; @@ -99,8 +100,7 @@ export const QRInfoWalletDrawer = (): React.ReactElement => { const [currentUnusedAddress, setCurrentUnusedAddress] = useState(); const [, closeDrawer] = useDrawer(); const [isReceiveInAdvancedMode] = useLocalStorage('isReceiveInAdvancedMode', false); - const [{ chainName }] = useAppSettingsContext(); - const chainHistoryProvider = useChainHistoryProvider({ chainName }); + const { chainHistoryProvider } = getProviders(); useKeyboardShortcut(['Escape'], () => closeDrawer()); diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/restore-wallet/steps/WalletOverview.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/restore-wallet/steps/WalletOverview.tsx index 628216643..ca9ee0db5 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/restore-wallet/steps/WalletOverview.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/restore-wallet/steps/WalletOverview.tsx @@ -19,7 +19,7 @@ import { Wallet } from '@lace/cardano'; import { compactNumberWithUnit } from '@src/utils/format-number'; import { PortfolioBalance } from '@src/views/browser-view/components'; import { addEllipsis, WarningBanner, toast } from '@lace/common'; -import { getProviderByChain } from '@src/stores/slices'; +import { getProviders } from '@src/stores/slices'; import { CARDANO_COIN_SYMBOL, COINGECKO_URL } from '@src/utils/constants'; import BigNumber from 'bignumber.js'; import styles from './WalletOverview.module.scss'; @@ -59,7 +59,7 @@ export const WalletOverview = (): JSX.Element => { const getData = async () => { if (!walletMetadata || !coinPricing.priceResult.cardano.price) return; try { - const { utxoProvider } = getProviderByChain(walletMetadata.chain); + const { utxoProvider } = getProviders(); const utxos: Wallet.Cardano.Utxo[] = await utxoProvider.utxoByAddresses({ addresses: [walletMetadata.address] }); diff --git a/packages/cardano/src/wallet/lib/providers.ts b/packages/cardano/src/wallet/lib/providers.ts index 018ac4079..7f617ffdf 100644 --- a/packages/cardano/src/wallet/lib/providers.ts +++ b/packages/cardano/src/wallet/lib/providers.ts @@ -29,6 +29,7 @@ import { } from '@cardano-sdk/cardano-services-client'; import { BlockfrostClient, BlockfrostClientConfig, RateLimiter } from './blockfrost/blockfrost-client'; import { BlockfrostAssetProvider } from './blockfrost'; +import { RemoteApiProperties, RemoteApiPropertyType } from '@cardano-sdk/web-extension'; const createTxSubmitProvider = ( httpProviderConfig: CreateHttpProviderConfig, @@ -159,3 +160,45 @@ export const createProviders = ({ rewardsProvider }; }; + +export const walletProvidersChannel = (walletName: string): string => `${walletName}-providers`; +export const walletProvidersProperties: RemoteApiProperties = { + stakePoolProvider: { + queryStakePools: RemoteApiPropertyType.MethodReturningPromise, + stakePoolStats: RemoteApiPropertyType.MethodReturningPromise, + healthCheck: RemoteApiPropertyType.MethodReturningPromise + }, + assetProvider: { + getAsset: RemoteApiPropertyType.MethodReturningPromise, + getAssets: RemoteApiPropertyType.MethodReturningPromise, + healthCheck: RemoteApiPropertyType.MethodReturningPromise + }, + txSubmitProvider: { + submitTx: RemoteApiPropertyType.MethodReturningPromise, + healthCheck: RemoteApiPropertyType.MethodReturningPromise + }, + networkInfoProvider: { + ledgerTip: RemoteApiPropertyType.MethodReturningPromise, + protocolParameters: RemoteApiPropertyType.MethodReturningPromise, + genesisParameters: RemoteApiPropertyType.MethodReturningPromise, + lovelaceSupply: RemoteApiPropertyType.MethodReturningPromise, + stake: RemoteApiPropertyType.MethodReturningPromise, + eraSummaries: RemoteApiPropertyType.MethodReturningPromise, + healthCheck: RemoteApiPropertyType.MethodReturningPromise + }, + utxoProvider: { + utxoByAddresses: RemoteApiPropertyType.MethodReturningPromise, + healthCheck: RemoteApiPropertyType.MethodReturningPromise + }, + rewardsProvider: { + rewardsHistory: RemoteApiPropertyType.MethodReturningPromise, + rewardAccountBalance: RemoteApiPropertyType.MethodReturningPromise, + healthCheck: RemoteApiPropertyType.MethodReturningPromise + }, + chainHistoryProvider: { + transactionsByAddresses: RemoteApiPropertyType.MethodReturningPromise, + transactionsByHashes: RemoteApiPropertyType.MethodReturningPromise, + blocksByHashes: RemoteApiPropertyType.MethodReturningPromise, + healthCheck: RemoteApiPropertyType.MethodReturningPromise + } +};