Skip to content

Commit

Permalink
feat: add account UI (#475)
Browse files Browse the repository at this point in the history
* feat: add account ui

---------

Co-authored-by: khanti42 <[email protected]>
  • Loading branch information
stanleyyconsensys and khanti42 authored Jan 14, 2025
1 parent 61ea119 commit 8688436
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 36 deletions.
12 changes: 5 additions & 7 deletions packages/wallet-ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,10 @@ function App() {
} = useAppSelector((state) => state.modals);
const { loader } = useAppSelector((state) => state.UI);
const networks = useAppSelector((state) => state.networks);
const { accounts } = useAppSelector((state) => state.wallet);
const { currentAccount } = useAppSelector((state) => state.wallet);
const { hasMetamask } = useHasMetamask();

const address =
accounts?.length > 0 ? (accounts[0] as unknown as string) : DUMMY_ADDRESS;
const chainId = networks.items?.[networks.activeNetwork]?.chainId;
const address = currentAccount ?? DUMMY_ADDRESS;

useEffect(() => {
if (!provider) {
Expand All @@ -57,12 +56,11 @@ function App() {
}, [connected, forceReconnect, hasMetamask, provider]);

useEffect(() => {
if (provider && networks.items.length > 0) {
const chainId = networks.items[networks.activeNetwork].chainId;
if (provider && networks.items.length > 0 && chainId) {
getWalletData(chainId);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [networks.activeNetwork, provider]);
}, [networks.activeNetwork, provider, chainId]);

const loading = loader.isLoading;
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,23 @@ export const TransactionsListView = ({ transactions }: Props) => {
const networks = useAppSelector((state) => state.networks);
const wallet = useAppSelector((state) => state.wallet);
const timeoutHandle = useRef(setTimeout(() => {}));
const chainId = networks.items[networks.activeNetwork]?.chainId;
const {
currentAccount,
erc20TokenBalanceSelected,
transactions: walletTransactions,
} = wallet;

useEffect(() => {
const chain = networks.items[networks.activeNetwork]?.chainId;
const address = wallet.accounts?.[0] as unknown as string;
if (chain && address) {
if (chainId && currentAccount) {
clearTimeout(timeoutHandle.current); // cancel the timeout that was in-flight
timeoutHandle.current = setTimeout(
() =>
getTransactions(
address,
wallet.erc20TokenBalanceSelected.address,
currentAccount,
erc20TokenBalanceSelected.address,
10,
chain,
chainId,
false,
true,
),
Expand All @@ -37,30 +41,29 @@ export const TransactionsListView = ({ transactions }: Props) => {
return () => clearTimeout(timeoutHandle.current);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [wallet.transactions]);
}, [walletTransactions]);

useEffect(
() => {
const chain = networks.items[networks.activeNetwork]?.chainId;
const address = wallet.accounts?.[0] as unknown as string;
if (chain && address) {
if (chainId && currentAccount) {
clearTimeout(timeoutHandle.current); // cancel the timeout that was in-flight
getTransactions(
address,
wallet.erc20TokenBalanceSelected.address,
currentAccount,
erc20TokenBalanceSelected.address,
10,
chain,
chainId,
);
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[
// eslint-disable-next-line react-hooks/exhaustive-deps
wallet.erc20TokenBalanceSelected.address,
erc20TokenBalanceSelected.address,
// eslint-disable-next-line react-hooks/exhaustive-deps
wallet.erc20TokenBalanceSelected.chainId,
erc20TokenBalanceSelected.chainId,
// eslint-disable-next-line react-hooks/exhaustive-deps
wallet.accounts?.[0],
currentAccount,
chainId,
],
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export const AddTokenModalView = ({ closeModal }: Props) => {
const { setErc20TokenBalance, addErc20Token } = useStarkNetSnap();
const [enabled, setEnabled] = useState(false);
const networks = useAppSelector((state) => state.networks);
const { accounts } = useAppSelector((state) => state.wallet);
const chain = networks && networks.items[networks.activeNetwork].chainId;
const { currentAccount } = useAppSelector((state) => state.wallet);
const chainId = networks && networks.items[networks.activeNetwork].chainId;
const [isValidAddress, setIsValidAddress] = useState(false);
const [fields, setFields] = useState({
address: '',
Expand Down Expand Up @@ -105,8 +105,8 @@ export const AddTokenModalView = ({ closeModal }: Props) => {
fields.name,
fields.symbol,
parseFloat(fields.decimal),
chain,
accounts[0] as unknown as string,
chainId,
currentAccount,
);
if (newToken) {
setErc20TokenBalance(newToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export const SendSummaryModalView = ({
selectedFeeToken,
}: Props) => {
const wallet = useAppSelector((state) => state.wallet);
const currentAccount = wallet.currentAccount;
const [estimatingGas, setEstimatingGas] = useState(true);
const [gasFees, setGasFees] = useState({
suggestedMaxFee: '0',
Expand Down Expand Up @@ -80,7 +81,7 @@ export const SendSummaryModalView = ({

useEffect(() => {
const fetchGasFee = () => {
if (wallet.accounts) {
if (currentAccount) {
setGasFeesError(false);
setEstimatingGas(true);
const amountBN = ethers.utils.parseUnits(
Expand All @@ -92,7 +93,7 @@ export const SendSummaryModalView = ({
wallet.erc20TokenBalanceSelected.address,
ContractFuncName.Transfer,
callData,
wallet.accounts[0] as unknown as string,
currentAccount,
chainId,
selectedFeeToken === FeeToken.STRK
? constants.TRANSACTION_VERSION.V3
Expand All @@ -113,7 +114,7 @@ export const SendSummaryModalView = ({
}
};
fetchGasFee();
}, []);
}, [currentAccount]);

useEffect(() => {
if (gasFees?.suggestedMaxFee) {
Expand Down Expand Up @@ -175,7 +176,7 @@ export const SendSummaryModalView = ({
}, [amount, wallet.erc20TokenBalanceSelected]);

const handleConfirmClick = () => {
if (wallet.accounts) {
if (currentAccount) {
const amountBN = ethers.utils.parseUnits(
amount,
wallet.erc20TokenBalanceSelected.decimals,
Expand All @@ -185,7 +186,7 @@ export const SendSummaryModalView = ({
wallet.erc20TokenBalanceSelected.address,
ContractFuncName.Transfer,
callData,
wallet.accounts[0] as unknown as string,
currentAccount,
gasFees.suggestedMaxFee,
chainId,
selectedFeeToken,
Expand All @@ -194,7 +195,7 @@ export const SendSummaryModalView = ({
if (result) {
toastr.success('Transaction sent successfully');
getTransactions(
wallet.accounts[0] as unknown as string,
currentAccount,
wallet.erc20TokenBalanceSelected.address,
10,
chainId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ export const InfoIcon = styled(RoundedIcon)`
margin-right: ${(props) => props.theme.spacing.tiny2};
`;

export const AddIcon = styled(RoundedIcon)`
cursor: pointer;
margin-left: ${(props) => props.theme.spacing.tiny2};
`;

export const AddTokenButton = styled(Button).attrs((props) => ({
textStyle: {
fontWeight: props.theme.typography.bold.fontWeight,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
AccountDetailsContent,
AccountImageStyled,
AccountLabel,
AddIcon,
AddTokenButton,
DivList,
InfoIcon,
Expand All @@ -37,7 +38,7 @@ export const SideBarView = ({ address }: Props) => {
const [accountDetailsOpen, setAccountDetailsOpen] = useState(false);
const wallet = useAppSelector((state) => state.wallet);
const [addTokenOpen, setAddTokenOpen] = useState(false);
const { getStarkName } = useStarkNetSnap();
const { getStarkName, addNewAccount } = useStarkNetSnap();
const [starkName, setStarkName] = useState<string | undefined>(undefined);

const ref = useRef<HTMLDivElement>();
Expand Down Expand Up @@ -114,6 +115,7 @@ export const SideBarView = ({ address }: Props) => {
<RowDiv>
<InfoIcon onClick={() => setInfoModalOpen(true)}>i</InfoIcon>
<AccountAddress address={address} starkName={starkName} />
<AddIcon onClick={async () => await addNewAccount(chainId)}>+</AddIcon>
</RowDiv>
<DivList ref={ref as any}>
<AssetsList />
Expand Down
87 changes: 87 additions & 0 deletions packages/wallet-ui/src/services/useStarkNetSnap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@ export const useStarkNetSnap = () => {
}
};

// FIXME: this method has to rewrite when switch account enabled
// we should get the active account, instead of recovering all accounts
const getWalletData = async (chainId: string, networks?: Network[]) => {
if (!loader.isLoading && !networks) {
dispatch(enableLoadingWithMessage('Getting network data ...'));
Expand Down Expand Up @@ -302,10 +304,62 @@ export const useStarkNetSnap = () => {
dispatch(disableLoading());
};

// FIXME: this method has to replace getWalletData()
const initWalletData = async ({
account,
}: {
// TODO: we should allow the account to be optional
// and get the active account from the snap
account: Account;
}) => {
if (!loader.isLoading) {
dispatch(enableLoadingWithMessage('Getting network data ...'));
}

const { address, chainId } = account;

await setAccount(account);

await initTokensAndBalances(chainId, address);

dispatch(disableLoading());
};

const setAccount = async (account: Account) => {
const { upgradeRequired, deployRequired } = account;
dispatch(setAccounts(account));

// FIXME: hardcode to set the info modal visible,
// but it should only visible when the account is not deployed
dispatch(setInfoModalVisible(true));

dispatch(setUpgradeModalVisible(upgradeRequired));
dispatch(setDeployModalVisible(deployRequired));
};

const setErc20TokenBalance = (erc20TokenBalance: Erc20TokenBalance) => {
dispatch(setErc20TokenBalanceSelected(erc20TokenBalance));
};

const initTokensAndBalances = async (chainId: string, address: string) => {
const tokens = await getTokens(chainId);

// Get all tokens balance, USD value, and format them into Erc20TokenBalance type
const tokensWithBalances: Erc20TokenBalance[] = await Promise.all(
tokens.map(async (token) => {
const balance = await getTokenBalance(token.address, address, chainId);
const usdPrice = await getAssetPriceUSD(token);
return await getTokenBalanceWithDetails(balance, token, usdPrice);
}),
);

dispatch(setErc20TokenBalances(tokensWithBalances));

if (tokensWithBalances.length > 0) {
setErc20TokenBalance(tokensWithBalances[0]);
}
};

async function getPrivateKeyFromAddress(address: string, chainId: string) {
try {
await provider.request({
Expand Down Expand Up @@ -337,6 +391,9 @@ export const useStarkNetSnap = () => {
chainId: string,
transactionVersion?: typeof constants.TRANSACTION_VERSION.V3,
) {
console.log('contractCallData', contractCallData);
console.log('contractAddress', contractAddress);
console.log('address', address);
try {
const invocations: Invocations = [
{
Expand Down Expand Up @@ -974,6 +1031,35 @@ export const useStarkNetSnap = () => {
}
};

const addNewAccount = async (chainId: string) => {
dispatch(enableLoadingWithMessage('Adding new account...'));
try {
const account = (await provider.request({
method: 'wallet_invokeSnap',
params: {
snapId,
request: {
method: 'starkNet_addAccount',
params: {
chainId,
},
},
},
})) as Account;

await initWalletData({
account,
});

return account;
} catch (err: any) {
const toastr = new Toastr();
toastr.error(err.message as unknown as string);
} finally {
dispatch(disableLoading());
}
};

return {
connectToSnap,
getNetworks,
Expand Down Expand Up @@ -1004,6 +1090,7 @@ export const useStarkNetSnap = () => {
getCurrentNetwork,
getStarkName,
getAddrFromStarkName,
addNewAccount,
satisfiesVersion: oldVersionDetected,
};
};
Loading

0 comments on commit 8688436

Please sign in to comment.