Skip to content

Commit

Permalink
feat(HW-1044): Contracts store refactoring (#2260)
Browse files Browse the repository at this point in the history
* feat(HW-1044): Fix mobx ts-ignores

* feat(HW-1044): Contracts store

* feat(HW-1044): Store contracts by id

* feat(HW-1044): Check fetched contracts

* feat(HW-1044): _searchContract

* feat(HW-1044): Fix contract search function by using haqq address
  • Loading branch information
devkudasov authored Jan 22, 2025
1 parent 02742cb commit e932aa0
Show file tree
Hide file tree
Showing 33 changed files with 382 additions and 239 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@
"rn-nodeify": "10.3.0",
"ts-jest": "29.1.1",
"ts-node": "10.9.1",
"typescript": "5.1.6",
"typescript": "5.7.3",
"typescript-coverage-report": "0.8.0",
"zx": "7.2.3"
},
Expand Down
17 changes: 10 additions & 7 deletions src/components/json-rpc-sign/json-rpc-common-transaction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,17 @@ import {createTheme} from '@app/helpers';
import {shortAddress} from '@app/helpers/short-address';
import {useEffectAsync} from '@app/hooks/use-effect-async';
import {I18N} from '@app/i18n';
import {Contract} from '@app/models/contract';
import {Fee} from '@app/models/fee';
import {ProviderModel} from '@app/models/provider';
import {Token} from '@app/models/tokens';
import {Balance} from '@app/services/balance';
import {Indexer} from '@app/services/indexer';
import {IToken, JsonRpcMetadata, JsonRpcTransactionRequest} from '@app/types';
import {
ChainId,
IToken,
JsonRpcMetadata,
JsonRpcTransactionRequest,
} from '@app/types';
import {getHostnameFromUrl, openInAppBrowser} from '@app/utils';
import {STRINGS} from '@app/variables/common';

Expand All @@ -41,7 +46,7 @@ export interface JsonRpcCommonTransactionProps {
fee: Fee | null | undefined;
tx: Partial<JsonRpcTransactionRequest> | undefined;
parsedInput: ethers.utils.TransactionDescription | undefined;
chainId: number;
chainId: ChainId;
onFeePress: () => void;
}

Expand Down Expand Up @@ -151,10 +156,8 @@ export const JsonRpcCommonTransaction = ({
}, [provider, parsedInput, delegatorAddress]);

useEffectAsync(async () => {
const resp = await Indexer.instance.getAddresses({
[chainId]: [tx?.to!],
});
const t = resp[chainId]?.[0] ?? Token.UNKNOWN_TOKEN;
const contract = await Contract.getById(tx?.to!, chainId);
const t = contract ?? Token.UNKNOWN_TOKEN;
setToken(t as unknown as IToken);
}, [tx, chainId]);

Expand Down
6 changes: 3 additions & 3 deletions src/components/modals/providers-bottom-sheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {createTheme} from '@app/helpers';
import {useCalculatedDimensionsValue} from '@app/hooks/use-calculated-dimensions-value';
import {I18N} from '@app/i18n';
import {ALL_NETWORKS_ID, Provider} from '@app/models/provider';
import {ModalType, Modals} from '@app/types';
import {ChainId, ModalType, Modals} from '@app/types';

import {SettingsProvidersAllNetworksRow} from '../settings/settings-providers/settings-providers-all-networks-row';
import {SettingsProvidersRow} from '../settings/settings-providers/settings-providers-row';
Expand All @@ -24,7 +24,7 @@ export function ProvidersBottomSheet({
}: Modals[ModalType.providersBottomSheet]) {
const [searchProviderValue, setSearchProviderValue] = useState('');
const bsRef = useRef<BottomSheetRef>(null);
const selectedProvider = useRef(0);
const selectedProvider = useRef<ChainId>(0);

const providers = useMemo(() => {
if (outProviders?.length) {
Expand All @@ -43,7 +43,7 @@ export function ProvidersBottomSheet({
[closeDistance],
);
const onPressProvider = useCallback(
async (providerChainId: number) => {
async (providerChainId: ChainId) => {
if (
!!initialProviderChainId &&
providerChainId === initialProviderChainId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import {Color} from '@app/colors';
import {DataContent, Icon, IconsName, Spacer} from '@app/components/ui';
import {createTheme} from '@app/helpers';
import {ALL_NETWORKS_CHAIN_ID, ProviderModel} from '@app/models/provider';
import {ChainId} from '@app/types';

export type SettingsProvidersAllNetworksRowProps = {
item: ProviderModel;
providerChainId: number;
onPress: (providerChainId: number) => void;
providerChainId: ChainId;
onPress: (providerChainId: ChainId) => void;
};
export const SettingsProvidersAllNetworksRow = ({
item,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ import {Color} from '@app/colors';
import {ImageWrapper} from '@app/components/image-wrapper';
import {DataContent, Icon, Spacer} from '@app/components/ui';
import {ALL_NETWORKS_ID, ProviderModel} from '@app/models/provider';
import {ChainId} from '@app/types';

import {SettingsProvidersAllNetworksRow} from './settings-providers-all-networks-row';

export type SettingsProvidersRowProps = {
item: ProviderModel;
providerChainId: number;
onPress: (providerChainId: number) => void;
providerChainId: ChainId;
onPress: (providerChainId: ChainId) => void;
};
export const SettingsProvidersRow = ({
item,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import React from 'react';
import {FlatList, StyleSheet} from 'react-native';

import {ProviderModel} from '@app/models/provider';
import {ChainId} from '@app/types';

import {SettingsProvidersRow} from './settings-providers-row';

export type SettingsProvidersProps = {
providers: ProviderModel[];
providerChainId: number;
onSelect: (providerChainId: number) => void;
providerChainId: ChainId;
onSelect: (providerChainId: ChainId) => void;
};

export const SettingsProviders = ({
Expand Down
3 changes: 2 additions & 1 deletion src/components/wallet-row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {StyleProp, ViewStyle} from 'react-native';

import {Provider} from '@app/models/provider';
import {WalletModel} from '@app/models/wallet';
import {ChainId} from '@app/types';

import {WalletRowVariant1} from './wallet-row-variant-1';
import {WalletRowVariant2} from './wallet-row-variant-2';
Expand All @@ -28,7 +29,7 @@ export type WalletRowProps = {
disabled?: boolean;
type?: WalletRowTypes;
hideBalance?: boolean;
chainId?: number;
chainId?: ChainId;
};

export const WalletRow = ({
Expand Down
3 changes: 2 additions & 1 deletion src/components/wallet-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import {PopupContainer} from '@app/components/ui';
import {WalletRow, WalletRowTypes} from '@app/components/wallet-row';
import {createTheme} from '@app/helpers';
import {WalletModel} from '@app/models/wallet';
import {ChainId} from '@app/types';

interface Props {
initialAddress?: string;
wallets: WalletModel[];
style?: StyleProp<ViewStyle>;
chainId?: number;
chainId?: ChainId;
onWalletSelected?(address: string): void;
}

Expand Down
3 changes: 2 additions & 1 deletion src/components/web3-browser/web3-browser-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {WebViewNavigation} from 'react-native-webview';
import {Color} from '@app/colors';
import {createTheme} from '@app/helpers';
import {Wallet} from '@app/models/wallet';
import {ChainId} from '@app/types';
import {IS_ANDROID} from '@app/variables/common';

import {clearUrl} from '../../helpers/web3-browser-utils';
Expand All @@ -33,7 +34,7 @@ interface Web3BrowserHeaderProps {
webviewNavigationData: WebViewNavigation;
siteUrl: string;
popup: boolean;
chainId: number;
chainId: ChainId;

onPressMore(): void;

Expand Down
4 changes: 2 additions & 2 deletions src/helpers/await-for-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import {app} from '@app/contexts';
import {showModal} from '@app/helpers/modal';
import {I18N} from '@app/i18n';
import {ProviderModel} from '@app/models/provider';
import {ModalType} from '@app/types';
import {ChainId, ModalType} from '@app/types';

import {getWindowHeight} from './scaling-utils';

export interface AwaitProviderParams {
title: I18N;
providers?: ProviderModel[];
initialProviderChainId?: number;
initialProviderChainId?: ChainId;
disableAllNetworksOption?: boolean;
}

Expand Down
4 changes: 2 additions & 2 deletions src/helpers/await-for-wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {Provider} from '@app/models/provider';
import {Wallet, WalletModel} from '@app/models/wallet';
import {navigator} from '@app/navigator';
import {HomeStackRoutes} from '@app/route-types';
import {Eventable} from '@app/types';
import {ChainId, Eventable} from '@app/types';

import {getWindowHeight} from './scaling-utils';

Expand All @@ -21,7 +21,7 @@ export interface AwaitForWalletParams {
initialAddress?: string;
autoSelectWallet?: boolean;
suggestedAddress?: string;
chainId?: number;
chainId?: ChainId;
eventSuffix?: string | number;
hideBalance?: boolean;
}
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/get-rpc-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {EthRpcEndpointAvailability} from './eth-rpc-endpoint-availability';
export async function getRpcProvider(provider: ProviderModel) {
await EthRpcEndpointAvailability.awaitForInitialization();
return new ethers.providers.StaticJsonRpcProvider(provider.ethRpcEndpoint, {
chainId: provider.ethChainId,
chainId: provider.ethChainId as number,
name: provider.name,
});
}
16 changes: 6 additions & 10 deletions src/models/app/app.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ class AppStore {
private _isInitialized = false;

// Hydrated properties
private _isOnboarded = false;
private _networkLoggerEnabled = false;
private _networkLogsCacheSize = 500; // count of stored http request
private _testnetsEnabledForAllNetworks = true;
_isOnboarded = false;
_networkLoggerEnabled = false;
_networkLogsCacheSize = 500; // count of stored http request
_testnetsEnabledForAllNetworks = true;
isDeveloperModeEnabled = Config.IS_DEVELOPMENT === 'true';
isTesterModeEnabled = Config.IS_TESTMODE === 'true';

Expand All @@ -25,16 +25,12 @@ class AppStore {
makePersistable(this, {
name: this.constructor.name,
properties: [
// @ts-ignore
'_isOnboarded',
'isDeveloperModeEnabled',
'isTesterModeEnabled',
// @ts-ignore
'_networkLoggerEnabled',
// @ts-ignore
'_testnetsEnabledForAllNetworks',
// @ts-ignore
'_networkLogsCacheSize',
'isDeveloperModeEnabled',
'isTesterModeEnabled',
],
storage,
});
Expand Down
126 changes: 126 additions & 0 deletions src/models/contract/contract.store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import {makeAutoObservable, runInAction} from 'mobx';
import {makePersistable} from 'mobx-persist-store';

import {AddressUtils} from '@app/helpers/address-utils';
import {Indexer, IndexerAddressesResponse} from '@app/services/indexer';
import {storage} from '@app/services/mmkv';
import {ChainId} from '@app/types';

import {ContractStoreData, IndexerContract} from './contract.types';

import {ALL_NETWORKS_ID, Provider} from '../provider';

class Contract {
_data: ContractStoreData = {};

private _searchContract = (contractAddress: string) => {
const fetchedContractFlatMap = Object.entries(this._data).flatMap(
([_, v]) => Object.entries(v).flatMap(([__, c]) => c),
);
return (
fetchedContractFlatMap?.find(t =>
AddressUtils.equals(t.id, contractAddress),
) ?? null
);
};

constructor(shouldSkipPersisting: boolean = false) {
makeAutoObservable(this);
if (!shouldSkipPersisting) {
makePersistable(this, {
name: this.constructor.name,
properties: ['_data'],
storage,
});
}
}

/**
* Fetch contracts' information and store it into this._data
*
* @param contractAddresses Array of contract's addresses which shoul be fetched
* @param chainId Chain id in which contracts will be fetched. If no chainId provided then contracts will be fetched for all chains
*/
fetch = async (contractAddresses: string[], chainId?: ChainId) => {
let contracts: IndexerAddressesResponse | null = null;

if (!chainId) {
const headers = Indexer.instance.getProvidersHeader(
contractAddresses,
Provider.getById(ALL_NETWORKS_ID),
);
contracts = await Indexer.instance.getAddresses(headers);
} else {
contracts = await Indexer.instance.getAddresses({
[chainId]: contractAddresses,
});
}

if (contracts) {
runInAction(() => {
this._data = Object.entries(contracts).reduce((acc, [cId, data]) => {
const reducedContracts = data.reduce(
(prev, contract) => ({
...prev,
[contract.id]: contract,
}),
{} as Record<string, IndexerContract>,
);

return {
...this._data,
...acc,
[cId]: {
...this._data[cId],
...reducedContracts,
},
};
}, {} as ContractStoreData);
});
}
};

/**
* Fetch contract information and update this._data with it
*
* @param contractAddress Contract's address which shoul be fetched
* @param chainId Chain id in which contracts will be fetched. If no chainId provided then contracts will be fetched for all chains
* @returns Contract for {contractAddress}
*/
getById = async (
contractAddress: string,
chainId?: ChainId,
): Promise<IndexerContract | null> => {
let contract: IndexerContract | null = null;
const contractId = AddressUtils.toHaqq(contractAddress);

if (!chainId) {
// Check already fetched contracts
contract = this._searchContract(contractId);

// If fetched contract doesn't exists than fetch and find contract from all chains
if (!contract) {
const headers = Indexer.instance.getProvidersHeader(
[contractAddress],
Provider.getById(ALL_NETWORKS_ID),
);
const contracts = await Indexer.instance.getAddresses(headers);
const contractFlatMap = Object.entries(contracts).flatMap(
([_, v]) => v,
);
contract = contractFlatMap?.find(t => t.name) ?? null;
}
} else {
contract = this._data[chainId][contractId] ?? null;
if (!contract) {
await this.fetch([contractAddress], chainId);
contract = this._data[chainId][contractId] ?? null;
}
}

return contract;
};
}

const instance = new Contract(Boolean(process.env.JEST_WORKER_ID));
export {instance as Contract};
Loading

0 comments on commit e932aa0

Please sign in to comment.