From 71dd87e84c253f53919c40b4a97e48bf152ddbba Mon Sep 17 00:00:00 2001 From: Thuc Nguyen Duy Date: Fri, 25 Aug 2023 11:22:30 +0700 Subject: [PATCH] [issue-960] Support domain name for mobile app --- package.json | 9 +- src/components/Input/InputAddressV2.tsx | 92 +++++++++++++++----- src/messaging/index.ts | 10 +++ src/predefined/dAppSites.ts | 15 +--- src/screens/Transaction/NFT/index.tsx | 2 +- src/screens/Transaction/SendFundV2/index.tsx | 4 + yarn.lock | 63 ++++++++------ 7 files changed, 129 insertions(+), 66 deletions(-) diff --git a/package.json b/package.json index be207d5be..6b20a29c3 100644 --- a/package.json +++ b/package.json @@ -50,8 +50,8 @@ "@react-navigation/native": "^6.1.2", "@react-navigation/native-stack": "^6.9.8", "@reduxjs/toolkit": "^1.9.2", - "@subwallet/extension-chains": "^1.1.8-0", - "@subwallet/extension-dapp": "^1.1.8-0", + "@subwallet/extension-chains": "^1.1.9-0", + "@subwallet/extension-dapp": "^1.1.9-0", "@subwallet/keyring": "^0.0.10", "@subwallet/react-ui": "^5.1.2-b69", "@subwallet/ui-keyring": "^0.0.10", @@ -60,6 +60,7 @@ "eslint-plugin-ft-flow": "^2.0.3", "eventemitter3": "^5.0.0", "i18next": "^22.4.9", + "loglevel": "^1.8.1", "moment": "^2.29.4", "patch-package": "^6.5.0", "phosphor-react-native": "^1.1.2", @@ -136,7 +137,7 @@ "@polkadot/types": "^9.9.4", "@react-native-community/eslint-config": "^3.2.0", "@subwallet/chain-list": "^0.2.10", - "@subwallet/extension-base": "^1.1.8-0", + "@subwallet/extension-base": "^1.1.9-0", "@tsconfig/react-native": "^2.0.2", "@types/jest": "^29.2.3", "@types/react": "^18.0.25", @@ -185,7 +186,7 @@ "@polkadot/util": "^12.2.1", "@polkadot/api": "^10.7.2", "@polkadot/util-crypto": "^12.2.1", - "@subwallet/extension-base": "^1.1.8-0", + "@subwallet/extension-base": "^1.1.9-0", "@subwallet/chain-list": "0.2.10", "react-native-svg": "^13.6.0" }, diff --git a/src/components/Input/InputAddressV2.tsx b/src/components/Input/InputAddressV2.tsx index a644c9cab..5dcd4dadf 100644 --- a/src/components/Input/InputAddressV2.tsx +++ b/src/components/Input/InputAddressV2.tsx @@ -1,5 +1,5 @@ import Input, { InputProps } from 'components/design-system-ui/input'; -import React, { ForwardedRef, forwardRef, useCallback, useEffect, useMemo, useState } from 'react'; +import React, { ForwardedRef, forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { Keyboard, TextInput, View } from 'react-native'; import { useSubWalletTheme } from 'hooks/useSubWalletTheme'; import { isAddress } from '@polkadot/util-crypto'; @@ -10,7 +10,8 @@ import { AddressBookModal } from 'components/Modal/AddressBook/AddressBookModal' import { NativeSyntheticEvent } from 'react-native/Libraries/Types/CoreEventTypes'; import { TextInputFocusEventData } from 'react-native/Libraries/Components/TextInput/TextInput'; import { AddressScanner, AddressScannerProps } from 'components/Scanner/AddressScanner'; -import { saveRecentAccountId } from 'messaging/index'; +import { CHAINS_SUPPORTED_DOMAIN, isAzeroDomain } from '@subwallet/extension-base/koni/api/dotsama/domain'; +import { saveRecentAccountId, resolveAddressToDomain, resolveDomainToAddress } from 'messaging/index'; import { requestCameraPermission } from 'utils/permission/camera'; import { RESULTS } from 'react-native-permissions'; import createStylesheet from './style/InputAddress'; @@ -21,6 +22,8 @@ import i18n from 'utils/i18n/i18n'; import { setAdjustResize } from 'rn-android-keyboard-adjust'; interface Props extends InputProps { + chain?: string; + reValidate?: () => void; isValidValue?: boolean; showAvatar?: boolean; showAddressBook?: boolean; @@ -33,6 +36,7 @@ interface Props extends InputProps { const Component = ( { + chain, isValidValue, showAvatar = true, showAddressBook, @@ -41,18 +45,22 @@ const Component = ( scannerProps = {}, saveAddress = true, value = '', + reValidate, onSideEffectChange, ...inputProps }: Props, + // eslint-disable-next-line @typescript-eslint/no-unused-vars ref: ForwardedRef, ) => { const theme = useSubWalletTheme().swThemes; + const [domainName, setDomainName] = useState(undefined); const [isInputBlur, setInputBlur] = useState(true); const [isShowAddressBookModal, setShowAddressBookModal] = useState(false); const [isShowQrModalVisible, setIsShowQrModalVisible] = useState(false); const isAddressValid = isAddress(value) && (isValidValue !== undefined ? isValidValue : true); const { accounts, contacts } = useSelector((root: RootState) => root.accountState); const [error, setError] = useState(undefined); + const inputRef = useRef(null); const hasLabel = !!inputProps.label; const isInputVisible = !isAddressValid || !value || !isInputBlur; @@ -68,6 +76,60 @@ const Component = ( useEffect(() => setAdjustResize(), []); + const onChangeInputText = useCallback( + (rawText: string) => { + const text = rawText.trim(); + + if (inputProps.onChangeText) { + inputProps.onChangeText(text); + + if (saveAddress && isAddress(text)) { + saveRecentAccountId(text).catch(console.error); + } + } + }, + [inputProps, saveAddress], + ); + + useEffect(() => { + if (chain && value && CHAINS_SUPPORTED_DOMAIN.includes(chain)) { + if (isAzeroDomain(value)) { + resolveDomainToAddress({ + chain, + domain: value, + }) + .then(result => { + if (result) { + setDomainName(value); + onChangeInputText(result); + if (inputRef.current) { + if (!inputRef.current.isFocused() && reValidate) { + reValidate(); + } else { + inputRef.current.blur(); + } + } + } + }) + .catch(console.error); + } else if (isAddress(value)) { + resolveAddressToDomain({ + chain, + address: value, + }) + .then(result => { + if (result) { + setDomainName(result); + } + }) + .catch(console.error); + } + } else { + setDomainName(undefined); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [chain, onChangeInputText, value]); + const _contacts = useMemo(() => [...accounts, ...contacts], [accounts, contacts]); const accountName = useMemo(() => { @@ -99,9 +161,9 @@ const Component = ( )} - {accountName || toShort(value, 9, 9)} + {accountName || domainName || toShort(value, 9, 9)} - {(accountName || addressPrefix !== undefined) && ( + {(accountName || domainName || addressPrefix !== undefined) && ( ({toShort(formattedAddress, 4, 4)}) )} @@ -109,6 +171,7 @@ const Component = ( }, [ accountName, addressPrefix, + domainName, formattedAddress, hasLabel, showAvatar, @@ -171,21 +234,6 @@ const Component = ( theme.colorTextLight5, ]); - const onChangeInputText = useCallback( - (rawText: string) => { - const text = rawText.trim(); - - if (inputProps.onChangeText) { - inputProps.onChangeText(text); - - if (saveAddress && isAddress(text)) { - saveRecentAccountId(text).catch(console.error); - } - } - }, - [inputProps, saveAddress], - ); - const onScanInputText = useCallback( (data: string) => { if (isAddress(data)) { @@ -226,7 +274,11 @@ const Component = ( return ( <> { + inputRef.current = myRef; + // @ts-ignored + ref = inputRef.current; + }} {...inputProps} leftPart={LeftPart} leftPartStyle={stylesheet.inputLeftPart} diff --git a/src/messaging/index.ts b/src/messaging/index.ts index 15049d947..d43173f06 100644 --- a/src/messaging/index.ts +++ b/src/messaging/index.ts @@ -105,6 +105,8 @@ import { RequestTuringStakeCompound, RequestUnbondingSubmit, RequestUnlockKeyring, + ResolveAddressToDomainRequest, + ResolveDomainRequest, ResponseAccountCreateSuriV2, ResponseAccountCreateWithSecretKey, ResponseAccountExportPrivateKey, @@ -1384,6 +1386,14 @@ export async function disconnectWalletConnectConnection(topic: string): Promise< return sendMessage('pri(walletConnect.session.disconnect)', { topic }); } +export async function resolveDomainToAddress(request: ResolveDomainRequest) { + return sendMessage('pri(accounts.resolveDomainToAddress)', request); +} + +export async function resolveAddressToDomain(request: ResolveAddressToDomainRequest) { + return sendMessage('pri(accounts.resolveAddressToDomain)', request); +} + export async function subscribeTransactions( callback: (rs: Record) => void, ): Promise> { diff --git a/src/predefined/dAppSites.ts b/src/predefined/dAppSites.ts index 8055bab37..f189a008c 100644 --- a/src/predefined/dAppSites.ts +++ b/src/predefined/dAppSites.ts @@ -843,19 +843,10 @@ export const predefinedDApps: PredefinedDApps = { isSupportEthereumAccount: true, }, { - name: 'Moonwell Apollo', + name: 'Moonwell', icon: 'https://raw.githubusercontent.com/nova-wallet/nova-utils/master/icons/dapps/color/Moonwell.svg', - id: 'moonwell.fi/apollo/MOVR', - url: 'https://moonwell.fi/apollo/MOVR', - categories: ['defi', 'evm'], - isSupportSubstrateAccount: false, - isSupportEthereumAccount: true, - }, - { - name: 'Moonwell Artemis', - icon: 'https://dotinsights.subwallet.app/assets/images/projects/moonwell.png', - id: 'moonwell.fi/artemis/GLMR', - url: 'https://moonwell.fi/artemis/GLMR', + id: 'https://moonwell.fi/discover', + url: 'https://moonwell.fi/discover', categories: ['defi', 'evm'], isSupportSubstrateAccount: false, isSupportEthereumAccount: true, diff --git a/src/screens/Transaction/NFT/index.tsx b/src/screens/Transaction/NFT/index.tsx index 869523a64..e059bcf95 100644 --- a/src/screens/Transaction/NFT/index.tsx +++ b/src/screens/Transaction/NFT/index.tsx @@ -239,10 +239,10 @@ const SendNFT: React.FC = ({ label={formState.labels.recipientAddress} value={formState.data.recipientAddress} onChangeText={onChangeReceiverAddress} - isValidValue={formState.isValidated.recipientAddress} placeholder={i18n.placeholder.accountAddress} onSubmitEditing={handleSend} disabled={loading} + chain={nftChain} /> {!!formState.errors.recipientAddress.length && ( diff --git a/src/screens/Transaction/SendFundV2/index.tsx b/src/screens/Transaction/SendFundV2/index.tsx index 1d4a3bc70..b9bb42afd 100644 --- a/src/screens/Transaction/SendFundV2/index.tsx +++ b/src/screens/Transaction/SendFundV2/index.tsx @@ -706,6 +706,8 @@ export const SendFund = ({ setIsTransferAll(false); }, []); + const reValidate = () => trigger('to'); + const renderAmountInput = useCallback( ({ field: { onBlur, onChange, value, ref } }: UseControllerReturn) => ( <> @@ -967,11 +969,13 @@ export const SendFund = ({ value={value} onChangeText={onChange} onBlur={onBlur} + reValidate={reValidate} onSideEffectChange={onBlur} placeholder={i18n.placeholder.accountAddress} disabled={loading} addressPrefix={destChainNetworkPrefix} networkGenesisHash={destChainGenesisHash} + chain={chainValue} showAddressBook saveAddress /> diff --git a/yarn.lock b/yarn.lock index 6b61562cb..bbfd09bed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -115,10 +115,10 @@ tslib "^2.3.0" zen-observable-ts "^1.2.5" -"@azns/resolver-core@^1.2.0": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@azns/resolver-core/-/resolver-core-1.3.1.tgz#c568706c3788d631c86362dd7a69fa85cb10d0df" - integrity sha512-551mf8C44Yk12nSHAJ2BBFbTiMDxygWswl3E5qTUWv8sNVWhPW3cFHt7L7YX8WdijS4u74BW1vxcoWnj3iABCA== +"@azns/resolver-core@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@azns/resolver-core/-/resolver-core-1.4.0.tgz#2698f009b832b7987f648e59a3ec81ea15633f36" + integrity sha512-er7teHxdnm77JoXQXQB4jdagOg6sjDZAlYE/6uBWSyw5TipjOeNlA+bufZ95TENw+Q67ueQ9o01Bn4YXAP3s3w== "@babel/cli@^7.19.3": version "7.22.9" @@ -4145,7 +4145,7 @@ resolved "https://registry.yarnpkg.com/@substrate/ss58-registry/-/ss58-registry-1.41.0.tgz#dd18e132f44b73c3cd31cf0db489c10af70bef36" integrity sha512-TLz5VkEaJRNFzf1Oiix9gqknKer3aKbLfjK9XHBFCIhdxlQpI+S6lZGu3wT4DHAGXPakYfXb8+9ZIOtWLcQ/2Q== -"@subwallet/chain-list@0.2.10", "@subwallet/chain-list@^0.2.10": +"@subwallet/chain-list@0.2.10", "@subwallet/chain-list@0.2.11-beta.0", "@subwallet/chain-list@^0.2.10": version "0.2.10" resolved "https://registry.yarnpkg.com/@subwallet/chain-list/-/chain-list-0.2.10.tgz#9b572ce3b41a3c1f68c6be6f2d8558f132321bde" integrity sha512-SdLi/nxiMquSGTto3GCprD4uvwL4ex0asItNdIokYpd8T2prEVk017xqZHzHQZEcTkBTr0v8kS0m+GPKwIXvKg== @@ -4154,14 +4154,14 @@ "@polkadot/util" "^10.2.1" eventemitter3 "^4.0.7" -"@subwallet/extension-base@^1.1.8-0": - version "1.1.8-0" - resolved "https://registry.yarnpkg.com/@subwallet/extension-base/-/extension-base-1.1.8-0.tgz#918bae3aa4bf837cd3292e91e51dc18ab4a09280" - integrity sha512-3p4GE9TL8oimTjk8jEprDT/UWVr08A5nEoz7lb0SJogJn0TUUG5JG81reSQ2Yds+pZf5uixp6ileqrl5Q2JN6g== +"@subwallet/extension-base@^1.1.9-0": + version "1.1.9-0" + resolved "https://registry.yarnpkg.com/@subwallet/extension-base/-/extension-base-1.1.9-0.tgz#dfc0f38dbd9d6ff1e9b4cf5c53e011fad47ecfdc" + integrity sha512-eh+Y1/4QWCSUgdSv5FW0SP5jfUDq4sMd/mN50FB2Vo6Y3RCU7yBBczct/7BwyG+bHNn2E4a2LbVPyWX2gAgm+w== dependencies: "@acala-network/api" "^5.0.2" "@apollo/client" "^3.7.14" - "@azns/resolver-core" "^1.2.0" + "@azns/resolver-core" "^1.4.0" "@equilab/api" "^1.14.25" "@ethereumjs/common" "^2.6.5" "@ethereumjs/tx" "^4.0.2" @@ -4186,11 +4186,11 @@ "@reduxjs/toolkit" "^1.9.1" "@sora-substrate/type-definitions" "^1.17.7" "@substrate/connect" "^0.7.26" - "@subwallet/chain-list" "0.2.10" - "@subwallet/extension-base" "^1.1.8-0" - "@subwallet/extension-chains" "^1.1.8-0" - "@subwallet/extension-dapp" "^1.1.8-0" - "@subwallet/extension-inject" "^1.1.8-0" + "@subwallet/chain-list" "0.2.11-beta.0" + "@subwallet/extension-base" "^1.1.9-0" + "@subwallet/extension-chains" "^1.1.9-0" + "@subwallet/extension-dapp" "^1.1.9-0" + "@subwallet/extension-inject" "^1.1.9-0" "@subwallet/keyring" "^0.0.10" "@subwallet/ui-keyring" "^0.0.10" "@walletconnect/sign-client" "^2.8.4" @@ -4224,31 +4224,31 @@ web3-eth-contract "^1.10.0" web3-utils "^1.10.0" -"@subwallet/extension-chains@^1.1.8-0": - version "1.1.8-0" - resolved "https://registry.yarnpkg.com/@subwallet/extension-chains/-/extension-chains-1.1.8-0.tgz#e5428b84bc1c6eae6caf9152dee99ea24372f5b5" - integrity sha512-PzGQmAm6iCHGGsP84vZlhm6ZUELWj6Qg/2A4rpbrsAT1nWd1lEH+gPKp6cOM2i8Fd5XASMhZ9RnFCjA8u9xeGg== +"@subwallet/extension-chains@^1.1.9-0": + version "1.1.9-0" + resolved "https://registry.yarnpkg.com/@subwallet/extension-chains/-/extension-chains-1.1.9-0.tgz#d89b282b813c4401f3be18e4ee851160ef27b203" + integrity sha512-s+hUkK3tBkCuFHIe3tFk9zXk+pkNc9ft3GFJFEVexEmIchLQu1WWnXd9MEGlPBxhGy3iLPvSw0k6tClxiLjlRg== dependencies: "@babel/runtime" "^7.20.6" "@polkadot/networks" "^12.3.2" "@polkadot/util" "^12.3.2" "@polkadot/util-crypto" "^12.3.2" - "@subwallet/extension-inject" "^1.1.8-0" + "@subwallet/extension-inject" "^1.1.9-0" -"@subwallet/extension-dapp@^1.1.8-0": - version "1.1.8-0" - resolved "https://registry.yarnpkg.com/@subwallet/extension-dapp/-/extension-dapp-1.1.8-0.tgz#9efbf1dec28e36136f6b69ce5796639cf5688dd6" - integrity sha512-Wl9YKhRzSf1xziv0U9tT7TTmXajs0HU0bQEC0IW3nqi0bh0bM2vHcYQ1DjdpKTPZnEGEoHfSd1F2GaXDPopJhw== +"@subwallet/extension-dapp@^1.1.9-0": + version "1.1.9-0" + resolved "https://registry.yarnpkg.com/@subwallet/extension-dapp/-/extension-dapp-1.1.9-0.tgz#2f3f824af672d16f5c784d631c200f0810ee4b44" + integrity sha512-PvM39AOX9tfKhJsIWD36e9Rrr0xT295lVSlMndPeHY4QJ6BK9UmafSvvNPuzVXCK6dMI1JKqJjHht9r/VEnEHA== dependencies: "@babel/runtime" "^7.20.6" "@polkadot/util" "^12.3.2" "@polkadot/util-crypto" "^12.3.2" - "@subwallet/extension-inject" "^1.1.8-0" + "@subwallet/extension-inject" "^1.1.9-0" -"@subwallet/extension-inject@^1.1.8-0": - version "1.1.8-0" - resolved "https://registry.yarnpkg.com/@subwallet/extension-inject/-/extension-inject-1.1.8-0.tgz#c4e42ff9ae3ecd80b2088e1169667729193105a7" - integrity sha512-qEMZql5RR5Aiu6av6EnaHyegsQaql+jW1Egu9Pc0/lN0p6EZFF2I93aVBCSTmuvNbyXrimZOLj/v+65xddgUBw== +"@subwallet/extension-inject@^1.1.9-0": + version "1.1.9-0" + resolved "https://registry.yarnpkg.com/@subwallet/extension-inject/-/extension-inject-1.1.9-0.tgz#e21e11e3a523476285f53bd6250a5711a6ce1201" + integrity sha512-22tWVMxlOn+fVdjxDs+isYIBjitQZrILsyRCvqZHswWqZnKpq9iNSqwQoxyYC81nej+M+x0mqMxiXUpdirFocw== dependencies: "@babel/runtime" "^7.20.6" "@polkadot/rpc-provider" "^10.9.1" @@ -12091,6 +12091,11 @@ logkitty@^0.7.1: dayjs "^1.8.15" yargs "^15.1.0" +loglevel@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.1.tgz#5c621f83d5b48c54ae93b6156353f555963377b4" + integrity sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg== + long@^5.0.0: version "5.2.3" resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1"