Skip to content

Commit

Permalink
refactor: fetch tokens metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
alexruzenhack committed Jun 13, 2024
1 parent 5502b3c commit 286ed1a
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 63 deletions.
11 changes: 11 additions & 0 deletions src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ export const types = {
TOKEN_METADATA_LOADED: 'TOKEN_METADATA_LOADED',
SET_UNIQUE_DEVICE_ID: 'SET_UNIQUE_DEVICE_ID',
SET_IS_SHOWING_PIN_SCREEN: 'SET_IS_SHOWING_PIN_SCREEN',
/* It initiates download of tokens metadata. */
TOKENS_FETCH_METADATA_REQUESTED: 'TOKENS_FETCH_METADATA_REQUESTED',
TOKEN_FETCH_METADATA_REQUESTED: 'TOKEN_FETCH_METADATA_REQUESTED',
TOKEN_FETCH_METADATA_SUCCESS: 'TOKEN_FETCH_METADATA_SUCCESS',
TOKEN_FETCH_METADATA_FAILED: 'TOKEN_FETCH_METADATA_FAILED',
Expand Down Expand Up @@ -1231,3 +1233,12 @@ export const firstAddressFailure = (failurePayload) => ({
type: types.FIRSTADDRESS_FAILURE,
payload: failurePayload,
});

/**
* Request the downalod of token metadata for a list of tokens.
* @param {string[]} tokens A list of token uid
*/
export const tokensFetchMetadataRequest = (tokens) => ({
type: types.TOKENS_FETCH_METADATA_REQUESTED,
tokens
});
123 changes: 65 additions & 58 deletions src/components/WalletConnect/NewNanoContractTransactionRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,29 @@
* LICENSE file in the root directory of this source tree.
*/

import React, { useMemo, useState } from 'react';
import { StyleSheet, View, Text, ScrollView, TouchableWithoutFeedback, TouchableOpacity, Image } from 'react-native';
import { } from 'react-native-gesture-handler';
import React, {
useEffect,
useMemo,
useState
} from 'react';
import {
StyleSheet,
View,
Text,
ScrollView,
TouchableWithoutFeedback,
TouchableOpacity,
Image
} from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
import { useNavigation } from '@react-navigation/native';
import { t } from 'ttag';
import { fetchTokensMetadata, walletConnectAccept, walletWalletReject } from '../../actions';

import {
fetchTokensMetadata,
tokensFetchMetadataRequest,
walletConnectAccept,
walletWalletReject
} from '../../actions';
import { COLORS } from '../../styles/themes';
import { renderValue } from '../../utils';
import { HathorFlatList } from '../HathorFlatList';
Expand All @@ -23,11 +39,10 @@ import { ModalBase } from '../ModalBase.component';
import NewHathorButton from '../NewHathorButton';
import { SelectAddressModal } from '../NanoContract/SelectAddressModal.component';
import { commonStyles } from './theme';
import { useNavigation } from '@react-navigation/native';

const actionTitleMap = ({ tokenValue }) => ({
deposit: t`${tokenValue} Deposit`,
withdrawal: t`${tokenValue} Withdrawal`,
const actionTitleMap = (tokenSymbol) => ({
deposit: t`${tokenSymbol} Deposit`,
withdrawal: t`${tokenSymbol} Withdrawal`,
});

/**
Expand All @@ -44,56 +59,27 @@ export const NewNanoContractTransactionRequest = ({ ncTxRequest }) => {
const { nc, dapp } = ncTxRequest;
const dispatch = useDispatch();
const navigation = useNavigation();
const { blueprintName } = useSelector((state) => state.nanoContract.registered[nc.ncId]);
const registeredTokensMetadata = useSelector((state) => state.tokenMetadata);
// Use it to add loading feedback
const metadataLoaded = useSelector((state) => state.metadataLoaded);

const [showSelectAddressModal, setShowSelectAddressModal] = useState(false);
const [showDeclineModal, setShowDeclineModal] = useState(false);
const [ncAddress, setNcAddress] = useState(registeredNc.address);
const ncToAccept = useMemo(() => ({ ...nc, caller: ncAddress }), [ncAddress])

// Get blueprint metadata
const registeredNc = useSelector((state) => state.nanoContract.registered[nc.ncId]);
if (!registeredNc) {
if (!blueprintName) {
throw new Error(`Nano Contract ${nc.ncId} not registered.`);
}
const blueprintName = registeredNc.blueprintName;
const [ncAddress, setNcAddress] = useState(registeredNc.address);
const ncToAccept = useMemo(() => ({ ...nc, caller: ncAddress }), [ncAddress])

// Controle SelectAddressModal
const [showSelectAddressModal, setShowSelectAddressModal] = useState(false);
const toggleSelectAddressModal = () => setShowSelectAddressModal(!showSelectAddressModal);
const handleAddressSelection = (newAddress) => {
setNcAddress(newAddress);
toggleSelectAddressModal();
};

// Get tokens metadata
const wallet = useSelector((state) => state.wallet);
const tokensUid = nc.actions.map((each) => each.token);
const registeredTokensMetadata = useSelector((state) => state.tokenMetadata);
const tokensMetadata = {};
const tokensMetadataToDownload = [];

tokensUid.forEach((uid) => {
if (uid in registeredTokensMetadata) {
tokensMetadata[uid] = registeredTokensMetadata[uid];
}
else {
tokensMetadataToDownload.push(uid);
}
});

// TODO: Implement a spinner while token's metadata are under download
if (tokensMetadataToDownload.length > 0) {
const networkName = wallet.getNetworkObject().name;
fetchTokensMetadata(tokensMetadataToDownload, networkName)
.then((metadatas) => {
metadatas.forEach((metadata) => {
tokensMetadata[metadata.uid] = metadata;
});
})
.catch(() => {
// TODO: dispatch error for both user feedback and Sentry
});
}

// Accepts the Nano Contract data preseted.
const onAcceptTransaction = () => {
// Update the caller with the address selected by the user.
Expand All @@ -110,7 +96,21 @@ export const NewNanoContractTransactionRequest = ({ ncTxRequest }) => {
// TODO: It is not being dimissed automatically
};

// TODO: identify the argument name given its position
useEffect(() => {
// Get tokens metadata
const tokensUid = nc.actions.map((each) => each.token);
const tokensMetadataToDownload = [];

tokensUid.forEach((uid) => {
if (!(uid in registeredTokensMetadata)) {
tokensMetadataToDownload.push(uid);
}
});

if (tokensMetadataToDownload.length) {
dispatch(tokensFetchMetadataRequest(tokensMetadataToDownload));
}
}, []);

return (
<>
Expand All @@ -123,7 +123,10 @@ export const NewNanoContractTransactionRequest = ({ ncTxRequest }) => {
blueprintName={blueprintName}
onSelectAddress={toggleSelectAddressModal}
/>
<NanoContractActions ncActions={nc.actions} />
<NanoContractActions
ncActions={nc.actions}
tokens={registeredTokensMetadata}
/>
<NanoContractMethodParams ncArgs={nc.args} />

{/* User actions */}
Expand Down Expand Up @@ -278,8 +281,9 @@ const NanoContractExecInfo = ({ nc, blueprintName, onSelectAddress }) => {
);
};

const NanoContractActions = ({ ncActions }) => {
const NanoContractActions = ({ ncActions, tokens }) => {
const styles = StyleSheet.create({
wrapper: { marginTop: 0, marginBottom: 0, marginHorizontal: 0 },
action: [commonStyles.text, commonStyles.bold],
valueLabel: [commonStyles.text, commonStyles.value, commonStyles.bold, commonStyles.mb4],
value: [commonStyles.text, commonStyles.value],
Expand All @@ -291,13 +295,13 @@ const NanoContractActions = ({ ncActions }) => {
<Text style={commonStyles.sectionTitle}>{'Action List'}</Text>
</View>
<HathorFlatList
wrapperStyle={{ marginTop: 0, marginBottom: 0, marginHorizontal: 0 }}
wrapperStyle={styles.wrapper}
data={ncActions}
renderItem={({ item, index }) => (
<View style={[commonStyles.cardSplit, commonStyles.listItem]}>
<Icon type={item.type} />
<View style={commonStyles.cardSplitContent}>
<Text style={styles.action}>{actionTitleMap(item.type)[item.type]}</Text>
<Text style={styles.action}>{actionTitleMap(tokens[item.token].symbol)[item.type]}</Text>
{item.address
&& (
<View>
Expand All @@ -306,7 +310,7 @@ const NanoContractActions = ({ ncActions }) => {
</View>
)}
</View>
<BalanceValue balance={item.amount} isNft={false} />
<Amount amount={item.amount} isNft={false} />
</View>
)}
keyExtractor={(item) => item.tokenUid}
Expand All @@ -322,7 +326,10 @@ const NanoContractMethodParams = ({ ncArgs }) => {
width: '30%',
paddingRight: 8,
},
argPositionText: [commonStyles.text, commonStyles.bold],
argPositionText: [
commonStyles.text,
commonStyles.bold
],
argValue: {
maxWidth: '70%',
backgroundColor: 'hsla(0, 0%, 96%, 1)',
Expand Down Expand Up @@ -395,14 +402,14 @@ const Icon = ({ type }) => {
return (iconMap[type]);
};

const BalanceValue = ({ balance, isNft }) => {
const balanceValue = renderValue(balance, isNft);
const Amount = ({ amount, isNft }) => {
const amountToRender = renderValue(amount, isNft);

const styles = StyleSheet.create({
wrapper: {
marginLeft: 'auto',
},
balance: {
amount: {
fontSize: 16,
lineHeight: 20,
color: COLORS.black,
Expand All @@ -411,8 +418,8 @@ const BalanceValue = ({ balance, isNft }) => {

return (
<View style={styles.wrapper}>
<Text style={[styles.balance]}>
{balanceValue}
<Text style={[styles.amount]}>
{amountToRender}
</Text>
</View>
)
Expand Down
5 changes: 0 additions & 5 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,6 @@ export const unleashStorageKey = {
ignoreWalletServiceFlag: 'featureFlags:ignoreWalletServiceFlag',
};

/**
* Quantity of token metadata to download concurrently
*/
export const METADATA_CONCURRENT_DOWNLOAD = 5;

// Wallet service URLs
export const WALLET_SERVICE_MAINNET_BASE_URL = 'https://wallet-service.hathor.network/';
export const WALLET_SERVICE_MAINNET_BASE_WS_URL = 'wss://ws.wallet-service.hathor.network/';
Expand Down
10 changes: 10 additions & 0 deletions src/reducers/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ export const reducer = (state = initialState, action) => {
return onUpdateLoadedData(state, action);
case types.SET_USE_WALLET_SERVICE:
return onSetUseWalletService(state, action);
case types.TOKENS_FETCH_METADATA_REQUESTED:
return onTokensFetchMetadataRequested(state);
case types.TOKEN_METADATA_UPDATED:
return onTokenMetadataUpdated(state, action);
case types.TOKEN_METADATA_REMOVED:
Expand Down Expand Up @@ -806,6 +808,14 @@ const onTokenMetadataLoaded = (state, action) => ({
metadataLoaded: action.payload,
});

/**
* Update token metadata status to false, meaning it is loading.
*/
const onTokensFetchMetadataRequested = (state) => ({
...state,
metadataLoaded: false,
});

/**
* Update token metadata
*/
Expand Down
1 change: 1 addition & 0 deletions src/sagas/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,7 @@ export function* saga() {
takeEvery('WALLET_UPDATE_TX', handleTx),
takeEvery('WALLET_BEST_BLOCK_UPDATE', bestBlockUpdate),
takeEvery('WALLET_PARTIAL_UPDATE', loadPartialUpdate),
takeEvery(types.TOKENS_FETCH_METADATA_REQUESTED, fetchTokensMetadata),
takeEvery(types.WALLET_REFRESH_SHARED_ADDRESS, refreshSharedAddress),
takeEvery(types.SELECTADDRESS_ADDRESSES_REQUEST, fetchAllWalletAddresses),
takeEvery(types.FIRSTADDRESS_REQUEST, fetchFirstWalletAddress),
Expand Down

0 comments on commit 286ed1a

Please sign in to comment.