diff --git a/package.json b/package.json index fc9ee8ba77..47aa77ed45 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "@polkadot/types-support": "^15.0.1", "@polkadot/util": "^13.2.3", "@polkadot/util-crypto": "^13.2.3", - "@subwallet/chain-list": "0.2.97", + "@subwallet/chain-list": "0.2.98-beta.6", "@subwallet/keyring": "^0.1.8-beta.0", "@subwallet/react-ui": "5.1.2-b79", "@subwallet/ui-keyring": "0.1.8-beta.0", diff --git a/packages/extension-base/package.json b/packages/extension-base/package.json index 2d65f302c5..b3998b631f 100644 --- a/packages/extension-base/package.json +++ b/packages/extension-base/package.json @@ -55,7 +55,7 @@ "@reduxjs/toolkit": "^1.9.1", "@sora-substrate/type-definitions": "^1.17.7", "@substrate/connect": "^0.8.9", - "@subwallet/chain-list": "0.2.97", + "@subwallet/chain-list": "0.2.98-beta.6", "@subwallet/extension-base": "^1.3.12-1", "@subwallet/extension-chains": "^1.3.12-1", "@subwallet/extension-dapp": "^1.3.12-1", diff --git a/packages/extension-koni-ui/package.json b/packages/extension-koni-ui/package.json index 2530fe88cf..ca105c932b 100644 --- a/packages/extension-koni-ui/package.json +++ b/packages/extension-koni-ui/package.json @@ -34,7 +34,7 @@ "@polkadot/util-crypto": "^12.6.2", "@ramonak/react-progress-bar": "^5.0.3", "@reduxjs/toolkit": "^1.9.1", - "@subwallet/chain-list": "0.2.97", + "@subwallet/chain-list": "0.2.98-beta.6", "@subwallet/extension-base": "^1.3.12-1", "@subwallet/extension-chains": "^1.3.12-1", "@subwallet/extension-dapp": "^1.3.12-1", diff --git a/packages/extension-koni-ui/src/Popup/Home/Nfts/NftImport.tsx b/packages/extension-koni-ui/src/Popup/Home/Nfts/NftImport.tsx index e5064a4296..ede8e2aa34 100644 --- a/packages/extension-koni-ui/src/Popup/Home/Nfts/NftImport.tsx +++ b/packages/extension-koni-ui/src/Popup/Home/Nfts/NftImport.tsx @@ -8,8 +8,9 @@ import { AddressInput, ChainSelector, Layout, PageWrapper, TokenTypeSelector } f import { DataContext } from '@subwallet/extension-koni-ui/contexts/DataContext'; import { useChainChecker, useGetChainPrefixBySlug, useGetNftContractSupportedChains, useNotification, useTranslation } from '@subwallet/extension-koni-ui/hooks'; import { upsertCustomToken, validateCustomToken } from '@subwallet/extension-koni-ui/messaging'; -import { FormCallbacks, FormFieldData, ThemeProps } from '@subwallet/extension-koni-ui/types'; +import { FormCallbacks, FormFieldData, FormRule, ThemeProps } from '@subwallet/extension-koni-ui/types'; import { convertFieldToError, convertFieldToObject, reformatAddress, simpleCheckForm } from '@subwallet/extension-koni-ui/utils'; +import { reformatContractAddress } from '@subwallet/extension-koni-ui/utils/account/reformatContractAddress'; import { Form, Icon, Input } from '@subwallet/react-ui'; import { PlusCircle } from 'phosphor-react'; import { RuleObject } from 'rc-field-form/lib/interface'; @@ -92,7 +93,8 @@ function Component ({ className = '' }: Props): React.ReactElement { const empty = Object.entries(all).some(([key, value]) => key !== 'symbol' ? !value : false); - const { chain, type } = changes; + const { chain, contractAddress, type } = changes; + const { chain: selectedChain } = all; if (chain) { const nftTypes = getNftTypeSupported(chainInfoMap[chain]); @@ -110,6 +112,10 @@ function Component ({ className = '' }: Props): React.ReactElement { form.resetFields(['contractAddress', 'collectionName']); } + if (contractAddress) { + form.setFieldValue('contractAddress', reformatContractAddress(selectedChain, contractAddress)); + } + if (allError.contractAddress.length > 0) { form.resetFields(['collectionName']); } @@ -182,49 +188,62 @@ function Component ({ className = '' }: Props): React.ReactElement { }); }, [t]); - const contractAddressValidator = useCallback((rule: RuleObject, contractAddress: string): Promise => { - return new Promise((resolve, reject) => { - if (!isAddress(contractAddress)) { - reject(t('Invalid contract address')); - } else { - const isValidEvmContract = [_AssetType.ERC721].includes(selectedNftType) && isEthereumAddress(contractAddress); - const isValidWasmContract = [_AssetType.PSP34].includes(selectedNftType) && isValidSubstrateAddress(contractAddress); - const reformattedAddress = reformatAddress(contractAddress, chainNetworkPrefix); - - if (isValidEvmContract || isValidWasmContract) { - setLoading(true); - validateCustomToken({ - contractAddress: reformattedAddress, - originChain: selectedChain, - type: selectedNftType - }) - .then((validationResult) => { - setLoading(false); - - if (validationResult.isExist) { - reject(t('Existed NFT')); + const contractRules = useMemo((): FormRule[] => { + return [ + ({ getFieldValue }) => ({ + transform: (contractAddress: string) => { + const selectedChain = getFieldValue('chain') as string; + + return reformatContractAddress(selectedChain, contractAddress); + }, + validator: (_, contractAddress: string): Promise => { + return new Promise((resolve, reject) => { + if (!isAddress(contractAddress)) { + reject(t('Invalid contract address')); + } else { + const selectedChain = getFieldValue('chain') as string; + const selectedNftType = getFieldValue('type') as _AssetType; + const isValidEvmContract = [_AssetType.ERC721].includes(selectedNftType) && isEthereumAddress(contractAddress); + const isValidWasmContract = [_AssetType.PSP34].includes(selectedNftType) && isValidSubstrateAddress(contractAddress); + const reformattedAddress = reformatAddress(contractAddress, chainNetworkPrefix); + + if (isValidEvmContract || isValidWasmContract) { + setLoading(true); + validateCustomToken({ + contractAddress: reformattedAddress, + originChain: selectedChain, + type: selectedNftType + }) + .then((validationResult) => { + setLoading(false); + + if (validationResult.isExist) { + reject(t('Existed NFT')); + } + + if (validationResult.contractError) { + reject(t('Invalid contract for the selected chain')); + } + + if (!validationResult.isExist && !validationResult.contractError) { + form.setFieldValue('collectionName', validationResult.name); + form.setFieldValue('symbol', validationResult.symbol); + resolve(); + } + }) + .catch(() => { + setLoading(false); + reject(t('Invalid contract for the selected chain')); + }); + } else { + reject(t('Invalid contract address')); } - - if (validationResult.contractError) { - reject(t('Invalid contract for the selected chain')); - } - - if (!validationResult.isExist && !validationResult.contractError) { - form.setFieldValue('collectionName', validationResult.name); - form.setFieldValue('symbol', validationResult.symbol); - resolve(); - } - }) - .catch(() => { - setLoading(false); - reject(t('Invalid contract for the selected chain')); - }); - } else { - reject(t('Invalid contract address')); + } + }); } - } - }); - }, [chainNetworkPrefix, form, selectedChain, selectedNftType, t]); + }) + ]; + }, [chainNetworkPrefix, form, t]); useEffect(() => { selectedChain && checkChain(selectedChain); @@ -291,7 +310,7 @@ function Component ({ className = '' }: Props): React.ReactElement { { const contractRules = useMemo((): FormRule[] => { return [ ({ getFieldValue }) => ({ + transform: (contractAddress: string) => { + const selectedChain = getFieldValue('chain') as string; + + return reformatContractAddress(selectedChain, contractAddress); + }, validator: (_, contractAddress: string) => { return new Promise((resolve, reject) => { const selectedTokenType = getFieldValue('type') as _AssetType; + const selectedChain = getFieldValue('chain') as string; + const isValidEvmContract = [_AssetType.ERC20].includes(selectedTokenType) && isEthereumAddress(contractAddress); const isValidWasmContract = [_AssetType.PSP22].includes(selectedTokenType) && isValidSubstrateAddress(contractAddress); const isValidGearContract = [_AssetType.VFT].includes(selectedTokenType) && isValidSubstrateAddress(contractAddress); @@ -155,7 +163,7 @@ function Component ({ className = '' }: Props): React.ReactElement { } }) ]; - }, [chainNetworkPrefix, form, selectedChain, t]); + }, [chainNetworkPrefix, form, t]); const assetIdRules = useMemo((): FormRule[] => { return [ @@ -210,7 +218,8 @@ function Component ({ className = '' }: Props): React.ReactElement { const all = convertFieldToObject(allFields); const allError = convertFieldToError(allFields); - const { chain, type } = changes; + const { chain, contractAddress, type } = changes; + const { chain: selectedChain } = all; const baseResetFields = ['tokenName', 'symbol', 'decimals', 'priceId']; @@ -232,6 +241,10 @@ function Component ({ className = '' }: Props): React.ReactElement { form.resetFields(['assetId', ...baseResetFields]); } + if (contractAddress) { + form.setFieldValue('contractAddress', reformatContractAddress(selectedChain, contractAddress)); + } + if (allError.contractAddress.length > 0 || allError.assetId.length > 0) { form.resetFields([...baseResetFields]); } diff --git a/packages/extension-koni-ui/src/utils/account/reformatContractAddress.ts b/packages/extension-koni-ui/src/utils/account/reformatContractAddress.ts new file mode 100644 index 0000000000..4c5eeb844d --- /dev/null +++ b/packages/extension-koni-ui/src/utils/account/reformatContractAddress.ts @@ -0,0 +1,16 @@ +// Copyright 2019-2022 @polkadot/extension-ui authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { reformatAddress } from '@subwallet/extension-koni-ui/utils'; + +import { isEthereumAddress } from '@polkadot/util-crypto'; + +const SPECIAL_CHAIN = ['rootstock']; + +export function reformatContractAddress (chainSlug: string, contractAddress: string) { + if (SPECIAL_CHAIN.includes(chainSlug) && isEthereumAddress(contractAddress.toLowerCase())) { + return reformatAddress(contractAddress.toLowerCase()); + } + + return contractAddress; +} diff --git a/packages/extension-web-ui/package.json b/packages/extension-web-ui/package.json index 9d2c8114ca..40b42738c4 100644 --- a/packages/extension-web-ui/package.json +++ b/packages/extension-web-ui/package.json @@ -35,7 +35,7 @@ "@polkadot/util-crypto": "^12.6.2", "@ramonak/react-progress-bar": "^5.0.3", "@reduxjs/toolkit": "^1.9.1", - "@subwallet/chain-list": "0.2.97", + "@subwallet/chain-list": "0.2.98-beta.6", "@subwallet/extension-base": "^1.3.12-1", "@subwallet/extension-chains": "^1.3.12-1", "@subwallet/extension-dapp": "^1.3.12-1", diff --git a/yarn.lock b/yarn.lock index 39db93445c..a5ca35b532 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6439,15 +6439,15 @@ __metadata: languageName: node linkType: hard -"@subwallet/chain-list@npm:0.2.97": - version: 0.2.97 - resolution: "@subwallet/chain-list@npm:0.2.97" +"@subwallet/chain-list@npm:0.2.98-beta.6": + version: 0.2.98-beta.6 + resolution: "@subwallet/chain-list@npm:0.2.98-beta.6" dependencies: "@polkadot/dev": 0.67.167 "@polkadot/util": ^12.5.1 eventemitter3: ^5.0.1 ts-md5: ^1.3.1 - checksum: 3271231e2c5b435dd2f4c502da5af8b547a5ac8aafe7089d09c9966fd74b233eb4077d04e0c960857d5b5e2fbd29f178f08aec473e6ec23d19bd07b6642af432 + checksum: 6379d32e6ebbb0ee147d591effbd21474b9a6c44de242fcde025520a5b71ae26ec9ddb2a7949b701fedd5fbe863e9b0309b12c6ac185eec80a541c54c45f553c languageName: node linkType: hard @@ -6490,7 +6490,7 @@ __metadata: "@reduxjs/toolkit": ^1.9.1 "@sora-substrate/type-definitions": ^1.17.7 "@substrate/connect": ^0.8.9 - "@subwallet/chain-list": 0.2.97 + "@subwallet/chain-list": 0.2.98-beta.6 "@subwallet/extension-base": ^1.3.12-1 "@subwallet/extension-chains": ^1.3.12-1 "@subwallet/extension-dapp": ^1.3.12-1 @@ -6629,7 +6629,7 @@ __metadata: "@polkadot/util-crypto": ^12.6.2 "@ramonak/react-progress-bar": ^5.0.3 "@reduxjs/toolkit": ^1.9.1 - "@subwallet/chain-list": 0.2.97 + "@subwallet/chain-list": 0.2.98-beta.6 "@subwallet/extension-base": ^1.3.12-1 "@subwallet/extension-chains": ^1.3.12-1 "@subwallet/extension-dapp": ^1.3.12-1 @@ -6769,7 +6769,7 @@ __metadata: "@polkadot/util-crypto": ^12.6.2 "@ramonak/react-progress-bar": ^5.0.3 "@reduxjs/toolkit": ^1.9.1 - "@subwallet/chain-list": 0.2.97 + "@subwallet/chain-list": 0.2.98-beta.6 "@subwallet/extension-base": ^1.3.12-1 "@subwallet/extension-chains": ^1.3.12-1 "@subwallet/extension-dapp": ^1.3.12-1