From b22be39953fdf35eb68af710d559348a7776ccda Mon Sep 17 00:00:00 2001 From: S2kael Date: Wed, 21 Feb 2024 12:22:29 +0700 Subject: [PATCH 1/8] [Issue-2628] Adjust showing/validating address on Send fund, Send NFT --- .../src/services/transaction-service/index.ts | 4 ++-- .../variants/Transaction/variants/SendNft.tsx | 1 + .../Transaction/variants/TransferBlock.tsx | 10 +++++++++ .../Popup/Transaction/variants/SendFund.tsx | 22 +++++++++++++++---- .../Popup/Transaction/variants/SendNFT.tsx | 21 ++++++++++++++---- .../Modal/AddressBook/AddressBookModal.tsx | 6 +++-- 6 files changed, 52 insertions(+), 12 deletions(-) diff --git a/packages/extension-base/src/services/transaction-service/index.ts b/packages/extension-base/src/services/transaction-service/index.ts index 625ae52350..193b341df0 100644 --- a/packages/extension-base/src/services/transaction-service/index.ts +++ b/packages/extension-base/src/services/transaction-service/index.ts @@ -404,6 +404,7 @@ export default class TransactionService { const transaction = this.getTransaction(id); const extrinsicType = transaction.extrinsicType; + const chainInfo = this.state.chainService.getChainInfoByKey(transaction.chain); const formattedTransactionAddress = reformatAddress(transaction.address); const historyItem: TransactionHistoryItem = { @@ -411,7 +412,7 @@ export default class TransactionService { chain: transaction.chain, direction: TransactionDirection.SEND, type: transaction.extrinsicType, - from: formattedTransactionAddress, + from: transaction.address, to: '', chainType: transaction.chainType, address: formattedTransactionAddress, @@ -426,7 +427,6 @@ export default class TransactionService { startBlock: startBlock || 0 }; - const chainInfo = this.state.chainService.getChainInfoByKey(transaction.chain); const nativeAsset = _getChainNativeTokenBasicInfo(chainInfo); const baseNativeAmount = { value: '0', decimals: nativeAsset.decimals, symbol: nativeAsset.symbol }; diff --git a/packages/extension-koni-ui/src/Popup/Confirmations/variants/Transaction/variants/SendNft.tsx b/packages/extension-koni-ui/src/Popup/Confirmations/variants/Transaction/variants/SendNft.tsx index db6bc6ec9a..d5db45d4e2 100644 --- a/packages/extension-koni-ui/src/Popup/Confirmations/variants/Transaction/variants/SendNft.tsx +++ b/packages/extension-koni-ui/src/Popup/Confirmations/variants/Transaction/variants/SendNft.tsx @@ -34,6 +34,7 @@ const Component: React.FC = (props: Props) => { = ({ className, transaction }: Props) => { [chainInfoMap, transaction.chain] ); + const receiveChain = useMemo(() => { + if (xcmData) { + return xcmData.destinationNetworkKey || transaction.chain; + } else { + return transaction.chain; + } + }, [transaction.chain, xcmData]); + const { decimals: chainDecimals, symbol: chainSymbol } = useGetNativeTokenBasicInfo(transaction.chain); const senderPrefix = useGetChainPrefixBySlug(transaction.chain); + const receiverPrefix = useGetChainPrefixBySlug(receiveChain); return ( <> @@ -54,6 +63,7 @@ const Component: React.FC = ({ className, transaction }: Props) => { { diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx index 5145ed2f54..f0427a0df7 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx @@ -18,7 +18,7 @@ import { useIsMantaPayEnabled } from '@subwallet/extension-koni-ui/hooks/account import { getMaxTransfer, makeCrossChainTransfer, makeTransfer } from '@subwallet/extension-koni-ui/messaging'; import { RootState } from '@subwallet/extension-koni-ui/stores'; import { ChainItemType, FormCallbacks, Theme, ThemeProps, TransferParams } from '@subwallet/extension-koni-ui/types'; -import { findAccountByAddress, formatBalance, isAccountAll, noop } from '@subwallet/extension-koni-ui/utils'; +import { findAccountByAddress, formatBalance, isAccountAll, noop, reformatAddress } from '@subwallet/extension-koni-ui/utils'; import { findNetworkJsonByGenesisHash } from '@subwallet/extension-koni-ui/utils/chain/getNetworkJsonByGenesisHash'; import { Button, Form, Icon } from '@subwallet/react-ui'; import { Rule } from '@subwallet/react-ui/es/form'; @@ -325,6 +325,16 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => { return Promise.resolve(); } + if (!isEthereumAddress(_recipientAddress)) { + const destChainInfo = chainInfoMap[destChain]; + const addressPrefix = destChainInfo?.substrateInfo?.addressPrefix ?? 42; + const _addressOnChain = reformatAddress(_recipientAddress, addressPrefix); + + if (_addressOnChain !== _recipientAddress) { + return Promise.reject(t('Recipient should be a valid {{networkName}} address', { replace: { networkName: destChainInfo.name } })); + } + } + const isOnChain = chain === destChain; const account = findAccountByAddress(accounts, _recipientAddress); @@ -442,11 +452,11 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => { // Submit transaction const onSubmit: FormCallbacks['onFinish'] = useCallback((values: TransferParams) => { setLoading(true); - const { asset, chain, destChain, from, to, value } = values; + const { asset, chain, destChain, from: _from, to, value } = values; let sendPromise: Promise; - const account = findAccountByAddress(accounts, from); + const account = findAccountByAddress(accounts, _from); if (!account) { setLoading(false); @@ -458,6 +468,10 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => { return; } + const chainInfo = chainInfoMap[chain]; + const addressPrefix = chainInfo?.substrateInfo?.addressPrefix ?? 42; + const from = reformatAddress(_from, addressPrefix); + const isLedger = !!account.isHardware; const isEthereum = isEthereumAddress(account.address); const chainAsset = assetRegistry[asset]; @@ -519,7 +533,7 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => { }) ; }, 300); - }, [accounts, assetRegistry, notification, t, isTransferAll, onSuccess, onError]); + }, [accounts, chainInfoMap, assetRegistry, notification, t, isTransferAll, onSuccess, onError]); const onFilterAccountFunc = useMemo(() => filterAccountFunc(chainInfoMap, assetRegistry, multiChainAssetMap, sendFundSlug), [assetRegistry, chainInfoMap, multiChainAssetMap, sendFundSlug]); diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendNFT.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendNFT.tsx index 99f6bb0fc8..c5cfcf9c8e 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendNFT.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendNFT.tsx @@ -10,7 +10,7 @@ import { DataContext } from '@subwallet/extension-koni-ui/contexts/DataContext'; import { useFocusFormItem, useGetChainPrefixBySlug, useHandleSubmitTransaction, useInitValidateTransaction, usePreCheckAction, useRestoreTransaction, useSelector, useSetCurrentPage, useTransactionContext, useWatchTransaction } from '@subwallet/extension-koni-ui/hooks'; import { evmNftSubmitTransaction, substrateNftSubmitTransaction } from '@subwallet/extension-koni-ui/messaging'; import { FormCallbacks, FormFieldData, FormInstance, FormRule, SendNftParams, ThemeProps } from '@subwallet/extension-koni-ui/types'; -import { findAccountByAddress, noop, simpleCheckForm } from '@subwallet/extension-koni-ui/utils'; +import { findAccountByAddress, noop, reformatAddress, simpleCheckForm } from '@subwallet/extension-koni-ui/utils'; import { Button, Form, Icon, Image, Typography } from '@subwallet/react-ui'; import CN from 'classnames'; import { ArrowCircleRight } from 'phosphor-react'; @@ -103,6 +103,16 @@ const Component: React.FC = () => { return Promise.reject(t('Invalid recipient address')); } + if (!isEthereumAddress(_recipientAddress)) { + const chainInfo = chainInfoMap[chain]; + const addressPrefix = chainInfo?.substrateInfo?.addressPrefix ?? 42; + const _addressOnChain = reformatAddress(_recipientAddress, addressPrefix); + + if (_addressOnChain !== _recipientAddress) { + return Promise.reject(t('Recipient should be a valid {{networkName}} address', { replace: { networkName: chainInfo.name } })); + } + } + if (isSameAddress(_recipientAddress, from)) { return Promise.reject(t('The recipient address can not be the same as the sender address')); } @@ -141,8 +151,11 @@ const Component: React.FC = () => { // Submit transaction const onSubmit: FormCallbacks['onFinish'] = useCallback( (values: SendNftParams) => { - const isEthereumInterface = isEthereumAddress(from); - const { to } = values; + const { chain, from: _from, to } = values; + const isEthereumInterface = isEthereumAddress(_from); + + const from = reformatAddress(_from, addressPrefix); + const params = nftParamsHandler(nftItem, chain); let sendPromise: Promise; @@ -180,7 +193,7 @@ const Component: React.FC = () => { }); }, 300); }, - [chain, from, nftItem, onError, onSuccess] + [nftItem, onError, onSuccess, addressPrefix] ); const checkAction = usePreCheckAction(from); diff --git a/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx b/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx index e23d22d1f8..e7b67cec53 100644 --- a/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx @@ -144,11 +144,13 @@ const Component: React.FC = (props: Props) => { const onSelectItem = useCallback((item: AccountItem) => { return () => { + const address = reformatAddress(item.address, addressPrefix); + inactiveModal(id); - onSelect(item.address); + onSelect(address); onResetFilter(); }; - }, [id, inactiveModal, onResetFilter, onSelect]); + }, [addressPrefix, id, inactiveModal, onResetFilter, onSelect]); const renderItem = useCallback((item: AccountItem) => { const address = formatAddress(item); From e14ebb0fb8dfce5bcfffd25ac35e901d54d5a00a Mon Sep 17 00:00:00 2001 From: S2kael Date: Thu, 22 Feb 2024 14:56:19 +0700 Subject: [PATCH 2/8] [Issue-2628] Update filter for address book modal --- .../src/background/KoniTypes.ts | 1 + .../extension-base/src/background/types.ts | 1 + .../src/koni/background/handlers/Extension.ts | 38 +++++++++++++++++-- .../src/components/Field/AddressInput.tsx | 12 ++++-- .../Modal/AddressBook/AddressBookModal.tsx | 23 ++++++++--- .../src/messaging/accounts/addressBook.ts | 4 +- 6 files changed, 64 insertions(+), 15 deletions(-) diff --git a/packages/extension-base/src/background/KoniTypes.ts b/packages/extension-base/src/background/KoniTypes.ts index a0fc379448..5fa3cd5c7b 100644 --- a/packages/extension-base/src/background/KoniTypes.ts +++ b/packages/extension-base/src/background/KoniTypes.ts @@ -1195,6 +1195,7 @@ export interface RequestTransferExistentialDeposit { export interface RequestSaveRecentAccount { accountId: string; + chain?: string; } export interface SubstrateNftTransaction { diff --git a/packages/extension-base/src/background/types.ts b/packages/extension-base/src/background/types.ts index 36cd9942a2..43059bb9ca 100644 --- a/packages/extension-base/src/background/types.ts +++ b/packages/extension-base/src/background/types.ts @@ -59,6 +59,7 @@ export interface AccountJson extends AbstractAddressJson { export interface AddressJson extends AbstractAddressJson { isRecent?: boolean; + recentChainSlugs?: string[]; } // all Accounts and the address of the current Account diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index 3bd27cca42..a59b48cc03 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -35,6 +35,7 @@ import { SWTransaction, SWTransactionResponse, SWTransactionResult, TransactionE import { WALLET_CONNECT_EIP155_NAMESPACE } from '@subwallet/extension-base/services/wallet-connect-service/constants'; import { isProposalExpired, isSupportWalletConnectChain, isSupportWalletConnectNamespace } from '@subwallet/extension-base/services/wallet-connect-service/helpers'; import { ResultApproveWalletConnectSession, WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; +import { AccountsStore } from '@subwallet/extension-base/stores'; import { BalanceJson, BuyServiceInfo, BuyTokenInfo, EarningRewardJson, NominationPoolInfo, OptimalYieldPathParams, RequestEarlyValidateYield, RequestGetYieldPoolTargets, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseGetYieldPoolTargets, ValidateYieldProcessParams, YieldPoolType } from '@subwallet/extension-base/types'; import { convertSubjectInfoToAddresses, isSameAddress, reformatAddress, uniqueStringArray } from '@subwallet/extension-base/utils'; import { calculateGasFeeParams, createTransactionFromRLP, signatureToHex, Transaction as QrTransaction } from '@subwallet/extension-base/utils/eth'; @@ -45,7 +46,7 @@ import { createPair } from '@subwallet/keyring'; import { KeyringPair, KeyringPair$Json, KeyringPair$Meta } from '@subwallet/keyring/types'; import { keyring } from '@subwallet/ui-keyring'; import { SubjectInfo } from '@subwallet/ui-keyring/observable/types'; -import { KeyringAddress } from '@subwallet/ui-keyring/types'; +import { KeyringAddress, KeyringJson$Meta } from '@subwallet/ui-keyring/types'; import { ProposalTypes } from '@walletconnect/types/dist/types/sign-client/proposal'; import { SessionTypes } from '@walletconnect/types/dist/types/sign-client/session'; import { getSdkError } from '@walletconnect/utils'; @@ -542,13 +543,42 @@ export default class KoniExtension { }; } - private saveRecentAccount ({ accountId }: RequestSaveRecentAccount): KeyringAddress { + private saveRecentAccount ({ accountId, chain }: RequestSaveRecentAccount): KeyringAddress { if (isAddress((accountId))) { const address = reformatAddress(accountId); const account = keyring.getAccount(address); - const contact = keyring.getAddress(address); + const contact = keyring.getAddress(address, 'address'); + const recent = keyring.getAddress(address, 'address'); - return account || contact || { ...keyring.saveRecent(address).json, publicKey: decodeAddress(address) }; + if (account) { + return account; + } else if (contact) { + return contact; + } else { + let metadata: KeyringJson$Meta; + + if (recent) { + metadata = recent.meta; + } else { + const _new = keyring.saveRecent(address); + + metadata = _new.json.meta; + } + + const recentChainSlugs: string[] = (metadata.recentChainSlugs as string[]) || []; + + if (chain) { + if (!recentChainSlugs.includes(chain)) { + recentChainSlugs.push(chain); + } + } + + metadata.recentChainSlugs = recentChainSlugs; + + const result = keyring.addresses.add(new AccountsStore(), address, { address: address, meta: metadata }); + + return { ...result.json, publicKey: decodeAddress(address) }; + } } else { throw Error(t('This is not an address')); } diff --git a/packages/extension-koni-ui/src/components/Field/AddressInput.tsx b/packages/extension-koni-ui/src/components/Field/AddressInput.tsx index 2a05683629..e98cce058f 100644 --- a/packages/extension-koni-ui/src/components/Field/AddressInput.tsx +++ b/packages/extension-koni-ui/src/components/Field/AddressInput.tsx @@ -16,7 +16,7 @@ import { Book, Scan } from 'phosphor-react'; import React, { ChangeEventHandler, ForwardedRef, forwardRef, SyntheticEvent, useCallback, useContext, useEffect, useMemo, useState } from 'react'; import styled from 'styled-components'; -import { isAddress, isEthereumAddress } from '@polkadot/util-crypto'; +import { decodeAddress, isAddress, isEthereumAddress } from '@polkadot/util-crypto'; import { Avatar } from '../Avatar'; import { QrScannerErrorNotice } from '../Qr'; @@ -90,9 +90,15 @@ function Component (props: Props, ref: ForwardedRef): React.ReactEleme !skipClearDomainName && setDomainName(undefined); if (isAddress(val) && saveAddress) { - saveRecentAccount(val).catch(console.error); + if (isEthereumAddress(val)) { + saveRecentAccount(val, chain).catch(console.error); + } else { + if (decodeAddress(val, false, addressPrefix)) { + saveRecentAccount(val, chain).catch(console.error); + } + } } - }, [onChange, saveAddress]); + }, [onChange, saveAddress, chain, addressPrefix]); const _onChange: ChangeEventHandler = useCallback((event) => { parseAndChangeValue(event.target.value); diff --git a/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx b/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx index e7b67cec53..1dc6090221 100644 --- a/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx @@ -2,9 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 import { AbstractAddressJson, AccountJson } from '@subwallet/extension-base/background/types'; -import { isSameAddress } from '@subwallet/extension-base/utils'; import { BackIcon } from '@subwallet/extension-koni-ui/components'; -import { useFilterModal, useFormatAddress, useSelector } from '@subwallet/extension-koni-ui/hooks'; +import { useFilterModal, useFormatAddress, useGetChainInfoByGenesisHash, useSelector } from '@subwallet/extension-koni-ui/hooks'; import { ThemeProps } from '@subwallet/extension-koni-ui/types'; import { funcSortByName, isAccountAll, reformatAddress, toShort } from '@subwallet/extension-koni-ui/utils'; import { Badge, Icon, ModalContext, SwList, SwModal } from '@subwallet/react-ui'; @@ -76,6 +75,8 @@ const Component: React.FC = (props: Props) => { const { accounts, contacts, recent } = useSelector((state) => state.accountState); const formatAddress = useFormatAddress(addressPrefix); + const chainInfo = useGetChainInfoByGenesisHash(networkGenesisHash); + const chain = chainInfo?.slug || ''; const filterModal = useMemo(() => `${id}-filter-modal`, [id]); @@ -102,9 +103,13 @@ const Component: React.FC = (props: Props) => { const result: AccountItem[] = []; (!selectedFilters.length || selectedFilters.includes(AccountGroup.RECENT)) && recent.forEach((acc) => { - const address = isAddress(acc.address) ? reformatAddress(acc.address) : acc.address; + const chains = acc.recentChainSlugs || []; + + if (chains.includes(chain)) { + const address = isAddress(acc.address) ? reformatAddress(acc.address) : acc.address; - result.push({ ...acc, address: address, group: AccountGroup.RECENT }); + result.push({ ...acc, address: address, group: AccountGroup.RECENT }); + } }); (!selectedFilters.length || selectedFilters.includes(AccountGroup.CONTACT)) && contacts.forEach((acc) => { @@ -124,7 +129,7 @@ const Component: React.FC = (props: Props) => { return result .sort(funcSortByName) .sort((a, b) => getGroupPriority(b) - getGroupPriority(a)); - }, [accounts, contacts, networkGenesisHash, recent, selectedFilters]); + }, [accounts, chain, contacts, networkGenesisHash, recent, selectedFilters]); const searchFunction = useCallback((item: AccountItem, searchText: string) => { const searchTextLowerCase = searchText.toLowerCase(); @@ -154,7 +159,13 @@ const Component: React.FC = (props: Props) => { const renderItem = useCallback((item: AccountItem) => { const address = formatAddress(item); - const selected = value ? isSameAddress(address, value) : false; + let selected: boolean; + + if (isEthereumAddress(value)) { + selected = value.toLowerCase() === address.toLowerCase(); + } else { + selected = value === address; + } return ( { - return sendMessage('pri(accounts.saveRecent)', { accountId }); +export async function saveRecentAccount (accountId: string, chain?: string): Promise { + return sendMessage('pri(accounts.saveRecent)', { accountId, chain }); } export async function editContactAddress (address: string, name: string): Promise { From 5e1163f9725e1b9c9b0fffbaaafece77d958d388 Mon Sep 17 00:00:00 2001 From: S2kael Date: Thu, 22 Feb 2024 15:34:29 +0700 Subject: [PATCH 3/8] [Issue-2628] Update auto change address value for wallet's account --- .../src/components/Field/AddressInput.tsx | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/extension-koni-ui/src/components/Field/AddressInput.tsx b/packages/extension-koni-ui/src/components/Field/AddressInput.tsx index e98cce058f..d2ad1e99cb 100644 --- a/packages/extension-koni-ui/src/components/Field/AddressInput.tsx +++ b/packages/extension-koni-ui/src/components/Field/AddressInput.tsx @@ -98,7 +98,8 @@ function Component (props: Props, ref: ForwardedRef): React.ReactEleme } } } - }, [onChange, saveAddress, chain, addressPrefix]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [saveAddress, chain, addressPrefix]); const _onChange: ChangeEventHandler = useCallback((event) => { parseAndChangeValue(event.target.value); @@ -173,6 +174,28 @@ function Component (props: Props, ref: ForwardedRef): React.ReactEleme } }, [allowDomain, chain, inputRef, parseAndChangeValue, value]); + useEffect(() => { + if (value) { + const account = findContactByAddress(_contacts, value); + + if (account) { + if (!isEthereumAddress(account.address) && !!account.isHardware) { + const availableGens: string[] = (account.availableGenesisHashes as string[]) || []; + + if (!availableGens.includes(networkGenesisHash || '')) { + return; + } + } + + const address = reformatAddress(account.address, addressPrefix); + + parseAndChangeValue(address); + inputRef?.current?.focus(); + inputRef?.current?.blur(); + } + } + }, [_contacts, addressPrefix, value, parseAndChangeValue, inputRef, networkGenesisHash]); + // todo: Will work with "Manage address book" feature later return ( <> From 4718f1e225d1bf939842481730a340befdf3a573 Mon Sep 17 00:00:00 2001 From: S2kael Date: Thu, 22 Feb 2024 17:32:49 +0700 Subject: [PATCH 4/8] [Issue-2617] Update balance formatter for show min amount when validate transfer action --- .../extension-base/src/koni/background/handlers/Extension.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index a59b48cc03..3fde220b38 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -1765,7 +1765,7 @@ export default class KoniExtension { if (new BigN(receiverBalance).plus(transferAmount.value).lt(minAmount)) { const atLeast = new BigN(minAmount).minus(receiverBalance).plus((tokenInfo.decimals || 0) === 0 ? 0 : 1); - const atLeastStr = formatNumber(atLeast, tokenInfo.decimals || 0, balanceFormatter); + const atLeastStr = formatNumber(atLeast, tokenInfo.decimals || 0, balanceFormatter, { maxNumberFormat: tokenInfo.decimals || 6 }); inputTransaction.errors.push(new TransactionError(TransferTxErrorType.RECEIVER_NOT_ENOUGH_EXISTENTIAL_DEPOSIT, t('You must transfer at least {{amount}} {{symbol}} to keep the destination account alive', { replace: { amount: atLeastStr, symbol: tokenInfo.symbol } }))); } @@ -1838,7 +1838,7 @@ export default class KoniExtension { // Check ed for receiver if (new BigN(value).lt(atLeast)) { - const atLeastStr = formatNumber(atLeast, destinationTokenInfo.decimals || 0, balanceFormatter); + const atLeastStr = formatNumber(atLeast, destinationTokenInfo.decimals || 0, balanceFormatter, { maxNumberFormat: destinationTokenInfo.decimals || 6 }); inputTransaction.errors.push(new TransactionError(TransferTxErrorType.RECEIVER_NOT_ENOUGH_EXISTENTIAL_DEPOSIT, t('You must transfer at least {{amount}} {{symbol}} to keep the destination account alive', { replace: { amount: atLeastStr, symbol: originTokenInfo.symbol } }))); } From 0ad081bb9bdfffbc2838adf714fd9df054db2790 Mon Sep 17 00:00:00 2001 From: S2kael Date: Fri, 23 Feb 2024 10:32:54 +0700 Subject: [PATCH 5/8] [Issue-2617] Update UI --- .../src/koni/background/handlers/Extension.ts | 11 ++++++----- .../Popup/Transaction/variants/SendFund.tsx | 1 + .../Popup/Transaction/variants/SendNFT.tsx | 1 + .../Account/Item/AccountItemWithName.tsx | 19 ++++++++++++++++--- .../src/components/Field/AddressInput.tsx | 15 +++++++++------ .../Modal/AddressBook/AddressBookModal.tsx | 5 +++-- 6 files changed, 36 insertions(+), 16 deletions(-) diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index 3fde220b38..66c88ffd97 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -548,23 +548,24 @@ export default class KoniExtension { const address = reformatAddress(accountId); const account = keyring.getAccount(address); const contact = keyring.getAddress(address, 'address'); - const recent = keyring.getAddress(address, 'address'); if (account) { return account; - } else if (contact) { - return contact; } else { let metadata: KeyringJson$Meta; - if (recent) { - metadata = recent.meta; + if (contact) { + metadata = contact.meta; } else { const _new = keyring.saveRecent(address); metadata = _new.json.meta; } + if (contact && !metadata.isRecent) { + return contact; + } + const recentChainSlugs: string[] = (metadata.recentChainSlugs as string[]) || []; if (chain) { diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx index f0427a0df7..ea56389502 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx @@ -706,6 +706,7 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => { addressPrefix={destChainNetworkPrefix} allowDomain={true} chain={chain} + fitNetwork={true} label={t('Send to')} networkGenesisHash={destChainGenesisHash} placeholder={t('Account address')} diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendNFT.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendNFT.tsx index c5cfcf9c8e..c7ba23616c 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendNFT.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendNFT.tsx @@ -255,6 +255,7 @@ const Component: React.FC = () => { addressPrefix={addressPrefix} allowDomain={true} chain={chain} + fitNetwork={true} label={t('Send to')} networkGenesisHash={chainGenesisHash} placeholder={t('Account address')} diff --git a/packages/extension-koni-ui/src/components/Account/Item/AccountItemWithName.tsx b/packages/extension-koni-ui/src/components/Account/Item/AccountItemWithName.tsx index f519a17922..12e2b026fb 100644 --- a/packages/extension-koni-ui/src/components/Account/Item/AccountItemWithName.tsx +++ b/packages/extension-koni-ui/src/components/Account/Item/AccountItemWithName.tsx @@ -6,20 +6,33 @@ import AvatarGroup from '@subwallet/extension-koni-ui/components/Account/Info/Av import AccountItemBase, { AccountItemBaseProps } from '@subwallet/extension-koni-ui/components/Account/Item/AccountItemBase'; import { isAccountAll, toShort } from '@subwallet/extension-koni-ui/utils'; import CN from 'classnames'; -import React from 'react'; +import React, { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; interface Props extends AccountItemBaseProps { direction?: 'vertical' | 'horizontal'; accounts?: AbstractAddressJson[]; + fallbackName?: boolean; } const Component: React.FC = (props: Props) => { - const { accountName, accounts, address, addressPreLength = 4, addressSufLength = 4, direction = 'horizontal' } = props; + const { accountName, accounts, address, addressPreLength = 4, addressSufLength = 4, direction = 'horizontal', fallbackName = true } = props; const isAll = isAccountAll(address); const { t } = useTranslation(); + const showFallback = useMemo(() => { + if (isAll) { + return false; + } else { + if (fallbackName) { + return true; + } else { + return !!accountName; + } + } + }, [accountName, fallbackName, isAll]); + return ( = (props: Props) => { middleItem={(
{isAll ? t('All accounts') : (accountName || toShort(address, addressPreLength, addressSufLength))}
- {!isAll &&
{toShort(address, addressPreLength, addressSufLength)}
} + {showFallback &&
{toShort(address, addressPreLength, addressSufLength)}
}
)} /> diff --git a/packages/extension-koni-ui/src/components/Field/AddressInput.tsx b/packages/extension-koni-ui/src/components/Field/AddressInput.tsx index d2ad1e99cb..30554b29cc 100644 --- a/packages/extension-koni-ui/src/components/Field/AddressInput.tsx +++ b/packages/extension-koni-ui/src/components/Field/AddressInput.tsx @@ -30,14 +30,15 @@ interface Props extends BasicInputWrapper, ThemeProps { networkGenesisHash?: string; chain?: string; allowDomain?: boolean; + fitNetwork?: boolean; } const defaultScannerModalId = 'input-account-address-scanner-modal'; const defaultAddressBookModalId = 'input-account-address-book-modal'; function Component (props: Props, ref: ForwardedRef): React.ReactElement { - const { addressPrefix, - allowDomain, chain, className = '', disabled, id, label, networkGenesisHash, onBlur, + const { addressPrefix, allowDomain, + chain, className = '', disabled, fitNetwork, id, label, networkGenesisHash, onBlur, onChange, onFocus, placeholder, readOnly, saveAddress, showAddressBook, showScanner, status, statusHelp, value } = props; const { t } = useTranslation(); @@ -93,9 +94,11 @@ function Component (props: Props, ref: ForwardedRef): React.ReactEleme if (isEthereumAddress(val)) { saveRecentAccount(val, chain).catch(console.error); } else { - if (decodeAddress(val, false, addressPrefix)) { - saveRecentAccount(val, chain).catch(console.error); - } + try { + if (decodeAddress(val, true, addressPrefix)) { + saveRecentAccount(val, chain).catch(console.error); + } + } catch (e) {} } } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -218,7 +221,7 @@ function Component (props: Props, ref: ForwardedRef): React.ReactEleme
{accountName || toShort(value, 9, 9)}
- {(accountName || addressPrefix !== undefined) && + {(fitNetwork ? accountName : (accountName || addressPrefix !== undefined)) && (
({toShort(formattedAddress, 4, 4)}) diff --git a/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx b/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx index 1dc6090221..c8713009e9 100644 --- a/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx @@ -5,7 +5,7 @@ import { AbstractAddressJson, AccountJson } from '@subwallet/extension-base/back import { BackIcon } from '@subwallet/extension-koni-ui/components'; import { useFilterModal, useFormatAddress, useGetChainInfoByGenesisHash, useSelector } from '@subwallet/extension-koni-ui/hooks'; import { ThemeProps } from '@subwallet/extension-koni-ui/types'; -import { funcSortByName, isAccountAll, reformatAddress, toShort } from '@subwallet/extension-koni-ui/utils'; +import { funcSortByName, isAccountAll, reformatAddress } from '@subwallet/extension-koni-ui/utils'; import { Badge, Icon, ModalContext, SwList, SwModal } from '@subwallet/react-ui'; import { SwListSectionRef } from '@subwallet/react-ui/es/sw-list'; import CN from 'classnames'; @@ -169,9 +169,10 @@ const Component: React.FC = (props: Props) => { return ( Date: Fri, 23 Feb 2024 11:05:34 +0700 Subject: [PATCH 6/8] [Issue-2617] Update logic add recent when change account --- .../src/koni/background/handlers/Extension.ts | 13 ++++++++++--- .../src/Popup/Transaction/variants/SendFund.tsx | 2 +- .../src/components/Field/AddressInput.tsx | 6 ++++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index 66c88ffd97..5507e4140a 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -522,12 +522,19 @@ export default class KoniExtension { private subscribeAddresses (id: string, port: chrome.runtime.Port): AddressBookInfo { const _cb = createSubscription<'pri(accounts.subscribeAddresses)'>(id, port); + let old = ''; + const subscription = this.#koniState.keyringService.addressesSubject.subscribe((subjectInfo: SubjectInfo): void => { const addresses = convertSubjectInfoToAddresses(subjectInfo); + const _new = JSON.stringify(addresses); - _cb({ - addresses: addresses - }); + if (old !== _new) { + _cb({ + addresses: addresses + }); + + old = _new; + } }); this.createUnsubscriptionHandle(id, subscription.unsubscribe); diff --git a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx index ea56389502..330b3a9860 100644 --- a/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx +++ b/packages/extension-koni-ui/src/Popup/Transaction/variants/SendFund.tsx @@ -705,7 +705,7 @@ const _SendFund = ({ className = '' }: Props): React.ReactElement => { ): React.ReactEleme } }, [_contacts, addressPrefix, value, parseAndChangeValue, inputRef, networkGenesisHash]); + useEffect(() => { + if (isAddress(value)) { + parseAndChangeValue(value); + } + }, [value, parseAndChangeValue]); + // todo: Will work with "Manage address book" feature later return ( <> From 77288aed0aa829375dfa9dc402c6e60e20ea75fb Mon Sep 17 00:00:00 2001 From: S2kael Date: Fri, 23 Feb 2024 12:02:28 +0700 Subject: [PATCH 7/8] [Issue-2617] Fix error with input address --- .../src/components/Field/AddressInput.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/extension-koni-ui/src/components/Field/AddressInput.tsx b/packages/extension-koni-ui/src/components/Field/AddressInput.tsx index 14acc25f2e..cea1450282 100644 --- a/packages/extension-koni-ui/src/components/Field/AddressInput.tsx +++ b/packages/extension-koni-ui/src/components/Field/AddressInput.tsx @@ -195,16 +195,14 @@ function Component (props: Props, ref: ForwardedRef): React.ReactEleme parseAndChangeValue(address); inputRef?.current?.focus(); inputRef?.current?.blur(); + } else { + if (isAddress(value)) { + parseAndChangeValue(value); + } } } }, [_contacts, addressPrefix, value, parseAndChangeValue, inputRef, networkGenesisHash]); - useEffect(() => { - if (isAddress(value)) { - parseAndChangeValue(value); - } - }, [value, parseAndChangeValue]); - // todo: Will work with "Manage address book" feature later return ( <> From 0b410ff95f9da162fdcffce870b631ef40baf74f Mon Sep 17 00:00:00 2001 From: S2kael Date: Fri, 23 Feb 2024 14:28:44 +0700 Subject: [PATCH 8/8] [Issue-2617] Update input address display length --- .../extension-koni-ui/src/components/Field/AddressInput.tsx | 4 +++- .../src/components/Modal/AddressBook/AddressBookModal.tsx | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/extension-koni-ui/src/components/Field/AddressInput.tsx b/packages/extension-koni-ui/src/components/Field/AddressInput.tsx index cea1450282..69269c3cc1 100644 --- a/packages/extension-koni-ui/src/components/Field/AddressInput.tsx +++ b/packages/extension-koni-ui/src/components/Field/AddressInput.tsx @@ -36,6 +36,8 @@ interface Props extends BasicInputWrapper, ThemeProps { const defaultScannerModalId = 'input-account-address-scanner-modal'; const defaultAddressBookModalId = 'input-account-address-book-modal'; +const addressLength = 9; + function Component (props: Props, ref: ForwardedRef): React.ReactElement { const { addressPrefix, allowDomain, chain, className = '', disabled, fitNetwork, id, label, networkGenesisHash, onBlur, @@ -223,7 +225,7 @@ function Component (props: Props, ref: ForwardedRef): React.ReactEleme value && isAddress(value) && (
- {accountName || toShort(value, 9, 9)} + {accountName || toShort(value, addressLength, addressLength)}
{(fitNetwork ? accountName : (accountName || addressPrefix !== undefined)) && ( diff --git a/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx b/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx index c8713009e9..a21a171661 100644 --- a/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx +++ b/packages/extension-koni-ui/src/components/Modal/AddressBook/AddressBookModal.tsx @@ -159,6 +159,7 @@ const Component: React.FC = (props: Props) => { const renderItem = useCallback((item: AccountItem) => { const address = formatAddress(item); + const isRecent = item.group === AccountGroup.RECENT; let selected: boolean; if (isEthereumAddress(value)) { @@ -171,6 +172,8 @@ const Component: React.FC = (props: Props) => {