Skip to content

Commit

Permalink
integrated transactions (#902)
Browse files Browse the repository at this point in the history
  • Loading branch information
Teja2045 authored Nov 27, 2023
2 parents 8c018d3 + 9305e6f commit 910cf96
Show file tree
Hide file tree
Showing 25 changed files with 388 additions and 144 deletions.
113 changes: 113 additions & 0 deletions frontend/src/app/(routes)/(overview)/overview-components/Asset.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { formatAmount, formatCoin, formatDollarAmount } from '@/utils/util';
import Link from 'next/link';
import React from 'react';
import Image from 'next/image';
import { useAppDispatch, useAppSelector } from '@/custom-hooks/StateHooks';
import { txWithdrawAllRewards } from '@/store/features/distribution/distributionSlice';
import useGetTxInputs from '@/custom-hooks/useGetTxInputs';
import { TxStatus } from '@/types/enums';
import { txRestake } from '@/store/features/staking/stakeSlice';
import { RootState } from '@/store/store';

const Asset = ({
asset,
showChainName,
}: {
asset: ParsedAsset;
showChainName: boolean;
}) => {
const txClaimStatus = useAppSelector(
(state: RootState) => state.distribution.chains[asset.chainID].tx.status
);
const txRestakeStatus = useAppSelector(
(state: RootState) => state.staking.chains[asset.chainID].reStakeTxStatus
);

const dispatch = useAppDispatch();
const { txWithdrawAllRewardsInputs, txRestakeInputs } = useGetTxInputs();

const claim = (chainID: string) => {
if (txClaimStatus === TxStatus.PENDING) {
alert('A claim transaction is already in pending...');
return;
}
const txInputs = txWithdrawAllRewardsInputs(chainID);
if (txInputs.msgs.length) dispatch(txWithdrawAllRewards(txInputs));
else alert('no delegations');
};

const claimAndStake = (chainID: string) => {
if (txRestakeStatus === TxStatus.PENDING) {
alert('A restake transaction is already pending...');
return;
}
const txInputs = txRestakeInputs(chainID);
if (txInputs.msgs.length) dispatch(txRestake(txInputs));
else alert('no rewards');
};

return (
<tr key={asset.chainID + asset.denom}>
<td>
<div>{formatCoin(asset.balance, asset.displayDenom)}</div>
{showChainName && (
<div className="text-xs text-[#a7a2b5] font-thin leading-[normal]">
on{' '}
<Link href={`/overview/${asset.chainName}`}>{asset.chainName}</Link>
</div>
)}
</td>
<td>
{asset.type === 'native'
? formatCoin(asset.staked, asset.displayDenom)
: '-'}
</td>
<td>
{asset.type === 'native'
? formatCoin(asset.rewards, asset.displayDenom)
: '-'}
</td>
<td>
<div className="flex gap-2" style={{ alignItems: 'flex-end' }}>
<div>{formatDollarAmount(asset.usdPrice)}</div>
<div className="flex">
<Image
src={`/${
asset.inflation >= 0 ? 'up' : 'down'
}-arrow-filled-icon.svg`}
height={16}
width={16}
alt="inflation change"
/>
<div className="text-[#E57575] text-[12px]">
{formatAmount(Math.abs(asset.inflation))}%
</div>
</div>
</div>
</td>
<td>
<div className="flex justify-between gap-1">
<div className="asset-action" onClick={() => claim(asset.chainID)}>
<Image src="/claim-icon.svg" height={16} width={16} alt="Claim" />
</div>
<div
className="asset-action"
onClick={() => claimAndStake(asset.chainID)}
>
<Image
src="/claim-stake-icon.svg"
height={16}
width={16}
alt="Claim and Stake"
/>
</div>
</div>
</td>
</tr>
);
};

export default Asset;
function txWithdrawAllRewardsInputs(chainID: string) {
throw new Error('Function not implemented.');
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { useAppSelector } from '@/custom-hooks/StateHooks';
import useSortedAssets from '@/custom-hooks/useSortedAssets';
import { formatAmount, formatCoin, formatDollarAmount } from '@/utils/util';
import Image from 'next/image';
import Link from 'next/link';
import React from 'react';
import Asset from './Asset';

const AssetsTable = ({ chainIDs }: { chainIDs: string[] }) => {
const [sortedAssets] = useSortedAssets(chainIDs);
Expand All @@ -13,6 +11,7 @@ const AssetsTable = ({ chainIDs }: { chainIDs: string[] }) => {
const delegationsLoading = useAppSelector(
(state) => state.staking.delegationsLoading > 0
);

return (
<>
{sortedAssets.length ? (
Expand All @@ -33,70 +32,7 @@ const AssetsTable = ({ chainIDs }: { chainIDs: string[] }) => {
</thead>
<tbody>
{sortedAssets.map((asset) => (
<tr key={asset.chainID + asset.denom}>
<td>
<div>{formatCoin(asset.balance, asset.displayDenom)}</div>
{chainIDs.length > 1 && (
<div className="text-xs text-[#a7a2b5] font-thin leading-[normal]">
on{' '}
<Link href={`/overview/${asset.chainName}`}>
{asset.chainName}
</Link>
</div>
)}
</td>
<td>
{asset.type === 'native'
? formatCoin(asset.staked, asset.displayDenom)
: '-'}
</td>
<td>
{asset.type === 'native'
? formatCoin(asset.rewards, asset.displayDenom)
: '-'}
</td>
<td>
<div
className="flex gap-2"
style={{ alignItems: 'flex-end' }}
>
<div>{formatDollarAmount(asset.usdPrice)}</div>
<div className="flex">
<Image
src={`/${
asset.inflation >= 0 ? 'up' : 'down'
}-arrow-filled-icon.svg`}
height={16}
width={16}
alt="inflation change"
/>
<div className="text-[#E57575] text-[12px]">
{formatAmount(Math.abs(asset.inflation))}%
</div>
</div>
</div>
</td>
<td>
<div className="flex justify-between gap-1">
<div className="asset-action">
<Image
src="/claim-icon.svg"
height={16}
width={16}
alt="Claim"
/>
</div>
<div className="asset-action">
<Image
src="/claim-stake-icon.svg"
height={16}
width={16}
alt="Claim and Stake"
/>
</div>
</div>
</td>
</tr>
<Asset asset={asset} showChainName={chainIDs.length > 1} />
))}
</tbody>
</table>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { formatDollarAmount } from '@/utils/util';
import Profile from './Profile';
import TransactionItem from './TransactionItem';
import { useAppSelector } from '@/custom-hooks/StateHooks';
import { RootState } from '@/store/store';

const History = ({ chainIDs }: { chainIDs: string[] }) => {
return (
Expand Down Expand Up @@ -76,16 +77,16 @@ const Balance = ({ chainIDs }: { chainIDs: string[] }) => {
};

const RecentTransactions = ({ chainIDs }: { chainIDs: string[] }) => {

/**
* Note: Currently, this implementation of recent transactions addresses scenarios involving either a single chain or all chains.
* If the system evolves to support multiple selected chains in the future,
* modifications to this logic will be necessary.
*/
const transactions = useAppSelector((state) =>
chainIDs.length == 1
? state.transactionHistory.chains[chainIDs[0]]
: state.transactionHistory.allTransactions
const transactions = useAppSelector(
(state:RootState) =>
(chainIDs.length == 1
? state.transactionHistory.chains[chainIDs[0]]
: state.transactionHistory.allTransactions) || []
);
return (
<div className="flex-1 overflow-y-scroll">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import PageAd from './PageAd';
import AssetsTable from './AssetsTable';
import AccountSummery from './AccountSummary';
import { getAccountInfo } from '@/store/features/auth/authSlice';
import { getDelegatorTotalRewards } from '@/store/features/distribution/distributionSlice';

const OverviewPage = ({ chainIDs }: { chainIDs: string[] }) => {
const dispatch = useAppDispatch();
Expand All @@ -25,6 +26,8 @@ const OverviewPage = ({ chainIDs }: { chainIDs: string[] }) => {
const allChainInfo = networks[chainID];
const chainInfo = allChainInfo.network;
const address = allChainInfo?.walletInfo?.bech32Address;
const minimalDenom =
allChainInfo.network.config.stakeCurrency.coinMinimalDenom;
const basicChainInputs = {
baseURL: chainInfo.config.rest,
address,
Expand All @@ -40,16 +43,14 @@ const OverviewPage = ({ chainIDs }: { chainIDs: string[] }) => {
})
);
dispatch(getAccountInfo(basicChainInputs));

// Todo: after distribution slice
// dispatch(
// getDelegatorTotalRewards({
// baseURL: chainInfo.config.rest,
// address: address,
// chainID: chainID,
// denom: denom,
// })
// );
dispatch(
getDelegatorTotalRewards({
baseURL: chainInfo.config.rest,
address: address,
chainID: chainID,
denom: minimalDenom,
})
);
});
}, []);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import Image from 'next/image';

const TransactionItem = ({ transaction }: { transaction: Transaction }) => {
const uiTx = formatTransaction(transaction);

return (
<div className="w-full flex gap-4">
<div className="flex gap-2 min-w-[88px]">
<div className="flex gap-2 min-w-[88px] max-w-[88px]">
<div className="space-y-4">
<div className="ml-auto text-right text-[12px]">{uiTx.time}</div>
<div className="ml-auto text-right text-[12px] max-w-[68px]">{uiTx.time}</div>
<Image
className="ml-auto"
src="/back-arrow.svg"
Expand All @@ -27,7 +27,7 @@ const TransactionItem = ({ transaction }: { transaction: Transaction }) => {
<div className="space-y-2">
<div className="formatted-text-1">{uiTx.firstMessage}</div>
<div className="flex gap-2">
<Image width={20} height={20} alt="success" src="round-checked.svg" />
<Image width={20} height={20} alt="success" src="/round-checked.svg" />
<div className="text-xs not-italic font-normal leading-4 tracking-[0.48px]">
{uiTx.isTxSuccess ? 'Transaction Successful' : 'Transaction Failed'}
</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/(routes)/(overview)/overview.css
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
}

.asset-action {
@apply w-8 h-8 rounded-lg flex justify-center items-center;
@apply w-8 h-8 rounded-lg flex justify-center items-center cursor-pointer;
background: linear-gradient(180deg,
rgba(74, 162, 156, 0.8) 0%,
rgba(139, 61, 167, 0.8) 100%),
Expand Down
7 changes: 0 additions & 7 deletions frontend/src/custom-hooks/useConvertToDollars.ts

This file was deleted.

40 changes: 20 additions & 20 deletions frontend/src/custom-hooks/useGetAssetsAmount.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { RootState } from '@/store/store';
import { useCallback, useMemo } from 'react';
import { useMemo } from 'react';
import { useAppSelector } from './StateHooks';
import { parseBalance } from '@/utils/denom';
import { getIBCBalances } from '@/utils/ibc';
import useGetChainInfo from './useGetChainInfo';

const useGetAssetsAmount = (chainIDs: string[]) => {
const stakingChains = useAppSelector(
Expand All @@ -12,26 +13,14 @@ const useGetAssetsAmount = (chainIDs: string[]) => {
const balanceChains = useAppSelector(
(state: RootState) => state.bank.balances
);
const rewardsChains = useAppSelector(
(state: RootState) => state.distribution.chains
);
const tokensPriceInfo = useAppSelector(
(state) => state.common.allTokensInfoState.info
);

const getDenomInfo = useCallback(
(
chainID: string
): { minimalDenom: string; decimals: number; chainName: string } => {
const config = networks?.[chainID]?.network?.config;
const currency = config?.currencies?.[0];
const chainName = config?.chainName.toLowerCase();

return {
minimalDenom: currency.coinMinimalDenom,
decimals: currency.coinDecimals || 0,
chainName,
};
},
[networks]
);
const { getDenomInfo } = useGetChainInfo();

// calculates staked amount in usd
const totalStakedAmount = useMemo(() => {
Expand Down Expand Up @@ -91,9 +80,20 @@ const useGetAssetsAmount = (chainIDs: string[]) => {

// calculates rewards amount in usd
const rewardsAmount = useMemo(() => {
// Todo: implement distribution slice
return 0;
}, []);
let totalRewardsAmount = 0;
chainIDs.forEach((chainID) => {
const rewards =
rewardsChains?.[chainID]?.delegatorRewards?.totalRewards || 0;
if (rewards > 0) {
const { decimals, minimalDenom } = getDenomInfo(chainID);
const usdPriceInfo: TokenInfo | undefined =
tokensPriceInfo?.[minimalDenom]?.info;
const usdDenomPrice = usdPriceInfo?.usd || 0;
totalRewardsAmount += (rewards / 10 ** decimals) * usdDenomPrice;
}
});
return totalRewardsAmount;
}, [chainIDs, rewardsChains, getDenomInfo, tokensPriceInfo]);

return [totalStakedAmount, availableAmount, rewardsAmount];
};
Expand Down
Loading

0 comments on commit 910cf96

Please sign in to comment.