Skip to content

Commit

Permalink
feat(tangle-dapp): Create useLsPoolJoinTx hook
Browse files Browse the repository at this point in the history
  • Loading branch information
yurixander committed Sep 23, 2024
1 parent fb89adc commit 0dfecdb
Show file tree
Hide file tree
Showing 22 changed files with 138 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,21 @@ import { FC } from 'react';
import { twMerge } from 'tailwind-merge';

import { LS_DERIVATIVE_TOKEN_PREFIX } from '../../../constants/liquidStaking/constants';
import { LsProtocolId, LsToken } from '../../../constants/liquidStaking/types';
import { LsToken } from '../../../constants/liquidStaking/types';
import { ExchangeRateType } from '../../../data/liquidStaking/useLsExchangeRate';
import useLsExchangeRate from '../../../data/liquidStaking/useLsExchangeRate';
import DetailItem from './DetailItem';

export type ExchangeRateDetailItemProps = {
type: ExchangeRateType;
token: LsToken;
protocolId: LsProtocolId;
};

const ExchangeRateDetailItem: FC<ExchangeRateDetailItemProps> = ({
type,
token,
protocolId,
}) => {
const { exchangeRate, isRefreshing } = useLsExchangeRate(type, protocolId);
const { exchangeRate, isRefreshing } = useLsExchangeRate(type);

const exchangeRateElement =
exchangeRate instanceof Error ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,29 @@ import { twMerge } from 'tailwind-merge';

import { EMPTY_VALUE_PLACEHOLDER } from '../../../constants';
import { LS_DERIVATIVE_TOKEN_PREFIX } from '../../../constants/liquidStaking/constants';
import {
LsNetworkId,
LsProtocolId,
} from '../../../constants/liquidStaking/types';
import { LsNetworkId } from '../../../constants/liquidStaking/types';
import formatBn from '../../../utils/formatBn';
import getLsProtocolDef from '../../../utils/liquidStaking/getLsProtocolDef';
import useLsAgnosticBalance from './useLsAgnosticBalance';
import { useLsStore } from '../../../data/liquidStaking/useLsStore';

export type LsAgnosticBalanceProps = {
isNative?: boolean;
protocolId: LsProtocolId;
tooltip?: string;
onlyShowTooltipWhenBalanceIsSet?: boolean;
onClick?: () => void;
};

const LsAgnosticBalance: FC<LsAgnosticBalanceProps> = ({
isNative = true,
protocolId,
tooltip,
onlyShowTooltipWhenBalanceIsSet = true,
onClick,
}) => {
const [isHovering, setIsHovering] = useState(false);
const { balance, isRefreshing } = useLsAgnosticBalance(isNative, protocolId);
const protocol = getLsProtocolDef(protocolId);
const { balance, isRefreshing } = useLsAgnosticBalance(isNative);
const { selectedProtocolId } = useLsStore();
const protocol = getLsProtocolDef(selectedProtocolId);

// Special case for liquid tokens on the `TgToken.sol` contract.
// See: https://github.com/webb-tools/tnt-core/blob/1f371959884352e7af68e6091c5bb330fcaa58b8/src/lst/liquidtoken/TgToken.sol#L26
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ import {
LsProtocolId,
LsSearchParamKey,
} from '../../../constants/liquidStaking/types';
import useLsPoolJoinTx from '../../../data/liquidStaking/tangle/useLsPoolJoinTx';
import useLsExchangeRate, {
ExchangeRateType,
} from '../../../data/liquidStaking/useLsExchangeRate';
import { useLsStore } from '../../../data/liquidStaking/useLsStore';
import useMintTx from '../../../data/liquidStaking/useMintTx';
import useMintTx from '../../../data/liquidStaking/parachain/useMintTx';
import useLiquifierDeposit from '../../../data/liquifier/useLiquifierDeposit';
import useActiveAccountAddress from '../../../hooks/useActiveAccountAddress';
import useSearchParamState from '../../../hooks/useSearchParamState';
Expand All @@ -51,10 +52,15 @@ const LsStakeCard: FC = () => {
stringify: (value) => value?.toString(),
});

const { selectedProtocolId, setSelectedProtocolId, selectedNetworkId } =
useLsStore();
const {
selectedProtocolId,
setSelectedProtocolId,
selectedNetworkId,
selectedPoolId,
} = useLsStore();

const { execute: executeMintTx, status: mintTxStatus } = useMintTx();
const { execute: executeTanglePoolJoinTx } = useLsPoolJoinTx();
const { execute: executeParachainMintTx, status: mintTxStatus } = useMintTx();
const performLiquifierDeposit = useLiquifierDeposit();
const activeAccountAddress = useActiveAccountAddress();

Expand Down Expand Up @@ -86,15 +92,17 @@ const LsStakeCard: FC = () => {
const {
exchangeRate: exchangeRateOrError,
isRefreshing: isRefreshingExchangeRate,
} = useLsExchangeRate(
ExchangeRateType.NativeToDerivative,
selectedProtocolId,
);
} = useLsExchangeRate(ExchangeRateType.NativeToDerivative);

// TODO: Properly handle the error state.
const exchangeRate =
exchangeRateOrError instanceof Error ? null : exchangeRateOrError;

const isTangleNetwork =
selectedNetworkId === LsNetworkId.TANGLE_LOCAL ||
selectedNetworkId === LsNetworkId.TANGLE_MAINNET ||
selectedNetworkId === LsNetworkId.TANGLE_TESTNET;

const handleStakeClick = useCallback(async () => {
// Not ready yet; no amount given.
if (fromAmount === null) {
Expand All @@ -103,9 +111,9 @@ const LsStakeCard: FC = () => {

if (
selectedProtocol.networkId === LsNetworkId.TANGLE_RESTAKING_PARACHAIN &&
executeMintTx !== null
executeParachainMintTx !== null
) {
executeMintTx({
executeParachainMintTx({
amount: fromAmount,
currency: selectedProtocol.currency,
});
Expand All @@ -114,8 +122,25 @@ const LsStakeCard: FC = () => {
performLiquifierDeposit !== null
) {
await performLiquifierDeposit(selectedProtocol.id, fromAmount);
} else if (
isTangleNetwork &&
executeTanglePoolJoinTx !== null &&
selectedPoolId !== null
) {
executeTanglePoolJoinTx({
amount: fromAmount,
poolId: selectedPoolId,
});
}
}, [executeMintTx, fromAmount, performLiquifierDeposit, selectedProtocol]);
}, [
executeParachainMintTx,
executeTanglePoolJoinTx,
fromAmount,
isTangleNetwork,
performLiquifierDeposit,
selectedProtocol,
selectedPoolId,
]);

const toAmount = useMemo(() => {
if (fromAmount === null || exchangeRate === null) {
Expand All @@ -128,13 +153,15 @@ const LsStakeCard: FC = () => {
const canCallStake =
(fromAmount !== null &&
selectedProtocol.networkId === LsNetworkId.TANGLE_RESTAKING_PARACHAIN &&
executeMintTx !== null) ||
executeParachainMintTx !== null) ||
(selectedProtocol.networkId === LsNetworkId.ETHEREUM_MAINNET_LIQUIFIER &&
performLiquifierDeposit !== null);
performLiquifierDeposit !== null) ||
(isTangleNetwork &&
executeTanglePoolJoinTx !== null &&
selectedPoolId !== null);

const walletBalance = (
<LsAgnosticBalance
protocolId={selectedProtocolId}
tooltip="Click to use all available balance"
onClick={() => {
if (maxSpendable !== null) {
Expand Down Expand Up @@ -187,7 +214,6 @@ const LsStakeCard: FC = () => {
<UnstakePeriodDetailItem protocolId={selectedProtocolId} />

<ExchangeRateDetailItem
protocolId={selectedProtocolId}
token={selectedProtocol.token}
type={ExchangeRateType.NativeToDerivative}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import useLsExchangeRate, {
ExchangeRateType,
} from '../../../data/liquidStaking/useLsExchangeRate';
import { useLsStore } from '../../../data/liquidStaking/useLsStore';
import useRedeemTx from '../../../data/liquidStaking/useRedeemTx';
import useRedeemTx from '../../../data/liquidStaking/parachain/useRedeemTx';
import useLiquifierUnlock from '../../../data/liquifier/useLiquifierUnlock';
import useActiveAccountAddress from '../../../hooks/useActiveAccountAddress';
import useSearchParamSync from '../../../hooks/useSearchParamSync';
Expand Down Expand Up @@ -80,10 +80,7 @@ const LsUnstakeCard: FC = () => {
const {
exchangeRate: exchangeRateOrError,
isRefreshing: isRefreshingExchangeRate,
} = useLsExchangeRate(
ExchangeRateType.DerivativeToNative,
selectedProtocol.id,
);
} = useLsExchangeRate(ExchangeRateType.DerivativeToNative);

// TODO: Properly handle the error state.
const exchangeRate =
Expand Down Expand Up @@ -159,7 +156,6 @@ const LsUnstakeCard: FC = () => {
const stakedWalletBalance = (
<LsAgnosticBalance
isNative={false}
protocolId={selectedProtocol.id}
tooltip="Click to use all staked balance"
onClick={() => setFromAmount(maxSpendable)}
/>
Expand Down Expand Up @@ -213,7 +209,6 @@ const LsUnstakeCard: FC = () => {
<UnstakePeriodDetailItem protocolId={selectedProtocolId} />

<ExchangeRateDetailItem
protocolId={selectedProtocolId}
token={selectedProtocol.token}
type={ExchangeRateType.DerivativeToNative}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,7 @@ const NetworkSelector: FC<NetworkSelectorProps> = ({

// Filter out networks that don't support liquid staking yet.
const supportedLsNetworks = LS_NETWORKS.filter((network) => {
// TODO: Check whether the restaking parachain supports liquid staking instead of hardcoding it.
if (network.id === LsNetworkId.TANGLE_RESTAKING_PARACHAIN) {
return true;
} else if (network.id === LsNetworkId.ETHEREUM_MAINNET_LIQUIFIER) {
if (network.id === LsNetworkId.ETHEREUM_MAINNET_LIQUIFIER) {
return true;
}
// Exclude the local Tangle network in production.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ const TotalDetailItem: FC<TotalDetailItemProps> = ({
isMinting
? ExchangeRateType.NativeToDerivative
: ExchangeRateType.DerivativeToNative,
protocolId,
);

const protocol = getLsProtocolDef(protocolId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,15 @@ import { erc20Abi } from 'viem';

import { EMPTY_VALUE_PLACEHOLDER } from '../../../constants';
import LIQUIFIER_TG_TOKEN_ABI from '../../../constants/liquidStaking/liquifierTgTokenAbi';
import {
LsNetworkId,
LsProtocolId,
} from '../../../constants/liquidStaking/types';
import { LsNetworkId } from '../../../constants/liquidStaking/types';
import useBalances from '../../../data/balances/useBalances';
import useParachainBalances from '../../../data/liquidStaking/useParachainBalances';
import useParachainBalances from '../../../data/liquidStaking/parachain/useParachainBalances';
import usePolling from '../../../data/liquidStaking/usePolling';
import useContractReadOnce from '../../../data/liquifier/useContractReadOnce';
import useActiveAccountAddress from '../../../hooks/useActiveAccountAddress';
import useEvmAddress20 from '../../../hooks/useEvmAddress';
import getLsProtocolDef from '../../../utils/liquidStaking/getLsProtocolDef';
import { useLsStore } from '../../../data/liquidStaking/useLsStore';

type BalanceUpdater = (
prevBalance: BN | null | typeof EMPTY_VALUE_PLACEHOLDER,
Expand Down Expand Up @@ -47,11 +45,12 @@ const createBalanceStateUpdater = (
};
};

const useLsAgnosticBalance = (isNative: boolean, protocolId: LsProtocolId) => {
const useLsAgnosticBalance = (isNative: boolean) => {
const activeAccountAddress = useActiveAccountAddress();
const evmAddress20 = useEvmAddress20();
const { nativeBalances, liquidBalances } = useParachainBalances();
const { free: tangleBalance } = useBalances();
const { free: tangleFreeBalance } = useBalances();
const { selectedProtocolId, selectedNetworkId } = useLsStore();

// TODO: Why not use the subscription hook variants (useContractRead) instead of manually utilizing usePolling?
const readErc20 = useContractReadOnce(erc20Abi);
Expand All @@ -63,7 +62,7 @@ const useLsAgnosticBalance = (isNative: boolean, protocolId: LsProtocolId) => {

const parachainBalances = isNative ? nativeBalances : liquidBalances;
const isAccountConnected = activeAccountAddress !== null;
const protocol = getLsProtocolDef(protocolId);
const protocol = getLsProtocolDef(selectedProtocolId);

// Reset balance to a placeholder when the active account is
// disconnected, and to a loading state once an account is
Expand All @@ -77,7 +76,7 @@ const useLsAgnosticBalance = (isNative: boolean, protocolId: LsProtocolId) => {
if (isAccountConnected) {
setBalance(null);
}
}, [isAccountConnected, isNative, protocolId]);
}, [isAccountConnected, isNative, selectedProtocolId]);

const erc20BalanceFetcher = useCallback(() => {
if (
Expand Down Expand Up @@ -132,18 +131,20 @@ const useLsAgnosticBalance = (isNative: boolean, protocolId: LsProtocolId) => {
setBalance(createBalanceStateUpdater(newBalance));
}, [parachainBalances, protocol.token, protocol.networkId]);

const isLsTangleNetwork =
selectedNetworkId === LsNetworkId.TANGLE_LOCAL ||
selectedNetworkId === LsNetworkId.TANGLE_MAINNET ||
selectedNetworkId === LsNetworkId.TANGLE_TESTNET;

// Update the balance to the Tangle balance when the Tangle
// network is the active network.
useEffect(() => {
if (
protocol.networkId !== LsNetworkId.TANGLE_MAINNET ||
tangleBalance === null
) {
if (!isLsTangleNetwork || tangleFreeBalance === null) {
return;
}

setBalance(createBalanceStateUpdater(tangleBalance));
}, [protocol.networkId, tangleBalance]);
setBalance(createBalanceStateUpdater(tangleFreeBalance));
}, [protocol.networkId, tangleFreeBalance, isLsTangleNetwork]);

return { balance, isRefreshing };
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
LsNetworkId,
LsProtocolId,
} from '../../../constants/liquidStaking/types';
import useParachainLsFees from '../../../data/liquidStaking/useParachainLsFees';
import useParachainLsFees from '../../../data/liquidStaking/parachain/useParachainLsFees';
import useContractRead from '../../../data/liquifier/useContractRead';
import { ContractReadOptions } from '../../../data/liquifier/useContractReadOnce';
import getLsProtocolDef from '../../../utils/liquidStaking/getLsProtocolDef';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const useLsSpendingLimits = (
isNative: boolean,
protocolId: LsProtocolId,
): LsSpendingLimits => {
const { balance } = useLsAgnosticBalance(isNative, protocolId);
const { balance } = useLsAgnosticBalance(isNative);

const { result: existentialDepositAmount } = useApi(
useCallback((api) => api.consts.balances.existentialDeposit, []),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ export const NetworkSelectorDropdown: FC<NetworkSelectorDropdownProps> = ({
}) => {
return (
<div className="flex flex-col items-center justify-between">
{/* Mainnet network */}
{/* Tangle Mainnet */}
<NetworkOption
isSelected={selectedNetwork?.id === TANGLE_MAINNET_NETWORK.id}
name={TANGLE_MAINNET_NETWORK.name}
onClick={() => onNetworkChange(TANGLE_MAINNET_NETWORK)}
/>

{/* Testnet network */}
{/* Tangle Testnet */}
<NetworkOption
isSelected={selectedNetwork?.id === TANGLE_TESTNET_NATIVE_NETWORK.id}
name={TANGLE_TESTNET_NATIVE_NETWORK.name}
Expand All @@ -46,7 +46,7 @@ export const NetworkSelectorDropdown: FC<NetworkSelectorDropdownProps> = ({

<hr className="w-full h-0 border-t border-mono-40 dark:border-mono-120" />

{/* Local dev network */}
{/* Tangle Local Dev */}
<NetworkOption
isSelected={selectedNetwork?.id === TANGLE_LOCAL_DEV_NETWORK.id}
name={TANGLE_LOCAL_DEV_NETWORK.name}
Expand Down
1 change: 1 addition & 0 deletions apps/tangle-dapp/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export enum TxName {
LS_LIQUIFIER_DEPOSIT = 'liquifier deposit',
LS_LIQUIFIER_UNLOCK = 'liquifier unlock',
LS_LIQUIFIER_WITHDRAW = 'liquifier withdraw',
LS_TANGLE_POOL_JOIN = 'join liquid staking pool',
}

export const PAYMENT_DESTINATION_OPTIONS: StakingRewardsDestinationDisplayText[] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import { Bytes } from '@polkadot/types';
import { BN } from '@polkadot/util';
import { TANGLE_RESTAKING_PARACHAIN_LOCAL_DEV_NETWORK } from '@webb-tools/webb-ui-components/constants/networks';

import { TxName } from '../../constants';
import { TxName } from '../../../constants';
import {
LsParachainCurrencyKey,
ParachainCurrency,
} from '../../constants/liquidStaking/types';
import { useSubstrateTxWithNotification } from '../../hooks/useSubstrateTx';
} from '../../../constants/liquidStaking/types';
import { useSubstrateTxWithNotification } from '../../../hooks/useSubstrateTx';

export type MintTxContext = {
amount: BN;
Expand Down
Loading

0 comments on commit 0dfecdb

Please sign in to comment.