From d1a0977a655e0069fff2245efe8f88a749979e85 Mon Sep 17 00:00:00 2001 From: Arjun Porwal <65214523+ap211unitech@users.noreply.github.com> Date: Tue, 25 Feb 2025 19:07:12 +0530 Subject: [PATCH] feat: max transfer value while teleport (#11332) --- packages/page-parachains/src/Teleport.tsx | 55 +++++++++++++++++-- .../react-components/src/InputBalance.tsx | 2 +- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/packages/page-parachains/src/Teleport.tsx b/packages/page-parachains/src/Teleport.tsx index f440ba56bb..2dfd74ecdb 100644 --- a/packages/page-parachains/src/Teleport.tsx +++ b/packages/page-parachains/src/Teleport.tsx @@ -2,16 +2,17 @@ // SPDX-License-Identifier: Apache-2.0 import type { SubmittableExtrinsicFunction } from '@polkadot/api/types'; +import type { DeriveBalancesAll } from '@polkadot/api-derive/types'; import type { LinkOption } from '@polkadot/apps-config/endpoints/types'; import type { Option } from '@polkadot/apps-config/settings/types'; import type { BN } from '@polkadot/util'; -import React, { useMemo, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; -import { ChainImg, Dropdown, InputAddress, InputBalance, MarkWarning, Modal, TxButton } from '@polkadot/react-components'; -import { useApi, useApiUrl, useTeleport } from '@polkadot/react-hooks'; -import { Available } from '@polkadot/react-query'; -import { BN_ZERO, isFunction } from '@polkadot/util'; +import { ChainImg, Dropdown, InputAddress, InputBalance, MarkWarning, Modal, styled, TxButton } from '@polkadot/react-components'; +import { useApi, useApiUrl, useCall, useTeleport } from '@polkadot/react-hooks'; +import { Available, FormatBalance } from '@polkadot/react-query'; +import { BN_HUNDRED, BN_ZERO, isFunction, nextTick } from '@polkadot/util'; import { useTranslation } from './translate.js'; @@ -48,6 +49,8 @@ function Teleport ({ onClose }: Props): React.ReactElement | null { const [senderId, setSenderId] = useState(null); const [recipientParaId, setParaId] = useState(INVALID_PARAID); const { allowTeleport, destinations, isParaTeleport, oneWay } = useTeleport(); + const balances = useCall(api.derive.balances?.all, [senderId]); + const [maxTransfer, setMaxTransfer] = useState(null); const call = useMemo( (): SubmittableExtrinsicFunction<'promise'> => { @@ -125,7 +128,31 @@ function Teleport ({ onClose }: Props): React.ReactElement | null { [api, amount, isParaTeleport, recipientId, recipientParaId] ); - const hasAvailable = !!amount; + const hasAvailable = !!amount && (maxTransfer ? amount.lte(maxTransfer) : true); + + useEffect(() => { + if (balances && balances.accountId.eq(senderId) && senderId && recipientId && api.call.transactionPaymentApi && api.tx.balances) { + nextTick(async (): Promise => { + try { + const extrinsic = call(...params); + const { partialFee } = await extrinsic.paymentInfo(senderId); + + const adjFee = partialFee.muln(110).div(BN_HUNDRED); + const maxTransfer = (balances.transferable || balances.availableBalance).sub(adjFee); + + setMaxTransfer( + api.consts.balances && maxTransfer.gt(api.consts.balances.existentialDeposit) + ? maxTransfer.sub(api.consts.balances.existentialDeposit) + : null + ); + } catch (error) { + console.error(error); + } + }); + } else { + setMaxTransfer(null); + } + }, [api.call.transactionPaymentApi, api.consts.balances, api.tx.balances, balances, call, params, recipientId, senderId]); return ( | null { label={t('amount')} onChange={setAmount} /> + {maxTransfer && + + Max - + + } | null { } export default React.memo(Teleport); + +const StyledInfo = styled.p` + align-items: center; + display: flex; + font-size: var(--font-size-small); + gap: 3px; + justify-content: flex-end; + span:first-of-type { + font-weight: var(--font-weight-bold); + } +`; diff --git a/packages/react-components/src/InputBalance.tsx b/packages/react-components/src/InputBalance.tsx index f1f15a8cf5..60013cc6f5 100644 --- a/packages/react-components/src/InputBalance.tsx +++ b/packages/react-components/src/InputBalance.tsx @@ -95,7 +95,7 @@ function InputBalance ({ autoFocus, children, className = '', defaultValue: inDe labelExtra={ {labelExtra} - {!!si && (siSymbol || TokenUnit.abbr) && + {!!si && (siSymbol || TokenUnit.abbr) && !isDisabled &&

{t('(enter value in standard units)')}