Skip to content

Commit

Permalink
Merge pull request #3998 from Koniverse/koni/dev/issue-3974-v2
Browse files Browse the repository at this point in the history
[Issue-3974] Fix: cannot import token & NFT on Rootstock
  • Loading branch information
saltict authored Jan 23, 2025
2 parents a4680ac + 630b9fc commit bc6f4c5
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 57 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/extension-base/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/extension-koni-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
107 changes: 63 additions & 44 deletions packages/extension-koni-ui/src/Popup/Home/Nfts/NftImport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -92,7 +93,8 @@ function Component ({ className = '' }: Props): React.ReactElement<Props> {

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]);
Expand All @@ -110,6 +112,10 @@ function Component ({ className = '' }: Props): React.ReactElement<Props> {
form.resetFields(['contractAddress', 'collectionName']);
}

if (contractAddress) {
form.setFieldValue('contractAddress', reformatContractAddress(selectedChain, contractAddress));
}

if (allError.contractAddress.length > 0) {
form.resetFields(['collectionName']);
}
Expand Down Expand Up @@ -182,49 +188,62 @@ function Component ({ className = '' }: Props): React.ReactElement<Props> {
});
}, [t]);

const contractAddressValidator = useCallback((rule: RuleObject, contractAddress: string): Promise<void> => {
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<void> => {
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);
Expand Down Expand Up @@ -291,7 +310,7 @@ function Component ({ className = '' }: Props): React.ReactElement<Props> {

<Form.Item
name='contractAddress'
rules={[{ validator: contractAddressValidator }]}
rules={contractRules}
statusHelpAsTooltip={true}
>
<AddressInput
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useChainChecker, useDefaultNavigate, useGetChainPrefixBySlug, useGetFun
import { upsertCustomToken, validateCustomToken } from '@subwallet/extension-koni-ui/messaging';
import { FormCallbacks, FormRule, Theme, 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 { Col, Field, Form, Icon, Input, Row } from '@subwallet/react-ui';
import SwAvatar from '@subwallet/react-ui/es/sw-avatar';
import { PlusCircle } from 'phosphor-react';
Expand Down Expand Up @@ -108,9 +109,16 @@ function Component ({ className = '' }: Props): React.ReactElement<Props> {
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<void>((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);
Expand Down Expand Up @@ -155,7 +163,7 @@ function Component ({ className = '' }: Props): React.ReactElement<Props> {
}
})
];
}, [chainNetworkPrefix, form, selectedChain, t]);
}, [chainNetworkPrefix, form, t]);

const assetIdRules = useMemo((): FormRule[] => {
return [
Expand Down Expand Up @@ -210,7 +218,8 @@ function Component ({ className = '' }: Props): React.ReactElement<Props> {
const all = convertFieldToObject<TokenImportFormType>(allFields);
const allError = convertFieldToError<TokenImportFormType>(allFields);

const { chain, type } = changes;
const { chain, contractAddress, type } = changes;
const { chain: selectedChain } = all;

const baseResetFields = ['tokenName', 'symbol', 'decimals', 'priceId'];

Expand All @@ -232,6 +241,10 @@ function Component ({ className = '' }: Props): React.ReactElement<Props> {
form.resetFields(['assetId', ...baseResetFields]);
}

if (contractAddress) {
form.setFieldValue('contractAddress', reformatContractAddress(selectedChain, contractAddress));
}

if (allError.contractAddress.length > 0 || allError.assetId.length > 0) {
form.resetFields([...baseResetFields]);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
2 changes: 1 addition & 1 deletion packages/extension-web-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
14 changes: 7 additions & 7 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

1 comment on commit bc6f4c5

@saltict
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.